From bd9ba4cd1c491cb90c5eb22cfa972a28a0fa05ef Mon Sep 17 00:00:00 2001 From: Tycho Andersen Date: Thu, 7 Feb 2019 07:42:39 -0700 Subject: [PATCH] api: implement user notification in libseccomp Kernel 5.0 includes the new user notification return code. Here's all the infrastructure to handle that. The idea behind the user notification return code is that the filter stops the syscall, and forwards it to a "listener fd" that is created when installing a filter. Then then some userspace task can listen and process events accordingly by taking some (or no) action in userspace, and then returning a value from the command. Signed-off-by: Tycho Andersen --- doc/man/man3/seccomp_api_get.3 | 4 + doc/man/man3/seccomp_attr_set.3 | 6 ++ include/seccomp.h.in | 108 ++++++++++++++++++++++++++ src/api.c | 66 ++++++++++++++++ src/db.c | 14 ++++ src/db.h | 5 ++ src/python/libseccomp.pxd | 3 +- src/python/seccomp.pyx | 1 + src/system.c | 90 ++++++++++++++++++++- src/system.h | 13 ++-- tests/.gitignore | 1 + tests/13-basic-attrs.c | 15 +++- tests/13-basic-attrs.py | 5 +- tests/51-live-user_notification.c | 95 ++++++++++++++++++++++ tests/51-live-user_notification.tests | 11 +++ tests/Makefile.am | 6 +- 16 files changed, 432 insertions(+), 11 deletions(-) create mode 100644 tests/51-live-user_notification.c create mode 100644 tests/51-live-user_notification.tests diff --git a/doc/man/man3/seccomp_api_get.3 b/doc/man/man3/seccomp_api_get.3 index ac3c2ff8..4f8c5c86 100644 --- a/doc/man/man3/seccomp_api_get.3 +++ b/doc/man/man3/seccomp_api_get.3 @@ -53,6 +53,10 @@ The SCMP_FLTATR_CTL_LOG filter attribute and the SCMP_ACT_LOG action are support .TP .B 4 The SCMP_FLTATR_SPEC_ALLOW filter attribute is supported. +.TP +.B 5 +The SCMP_FLTATR_NEW_LISTENER filter attribute and the SCMP_ACT_NEW_LISTENER +action are supported. .\" ////////////////////////////////////////////////////////////////////////// .SH RETURN VALUE .\" ////////////////////////////////////////////////////////////////////////// diff --git a/doc/man/man3/seccomp_attr_set.3 b/doc/man/man3/seccomp_attr_set.3 index 11320043..473c91ab 100644 --- a/doc/man/man3/seccomp_attr_set.3 +++ b/doc/man/man3/seccomp_attr_set.3 @@ -100,6 +100,12 @@ A flag to disable Speculative Store Bypass mitigations for this filter. Defaults to off ( .I value == 0). +.TP +.B SCMP_FLTATR_NEW_LISTENER +Generate a userspace listener file descriptor when this filter is installed. +Defaults to off ( +.I value +== 0). .\" ////////////////////////////////////////////////////////////////////////// .SH RETURN VALUE .\" ////////////////////////////////////////////////////////////////////////// diff --git a/include/seccomp.h.in b/include/seccomp.h.in index eaa56740..ec7f6ec6 100644 --- a/include/seccomp.h.in +++ b/include/seccomp.h.in @@ -26,6 +26,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -66,6 +67,7 @@ enum scmp_filter_attr { SCMP_FLTATR_API_TSKIP = 5, /**< allow rules with a -1 syscall */ SCMP_FLTATR_CTL_LOG = 6, /**< log not-allowed actions */ SCMP_FLTATR_SPEC_ALLOW = 7, /**< disable SSB mitigation */ + SCMP_FLTATR_NEW_LISTENER = 8, /**< returns a listener fd */ _SCMP_FLTATR_MAX, }; @@ -319,6 +321,10 @@ struct scmp_arg_cmp { * Throw a SIGSYS signal */ #define SCMP_ACT_TRAP 0x00030000U +/** + * Notifies userspace + */ +#define SCMP_ACT_USER_NOTIF 0x7fc00000U /** * Return the specified error code */ @@ -336,6 +342,46 @@ struct scmp_arg_cmp { */ #define SCMP_ACT_ALLOW 0x7fff0000U +/* + * User notification bits. It's a little unfortunate that we don't export + * system.h, so we end up having to define all these structures again. + * SECCOMP_RET_USER_NOTIF was added in kernel 5.0. + */ +#ifndef SECCOMP_RET_USER_NOTIF +#define SECCOMP_RET_USER_NOTIF 0x7fc00000U + +struct seccomp_notif_sizes { + __u16 seccomp_notif; + __u16 seccomp_notif_resp; + __u16 seccomp_data; +}; + +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; +}; +#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) +#endif + /* * functions */ @@ -369,6 +415,7 @@ const struct scmp_version *seccomp_version(void); * support for the SCMP_ACT_LOG action * support for the SCMP_ACT_KILL_PROCESS action * 4 : support for the SCMP_FLTATR_SPEC_ALLOW filter attrbute + * 5 : support for the SCMP_FLTATR_NEW_LISTENER filter attribute * */ unsigned int seccomp_api_get(void); @@ -695,6 +742,67 @@ int seccomp_export_pfc(const scmp_filter_ctx ctx, int fd); */ int seccomp_export_bpf(const scmp_filter_ctx ctx, int fd); +/** + * Allocate a pair of notification request/response structures. + * @param req the request location + * @param resp the response location + * + * This function allocates a pair of request/response structure by computing + * the correct sized based on the currently running kernel. It returns zero on + * success, and negative values on failure. + */ +int seccomp_notif_alloc(struct seccomp_notif **req, + struct seccomp_notif_resp **resp); + +/** + * Free a pair of notification request/response structures. + * @param req the request location + * @param resp the response location + */ +void seccomp_notif_free(struct seccomp_notif *req, + struct seccomp_notif_resp *resp); +/** + * Receive a notification from a seccomp notification fd. + * @param fd the notification fd + * @param req the request buffer to save into + * + * Blocks waiting for a notification on this fd. This function is thread safe + * (synchronization is performed in the kernel). Returns zero on success, + * negative values on error. + */ +int seccomp_notif_receive(int fd, struct seccomp_notif *req); + +/** + * Send a notification response to a seccomp notification fd. + * @param fd the notification fd + * @param resp the response buffer to use + * + * Sends a notification response on this fd. This function is thread safe + * (synchronization is performed in the kernel). Returns zero on success, + * negative values on error. + */ +int seccomp_notif_send_resp(int fd, struct seccomp_notif_resp *resp); + +/** + * Check if a notification id is still valid. + * @param fd the notification fd + * @param id the id to test + * + * Checks to see if a notification id is still valid. Returns 0 on success, and + * negative values on failure. + */ +int seccomp_notif_id_valid(int fd, uint64_t id); + +/** + * Return the notification fd from a filter that has already been loaded. + * @param ctx the filter context + * + * This returns the listener fd that was generated when the seccomp policy was + * loaded. This is only valid after seccomp_load() with + * SCMP_FLTATR_NEW_LISTENER set. + */ +int seccomp_notif_fd(const scmp_filter_ctx ctx); + /* * pseudo syscall definitions */ diff --git a/src/api.c b/src/api.c index 34fd9c71..f55c0188 100644 --- a/src/api.c +++ b/src/api.c @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -34,6 +35,7 @@ #include "db.h" #include "gen_pfc.h" #include "gen_bpf.h" +#include "helper.h" #include "system.h" #define API __attribute__((visibility("default"))) @@ -112,6 +114,10 @@ static unsigned int _seccomp_api_update(void) sys_chk_seccomp_flag(SECCOMP_FILTER_FLAG_SPEC_ALLOW) == 1) level = 4; + if (level == 4 && + sys_chk_seccomp_flag(SECCOMP_FILTER_FLAG_NEW_LISTENER) == 1) + level = 5; + /* update the stored api level and return */ seccomp_api_level = level; return seccomp_api_level; @@ -163,6 +169,16 @@ API int seccomp_api_set(unsigned int level) sys_set_seccomp_action(SCMP_ACT_KILL_PROCESS, true); sys_set_seccomp_flag(SECCOMP_FILTER_FLAG_SPEC_ALLOW, true); break; + case 5: + sys_set_seccomp_syscall(true); + sys_set_seccomp_flag(SECCOMP_FILTER_FLAG_TSYNC, true); + sys_set_seccomp_flag(SECCOMP_FILTER_FLAG_LOG, true); + sys_set_seccomp_action(SCMP_ACT_LOG, true); + sys_set_seccomp_action(SCMP_ACT_KILL_PROCESS, true); + sys_set_seccomp_flag(SECCOMP_FILTER_FLAG_SPEC_ALLOW, true); + sys_set_seccomp_flag(SECCOMP_FILTER_FLAG_NEW_LISTENER, true); + sys_set_seccomp_action(SCMP_ACT_USER_NOTIF, true); + break; default: return -EINVAL; } @@ -538,3 +554,53 @@ API int seccomp_export_bpf(const scmp_filter_ctx ctx, int fd) return 0; } + +/* NOTE - function header comment in include/seccomp.h */ +API int seccomp_notif_alloc(struct seccomp_notif **req, + struct seccomp_notif_resp **resp) +{ + return sys_notif_alloc(req, resp); +} + +/* NOTE - function header comment in include/seccomp.h */ +API void seccomp_notif_free(struct seccomp_notif *req, + struct seccomp_notif_resp *resp) +{ + if (req) + free(req); + if (resp) + free(resp); +} + +/* NOTE - function header comment in include/seccomp.h */ +API int seccomp_notif_receive(int fd, struct seccomp_notif *req) +{ + return sys_notif_receive(fd, req); +} + +/* NOTE - function header comment in include/seccomp.h */ +API int seccomp_notif_send_resp(int fd, struct seccomp_notif_resp *resp) +{ + return sys_notif_send_resp(fd, resp); +} + +/* NOTE - function header comment in include/seccomp.h */ +API int seccomp_notif_id_valid(int fd, uint64_t id) +{ + return sys_notif_id_valid(fd, id); +} + +/* NOTE - function header comment in include/seccomp.h */ +API int seccomp_notif_fd(const scmp_filter_ctx ctx) +{ + struct db_filter_col *col; + + if (_ctx_valid(ctx)) + return -EINVAL; + col = (struct db_filter_col *)ctx; + + if (!col->attr.new_listener) + return -EINVAL; + + return col->notif_fd; +} diff --git a/src/db.c b/src/db.c index 064f343a..752fc6dd 100644 --- a/src/db.c +++ b/src/db.c @@ -1283,6 +1283,9 @@ int db_col_attr_get(const struct db_filter_col *col, case SCMP_FLTATR_SPEC_ALLOW: *value = col->attr.spec_allow; break; + case SCMP_FLTATR_NEW_LISTENER: + *value = col->attr.new_listener; + break; default: rc = -EEXIST; break; @@ -1355,6 +1358,17 @@ int db_col_attr_set(struct db_filter_col *col, rc = -EOPNOTSUPP; } break; + case SCMP_FLTATR_NEW_LISTENER: + rc = sys_chk_seccomp_flag(SECCOMP_FILTER_FLAG_NEW_LISTENER); + if (rc == 1) { + /* supported */ + rc = 0; + col->attr.new_listener = (value ? 1 : 0); + } else if (rc == 0) { + /* unsupported */ + rc = -EOPNOTSUPP; + } + break; default: rc = -EEXIST; break; diff --git a/src/db.h b/src/db.h index fa9c0850..d7386178 100644 --- a/src/db.h +++ b/src/db.h @@ -118,6 +118,8 @@ struct db_filter_attr { uint32_t log_enable; /* SPEC_ALLOW related attributes */ uint32_t spec_allow; + /* SECCOMP_FILTER_FLAG_NEW_LISTENER attributes */ + uint32_t new_listener; }; struct db_filter { @@ -153,6 +155,9 @@ struct db_filter_col { /* transaction snapshots */ struct db_filter_snap *snapshots; + + /* notification fd that was returned from seccomp() */ + int notif_fd; }; /** diff --git a/src/python/libseccomp.pxd b/src/python/libseccomp.pxd index 1293208a..c03bf7da 100644 --- a/src/python/libseccomp.pxd +++ b/src/python/libseccomp.pxd @@ -59,6 +59,7 @@ cdef extern from "seccomp.h": SCMP_FLTATR_API_TSKIP SCMP_FLTATR_CTL_LOG SCMP_FLTATR_SPEC_ALLOW + SCMP_FLTATR_NEW_LISTENER cdef enum scmp_compare: SCMP_CMP_NE @@ -75,6 +76,7 @@ cdef extern from "seccomp.h": SCMP_ACT_TRAP SCMP_ACT_LOG SCMP_ACT_ALLOW + SCMP_ACT_USER_NOTIF unsigned int SCMP_ACT_ERRNO(int errno) unsigned int SCMP_ACT_TRACE(int value) @@ -132,6 +134,5 @@ cdef extern from "seccomp.h": int seccomp_export_pfc(scmp_filter_ctx ctx, int fd) int seccomp_export_bpf(scmp_filter_ctx ctx, int fd) - # kate: syntax python; # kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; diff --git a/src/python/seccomp.pyx b/src/python/seccomp.pyx index 27211ad6..5ba55736 100644 --- a/src/python/seccomp.pyx +++ b/src/python/seccomp.pyx @@ -309,6 +309,7 @@ cdef class Attr: API_TSKIP = libseccomp.SCMP_FLTATR_API_TSKIP CTL_LOG = libseccomp.SCMP_FLTATR_CTL_LOG SPEC_ALLOW = libseccomp.SCMP_FLTATR_SPEC_ALLOW + NEW_LISTENER = libseccomp.SCMP_FLTATR_NEW_LISTENER cdef class Arg: """ Python object representing a SyscallFilter syscall argument. diff --git a/src/system.c b/src/system.c index f45379c1..a90ef358 100644 --- a/src/system.c +++ b/src/system.c @@ -32,6 +32,7 @@ #include "db.h" #include "gen_bpf.h" #include "system.h" +#include "helper.h" /* NOTE: the seccomp syscall whitelist is currently disabled for testing * purposes, but unless we can verify all of the supported ABIs before @@ -45,6 +46,8 @@ 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_action_user_notif = -1; /** * Check to see if the seccomp() syscall is supported @@ -158,6 +161,17 @@ int sys_chk_seccomp_action(uint32_t action) return _support_seccomp_action_log; } else if (action == SCMP_ACT_ALLOW) { return 1; + } else if (action == SCMP_ACT_USER_NOTIF) { + if (_support_seccomp_action_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_action_user_notif = 1; + else + _support_seccomp_action_user_notif = 0; + } + return 1; } return 0; @@ -227,6 +241,11 @@ int sys_chk_seccomp_flag(int flag) _support_seccomp_flag_spec_allow = _sys_chk_seccomp_flag_kernel(flag); return _support_seccomp_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; } return -EOPNOTSUPP; @@ -253,6 +272,9 @@ void sys_set_seccomp_flag(int flag, bool enable) case SECCOMP_FILTER_FLAG_SPEC_ALLOW: _support_seccomp_flag_spec_allow = (enable ? 1 : 0); break; + case SECCOMP_FILTER_FLAG_NEW_LISTENER: + _support_seccomp_flag_new_listener = (enable ? 1 : 0); + break; } } @@ -266,7 +288,7 @@ void sys_set_seccomp_flag(int flag, bool enable) * error. * */ -int sys_filter_load(const struct db_filter_col *col) +int sys_filter_load(struct db_filter_col *col) { int rc; struct bpf_program *prgm = NULL; @@ -291,10 +313,17 @@ int sys_filter_load(const struct db_filter_col *col) flgs |= SECCOMP_FILTER_FLAG_LOG; if (col->attr.spec_allow) flgs |= SECCOMP_FILTER_FLAG_SPEC_ALLOW; + if (col->attr.new_listener) + flgs |= SECCOMP_FILTER_FLAG_NEW_LISTENER; rc = syscall(_nr_seccomp, SECCOMP_SET_MODE_FILTER, flgs, prgm); if (rc > 0 && col->attr.tsync_enable) /* always return -ESRCH if we fail to sync threads */ errno = ESRCH; + if (rc > 0 && col->attr.new_listener) { + /* return 0 on NEW_LISTENER success, but save the fd */ + col->notif_fd = rc; + rc = 0; + } } else rc = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, prgm); @@ -303,5 +332,64 @@ int sys_filter_load(const struct db_filter_col *col) gen_bpf_release(prgm); if (rc < 0) return -errno; + return rc; +} + +int sys_notif_alloc(struct seccomp_notif **req, + struct seccomp_notif_resp **resp) +{ + static struct seccomp_notif_sizes sizes = {}; + + if (_support_seccomp_syscall <= 0) + return -EOPNOTSUPP; + + if (sizes.seccomp_notif == 0) { + int ret = syscall(__NR_seccomp, SECCOMP_GET_NOTIF_SIZES, 0, &sizes); + if (ret < 0) + return errno; + } else { + return -1; + } + + *req = zmalloc(sizes.seccomp_notif); + if (!*req) + return -ENOMEM; + + *resp = zmalloc(sizes.seccomp_notif_resp); + if (!*resp) { + free(req); + return -ENOMEM; + } + + return 0; +} + +int sys_notif_receive(int fd, struct seccomp_notif *req) +{ + if (_support_seccomp_action_user_notif <= 0) + return -EOPNOTSUPP; + + if (ioctl(fd, SECCOMP_IOCTL_NOTIF_RECV, req) < 0) + return errno; + return 0; +} + +int sys_notif_send_resp(int fd, struct seccomp_notif_resp *resp) +{ + if (_support_seccomp_action_user_notif <= 0) + return -EOPNOTSUPP; + + if (ioctl(fd, SECCOMP_IOCTL_NOTIF_SEND, resp) < 0) + return errno; + return 0; +} + +int sys_notif_id_valid(int fd, uint64_t id) +{ + if (_support_seccomp_action_user_notif <= 0) + return -EOPNOTSUPP; + + if (ioctl(fd, SECCOMP_IOCTL_NOTIF_ID_VALID, id) < 0) + return errno; return 0; } diff --git a/src/system.h b/src/system.h index 884d6ff6..9438fab4 100644 --- a/src/system.h +++ b/src/system.h @@ -24,6 +24,7 @@ #include #include +#include #include "configure.h" @@ -178,10 +179,7 @@ typedef struct sock_filter bpf_instr_raw; #define SECCOMP_RET_LOG 0x7fc00000U #endif -/* SECCOMP_RET_USER_NOTIF was added in kernel 5.0. It may not be defined on - * older kernels. This version also added the structures below, so let's define - * those if the header doesn't have this definiton. - */ +/* SECCOMP_RET_USER_NOTIF was added in kernel 5.0. */ #ifndef SECCOMP_RET_USER_NOTIF #define SECCOMP_RET_USER_NOTIF 0x7fc00000U @@ -227,6 +225,11 @@ void sys_set_seccomp_action(uint32_t action, bool enable); int sys_chk_seccomp_flag(int flag); void sys_set_seccomp_flag(int flag, bool enable); -int sys_filter_load(const struct db_filter_col *col); +int sys_filter_load(struct db_filter_col *col); +int sys_notif_alloc(struct seccomp_notif **req, + struct seccomp_notif_resp **resp); +int sys_notif_receive(int fd, struct seccomp_notif *req); +int sys_notif_send_resp(int fd, struct seccomp_notif_resp *resp); +int sys_notif_id_valid(int fd, uint64_t id); #endif diff --git a/tests/.gitignore b/tests/.gitignore index a5bc9e45..67102435 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -56,3 +56,4 @@ util.pyc 48-sim-32b_args 49-sim-64b_comparisons 50-sim-hash_collision +51-live-user_notification diff --git a/tests/13-basic-attrs.c b/tests/13-basic-attrs.c index 29ef3210..93c2acbc 100644 --- a/tests/13-basic-attrs.c +++ b/tests/13-basic-attrs.c @@ -32,7 +32,7 @@ int main(int argc, char *argv[]) uint32_t val = (uint32_t)(-1); scmp_filter_ctx ctx = NULL; - rc = seccomp_api_set(4); + rc = seccomp_api_set(5); if (rc != 0) return EOPNOTSUPP; @@ -122,6 +122,19 @@ int main(int argc, char *argv[]) goto out; } + rc = seccomp_attr_set(ctx, SCMP_FLTATR_NEW_LISTENER, 1); + if (rc == -EOPNOTSUPP) + goto out; + else if (rc != 0) + goto out; + rc = seccomp_attr_get(ctx, SCMP_FLTATR_NEW_LISTENER, &val); + if (rc != 0) + goto out; + if (val != 1) { + rc = -1; + goto out; + } + rc = 0; out: seccomp_release(ctx); diff --git a/tests/13-basic-attrs.py b/tests/13-basic-attrs.py index 7ee5df79..4c4c3e5e 100755 --- a/tests/13-basic-attrs.py +++ b/tests/13-basic-attrs.py @@ -29,7 +29,7 @@ from seccomp import * def test(): - set_api(4) + set_api(5) f = SyscallFilter(ALLOW) if f.get_attr(Attr.ACT_DEFAULT) != ALLOW: @@ -55,6 +55,9 @@ def test(): f.set_attr(Attr.SPEC_ALLOW, 1) if f.get_attr(Attr.SPEC_ALLOW) != 1: raise RuntimeError("Failed getting Attr.SPEC_ALLOW") + f.set_attr(Attr.NEW_LISTENER, 1) + if f.get_attr(Attr.NEW_LISTENER) != 1: + raise RuntimeError("Failed getting Attr.NEW_LISTENER") test() diff --git a/tests/51-live-user_notification.c b/tests/51-live-user_notification.c new file mode 100644 index 00000000..ed06bdbc --- /dev/null +++ b/tests/51-live-user_notification.c @@ -0,0 +1,95 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" + +int main(int argc, char *argv[]) +{ + int rc, fd = -1, status; + struct seccomp_notif *req = NULL; + struct seccomp_notif_resp *resp = NULL; + scmp_filter_ctx ctx = NULL; + pid_t pid = 0; + struct util_options opts; + + rc = util_getopt(argc, argv, &opts); + if (rc < 0) + goto out; + + ctx = seccomp_init(SCMP_ACT_ALLOW); + if (ctx == NULL) + return ENOMEM; + + rc = util_filter_output(&opts, ctx); + if (rc) + goto out; + + rc = seccomp_attr_set(ctx, SCMP_FLTATR_NEW_LISTENER, 1); + if (rc) + goto out; + + rc = seccomp_rule_add_exact(ctx, SCMP_ACT_USER_NOTIF, SCMP_SYS(getpid), 0, NULL); + if (rc) + goto out; + + rc = seccomp_load(ctx); + if (rc < 0) + goto out; + + rc = fd = seccomp_notif_fd(ctx); + if (fd < 0) + goto out; + +#define MAGIC 0x1122334455667788UL + pid = fork(); + if (pid == 0) + exit(syscall(SCMP_SYS(getpid)) != MAGIC); + + rc = seccomp_notif_alloc(&req, &resp); + if (rc) + goto out; + + rc = seccomp_notif_receive(fd, req); + if (rc) + goto out; + + if (req->data.nr != SCMP_SYS(getpid)) { + rc = -EINVAL; + goto out; + } + + resp->id = req->id; + resp->val = MAGIC; + resp->error = 0; + + rc = seccomp_notif_send_resp(fd, resp); + if (rc) + goto out; + + rc = -EINVAL; + if (waitpid(pid, &status, 0) != pid) + goto out; + + if (!WIFEXITED(status)) + goto out; + + if (WEXITSTATUS(status)) + goto out; + + rc = 0; +out: + if (req) + seccomp_notif_free(req, resp); + if (pid) + kill(pid, SIGKILL); + seccomp_release(ctx); + if (fd >= 0) + close(fd); + return (rc < 0 ? -rc : rc); +} diff --git a/tests/51-live-user_notification.tests b/tests/51-live-user_notification.tests new file mode 100644 index 00000000..f32cacd6 --- /dev/null +++ b/tests/51-live-user_notification.tests @@ -0,0 +1,11 @@ +# +# libseccomp regression test automation data +# +# Copyright Cisco Systems 2019 +# Author: Tycho Andersen +# + +test type: live + +# Testname API Result +51-live-user_notification 5 USER_NOTIF diff --git a/tests/Makefile.am b/tests/Makefile.am index eb84e143..83e41c47 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -89,7 +89,8 @@ check_PROGRAMS = \ 47-live-kill_process \ 48-sim-32b_args \ 49-sim-64b_comparisons \ - 50-sim-hash_collision + 50-sim-hash_collision \ + 51-live-user_notification EXTRA_DIST_TESTPYTHON = \ util.py \ @@ -193,7 +194,8 @@ EXTRA_DIST_TESTCFGS = \ 47-live-kill_process.tests \ 48-sim-32b_args.tests \ 49-sim-64b_comparisons.tests \ - 50-sim-hash_collision.tests + 50-sim-hash_collision.tests \ + 51-live-user_notification.tests EXTRA_DIST_TESTSCRIPTS = \ 38-basic-pfc_coverage.sh 38-basic-pfc_coverage.pfc