diff options
-rw-r--r-- | doc/man/man3/seccomp_api_get.3 | 10 | ||||
-rw-r--r-- | include/seccomp.h.in | 6 | ||||
-rw-r--r-- | src/api.c | 33 | ||||
-rw-r--r-- | src/db.c | 12 | ||||
-rw-r--r-- | src/system.c | 30 | ||||
-rw-r--r-- | src/system.h | 9 | ||||
-rw-r--r-- | tests/.gitignore | 1 | ||||
-rw-r--r-- | tests/39-basic-api_level.c | 9 | ||||
-rwxr-xr-x | tests/39-basic-api_level.py | 7 | ||||
-rw-r--r-- | tests/58-live-tsync_notify.c | 116 | ||||
-rwxr-xr-x | tests/58-live-tsync_notify.py | 61 | ||||
-rw-r--r-- | tests/58-live-tsync_notify.tests | 11 | ||||
-rw-r--r-- | tests/Makefile.am | 9 |
13 files changed, 289 insertions, 25 deletions
diff --git a/doc/man/man3/seccomp_api_get.3 b/doc/man/man3/seccomp_api_get.3 index 6fa83a8..ab2f552 100644 --- a/doc/man/man3/seccomp_api_get.3 +++ b/doc/man/man3/seccomp_api_get.3 @@ -1,4 +1,4 @@ -.TH "seccomp_api_get" 3 "8 October 2017" "paul@paul-moore.com" "libseccomp Documentation" +.TH "seccomp_api_get" 3 "13 June 2020" "paul@paul-moore.com" "libseccomp Documentation" .\" ////////////////////////////////////////////////////////////////////////// .SH NAME .\" ////////////////////////////////////////////////////////////////////////// @@ -49,13 +49,17 @@ the syscall to load the seccomp filter into the kernel. .TP .B 3 -The SCMP_FLTATR_CTL_LOG filter attribute and the SCMP_ACT_LOG action are supported. +The SCMP_FLTATR_CTL_LOG filter attribute and the SCMP_ACT_LOG action are +supported. .TP .B 4 The SCMP_FLTATR_CTL_SSB filter attribute is supported. .TP .B 5 -The SCMP_ACT_NOTIFY action is supported. +The SCMP_ACT_NOTIFY action and the notify APIs are supported. +.TP +.B 5 +The simultaneous use of SCMP_FLTATR_CTL_TSYNC and the notify APIs are supported. .\" ////////////////////////////////////////////////////////////////////////// .SH RETURN VALUE .\" ////////////////////////////////////////////////////////////////////////// diff --git a/include/seccomp.h.in b/include/seccomp.h.in index c78846b..ef4c6e4 100644 --- a/include/seccomp.h.in +++ b/include/seccomp.h.in @@ -415,10 +415,8 @@ 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_CTL_SSB filter attrbute - * 5 : support for the SCMP_ACT_NOTIFY action - * support for using seccomp_notify_receive() - * support for using seccomp_notify_respond() - * support for using seccomp_notify_id_valid() + * 5 : support for the SCMP_ACT_NOTIFY action and notify APIs + * 6 : support the simultaneous use of SCMP_FLTATR_CTL_TSYNC and notify APIs * */ unsigned int seccomp_api_get(void); @@ -165,12 +165,10 @@ static unsigned int _seccomp_api_update(void) /* NOTE: level 1 is the base level, start checking at 2 */ - /* level 2 */ if (sys_chk_seccomp_syscall() && sys_chk_seccomp_flag(SECCOMP_FILTER_FLAG_TSYNC) == 1) level = 2; - /* level 3 */ if (level == 2 && sys_chk_seccomp_flag(SECCOMP_FILTER_FLAG_LOG) == 1 && sys_chk_seccomp_action(SCMP_ACT_LOG) == 1 && @@ -186,6 +184,10 @@ static unsigned int _seccomp_api_update(void) sys_chk_seccomp_action(SCMP_ACT_NOTIFY) == 1) level = 5; + if (level == 5 && + sys_chk_seccomp_flag(SECCOMP_FILTER_FLAG_TSYNC_ESRCH) == 1) + level = 6; + /* update the stored api level and return */ seccomp_api_level = level; return seccomp_api_level; @@ -214,6 +216,10 @@ API int seccomp_api_set(unsigned int level) sys_set_seccomp_flag(SECCOMP_FILTER_FLAG_LOG, false); sys_set_seccomp_action(SCMP_ACT_LOG, false); sys_set_seccomp_action(SCMP_ACT_KILL_PROCESS, false); + sys_set_seccomp_flag(SECCOMP_FILTER_FLAG_SPEC_ALLOW, false); + sys_set_seccomp_flag(SECCOMP_FILTER_FLAG_NEW_LISTENER, false); + sys_set_seccomp_action(SCMP_ACT_NOTIFY, false); + sys_set_seccomp_flag(SECCOMP_FILTER_FLAG_TSYNC_ESRCH, false); break; case 2: sys_set_seccomp_syscall(true); @@ -221,6 +227,10 @@ API int seccomp_api_set(unsigned int level) sys_set_seccomp_flag(SECCOMP_FILTER_FLAG_LOG, false); sys_set_seccomp_action(SCMP_ACT_LOG, false); sys_set_seccomp_action(SCMP_ACT_KILL_PROCESS, false); + sys_set_seccomp_flag(SECCOMP_FILTER_FLAG_SPEC_ALLOW, false); + sys_set_seccomp_flag(SECCOMP_FILTER_FLAG_NEW_LISTENER, false); + sys_set_seccomp_action(SCMP_ACT_NOTIFY, false); + sys_set_seccomp_flag(SECCOMP_FILTER_FLAG_TSYNC_ESRCH, false); break; case 3: sys_set_seccomp_syscall(true); @@ -228,6 +238,10 @@ API int seccomp_api_set(unsigned int level) 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, false); + sys_set_seccomp_flag(SECCOMP_FILTER_FLAG_NEW_LISTENER, false); + sys_set_seccomp_action(SCMP_ACT_NOTIFY, false); + sys_set_seccomp_flag(SECCOMP_FILTER_FLAG_TSYNC_ESRCH, false); break; case 4: sys_set_seccomp_syscall(true); @@ -236,6 +250,9 @@ API int seccomp_api_set(unsigned int level) 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, false); + sys_set_seccomp_action(SCMP_ACT_NOTIFY, false); + sys_set_seccomp_flag(SECCOMP_FILTER_FLAG_TSYNC_ESRCH, false); break; case 5: sys_set_seccomp_syscall(true); @@ -246,6 +263,18 @@ API int seccomp_api_set(unsigned int level) 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_NOTIFY, true); + sys_set_seccomp_flag(SECCOMP_FILTER_FLAG_TSYNC_ESRCH, false); + break; + case 6: + 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_NOTIFY, true); + sys_set_seccomp_flag(SECCOMP_FILTER_FLAG_TSYNC_ESRCH, true); break; default: return _rc_filter(-EINVAL); @@ -1196,8 +1196,10 @@ int db_col_action_valid(const struct db_filter_col *col, uint32_t action) /* NOTE: in some cases we don't have a filter collection yet, * but when we do we need to do the following checks */ - /* kernel disallows TSYNC and NOTIFY in one filter */ - if (col->attr.tsync_enable && action == SCMP_ACT_NOTIFY) + /* kernel disallows TSYNC and NOTIFY in one filter unless we + * have the TSYNC_ESRCH flag */ + if (sys_chk_seccomp_flag(SECCOMP_FILTER_FLAG_TSYNC_ESRCH) < 1 && + col->attr.tsync_enable && action == SCMP_ACT_NOTIFY) return -EINVAL; } @@ -1381,8 +1383,10 @@ int db_col_attr_set(struct db_filter_col *col, if (rc == 1) { /* supported */ rc = 0; - /* kernel disallows TSYNC and NOTIFY in one filter */ - if (value && col->notify_used) + /* kernel disallows TSYNC and NOTIFY in one filter + * unless we have TSYNC_ESRCH */ + if (sys_chk_seccomp_flag(SECCOMP_FILTER_FLAG_TSYNC_ESRCH) < 1 && + value && col->notify_used) return -EINVAL; col->attr.tsync_enable = (value ? 1 : 0); } else if (rc == 0) diff --git a/src/system.c b/src/system.c index 6522cb8..6cdfc16 100644 --- a/src/system.c +++ b/src/system.c @@ -49,6 +49,7 @@ 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; /** * Check to see if the seccomp() syscall is supported @@ -256,6 +257,10 @@ int sys_chk_seccomp_flag(int flag) _support_seccomp_flag_new_listener = _sys_chk_seccomp_flag_kernel(flag); return _support_seccomp_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; } return -EOPNOTSUPP; @@ -285,6 +290,9 @@ void sys_set_seccomp_flag(int flag, bool enable) case SECCOMP_FILTER_FLAG_NEW_LISTENER: _support_seccomp_flag_new_listener = (enable ? 1 : 0); break; + case SECCOMP_FILTER_FLAG_TSYNC_ESRCH: + _support_seccomp_flag_tsync_esrch = (enable ? 1 : 0); + break; } } @@ -302,6 +310,7 @@ void sys_set_seccomp_flag(int flag, bool enable) int sys_filter_load(struct db_filter_col *col, bool rawrc) { int rc; + bool tsync_notify; struct bpf_program *prgm = NULL; rc = gen_bpf_generate(col, &prgm); @@ -315,10 +324,18 @@ int sys_filter_load(struct db_filter_col *col, bool rawrc) goto filter_load_out; } + tsync_notify = (_support_seccomp_flag_tsync_esrch > 0); + /* load the filter into the kernel */ if (sys_chk_seccomp_syscall() == 1) { int flgs = 0; - if (col->attr.tsync_enable) + if (tsync_notify) { + if (col->attr.tsync_enable) + flgs |= SECCOMP_FILTER_FLAG_TSYNC | \ + SECCOMP_FILTER_FLAG_TSYNC_ESRCH; + if (_support_seccomp_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) flgs |= SECCOMP_FILTER_FLAG_NEW_LISTENER; @@ -327,10 +344,15 @@ int sys_filter_load(struct db_filter_col *col, bool rawrc) if (col->attr.spec_allow) flgs |= SECCOMP_FILTER_FLAG_SPEC_ALLOW; rc = syscall(_nr_seccomp, SECCOMP_SET_MODE_FILTER, flgs, prgm); - if (rc > 0 && col->attr.tsync_enable) + if (tsync_notify && rc > 0) { + /* return 0 on NEW_LISTENER success, but save the fd */ + col->notify_fd = rc; + rc = 0; + } else if (rc > 0 && col->attr.tsync_enable) { /* always return -ESRCH if we fail to sync threads */ - rc = -ESRCH; - if (rc > 0 && _support_seccomp_user_notif > 0) { + errno = ESRCH; + rc = -errno; + } else if (rc > 0 && _support_seccomp_user_notif > 0) { /* return 0 on NEW_LISTENER success, but save the fd */ col->notify_fd = rc; rc = 0; diff --git a/src/system.h b/src/system.h index 7517c71..133f9b1 100644 --- a/src/system.h +++ b/src/system.h @@ -116,17 +116,20 @@ typedef struct sock_filter bpf_instr_raw; /* flags for the seccomp() syscall */ #ifndef SECCOMP_FILTER_FLAG_TSYNC -#define SECCOMP_FILTER_FLAG_TSYNC (1UL << 0) +#define SECCOMP_FILTER_FLAG_TSYNC (1UL << 0) #endif #ifndef SECCOMP_FILTER_FLAG_LOG -#define SECCOMP_FILTER_FLAG_LOG (1UL << 1) +#define SECCOMP_FILTER_FLAG_LOG (1UL << 1) #endif #ifndef SECCOMP_FILTER_FLAG_SPEC_ALLOW -#define SECCOMP_FILTER_FLAG_SPEC_ALLOW (1UL << 2) +#define SECCOMP_FILTER_FLAG_SPEC_ALLOW (1UL << 2) #endif #ifndef SECCOMP_FILTER_FLAG_NEW_LISTENER #define SECCOMP_FILTER_FLAG_NEW_LISTENER (1UL << 3) #endif +#ifndef SECCOMP_FILTER_FLAG_TSYNC_ESRCH +#define SECCOMP_FILTER_FLAG_TSYNC_ESRCH (1UL << 4) +#endif #ifndef SECCOMP_RET_LOG #define SECCOMP_RET_LOG 0x7ffc0000U /* allow after logging */ diff --git a/tests/.gitignore b/tests/.gitignore index 59eb15c..1929840 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -63,3 +63,4 @@ util.pyc 55-basic-pfc_binary_tree 56-basic-iterate_syscalls 57-basic-rawsysrc +58-live-tsync_notify diff --git a/tests/39-basic-api_level.c b/tests/39-basic-api_level.c index 72801b5..6c31be1 100644 --- a/tests/39-basic-api_level.c +++ b/tests/39-basic-api_level.c @@ -68,13 +68,20 @@ int main(int argc, char *argv[]) if (api != 5) return -11; + rc = seccomp_api_set(6); + if (rc != 0) + return -12; + api = seccomp_api_get(); + if (api != 6) + return -13; + /* Attempt to set a high, invalid API level */ rc = seccomp_api_set(1024); if (rc != -EINVAL) return -1001; /* Ensure that the previously set API level didn't change */ api = seccomp_api_get(); - if (api != 5) + if (api != 6) return -1002; return 0; diff --git a/tests/39-basic-api_level.py b/tests/39-basic-api_level.py index 755ca02..352568e 100755 --- a/tests/39-basic-api_level.py +++ b/tests/39-basic-api_level.py @@ -60,6 +60,11 @@ def test(): if api != 5: raise RuntimeError("Failed getting API level 5") + set_api(6) + api = get_api() + if api != 6: + raise RuntimeError("Failed getting API level 6") + # Attempt to set a high, invalid API level try: set_api(1024) @@ -69,7 +74,7 @@ def test(): raise RuntimeError("Missing failure when setting invalid API level") # Ensure that the previously set API level didn't change api = get_api() - if api != 5: + if api != 6: raise RuntimeError("Failed getting old API level after setting an invalid API level") test() diff --git a/tests/58-live-tsync_notify.c b/tests/58-live-tsync_notify.c new file mode 100644 index 0000000..86e1b0c --- /dev/null +++ b/tests/58-live-tsync_notify.c @@ -0,0 +1,116 @@ +/** + * Seccomp Library test program + * + * Copyright (c) 2019 Cisco Systems, Inc. <pmoore2@cisco.com> + * Author: Paul Moore <paul@paul-moore.com> + */ + +/* + * This library is free software; you can redistribute it and/or modify it + * under the terms of version 2.1 of the GNU Lesser General Public License as + * published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see <http://www.gnu.org/licenses>. + */ + +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> +#include <seccomp.h> +#include <signal.h> +#include <syscall.h> +#include <errno.h> +#include <stdlib.h> + +#include "util.h" + +#define MAGIC 0x1122334455667788UL + +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; + + ctx = seccomp_init(SCMP_ACT_ALLOW); + if (ctx == NULL) + return ENOMEM; + + rc = seccomp_attr_set(ctx, SCMP_FLTATR_CTL_TSYNC, 1); + if (rc) + goto out; + + rc = seccomp_rule_add(ctx, SCMP_ACT_NOTIFY, SCMP_SYS(getpid), 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; + fd = rc; + + pid = fork(); + if (pid == 0) + exit(syscall(SCMP_SYS(getpid)) != MAGIC); + + rc = seccomp_notify_alloc(&req, &resp); + if (rc) + goto out; + + rc = seccomp_notify_receive(fd, req); + if (rc) + goto out; + if (req->data.nr != SCMP_SYS(getpid)) { + rc = -EFAULT; + goto out; + } + rc = seccomp_notify_id_valid(fd, req->id); + if (rc) + goto out; + + resp->id = req->id; + resp->val = MAGIC; + resp->error = 0; + resp->flags = 0; + rc = seccomp_notify_respond(fd, resp); + if (rc) + goto out; + + if (waitpid(pid, &status, 0) != pid) { + rc = -EFAULT; + goto out; + } + + if (!WIFEXITED(status)) { + rc = -EFAULT; + goto out; + } + if (WEXITSTATUS(status)) { + rc = -EFAULT; + goto out; + } + +out: + if (fd >= 0) + close(fd); + if (pid) + kill(pid, SIGKILL); + seccomp_notify_free(req, resp); + seccomp_release(ctx); + + if (rc != 0) + return (rc < 0 ? -rc : rc); + return 160; +} diff --git a/tests/58-live-tsync_notify.py b/tests/58-live-tsync_notify.py new file mode 100755 index 0000000..ae01b06 --- /dev/null +++ b/tests/58-live-tsync_notify.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python + +# +# Seccomp Library test program +# +# Copyright (c) 2019 Cisco Systems, Inc. <pmoore2@cisco.com> +# Author: Paul Moore <paul@paul-moore.com> +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see <http://www.gnu.org/licenses>. +# + +import argparse +import os +import signal +import sys + +import util + +from seccomp import * + +def test(): + magic = os.getuid() + 1 + f = SyscallFilter(ALLOW) + f.set_attr(Attr.CTL_TSYNC, 1) + f.add_rule(NOTIFY, "getuid") + f.load() + pid = os.fork() + if pid == 0: + val = os.getuid() + if val != magic: + raise RuntimeError("Response return value failed") + quit(1) + quit(0) + else: + notify = f.receive_notify() + if notify.syscall != resolve_syscall(Arch(), "getuid"): + raise RuntimeError("Notification failed") + f.respond_notify(NotificationResponse(notify, magic, 0, 0)) + wpid, rc = os.waitpid(pid, 0) + if os.WIFEXITED(rc) == 0: + raise RuntimeError("Child process error") + if os.WEXITSTATUS(rc) != 0: + raise RuntimeError("Child process error") + quit(160) + +test() + +# kate: syntax python; +# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off; diff --git a/tests/58-live-tsync_notify.tests b/tests/58-live-tsync_notify.tests new file mode 100644 index 0000000..6c84891 --- /dev/null +++ b/tests/58-live-tsync_notify.tests @@ -0,0 +1,11 @@ +# +# libseccomp regression test automation data +# +# Copyright (c) 2019 Cisco Systems, Inc. <pmoore2@cisco.com> +# Author: Paul Moore <paul@paul-moore.com> +# + +test type: live + +# Testname API Result +58-live-tsync_notify 6 ALLOW diff --git a/tests/Makefile.am b/tests/Makefile.am index 1765eec..ddacbf3 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -96,7 +96,8 @@ check_PROGRAMS = \ 54-live-binary_tree \ 55-basic-pfc_binary_tree \ 56-basic-iterate_syscalls \ - 57-basic-rawsysrc + 57-basic-rawsysrc \ + 58-live-tsync_notify EXTRA_DIST_TESTPYTHON = \ util.py \ @@ -153,7 +154,8 @@ EXTRA_DIST_TESTPYTHON = \ 52-basic-load.py \ 53-sim-binary_tree.py \ 54-live-binary_tree.py \ - 56-basic-iterate_syscalls.py + 56-basic-iterate_syscalls.py \ + 58-live-tsync_notify.py EXTRA_DIST_TESTCFGS = \ 01-sim-allow.tests \ @@ -212,7 +214,8 @@ EXTRA_DIST_TESTCFGS = \ 54-live-binary_tree.tests \ 55-basic-pfc_binary_tree.tests \ 56-basic-iterate_syscalls.tests \ - 57-basic-rawsysrc.tests + 57-basic-rawsysrc.tests \ + 58-live-tsync_notify.tests EXTRA_DIST_TESTSCRIPTS = \ 38-basic-pfc_coverage.sh 38-basic-pfc_coverage.pfc \ |