Merge tag 'seccomp-next' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux...
authorJames Morris <james.l.morris@oracle.com>
Mon, 20 Jul 2015 07:19:19 +0000 (17:19 +1000)
committerJames Morris <james.l.morris@oracle.com>
Mon, 20 Jul 2015 07:19:19 +0000 (17:19 +1000)
1  2 
kernel/seccomp.c

diff --combined kernel/seccomp.c
index 245df6b32b81f8eef778a203c2edb8432a52abd6,383bd6caca815d3dcdf96a6715d6c195fbe14b48..5bd4779282df00e8831d07ec09b80f9e07b73ad7
@@@ -175,17 -175,16 +175,16 @@@ static int seccomp_check_filter(struct 
   */
  static u32 seccomp_run_filters(struct seccomp_data *sd)
  {
-       struct seccomp_filter *f = ACCESS_ONCE(current->seccomp.filter);
        struct seccomp_data sd_local;
        u32 ret = SECCOMP_RET_ALLOW;
+       /* Make sure cross-thread synced filter points somewhere sane. */
+       struct seccomp_filter *f =
+                       lockless_dereference(current->seccomp.filter);
  
        /* Ensure unexpected behavior doesn't result in failing open. */
        if (unlikely(WARN_ON(f == NULL)))
                return SECCOMP_RET_KILL;
  
-       /* Make sure cross-thread synced filter points somewhere sane. */
-       smp_read_barrier_depends();
        if (!sd) {
                populate_seccomp_data(&sd_local);
                sd = &sd_local;
@@@ -346,13 -345,16 +345,13 @@@ static inline void seccomp_sync_threads
   */
  static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog)
  {
 -      struct seccomp_filter *filter;
 -      unsigned long fp_size;
 -      struct sock_filter *fp;
 -      int new_len;
 -      long ret;
 +      struct seccomp_filter *sfilter;
 +      int ret;
  
        if (fprog->len == 0 || fprog->len > BPF_MAXINSNS)
                return ERR_PTR(-EINVAL);
 +
        BUG_ON(INT_MAX / fprog->len < sizeof(struct sock_filter));
 -      fp_size = fprog->len * sizeof(struct sock_filter);
  
        /*
         * Installing a seccomp filter requires that the task has
                                     CAP_SYS_ADMIN) != 0)
                return ERR_PTR(-EACCES);
  
 -      fp = kzalloc(fp_size, GFP_KERNEL|__GFP_NOWARN);
 -      if (!fp)
 +      /* Allocate a new seccomp_filter */
 +      sfilter = kzalloc(sizeof(*sfilter), GFP_KERNEL | __GFP_NOWARN);
 +      if (!sfilter)
                return ERR_PTR(-ENOMEM);
  
 -      /* Copy the instructions from fprog. */
 -      ret = -EFAULT;
 -      if (copy_from_user(fp, fprog->filter, fp_size))
 -              goto free_prog;
 -
 -      /* Check and rewrite the fprog via the skb checker */
 -      ret = bpf_check_classic(fp, fprog->len);
 -      if (ret)
 -              goto free_prog;
 -
 -      /* Check and rewrite the fprog for seccomp use */
 -      ret = seccomp_check_filter(fp, fprog->len);
 -      if (ret)
 -              goto free_prog;
 +      ret = bpf_prog_create_from_user(&sfilter->prog, fprog,
 +                                      seccomp_check_filter);
 +      if (ret < 0) {
 +              kfree(sfilter);
 +              return ERR_PTR(ret);
 +      }
  
 -      /* Convert 'sock_filter' insns to 'bpf_insn' insns */
 -      ret = bpf_convert_filter(fp, fprog->len, NULL, &new_len);
 -      if (ret)
 -              goto free_prog;
 +      atomic_set(&sfilter->usage, 1);
  
 -      /* Allocate a new seccomp_filter */
 -      ret = -ENOMEM;
 -      filter = kzalloc(sizeof(struct seccomp_filter),
 -                       GFP_KERNEL|__GFP_NOWARN);
 -      if (!filter)
 -              goto free_prog;
 -
 -      filter->prog = bpf_prog_alloc(bpf_prog_size(new_len), __GFP_NOWARN);
 -      if (!filter->prog)
 -              goto free_filter;
 -
 -      ret = bpf_convert_filter(fp, fprog->len, filter->prog->insnsi, &new_len);
 -      if (ret)
 -              goto free_filter_prog;
 -
 -      kfree(fp);
 -      atomic_set(&filter->usage, 1);
 -      filter->prog->len = new_len;
 -
 -      bpf_prog_select_runtime(filter->prog);
 -
 -      return filter;
 -
 -free_filter_prog:
 -      __bpf_prog_free(filter->prog);
 -free_filter:
 -      kfree(filter);
 -free_prog:
 -      kfree(fp);
 -      return ERR_PTR(ret);
 +      return sfilter;
  }
  
  /**
@@@ -549,7 -590,11 +548,11 @@@ void secure_computing_strict(int this_s
  {
        int mode = current->seccomp.mode;
  
-       if (mode == 0)
+       if (config_enabled(CONFIG_CHECKPOINT_RESTORE) &&
+           unlikely(current->ptrace & PT_SUSPEND_SECCOMP))
+               return;
+       if (mode == SECCOMP_MODE_DISABLED)
                return;
        else if (mode == SECCOMP_MODE_STRICT)
                __secure_computing_strict(this_syscall);
@@@ -650,6 -695,10 +653,10 @@@ u32 seccomp_phase1(struct seccomp_data 
        int this_syscall = sd ? sd->nr :
                syscall_get_nr(current, task_pt_regs(current));
  
+       if (config_enabled(CONFIG_CHECKPOINT_RESTORE) &&
+           unlikely(current->ptrace & PT_SUSPEND_SECCOMP))
+               return SECCOMP_PHASE1_OK;
        switch (mode) {
        case SECCOMP_MODE_STRICT:
                __secure_computing_strict(this_syscall);  /* may call do_exit */