This is what I've been using to explore actual bitmap results for
real-world filters...

Signed-off-by: Kees Cook <keesc...@chromium.org>
---
 kernel/seccomp.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 115 insertions(+)

diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 9921f6f39d12..1a0595d7f8ef 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -835,6 +835,85 @@ static void seccomp_update_bitmap(struct seccomp_filter 
*filter,
        }
 }
 
+static void __report_bitmap(const char *arch, u32 ret, int start, int finish)
+{
+       int gap;
+       char *name;
+
+       if (finish == -1)
+               return;
+
+       switch (ret) {
+       case UINT_MAX:
+               name = "filter";
+               break;
+       case SECCOMP_RET_ALLOW:
+               name = "SECCOMP_RET_ALLOW";
+               break;
+       case SECCOMP_RET_KILL_PROCESS:
+               name = "SECCOMP_RET_KILL_PROCESS";
+               break;
+       case SECCOMP_RET_KILL_THREAD:
+               name = "SECCOMP_RET_KILL_THREAD";
+               break;
+       default:
+               WARN_ON_ONCE(1);
+               name = "unknown";
+               break;
+       }
+
+       gap = 0;
+       if (start < 100)
+               gap++;
+       if (start < 10)
+               gap++;
+       if (finish < 100)
+               gap++;
+       if (finish < 10)
+               gap++;
+
+       if (start == finish)
+               pr_info("%s     %3d: %s\n", arch, start, name);
+       else if (start + 1 == finish)
+               pr_info("%s %*s%d,%d: %s\n", arch, gap, "", start, finish, 
name);
+       else
+               pr_info("%s %*s%d-%d: %s\n", arch, gap, "", start, finish, 
name);
+}
+
+static void report_bitmap(struct seccomp_bitmaps *bitmaps, const char *arch)
+{
+       u32 nr;
+       int start = 0, finish = -1;
+       u32 ret = UINT_MAX;
+       struct report_states {
+               unsigned long *bitmap;
+               u32 ret;
+       } states[] = {
+               { .bitmap = bitmaps->allow,        .ret = SECCOMP_RET_ALLOW, },
+               { .bitmap = bitmaps->kill_process, .ret = 
SECCOMP_RET_KILL_PROCESS, },
+               { .bitmap = bitmaps->kill_thread,  .ret = 
SECCOMP_RET_KILL_THREAD, },
+               { .bitmap = NULL,                  .ret = UINT_MAX, },
+       };
+
+       for (nr = 0; nr < NR_syscalls; nr++) {
+               int i;
+
+               for (i = 0; i < ARRAY_SIZE(states); i++) {
+                       if (!states[i].bitmap || test_bit(nr, 
states[i].bitmap)) {
+                               if (ret != states[i].ret) {
+                                       __report_bitmap(arch, ret, start, 
finish);
+                                       ret = states[i].ret;
+                                       start = nr;
+                               }
+                               finish = nr;
+                               break;
+                       }
+               }
+       }
+       if (start != nr)
+               __report_bitmap(arch, ret, start, finish);
+}
+
 static void seccomp_update_bitmaps(struct seccomp_filter *filter,
                                   void *pagepair)
 {
@@ -849,6 +928,23 @@ static void seccomp_update_bitmaps(struct seccomp_filter 
*filter,
                              SECCOMP_MULTIPLEXED_SYSCALL_TABLE_MASK,
                              &current->seccomp.multiplex);
 #endif
+       if (strncmp(current->comm, "test-", 5) == 0 ||
+           strcmp(current->comm, "seccomp_bpf") == 0 ||
+           /*
+            * Why are systemd's process names head-truncated to 8 bytes
+            * and wrapped in parens!?
+            */
+           (current->comm[0] == '(' && strrchr(current->comm, ')') != NULL)) {
+               pr_info("reporting syscall bitmap usage for %d (%s):\n",
+                       task_pid_nr(current), current->comm);
+               report_bitmap(&current->seccomp.native, "native");
+#ifdef CONFIG_COMPAT
+               report_bitmap(&current->seccomp.compat, "compat");
+#endif
+#ifdef SECCOMP_MULTIPLEXED_SYSCALL_TABLE_ARCH
+               report_bitmap(&current->seccomp.multiplex, "multiplex");
+#endif
+       }
 }
 #else
 static void seccomp_update_bitmaps(struct seccomp_filter *filter,
@@ -908,6 +1004,10 @@ static long seccomp_attach_filter(unsigned int flags,
        filter->prev = current->seccomp.filter;
        current->seccomp.filter = filter;
        atomic_inc(&current->seccomp.filter_count);
+       if (atomic_read(&current->seccomp.filter_count) > 10)
+               pr_info("%d filters: %d (%s)\n",
+                       atomic_read(&current->seccomp.filter_count),
+                       task_pid_nr(current), current->comm);
 
        /* Evaluate filter for new known-outcome syscalls */
        seccomp_update_bitmaps(filter, pagepair);
@@ -2419,6 +2519,21 @@ static int __init seccomp_sysctl_init(void)
                pr_warn("sysctl registration failed\n");
        else
                kmemleak_not_leak(hdr);
+#ifndef SECCOMP_ARCH
+       pr_info("arch lacks support for constant action bitmaps\n");
+#else
+       pr_info("NR_syscalls: %d\n", NR_syscalls);
+       pr_info("arch: 0x%x\n", SECCOMP_ARCH);
+#ifdef CONFIG_COMPAT
+       pr_info("compat arch: 0x%x\n", SECCOMP_ARCH_COMPAT);
+#endif
+#ifdef SECCOMP_MULTIPLEXED_SYSCALL_TABLE_ARCH
+       pr_info("multiplex arch: 0x%x (mask: 0x%x)\n",
+               SECCOMP_MULTIPLEXED_SYSCALL_TABLE_ARCH,
+               SECCOMP_MULTIPLEXED_SYSCALL_TABLE_MASK);
+#endif
+#endif
+       pr_info("sizeof(struct seccomp_bitmaps): %zu\n", sizeof(struct 
seccomp_bitmaps));
 
        return 0;
 }
-- 
2.25.1

Reply via email to