seccomp/cache: Report cache data through /proc/pid/seccomp_cache
[sfrench/cifs-2.6.git] / kernel / seccomp.c
index d8cf468dbe1e5bf605d86ef6adcc3724fb5676fa..76f524e320b1849f9730ed0e32f30ebc9c771dc9 100644 (file)
@@ -553,6 +553,9 @@ void seccomp_filter_release(struct task_struct *tsk)
 {
        struct seccomp_filter *orig = tsk->seccomp.filter;
 
+       /* We are effectively holding the siglock by not having any sighand. */
+       WARN_ON(tsk->sighand != NULL);
+
        /* Detach task from its filter tree. */
        tsk->seccomp.filter = NULL;
        __seccomp_filter_release(orig);
@@ -2335,3 +2338,59 @@ static int __init seccomp_sysctl_init(void)
 device_initcall(seccomp_sysctl_init)
 
 #endif /* CONFIG_SYSCTL */
+
+#ifdef CONFIG_SECCOMP_CACHE_DEBUG
+/* Currently CONFIG_SECCOMP_CACHE_DEBUG implies SECCOMP_ARCH_NATIVE */
+static void proc_pid_seccomp_cache_arch(struct seq_file *m, const char *name,
+                                       const void *bitmap, size_t bitmap_size)
+{
+       int nr;
+
+       for (nr = 0; nr < bitmap_size; nr++) {
+               bool cached = test_bit(nr, bitmap);
+               char *status = cached ? "ALLOW" : "FILTER";
+
+               seq_printf(m, "%s %d %s\n", name, nr, status);
+       }
+}
+
+int proc_pid_seccomp_cache(struct seq_file *m, struct pid_namespace *ns,
+                          struct pid *pid, struct task_struct *task)
+{
+       struct seccomp_filter *f;
+       unsigned long flags;
+
+       /*
+        * We don't want some sandboxed process to know what their seccomp
+        * filters consist of.
+        */
+       if (!file_ns_capable(m->file, &init_user_ns, CAP_SYS_ADMIN))
+               return -EACCES;
+
+       if (!lock_task_sighand(task, &flags))
+               return -ESRCH;
+
+       f = READ_ONCE(task->seccomp.filter);
+       if (!f) {
+               unlock_task_sighand(task, &flags);
+               return 0;
+       }
+
+       /* prevent filter from being freed while we are printing it */
+       __get_seccomp_filter(f);
+       unlock_task_sighand(task, &flags);
+
+       proc_pid_seccomp_cache_arch(m, SECCOMP_ARCH_NATIVE_NAME,
+                                   f->cache.allow_native,
+                                   SECCOMP_ARCH_NATIVE_NR);
+
+#ifdef SECCOMP_ARCH_COMPAT
+       proc_pid_seccomp_cache_arch(m, SECCOMP_ARCH_COMPAT_NAME,
+                                   f->cache.allow_compat,
+                                   SECCOMP_ARCH_COMPAT_NR);
+#endif /* SECCOMP_ARCH_COMPAT */
+
+       __put_seccomp_filter(f);
+       return 0;
+}
+#endif /* CONFIG_SECCOMP_CACHE_DEBUG */