summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Moore <paul@paul-moore.com>2016-01-10 16:09:14 -0500
committerPaul Moore <paul@paul-moore.com>2016-02-09 08:32:15 -0500
commit19ef09ba70aea96863cbeee4fbe5e5253ae07424 (patch)
tree6a2f7f4d5a7f249846a80414b2707ebc0c31d599
parent5b42b8cfa25506fa260c8f46b4a063b5cfd09d1c (diff)
downloadlibseccomp-19ef09ba70aea96863cbeee4fbe5e5253ae07424.tar.gz
arch: generate both multiplexed and direct socket syscall rules
Linux 4.3 added direct-wired socket syscalls in addition to the multiplexed socket syscalls available via socketcall(). This patch causes libseccomp to generate filters for socket syscall methods on x86 systems. Signed-off-by: Paul Moore <paul@paul-moore.com>
-rw-r--r--include/seccomp.h.in1
-rw-r--r--src/arch-x86.c237
-rw-r--r--src/arch-x86.h2
-rw-r--r--src/arch.c7
-rw-r--r--src/arch.h8
-rw-r--r--src/db.c2
6 files changed, 231 insertions, 26 deletions
diff --git a/include/seccomp.h.in b/include/seccomp.h.in
index 4b1cd2e..edfa377 100644
--- a/include/seccomp.h.in
+++ b/include/seccomp.h.in
@@ -570,6 +570,7 @@ int seccomp_export_bpf(const scmp_filter_ctx ctx, int fd);
/* NOTE - pseudo syscall values {-1..-99} are reserved */
#define __NR_SCMP_ERROR -1
+#define __NR_SCMP_UNDEF -2
/* socket syscalls */
diff --git a/src/arch-x86.c b/src/arch-x86.c
index b5fbbab..20e9805 100644
--- a/src/arch-x86.c
+++ b/src/arch-x86.c
@@ -1,7 +1,7 @@
/**
* Enhanced Seccomp x86 Specific Code
*
- * Copyright (c) 2012 Red Hat <pmoore@redhat.com>
+ * Copyright (c) 2012,2016 Red Hat <pmoore@redhat.com>
* Author: Paul Moore <pmoore@redhat.com>
*/
@@ -21,6 +21,7 @@
#include <stdlib.h>
#include <errno.h>
+#include <string.h>
#include <linux/audit.h>
#include "arch.h"
@@ -42,6 +43,134 @@ const struct arch_def arch_def_x86 = {
};
/**
+ * Convert a multiplexed pseudo socket syscall into a direct syscall
+ * @param socketcall the multiplexed pseudo syscall number
+ *
+ * Return the related direct syscall number, __NR_SCMP_UNDEF is there is
+ * no related syscall, or __NR_SCMP_ERROR otherwise.
+ *
+ */
+int _x86_sock_demux(int socketcall)
+{
+ switch (socketcall) {
+ case -101:
+ /* socket */
+ return 359;
+ case -102:
+ /* bind */
+ return 361;
+ case -103:
+ /* connect */
+ return 362;
+ case -104:
+ /* listen */
+ return 363;
+ case -105:
+ /* accept - not defined */
+ return __NR_SCMP_UNDEF;
+ case -106:
+ /* getsockname */
+ return 367;
+ case -107:
+ /* getpeername */
+ return 368;
+ case -108:
+ /* socketpair */
+ return 360;
+ case -109:
+ /* send - not defined */
+ return __NR_SCMP_UNDEF;
+ case -110:
+ /* recv - not defined */
+ return __NR_SCMP_UNDEF;
+ case -111:
+ /* sendto */
+ return 369;
+ case -112:
+ /* recvfrom */
+ return 371;
+ case -113:
+ /* shutdown */
+ return 373;
+ case -114:
+ /* setsockopt */
+ return 366;
+ case -115:
+ /* getsockopt */
+ return 365;
+ case -116:
+ /* sendmsg */
+ return 370;
+ case -117:
+ /* recvmsg */
+ return 372;
+ }
+
+ return __NR_SCMP_ERROR;
+}
+
+/**
+ * Convert a direct socket syscall into multiplexed pseudo socket syscall
+ * @param syscall the direct syscall
+ *
+ * Return the related multiplexed pseduo syscall number, __NR_SCMP_UNDEF is
+ * there is no related pseudo syscall, or __NR_SCMP_ERROR otherwise.
+ *
+ */
+int _x86_sock_mux(int syscall)
+{
+ switch (syscall) {
+ case 359:
+ /* socket */
+ return -101;
+ case 360:
+ /* socketpair */
+ return -108;
+ case 361:
+ /* bind */
+ return -102;
+ case 362:
+ /* connect */
+ return -103;
+ case 363:
+ /* listen */
+ return -104;
+ case 364:
+ /* accept4 */
+ return __NR_SCMP_UNDEF;
+ case 365:
+ /* getsockopt */
+ return -115;
+ case 366:
+ /* setsockopt */
+ return -114;
+ case 367:
+ /* getsockname */
+ return -106;
+ case 368:
+ /* getpeername */
+ return -107;
+ case 369:
+ /* sendto */
+ return -111;
+ case 370:
+ /* sendmsg */
+ return -116;
+ case 371:
+ /* recvfrom */
+ return -112;
+ case 372:
+ /* recvmsg */
+ return -117;
+ case 373:
+ /* shutdown */
+ return -113;
+ }
+
+ return __NR_SCMP_ERROR;
+}
+
+/**
* Rewrite a syscall value to match the architecture
* @param syscall the syscall number
*
@@ -66,6 +195,7 @@ int x86_syscall_rewrite(int *syscall)
/**
* add a new rule to the x86 seccomp filter
+ * @param col the filter collection
* @param db the seccomp filter db
* @param strict the strict flag
* @param rule the filter rule
@@ -75,34 +205,98 @@ int x86_syscall_rewrite(int *syscall)
* values on failure.
*
*/
-int x86_rule_add(struct db_filter *db, bool strict,
+int x86_rule_add(struct db_filter_col *col, struct db_filter *db, bool strict,
struct db_api_rule_list *rule)
{
int rc;
unsigned int iter;
+ size_t args_size;
int sys = rule->syscall;
+ int sys_a, sys_b;
+ struct db_api_rule_list *rule_a, *rule_b;
- if (sys >= 0) {
- /* normal syscall processing */
- rc = db_rule_add(db, rule);
- if (rc < 0)
- return rc;
- } else if (sys <= -100 && sys >= -117) {
- /* multiplexed socket syscalls */
- for (iter = 0; iter < ARG_COUNT_MAX; iter++) {
+ if ((sys <= -100 && sys >= -117) || (sys >= 359 && sys <= 373)) {
+ /* (-100 to -117) : multiplexed socket syscalls
+ (359 to 373) : direct socket syscalls, Linux 4.4+ */
+
+ /* strict check for the multiplexed socket syscalls */
+ for (iter = 0; iter < rule->args_cnt; iter++) {
if ((rule->args[iter].valid != 0) && (strict))
return -EINVAL;
}
- rule->args[0].arg = 0;
- rule->args[0].op = SCMP_CMP_EQ;
- rule->args[0].mask = DATUM_MAX;
- rule->args[0].datum = abs(sys) % 100;
- rule->args[0].valid = 1;
- rule->syscall = __x86_NR_socketcall;
- rc = db_rule_add(db, rule);
+ /* determine both the muxed and direct syscall numbers */
+ if (sys > 0) {
+ sys_a = _x86_sock_mux(sys);
+ if (sys_a == __NR_SCMP_ERROR)
+ return __NR_SCMP_ERROR;
+ sys_b = sys;
+ } else {
+ sys_a = sys;
+ sys_b = _x86_sock_demux(sys);
+ if (sys_b == __NR_SCMP_ERROR)
+ return __NR_SCMP_ERROR;
+ }
+
+ /* use rule_a for the multiplexed syscall and use rule_b for
+ * the direct wired syscall */
+
+ if (sys_a == __NR_SCMP_UNDEF) {
+ rule_a = NULL;
+ rule_b = rule;
+ } else if (sys_b == __NR_SCMP_UNDEF) {
+ rule_a = rule;
+ rule_b = NULL;
+ } else {
+ /* need two rules, dup the first and link together */
+ rule_a = rule;
+ rule_b = malloc(sizeof(*rule_b));
+ if (rule_b == NULL)
+ return -ENOMEM;
+ args_size = sizeof(*rule_b->args) * rule_a->args_cnt;
+ rule_b->args = malloc(args_size);
+ if (rule_b->args == NULL) {
+ free(rule_b);
+ return -ENOMEM;
+ }
+ rule_b->action = rule_a->action;
+ rule_b->syscall = rule_a->syscall;
+ rule_b->args_cnt = rule_a->args_cnt;
+ memcpy(rule_b->args, rule_a->args, args_size);
+ rule_b->prev = rule_a;
+ rule_b->next = NULL;
+ rule_a->next = rule_b;
+ }
+
+ /* multiplexed socket syscalls */
+ if (rule_a != NULL) {
+ rule_a->syscall = __x86_NR_socketcall;
+ rule_a->args[0].arg = 0;
+ rule_a->args[0].op = SCMP_CMP_EQ;
+ rule_a->args[0].mask = DATUM_MAX;
+ rule_a->args[0].datum = (-sys_a) % 100;
+ rule_a->args[0].valid = 1;
+ }
+
+ /* direct wired socket syscalls */
+ if (rule_b != NULL)
+ rule_b->syscall = sys_b;
+
+ /* add the rules as a single transaction */
+ rc = db_col_transaction_start(col);
if (rc < 0)
return rc;
+ if (rule_a != NULL) {
+ rc = db_rule_add(db, rule_a);
+ if (rc < 0)
+ goto fail_transaction;
+ }
+ if (rule_b != NULL) {
+ rc = db_rule_add(db, rule_b);
+ if (rc < 0)
+ goto fail_transaction;
+ }
+ db_col_transaction_commit(col);
} else if (sys <= -200 && sys >= -211) {
/* multiplexed ipc syscalls */
for (iter = 0; iter < ARG_COUNT_MAX; iter++) {
@@ -119,8 +313,17 @@ int x86_rule_add(struct db_filter *db, bool strict,
rc = db_rule_add(db, rule);
if (rc < 0)
return rc;
+ } else if (sys >= 0) {
+ /* normal syscall processing */
+ rc = db_rule_add(db, rule);
+ if (rc < 0)
+ return rc;
} else if (strict)
return -EDOM;
return 0;
+
+fail_transaction:
+ db_col_transaction_abort(col);
+ return rc;
}
diff --git a/src/arch-x86.h b/src/arch-x86.h
index 793c480..5fa0340 100644
--- a/src/arch-x86.h
+++ b/src/arch-x86.h
@@ -37,7 +37,7 @@ const char *x86_syscall_iterate_name(unsigned int spot);
int x86_syscall_rewrite(int *syscall);
-int x86_rule_add(struct db_filter *db, bool strict,
+int x86_rule_add(struct db_filter_col *col, struct db_filter *db, bool strict,
struct db_api_rule_list *rule);
#endif
diff --git a/src/arch.c b/src/arch.c
index afe7ae9..1ccaeec 100644
--- a/src/arch.c
+++ b/src/arch.c
@@ -382,6 +382,7 @@ int arch_syscall_rewrite(const struct arch_def *arch, int *syscall)
/**
* Add a new rule to the specified filter
+ * @param col the filter collection
* @param db the seccomp filter db
* @param strict the strict flag
* @param action the filter action
@@ -398,8 +399,8 @@ int arch_syscall_rewrite(const struct arch_def *arch, int *syscall)
* zero on success, negative values on failure.
*
*/
-int arch_filter_rule_add(struct db_filter *db, bool strict,
- uint32_t action, int syscall,
+int arch_filter_rule_add(struct db_filter_col *col, struct db_filter *db,
+ bool strict, uint32_t action, int syscall,
unsigned int chain_len, struct db_api_arg *chain)
{
int rc;
@@ -440,7 +441,7 @@ int arch_filter_rule_add(struct db_filter *db, bool strict,
}
rc = db_rule_add(db, rule);
} else
- rc = (db->arch->rule_add)(db, strict, rule);
+ rc = (db->arch->rule_add)(col, db, strict, rule);
if (rc == 0) {
/* insert the chain to the end of the filter's rule list */
rule_tail = rule;
diff --git a/src/arch.h b/src/arch.h
index 580e521..17b66f9 100644
--- a/src/arch.h
+++ b/src/arch.h
@@ -53,8 +53,8 @@ struct arch_def {
int (*syscall_resolve_name)(const char *name);
const char *(*syscall_resolve_num)(int num);
int (*syscall_rewrite)(int *syscall);
- int (*rule_add)(struct db_filter *filter, bool strict,
- struct db_api_rule_list *rule);
+ int (*rule_add)(struct db_filter_col *col, struct db_filter *db,
+ bool strict, struct db_api_rule_list *rule);
};
/* arch_def for the current architecture */
@@ -102,8 +102,8 @@ const char *arch_syscall_resolve_num(const struct arch_def *arch, int num);
int arch_syscall_translate(const struct arch_def *arch, int *syscall);
int arch_syscall_rewrite(const struct arch_def *arch, int *syscall);
-int arch_filter_rule_add(struct db_filter *db, bool strict,
- uint32_t action, int syscall,
+int arch_filter_rule_add(struct db_filter_col *col, struct db_filter *db,
+ bool strict, uint32_t action, int syscall,
unsigned int chain_len, struct db_api_arg *chain);
#endif
diff --git a/src/db.c b/src/db.c
index 793a1db..b83265b 100644
--- a/src/db.c
+++ b/src/db.c
@@ -1611,7 +1611,7 @@ int db_col_rule_add(struct db_filter_col *col,
}
for (iter = 0; iter < col->filter_cnt; iter++) {
- rc_tmp = arch_filter_rule_add(col->filters[iter], strict,
+ rc_tmp = arch_filter_rule_add(col, col->filters[iter], strict,
action, syscall,
chain_len, chain);
if (rc == 0 && rc_tmp < 0)