Merge branch 'next-seccomp' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 2 Jan 2019 17:48:13 +0000 (09:48 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 2 Jan 2019 17:48:13 +0000 (09:48 -0800)
Pull seccomp updates from James Morris:

 - Add SECCOMP_RET_USER_NOTIF

 - seccomp fixes for sparse warnings and s390 build (Tycho)

* 'next-seccomp' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security:
  seccomp, s390: fix build for syscall type change
  seccomp: fix poor type promotion
  samples: add an example of seccomp user trap
  seccomp: add a return code to trap to userspace
  seccomp: switch system call argument type to void *
  seccomp: hoist struct seccomp_data recalculation higher

1  2 
include/linux/syscalls.h
tools/testing/selftests/seccomp/seccomp_bpf.c

diff --combined include/linux/syscalls.h
index 251979d2e70919ca7bc80e7204617e70201213ef,a60694fb0f58c9a5a1bb45103d72b2cc0d80d17a..257cccba30625726c0f78670b3a2c6188ee801eb
@@@ -296,18 -296,12 +296,18 @@@ asmlinkage long sys_io_getevents(aio_co
                                long min_nr,
                                long nr,
                                struct io_event __user *events,
 -                              struct timespec __user *timeout);
 +                              struct __kernel_timespec __user *timeout);
  asmlinkage long sys_io_pgetevents(aio_context_t ctx_id,
                                long min_nr,
                                long nr,
                                struct io_event __user *events,
 -                              struct timespec __user *timeout,
 +                              struct __kernel_timespec __user *timeout,
 +                              const struct __aio_sigset *sig);
 +asmlinkage long sys_io_pgetevents_time32(aio_context_t ctx_id,
 +                              long min_nr,
 +                              long nr,
 +                              struct io_event __user *events,
 +                              struct old_timespec32 __user *timeout,
                                const struct __aio_sigset *sig);
  
  /* fs/xattr.c */
