[PATCH] all: only request the userspace notification fd once
authorPaul Moore <paul@paul-moore.com>
Sun, 26 Jul 2020 15:01:49 +0000 (11:01 -0400)
committerFelix Geyer <fgeyer@debian.org>
Sun, 8 Nov 2020 18:59:21 +0000 (18:59 +0000)
It turns out that requesting the seccomp userspace notifcation fd
more than once is a bad thing which causes the kernel to complain
(rightfully so for a variety of reasons).  Unfortunately as we were
always requesting the notification fd whenever possible this results
in problems at filter load time.

Our solution is to move the notification fd out of the filter context
and into the global task context, using a newly created task_state
structure.  This allows us to store, and retrieve the notification
outside the scope of an individual filter context.  It also provides
some implementation improvements by giving us a convenient place to
stash all of the API level related support variables.  We also extend
the seccomp_reset() API call to reset this internal global state when
passed a NULL filter context.

There is one potential case which we don't currently handle well:
threads.  At the moment libseccomp is thread ignorant, and that works
well as the only global state up to this point was the currently
supported API level information which was common to all threads in a
process.  Unfortunately, it appears that the notification fd need not
be common to all threads in a process, yet this patch treats it as if
it is common.  I suspect this is a very unusual use case so I decided
to keep this patch simple and ignore this case, but in the future if
we need to support this properly we should be able to do so without
API changes by keeping an internal list of notification fds indexed
by gettid(2).

This fixes the GitHub issue below:
* https://github.com/seccomp/libseccomp/issues/273

Reported-by: Tobias Stoeckmann <tobias@stoeckmann.org>
Acked-by: Tom Hromatka <tom.hromatka@oracle.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
(imported from commit ce314fe4111887c593e3c6b17c60d93bc6ab66b9)

Gbp-Pq: Name all_only_request_the_userspace_notification_fd_once.patch

doc/man/man3/seccomp_init.3
doc/man/man3/seccomp_notify_alloc.3
src/api.c
src/db.c
src/db.h
src/system.c
src/system.h
tests/11-basic-basic_errors.c
tests/51-live-user_notification.c
tests/51-live-user_notification.py

index 3ab68feffcb8ebaa8526719875660ba435886aae..87520cd3ba5e243a9af031ea4a684314d6c58272 100644 (file)
@@ -36,7 +36,15 @@ The
 function releases the existing filter context state before reinitializing it
 and can only be called after a call to
 .BR seccomp_init ()
-has succeeded.
+has succeeded.  If
+.BR seccomp_reset ()
+is called with a NULL filter, it resets the library's global task state;
+normally this is not needed, but it may be required to continue using the
+library after a
+.BR fork ()
+or
+.BR clone ()
+call to ensure the API level and user notification state is properly reset.
 .P
 When the caller is finished configuring the seccomp filter and has loaded it
 into the kernel, the caller should call
index 50c8970644eb73d7d4daa878a87e6d21b7a5dd22..cb1c04806f48092cfcc9552feba06f6ff42af69f 100644 (file)
@@ -59,7 +59,8 @@ returns the notification fd of a filter after it has been loaded.
 .\" //////////////////////////////////////////////////////////////////////////
 The
 .BR seccomp_notify_fd ()
-returns the notification fd of the loaded filter.
+returns the notification fd of the loaded filter, -1 if a notification fd has
+not yet been created, and -EINVAL if the filter context is invalid.
 .P
 The
 .BR seccomp_notify_id_valid ()
index 00975ad50915894c34226007b9101080de72319d..5cec0883633fe8334973319c80646d068ac37860 100644 (file)
--- a/src/api.c
+++ b/src/api.c
@@ -301,10 +301,18 @@ API int seccomp_reset(scmp_filter_ctx ctx, uint32_t def_action)
 {
        struct db_filter_col *col = (struct db_filter_col *)ctx;
 
-       /* use a NULL filter collection here since we are resetting it */
-       if (ctx == NULL || db_col_action_valid(NULL, def_action) < 0)
+       /* a NULL filter context indicates we are resetting the global state */
+       if (ctx == NULL) {
+               /* reset the global state and redetermine the api level */
+               sys_reset_state();
+               _seccomp_api_update();
+               return _rc_filter(0);
+       }
+       /* ensure the default action is valid */
+       if (db_col_action_valid(NULL, def_action) < 0)
                return _rc_filter(-EINVAL);
 
+       /* reset the filter */
        return _rc_filter(db_col_reset(col, def_action));
 }
 
