strace/capability.c
Dmitry V. Levin b93d52fe3d Change the license of strace to LGPL-2.1-or-later
strace is now provided under the terms of the GNU Lesser General
Public License version 2.1 or later, see COPYING for more details.

strace test suite is now provided under the terms of the GNU General
Public License version 2 or later, see tests/COPYING for more details.
2018-12-10 00:00:00 +00:00

144 lines
3.0 KiB
C

/*
* Copyright (c) 2000 Wichert Akkerman <wakkerma@debian.org>
* Copyright (c) 2011 Denys Vlasenko <dvlasenk@redhat.com>
* Copyright (c) 2005-2015 Dmitry V. Levin <ldv@altlinux.org>
* Copyright (c) 2014-2017 The strace developers.
* All rights reserved.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include "defs.h"
/* these constants are the same as in <linux/capability.h> */
enum {
#include "caps0.h"
};
#include "xlat/cap_mask0.h"
/* these constants are CAP_TO_INDEX'ed constants from <linux/capability.h> */
enum {
#include "caps1.h"
};
#include "xlat/cap_mask1.h"
/* these constants are the same as in <linux/capability.h> */
enum {
_LINUX_CAPABILITY_VERSION_1 = 0x19980330,
_LINUX_CAPABILITY_VERSION_2 = 0x20071026,
_LINUX_CAPABILITY_VERSION_3 = 0x20080522
};
#include "xlat/cap_version.h"
struct user_cap_header_struct {
uint32_t version;
int pid;
};
struct user_cap_data_struct {
uint32_t effective;
uint32_t permitted;
uint32_t inheritable;
};
static const struct user_cap_header_struct *
get_cap_header(struct tcb *const tcp, const kernel_ulong_t addr)
{
static struct user_cap_header_struct header;
if (!addr || !verbose(tcp))
return NULL;
if (umove(tcp, addr, &header) < 0)
return NULL;
return &header;
}
static void
print_cap_header(struct tcb *const tcp, const kernel_ulong_t addr,
const struct user_cap_header_struct *const h)
{
if (!addr || !h) {
printaddr(addr);
return;
}
tprints("{version=");
printxval(cap_version, h->version,
"_LINUX_CAPABILITY_VERSION_???");
tprintf(", pid=%d}", h->pid);
}
static void
print_cap_bits(const uint32_t lo, const uint32_t hi)
{
if (lo || !hi)
printflags(cap_mask0, lo, "CAP_???");
if (hi) {
if (lo)
tprints("|");
printflags(cap_mask1, hi, "CAP_???");
}
}
static void
print_cap_data(struct tcb *const tcp, const kernel_ulong_t addr,
const struct user_cap_header_struct *const h)
{
struct user_cap_data_struct data[2];
unsigned int len;
if (!addr || !h) {
printaddr(addr);
return;
}
if (_LINUX_CAPABILITY_VERSION_2 == h->version ||
_LINUX_CAPABILITY_VERSION_3 == h->version)
len = 2;
else
len = 1;
if (umoven_or_printaddr(tcp, addr, len * sizeof(data[0]), data))
return;
tprints("{effective=");
print_cap_bits(data[0].effective, len > 1 ? data[1].effective : 0);
tprints(", permitted=");
print_cap_bits(data[0].permitted, len > 1 ? data[1].permitted : 0);
tprints(", inheritable=");
print_cap_bits(data[0].inheritable, len > 1 ? data[1].inheritable : 0);
tprints("}");
}
SYS_FUNC(capget)
{
const struct user_cap_header_struct *h;
if (entering(tcp)) {
h = get_cap_header(tcp, tcp->u_arg[0]);
print_cap_header(tcp, tcp->u_arg[0], h);
tprints(", ");
} else {
h = syserror(tcp) ? NULL : get_cap_header(tcp, tcp->u_arg[0]);
print_cap_data(tcp, tcp->u_arg[1], h);
}
return 0;
}
SYS_FUNC(capset)
{
const struct user_cap_header_struct *const h =
get_cap_header(tcp, tcp->u_arg[0]);
print_cap_header(tcp, tcp->u_arg[0], h);
tprints(", ");
print_cap_data(tcp, tcp->u_arg[1], h);
return RVAL_DECODED;
}