summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Moore <paul@paul-moore.com>2016-04-20 13:49:04 -0400
committerPaul Moore <paul@paul-moore.com>2016-04-20 13:49:04 -0400
commit47516603828396f85107ea3e2a254958c2bc3ff5 (patch)
treec06df7aa1c7797ecafd359de93ad54415ae620e4
parent13dc09f77b30b3ba2d72eba3e02334fa244e63bd (diff)
downloadlibseccomp-47516603828396f85107ea3e2a254958c2bc3ff5.tar.gz
s390: handle multiplexed syscalls correctly
It turns out the socket and ipc related syscalls are also multiplexed on s390/s390x much like they are on 32-bit x86. Further making things difficult is that starting with Linux 4.3 the socket syscalls are also available as directly wired versions, much like 32-bit x86. This patch attempts to fix all those problems. Signed-off-by: Paul Moore <paul@paul-moore.com> (imported from commit 66282c31034e2bb442bd9dc862d6d814f0df2f98)
-rw-r--r--src/arch-s390-syscalls.c84
-rw-r--r--src/arch-s390.c310
-rw-r--r--src/arch-s390.h11
-rw-r--r--src/arch-s390x-syscalls.c84
-rw-r--r--src/arch-s390x.c310
-rw-r--r--src/arch-s390x.h13
-rw-r--r--src/arch-x86.c2
-rw-r--r--tests/.gitignore1
-rw-r--r--tests/33-sim-socket_syscalls_be.c81
-rwxr-xr-xtests/33-sim-socket_syscalls_be.py48
-rw-r--r--tests/33-sim-socket_syscalls_be.tests39
-rw-r--r--tests/Makefile.am9
12 files changed, 979 insertions, 13 deletions
diff --git a/src/arch-s390-syscalls.c b/src/arch-s390-syscalls.c
index a6cf826..a04673a 100644
--- a/src/arch-s390-syscalls.c
+++ b/src/arch-s390-syscalls.c
@@ -453,6 +453,48 @@ int s390_syscall_resolve_name(const char *name)
const struct arch_syscall_def *table = s390_syscall_table;
/* XXX - plenty of room for future improvement here */
+
+ if (strcmp(name, "accept") == 0)
+ return __PNR_accept;
+ if (strcmp(name, "accept4") == 0)
+ return __PNR_accept4;
+ else if (strcmp(name, "bind") == 0)
+ return __PNR_bind;
+ else if (strcmp(name, "connect") == 0)
+ return __PNR_connect;
+ else if (strcmp(name, "getpeername") == 0)
+ return __PNR_getpeername;
+ else if (strcmp(name, "getsockname") == 0)
+ return __PNR_getsockname;
+ else if (strcmp(name, "getsockopt") == 0)
+ return __PNR_getsockopt;
+ else if (strcmp(name, "listen") == 0)
+ return __PNR_listen;
+ else if (strcmp(name, "recv") == 0)
+ return __PNR_recv;
+ else if (strcmp(name, "recvfrom") == 0)
+ return __PNR_recvfrom;
+ else if (strcmp(name, "recvmsg") == 0)
+ return __PNR_recvmsg;
+ else if (strcmp(name, "recvmmsg") == 0)
+ return __PNR_recvmmsg;
+ else if (strcmp(name, "send") == 0)
+ return __PNR_send;
+ else if (strcmp(name, "sendmsg") == 0)
+ return __PNR_sendmsg;
+ else if (strcmp(name, "sendmmsg") == 0)
+ return __PNR_sendmmsg;
+ else if (strcmp(name, "sendto") == 0)
+ return __PNR_sendto;
+ else if (strcmp(name, "setsockopt") == 0)
+ return __PNR_setsockopt;
+ else if (strcmp(name, "shutdown") == 0)
+ return __PNR_shutdown;
+ else if (strcmp(name, "socket") == 0)
+ return __PNR_socket;
+ else if (strcmp(name, "socketpair") == 0)
+ return __PNR_socketpair;
+
for (iter = 0; table[iter].name != NULL; iter++) {
if (strcmp(name, table[iter].name) == 0)
return table[iter].num;
@@ -476,6 +518,48 @@ const char *s390_syscall_resolve_num(int num)
const struct arch_syscall_def *table = s390_syscall_table;
/* XXX - plenty of room for future improvement here */
+
+ if (num == __PNR_accept)
+ return "accept";
+ else if (num == __PNR_accept4)
+ return "accept4";
+ else if (num == __PNR_bind)
+ return "bind";
+ else if (num == __PNR_connect)
+ return "connect";
+ else if (num == __PNR_getpeername)
+ return "getpeername";
+ else if (num == __PNR_getsockname)
+ return "getsockname";
+ else if (num == __PNR_getsockopt)
+ return "getsockopt";
+ else if (num == __PNR_listen)
+ return "listen";
+ else if (num == __PNR_recv)
+ return "recv";
+ else if (num == __PNR_recvfrom)
+ return "recvfrom";
+ else if (num == __PNR_recvmsg)
+ return "recvmsg";
+ else if (num == __PNR_recvmmsg)
+ return "recvmmsg";
+ else if (num == __PNR_send)
+ return "send";
+ else if (num == __PNR_sendmsg)
+ return "sendmsg";
+ else if (num == __PNR_sendmmsg)
+ return "sendmmsg";
+ else if (num == __PNR_sendto)
+ return "sendto";
+ else if (num == __PNR_setsockopt)
+ return "setsockopt";
+ else if (num == __PNR_shutdown)
+ return "shutdown";
+ else if (num == __PNR_socket)
+ return "socket";
+ else if (num == __PNR_socketpair)
+ return "socketpair";
+
for (iter = 0; table[iter].num != __NR_SCMP_ERROR; iter++) {
if (num == table[iter].num)
return table[iter].name;
diff --git a/src/arch-s390.c b/src/arch-s390.c
index f509809..fca5fee 100644
--- a/src/arch-s390.c
+++ b/src/arch-s390.c
@@ -5,11 +5,16 @@
#include <stdlib.h>
#include <errno.h>
+#include <string.h>
#include <linux/audit.h>
#include "arch.h"
#include "arch-s390.h"
+/* s390 syscall numbers */
+#define __s390_NR_socketcall 102
+#define __s390_NR_ipc 117
+
const struct arch_def arch_def_s390 = {
.token = SCMP_ARCH_S390,
.token_bpf = AUDIT_ARCH_S390,
@@ -17,6 +22,307 @@ const struct arch_def arch_def_s390 = {
.endian = ARCH_ENDIAN_BIG,
.syscall_resolve_name = s390_syscall_resolve_name,
.syscall_resolve_num = s390_syscall_resolve_num,
- .syscall_rewrite = NULL,
- .rule_add = NULL,
+ .syscall_rewrite = s390_syscall_rewrite,
+ .rule_add = s390_rule_add,
};
+
+/**
+ * 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 _s390_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;
+ case -118:
+ /* accept4 */
+ return 364;
+ case -119:
+ /* recvmmsg */
+ return 337;
+ case -120:
+ /* sendmmsg */
+ return 345;
+ }
+
+ 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 _s390_sock_mux(int syscall)
+{
+ switch (syscall) {
+ case 337:
+ /* recvmmsg */
+ return -119;
+ case 345:
+ /* sendmmsg */
+ return -120;
+ 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 -118;
+ 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
+ *
+ * Syscalls can vary across different architectures so this function rewrites
+ * the syscall into the correct value for the specified architecture. Returns
+ * zero on success, negative values on failure.
+ *
+ */
+int s390_syscall_rewrite(int *syscall)
+{
+ int sys = *syscall;
+
+ if (sys <= -100 && sys >= -120)
+ *syscall = __s390_NR_socketcall;
+ else if (sys <= -200 && sys >= -211)
+ *syscall = __s390_NR_ipc;
+ else if (sys < 0)
+ return -EDOM;
+
+ return 0;
+}
+
+/**
+ * add a new rule to the s390 seccomp filter
+ * @param col the filter collection
+ * @param db the seccomp filter db
+ * @param strict the strict flag
+ * @param rule the filter rule
+ *
+ * This function adds a new syscall filter to the seccomp filter db, making any
+ * necessary adjustments for the s390 ABI. Returns zero on success, negative
+ * values on failure.
+ *
+ */
+int s390_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 <= -100 && sys >= -120) || (sys >= 359 && sys <= 373)) {
+ /* (-100 to -120) : multiplexed socket syscalls
+ (359 to 373) : direct socket syscalls, Linux 4.3+ */
+
+ /* strict check for the multiplexed socket syscalls */
+ for (iter = 0; iter < rule->args_cnt; iter++) {
+ if ((rule->args[iter].valid != 0) && (strict))
+ return -EINVAL;
+ }
+
+ /* determine both the muxed and direct syscall numbers */
+ if (sys > 0) {
+ sys_a = _s390_sock_mux(sys);
+ if (sys_a == __NR_SCMP_ERROR)
+ return __NR_SCMP_ERROR;
+ sys_b = sys;
+ } else {
+ sys_a = sys;
+ sys_b = _s390_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 = __s390_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++) {
+ 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) % 200;
+ rule->args[0].valid = 1;
+ rule->syscall = __s390_NR_ipc;
+
+ 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-s390.h b/src/arch-s390.h
index 71ba260..899c952 100644
--- a/src/arch-s390.h
+++ b/src/arch-s390.h
@@ -3,12 +3,13 @@
* Author: Jan Willeke <willeke@linux.vnet.com.com>
*/
-#ifndef _ARCH_s390_H
-#define _ARCH_s390_H
+#ifndef _ARCH_S390_H
+#define _ARCH_S390_H
#include <inttypes.h>
#include "arch.h"
+#include "db.h"
#include "system.h"
#define s390_arg_count_max 6
@@ -18,6 +19,12 @@ extern const struct arch_def arch_def_s390;
int s390_syscall_resolve_name(const char *name);
const char *s390_syscall_resolve_num(int num);
+
const char *s390_syscall_iterate_name(unsigned int spot);
+int s390_syscall_rewrite(int *syscall);
+
+int s390_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-s390x-syscalls.c b/src/arch-s390x-syscalls.c
index 25e4c34..9825c63 100644
--- a/src/arch-s390x-syscalls.c
+++ b/src/arch-s390x-syscalls.c
@@ -453,6 +453,48 @@ int s390x_syscall_resolve_name(const char *name)
const struct arch_syscall_def *table = s390x_syscall_table;
/* XXX - plenty of room for future improvement here */
+
+ if (strcmp(name, "accept") == 0)
+ return __PNR_accept;
+ if (strcmp(name, "accept4") == 0)
+ return __PNR_accept4;
+ else if (strcmp(name, "bind") == 0)
+ return __PNR_bind;
+ else if (strcmp(name, "connect") == 0)
+ return __PNR_connect;
+ else if (strcmp(name, "getpeername") == 0)
+ return __PNR_getpeername;
+ else if (strcmp(name, "getsockname") == 0)
+ return __PNR_getsockname;
+ else if (strcmp(name, "getsockopt") == 0)
+ return __PNR_getsockopt;
+ else if (strcmp(name, "listen") == 0)
+ return __PNR_listen;
+ else if (strcmp(name, "recv") == 0)
+ return __PNR_recv;
+ else if (strcmp(name, "recvfrom") == 0)
+ return __PNR_recvfrom;
+ else if (strcmp(name, "recvmsg") == 0)
+ return __PNR_recvmsg;
+ else if (strcmp(name, "recvmmsg") == 0)
+ return __PNR_recvmmsg;
+ else if (strcmp(name, "send") == 0)
+ return __PNR_send;
+ else if (strcmp(name, "sendmsg") == 0)
+ return __PNR_sendmsg;
+ else if (strcmp(name, "sendmmsg") == 0)
+ return __PNR_sendmmsg;
+ else if (strcmp(name, "sendto") == 0)
+ return __PNR_sendto;
+ else if (strcmp(name, "setsockopt") == 0)
+ return __PNR_setsockopt;
+ else if (strcmp(name, "shutdown") == 0)
+ return __PNR_shutdown;
+ else if (strcmp(name, "socket") == 0)
+ return __PNR_socket;
+ else if (strcmp(name, "socketpair") == 0)
+ return __PNR_socketpair;
+
for (iter = 0; table[iter].name != NULL; iter++) {
if (strcmp(name, table[iter].name) == 0)
return table[iter].num;
@@ -476,6 +518,48 @@ const char *s390x_syscall_resolve_num(int num)
const struct arch_syscall_def *table = s390x_syscall_table;
/* XXX - plenty of room for future improvement here */
+
+ if (num == __PNR_accept)
+ return "accept";
+ else if (num == __PNR_accept4)
+ return "accept4";
+ else if (num == __PNR_bind)
+ return "bind";
+ else if (num == __PNR_connect)
+ return "connect";
+ else if (num == __PNR_getpeername)
+ return "getpeername";
+ else if (num == __PNR_getsockname)
+ return "getsockname";
+ else if (num == __PNR_getsockopt)
+ return "getsockopt";
+ else if (num == __PNR_listen)
+ return "listen";
+ else if (num == __PNR_recv)
+ return "recv";
+ else if (num == __PNR_recvfrom)
+ return "recvfrom";
+ else if (num == __PNR_recvmsg)
+ return "recvmsg";
+ else if (num == __PNR_recvmmsg)
+ return "recvmmsg";
+ else if (num == __PNR_send)
+ return "send";
+ else if (num == __PNR_sendmsg)
+ return "sendmsg";
+ else if (num == __PNR_sendmmsg)
+ return "sendmmsg";
+ else if (num == __PNR_sendto)
+ return "sendto";
+ else if (num == __PNR_setsockopt)
+ return "setsockopt";
+ else if (num == __PNR_shutdown)
+ return "shutdown";
+ else if (num == __PNR_socket)
+ return "socket";
+ else if (num == __PNR_socketpair)
+ return "socketpair";
+
for (iter = 0; table[iter].num != __NR_SCMP_ERROR; iter++) {
if (num == table[iter].num)
return table[iter].name;
diff --git a/src/arch-s390x.c b/src/arch-s390x.c
index 5471738..d14bdf0 100644
--- a/src/arch-s390x.c
+++ b/src/arch-s390x.c
@@ -5,11 +5,16 @@
#include <stdlib.h>
#include <errno.h>
+#include <string.h>
#include <linux/audit.h>
#include "arch.h"
#include "arch-s390x.h"
+/* s390x syscall numbers */
+#define __s390x_NR_socketcall 102
+#define __s390x_NR_ipc 117
+
const struct arch_def arch_def_s390x = {
.token = SCMP_ARCH_S390X,
.token_bpf = AUDIT_ARCH_S390X,
@@ -17,6 +22,307 @@ const struct arch_def arch_def_s390x = {
.endian = ARCH_ENDIAN_BIG,
.syscall_resolve_name = s390x_syscall_resolve_name,
.syscall_resolve_num = s390x_syscall_resolve_num,
- .syscall_rewrite = NULL,
- .rule_add = NULL,
+ .syscall_rewrite = s390x_syscall_rewrite,
+ .rule_add = s390x_rule_add,
};
+
+/**
+ * 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 _s390x_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;
+ case -118:
+ /* accept4 */
+ return 364;
+ case -119:
+ /* recvmmsg */
+ return 337;
+ case -120:
+ /* sendmmsg */
+ return 345;
+ }
+
+ 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 _s390x_sock_mux(int syscall)
+{
+ switch (syscall) {
+ case 337:
+ /* recvmmsg */
+ return -119;
+ case 345:
+ /* sendmmsg */
+ return -120;
+ 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 -118;
+ 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
+ *
+ * Syscalls can vary across different architectures so this function rewrites
+ * the syscall into the correct value for the specified architecture. Returns
+ * zero on success, negative values on failure.
+ *
+ */
+int s390x_syscall_rewrite(int *syscall)
+{
+ int sys = *syscall;
+
+ if (sys <= -100 && sys >= -120)
+ *syscall = __s390x_NR_socketcall;
+ else if (sys <= -200 && sys >= -211)
+ *syscall = __s390x_NR_ipc;
+ else if (sys < 0)
+ return -EDOM;
+
+ return 0;
+}
+
+/**
+ * add a new rule to the s390x seccomp filter
+ * @param col the filter collection
+ * @param db the seccomp filter db
+ * @param strict the strict flag
+ * @param rule the filter rule
+ *
+ * This function adds a new syscall filter to the seccomp filter db, making any
+ * necessary adjustments for the s390x ABI. Returns zero on success, negative
+ * values on failure.
+ *
+ */
+int s390x_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 <= -100 && sys >= -120) || (sys >= 359 && sys <= 373)) {
+ /* (-100 to -120) : multiplexed socket syscalls
+ (359 to 373) : direct socket syscalls, Linux 4.3+ */
+
+ /* strict check for the multiplexed socket syscalls */
+ for (iter = 0; iter < rule->args_cnt; iter++) {
+ if ((rule->args[iter].valid != 0) && (strict))
+ return -EINVAL;
+ }
+
+ /* determine both the muxed and direct syscall numbers */
+ if (sys > 0) {
+ sys_a = _s390x_sock_mux(sys);
+ if (sys_a == __NR_SCMP_ERROR)
+ return __NR_SCMP_ERROR;
+ sys_b = sys;
+ } else {
+ sys_a = sys;
+ sys_b = _s390x_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 = __s390x_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++) {
+ 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) % 200;
+ rule->args[0].valid = 1;
+ rule->syscall = __s390x_NR_ipc;
+
+ 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-s390x.h b/src/arch-s390x.h
index 054044b..2857d7f 100644
--- a/src/arch-s390x.h
+++ b/src/arch-s390x.h
@@ -3,12 +3,13 @@
* Author: Jan Willeke <willeke@linux.vnet.com.com>
*/
-#ifndef _ARCH_s390x_H
-#define _ARCH_s390x_H
+#ifndef _ARCH_S390X_H
+#define _ARCH_S390X_H
#include <inttypes.h>
#include "arch.h"
+#include "db.h"
#include "system.h"
#define s390x_arg_count_max 6
@@ -21,6 +22,12 @@ extern const struct arch_def arch_def_s390x;
int s390x_syscall_resolve_name(const char *name);
const char *s390x_syscall_resolve_num(int num);
+
const char *s390x_syscall_iterate_name(unsigned int spot);
-const char *s390x_syscall_iterate_name(unsigned int spot);
+
+int s390x_syscall_rewrite(int *syscall);
+
+int s390x_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-x86.c b/src/arch-x86.c
index 1bab53f..1bfe926 100644
--- a/src/arch-x86.c
+++ b/src/arch-x86.c
@@ -232,7 +232,7 @@ int x86_rule_add(struct db_filter_col *col, struct db_filter *db, bool strict,
if ((sys <= -100 && sys >= -120) || (sys >= 359 && sys <= 373)) {
/* (-100 to -120) : multiplexed socket syscalls
- (359 to 373) : direct socket syscalls, Linux 4.4+ */
+ (359 to 373) : direct socket syscalls, Linux 4.3+ */
/* strict check for the multiplexed socket syscalls */
for (iter = 0; iter < rule->args_cnt; iter++) {
diff --git a/tests/.gitignore b/tests/.gitignore
index f6c40ee..b282fa4 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -37,3 +37,4 @@ util.pyc
30-sim-socket_syscalls
31-basic-version_check
32-live-tsync_allow
+33-sim-socket_syscalls_be
diff --git a/tests/33-sim-socket_syscalls_be.c b/tests/33-sim-socket_syscalls_be.c
new file mode 100644
index 0000000..7c4d788
--- /dev/null
+++ b/tests/33-sim-socket_syscalls_be.c
@@ -0,0 +1,81 @@
+/**
+ * Seccomp Library test program
+ *
+ * Copyright (c) 2016 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <paul@paul-moore.com>
+ */
+
+/*
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, see <http://www.gnu.org/licenses>.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+
+#include <seccomp.h>
+
+#include "util.h"
+
+int main(int argc, char *argv[])
+{
+ int rc;
+ struct util_options opts;
+ scmp_filter_ctx ctx = NULL;
+
+ rc = util_getopt(argc, argv, &opts);
+ if (rc < 0)
+ goto out;
+
+ ctx = seccomp_init(SCMP_ACT_KILL);
+ if (ctx == NULL)
+ return ENOMEM;
+
+ rc = seccomp_arch_remove(ctx, SCMP_ARCH_NATIVE);
+ if (rc != 0)
+ goto out;
+
+ rc = seccomp_arch_add(ctx, SCMP_ARCH_S390);
+ if (rc != 0)
+ goto out;
+ rc = seccomp_arch_add(ctx, SCMP_ARCH_S390X);
+ if (rc != 0)
+ goto out;
+
+ rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(socket), 0);
+ if (rc != 0)
+ goto out;
+
+ rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(connect), 0);
+ if (rc != 0)
+ goto out;
+
+ rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(accept), 0);
+ if (rc != 0)
+ goto out;
+
+ rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(accept4), 0);
+ if (rc != 0)
+ goto out;
+
+ rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(shutdown), 0);
+ if (rc != 0)
+ goto out;
+
+ rc = util_filter_output(&opts, ctx);
+ if (rc)
+ goto out;
+
+out:
+ seccomp_release(ctx);
+ return (rc < 0 ? -rc : rc);
+}
diff --git a/tests/33-sim-socket_syscalls_be.py b/tests/33-sim-socket_syscalls_be.py
new file mode 100755
index 0000000..416fb33
--- /dev/null
+++ b/tests/33-sim-socket_syscalls_be.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+
+#
+# Seccomp Library test program
+#
+# Copyright (c) 2016 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <paul@paul-moore.com>
+#
+
+#
+# This library is free software; you can redistribute it and/or modify it
+# under the terms of version 2.1 of the GNU Lesser General Public License as
+# published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+# for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library; if not, see <http://www.gnu.org/licenses>.
+#
+
+import argparse
+import sys
+
+import util
+
+from seccomp import *
+
+def test(args):
+ f = SyscallFilter(KILL)
+ f.remove_arch(Arch())
+ f.add_arch(Arch("s390"))
+ f.add_arch(Arch("s390x"))
+ f.add_rule(ALLOW, "socket")
+ f.add_rule(ALLOW, "connect")
+ f.add_rule(ALLOW, "accept")
+ f.add_rule(ALLOW, "accept4")
+ f.add_rule(ALLOW, "shutdown")
+ return f
+
+args = util.get_opt()
+ctx = test(args)
+util.filter_output(args, ctx)
+
+# kate: syntax python;
+# kate: indent-mode python; space-indent on; indent-width 4; mixedindent off;
diff --git a/tests/33-sim-socket_syscalls_be.tests b/tests/33-sim-socket_syscalls_be.tests
new file mode 100644
index 0000000..b2523af
--- /dev/null
+++ b/tests/33-sim-socket_syscalls_be.tests
@@ -0,0 +1,39 @@
+#
+# libseccomp regression test automation data
+#
+# Copyright (c) 2016 Red Hat <pmoore@redhat.com>
+# Author: Paul Moore <paul@paul-moore.com>
+#
+
+test type: bpf-sim
+
+# Testname Arch Syscall Arg0 Arg1 Arg2 Arg3 Arg4 Arg5 Result
+33-sim-socket_syscalls_be +s390 socketcall 1 N N N N N ALLOW
+33-sim-socket_syscalls_be +s390 socketcall 3 N N N N N ALLOW
+33-sim-socket_syscalls_be +s390 socketcall 5 N N N N N ALLOW
+33-sim-socket_syscalls_be +s390 socketcall 13 N N N N N ALLOW
+33-sim-socket_syscalls_be +s390 359 0 1 2 N N N ALLOW
+33-sim-socket_syscalls_be +s390 362 0 1 2 N N N ALLOW
+33-sim-socket_syscalls_be +s390 364 0 1 2 N N N ALLOW
+33-sim-socket_syscalls_be +s390 373 0 1 2 N N N ALLOW
+33-sim-socket_syscalls_be +s390 accept 5 N N N N N ALLOW
+33-sim-socket_syscalls_be +s390 accept 0 1 2 N N N KILL
+33-sim-socket_syscalls_be +s390 accept4 18 1 2 N N N ALLOW
+33-sim-socket_syscalls_be +s390 accept4 0 1 2 N N N KILL
+33-sim-socket_syscalls_be +s390x socketcall 1 N N N N N ALLOW
+33-sim-socket_syscalls_be +s390x socketcall 3 N N N N N ALLOW
+33-sim-socket_syscalls_be +s390x socketcall 5 N N N N N ALLOW
+33-sim-socket_syscalls_be +s390x socketcall 13 N N N N N ALLOW
+33-sim-socket_syscalls_be +s390x 359 0 1 2 N N N ALLOW
+33-sim-socket_syscalls_be +s390x 362 0 1 2 N N N ALLOW
+33-sim-socket_syscalls_be +s390x 364 0 1 2 N N N ALLOW
+33-sim-socket_syscalls_be +s390x 373 0 1 2 N N N ALLOW
+33-sim-socket_syscalls_be +s390x accept 5 N N N N N ALLOW
+33-sim-socket_syscalls_be +s390x accept 0 1 2 N N N KILL
+33-sim-socket_syscalls_be +s390x accept4 18 1 2 N N N ALLOW
+33-sim-socket_syscalls_be +s390x accept4 0 1 2 N N N KILL
+
+test type: bpf-valgrind
+
+# Testname
+33-sim-socket_syscalls_be
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 5f17e97..ee4e41b 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -60,7 +60,8 @@ check_PROGRAMS = \
29-sim-pseudo_syscall \
30-sim-socket_syscalls \
31-basic-version_check \
- 32-live-tsync_allow
+ 32-live-tsync_allow \
+ 33-sim-socket_syscalls_be
EXTRA_DIST_TESTPYTHON = \
util.py \
@@ -95,7 +96,8 @@ EXTRA_DIST_TESTPYTHON = \
29-sim-pseudo_syscall.py \
30-sim-socket_syscalls.py \
31-basic-version_check.py \
- 32-live-tsync_allow.py
+ 32-live-tsync_allow.py \
+ 33-sim-socket_syscalls_be.py
EXTRA_DIST_TESTCFGS = \
01-sim-allow.tests \
@@ -129,7 +131,8 @@ EXTRA_DIST_TESTCFGS = \
29-sim-pseudo_syscall.tests \
30-sim-socket_syscalls.tests \
31-basic-version_check.tests \
- 32-live-tsync_allow.tests
+ 32-live-tsync_allow.tests \
+ 33-sim-socket_syscalls_be.tests
EXTRA_DIST_TESTSCRIPTS = regression testdiff testgen