@@ -675,16 +683,17 @@ API int seccomp_notify_id_valid(int fd, uint64_t id)
 /* NOTE - function header comment in include/seccomp.h */
 API int seccomp_notify_fd(const scmp_filter_ctx ctx)
 {
-       struct db_filter_col *col;
+       /* NOTE: for historical reasons, and possibly future use, we require a
+        * valid filter context even though we don't actual use it here; the
+        * api update is also not strictly necessary, but keep it for now */
 
        /* force a runtime api level detection */
        _seccomp_api_update();
 
        if (_ctx_valid(ctx))
                return _rc_filter(-EINVAL);
-       col = (struct db_filter_col *)ctx;
 
-       return _rc_filter(col->notify_fd);
+       return _rc_filter(sys_notify_fd());
 }
 
 /* NOTE - function header comment in include/seccomp.h */
index 4a87ea36d08693c8169c42eea2fa1f33a4709a86..836171aef026af958ff99af716da409389548358 100644 (file)
--- a/src/db.c
+++ b/src/db.c
@@ -1057,7 +1057,6 @@ int db_col_reset(struct db_filter_col *col, uint32_t def_action)
        if (col->filters)
                free(col->filters);
        col->filters = NULL;
-       col->notify_fd = -1;
 
        /* set the endianess to undefined */
        col->endian = 0;
index b96b1049aecefed784150bd659a8b824c206f8bb..765c607eaa1628aee1707531be95b842c18fcc68 100644 (file)
--- a/src/db.h
+++ b/src/db.h
@@ -160,8 +160,7 @@ struct db_filter_col {
        /* transaction snapshots */
        struct db_filter_snap *snapshots;
 
-       /* notification fd that was returned from seccomp() */
-       int notify_fd;
+       /* userspace notification */
        bool notify_used;
 };
 
index 6cdfc16ac2c7e48245255f095457c66d116ad46e..3b43b2a967106fc7903178b5402a22f0211ef672 100644 (file)
  *       our next release we may have to enable the allowlist */
 #define SYSCALL_ALLOWLIST_ENABLE       0
 
-static int _nr_seccomp = -1;
-static int _support_seccomp_syscall = -1;
-static int _support_seccomp_flag_tsync = -1;
-static int _support_seccomp_flag_log = -1;
-static int _support_seccomp_action_log = -1;
-static int _support_seccomp_kill_process = -1;
-static int _support_seccomp_flag_spec_allow = -1;
-static int _support_seccomp_flag_new_listener = -1;
-static int _support_seccomp_user_notif = -1;
-static int _support_seccomp_flag_tsync_esrch = -1;
+/* task global state */
+struct task_state {
+       /* seccomp(2) syscall */
+       int nr_seccomp;
+
+       /* userspace notification fd */
+       int notify_fd;
+
+       /* runtime support flags */
+       int sup_syscall;
+       int sup_flag_tsync;
+       int sup_flag_log;
+       int sup_action_log;
+       int sup_kill_process;
+       int sup_flag_spec_allow;
+       int sup_flag_new_listener;
+       int sup_user_notif;
+       int sup_flag_tsync_esrch;
+};
+static struct task_state state = {
+       .nr_seccomp = -1,
+
+       .notify_fd = -1,
+
+       .sup_syscall = -1,
+       .sup_flag_tsync = -1,
+       .sup_flag_log = -1,
+       .sup_action_log = -1,
+       .sup_kill_process = -1,
+       .sup_flag_spec_allow = -1,
+       .sup_flag_new_listener = -1,
+       .sup_user_notif = -1,
+       .sup_flag_tsync_esrch = -1,
+};
+
+/**
+ * Reset the task state
+ *
+ * This function fully resets the library's global "system task state".
+ *
+ */
+void sys_reset_state(void)
+{
+       state.nr_seccomp = -1;
+       state.notify_fd = -1;
+       state.sup_syscall = -1;
+       state.sup_flag_tsync = -1;
+       state.sup_flag_log = -1;
+       state.sup_action_log = -1;
+       state.sup_kill_process = -1;
+       state.sup_flag_spec_allow = -1;
+       state.sup_flag_new_listener = -1;
+       state.sup_user_notif = -1;
+       state.sup_flag_tsync_esrch = -1;
+}
 
 /**
  * Check to see if the seccomp() syscall is supported
@@ -68,8 +113,8 @@ int sys_chk_seccomp_syscall(void)
        /* NOTE: it is reasonably safe to assume that we should be able to call
         *       seccomp() when the caller first starts, but we can't rely on
         *       it later so we need to cache our findings for use later */
