]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - kernel/seccomp.c
UBUNTU: [Config] CONFIG_QCOM_PM8XXX_XOADC=m
[mirror_ubuntu-artful-kernel.git] / kernel / seccomp.c
index 54357e361aea5cbe90597208372f26ef94ead915..3fd2c4b23697ec8ff01470ab664fc980a7058c95 100644 (file)
@@ -44,6 +44,7 @@
  *         get/put helpers should be used when accessing an instance
  *         outside of a lifetime-guarded section.  In general, this
  *         is only needed for handling filters shared across tasks.
+ * @log: true if all actions except for SECCOMP_RET_ALLOW should be logged
  * @prev: points to a previously installed, or inherited, filter
  * @prog: the BPF program to evaluate
  *
@@ -59,6 +60,7 @@
  */
 struct seccomp_filter {
        refcount_t usage;
+       bool log;
        struct seccomp_filter *prev;
        struct bpf_prog *prog;
 };
@@ -186,7 +188,7 @@ static u32 seccomp_run_filters(const struct seccomp_data *sd,
        u32 ret = SECCOMP_RET_ALLOW;
        /* Make sure cross-thread synced filter points somewhere sane. */
        struct seccomp_filter *f =
-                       lockless_dereference(current->seccomp.filter);
+                       READ_ONCE(current->seccomp.filter);
 
        /* Ensure unexpected behavior doesn't result in failing open. */
        if (unlikely(WARN_ON(f == NULL)))
@@ -452,6 +454,10 @@ static long seccomp_attach_filter(unsigned int flags,
                        return ret;
        }
 
+       /* Set log flag, if present. */
+       if (flags & SECCOMP_FILTER_FLAG_LOG)
+               filter->log = true;
+
        /*
         * If there is an existing filter, make it the prev and don't drop its
         * task reference.
@@ -466,14 +472,19 @@ static long seccomp_attach_filter(unsigned int flags,
        return 0;
 }
 
+void __get_seccomp_filter(struct seccomp_filter *filter)
+{
+       /* Reference count is bounded by the number of total processes. */
+       refcount_inc(&filter->usage);
+}
+
 /* get_seccomp_filter - increments the reference count of the filter on @tsk */
 void get_seccomp_filter(struct task_struct *tsk)
 {
        struct seccomp_filter *orig = tsk->seccomp.filter;
        if (!orig)
                return;
-       /* Reference count is bounded by the number of total processes. */
-       refcount_inc(&orig->usage);
+       __get_seccomp_filter(orig);
 }
 
 static inline void seccomp_filter_free(struct seccomp_filter *filter)
@@ -484,10 +495,8 @@ static inline void seccomp_filter_free(struct seccomp_filter *filter)
        }
 }
 
-/* put_seccomp_filter - decrements the ref count of tsk->seccomp.filter */
-void put_seccomp_filter(struct task_struct *tsk)
+static void __put_seccomp_filter(struct seccomp_filter *orig)
 {
-       struct seccomp_filter *orig = tsk->seccomp.filter;
        /* Clean up single-reference branches iteratively. */
        while (orig && refcount_dec_and_test(&orig->usage)) {
                struct seccomp_filter *freeme = orig;
@@ -496,6 +505,12 @@ void put_seccomp_filter(struct task_struct *tsk)
        }
 }
 
+/* put_seccomp_filter - decrements the ref count of tsk->seccomp.filter */
+void put_seccomp_filter(struct task_struct *tsk)
+{
+       __put_seccomp_filter(tsk->seccomp.filter);
+}
+
 static void seccomp_init_siginfo(siginfo_t *info, int syscall, int reason)
 {
        memset(info, 0, sizeof(*info));
@@ -527,20 +542,32 @@ static void seccomp_send_sigsys(int syscall, int reason)
 #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)
+static inline void seccomp_log(unsigned long syscall, long signr, u32 action,
+                              bool requested)
 {
        bool log = false;
 
        switch (action) {
        case SECCOMP_RET_ALLOW:
+               break;
        case SECCOMP_RET_TRAP:
+               log = requested && seccomp_actions_logged & SECCOMP_LOG_TRAP;
+               break;
        case SECCOMP_RET_ERRNO:
+               log = requested && seccomp_actions_logged & SECCOMP_LOG_ERRNO;
+               break;
        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:
@@ -548,8 +575,9 @@ static inline void seccomp_log(unsigned long syscall, long signr, u32 action)
        }
 
        /*
-        * Force an audit message to be emitted when the action is RET_KILL 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);
@@ -586,7 +614,7 @@ static void __secure_computing_strict(int this_syscall)
 #ifdef SECCOMP_DEBUG
        dump_stack();
 #endif
-       seccomp_log(this_syscall, SIGKILL, SECCOMP_RET_KILL);
+       seccomp_log(this_syscall, SIGKILL, SECCOMP_RET_KILL, true);
        do_exit(SIGKILL);
 }
 
@@ -685,6 +713,10 @@ static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd,
 
                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
@@ -695,7 +727,7 @@ static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd,
 
        case SECCOMP_RET_KILL:
        default:
-               seccomp_log(this_syscall, SIGSYS, action);
+               seccomp_log(this_syscall, SIGSYS, action, true);
                /* Dump core only if this is the last remaining thread. */
                if (get_nr_threads(current) == 1) {
                        siginfo_t info;
@@ -712,7 +744,7 @@ static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd,
        unreachable();
 
 skip:
-       seccomp_log(this_syscall, 0, action);
+       seccomp_log(this_syscall, 0, action, match ? match->log : false);
        return -1;
 }
 #else
@@ -859,6 +891,7 @@ static long seccomp_get_action_avail(const char __user *uaction)
        case SECCOMP_RET_TRAP:
        case SECCOMP_RET_ERRNO:
        case SECCOMP_RET_TRACE:
+       case SECCOMP_RET_LOG:
        case SECCOMP_RET_ALLOW:
                break;
        default:
@@ -987,13 +1020,13 @@ long seccomp_get_filter(struct task_struct *task, unsigned long filter_off,
        if (!data)
                goto out;
 
-       get_seccomp_filter(task);
+       __get_seccomp_filter(filter);
        spin_unlock_irq(&task->sighand->siglock);
 
        if (copy_to_user(data, fprog->filter, bpf_classic_proglen(fprog)))
                ret = -EFAULT;
 
-       put_seccomp_filter(task);
+       __put_seccomp_filter(filter);
        return ret;
 
 out:
@@ -1009,12 +1042,14 @@ out:
 #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 {
@@ -1027,6 +1062,7 @@ static const struct seccomp_log_name seccomp_log_names[] = {
        { 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 },
        { }
 };