From: Thomas Weißschuh Date: Mon, 26 Jun 2023 18:25:18 +0000 (+0200) Subject: enosys: add support for ioctl blocking X-Git-Tag: v2.40-rc1~275^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=65bf3c73f1b813135c47c778dd5e396d62151c35;p=thirdparty%2Futil-linux.git enosys: add support for ioctl blocking Ioctls are blocked with ENOTTY. Signed-off-by: Thomas Weißschuh --- diff --git a/bash-completion/enosys b/bash-completion/enosys index 61aff46c84..7ce7609a75 100644 --- a/bash-completion/enosys +++ b/bash-completion/enosys @@ -8,9 +8,15 @@ _waitpid_module() '-s'|'--syscall') return 0 ;; + '-i'|'--ioctl') + return 0 + ;; '-l'|'--list') return 0 ;; + '-m'|'--list-ioctl') + return 0 + ;; '-h'|'--help'|'-V'|'--version') return 0 ;; @@ -18,7 +24,9 @@ _waitpid_module() case $cur in -*) OPTS="--syscall + --ioctl --list + --list-ioctl --help --version" COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) ) diff --git a/misc-utils/enosys.1.adoc b/misc-utils/enosys.1.adoc index 9ce272860b..a9bc693b1e 100644 --- a/misc-utils/enosys.1.adoc +++ b/misc-utils/enosys.1.adoc @@ -27,9 +27,15 @@ syscalls as would happen when running on old kernels. *-s*, *--syscall*:: Syscall to block. Can be specified multiple times. +*-i*, *--ioctl*:: +Ioctl to block. Can be specified multiple times. + *-l*, *--list*:: List syscalls known to *enosys*. +*-m*, *--list-ioctl*:: +List ioctls known to *enosys*. + include::man-common/help-version.adoc[] == EXIT STATUS diff --git a/misc-utils/enosys.c b/misc-utils/enosys.c index 0f7a16e0df..6754dd235f 100644 --- a/misc-utils/enosys.c +++ b/misc-utils/enosys.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "c.h" #include "exitcodes.h" @@ -64,6 +65,11 @@ static const struct syscall syscalls[] = { }; static_assert(sizeof(syscalls) > 0, "no syscalls found"); +static const struct syscall ioctls[] = { + { "FIOCLEX", FIOCLEX }, +}; +static_assert(sizeof(ioctls) > 0, "no ioctls found"); + static void __attribute__((__noreturn__)) usage(void) { FILE *out = stdout; @@ -73,6 +79,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(USAGE_OPTIONS, out); fputs(_(" -s, --syscall syscall to block\n"), out); + fputs(_(" -i, --ioctl ioctl to block\n"), out); fputs(_(" -l, --list list known syscalls\n"), out); fputs(USAGE_SEPARATOR, out); @@ -94,24 +101,28 @@ int main(int argc, char **argv) size_t i; bool found; static const struct option longopts[] = { - { "syscall", required_argument, NULL, 's' }, - { "list", no_argument, NULL, 'l' }, - { "version", no_argument, NULL, 'V' }, - { "help", no_argument, NULL, 'h' }, + { "syscall", required_argument, NULL, 's' }, + { "ioctl", required_argument, NULL, 'i' }, + { "list", no_argument, NULL, 'l' }, + { "list-ioctl", no_argument, NULL, 'm' }, + { "version", no_argument, NULL, 'V' }, + { "help", no_argument, NULL, 'h' }, { 0 } }; long blocked_number; struct blocked_number *blocked; + struct list_head *loop_ctr; struct list_head blocked_syscalls; INIT_LIST_HEAD(&blocked_syscalls); - struct list_head *loop_ctr; + struct list_head blocked_ioctls; + INIT_LIST_HEAD(&blocked_ioctls); setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); - while ((c = getopt_long (argc, argv, "+Vhs:l", longopts, NULL)) != -1) { + while ((c = getopt_long (argc, argv, "+Vhs:i:lm", longopts, NULL)) != -1) { switch (c) { case 's': found = 0; @@ -130,11 +141,33 @@ int main(int argc, char **argv) blocked->number = blocked_number; list_add(&blocked->head, &blocked_syscalls); + break; + case 'i': + found = 0; + for (i = 0; i < ARRAY_SIZE(ioctls); i++) { + if (strcmp(optarg, ioctls[i].name) == 0) { + blocked_number = ioctls[i].number; + found = 1; + break; + } + } + if (!found) + blocked_number = str2num_or_err( + optarg, 10, _("Unknown ioctl"), 0, LONG_MAX); + + blocked = xmalloc(sizeof(*blocked)); + blocked->number = blocked_number; + list_add(&blocked->head, &blocked_ioctls); + break; case 'l': for (i = 0; i < ARRAY_SIZE(syscalls); i++) printf("%5ld %s\n", syscalls[i].number, syscalls[i].name); return EXIT_SUCCESS; + case 'm': + for (i = 0; i < ARRAY_SIZE(ioctls); i++) + printf("%5ld %s\n", ioctls[i].number, ioctls[i].name); + return EXIT_SUCCESS; case 'V': print_version(EXIT_SUCCESS); case 'h': @@ -182,6 +215,21 @@ int main(int argc, char **argv) INSTR(BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | ENOSYS)); } + INSTR(BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_ioctl, 1, 0)); + INSTR(BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW)); + + INSTR(BPF_STMT(BPF_LD | BPF_W | BPF_ABS, syscall_arg(1))); + + list_for_each(loop_ctr, &blocked_ioctls) { + blocked = list_entry(loop_ctr, struct blocked_number, head); + + INSTR(BPF_STMT(BPF_LD | BPF_W | BPF_ABS, syscall_arg(1) + 4 * !IS_LITTLE_ENDIAN)); + INSTR(BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, (uint64_t) blocked->number, 0, 3)); + INSTR(BPF_STMT(BPF_LD | BPF_W | BPF_ABS, syscall_arg(1) + 4 * IS_LITTLE_ENDIAN)); + INSTR(BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, (uint64_t) blocked->number >> 32, 0, 1)); + INSTR(BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | ENOTTY)); + } + INSTR(BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW)); struct sock_fprog prog = { diff --git a/tests/expected/misc/enosys-ioctl b/tests/expected/misc/enosys-ioctl new file mode 100644 index 0000000000..7ab1efd15a --- /dev/null +++ b/tests/expected/misc/enosys-ioctl @@ -0,0 +1,5 @@ +test_enosys: ioctl r=0 errno=Success +test_enosys: ioctl r=-1 errno=Function not implemented +test_enosys: ioctl r=-1 errno=Inappropriate ioctl for device +test_enosys: ioctl r=-1 errno=Inappropriate ioctl for device +test_enosys: ioctl r=-1 errno=Function not implemented diff --git a/tests/helpers/test_enosys.c b/tests/helpers/test_enosys.c index 69f7af9af9..98f8d15eea 100644 --- a/tests/helpers/test_enosys.c +++ b/tests/helpers/test_enosys.c @@ -23,6 +23,7 @@ #include #include #include +#include int main(int argc, char **argv) { @@ -44,6 +45,9 @@ int main(int argc, char **argv) }; execve(cmd[0], cmd, NULL); err(EXIT_FAILURE, "exec failed"); + } else if (strcmp(argv[1], "ioctl") == 0) { + r = ioctl(0, FIOCLEX); + errx(EXIT_SUCCESS, "ioctl r=%d errno=%s", r, strerror(errno)); } errx(EXIT_FAILURE, "invalid mode %s", argv[1]); diff --git a/tests/ts/misc/enosys b/tests/ts/misc/enosys index bf92ae376c..ae93c63066 100755 --- a/tests/ts/misc/enosys +++ b/tests/ts/misc/enosys @@ -43,4 +43,16 @@ $FALLOCATE_TEST > /dev/null 2>> "$TS_OUTPUT" ts_finalize_subtest +ts_init_subtest ioctl + +FALLOCATE_TEST="$TS_HELPER_ENOSYS ioctl" + +$FALLOCATE_TEST > /dev/null 2>> "$TS_OUTPUT" +"$TS_CMD_ENOSYS" -s ioctl $FALLOCATE_TEST > /dev/null 2>> "$TS_OUTPUT" +"$TS_CMD_ENOSYS" -i FIOCLEX $FALLOCATE_TEST > /dev/null 2>> "$TS_OUTPUT" +"$TS_CMD_ENOSYS" -i "$("$TS_CMD_ENOSYS" -m | grep FIOCLEX | awk '{ print $1 }')" $FALLOCATE_TEST > /dev/null 2>> "$TS_OUTPUT" +"$TS_CMD_ENOSYS" -s ioctl -i FIOCLEX $FALLOCATE_TEST > /dev/null 2>> "$TS_OUTPUT" + +ts_finalize_subtest + ts_finalize