-       if (_support_seccomp_syscall >= 0)
-               return _support_seccomp_syscall;
+       if (state.sup_syscall >= 0)
+               return state.sup_syscall;
 
 #if SYSCALL_ALLOWLIST_ENABLE
        /* architecture allowlist */
@@ -100,11 +145,11 @@ int sys_chk_seccomp_syscall(void)
                goto supported;
 
 unsupported:
-       _support_seccomp_syscall = 0;
+       state.sup_syscall = 0;
        return 0;
 supported:
-       _nr_seccomp = nr_seccomp;
-       _support_seccomp_syscall = 1;
+       state.nr_seccomp = nr_seccomp;
+       state.sup_syscall = 1;
        return 1;
 }
 
@@ -118,7 +163,7 @@ supported:
  */
 void sys_set_seccomp_syscall(bool enable)
 {
-       _support_seccomp_syscall = (enable ? 1 : 0);
+       state.sup_syscall = (enable ? 1 : 0);
 }
 
 /**
@@ -132,16 +177,16 @@ void sys_set_seccomp_syscall(bool enable)
 int sys_chk_seccomp_action(uint32_t action)
 {
        if (action == SCMP_ACT_KILL_PROCESS) {
-               if (_support_seccomp_kill_process < 0) {
+               if (state.sup_kill_process < 0) {
                        if (sys_chk_seccomp_syscall() == 1 &&
-                           syscall(_nr_seccomp, SECCOMP_GET_ACTION_AVAIL, 0,
-                                   &action) == 0)
-                               _support_seccomp_kill_process = 1;
+                           syscall(state.nr_seccomp,
+                                   SECCOMP_GET_ACTION_AVAIL, 0, &action) == 0)
+                               state.sup_kill_process = 1;
                        else
-                               _support_seccomp_kill_process = 0;
+                               state.sup_kill_process = 0;
                }
 
-               return _support_seccomp_kill_process;
+               return state.sup_kill_process;
        } else if (action == SCMP_ACT_KILL_THREAD) {
                return 1;
        } else if (action == SCMP_ACT_TRAP) {
@@ -152,30 +197,30 @@ int sys_chk_seccomp_action(uint32_t action)
        } else if (action == SCMP_ACT_TRACE(action & 0x0000ffff)) {
                return 1;
        } else if (action == SCMP_ACT_LOG) {
-               if (_support_seccomp_action_log < 0) {
+               if (state.sup_action_log < 0) {
                        if (sys_chk_seccomp_syscall() == 1 &&
-                           syscall(_nr_seccomp, SECCOMP_GET_ACTION_AVAIL, 0,
-                                   &action) == 0)
-                               _support_seccomp_action_log = 1;
+                           syscall(state.nr_seccomp,
+                                   SECCOMP_GET_ACTION_AVAIL, 0, &action) == 0)
+                               state.sup_action_log = 1;
                        else
-                               _support_seccomp_action_log = 0;
+                               state.sup_action_log = 0;
                }
 
-               return _support_seccomp_action_log;
+               return state.sup_action_log;
        } else if (action == SCMP_ACT_ALLOW) {
                return 1;
        } else if (action == SCMP_ACT_NOTIFY) {
-               if (_support_seccomp_user_notif < 0) {
+               if (state.sup_user_notif < 0) {
                        struct seccomp_notif_sizes sizes;
                        if (sys_chk_seccomp_syscall() == 1 &&
-                           syscall(_nr_seccomp, SECCOMP_GET_NOTIF_SIZES, 0,
-                                   &sizes) == 0)
-                               _support_seccomp_user_notif = 1;
+                           syscall(state.nr_seccomp,
+                                   SECCOMP_GET_NOTIF_SIZES, 0, &sizes) == 0)
+                               state.sup_user_notif = 1;
                        else
-                               _support_seccomp_user_notif = 0;
+                               state.sup_user_notif = 0;
                }
 
-               return _support_seccomp_user_notif;
+               return state.sup_user_notif;
        }
 
        return 0;
@@ -193,13 +238,13 @@ void sys_set_seccomp_action(uint32_t action, bool enable)
 {
        switch (action) {
        case SCMP_ACT_LOG:
-               _support_seccomp_action_log = (enable ? 1 : 0);
+               state.sup_action_log = (enable ? 1 : 0);
                break;
        case SCMP_ACT_KILL_PROCESS:
-               _support_seccomp_kill_process = (enable ? 1 : 0);
+               state.sup_kill_process = (enable ? 1 : 0);
                break;
        case SCMP_ACT_NOTIFY:
-               _support_seccomp_user_notif = (enable ? 1 : 0);
+               state.sup_user_notif = (enable ? 1 : 0);
                break;
        }
 }
@@ -212,13 +257,14 @@ void sys_set_seccomp_action(uint32_t action, bool enable)
  * Return one if the flag is supported, zero otherwise.
  *
  */
