@@ -715,6 +715,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)
{
@@ -724,6 +803,20 @@ static void seccomp_update_bitmaps(struct seccomp_filter *filter,
seccomp_update_bitmap(filter, pagepair, SECCOMP_ARCH_COMPAT,
¤t->seccomp.compat);
#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(¤t->seccomp.native, "native");
+#ifdef CONFIG_COMPAT
+ report_bitmap(¤t->seccomp.compat, "compat");
+#endif
+ }
}
#else
static void seccomp_update_bitmaps(struct seccomp_filter *filter,
@@ -783,6 +876,10 @@ static long seccomp_attach_filter(unsigned int flags,
filter->prev = current->seccomp.filter;
current->seccomp.filter = filter;
atomic_inc(¤t->seccomp.filter_count);
+ if (atomic_read(¤t->seccomp.filter_count) > 10)
+ pr_info("%d filters: %d (%s)\n",
+ atomic_read(¤t->seccomp.filter_count),
+ task_pid_nr(current), current->comm);
/* Evaluate filter for new known-outcome syscalls */
seccomp_update_bitmaps(filter, pagepair);
@@ -2131,6 +2228,16 @@ static int __init seccomp_sysctl_init(void)
pr_warn("sysctl registration failed\n");
else
kmemleak_not_leak(hdr);
+#ifndef CONFIG_HAVE_ARCH_SECCOMP_BITMAP
+ 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
+#endif
+ pr_info("sizeof(struct seccomp_bitmaps): %zu\n", sizeof(struct seccomp_bitmaps));
return 0;
}
This is what I've been using to explore actual bitmap results for real-world filters. Signed-off-by: Kees Cook <keescook@chromium.org> --- kernel/seccomp.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+)