summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Moore <paul@paul-moore.com>2016-02-19 11:39:00 -0500
committerPaul Moore <paul@paul-moore.com>2016-02-22 17:07:07 -0500
commita1f144a9a28aa1b831f7d3f481fb3e0e5e3de3aa (patch)
tree6ede7b5cf09d7bca92014eba186db8939dd0d4a2
parent4d29f58649cbd1fbf13e95aeac5208eb5638b436 (diff)
downloadlibseccomp-a1f144a9a28aa1b831f7d3f481fb3e0e5e3de3aa.tar.gz
all: use the seccomp() syscall whenever possible for tested ABIs
The seccomp() syscall was first added in Linux 3.17 so most systems should now support this syscall. Most importantly, the use of the seccomp() syscall enabled the thread sync functionality which isn't possible with prctl(); although callers still need to enable the flag per-filter as the thread sync default is disabled. This patch also unified the return values of the sys_chk_*() functions. Signed-off-by: Paul Moore <paul@paul-moore.com>
-rw-r--r--configure.ac6
-rw-r--r--src/db.c10
-rw-r--r--src/system.c100
-rw-r--r--src/system.h14
4 files changed, 96 insertions, 34 deletions
diff --git a/configure.ac b/configure.ac
index 75f721e..3d8596e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -89,12 +89,6 @@ AC_SUBST([VERSION_MINOR])
AC_SUBST([VERSION_MICRO])
dnl ####
-dnl function checks
-dnl ####
-dnl # NOTE: keep this disabled until we can test on a released 3.17 kernel
-dnl AC_CHECK_FUNCS(seccomp)
-
-dnl ####
dnl cython checks
dnl ####
AC_CHECK_PROG(have_cython, cython, "yes", "no")
diff --git a/src/db.c b/src/db.c
index 7233c84..1a85b1f 100644
--- a/src/db.c
+++ b/src/db.c
@@ -811,9 +811,13 @@ int db_col_attr_set(struct db_filter_col *col,
break;
case SCMP_FLTATR_CTL_TSYNC:
rc = sys_chk_seccomp_flag(SECCOMP_FILTER_FLAG_TSYNC);
- if (rc)
- return rc;
- col->attr.tsync_enable = (value ? 1 : 0);
+ if (rc == 1) {
+ /* supported */
+ rc = 0;
+ col->attr.tsync_enable = (value ? 1 : 0);
+ } else if (rc == 0)
+ /* unsupported */
+ rc = -EOPNOTSUPP;
break;
default:
rc = -EEXIST;
diff --git a/src/system.c b/src/system.c
index 87341bd..ebc4464 100644
--- a/src/system.c
+++ b/src/system.c
@@ -23,32 +23,91 @@
#include <errno.h>
#include <sys/prctl.h>
+#define _GNU_SOURCE
+#include <unistd.h>
+
#include <seccomp.h>
+#include "arch.h"
#include "db.h"
#include "gen_bpf.h"
#include "system.h"
+/* NOTE: the seccomp syscall whitelist is currently disabled for testing
+ * purposes, but unless we can verify all of the supported ABIs before
+ * our next release we may have to enable the whitelist */
+#define SYSCALL_WHITELIST_ENABLE 0
+
+static int _nr_seccomp = -1;
+static int _support_seccomp_syscall = -1;
+
+/**
+ * Check to see if the seccomp() syscall is supported
+ *
+ * This function attempts to see if the system supports the seccomp() syscall.
+ * Unfortunately, there are a few reasons why this check may fail, including
+ * a previously loaded seccomp filter, so it is hard to say for certain.
+ * Return one if the syscall is supported, zero otherwise.
+ *
+ */
+int sys_chk_seccomp_syscall(void)
+{
+ int rc;
+ int nr_seccomp;
+
+ /* 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 SYSCALL_WHITELIST_ENABLE
+ /* architecture whitelist */
+ switch (arch_def_native->token) {
+ case SCMP_ARCH_X86_64:
+ break;
+ default:
+ goto unsupported;
+ }
+#endif
+
+ nr_seccomp = arch_syscall_resolve_name(arch_def_native, "seccomp");
+ if (nr_seccomp < 0)
+ goto unsupported;
+
+ /* this is an invalid call because the second argument is non-zero, but
+ * depending on the errno value of ENOSYS or EINVAL we can guess if the
+ * seccomp() syscal is supported or not */
+ rc = syscall(nr_seccomp, SECCOMP_SET_MODE_STRICT, 1, NULL);
+ if (rc < 0 && errno == EINVAL)
+ goto supported;
+
+unsupported:
+ _support_seccomp_syscall = 0;
+ return 0;
+supported:
+ _nr_seccomp = nr_seccomp;
+ _support_seccomp_syscall = 1;
+ return 1;
+}
+
/**
* Check to see if a seccomp() flag is supported
* @param flag the seccomp() flag
*
* This function checks to see if a seccomp() flag is supported by the system.
- * If the flag is supported zero is returned, negative values otherwise.
+ * If the flag is supported one is returned, zero if unsupported, negative
+ * values on error.
*
*/
int sys_chk_seccomp_flag(int flag)
{
-#ifdef HAVE_SECCOMP
- switch (flags) {
+ switch (flag) {
case SECCOMP_FILTER_FLAG_TSYNC:
- return 0;
- default:
- return -EOPNOTSUPP;
+ return sys_chk_seccomp_syscall();
}
-#else
+
return -EOPNOTSUPP;
-#endif /* HAVE_SECCOMP */
}
/**
@@ -64,10 +123,10 @@ int sys_chk_seccomp_flag(int flag)
int sys_filter_load(const struct db_filter_col *col)
{
int rc;
- struct bpf_program *program = NULL;
+ struct bpf_program *prgm = NULL;
- program = gen_bpf_generate(col);
- if (program == NULL)
+ prgm = gen_bpf_generate(col);
+ if (prgm == NULL)
return -ENOMEM;
/* attempt to set NO_NEW_PRIVS */
@@ -78,23 +137,20 @@ int sys_filter_load(const struct db_filter_col *col)
}
/* load the filter into the kernel */
-#ifdef HAVE_SECCOMP
- {
- int flags = 0;
+ if (sys_chk_seccomp_syscall() == 1) {
+ int flgs = 0;
if (col->attr.tsync_enable)
- flags = SECCOMP_FILTER_FLAG_TSYNC;
- rc = seccomp(SECCOMP_SET_MODE_FILTER, flags, program);
+ flgs = SECCOMP_FILTER_FLAG_TSYNC;
+ 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;
- }
-#else
- rc = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, program);
-#endif /* HAVE_SECCOMP */
+ errno = ESRCH;
+ } else
+ rc = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, prgm);
filter_load_out:
/* cleanup and return */
- gen_bpf_release(program);
+ gen_bpf_release(prgm);
if (rc < 0)
return -errno;
return 0;
diff --git a/src/system.h b/src/system.h
index ffdcd1b..95384aa 100644
--- a/src/system.h
+++ b/src/system.h
@@ -47,6 +47,13 @@ struct db_filter_col;
#define SECCOMP_MODE_STRICT 1 /* uses hard-coded filter. */
#define SECCOMP_MODE_FILTER 2 /* uses user-supplied filter. */
+/* Valid operations for seccomp syscall. */
+#define SECCOMP_SET_MODE_STRICT 0
+#define SECCOMP_SET_MODE_FILTER 1
+
+/* Valid flags for SECCOMP_SET_MODE_FILTER */
+#define SECCOMP_FILTER_FLAG_TSYNC 1
+
/*
* All BPF programs must return a 32-bit value.
* The bottom 16-bits are for optional return data.
@@ -65,14 +72,14 @@ struct db_filter_col;
#define SECCOMP_RET_ACTION 0x7fff0000U
#define SECCOMP_RET_DATA 0x0000ffffU
-/*
+/**
* struct seccomp_data - the format the BPF program executes over.
* @nr: the system call number
* @arch: indicates system call convention as an AUDIT_ARCH_* value
- * as defined in <linux/audit.h>.
+ * as defined in <linux/audit.h>.
* @instruction_pointer: at the time of the system call.
* @args: up to 6 system call arguments always stored as 64-bit values
- * regardless of the architecture.
+ * regardless of the architecture.
*/
struct seccomp_data {
int nr;
@@ -108,6 +115,7 @@ typedef struct sock_filter bpf_instr_raw;
#define SECCOMP_FILTER_FLAG_TSYNC 1
#endif
+int sys_chk_seccomp_syscall(void);
int sys_chk_seccomp_flag(int flag);
int sys_filter_load(const struct db_filter_col *col);