diff options
author | Paul Moore <paul@paul-moore.com> | 2016-01-10 16:09:14 -0500 |
---|---|---|
committer | Paul Moore <paul@paul-moore.com> | 2016-02-09 08:32:15 -0500 |
commit | 983835f3e0fd000a42c8beaea9d7fbe726ffff65 (patch) | |
tree | 5e4fb69f762c5163b74bc059581fba0113d490be | |
parent | 5b42b8cfa25506fa260c8f46b4a063b5cfd09d1c (diff) | |
download | libseccomp-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>
-rw-r--r-- | include/seccomp.h.in | 1 | ||||
-rw-r--r-- | src/arch-x86-syscalls.c | 73 | ||||
-rw-r--r-- | src/arch-x86.c | 237 | ||||
-rw-r--r-- | src/arch-x86.h | 2 | ||||
-rw-r--r-- | src/arch.c | 7 | ||||
-rw-r--r-- | src/arch.h | 8 | ||||
-rw-r--r-- | src/db.c | 2 |
7 files changed, 231 insertions, 99 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-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 @@ -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; @@ -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 @@ -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) |