]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
enosys: add support for ioctl blocking
authorThomas Weißschuh <thomas@t-8ch.de>
Mon, 26 Jun 2023 18:25:18 +0000 (20:25 +0200)
committerThomas Weißschuh <thomas@t-8ch.de>
Sun, 23 Jul 2023 19:15:41 +0000 (21:15 +0200)
Ioctls are blocked with ENOTTY.

Signed-off-by: Thomas Weißschuh <thomas@t-8ch.de>
bash-completion/enosys
misc-utils/enosys.1.adoc
misc-utils/enosys.c
tests/expected/misc/enosys-ioctl [new file with mode: 0644]
tests/helpers/test_enosys.c
tests/ts/misc/enosys

index 61aff46c844ab4c8b4833788aa5b8e7afe42e3cb..7ce7609a755a915c0ca47399c8ada3650d88602e 100644 (file)
@@ -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) )
index 9ce272860be162c8b71c52e54e6dadc6c219c4cb..a9bc693b1eb3cad51732e51b504d37c0ece37c95 100644 (file)
@@ -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
index 0f7a16e0df58ab595fc2ab545f2d6ab8a47b0fb3..6754dd235fb64dbd7ce69b4d31e4e4fe58c74ebb 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/audit.h>
 #include <sys/prctl.h>
 #include <sys/syscall.h>
+#include <sys/ioctl.h>
 
 #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 (file)
index 0000000..7ab1efd
--- /dev/null
@@ -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
index 69f7af9af91fd83aa046086af7b765e93d702b52..98f8d15eea2f8b79a50c0319bcd596a37c44fed9 100644 (file)
@@ -23,6 +23,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/ioctl.h>
 
 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]);
index bf92ae376c20a7ff9a048dd048ab4c6e76aca8c5..ae93c630665d9a24dbb32efcf20e9117a8bf0a2a 100755 (executable)
@@ -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