Dmitry V. Levin
b93d52fe3d
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.
410 lines
8.6 KiB
C
410 lines
8.6 KiB
C
/*
|
|
* Copyright (c) 2014-2015 Dmitry V. Levin <ldv@altlinux.org>
|
|
* Copyright (c) 2014-2018 The strace developers.
|
|
* All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
|
*/
|
|
|
|
#include "defs.h"
|
|
|
|
#include "keyctl_kdf_params.h"
|
|
#include "print_fields.h"
|
|
|
|
typedef int32_t key_serial_t;
|
|
|
|
#include "xlat/key_spec.h"
|
|
|
|
struct keyctl_dh_params {
|
|
int32_t private;
|
|
int32_t prime;
|
|
int32_t base;
|
|
};
|
|
|
|
static void
|
|
print_keyring_serial_number(key_serial_t id)
|
|
{
|
|
printxval_d(key_spec, id, NULL);
|
|
}
|
|
|
|
SYS_FUNC(add_key)
|
|
{
|
|
/* type */
|
|
printstr(tcp, tcp->u_arg[0]);
|
|
/* description */
|
|
tprints(", ");
|
|
printstr(tcp, tcp->u_arg[1]);
|
|
/* payload */
|
|
tprints(", ");
|
|
printstrn(tcp, tcp->u_arg[2], tcp->u_arg[3]);
|
|
/* payload length */
|
|
tprintf(", %" PRI_klu ", ", tcp->u_arg[3]);
|
|
/* keyring serial number */
|
|
print_keyring_serial_number(tcp->u_arg[4]);
|
|
|
|
return RVAL_DECODED;
|
|
}
|
|
|
|
SYS_FUNC(request_key)
|
|
{
|
|
/* type */
|
|
printstr(tcp, tcp->u_arg[0]);
|
|
/* description */
|
|
tprints(", ");
|
|
printstr(tcp, tcp->u_arg[1]);
|
|
/* callout_info */
|
|
tprints(", ");
|
|
printstr(tcp, tcp->u_arg[2]);
|
|
/* keyring serial number */
|
|
tprints(", ");
|
|
print_keyring_serial_number(tcp->u_arg[3]);
|
|
|
|
return RVAL_DECODED;
|
|
}
|
|
|
|
static void
|
|
keyctl_get_keyring_id(struct tcb *tcp, key_serial_t id, int create)
|
|
{
|
|
print_keyring_serial_number(id);
|
|
tprintf(", %d", create);
|
|
}
|
|
|
|
static void
|
|
keyctl_update_key(struct tcb *tcp, key_serial_t id, kernel_ulong_t addr,
|
|
kernel_ulong_t len)
|
|
{
|
|
print_keyring_serial_number(id);
|
|
tprints(", ");
|
|
printstrn(tcp, addr, len);
|
|
tprintf(", %llu", zero_extend_signed_to_ull(len));
|
|
}
|
|
|
|
static void
|
|
keyctl_handle_key_key(struct tcb *tcp, key_serial_t id1, key_serial_t id2)
|
|
{
|
|
print_keyring_serial_number(id1);
|
|
tprints(", ");
|
|
print_keyring_serial_number(id2);
|
|
}
|
|
|
|
static void
|
|
keyctl_read_key(struct tcb *tcp, key_serial_t id, kernel_ulong_t addr,
|
|
kernel_ulong_t len, bool has_nul)
|
|
{
|
|
if (entering(tcp)) {
|
|
print_keyring_serial_number(id);
|
|
tprints(", ");
|
|
} else {
|
|
if (syserror(tcp))
|
|
printaddr(addr);
|
|
else {
|
|
kernel_ulong_t rval = (tcp->u_rval >= 0) &&
|
|
((kernel_ulong_t) tcp->u_rval > len) ? len :
|
|
(kernel_ulong_t) tcp->u_rval;
|
|
printstr_ex(tcp, addr, rval, has_nul ?
|
|
QUOTE_OMIT_TRAILING_0 : 0);
|
|
}
|
|
tprintf(", %llu", zero_extend_signed_to_ull(len));
|
|
}
|
|
}
|
|
|
|
static void
|
|
keyctl_keyring_search(struct tcb *tcp, key_serial_t id1, kernel_ulong_t addr1,
|
|
kernel_ulong_t addr2, key_serial_t id2)
|
|
{
|
|
print_keyring_serial_number(id1);
|
|
tprints(", ");
|
|
printstr(tcp, addr1);
|
|
tprints(", ");
|
|
printstr(tcp, addr2);
|
|
tprints(", ");
|
|
print_keyring_serial_number(id2);
|
|
}
|
|
|
|
static void
|
|
keyctl_chown_key(struct tcb *tcp, key_serial_t id, unsigned user,
|
|
unsigned group)
|
|
{
|
|
print_keyring_serial_number(id);
|
|
printuid(", ", user);
|
|
printuid(", ", group);
|
|
}
|
|
|
|
static void
|
|
keyctl_instantiate_key(struct tcb *tcp, key_serial_t id1, kernel_ulong_t addr,
|
|
kernel_ulong_t len, key_serial_t id2)
|
|
{
|
|
print_keyring_serial_number(id1);
|
|
tprints(", ");
|
|
printstrn(tcp, addr, len);
|
|
tprintf(", %llu, ", zero_extend_signed_to_ull(len));
|
|
print_keyring_serial_number(id2);
|
|
}
|
|
|
|
static void
|
|
keyctl_instantiate_key_iov(struct tcb *tcp, key_serial_t id1,
|
|
kernel_ulong_t addr, kernel_ulong_t len,
|
|
key_serial_t id2)
|
|
{
|
|
print_keyring_serial_number(id1);
|
|
tprints(", ");
|
|
tprint_iov(tcp, len, addr, IOV_DECODE_STR);
|
|
tprintf(", %llu, ", zero_extend_signed_to_ull(len));
|
|
print_keyring_serial_number(id2);
|
|
}
|
|
|
|
static void
|
|
keyctl_negate_key(struct tcb *tcp, key_serial_t id1, unsigned timeout,
|
|
key_serial_t id2)
|
|
{
|
|
print_keyring_serial_number(id1);
|
|
tprintf(", %u, ", timeout);
|
|
print_keyring_serial_number(id2);
|
|
}
|
|
|
|
static void
|
|
keyctl_reject_key(struct tcb *tcp, key_serial_t id1, unsigned timeout,
|
|
unsigned error, key_serial_t id2)
|
|
{
|
|
const char *err_str = err_name(error);
|
|
|
|
print_keyring_serial_number(id1);
|
|
tprintf(", %u, ", timeout);
|
|
print_xlat_ex(error, err_str, XLAT_STYLE_FMT_U);
|
|
tprints(", ");
|
|
print_keyring_serial_number(id2);
|
|
}
|
|
|
|
static void
|
|
keyctl_set_timeout(struct tcb *tcp, key_serial_t id, unsigned timeout)
|
|
{
|
|
print_keyring_serial_number(id);
|
|
tprintf(", %u", timeout);
|
|
}
|
|
|
|
static void
|
|
keyctl_get_persistent(struct tcb *tcp, unsigned uid, key_serial_t id)
|
|
{
|
|
printuid("", uid);
|
|
tprints(", ");
|
|
print_keyring_serial_number(id);
|
|
}
|
|
|
|
#include "xlat/key_perms.h"
|
|
|
|
static void
|
|
keyctl_setperm_key(struct tcb *tcp, key_serial_t id, uint32_t perm)
|
|
{
|
|
print_keyring_serial_number(id);
|
|
tprints(", ");
|
|
printflags(key_perms, perm, "KEY_???");
|
|
}
|
|
|
|
static void
|
|
print_dh_params(struct tcb *tcp, kernel_ulong_t addr)
|
|
{
|
|
struct keyctl_dh_params params;
|
|
|
|
if (umove_or_printaddr(tcp, addr, ¶ms))
|
|
return;
|
|
|
|
tprints("{private=");
|
|
print_keyring_serial_number(params.private);
|
|
tprints(", prime=");
|
|
print_keyring_serial_number(params.prime);
|
|
tprints(", base=");
|
|
print_keyring_serial_number(params.base);
|
|
tprints("}");
|
|
}
|
|
|
|
static void
|
|
keyctl_dh_compute(struct tcb *tcp, kernel_ulong_t params, kernel_ulong_t buf,
|
|
kernel_ulong_t len, kernel_ulong_t kdf_addr)
|
|
{
|
|
if (entering(tcp)) {
|
|
print_dh_params(tcp, params);
|
|
tprints(", ");
|
|
} else {
|
|
struct strace_keyctl_kdf_params kdf;
|
|
|
|
if (syserror(tcp)) {
|
|
printaddr(buf);
|
|
} else {
|
|
kernel_ulong_t rval = (tcp->u_rval >= 0) &&
|
|
((kernel_ulong_t) tcp->u_rval > len) ? len :
|
|
(kernel_ulong_t) tcp->u_rval;
|
|
printstrn(tcp, buf, rval);
|
|
}
|
|
tprintf(", %llu, ", zero_extend_signed_to_ull(len));
|
|
|
|
if (fetch_keyctl_kdf_params(tcp, kdf_addr, &kdf)) {
|
|
printaddr(kdf_addr);
|
|
} else {
|
|
size_t i;
|
|
|
|
PRINT_FIELD_STR("{", kdf, hashname, tcp);
|
|
|
|
/*
|
|
* Kernel doesn't touch otherinfo
|
|
* if otherinfolen is zero.
|
|
*/
|
|
if (kdf.otherinfolen)
|
|
PRINT_FIELD_STRN(", ", kdf, otherinfo,
|
|
kdf.otherinfolen, tcp);
|
|
else
|
|
PRINT_FIELD_PTR(", ", kdf, otherinfo);
|
|
|
|
PRINT_FIELD_U(", ", kdf, otherinfolen);
|
|
|
|
/* Some future-proofing */
|
|
for (i = 0; i < ARRAY_SIZE(kdf.__spare); i++) {
|
|
if (kdf.__spare[i])
|
|
break;
|
|
}
|
|
|
|
if (i < ARRAY_SIZE(kdf.__spare)) {
|
|
tprints(", __spare=[");
|
|
|
|
for (i = 0; i < ARRAY_SIZE(kdf.__spare); i++) {
|
|
if (i)
|
|
tprints(", ");
|
|
|
|
tprintf("%#x", kdf.__spare[i]);
|
|
}
|
|
|
|
tprints("]");
|
|
}
|
|
|
|
tprints("}");
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
keyctl_restrict_keyring(struct tcb *const tcp,
|
|
const key_serial_t id,
|
|
const kernel_ulong_t addr1,
|
|
const kernel_ulong_t addr2)
|
|
{
|
|
print_keyring_serial_number(id);
|
|
tprints(", ");
|
|
printstr(tcp, addr1);
|
|
tprints(", ");
|
|
printstr(tcp, addr2);
|
|
}
|
|
|
|
#include "xlat/key_reqkeys.h"
|
|
#include "xlat/keyctl_commands.h"
|
|
|
|
SYS_FUNC(keyctl)
|
|
{
|
|
int cmd = tcp->u_arg[0];
|
|
kernel_ulong_t arg2 = tcp->u_arg[1];
|
|
kernel_ulong_t arg3 = tcp->u_arg[2];
|
|
kernel_ulong_t arg4 = tcp->u_arg[3];
|
|
kernel_ulong_t arg5 = tcp->u_arg[4];
|
|
|
|
if (entering(tcp)) {
|
|
printxval(keyctl_commands, cmd, "KEYCTL_???");
|
|
|
|
/*
|
|
* For now, KEYCTL_SESSION_TO_PARENT is the only cmd without
|
|
* arguments.
|
|
*/
|
|
if (cmd != KEYCTL_SESSION_TO_PARENT)
|
|
tprints(", ");
|
|
}
|
|
|
|
switch (cmd) {
|
|
case KEYCTL_GET_KEYRING_ID:
|
|
keyctl_get_keyring_id(tcp, arg2, arg3);
|
|
break;
|
|
|
|
case KEYCTL_JOIN_SESSION_KEYRING:
|
|
printstr(tcp, arg2);
|
|
break;
|
|
|
|
case KEYCTL_UPDATE:
|
|
keyctl_update_key(tcp, arg2, arg3, arg4);
|
|
break;
|
|
|
|
case KEYCTL_REVOKE:
|
|
case KEYCTL_CLEAR:
|
|
case KEYCTL_INVALIDATE:
|
|
case KEYCTL_ASSUME_AUTHORITY:
|
|
print_keyring_serial_number(arg2);
|
|
break;
|
|
|
|
case KEYCTL_LINK:
|
|
case KEYCTL_UNLINK:
|
|
keyctl_handle_key_key(tcp, arg2, arg3);
|
|
break;
|
|
|
|
case KEYCTL_DESCRIBE:
|
|
case KEYCTL_READ:
|
|
case KEYCTL_GET_SECURITY:
|
|
keyctl_read_key(tcp, arg2, arg3, arg4, cmd != KEYCTL_READ);
|
|
return 0;
|
|
|
|
case KEYCTL_SEARCH:
|
|
keyctl_keyring_search(tcp, arg2, arg3, arg4, arg5);
|
|
break;
|
|
|
|
case KEYCTL_CHOWN:
|
|
keyctl_chown_key(tcp, arg2, arg3, arg4);
|
|
break;
|
|
|
|
case KEYCTL_SETPERM:
|
|
keyctl_setperm_key(tcp, arg2, arg3);
|
|
break;
|
|
|
|
case KEYCTL_INSTANTIATE:
|
|
keyctl_instantiate_key(tcp, arg2, arg3, arg4, arg5);
|
|
break;
|
|
|
|
case KEYCTL_NEGATE:
|
|
keyctl_negate_key(tcp, arg2, arg3, arg4);
|
|
break;
|
|
|
|
case KEYCTL_SET_REQKEY_KEYRING:
|
|
printxvals_ex((int) arg2, "KEY_REQKEY_DEFL_???",
|
|
XLAT_STYLE_FMT_D, key_reqkeys, NULL);
|
|
break;
|
|
|
|
case KEYCTL_SET_TIMEOUT:
|
|
keyctl_set_timeout(tcp, arg2, arg3);
|
|
break;
|
|
|
|
case KEYCTL_SESSION_TO_PARENT:
|
|
break;
|
|
|
|
case KEYCTL_REJECT:
|
|
keyctl_reject_key(tcp, arg2, arg3, arg4, arg5);
|
|
break;
|
|
|
|
case KEYCTL_INSTANTIATE_IOV:
|
|
keyctl_instantiate_key_iov(tcp, arg2, arg3, arg4, arg5);
|
|
break;
|
|
|
|
case KEYCTL_GET_PERSISTENT:
|
|
keyctl_get_persistent(tcp, arg2, arg3);
|
|
break;
|
|
|
|
case KEYCTL_DH_COMPUTE:
|
|
keyctl_dh_compute(tcp, arg2, arg3, arg4, arg5);
|
|
return 0;
|
|
|
|
case KEYCTL_RESTRICT_KEYRING:
|
|
keyctl_restrict_keyring(tcp, arg2, arg3, arg4);
|
|
break;
|
|
|
|
default:
|
|
tprintf("%#" PRI_klx ", %#" PRI_klx
|
|
", %#" PRI_klx ", %#" PRI_klx,
|
|
arg2, arg3, arg4, arg5);
|
|
break;
|
|
}
|
|
|
|
return RVAL_DECODED;
|
|
}
|