From 96989965042a515a3cbcb50e9b98243b9b7d4c37 Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Mon, 31 Oct 2022 13:21:33 -0600 Subject: [PATCH] api: add the SCMP_FLTATR_CTL_WAITKILL filter attribute The SCMP_FLTATR_CTL_WAITKILL attribute requests that the SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV flag be passed to the seccomp(2) system call when possible, which is currently only when the SECCOMP_FILTER_FLAG_NEW_LISTENER flag is also set. Signed-off-by: Paul Moore Signed-off-by: Tom Hromatka --- doc/man/man3/seccomp_api_get.3 | 5 ++++- doc/man/man3/seccomp_attr_set.3 | 8 +++++++- include/seccomp.h.in | 2 ++ src/api.c | 29 +++++++++++++++++++++++++++++ src/db.c | 7 +++++++ src/db.h | 2 ++ src/python/libseccomp.pxd | 1 + src/python/seccomp.pyx | 2 ++ src/system.c | 12 ++++++++++++ src/system.h | 3 +++ tests/13-basic-attrs.c | 11 +++++++++++ tests/13-basic-attrs.py | 3 +++ tests/39-basic-api_level.c | 9 ++++++++- tests/39-basic-api_level.py | 7 ++++++- 14 files changed, 97 insertions(+), 4 deletions(-) diff --git a/doc/man/man3/seccomp_api_get.3 b/doc/man/man3/seccomp_api_get.3 index ea2ea750..549cce14 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 "6 November 2020" "paul@paul-moore.com" "libseccomp Documentation" +.TH "seccomp_api_get" 3 "22 September 2022" "paul@paul-moore.com" "libseccomp Documentation" .\" ////////////////////////////////////////////////////////////////////////// .SH NAME .\" ////////////////////////////////////////////////////////////////////////// @@ -60,6 +60,9 @@ The SCMP_ACT_NOTIFY action and the notify APIs are supported. .TP .B 6 The simultaneous use of SCMP_FLTATR_CTL_TSYNC and the notify APIs are supported. +.TP +.B 7 +The SCMP_FLTATR_CTL_WAITKILL filter attribute is supported. .\" ////////////////////////////////////////////////////////////////////////// .SH RETURN VALUE .\" ////////////////////////////////////////////////////////////////////////// diff --git a/doc/man/man3/seccomp_attr_set.3 b/doc/man/man3/seccomp_attr_set.3 index 4341abc9..571010ee 100644 --- a/doc/man/man3/seccomp_attr_set.3 +++ b/doc/man/man3/seccomp_attr_set.3 @@ -1,4 +1,4 @@ -.TH "seccomp_attr_set" 3 "06 June 2020" "paul@paul-moore.com" "libseccomp Documentation" +.TH "seccomp_attr_set" 3 "21 September 2022" "paul@paul-moore.com" "libseccomp Documentation" .\" ////////////////////////////////////////////////////////////////////////// .SH NAME .\" ////////////////////////////////////////////////////////////////////////// @@ -132,6 +132,12 @@ A flag to specify if libseccomp should pass system error codes back to the caller instead of the default -ECANCELED. Defaults to off .RI ( value == 0). +.TP +.B SCMP_FLTATR_CTL_WAITKILL +A flag to specify if libseccomp should request wait killable semantics when +possible. Defaults to off +.RI ( value +== 0). .\" ////////////////////////////////////////////////////////////////////////// .SH RETURN VALUE .\" ////////////////////////////////////////////////////////////////////////// diff --git a/include/seccomp.h.in b/include/seccomp.h.in index 6f4929b9..dfbb2671 100644 --- a/include/seccomp.h.in +++ b/include/seccomp.h.in @@ -78,6 +78,7 @@ enum scmp_filter_attr { * number */ SCMP_FLTATR_API_SYSRAWRC = 9, /**< return the system return codes */ + SCMP_FLTATR_CTL_WAITKILL = 10, /**< request wait killable semantics */ _SCMP_FLTATR_MAX, }; @@ -424,6 +425,7 @@ const struct scmp_version *seccomp_version(void); * 4 : support for the SCMP_FLTATR_CTL_SSB filter attribute * 5 : support for the SCMP_ACT_NOTIFY action and notify APIs * 6 : support the simultaneous use of SCMP_FLTATR_CTL_TSYNC and notify APIs + * 7 : support for the SCMP_FLTATR_CTL_WAITKILL filter attribute * */ unsigned int seccomp_api_get(void); diff --git a/src/api.c b/src/api.c index 9c2f64ad..b85e3b87 100644 --- a/src/api.c +++ b/src/api.c @@ -191,6 +191,10 @@ static unsigned int _seccomp_api_update(void) sys_chk_seccomp_flag(SECCOMP_FILTER_FLAG_TSYNC_ESRCH) == 1) level = 6; + if (level == 6 && + sys_chk_seccomp_flag(SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV) == 1) + level = 7; + /* update the stored api level and return */ seccomp_api_level = level; return seccomp_api_level; @@ -223,6 +227,8 @@ API int seccomp_api_set(unsigned int level) 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); + sys_set_seccomp_flag(SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV, + false); break; case 2: sys_set_seccomp_syscall(true); @@ -234,6 +240,8 @@ API int seccomp_api_set(unsigned int level) 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); + sys_set_seccomp_flag(SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV, + false); break; case 3: sys_set_seccomp_syscall(true); @@ -245,6 +253,8 @@ API int seccomp_api_set(unsigned int level) 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); + sys_set_seccomp_flag(SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV, + false); break; case 4: sys_set_seccomp_syscall(true); @@ -256,6 +266,8 @@ API int seccomp_api_set(unsigned int level) 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); + sys_set_seccomp_flag(SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV, + false); break; case 5: sys_set_seccomp_syscall(true); @@ -267,6 +279,8 @@ API int seccomp_api_set(unsigned int level) 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); + sys_set_seccomp_flag(SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV, + false); break; case 6: sys_set_seccomp_syscall(true); @@ -278,6 +292,21 @@ API int seccomp_api_set(unsigned int level) 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); + sys_set_seccomp_flag(SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV, + false); + break; + case 7: + 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); + sys_set_seccomp_flag(SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV, + true); break; default: return _rc_filter(-EINVAL); diff --git a/src/db.c b/src/db.c index 6d818749..02d462ef 100644 --- a/src/db.c +++ b/src/db.c @@ -1072,6 +1072,7 @@ int db_col_reset(struct db_filter_col *col, uint32_t def_action) col->attr.spec_allow = 0; col->attr.optimize = 1; col->attr.api_sysrawrc = 0; + col->attr.wait_killable_recv = 0; /* set the state */ col->state = _DB_STA_VALID; @@ -1331,6 +1332,9 @@ int db_col_attr_get(const struct db_filter_col *col, case SCMP_FLTATR_API_SYSRAWRC: *value = col->attr.api_sysrawrc; break; + case SCMP_FLTATR_CTL_WAITKILL: + *value = col->attr.wait_killable_recv; + break; default: rc = -EINVAL; break; @@ -1444,6 +1448,9 @@ int db_col_attr_set(struct db_filter_col *col, case SCMP_FLTATR_API_SYSRAWRC: col->attr.api_sysrawrc = (value ? 1 : 0); break; + case SCMP_FLTATR_CTL_WAITKILL: + col->attr.wait_killable_recv = (value ? 1 : 0); + break; default: rc = -EINVAL; break; diff --git a/src/db.h b/src/db.h index 9a414270..906a857c 100644 --- a/src/db.h +++ b/src/db.h @@ -124,6 +124,8 @@ struct db_filter_attr { uint32_t optimize; /* return the raw system return codes */ uint32_t api_sysrawrc; + /* request SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV */ + uint32_t wait_killable_recv; }; struct db_filter { diff --git a/src/python/libseccomp.pxd b/src/python/libseccomp.pxd index 9589cfea..55f8207d 100644 --- a/src/python/libseccomp.pxd +++ b/src/python/libseccomp.pxd @@ -63,6 +63,7 @@ cdef extern from "seccomp.h": SCMP_FLTATR_CTL_SSB SCMP_FLTATR_CTL_OPTIMIZE SCMP_FLTATR_API_SYSRAWRC + SCMP_FLTATR_CTL_WAITKILL cdef enum scmp_compare: SCMP_CMP_NE diff --git a/src/python/seccomp.pyx b/src/python/seccomp.pyx index 1f58517b..5657577f 100644 --- a/src/python/seccomp.pyx +++ b/src/python/seccomp.pyx @@ -325,6 +325,7 @@ cdef class Attr: 1: rules weighted by priority and complexity (DEFAULT) 2: binary tree sorted by syscall number API_SYSRAWRC - return the raw syscall codes + CTL_WAITKILL - request wait killable semantics """ ACT_DEFAULT = libseccomp.SCMP_FLTATR_ACT_DEFAULT ACT_BADARCH = libseccomp.SCMP_FLTATR_ACT_BADARCH @@ -335,6 +336,7 @@ cdef class Attr: CTL_SSB = libseccomp.SCMP_FLTATR_CTL_SSB CTL_OPTIMIZE = libseccomp.SCMP_FLTATR_CTL_OPTIMIZE API_SYSRAWRC = libseccomp.SCMP_FLTATR_API_SYSRAWRC + CTL_WAITKILL = libseccomp.SCMP_FLTATR_CTL_WAITKILL cdef class Arg: """ Python object representing a SyscallFilter syscall argument. diff --git a/src/system.c b/src/system.c index 94e0405d..3d10e21d 100644 --- a/src/system.c +++ b/src/system.c @@ -58,6 +58,7 @@ struct task_state { int sup_flag_new_listener; int sup_user_notif; int sup_flag_tsync_esrch; + int sup_flag_wait_kill; }; static struct task_state state = { .nr_seccomp = -1, @@ -73,6 +74,7 @@ static struct task_state state = { .sup_flag_new_listener = -1, .sup_user_notif = -1, .sup_flag_tsync_esrch = -1, + .sup_flag_wait_kill = -1, }; /** @@ -307,6 +309,10 @@ int sys_chk_seccomp_flag(int flag) if (state.sup_flag_tsync_esrch < 0) state.sup_flag_tsync_esrch = _sys_chk_flag_kernel(flag); return state.sup_flag_tsync_esrch; + case SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV: + if (state.sup_flag_wait_kill < 0) + state.sup_flag_wait_kill = _sys_chk_flag_kernel(flag); + return state.sup_flag_wait_kill; } return -EOPNOTSUPP; @@ -339,6 +345,9 @@ void sys_set_seccomp_flag(int flag, bool enable) case SECCOMP_FILTER_FLAG_TSYNC_ESRCH: state.sup_flag_tsync_esrch = (enable ? 1 : 0); break; + case SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV: + state.sup_flag_wait_kill = (enable ? 1 : 0); + break; } } @@ -394,6 +403,9 @@ int sys_filter_load(struct db_filter_col *col, bool rawrc) flgs |= SECCOMP_FILTER_FLAG_TSYNC; } else if (listener_req) flgs |= SECCOMP_FILTER_FLAG_NEW_LISTENER; + if ((flgs & SECCOMP_FILTER_FLAG_NEW_LISTENER) && + col->attr.wait_killable_recv) + flgs |= SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV; if (col->attr.log_enable) flgs |= SECCOMP_FILTER_FLAG_LOG; if (col->attr.spec_allow) diff --git a/src/system.h b/src/system.h index 804e9aae..7918c1f5 100644 --- a/src/system.h +++ b/src/system.h @@ -138,6 +138,9 @@ typedef struct sock_filter bpf_instr_raw; #ifndef SECCOMP_FILTER_FLAG_TSYNC_ESRCH #define SECCOMP_FILTER_FLAG_TSYNC_ESRCH (1UL << 4) #endif +#ifndef SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV +#define SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV (1UL << 5) +#endif #ifndef SECCOMP_RET_LOG #define SECCOMP_RET_LOG 0x7ffc0000U /* allow after logging */ diff --git a/tests/13-basic-attrs.c b/tests/13-basic-attrs.c index e3c5881d..fee83b4b 100644 --- a/tests/13-basic-attrs.c +++ b/tests/13-basic-attrs.c @@ -142,6 +142,17 @@ int main(int argc, char *argv[]) goto out; } + rc = seccomp_attr_set(ctx, SCMP_FLTATR_CTL_WAITKILL, 1); + if (rc != 0) + goto out; + rc = seccomp_attr_get(ctx, SCMP_FLTATR_CTL_WAITKILL, &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 48c25a06..abf4b68c 100755 --- a/tests/13-basic-attrs.py +++ b/tests/13-basic-attrs.py @@ -61,6 +61,9 @@ def test(): f.set_attr(Attr.API_SYSRAWRC, 1) if f.get_attr(Attr.API_SYSRAWRC) != 1: raise RuntimeError("Failed getting Attr.API_SYSRAWRC") + f.set_attr(Attr.CTL_WAITKILL, 1) + if f.get_attr(Attr.CTL_WAITKILL) != 1: + raise RuntimeError("Failed getting Attr.CTL_WAITKILL") test() diff --git a/tests/39-basic-api_level.c b/tests/39-basic-api_level.c index 6c31be1b..d3fb54b5 100644 --- a/tests/39-basic-api_level.c +++ b/tests/39-basic-api_level.c @@ -75,13 +75,20 @@ int main(int argc, char *argv[]) if (api != 6) return -13; + rc = seccomp_api_set(7); + if (rc != 0) + return -14; + api = seccomp_api_get(); + if (api != 7) + return -15; + /* 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 != 6) + if (api != 7) return -1002; return 0; diff --git a/tests/39-basic-api_level.py b/tests/39-basic-api_level.py index 352568e6..93f3d7b5 100755 --- a/tests/39-basic-api_level.py +++ b/tests/39-basic-api_level.py @@ -65,6 +65,11 @@ def test(): if api != 6: raise RuntimeError("Failed getting API level 6") + set_api(7) + api = get_api() + if api != 7: + raise RuntimeError("Failed getting API level 7") + # Attempt to set a high, invalid API level try: set_api(1024) @@ -74,7 +79,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 != 6: + if api != 7: raise RuntimeError("Failed getting old API level after setting an invalid API level") test()