]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - tools/testing/selftests/seccomp/seccomp_bpf.c
seccomp: Action to log before allowing
[mirror_ubuntu-artful-kernel.git] / tools / testing / selftests / seccomp / seccomp_bpf.c
index 0c286502597613e7abd68b92ff326d7405b3e796..0a7c40b0a17bce5b0c7c212695c2d67f2090d233 100644 (file)
 #define SECCOMP_RET_ERRNO       0x00050000U /* returns an errno */
 #define SECCOMP_RET_TRACE       0x7ff00000U /* pass to a tracer or disallow */
 #define SECCOMP_RET_ALLOW       0x7fff0000U /* allow */
+#endif
+#ifndef SECCOMP_RET_LOG
+#define SECCOMP_RET_LOG       0x7ffc0000U /* allow after logging */
+#endif
 
+#ifndef SECCOMP_RET_ACTION
 /* Masks for the return value sections. */
 #define SECCOMP_RET_ACTION      0x7fff0000U
 #define SECCOMP_RET_DATA        0x0000ffffU
@@ -342,6 +347,28 @@ TEST(empty_prog)
        EXPECT_EQ(EINVAL, errno);
 }
 
+TEST(log_all)
+{
+       struct sock_filter filter[] = {
+               BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_LOG),
+       };
+       struct sock_fprog prog = {
+               .len = (unsigned short)ARRAY_SIZE(filter),
+               .filter = filter,
+       };
+       long ret;
+       pid_t parent = getppid();
+
+       ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
+       ASSERT_EQ(0, ret);
+
+       ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
+       ASSERT_EQ(0, ret);
+
+       /* getppid() should succeed and be logged (no check for logging) */
+       EXPECT_EQ(parent, syscall(__NR_getppid));
+}
+
 TEST_SIGNAL(unknown_ret_is_kill_inside, SIGSYS)
 {
        struct sock_filter filter[] = {
@@ -735,6 +762,7 @@ TEST_F(TRAP, handler)
 
 FIXTURE_DATA(precedence) {
        struct sock_fprog allow;
+       struct sock_fprog log;
        struct sock_fprog trace;
        struct sock_fprog error;
        struct sock_fprog trap;
@@ -746,6 +774,13 @@ FIXTURE_SETUP(precedence)
        struct sock_filter allow_insns[] = {
                BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
        };
+       struct sock_filter log_insns[] = {
+               BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
+                       offsetof(struct seccomp_data, nr)),
+               BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 1, 0),
+               BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
+               BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_LOG),
+       };
        struct sock_filter trace_insns[] = {
                BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
                        offsetof(struct seccomp_data, nr)),
@@ -782,6 +817,7 @@ FIXTURE_SETUP(precedence)
        memcpy(self->_x.filter, &_x##_insns, sizeof(_x##_insns)); \
        self->_x.len = (unsigned short)ARRAY_SIZE(_x##_insns)
        FILTER_ALLOC(allow);
+       FILTER_ALLOC(log);
        FILTER_ALLOC(trace);
        FILTER_ALLOC(error);
        FILTER_ALLOC(trap);
@@ -792,6 +828,7 @@ FIXTURE_TEARDOWN(precedence)
 {
 #define FILTER_FREE(_x) if (self->_x.filter) free(self->_x.filter)
        FILTER_FREE(allow);
+       FILTER_FREE(log);
        FILTER_FREE(trace);
        FILTER_FREE(error);
        FILTER_FREE(trap);
@@ -809,6 +846,8 @@ TEST_F(precedence, allow_ok)
 
        ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);
        ASSERT_EQ(0, ret);
+       ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
+       ASSERT_EQ(0, ret);
        ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);
        ASSERT_EQ(0, ret);
        ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error);
@@ -833,6 +872,8 @@ TEST_F_SIGNAL(precedence, kill_is_highest, SIGSYS)
 
        ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);
        ASSERT_EQ(0, ret);
+       ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
+       ASSERT_EQ(0, ret);
        ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);
        ASSERT_EQ(0, ret);
        ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error);
@@ -864,6 +905,8 @@ TEST_F_SIGNAL(precedence, kill_is_highest_in_any_order, SIGSYS)
        ASSERT_EQ(0, ret);
        ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error);
        ASSERT_EQ(0, ret);