-static int _sys_chk_seccomp_flag_kernel(int flag)
+static int _sys_chk_flag_kernel(int flag)
 {
        /* this is an invalid seccomp(2) call because the last argument
         * is NULL, but depending on the errno value of EFAULT we can
         * guess if the filter flag is supported or not */
        if (sys_chk_seccomp_syscall() == 1 &&
-           syscall(_nr_seccomp, SECCOMP_SET_MODE_FILTER, flag, NULL) == -1 &&
+           syscall(state.nr_seccomp,
+                   SECCOMP_SET_MODE_FILTER, flag, NULL) == -1 &&
            errno == EFAULT)
                return 1;
 
@@ -238,29 +284,25 @@ int sys_chk_seccomp_flag(int flag)
 {
        switch (flag) {
        case SECCOMP_FILTER_FLAG_TSYNC:
-               if (_support_seccomp_flag_tsync < 0)
-                       _support_seccomp_flag_tsync = _sys_chk_seccomp_flag_kernel(flag);
-
-               return _support_seccomp_flag_tsync;
+               if (state.sup_flag_tsync < 0)
+                       state.sup_flag_tsync = _sys_chk_flag_kernel(flag);
+               return state.sup_flag_tsync;
        case SECCOMP_FILTER_FLAG_LOG:
-               if (_support_seccomp_flag_log < 0)
-                       _support_seccomp_flag_log = _sys_chk_seccomp_flag_kernel(flag);
-
-               return _support_seccomp_flag_log;
+               if (state.sup_flag_log < 0)
+                       state.sup_flag_log = _sys_chk_flag_kernel(flag);
+               return state.sup_flag_log;
        case SECCOMP_FILTER_FLAG_SPEC_ALLOW:
-               if (_support_seccomp_flag_spec_allow < 0)
-                       _support_seccomp_flag_spec_allow = _sys_chk_seccomp_flag_kernel(flag);
-
-               return _support_seccomp_flag_spec_allow;
+               if (state.sup_flag_spec_allow < 0)
+                       state.sup_flag_spec_allow = _sys_chk_flag_kernel(flag);
+               return state.sup_flag_spec_allow;
        case SECCOMP_FILTER_FLAG_NEW_LISTENER:
-               if (_support_seccomp_flag_new_listener < 0)
-                       _support_seccomp_flag_new_listener = _sys_chk_seccomp_flag_kernel(flag);
-
-               return _support_seccomp_flag_new_listener;
+               if (state.sup_flag_new_listener < 0)
+                       state.sup_flag_new_listener = _sys_chk_flag_kernel(flag);
+               return state.sup_flag_new_listener;
        case SECCOMP_FILTER_FLAG_TSYNC_ESRCH:
-               if (_support_seccomp_flag_tsync_esrch < 0)
-                       _support_seccomp_flag_tsync_esrch = _sys_chk_seccomp_flag_kernel(flag);
-               return _support_seccomp_flag_tsync_esrch;
+               if (state.sup_flag_tsync_esrch < 0)
+                       state.sup_flag_tsync_esrch = _sys_chk_flag_kernel(flag);
+               return state.sup_flag_tsync_esrch;
        }
 
        return -EOPNOTSUPP;
@@ -279,19 +321,19 @@ void sys_set_seccomp_flag(int flag, bool enable)
 {
        switch (flag) {
        case SECCOMP_FILTER_FLAG_TSYNC:
-               _support_seccomp_flag_tsync = (enable ? 1 : 0);
+               state.sup_flag_tsync = (enable ? 1 : 0);
                break;
        case SECCOMP_FILTER_FLAG_LOG:
-               _support_seccomp_flag_log = (enable ? 1 : 0);
+               state.sup_flag_log = (enable ? 1 : 0);
                break;
        case SECCOMP_FILTER_FLAG_SPEC_ALLOW:
-               _support_seccomp_flag_spec_allow = (enable ? 1 : 0);
+               state.sup_flag_spec_allow = (enable ? 1 : 0);
                break;
        case SECCOMP_FILTER_FLAG_NEW_LISTENER:
-               _support_seccomp_flag_new_listener = (enable ? 1 : 0);
+               state.sup_flag_new_listener = (enable ? 1 : 0);
                break;
        case SECCOMP_FILTER_FLAG_TSYNC_ESRCH:
-               _support_seccomp_flag_tsync_esrch = (enable ? 1 : 0);
+               state.sup_flag_tsync_esrch = (enable ? 1 : 0);
                break;
        }
 }
@@ -324,7 +366,7 @@ int sys_filter_load(struct db_filter_col *col, bool rawrc)
                        goto filter_load_out;
        }
 
-       tsync_notify = (_support_seccomp_flag_tsync_esrch > 0);
+       tsync_notify = state.sup_flag_tsync_esrch > 0 && state.notify_fd == -1;
 
        /* load the filter into the kernel */
        if (sys_chk_seccomp_syscall() == 1) {
@@ -333,28 +375,29 @@ int sys_filter_load(struct db_filter_col *col, bool rawrc)
                        if (col->attr.tsync_enable)
                                flgs |= SECCOMP_FILTER_FLAG_TSYNC | \
                                        SECCOMP_FILTER_FLAG_TSYNC_ESRCH;
-                       if (_support_seccomp_user_notif > 0)
+                       if (state.sup_user_notif > 0)
                                flgs |= SECCOMP_FILTER_FLAG_NEW_LISTENER;
                } else if (col->attr.tsync_enable)
                        flgs |= SECCOMP_FILTER_FLAG_TSYNC;
-               else if (_support_seccomp_user_notif > 0)
+               else if (state.sup_user_notif > 0 && state.notify_fd == -1)
                        flgs |= SECCOMP_FILTER_FLAG_NEW_LISTENER;
                if (col->attr.log_enable)
                        flgs |= SECCOMP_FILTER_FLAG_LOG;
                if (col->attr.spec_allow)
                        flgs |= SECCOMP_FILTER_FLAG_SPEC_ALLOW;
-               rc = syscall(_nr_seccomp, SECCOMP_SET_MODE_FILTER, flgs, prgm);
+               rc = syscall(state.nr_seccomp,
+                            SECCOMP_SET_MODE_FILTER, flgs, prgm);
                if (tsync_notify && rc > 0) {
                        /* return 0 on NEW_LISTENER success, but save the fd */
-                       col->notify_fd = rc;
+                       state.notify_fd = rc;
                        rc = 0;
                } else if (rc > 0 && col->attr.tsync_enable) {
                        /* always return -ESRCH if we fail to sync threads */
                        errno = ESRCH;
                        rc = -errno;
-               } else if (rc > 0 && _support_seccomp_user_notif > 0) {
+               } else if (rc > 0 && state.sup_user_notif > 0) {
                        /* return 0 on NEW_LISTENER success, but save the fd */
-                       col->notify_fd = rc;
+                       state.notify_fd = rc;
                        rc = 0;
                }
        } else
