keyctl: add support for KDF parameters decoding in KEYCTL_DH_COMPUTE
* fetch_struct_keyctl_kdf_params.c: New file. * keyctl_kdf_params.h: Likewise. * Makefile.am (strace_SOURCES): Add them. * configure.ac: Add check for struct keyctl_kdf_params presence in <linux/keyctl.h>. * defs.h (struct strace_keyctl_kdf_params): Add forward declaration. * keyctl.c (keyctl_dh_compute): Add new parameter kdf_addr, print it on exiting. (SYS_FUNC(keyctl)) <case KEYCTL_DH_COMPUTE>: Pass arg5 to keyctl_dh_compute. * tests/keyctl.c: Include assert.h. (struct keyctl_kdf_params) [!HAVE_STRUCT_KEYCTL_KDF_PARAMS]: New definition. (STR32): New definition, copied from ioctl_dm.c. (append_str, kckdfp_to_str): New functions. (main): Update expected output, add checks for struct keyctl_kdf_params decoding.
This commit is contained in:
parent
5a8b032f2f
commit
46a4dcf4c3
@ -126,6 +126,7 @@ strace_SOURCES = \
|
||||
fcntl.c \
|
||||
fetch_bpf_fprog.c \
|
||||
fetch_struct_flock.c \
|
||||
fetch_struct_keyctl_kdf_params.c \
|
||||
fetch_struct_mmsghdr.c \
|
||||
fetch_struct_msghdr.c \
|
||||
fetch_struct_stat.c \
|
||||
@ -162,6 +163,7 @@ strace_SOURCES = \
|
||||
kernel_types.h \
|
||||
kexec.c \
|
||||
keyctl.c \
|
||||
keyctl_kdf_params.h \
|
||||
ldt.c \
|
||||
link.c \
|
||||
linux/asm_stat.h \
|
||||
|
@ -333,6 +333,10 @@ AC_CHECK_TYPES(m4_normalize([
|
||||
struct crypto_report_rng
|
||||
]),,, [#include <linux/cryptouser.h>])
|
||||
|
||||
AC_CHECK_TYPES(m4_normalize([
|
||||
struct keyctl_kdf_params
|
||||
]),,, [#include <linux/keyctl.h>])
|
||||
|
||||
AC_CHECK_MEMBERS([struct timex.tai],,, [#include <sys/timex.h>])
|
||||
|
||||
AC_CHECK_MEMBERS([struct utsname.domainname],,, [#include <sys/utsname.h>])
|
||||
|
1
defs.h
1
defs.h
@ -645,6 +645,7 @@ struct strace_stat;
|
||||
extern void print_struct_stat(struct tcb *, const struct strace_stat *const st);
|
||||
|
||||
struct strace_statfs;
|
||||
struct strace_keyctl_kdf_params;
|
||||
|
||||
extern void
|
||||
print_struct_statfs(struct tcb *, kernel_ulong_t addr);
|
||||
|
34
fetch_struct_keyctl_kdf_params.c
Normal file
34
fetch_struct_keyctl_kdf_params.c
Normal file
@ -0,0 +1,34 @@
|
||||
#include "defs.h"
|
||||
|
||||
#include DEF_MPERS_TYPE(struct_keyctl_kdf_params)
|
||||
|
||||
#include "keyctl_kdf_params.h"
|
||||
typedef struct keyctl_kdf_params struct_keyctl_kdf_params;
|
||||
|
||||
#include MPERS_DEFS
|
||||
|
||||
MPERS_PRINTER_DECL(int, fetch_keyctl_kdf_params, struct tcb *const tcp,
|
||||
kernel_ulong_t addr, struct strace_keyctl_kdf_params *p)
|
||||
{
|
||||
struct_keyctl_kdf_params kdf;
|
||||
int ret;
|
||||
|
||||
if ((ret = umove(tcp, addr, &kdf)))
|
||||
return ret;
|
||||
|
||||
p->hashname = (kernel_ulong_t)
|
||||
#ifndef IN_MPERS
|
||||
(uintptr_t)
|
||||
#endif
|
||||
kdf.hashname;
|
||||
p->otherinfo = (kernel_ulong_t)
|
||||
#ifndef IN_MPERS
|
||||
(uintptr_t)
|
||||
#endif
|
||||
kdf.otherinfo;
|
||||
p->otherinfolen = kdf.otherinfolen;
|
||||
|
||||
memcpy(p->__spare, kdf.__spare, sizeof(kdf.__spare));
|
||||
|
||||
return 0;
|
||||
}
|
52
keyctl.c
52
keyctl.c
@ -28,6 +28,9 @@
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
#include "keyctl_kdf_params.h"
|
||||
#include "print_fields.h"
|
||||
|
||||
typedef int32_t key_serial_t;
|
||||
|
||||
#include "xlat/key_spec.h"
|
||||
@ -245,12 +248,14 @@ print_dh_params(struct tcb *tcp, kernel_ulong_t addr)
|
||||
|
||||
static void
|
||||
keyctl_dh_compute(struct tcb *tcp, kernel_ulong_t params, kernel_ulong_t buf,
|
||||
kernel_ulong_t len)
|
||||
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 {
|
||||
@ -259,7 +264,48 @@ keyctl_dh_compute(struct tcb *tcp, kernel_ulong_t params, kernel_ulong_t buf,
|
||||
(kernel_ulong_t) tcp->u_rval;
|
||||
printstrn(tcp, buf, rval);
|
||||
}
|
||||
tprintf(", %llu", zero_extend_signed_to_ull(len));
|
||||
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("}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -373,7 +419,7 @@ SYS_FUNC(keyctl)
|
||||
break;
|
||||
|
||||
case KEYCTL_DH_COMPUTE:
|
||||
keyctl_dh_compute(tcp, arg2, arg3, arg4);
|
||||
keyctl_dh_compute(tcp, arg2, arg3, arg4, arg5);
|
||||
return 0;
|
||||
|
||||
case KEYCTL_RESTRICT_KEYRING:
|
||||
|
27
keyctl_kdf_params.h
Normal file
27
keyctl_kdf_params.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef STRACE_KEYCTL_KDF_PARAMS_H
|
||||
#define STRACE_KEYCTL_KDF_PARAMS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "kernel_types.h"
|
||||
|
||||
/* from include/linux/crypto.h */
|
||||
#define CRYPTO_MAX_ALG_NAME 128
|
||||
|
||||
/* from security/keys/internal.h */
|
||||
#define KEYCTL_KDF_MAX_OI_LEN 64 /* max length of otherinfo */
|
||||
|
||||
struct keyctl_kdf_params {
|
||||
char *hashname;
|
||||
char *otherinfo;
|
||||
uint32_t otherinfolen;
|
||||
uint32_t __spare[8];
|
||||
};
|
||||
|
||||
struct strace_keyctl_kdf_params {
|
||||
kernel_ulong_t hashname;
|
||||
kernel_ulong_t otherinfo;
|
||||
uint32_t otherinfolen;
|
||||
uint32_t __spare[8];
|
||||
};
|
||||
|
||||
#endif /* STRACE_KEYCTL_KDF_PARAMS_H */
|
196
tests/keyctl.c
196
tests/keyctl.c
@ -36,6 +36,7 @@
|
||||
# include <linux/types.h>
|
||||
# include <linux/keyctl.h>
|
||||
|
||||
# include <assert.h>
|
||||
# include <errno.h>
|
||||
# include <inttypes.h>
|
||||
# include <stdarg.h>
|
||||
@ -55,6 +56,15 @@ struct keyctl_dh_params {
|
||||
};
|
||||
# endif
|
||||
|
||||
# ifndef HAVE_STRUCT_KEYCTL_KDF_PARAMS
|
||||
struct keyctl_kdf_params {
|
||||
char *hashname;
|
||||
char *otherinfo;
|
||||
uint32_t otherinfolen;
|
||||
uint32_t __spare[8];
|
||||
};
|
||||
# endif
|
||||
|
||||
# include "xlat.h"
|
||||
# include "xlat/keyctl_commands.h"
|
||||
|
||||
@ -76,6 +86,9 @@ static const size_t limit = 10;
|
||||
bool nul_terminated_buf = true;
|
||||
bool buf_in_arg;
|
||||
|
||||
/* From ioctl_dm.c */
|
||||
# define STR32 "AbCdEfGhIjKlMnOpQrStUvWxYz012345"
|
||||
|
||||
/*
|
||||
* When this is called with positive size, the buffer provided is an "out"
|
||||
* argument and rc contains resulting size (globally defined nul_terminated_buf
|
||||
@ -182,6 +195,85 @@ do_keyctl(kernel_ulong_t cmd, const char *cmd_str, ...)
|
||||
printf(") = %s\n", errstr);
|
||||
}
|
||||
|
||||
int
|
||||
append_str(char **buf, size_t *left, const char *fmt, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
ret = vsnprintf(*buf, *left, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
assert((ret >= 0) && ((unsigned) ret < *left));
|
||||
|
||||
*left -= ret;
|
||||
*buf += ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char *
|
||||
kckdfp_to_str(struct keyctl_kdf_params *kdf, bool deref_hash, bool deref_oi,
|
||||
bool print_spare, const char *hash_str, const char *oi_str)
|
||||
{
|
||||
static char buf[4096];
|
||||
|
||||
size_t left = sizeof(buf);
|
||||
char *pos = buf;
|
||||
|
||||
append_str(&pos, &left, "{hashname=");
|
||||
|
||||
if (deref_hash && hash_str) {
|
||||
append_str(&pos, &left, "%s", hash_str);
|
||||
} else if (!kdf->hashname) {
|
||||
append_str(&pos, &left, "NULL");
|
||||
} else if (deref_hash) {
|
||||
append_str(&pos, &left, "\"%.*s\"", limit, kdf->hashname);
|
||||
|
||||
if (strnlen(kdf->hashname, limit + 1) > limit)
|
||||
append_str(&pos, &left, "...");
|
||||
} else {
|
||||
append_str(&pos, &left, "%p", kdf->hashname);
|
||||
}
|
||||
|
||||
append_str(&pos, &left, ", otherinfo=");
|
||||
|
||||
if (deref_oi && oi_str) {
|
||||
append_str(&pos, &left, "%s", oi_str);
|
||||
} else if (!kdf->otherinfo) {
|
||||
append_str(&pos, &left, "NULL");
|
||||
} else if (deref_oi) {
|
||||
append_str(&pos, &left, "\"%.*s\"", limit, kdf->otherinfo);
|
||||
|
||||
if (strnlen(kdf->otherinfo, limit + 1) > limit)
|
||||
append_str(&pos, &left, "...");
|
||||
} else {
|
||||
append_str(&pos, &left, "%p", kdf->otherinfo);
|
||||
}
|
||||
|
||||
append_str(&pos, &left, ", otherinfolen=%u", kdf->otherinfolen);
|
||||
|
||||
if (print_spare) {
|
||||
size_t i;
|
||||
|
||||
append_str(&pos, &left, ", __spare=[");
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(kdf->__spare); i++) {
|
||||
if (i)
|
||||
append_str(&pos, &left, ", ");
|
||||
|
||||
append_str(&pos, &left, "%#x", kdf->__spare[i]);
|
||||
}
|
||||
|
||||
append_str(&pos, &left, "]");
|
||||
}
|
||||
|
||||
append_str(&pos, &left, "}");
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
@ -210,6 +302,32 @@ main(void)
|
||||
static const char *kcdhp_str = "{private=KEY_SPEC_GROUP_KEYRING, "
|
||||
"prime=1234567890, base=-1153374643}";
|
||||
|
||||
/*
|
||||
* It's bigger than current hash name size limit, but since it's
|
||||
* implementation-dependent and totally internal, we do not rely
|
||||
* on it much.
|
||||
*/
|
||||
static const char long_hash_data[] = STR32 STR32 STR32 STR32 "xxx";
|
||||
static const char short_hash_data[] = "hmac(aes)";
|
||||
static const char otherinfo1_data[] = "\1\2 OH HAI THAR\255\0\1";
|
||||
static const char otherinfo2_data[] = "\1\2\n\255\0\1";
|
||||
static const struct keyctl_kdf_params kckdfp_data[] = {
|
||||
[0] = { NULL, NULL, 0, { 0 } },
|
||||
[1] = { NULL /* Changed to unaccessible address in copy */,
|
||||
NULL, 0xbadc0dedU, { [7] = 0xdeadfeedU } },
|
||||
[2] = { NULL /* long_hash_data */,
|
||||
NULL /* Changed to unaccessible address in copy */,
|
||||
0, { 0 } },
|
||||
[3] = { NULL /* unterminated1 */,
|
||||
NULL /* otherinfo_data */, 0, { 1 } },
|
||||
[4] = { NULL /* short_hash_data */,
|
||||
NULL /* otherinfo1_data */, sizeof(otherinfo1_data),
|
||||
{ 0, 0xfacebeef, 0, 0xba5e1ead } },
|
||||
[5] = { NULL /* short_hash_data */,
|
||||
NULL /* otherinfo2_data */, sizeof(otherinfo2_data),
|
||||
{ 0 } },
|
||||
};
|
||||
|
||||
char *bogus_str = tail_memdup(unterminated1, sizeof(unterminated1));
|
||||
char *bogus_desc = tail_memdup(unterminated2, sizeof(unterminated2));
|
||||
char *short_type = tail_memdup(short_type_str, sizeof(short_type_str));
|
||||
@ -217,6 +335,15 @@ main(void)
|
||||
char *long_type = tail_memdup(long_type_str, sizeof(long_type_str));
|
||||
char *long_desc = tail_memdup(long_desc_str, sizeof(long_desc_str));
|
||||
char *kcdhp = tail_memdup(&kcdhp_data, sizeof(kcdhp_data));
|
||||
char *kckdfp_long_hash = tail_memdup(long_hash_data,
|
||||
sizeof(long_hash_data));
|
||||
char *kckdfp_short_hash = tail_memdup(short_hash_data,
|
||||
sizeof(short_hash_data));
|
||||
char *kckdfp_otherinfo1 = tail_memdup(otherinfo1_data,
|
||||
sizeof(otherinfo1_data));
|
||||
char *kckdfp_otherinfo2 = tail_memdup(otherinfo2_data,
|
||||
sizeof(otherinfo2_data));
|
||||
char *kckdfp_char = tail_alloc(sizeof(kckdfp_data[0]));
|
||||
struct iovec *key_iov = tail_alloc(sizeof(*key_iov) * IOV_SIZE);
|
||||
char *bogus_buf1 = tail_alloc(9);
|
||||
char *bogus_buf2 = tail_alloc(256);
|
||||
@ -224,7 +351,7 @@ main(void)
|
||||
char *key_iov_str2 = tail_alloc(4096);
|
||||
ssize_t ret;
|
||||
ssize_t kis_size = 0;
|
||||
int i;
|
||||
size_t i;
|
||||
|
||||
key_iov[0].iov_base = short_type;
|
||||
key_iov[0].iov_len = sizeof(short_type_str);
|
||||
@ -845,28 +972,85 @@ main(void)
|
||||
sizeof(char *), ARG_STR(NULL), ptr_fmt,
|
||||
sizeof(kernel_ulong_t),
|
||||
(kernel_ulong_t) 0xfeedf157badc0dedLLU, NULL, ksize_fmt,
|
||||
0UL);
|
||||
sizeof(char *), ARG_STR(NULL), ptr_fmt);
|
||||
do_keyctl(ARG_STR(KEYCTL_DH_COMPUTE),
|
||||
sizeof(char *), kcdhp + 1, NULL, ptr_fmt,
|
||||
sizeof(char *), (char *) 0xfffff157ffffdeadULL, NULL, ptr_fmt,
|
||||
sizeof(kernel_ulong_t),
|
||||
(kernel_ulong_t) 0xfeedf157badc0dedLLU, NULL, ksize_fmt,
|
||||
0UL);
|
||||
sizeof(char *), ARG_STR(NULL), ptr_fmt);
|
||||
do_keyctl(ARG_STR(KEYCTL_DH_COMPUTE),
|
||||
sizeof(kcdhp), kcdhp, kcdhp_str, NULL,
|
||||
(size_t) 9, (uintptr_t) bogus_buf1, NULL, NULL,
|
||||
sizeof(kernel_ulong_t), (kernel_ulong_t) 9, NULL, ksize_fmt,
|
||||
0UL);
|
||||
sizeof(char *), ARG_STR(NULL), ptr_fmt);
|
||||
do_keyctl(ARG_STR(KEYCTL_DH_COMPUTE),
|
||||
sizeof(kcdhp), kcdhp, kcdhp_str, NULL,
|
||||
(size_t) 256, (uintptr_t) bogus_buf2, NULL, NULL,
|
||||
sizeof(kernel_ulong_t), (kernel_ulong_t) 256, NULL, ksize_fmt,
|
||||
0UL);
|
||||
sizeof(char *), ARG_STR(NULL), ptr_fmt);
|
||||
do_keyctl(ARG_STR(KEYCTL_DH_COMPUTE),
|
||||
sizeof(kcdhp), kcdhp, kcdhp_str, NULL,
|
||||
(size_t) -1, (uintptr_t) bogus_buf2, NULL, NULL,
|
||||
sizeof(kernel_ulong_t), (kernel_ulong_t) -1, NULL, ksize_fmt,
|
||||
0UL);
|
||||
sizeof(char *), kckdfp_char + 1, NULL, ptr_fmt);
|
||||
|
||||
/* KEYCTL_DH_COMPUTE + KDF */
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(kckdfp_data); i++) {
|
||||
struct keyctl_kdf_params *kckdfp =
|
||||
(struct keyctl_kdf_params *) kckdfp_char;
|
||||
bool deref_hash = true;
|
||||
bool deref_opts = true;
|
||||
bool print_spare = false;
|
||||
const char *hash_str = NULL;
|
||||
const char *oi_str = NULL;
|
||||
|
||||
memcpy(kckdfp, kckdfp_data + i, sizeof(kckdfp_data[i]));
|
||||
|
||||
switch (i) {
|
||||
case 1:
|
||||
deref_hash = false;
|
||||
print_spare = true;
|
||||
kckdfp->hashname =
|
||||
kckdfp_short_hash + sizeof(short_hash_data);
|
||||
break;
|
||||
case 2:
|
||||
deref_opts = false;
|
||||
kckdfp->hashname = kckdfp_long_hash;
|
||||
kckdfp->otherinfo =
|
||||
kckdfp_otherinfo1 + sizeof(otherinfo1_data);
|
||||
break;
|
||||
case 3:
|
||||
deref_opts = false;
|
||||
deref_hash = false;
|
||||
print_spare = true;
|
||||
kckdfp->hashname = bogus_str;
|
||||
kckdfp->otherinfo = kckdfp_otherinfo1;
|
||||
break;
|
||||
case 4:
|
||||
oi_str = "\"\\1\\2 OH HAI \"...";
|
||||
print_spare = true;
|
||||
kckdfp->hashname = kckdfp_short_hash;
|
||||
kckdfp->otherinfo = kckdfp_otherinfo1;
|
||||
break;
|
||||
case 5:
|
||||
oi_str = "\"\\1\\2\\n\\255\\0\\1\\0\"";
|
||||
kckdfp->hashname = kckdfp_short_hash;
|
||||
kckdfp->otherinfo = kckdfp_otherinfo2;
|
||||
break;
|
||||
}
|
||||
|
||||
do_keyctl(ARG_STR(KEYCTL_DH_COMPUTE),
|
||||
sizeof(kcdhp), kcdhp, kcdhp_str, NULL,
|
||||
(size_t) -1, (uintptr_t) bogus_buf2, NULL, NULL,
|
||||
sizeof(kernel_ulong_t), (kernel_ulong_t) -1, NULL,
|
||||
ksize_fmt,
|
||||
sizeof(kckdfp), kckdfp_char,
|
||||
kckdfp_to_str(kckdfp, deref_hash, deref_opts,
|
||||
print_spare, hash_str, oi_str),
|
||||
NULL);
|
||||
}
|
||||
|
||||
nul_terminated_buf = true;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user