#define SECCOMP_LOG_TRAP               (1 << 2)
 #define SECCOMP_LOG_ERRNO              (1 << 3)
 #define SECCOMP_LOG_TRACE              (1 << 4)
-#define SECCOMP_LOG_ALLOW              (1 << 5)
+#define SECCOMP_LOG_LOG                        (1 << 5)
+#define SECCOMP_LOG_ALLOW              (1 << 6)
 
 static u32 seccomp_actions_logged = SECCOMP_LOG_KILL  | SECCOMP_LOG_TRAP  |
-                                   SECCOMP_LOG_ERRNO | SECCOMP_LOG_TRACE;
+                                   SECCOMP_LOG_ERRNO | SECCOMP_LOG_TRACE |
+                                   SECCOMP_LOG_LOG;
 
 static inline void seccomp_log(unsigned long syscall, long signr, u32 action,
                               bool requested)
        case SECCOMP_RET_TRACE:
                log = requested && seccomp_actions_logged & SECCOMP_LOG_TRACE;
                break;
+       case SECCOMP_RET_LOG:
+               log = seccomp_actions_logged & SECCOMP_LOG_LOG;
+               break;
        case SECCOMP_RET_KILL:
        default:
                log = seccomp_actions_logged & SECCOMP_LOG_KILL;
        }
 
        /*
-        * Force an audit message to be emitted when the action is RET_KILL or
-        * the FILTER_FLAG_LOG bit was set and the action is allowed to be
-        * logged by the admin.
+        * Force an audit message to be emitted when the action is RET_KILL,
+        * RET_LOG, or the FILTER_FLAG_LOG bit was set and the action is
+        * allowed to be logged by the admin.
         */
        if (log)
                return __audit_seccomp(syscall, signr, action);
 
                return 0;
 
+       case SECCOMP_RET_LOG:
+               seccomp_log(this_syscall, 0, action, true);
+               return 0;
+
        case SECCOMP_RET_ALLOW:
                /*
                 * Note that the "match" filter will always be NULL for
        case SECCOMP_RET_TRAP:
        case SECCOMP_RET_ERRNO:
        case SECCOMP_RET_TRACE:
+       case SECCOMP_RET_LOG:
        case SECCOMP_RET_ALLOW:
                break;
        default:
 #define SECCOMP_RET_TRAP_NAME          "trap"
 #define SECCOMP_RET_ERRNO_NAME         "errno"
 #define SECCOMP_RET_TRACE_NAME         "trace"
+#define SECCOMP_RET_LOG_NAME           "log"
 #define SECCOMP_RET_ALLOW_NAME         "allow"
 
 static const char seccomp_actions_avail[] = SECCOMP_RET_KILL_NAME      " "
                                            SECCOMP_RET_TRAP_NAME       " "
                                            SECCOMP_RET_ERRNO_NAME      " "
                                            SECCOMP_RET_TRACE_NAME      " "
+                                           SECCOMP_RET_LOG_NAME        " "
                                            SECCOMP_RET_ALLOW_NAME;
 
 struct seccomp_log_name {
        { SECCOMP_LOG_TRAP, SECCOMP_RET_TRAP_NAME },
        { SECCOMP_LOG_ERRNO, SECCOMP_RET_ERRNO_NAME },
        { SECCOMP_LOG_TRACE, SECCOMP_RET_TRACE_NAME },
+       { SECCOMP_LOG_LOG, SECCOMP_RET_LOG_NAME },
        { SECCOMP_LOG_ALLOW, SECCOMP_RET_ALLOW_NAME },
        { }
 };
 
 #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
        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[] = {
 
 FIXTURE_DATA(precedence) {
        struct sock_fprog allow;
+       struct sock_fprog log;
        struct sock_fprog trace;
        struct sock_fprog error;
        struct sock_fprog trap;
        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)),
        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);
 {
 #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);
 
        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);
 
        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);
        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);
 
        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);
        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);
 
        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);
        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);
 
        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. */
        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
 {
        __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;
  * - 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
  * - ...
  */