@@ -370,6 +413,19 @@ filter_load_out:
        return rc;
 }
 
+/**
+ * Return the userspace notification fd
+ *
+ * This function returns the userspace notification fd from
+ * SECCOMP_FILTER_FLAG_NEW_LISTENER.  If the notification fd has not yet been
+ * set, or an error has occurred, -1 is returned.
+ *
+ */
+int sys_notify_fd(void)
+{
+       return state.notify_fd;
+}
+
 /**
  * Allocate a pair of notification request/response structures
  * @param req the request location
@@ -386,7 +442,7 @@ int sys_notify_alloc(struct seccomp_notif **req,
        int rc;
        static struct seccomp_notif_sizes sizes = { 0, 0, 0 };
 
-       if (_support_seccomp_syscall <= 0)
+       if (state.sup_syscall <= 0)
                return -EOPNOTSUPP;
 
        if (sizes.seccomp_notif == 0 && sizes.seccomp_notif_resp == 0) {
@@ -427,7 +483,7 @@ int sys_notify_alloc(struct seccomp_notif **req,
  */
 int sys_notify_receive(int fd, struct seccomp_notif *req)
 {
-       if (_support_seccomp_user_notif <= 0)
+       if (state.sup_user_notif <= 0)
                return -EOPNOTSUPP;
 
        if (ioctl(fd, SECCOMP_IOCTL_NOTIF_RECV, req) < 0)
@@ -448,7 +504,7 @@ int sys_notify_receive(int fd, struct seccomp_notif *req)
  */
 int sys_notify_respond(int fd, struct seccomp_notif_resp *resp)
 {
-       if (_support_seccomp_user_notif <= 0)
+       if (state.sup_user_notif <= 0)
                return -EOPNOTSUPP;
 
        if (ioctl(fd, SECCOMP_IOCTL_NOTIF_SEND, resp) < 0)
@@ -467,7 +523,7 @@ int sys_notify_respond(int fd, struct seccomp_notif_resp *resp)
  */
 int sys_notify_id_valid(int fd, uint64_t id)
 {
-       if (_support_seccomp_user_notif <= 0)
+       if (state.sup_user_notif <= 0)
                return -EOPNOTSUPP;
 
        if (ioctl(fd, SECCOMP_IOCTL_NOTIF_ID_VALID, &id) < 0)
index 133f9b11068cfbb0aa34d58f0438af78abdcd479..096f3cad2c38334f65658a046e5c1b3a487edcf5 100644 (file)
@@ -182,6 +182,8 @@ struct seccomp_notif_resp {
 #define SECCOMP_IOCTL_NOTIF_ID_VALID    SECCOMP_IOR(2, __u64)
 #endif /* SECCOMP_RET_USER_NOTIF */
 
+void sys_reset_state(void);
+
 int sys_chk_seccomp_syscall(void);
 void sys_set_seccomp_syscall(bool enable);
 
@@ -193,6 +195,7 @@ void sys_set_seccomp_flag(int flag, bool enable);
 
 int sys_filter_load(struct db_filter_col *col, bool rawrc);
 
+int sys_notify_fd(void);
 int sys_notify_alloc(struct seccomp_notif **req,
                     struct seccomp_notif_resp **resp);
 int sys_notify_receive(int fd, struct seccomp_notif *req);
index d3b225664aa0a2c1561a7b3882ac81a59ff79c97..da059df2b367af61f6f5f840b662cd22a06b8e19 100644 (file)
@@ -41,12 +41,9 @@ int main(int argc, char *argv[])
        seccomp_release(ctx);
        ctx = NULL;
 
-       /* seccomp_reset error */
-       rc = seccomp_reset(ctx, SCMP_ACT_KILL + 1);
-       if (rc != -EINVAL)
-               return -1;
-       rc = seccomp_reset(ctx, SCMP_ACT_KILL);
-       if (rc != -EINVAL)
+       /* ensure that seccomp_reset(NULL, ...) is accepted */
+       rc = seccomp_reset(NULL, SCMP_ACT_ALLOW);
+       if (rc != 0)
                return -1;
 
        /* seccomp_load error */
index de31d2f0fa1e9d7303433c4c54699826d613a9f3..a00627b45896a617c0c4a6b2d98b9fde57184965 100644 (file)
@@ -98,6 +98,27 @@ int main(int argc, char *argv[])
                goto out;
        }
 
+       rc = seccomp_reset(ctx, SCMP_ACT_ALLOW);
+       if (rc < 0)
+               goto out;
+
+       rc = seccomp_rule_add(ctx, SCMP_ACT_NOTIFY, SCMP_SYS(getppid), 0, NULL);
+       if (rc)
+               goto out;
+
+       rc  = seccomp_load(ctx);
+       if (rc < 0)
+               goto out;
+
+       rc = seccomp_notify_fd(ctx);
+       if (rc < 0)
+               goto out;
+       if (rc != fd) {
+               rc = -EFAULT;
+               goto out;
+       } else
+               rc = 0;
+
 out:
        if (fd >= 0)
                close(fd);
index 0d81f5e1b6275fc88d1af689bc87744ab8212b2b..3449c44c43d1668d4497479d2f1a25d70f832c30 100755 (executable)
@@ -52,6 +52,10 @@ def test():
             raise RuntimeError("Child process error")
         if os.WEXITSTATUS(rc) != 0:
             raise RuntimeError("Child process error")
+        f.reset(ALLOW)
+        f.add_rule(NOTIFY, "getppid")
+        f.load()
+        # no easy way to check the notification fd here
         quit(160)
 
 test()