summaryrefslogtreecommitdiff
path: root/src
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
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')
-rw-r--r--src/arch-x86-syscalls.c73
-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, 230 insertions, 99 deletions
diff --git a/src/arch-x86-syscalls.c b/src/arch-x86-syscalls.c
index 1c0f65a..bda8305 100644
--- a/src/arch-x86-syscalls.c
+++ b/src/arch-x86-syscalls.c
@@ -19,19 +19,6 @@
* along with this library; if not, see <http://www.gnu.org/licenses>.
*/
-/* NOTE: Linux 4.3 introduced direct wired socket syscalls, at present we only
- * use the direct wired numbers if we are building on a x86 system and
- * the direct wired syscalls are defined (e.g. __NR_socket > 0) */
-#if __i386__
-#if __NR_socket < 0
-#define __SYS_SOCKET_MULTI 0
-#else
-#define __SYS_SOCKET_MULTI 1
-#endif
-#else
-#define __SYS_SOCKET_MULTI 1
-#endif
-
#include <string.h>
#include <seccomp.h>
@@ -45,11 +32,7 @@ const struct arch_syscall_def x86_syscall_table[] = { \
{ "_newselect", 142 },
{ "_sysctl", 149 },
{ "accept", __PNR_accept },
-#if __SYS_SOCKET_MULTI
{ "accept4", 364 },
-#else
- { "accept4", __PNR_accept4 },
-#endif
{ "access", 33 },
{ "acct", 51 },
{ "add_key", 286 },
@@ -60,11 +43,7 @@ const struct arch_syscall_def x86_syscall_table[] = { \
{ "arm_sync_file_range", __PNR_arm_sync_file_range },
{ "arch_prctl", __PNR_arch_prctl },
{ "bdflush", 134 },
-#if __SYS_SOCKET_MULTI
{ "bind", 361 },
-#else
- { "bind", __PNR_bind },
-#endif
{ "bpf", 357 },
{ "break", 17 },
{ "breakpoint", __PNR_breakpoint },
@@ -85,11 +64,7 @@ const struct arch_syscall_def x86_syscall_table[] = { \
{ "clock_settime", 264 },
{ "clone", 120 },
{ "close", 6 },
-#if __SYS_SOCKET_MULTI
{ "connect", 362 },
-#else
- { "connect", __PNR_connect },
-#endif
{ "creat", 8 },
{ "create_module", 127 },
{ "delete_module", 129 },
@@ -159,11 +134,7 @@ const struct arch_syscall_def x86_syscall_table[] = { \
{ "getgroups", 80 },
{ "getgroups32", 205 },
{ "getitimer", 105 },
-#if __SYS_SOCKET_MULTI
{ "getpeername", 368 },
-#else
- { "getpeername", __PNR_getpeername },
-#endif
{ "getpgid", 132 },
{ "getpgrp", 65 },
{ "getpid", 20 },
@@ -178,16 +149,8 @@ const struct arch_syscall_def x86_syscall_table[] = { \
{ "getrlimit", 76 },
{ "getrusage", 77 },
{ "getsid", 147 },
-#if __SYS_SOCKET_MULTI
{ "getsockname", 367 },
-#else
- { "getsockname", __PNR_getsockname },
-#endif
-#if __SYS_SOCKET_MULTI
{ "getsockopt", 365 },
-#else
- { "getsockopt", __PNR_getsockopt },
-#endif
{ "gettid", 224 },
{ "gettimeofday", 78 },
{ "getuid", 24 },
@@ -221,11 +184,7 @@ const struct arch_syscall_def x86_syscall_table[] = { \
{ "lgetxattr", 230 },
{ "link", 9 },
{ "linkat", 303 },
-#if __SYS_SOCKET_MULTI
{ "listen", 363 },
-#else
- { "listen", __PNR_listen },
-#endif
{ "listxattr", 232 },
{ "llistxattr", 233 },
{ "lock", 53 },
@@ -318,17 +277,9 @@ const struct arch_syscall_def x86_syscall_table[] = { \
{ "readv", 145 },
{ "reboot", 88 },
{ "recv", __PNR_recv },
-#if __SYS_SOCKET_MULTI
{ "recvfrom", 371 },
-#else
- { "recvfrom", __PNR_recvfrom },
-#endif
{ "recvmmsg", 337 },
-#if __SYS_SOCKET_MULTI
{ "recvmsg", 372 },
-#else
- { "recvmsg", __PNR_recvmsg },
-#endif
{ "remap_file_pages", 257 },
{ "removexattr", 235 },
{ "rename", 38 },
@@ -372,16 +323,8 @@ const struct arch_syscall_def x86_syscall_table[] = { \
{ "sendfile", 187 },
{ "sendfile64", 239 },
{ "sendmmsg", 345 },
-#if __SYS_SOCKET_MULTI
{ "sendmsg", 370 },
-#else
- { "sendmsg", __PNR_sendmsg },
-#endif
-#if __SYS_SOCKET_MULTI
{ "sendto", 369 },
-#else
- { "sendto", __PNR_sendto },
-#endif
{ "set_mempolicy", 276 },
{ "set_robust_list", 311 },
{ "set_thread_area", 243 },
@@ -411,11 +354,7 @@ const struct arch_syscall_def x86_syscall_table[] = { \
{ "setreuid32", 203 },
{ "setrlimit", 75 },
{ "setsid", 66 },
-#if __SYS_SOCKET_MULTI
{ "setsockopt", 366 },
-#else
- { "setsockopt", __PNR_setsockopt },
-#endif
{ "settimeofday", 79 },
{ "setuid", 23 },
{ "setuid32", 213 },
@@ -425,11 +364,7 @@ const struct arch_syscall_def x86_syscall_table[] = { \
{ "shmctl", __PNR_shmctl },
{ "shmdt", __PNR_shmdt },
{ "shmget", __PNR_shmget },
-#if __SYS_SOCKET_MULTI
{ "shutdown", 373 },
-#else
- { "shutdown", __PNR_shutdown },
-#endif
{ "sigaction", 67 },
{ "sigaltstack", 186 },
{ "signal", 48 },
@@ -439,17 +374,9 @@ const struct arch_syscall_def x86_syscall_table[] = { \
{ "sigprocmask", 126 },
{ "sigreturn", 119 },
{ "sigsuspend", 72 },
-#if __SYS_SOCKET_MULTI
{ "socket", 359 },
-#else
- { "socket", __PNR_socket },
-#endif
{ "socketcall", 102 },
-#if __SYS_SOCKET_MULTI
{ "socketpair", 360 },
-#else
- { "socketpair", __PNR_socketpair },
-#endif
{ "splice", 313 },
{ "spu_create", __PNR_spu_create },
{ "spu_run", __PNR_spu_run },
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)