@@@ -472,16 -466,10 +472,16 @@@ asmlinkage long sys_sendfile64(int out_
  
  /* fs/select.c */
  asmlinkage long sys_pselect6(int, fd_set __user *, fd_set __user *,
 -                           fd_set __user *, struct timespec __user *,
 +                           fd_set __user *, struct __kernel_timespec __user *,
 +                           void __user *);
 +asmlinkage long sys_pselect6_time32(int, fd_set __user *, fd_set __user *,
 +                           fd_set __user *, struct old_timespec32 __user *,
                             void __user *);
  asmlinkage long sys_ppoll(struct pollfd __user *, unsigned int,
 -                        struct timespec __user *, const sigset_t __user *,
 +                        struct __kernel_timespec __user *, const sigset_t __user *,
 +                        size_t);
 +asmlinkage long sys_ppoll_time32(struct pollfd __user *, unsigned int,
 +                        struct old_timespec32 __user *, const sigset_t __user *,
                          size_t);
  
  /* fs/signalfd.c */
@@@ -553,7 -541,7 +553,7 @@@ asmlinkage long sys_unshare(unsigned lo
  
  /* kernel/futex.c */
  asmlinkage long sys_futex(u32 __user *uaddr, int op, u32 val,
 -                      struct timespec __user *utime, u32 __user *uaddr2,
 +                      struct __kernel_timespec __user *utime, u32 __user *uaddr2,
                        u32 val3);
  asmlinkage long sys_get_robust_list(int pid,
                                    struct robust_list_head __user * __user *head_ptr,
@@@ -649,10 -637,6 +649,10 @@@ asmlinkage long sys_rt_sigtimedwait(con
                                siginfo_t __user *uinfo,
                                const struct __kernel_timespec __user *uts,
                                size_t sigsetsize);
 +asmlinkage long sys_rt_sigtimedwait_time32(const sigset_t __user *uthese,
 +                              siginfo_t __user *uinfo,
 +                              const struct old_timespec32 __user *uts,
 +                              size_t sigsetsize);
  asmlinkage long sys_rt_sigqueueinfo(pid_t pid, int sig, siginfo_t __user *uinfo);
  
  /* kernel/sys.c */
@@@ -847,9 -831,6 +847,9 @@@ asmlinkage long sys_accept4(int, struc
  asmlinkage long sys_recvmmsg(int fd, struct mmsghdr __user *msg,
                             unsigned int vlen, unsigned flags,
                             struct __kernel_timespec __user *timeout);
 +asmlinkage long sys_recvmmsg_time32(int fd, struct mmsghdr __user *msg,
 +                           unsigned int vlen, unsigned flags,
 +                           struct old_timespec32 __user *timeout);
  
  asmlinkage long sys_wait4(pid_t pid, int __user *stat_addr,
                                int options, struct rusage __user *ru);
@@@ -898,7 -879,7 +898,7 @@@ asmlinkage long sys_renameat2(int olddf
                              int newdfd, const char __user *newname,
                              unsigned int flags);
  asmlinkage long sys_seccomp(unsigned int op, unsigned int flags,
-                           const char __user *uargs);
+                           void __user *uargs);
  asmlinkage long sys_getrandom(char __user *buf, size_t count,
                              unsigned int flags);
  asmlinkage long sys_memfd_create(const char __user *uname_ptr, unsigned int flags);
index c9a2abf8be1b38d0ea3d0ee14019b6078ca95af2,5c9768a1b8cd117c8f0cc30b65af6893a649af66..067cb4607d6cd519793b4ea2d26a5ef96f446e89
@@@ -5,6 -5,7 +5,7 @@@
   * Test code for seccomp bpf.
   */
  
+ #define _GNU_SOURCE
  #include <sys/types.h>
  
  /*
  #include <sys/fcntl.h>
  #include <sys/mman.h>
  #include <sys/times.h>
+ #include <sys/socket.h>
+ #include <sys/ioctl.h>
  
- #define _GNU_SOURCE
  #include <unistd.h>
  #include <sys/syscall.h>
+ #include <poll.h>
  
  #include "../kselftest_harness.h"
  
@@@ -133,6 -136,10 +136,10 @@@ struct seccomp_data 
  #define SECCOMP_GET_ACTION_AVAIL 2
  #endif
  
+ #ifndef SECCOMP_GET_NOTIF_SIZES
+ #define SECCOMP_GET_NOTIF_SIZES 3
+ #endif
  #ifndef SECCOMP_FILTER_FLAG_TSYNC
  #define SECCOMP_FILTER_FLAG_TSYNC (1UL << 0)
  #endif
@@@ -154,6 -161,44 +161,44 @@@ struct seccomp_metadata 
  };
  #endif
  
+ #ifndef SECCOMP_FILTER_FLAG_NEW_LISTENER
+ #define SECCOMP_FILTER_FLAG_NEW_LISTENER      (1UL << 3)
+ #define SECCOMP_RET_USER_NOTIF 0x7fc00000U
+ #define SECCOMP_IOC_MAGIC             '!'
+ #define SECCOMP_IO(nr)                        _IO(SECCOMP_IOC_MAGIC, nr)
+ #define SECCOMP_IOR(nr, type)         _IOR(SECCOMP_IOC_MAGIC, nr, type)
+ #define SECCOMP_IOW(nr, type)         _IOW(SECCOMP_IOC_MAGIC, nr, type)
+ #define SECCOMP_IOWR(nr, type)                _IOWR(SECCOMP_IOC_MAGIC, nr, type)
+ /* Flags for seccomp notification fd ioctl. */
+ #define SECCOMP_IOCTL_NOTIF_RECV      SECCOMP_IOWR(0, struct seccomp_notif)
+ #define SECCOMP_IOCTL_NOTIF_SEND      SECCOMP_IOWR(1, \
+                                               struct seccomp_notif_resp)
+ #define SECCOMP_IOCTL_NOTIF_ID_VALID  SECCOMP_IOR(2, __u64)
+ struct seccomp_notif {
+       __u64 id;
+       __u32 pid;
+       __u32 flags;
+       struct seccomp_data data;
+ };
+ struct seccomp_notif_resp {
+       __u64 id;
+       __s64 val;
+       __s32 error;
+       __u32 flags;
+ };
+ struct seccomp_notif_sizes {
+       __u16 seccomp_notif;
+       __u16 seccomp_notif_resp;
+       __u16 seccomp_data;
+ };
+ #endif
  #ifndef seccomp
  int seccomp(unsigned int op, unsigned int flags, void *args)
  {
@@@ -2077,7 -2122,8 +2122,8 @@@ TEST(detect_seccomp_filter_flags
  {
        unsigned int flags[] = { SECCOMP_FILTER_FLAG_TSYNC,
                                 SECCOMP_FILTER_FLAG_LOG,
-                                SECCOMP_FILTER_FLAG_SPEC_ALLOW };
+                                SECCOMP_FILTER_FLAG_SPEC_ALLOW,
+                                SECCOMP_FILTER_FLAG_NEW_LISTENER };
        unsigned int flag, all_flags;
        int i;
        long ret;
@@@ -2731,14 -2777,9 +2777,14 @@@ TEST(syscall_restart
        ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
        ASSERT_EQ(true, WIFSTOPPED(status));
        ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
 -      /* Verify signal delivery came from parent now. */
        ASSERT_EQ(0, ptrace(PTRACE_GETSIGINFO, child_pid, NULL, &info));
 -      EXPECT_EQ(getpid(), info.si_pid);
 +      /*
 +       * There is no siginfo on SIGSTOP any more, so we can't verify
 +       * signal delivery came from parent now (getpid() == info.si_pid).
 +       * https://lkml.kernel.org/r/CAGXu5jJaZAOzP1qFz66tYrtbuywqb+UN2SOA1VLHpCCOiYvYeg@mail.gmail.com
 +       * At least verify the SIGSTOP via PTRACE_GETSIGINFO.
 +       */
 +      EXPECT_EQ(SIGSTOP, info.si_signo);
  
        /* Restart nanosleep with SIGCONT, which triggers restart_syscall. */
        ASSERT_EQ(0, kill(child_pid, SIGCONT));
        ASSERT_EQ(0, kill(pid, SIGKILL));
  }
  
+ static int user_trap_syscall(int nr, unsigned int flags)
+ {
+       struct sock_filter filter[] = {
+               BPF_STMT(BPF_LD+BPF_W+BPF_ABS,
+                       offsetof(struct seccomp_data, nr)),
+               BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, nr, 0, 1),
+               BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_USER_NOTIF),
+               BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW),
+       };
+       struct sock_fprog prog = {
+               .len = (unsigned short)ARRAY_SIZE(filter),
+               .filter = filter,
+       };
+       return seccomp(SECCOMP_SET_MODE_FILTER, flags, &prog);
+ }
+ #define USER_NOTIF_MAGIC 116983961184613L
+ TEST(user_notification_basic)
+ {
+       pid_t pid;
+       long ret;
+       int status, listener;
+       struct seccomp_notif req = {};
+       struct seccomp_notif_resp resp = {};
+       struct pollfd pollfd;
+       struct sock_filter filter[] = {
+               BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
+       };
+       struct sock_fprog prog = {
+               .len = (unsigned short)ARRAY_SIZE(filter),
+               .filter = filter,
+       };
+       pid = fork();
+       ASSERT_GE(pid, 0);
+       /* Check that we get -ENOSYS with no listener attached */
+       if (pid == 0) {
+               if (user_trap_syscall(__NR_getpid, 0) < 0)
+                       exit(1);
+               ret = syscall(__NR_getpid);
+               exit(ret >= 0 || errno != ENOSYS);
+       }
+       EXPECT_EQ(waitpid(pid, &status, 0), pid);
+       EXPECT_EQ(true, WIFEXITED(status));
+       EXPECT_EQ(0, WEXITSTATUS(status));
+       /* Add some no-op filters so for grins. */
+       EXPECT_EQ(seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog), 0);
+       EXPECT_EQ(seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog), 0);
+       EXPECT_EQ(seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog), 0);
+       EXPECT_EQ(seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog), 0);
+       /* Check that the basic notification machinery works */
+       listener = user_trap_syscall(__NR_getpid,
+                                    SECCOMP_FILTER_FLAG_NEW_LISTENER);
+       EXPECT_GE(listener, 0);
+       /* Installing a second listener in the chain should EBUSY */
+       EXPECT_EQ(user_trap_syscall(__NR_getpid,
+                                   SECCOMP_FILTER_FLAG_NEW_LISTENER),
+                 -1);
+       EXPECT_EQ(errno, EBUSY);
+       pid = fork();
+       ASSERT_GE(pid, 0);
+       if (pid == 0) {
+               ret = syscall(__NR_getpid);
+               exit(ret != USER_NOTIF_MAGIC);
+       }
+       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_getpid);
+       resp.id = req.id;
+       resp.error = 0;
+       resp.val = USER_NOTIF_MAGIC;
+       /* check that we make sure flags == 0 */
+       resp.flags = 1;
+       EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), -1);
+       EXPECT_EQ(errno, EINVAL);
+       resp.flags = 0;
+       EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
+       EXPECT_EQ(waitpid(pid, &status, 0), pid);
+       EXPECT_EQ(true, WIFEXITED(status));
+       EXPECT_EQ(0, WEXITSTATUS(status));
+ }
+ TEST(user_notification_kill_in_middle)
+ {
+       pid_t pid;
+       long ret;
+       int listener;
+       struct seccomp_notif req = {};
+       struct seccomp_notif_resp resp = {};
+       listener = user_trap_syscall(__NR_getpid,
+                                    SECCOMP_FILTER_FLAG_NEW_LISTENER);
+       EXPECT_GE(listener, 0);
+       /*
+        * Check that nothing bad happens when we kill the task in the middle
+        * of a syscall.
+        */
+       pid = fork();
+       ASSERT_GE(pid, 0);
+       if (pid == 0) {
+               ret = syscall(__NR_getpid);
+               exit(ret != USER_NOTIF_MAGIC);
+       }
+       EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
+       EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ID_VALID, &req.id), 0);
+       EXPECT_EQ(kill(pid, SIGKILL), 0);
+       EXPECT_EQ(waitpid(pid, NULL, 0), pid);
+       EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_ID_VALID, &req.id), -1);
+       resp.id = req.id;
+       ret = ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp);
+       EXPECT_EQ(ret, -1);
+       EXPECT_EQ(errno, ENOENT);
+ }
+ static int handled = -1;
+ static void signal_handler(int signal)
+ {
+       if (write(handled, "c", 1) != 1)
+               perror("write from signal");
+ }
+ TEST(user_notification_signal)
+ {
+       pid_t pid;
+       long ret;
+       int status, listener, sk_pair[2];
+       struct seccomp_notif req = {};
+       struct seccomp_notif_resp resp = {};
+       char c;
+       ASSERT_EQ(socketpair(PF_LOCAL, SOCK_SEQPACKET, 0, sk_pair), 0);
+       listener = user_trap_syscall(__NR_gettid,
+                                    SECCOMP_FILTER_FLAG_NEW_LISTENER);
+       EXPECT_GE(listener, 0);
+       pid = fork();
+       ASSERT_GE(pid, 0);
+       if (pid == 0) {
+               close(sk_pair[0]);
+               handled = sk_pair[1];
+               if (signal(SIGUSR1, signal_handler) == SIG_ERR) {
+                       perror("signal");
+                       exit(1);
+               }
+               /*
+                * ERESTARTSYS behavior is a bit hard to test, because we need
+                * to rely on a signal that has not yet been handled. Let's at
+                * least check that the error code gets propagated through, and
+                * hope that it doesn't break when there is actually a signal :)
+                */
+               ret = syscall(__NR_gettid);
+               exit(!(ret == -1 && errno == 512));
+       }
+       close(sk_pair[1]);
+       EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
+       EXPECT_EQ(kill(pid, SIGUSR1), 0);
+       /*
+        * Make sure the signal really is delivered, which means we're not
+        * stuck in the user notification code any more and the notification
+        * should be dead.
+        */
+       EXPECT_EQ(read(sk_pair[0], &c, 1), 1);
+       resp.id = req.id;
+       resp.error = -EPERM;
+       resp.val = 0;
+       EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), -1);
+       EXPECT_EQ(errno, ENOENT);
+       EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
+       resp.id = req.id;
+       resp.error = -512; /* -ERESTARTSYS */
+       resp.val = 0;
+       EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
+       EXPECT_EQ(waitpid(pid, &status, 0), pid);
+       EXPECT_EQ(true, WIFEXITED(status));
+       EXPECT_EQ(0, WEXITSTATUS(status));
+ }
+ TEST(user_notification_closed_listener)
+ {
+       pid_t pid;
+       long ret;
+       int status, listener;
+       listener = user_trap_syscall(__NR_getpid,
+                                    SECCOMP_FILTER_FLAG_NEW_LISTENER);
+       EXPECT_GE(listener, 0);
+       /*
+        * Check that we get an ENOSYS when the listener is closed.
+        */
+       pid = fork();
+       ASSERT_GE(pid, 0);
+       if (pid == 0) {
+               close(listener);
+               ret = syscall(__NR_getpid);
+               exit(ret != -1 && errno != ENOSYS);
+       }
+       close(listener);
+       EXPECT_EQ(waitpid(pid, &status, 0), pid);
+       EXPECT_EQ(true, WIFEXITED(status));
+       EXPECT_EQ(0, WEXITSTATUS(status));
+ }
+ /*
+  * Check that a pid in a child namespace still shows up as valid in ours.
+  */
+ TEST(user_notification_child_pid_ns)
+ {
+       pid_t pid;
+       int status, listener;
+       struct seccomp_notif req = {};
+       struct seccomp_notif_resp resp = {};
+       ASSERT_EQ(unshare(CLONE_NEWPID), 0);
+       listener = user_trap_syscall(__NR_getpid, SECCOMP_FILTER_FLAG_NEW_LISTENER);
+       ASSERT_GE(listener, 0);
+       pid = fork();
+       ASSERT_GE(pid, 0);
+       if (pid == 0)
+               exit(syscall(__NR_getpid) != USER_NOTIF_MAGIC);
+       EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
+       EXPECT_EQ(req.pid, pid);
+       resp.id = req.id;
+       resp.error = 0;
+       resp.val = USER_NOTIF_MAGIC;
+       EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
+       EXPECT_EQ(waitpid(pid, &status, 0), pid);
+       EXPECT_EQ(true, WIFEXITED(status));
+       EXPECT_EQ(0, WEXITSTATUS(status));
+       close(listener);
+ }
+ /*
+  * Check that a pid in a sibling (i.e. unrelated) namespace shows up as 0, i.e.
+  * invalid.
+  */
+ TEST(user_notification_sibling_pid_ns)
+ {
+       pid_t pid, pid2;
+       int status, listener;
+       struct seccomp_notif req = {};
+       struct seccomp_notif_resp resp = {};
+       listener = user_trap_syscall(__NR_getpid, SECCOMP_FILTER_FLAG_NEW_LISTENER);
+       ASSERT_GE(listener, 0);
+       pid = fork();
+       ASSERT_GE(pid, 0);
+       if (pid == 0) {
+               ASSERT_EQ(unshare(CLONE_NEWPID), 0);
+               pid2 = fork();
+               ASSERT_GE(pid2, 0);
+               if (pid2 == 0)
+                       exit(syscall(__NR_getpid) != USER_NOTIF_MAGIC);
+               EXPECT_EQ(waitpid(pid2, &status, 0), pid2);
+               EXPECT_EQ(true, WIFEXITED(status));
+               EXPECT_EQ(0, WEXITSTATUS(status));
+               exit(WEXITSTATUS(status));
+       }
+       /* Create the sibling ns, and sibling in it. */
+       EXPECT_EQ(unshare(CLONE_NEWPID), 0);
+       EXPECT_EQ(errno, 0);
+       pid2 = fork();
+       EXPECT_GE(pid2, 0);
+       if (pid2 == 0) {
+               ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
+               /*
+                * The pid should be 0, i.e. the task is in some namespace that
+                * we can't "see".
+                */
+               ASSERT_EQ(req.pid, 0);
+               resp.id = req.id;
+               resp.error = 0;
+               resp.val = USER_NOTIF_MAGIC;
+               ASSERT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
+               exit(0);
+       }
+       close(listener);
+       EXPECT_EQ(waitpid(pid, &status, 0), pid);
+       EXPECT_EQ(true, WIFEXITED(status));
+       EXPECT_EQ(0, WEXITSTATUS(status));
+       EXPECT_EQ(waitpid(pid2, &status, 0), pid2);
+       EXPECT_EQ(true, WIFEXITED(status));
+       EXPECT_EQ(0, WEXITSTATUS(status));
+ }
+ TEST(user_notification_fault_recv)
+ {
+       pid_t pid;
+       int status, listener;
+       struct seccomp_notif req = {};
+       struct seccomp_notif_resp resp = {};
+       listener = user_trap_syscall(__NR_getpid, SECCOMP_FILTER_FLAG_NEW_LISTENER);
+       ASSERT_GE(listener, 0);
+       pid = fork();
+       ASSERT_GE(pid, 0);
+       if (pid == 0)
+               exit(syscall(__NR_getpid) != USER_NOTIF_MAGIC);
+       /* Do a bad recv() */
+       EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, NULL), -1);
+       EXPECT_EQ(errno, EFAULT);
+       /* We should still be able to receive this notification, though. */
+       EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_RECV, &req), 0);
+       EXPECT_EQ(req.pid, pid);
+       resp.id = req.id;
+       resp.error = 0;
+       resp.val = USER_NOTIF_MAGIC;
+       EXPECT_EQ(ioctl(listener, SECCOMP_IOCTL_NOTIF_SEND, &resp), 0);
+       EXPECT_EQ(waitpid(pid, &status, 0), pid);
+       EXPECT_EQ(true, WIFEXITED(status));
+       EXPECT_EQ(0, WEXITSTATUS(status));
+ }
+ TEST(seccomp_get_notif_sizes)
+ {
+       struct seccomp_notif_sizes sizes;
+       EXPECT_EQ(seccomp(SECCOMP_GET_NOTIF_SIZES, 0, &sizes), 0);
+       EXPECT_EQ(sizes.seccomp_notif, sizeof(struct seccomp_notif));
+       EXPECT_EQ(sizes.seccomp_notif_resp, sizeof(struct seccomp_notif_resp));
+ }
  /*
   * TODO:
   * - add microbenchmarks