Merge tag 'seccomp-v5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 1 Dec 2019 01:23:16 +0000 (17:23 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 1 Dec 2019 01:23:16 +0000 (17:23 -0800)
Pull seccomp updates from Kees Cook:
 "Mostly this is implementing the new flag SECCOMP_USER_NOTIF_FLAG_CONTINUE,
  but there are cleanups as well.

   - implement SECCOMP_USER_NOTIF_FLAG_CONTINUE (Christian Brauner)

   - fixes to selftests (Christian Brauner)

   - remove secure_computing() argument (Christian Brauner)"

* tag 'seccomp-v5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux:
  seccomp: rework define for SECCOMP_USER_NOTIF_FLAG_CONTINUE
  seccomp: fix SECCOMP_USER_NOTIF_FLAG_CONTINUE test
  seccomp: simplify secure_computing()
  seccomp: test SECCOMP_USER_NOTIF_FLAG_CONTINUE
  seccomp: add SECCOMP_USER_NOTIF_FLAG_CONTINUE
  seccomp: avoid overflow in implicit constant conversion

1  2 
arch/riscv/kernel/ptrace.c
tools/testing/selftests/seccomp/seccomp_bpf.c

@@@ -148,22 -148,12 +148,22 @@@ long arch_ptrace(struct task_struct *ch
   * Allows PTRACE_SYSCALL to work.  These are called from entry.S in
   * {handle,ret_from}_syscall.
   */
 -void do_syscall_trace_enter(struct pt_regs *regs)
 +__visible void do_syscall_trace_enter(struct pt_regs *regs)
  {
        if (test_thread_flag(TIF_SYSCALL_TRACE))
                if (tracehook_report_syscall_entry(regs))
                        syscall_set_nr(current, regs, -1);
  
-       if (secure_computing(NULL) == -1) {
 +      /*
 +       * Do the secure computing after ptrace; failures should be fast.
 +       * If this fails we might have return value in a0 from seccomp
 +       * (via SECCOMP_RET_ERRNO/TRACE).
 +       */
++      if (secure_computing() == -1) {
 +              syscall_set_nr(current, regs, -1);
 +              return;
 +      }
 +
  #ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
        if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
                trace_sys_enter(regs, syscall_get_nr(current, regs));
        audit_syscall_entry(regs->a7, regs->a0, regs->a1, regs->a2, regs->a3);
  }
  
 -void do_syscall_trace_exit(struct pt_regs *regs)
 +__visible void do_syscall_trace_exit(struct pt_regs *regs)
  {
        audit_syscall_exit(regs);
  
@@@ -35,6 -35,7 +35,7 @@@
  #include <stdbool.h>
  #include <string.h>
  #include <time.h>
+ #include <limits.h>
  #include <linux/elf.h>
  #include <sys/uio.h>
  #include <sys/utsname.h>
@@@ -43,6 -44,7 +44,7 @@@
  #include <sys/times.h>
  #include <sys/socket.h>
  #include <sys/ioctl.h>
+ #include <linux/kcmp.h>
  
  #include <unistd.h>
  #include <sys/syscall.h>
@@@ -112,8 -114,6 +114,8 @@@ struct seccomp_data 
  #  define __NR_seccomp 383
  # elif defined(__aarch64__)
  #  define __NR_seccomp 277
 +# elif defined(__riscv)
 +#  define __NR_seccomp 277
  # elif defined(__hppa__)
  #  define __NR_seccomp 338
  # elif defined(__powerpc__)
@@@ -206,6 -206,10 +208,10 @@@ struct seccomp_notif_sizes 
  #define PTRACE_EVENTMSG_SYSCALL_EXIT  2
  #endif
  
+ #ifndef SECCOMP_USER_NOTIF_FLAG_CONTINUE
+ #define SECCOMP_USER_NOTIF_FLAG_CONTINUE 0x00000001
+ #endif
  #ifndef seccomp
  int seccomp(unsigned int op, unsigned int flags, void *args)
  {
@@@ -1589,10 -1593,6 +1595,10 @@@ TEST_F(TRACE_poke, getpid_runs_normally
  # define ARCH_REGS    struct user_pt_regs
  # define SYSCALL_NUM  regs[8]
  # define SYSCALL_RET  regs[0]
 +#elif defined(__riscv) && __riscv_xlen == 64
 +# define ARCH_REGS    struct user_regs_struct
 +# define SYSCALL_NUM  a7
 +# define SYSCALL_RET  a0
  #elif defined(__hppa__)
  # define ARCH_REGS    struct user_regs_struct
  # define SYSCALL_NUM  gr[20]
@@@ -1682,7 -1682,7 +1688,7 @@@ void change_syscall(struct __test_metad
        EXPECT_EQ(0, ret) {}
  
  #if defined(__x86_64__) || defined(__i386__) || defined(__powerpc__) || \
 -    defined(__s390__) || defined(__hppa__)
 +      defined(__s390__) || defined(__hppa__) || defined(__riscv)
        {
                regs.SYSCALL_NUM = syscall;
        }
@@@ -3083,7 -3083,7 +3089,7 @@@ static int user_trap_syscall(int nr, un
        return seccomp(SECCOMP_SET_MODE_FILTER, flags, &prog);
  }
  
- #define USER_NOTIF_MAGIC 116983961184613L
+ #define USER_NOTIF_MAGIC INT_MAX
  TEST(user_notification_basic)
  {
        pid_t pid;
@@@ -3491,6 -3491,108 +3497,108 @@@ TEST(seccomp_get_notif_sizes
        EXPECT_EQ(sizes.seccomp_notif_resp, sizeof(struct seccomp_notif_resp));
  }
  
+ static int filecmp(pid_t pid1, pid_t pid2, int fd1, int fd2)
+ {
+ #ifdef __NR_kcmp
+       return syscall(__NR_kcmp, pid1, pid2, KCMP_FILE, fd1, fd2);
+ #else
+       errno = ENOSYS;
+       return -1;
+ #endif
+ }
+ TEST(user_notification_continue)
+ {
+       pid_t pid;
+       long ret;
+       int status, listener;
+       struct seccomp_notif req = {};
+       struct seccomp_notif_resp resp = {};
+       struct pollfd pollfd;
+       ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
+       ASSERT_EQ(0, ret) {
+               TH_LOG("Kernel does not support PR_SET_NO_NEW_PRIVS!");
+       }
+       listener = user_trap_syscall(__NR_dup, SECCOMP_FILTER_FLAG_NEW_LISTENER);
+       ASSERT_GE(listener, 0);
+       pid = fork();
+       ASSERT_GE(pid, 0);
+       if (pid == 0) {
+               int dup_fd, pipe_fds[2];
+               pid_t self;
+               ret = pipe(pipe_fds);
+               if (ret < 0)
+                       exit(1);
+               dup_fd = dup(pipe_fds[0]);
+               if (dup_fd < 0)
+                       exit(1);
+               self = getpid();
+               ret = filecmp(self, self, pipe_fds[0], dup_fd);
+               if (ret)
+                       exit(2);
+               exit(0);
+       }
+       pollfd.fd = listener;
+       pollfd.events = POLLIN | POLLOUT;
+       EXPECT_GT(poll(&pollfd, 1, -1), 0);
+       EXPECT_EQ(pollfd.revents, POLLIN);
+       EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
+       pollfd.fd = listener;
+       pollfd.events = POLLIN | POLLOUT;
+       EXPECT_GT(poll(&pollfd, 1, -1), 0);
+       EXPECT_EQ(pollfd.revents, POLLOUT);
+       EXPECT_EQ(req.data.nr, __NR_dup);
+       resp.id = req.id;
+       resp.flags = SECCOMP_USER_NOTIF_FLAG_CONTINUE;
+       /*
+        * Verify that setting SECCOMP_USER_NOTIF_FLAG_CONTINUE enforces other
+        * args be set to 0.
+        */
+       resp.error = 0;
+       resp.val = USER_NOTIF_MAGIC;
+       EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), -1);
+       EXPECT_EQ(errno, EINVAL);
+       resp.error = USER_NOTIF_MAGIC;
+       resp.val = 0;
+       EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), -1);
+       EXPECT_EQ(errno, EINVAL);
+       resp.error = 0;
+       resp.val = 0;
+       EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0) {
+               if (errno == EINVAL)
+                       XFAIL(goto skip, "Kernel does not support SECCOMP_USER_NOTIF_FLAG_CONTINUE");
+       }
+ skip:
+       EXPECT_EQ(waitpid(pid, &status, 0), pid);
+       EXPECT_EQ(true, WIFEXITED(status));
+       EXPECT_EQ(0, WEXITSTATUS(status)) {
+               if (WEXITSTATUS(status) == 2) {
+                       XFAIL(return, "Kernel does not support kcmp() syscall");
+                       return;
+               }
+       }
+ }
  /*
   * TODO:
   * - add microbenchmarks