summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Moore <paul@paul-moore.com>2020-06-13 15:47:49 -0400
committerPaul Moore <paul@paul-moore.com>2020-06-29 21:45:01 -0400
commit6b286c2e8e43de76746346b8eab855311915f5aa (patch)
tree0564aa8607a2674e2abee86cfe2386a631cfa386 /src
parent12cf0074be3fa87ef33eecde6848176f03cd1460 (diff)
downloadlibseccomp-6b286c2e8e43de76746346b8eab855311915f5aa.tar.gz
api: add API level 6
API level 6 allows callers to use both the TSYNC and notify APIs at the same time. This is due to the TSYNC_ESRCH flag which was added in Linux v5.7. This patch also fixes some omissions in seccomp_api_set(). Acked-by: Tom Hromatka <tom.hromatka@oracle.com> Signed-off-by: Paul Moore <paul@paul-moore.com>
Diffstat (limited to 'src')
-rw-r--r--src/api.c33
-rw-r--r--src/db.c12
-rw-r--r--src/system.c30
-rw-r--r--src/system.h9
4 files changed, 71 insertions, 13 deletions
diff --git a/src/api.c b/src/api.c
index b4f0c64..00975ad 100644
--- a/src/api.c
+++ b/src/api.c
@@ -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);
diff --git a/src/db.c b/src/db.c
index f0e0006..4a87ea3 100644
--- a/src/db.c
+++ b/src/db.c
@@ -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 */