summaryrefslogtreecommitdiff
path: root/src/arch-x86.c
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
commit983835f3e0fd000a42c8beaea9d7fbe726ffff65 (patch)
tree5e4fb69f762c5163b74bc059581fba0113d490be /src/arch-x86.c
parent5b42b8cfa25506fa260c8f46b4a063b5cfd09d1c (diff)
downloadlibseccomp-983835f3e0fd000a42c8beaea9d7fbe726ffff65.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>
Diffstat (limited to 'src/arch-x86.c')
-rw-r--r--src/arch-x86.c237
1 files changed, 220 insertions, 17 deletions
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;
}