+       ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
+       ASSERT_EQ(0, ret);
        ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);
        ASSERT_EQ(0, ret);
        ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trap);
@@ -885,6 +928,8 @@ TEST_F_SIGNAL(precedence, trap_is_second, SIGSYS)
 
        ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);
        ASSERT_EQ(0, ret);
+       ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
+       ASSERT_EQ(0, ret);
        ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);
        ASSERT_EQ(0, ret);
        ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error);
@@ -910,6 +955,8 @@ TEST_F_SIGNAL(precedence, trap_is_second_in_any_order, SIGSYS)
        ASSERT_EQ(0, ret);
        ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trap);
        ASSERT_EQ(0, ret);
+       ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
+       ASSERT_EQ(0, ret);
        ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);
        ASSERT_EQ(0, ret);
        ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error);
@@ -931,6 +978,8 @@ TEST_F(precedence, errno_is_third)
 
        ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);
        ASSERT_EQ(0, ret);
+       ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
+       ASSERT_EQ(0, ret);
        ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);
        ASSERT_EQ(0, ret);
        ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error);
@@ -949,6 +998,8 @@ TEST_F(precedence, errno_is_third_in_any_order)
        ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
        ASSERT_EQ(0, ret);
 
+       ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
+       ASSERT_EQ(0, ret);
        ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->error);
        ASSERT_EQ(0, ret);
        ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);
@@ -971,6 +1022,8 @@ TEST_F(precedence, trace_is_fourth)
 
        ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);
        ASSERT_EQ(0, ret);
+       ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
+       ASSERT_EQ(0, ret);
        ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->trace);
        ASSERT_EQ(0, ret);
        /* Should work just fine. */
@@ -992,12 +1045,54 @@ TEST_F(precedence, trace_is_fourth_in_any_order)
        ASSERT_EQ(0, ret);
        ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);
        ASSERT_EQ(0, ret);
+       ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
+       ASSERT_EQ(0, ret);
        /* Should work just fine. */
        EXPECT_EQ(parent, syscall(__NR_getppid));
        /* No ptracer */
        EXPECT_EQ(-1, syscall(__NR_getpid));
 }
 
+TEST_F(precedence, log_is_fifth)
+{
+       pid_t mypid, parent;
+       long ret;
+
+       mypid = getpid();
+       parent = getppid();
+       ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
+       ASSERT_EQ(0, ret);
+
+       ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);
+       ASSERT_EQ(0, ret);
+       ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
+       ASSERT_EQ(0, ret);
+       /* Should work just fine. */
+       EXPECT_EQ(parent, syscall(__NR_getppid));
+       /* Should also work just fine */
+       EXPECT_EQ(mypid, syscall(__NR_getpid));
+}
+
+TEST_F(precedence, log_is_fifth_in_any_order)
+{
+       pid_t mypid, parent;
+       long ret;
+
+       mypid = getpid();
+       parent = getppid();
+       ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
+       ASSERT_EQ(0, ret);
+
+       ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->log);
+       ASSERT_EQ(0, ret);
+       ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &self->allow);
+       ASSERT_EQ(0, ret);
+       /* Should work just fine. */
+       EXPECT_EQ(parent, syscall(__NR_getppid));
+       /* Should also work just fine */
+       EXPECT_EQ(mypid, syscall(__NR_getpid));
+}
+
 #ifndef PTRACE_O_TRACESECCOMP
 #define PTRACE_O_TRACESECCOMP  0x00000080
 #endif
@@ -2555,7 +2650,7 @@ TEST(get_action_avail)
 {
        __u32 actions[] = { SECCOMP_RET_KILL,  SECCOMP_RET_TRAP,
                            SECCOMP_RET_ERRNO, SECCOMP_RET_TRACE,
-                           SECCOMP_RET_ALLOW };
+                           SECCOMP_RET_LOG,   SECCOMP_RET_ALLOW };
        __u32 unknown_action = 0x10000000U;
        int i;
        long ret;
@@ -2592,6 +2687,7 @@ TEST(get_action_avail)
  * - 64-bit arg prodding
  * - arch value testing (x86 modes especially)
  * - verify that FILTER_FLAG_LOG filters generate log messages
+ * - verify that RET_LOG generates log messages
  * - ...
  */