From b9bcc23a401fa82f8d76011c78d9a183971e5054 Mon Sep 17 00:00:00 2001 From: "Dmitry V. Levin" Date: Thu, 27 Jun 2019 16:51:33 +0000 Subject: [PATCH] Implement decoding of fsconfig syscall ... introduced by Linux kernel commits v5.2-rc1~141^2~3, v5.2-rc1~20^2~1, and v5.2-rc1~20^2. * fsconfig.c: New file. * Makefile.am (strace_SOURCES): Add it. * pathtrace.c (pathtrace_match_set): Add SEN_fsconfig. * xlat/fsconfig_cmds.in: New file. * linux/syscallent-common.h [BASE_NR + 431]: Wire up fsconfig. * NEWS: Mention this change. * tests/fsconfig.c: New file. * tests/fsconfig-P.c: Likewise. * tests/gen_tests.in (fsconfig, fsconfig-P): New entries. * tests/pure_executables.list: Add fsconfig and fsconfig-P. * tests/.gitignore: Likewise. --- Makefile.am | 1 + NEWS | 3 +- fsconfig.c | 88 +++++++++++ linux/syscallent-common.h | 1 + pathtrace.c | 15 ++ tests/.gitignore | 2 + tests/fsconfig-P.c | 2 + tests/fsconfig.c | 299 ++++++++++++++++++++++++++++++++++++ tests/gen_tests.in | 2 + tests/pure_executables.list | 2 + xlat/fsconfig_cmds.in | 9 ++ 11 files changed, 423 insertions(+), 1 deletion(-) create mode 100644 fsconfig.c create mode 100644 tests/fsconfig-P.c create mode 100644 tests/fsconfig.c create mode 100644 xlat/fsconfig_cmds.in diff --git a/Makefile.am b/Makefile.am index 9fe5055a..e22a1ced 100644 --- a/Makefile.am +++ b/Makefile.am @@ -132,6 +132,7 @@ strace_SOURCES = \ flock.c \ flock.h \ fs_x_ioctl.c \ + fsconfig.c \ fsopen.c \ futex.c \ gcc_compat.h \ diff --git a/NEWS b/NEWS index 75bed509..ef9da37b 100644 --- a/NEWS +++ b/NEWS @@ -2,7 +2,8 @@ Noteworthy changes in release ?.? (????-??-??) ============================================== * Improvements - * Implemented decoding of open_tree, move_mount, and fsopen syscalls. + * Implemented decoding of open_tree, move_mount, fsopen, and fsconfig + syscalls. * Enhanced decoding of clone syscall. * Updated lists of AT_*, AUDIT_*, CLONE_*, ETH_*, KEY_*, KVM_*, TIPC_*, and V4L2_* constants. diff --git a/fsconfig.c b/fsconfig.c new file mode 100644 index 00000000..7be095b0 --- /dev/null +++ b/fsconfig.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2019 Dmitry V. Levin + * All rights reserved. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#include "defs.h" +#ifdef HAVE_LINUX_MOUNT_H +# include +#endif +#include "xlat/fsconfig_cmds.h" + +SYS_FUNC(fsconfig) +{ + const int fs_fd = tcp->u_arg[0]; + const unsigned int cmd = tcp->u_arg[1]; + const kernel_ulong_t key = tcp->u_arg[2]; + const kernel_ulong_t value = tcp->u_arg[3]; + const int aux = tcp->u_arg[4]; + + printfd(tcp, fs_fd); + tprints(", "); + + printxval_index(fsconfig_cmds, cmd, "FSCONFIG_???"); + tprints(", "); + + switch (cmd) { + case FSCONFIG_SET_FLAG: + case FSCONFIG_SET_STRING: + case FSCONFIG_SET_BINARY: + case FSCONFIG_SET_PATH: + case FSCONFIG_SET_PATH_EMPTY: + case FSCONFIG_SET_FD: + printstr_ex(tcp, key, 256, QUOTE_0_TERMINATED); + break; + case FSCONFIG_CMD_CREATE: + case FSCONFIG_CMD_RECONFIGURE: + default: + printaddr(key); + break; + } + tprints(", "); + + switch (cmd) { + case FSCONFIG_SET_STRING: + printstr_ex(tcp, value, 256, QUOTE_0_TERMINATED); + break; + case FSCONFIG_SET_PATH: + case FSCONFIG_SET_PATH_EMPTY: + printpath(tcp, value); + break; + case FSCONFIG_SET_BINARY: + if (aux >= 0 && aux <= 1024 * 1024) { + printstr_ex(tcp, value, aux, QUOTE_FORCE_HEX); + break; + } + ATTRIBUTE_FALLTHROUGH; + case FSCONFIG_SET_FLAG: + case FSCONFIG_SET_FD: + case FSCONFIG_CMD_CREATE: + case FSCONFIG_CMD_RECONFIGURE: + default: + printaddr(value); + break; + } + tprints(", "); + + switch (cmd) { + case FSCONFIG_SET_PATH: + case FSCONFIG_SET_PATH_EMPTY: + print_dirfd(tcp, aux); + break; + case FSCONFIG_SET_FD: + printfd(tcp, aux); + break; + case FSCONFIG_SET_FLAG: + case FSCONFIG_SET_STRING: + case FSCONFIG_SET_BINARY: + case FSCONFIG_CMD_CREATE: + case FSCONFIG_CMD_RECONFIGURE: + default: + tprintf("%d", aux); + break; + } + + return RVAL_DECODED; +} diff --git a/linux/syscallent-common.h b/linux/syscallent-common.h index abad8805..c2e844ea 100644 --- a/linux/syscallent-common.h +++ b/linux/syscallent-common.h @@ -15,3 +15,4 @@ [BASE_NR + 428] = { 3, TD|TF, SEN(open_tree), "open_tree" }, [BASE_NR + 429] = { 5, TD|TF, SEN(move_mount), "move_mount" }, [BASE_NR + 430] = { 2, TD, SEN(fsopen), "fsopen" }, +[BASE_NR + 431] = { 5, TD|TF, SEN(fsconfig), "fsconfig" }, diff --git a/pathtrace.c b/pathtrace.c index 6de690e9..3c09bc32 100644 --- a/pathtrace.c +++ b/pathtrace.c @@ -318,6 +318,21 @@ pathtrace_match_set(struct tcb *tcp, struct path_set *set) return false; } + case SEN_fsconfig: { + /* x, x, x, maybe path, maybe fd */ + const unsigned int cmd = tcp->u_arg[1]; + switch (cmd) { + case 3 /* FSCONFIG_SET_PATH */: + case 4 /* FSCONFIG_SET_PATH_EMPTY */: + return fdmatch(tcp, tcp->u_arg[4], set) || + upathmatch(tcp, tcp->u_arg[3], set); + case 5 /* FSCONFIG_SET_FD */: + return fdmatch(tcp, tcp->u_arg[4], set); + } + + return false; + } + case SEN_accept4: case SEN_accept: case SEN_bpf: diff --git a/tests/.gitignore b/tests/.gitignore index c0d5bd7b..2b8e500a 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -89,6 +89,8 @@ filter-unavailable finit_module flock fork-f +fsconfig +fsconfig-P fsopen fstat fstat-Xabbrev diff --git a/tests/fsconfig-P.c b/tests/fsconfig-P.c new file mode 100644 index 00000000..b763332c --- /dev/null +++ b/tests/fsconfig-P.c @@ -0,0 +1,2 @@ +#define PATH_TRACING +#include "fsconfig.c" diff --git a/tests/fsconfig.c b/tests/fsconfig.c new file mode 100644 index 00000000..e5ece516 --- /dev/null +++ b/tests/fsconfig.c @@ -0,0 +1,299 @@ +/* + * Check decoding of fsconfig syscall. + * + * Copyright (c) 2019 Dmitry V. Levin + * All rights reserved. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "tests.h" +#include +#include "scno.h" + +#ifdef __NR_fsconfig + +# include +# include +# include +# include +# include + +# define XLAT_MACROS_ONLY +# include "xlat/fsconfig_cmds.h" +# undef XLAT_MACROS_ONLY + +static const char *errstr; + +static long +k_fsconfig(const unsigned int fs_fd, + const unsigned int cmd, + const void *key, + const void *value, + const unsigned int aux) +{ + const kernel_ulong_t fill = (kernel_ulong_t) 0xdefaced00000000ULL; + const kernel_ulong_t bad = (kernel_ulong_t) 0xbadc0dedbadc0dedULL; + const kernel_ulong_t arg1 = fill | fs_fd; + const kernel_ulong_t arg2 = fill | cmd; + const kernel_ulong_t arg3 = (uintptr_t) key; + const kernel_ulong_t arg4 = (uintptr_t) value; + const kernel_ulong_t arg5 = fill | aux; + const long rc = syscall(__NR_fsconfig, + arg1, arg2, arg3, arg4, arg5, bad); + errstr = sprintrc(rc); + return rc; +} + +static const char path_full[] = "/dev/full"; +static const int max_string_size = 256; +static const int max_blob_size = 300; +static const int huge_blob_size = 1024 * 1024 + 1; +static const char *fd_path; +static const void *efault; +static const char *empty; +static char *fname; +static char *key1; +static char *key; +static char *val1; +static char *val; +static char *blob1; +static char *blob; +static int fd; + +static void +test_fsconfig_unknown(void) +{ + k_fsconfig(fd, 8, empty, val, -100); +# ifndef PATH_TRACING + printf("fsconfig(%d<%s>, 0x8 /* FSCONFIG_??? */, %p, %p, -100) = %s\n", + fd, fd_path, empty, val, errstr); +# endif + + k_fsconfig(-100, -1, empty, fd_path, fd); +# ifndef PATH_TRACING + printf("fsconfig(-100, 0xffffffff /* FSCONFIG_??? */, %p, %p, %d)" + " = %s\n", + empty, fd_path, fd, errstr); +# endif +} + +static void +test_fsconfig_cmd(const unsigned int cmd, const char *cmd_str) +{ + k_fsconfig(fd, cmd, empty, val, -100); +# ifndef PATH_TRACING + printf("fsconfig(%d<%s>, %s, %p, %p, -100) = %s\n", + fd, fd_path, cmd_str, empty, val, errstr); +# endif + + k_fsconfig(-100, cmd, empty, fd_path, fd); +# ifndef PATH_TRACING + printf("fsconfig(-100, %s, %p, %p, %d) = %s\n", + cmd_str, empty, fd_path, fd, errstr); +# endif +} + +static void +test_fsconfig_set_flag(const unsigned int cmd, const char *cmd_str) +{ + k_fsconfig(fd, cmd, key, val, -100); +# ifndef PATH_TRACING + printf("fsconfig(%d<%s>, %s, \"%s\", %p, -100) = %s\n", + fd, fd_path, cmd_str, key, val, errstr); +# endif + + k_fsconfig(fd, cmd, key1, val, -100); +# ifndef PATH_TRACING + printf("fsconfig(%d<%s>, %s, \"%.*s\"..., %p, -100) = %s\n", + fd, fd_path, cmd_str, max_string_size, key1, val, errstr); +# endif + + k_fsconfig(-100, cmd, key, fd_path, fd); +# ifndef PATH_TRACING + printf("fsconfig(-100, %s, \"%s\", %p, %d) = %s\n", + cmd_str, key, fd_path, fd, errstr); +# endif +} + +static void +test_fsconfig_set_string(const unsigned int cmd, const char *cmd_str) +{ + k_fsconfig(fd, cmd, key, val, -100); +# ifndef PATH_TRACING + printf("fsconfig(%d<%s>, %s, \"%s\", \"%s\", -100) = %s\n", + fd, fd_path, cmd_str, key, val, errstr); +# endif + + k_fsconfig(fd, cmd, key1, val1, -100); +# ifndef PATH_TRACING + printf("fsconfig(%d<%s>, %s, \"%.*s\"..., \"%.*s\"..., -100) = %s\n", + fd, fd_path, cmd_str, max_string_size, key1, max_string_size, val1, + errstr); +# endif + + k_fsconfig(-100, cmd, key, fd_path, fd); +# ifndef PATH_TRACING + printf("fsconfig(-100, %s, \"%s\", \"%s\", %d) = %s\n", + cmd_str, key, fd_path, fd, errstr); +# endif +} + +static void +test_fsconfig_set_binary(const unsigned int cmd, const char *cmd_str) +{ + k_fsconfig(fd, cmd, key, blob, max_blob_size); +# ifndef PATH_TRACING + printf("fsconfig(%d<%s>, %s, \"%s\", ", fd, fd_path, cmd_str, key); + print_quoted_hex(blob, max_blob_size); + printf(", %d) = %s\n", max_blob_size, errstr); +# endif + + k_fsconfig(fd, cmd, key1, blob1, max_blob_size + 1); +# ifndef PATH_TRACING + printf("fsconfig(%d<%s>, %s, \"%.*s\"..., ", + fd, fd_path, cmd_str, max_string_size, key1); + print_quoted_hex(blob1, max_blob_size); + printf("..., %d) = %s\n", max_blob_size + 1, errstr); +# endif + + k_fsconfig(fd, cmd, key, empty, 0); +# ifndef PATH_TRACING + printf("fsconfig(%d<%s>, %s, \"%s\", \"\", 0) = %s\n", + fd, fd_path, cmd_str, key, errstr); +# endif + + k_fsconfig(fd, cmd, key, fname, -100); +# ifndef PATH_TRACING + printf("fsconfig(%d<%s>, %s, \"%s\", %p, -100) = %s\n", + fd, fd_path, cmd_str, key, fname, errstr); +# endif + + k_fsconfig(fd, cmd, key, fname, huge_blob_size); +# ifndef PATH_TRACING + printf("fsconfig(%d<%s>, %s, \"%s\", %p, %d) = %s\n", + fd, fd_path, cmd_str, key, fname, huge_blob_size, errstr); +# endif + + k_fsconfig(-100, cmd, key, fd_path, sizeof(path_full)); +# ifndef PATH_TRACING + printf("fsconfig(-100, %s, \"%s\", ", cmd_str, key); + print_quoted_hex(fd_path, sizeof(path_full)); + printf(", %d) = %s\n", (int) sizeof(path_full), errstr); +# endif + + k_fsconfig(-100, cmd, key, fname, fd); +# ifndef PATH_TRACING + printf("fsconfig(-100, %s, \"%s\", ", cmd_str, key); + print_quoted_hex(fname, fd); + printf(", %d) = %s\n", fd, errstr); +# endif +} + +static void +test_fsconfig_set_path(const unsigned int cmd, const char *cmd_str) +{ + fill_memory_ex(fname, PATH_MAX, '0', 10); + k_fsconfig(fd, cmd, key, fname, -100); +# ifndef PATH_TRACING + printf("fsconfig(%d<%s>, %s, \"%s\", \"%.*s\"..., AT_FDCWD) = %s\n", + fd, fd_path, cmd_str, key, (int) PATH_MAX - 1, fname, errstr); +# endif + + fname[PATH_MAX - 1] = '\0'; + k_fsconfig(fd, cmd, key, fname, -1); +# ifndef PATH_TRACING + printf("fsconfig(%d<%s>, %s, \"%s\", \"%s\", -1) = %s\n", + fd, fd_path, cmd_str, key, fname, errstr); +# endif + + k_fsconfig(-100, cmd, key, empty, fd); + printf("fsconfig(-100, %s, \"%s\", \"\", %d<%s>) = %s\n", + cmd_str, key, fd, fd_path, errstr); + + k_fsconfig(-1, cmd, 0, fd_path, -100); + printf("fsconfig(-1, %s, NULL, \"%s\", AT_FDCWD) = %s\n", + cmd_str, fd_path, errstr); + + k_fsconfig(-1, cmd, efault, efault + 1, fd); + printf("fsconfig(-1, %s, %p, %p, %d<%s>) = %s\n", + cmd_str, efault, efault + 1, fd, fd_path, errstr); + + k_fsconfig(-100, cmd, key, fname, -1); +# ifndef PATH_TRACING + printf("fsconfig(-100, %s, \"%s\", \"%s\", -1) = %s\n", + cmd_str, key, fname, errstr); +# endif +} + +static void +test_fsconfig_set_fd(const unsigned int cmd, const char *cmd_str) +{ + k_fsconfig(fd, cmd, key, val, -100); +# ifndef PATH_TRACING + printf("fsconfig(%d<%s>, %s, \"%s\", %p, -100) = %s\n", + fd, fd_path, cmd_str, key, val, errstr); +# endif + + k_fsconfig(-100, cmd, key1, 0, fd); + printf("fsconfig(-100, %s, \"%.*s\"..., NULL, %d<%s>) = %s\n", + cmd_str, max_string_size, key1, fd, fd_path, errstr); + + k_fsconfig(-1, cmd, efault, efault + 1, fd); + printf("fsconfig(-1, %s, %p, %p, %d<%s>) = %s\n", + cmd_str, efault, efault + 1, fd, fd_path, errstr); + + k_fsconfig(-100, cmd, key, fd_path, -1); +# ifndef PATH_TRACING + printf("fsconfig(-100, %s, \"%s\", %p, -1) = %s\n", + cmd_str, key, fd_path, errstr); +# endif +} + +int +main(void) +{ + skip_if_unavailable("/proc/self/fd/"); + + fd_path = tail_memdup(path_full, sizeof(path_full)); + efault = fd_path + sizeof(path_full); + empty = efault - 1; + fname = tail_alloc(PATH_MAX); + key1 = tail_alloc(max_string_size + 1); + key = key1 + 1; + val1 = tail_alloc(max_string_size + 1); + val = val1 + 1; + blob1 = tail_alloc(max_blob_size + 1); + blob = blob1 + 1; + + fill_memory_ex(fname, PATH_MAX, '0', 10); + fill_memory_ex(key1, max_string_size, 'a', 'z' - 'a' + 1); + key1[max_string_size] = '\0'; + fill_memory_ex(val1, max_string_size, 'A', 'Z' - 'A' + 1); + val1[max_string_size] = '\0'; + fill_memory_ex(blob, max_blob_size, '0', 10); + blob[0] = 0; + blob1[0] = 0; + fd = open(fd_path, O_WRONLY); + if (fd < 0) + perror_msg_and_fail("open: %s", fd_path); + + test_fsconfig_unknown(); + test_fsconfig_set_flag(ARG_STR(FSCONFIG_SET_FLAG)); + test_fsconfig_set_string(ARG_STR(FSCONFIG_SET_STRING)); + test_fsconfig_set_binary(ARG_STR(FSCONFIG_SET_BINARY)); + test_fsconfig_set_path(ARG_STR(FSCONFIG_SET_PATH)); + test_fsconfig_set_path(ARG_STR(FSCONFIG_SET_PATH_EMPTY)); + test_fsconfig_set_fd(ARG_STR(FSCONFIG_SET_FD)); + test_fsconfig_cmd(ARG_STR(FSCONFIG_CMD_CREATE)); + test_fsconfig_cmd(ARG_STR(FSCONFIG_CMD_RECONFIGURE)); + + puts("+++ exited with 0 +++"); + return 0; +} + +#else + +SKIP_MAIN_UNDEFINED("__NR_fsconfig") + +#endif diff --git a/tests/gen_tests.in b/tests/gen_tests.in index f2377556..7cbfc417 100644 --- a/tests/gen_tests.in +++ b/tests/gen_tests.in @@ -68,6 +68,8 @@ file_ioctl +ioctl.test finit_module -a25 flock -a19 fork-f -a26 -qq -f -e signal=none -e trace=chdir +fsconfig -s300 -y +fsconfig-P -s300 -y -P /dev/full -e trace=fsconfig fsopen -a35 fstat -a15 -v -P stat.sample fstat-Xabbrev -a15 -v -Xabbrev -P stat.sample -e trace=fstat diff --git a/tests/pure_executables.list b/tests/pure_executables.list index 9f57ad56..9fa551a8 100755 --- a/tests/pure_executables.list +++ b/tests/pure_executables.list @@ -71,6 +71,8 @@ file_handle file_ioctl finit_module flock +fsconfig +fsconfig-P fsopen fstat fstat-Xabbrev diff --git a/xlat/fsconfig_cmds.in b/xlat/fsconfig_cmds.in new file mode 100644 index 00000000..be33679b --- /dev/null +++ b/xlat/fsconfig_cmds.in @@ -0,0 +1,9 @@ +#value_indexed +FSCONFIG_SET_FLAG 0 +FSCONFIG_SET_STRING 1 +FSCONFIG_SET_BINARY 2 +FSCONFIG_SET_PATH 3 +FSCONFIG_SET_PATH_EMPTY 4 +FSCONFIG_SET_FD 5 +FSCONFIG_CMD_CREATE 6 +FSCONFIG_CMD_RECONFIGURE 7 -- 2.40.0