summaryrefslogtreecommitdiffstats
path: root/src/syscalls.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 17:09:30 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 17:09:30 +0000
commit81749f1fe87e489c4e2e7408a0fae9370c3810b3 (patch)
tree2d1345a5762855b6577495d90ac134c4e92d7ff8 /src/syscalls.c
parentInitial commit. (diff)
downloadlibseccomp-81749f1fe87e489c4e2e7408a0fae9370c3810b3.tar.xz
libseccomp-81749f1fe87e489c4e2e7408a0fae9370c3810b3.zip
Adding upstream version 2.5.5.upstream/2.5.5upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/syscalls.c')
-rw-r--r--src/syscalls.c551
1 files changed, 551 insertions, 0 deletions
diff --git a/src/syscalls.c b/src/syscalls.c
new file mode 100644
index 0000000..9c58c12
--- /dev/null
+++ b/src/syscalls.c
@@ -0,0 +1,551 @@
+/**
+ * Enhanced Seccomp Syscall Table Functions
+ *
+ * Copyright (c) 2012, 2020 Red Hat <pmoore@redhat.com>
+ * Author: Paul Moore <paul@paul-moore.com>
+ * gperf support: Giuseppe Scrivano <gscrivan@redhat.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 <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <seccomp.h>
+
+#include "db.h"
+#include "arch.h"
+#include "syscalls.h"
+
+/**
+ * Resolve a syscall name to a number
+ * @param arch the arch definition
+ * @param name the syscall name
+ *
+ * Resolve the given syscall name to the syscall number using the syscall table.
+ * Returns the syscall number on success, including negative pseudo syscall
+ * numbers; returns __NR_SCMP_ERROR on failure.
+ *
+ */
+int abi_syscall_resolve_name_munge(const struct arch_def *arch,
+ const char *name)
+{
+
+#define _ABI_SYSCALL_RES_NAME_CHK(NAME) \
+ if (!strcmp(name, #NAME)) return __PNR_##NAME;
+
+ _ABI_SYSCALL_RES_NAME_CHK(socket)
+ _ABI_SYSCALL_RES_NAME_CHK(bind)
+ _ABI_SYSCALL_RES_NAME_CHK(connect)
+ _ABI_SYSCALL_RES_NAME_CHK(listen)
+ _ABI_SYSCALL_RES_NAME_CHK(accept)
+ _ABI_SYSCALL_RES_NAME_CHK(getsockname)
+ _ABI_SYSCALL_RES_NAME_CHK(getpeername)
+ _ABI_SYSCALL_RES_NAME_CHK(socketpair)
+ _ABI_SYSCALL_RES_NAME_CHK(send)
+ _ABI_SYSCALL_RES_NAME_CHK(recv)
+ _ABI_SYSCALL_RES_NAME_CHK(sendto)
+ _ABI_SYSCALL_RES_NAME_CHK(recvfrom)
+ _ABI_SYSCALL_RES_NAME_CHK(shutdown)
+ _ABI_SYSCALL_RES_NAME_CHK(setsockopt)
+ _ABI_SYSCALL_RES_NAME_CHK(getsockopt)
+ _ABI_SYSCALL_RES_NAME_CHK(sendmsg)
+ _ABI_SYSCALL_RES_NAME_CHK(recvmsg)
+ _ABI_SYSCALL_RES_NAME_CHK(accept4)
+ _ABI_SYSCALL_RES_NAME_CHK(recvmmsg)
+ _ABI_SYSCALL_RES_NAME_CHK(sendmmsg)
+ _ABI_SYSCALL_RES_NAME_CHK(semop)
+ _ABI_SYSCALL_RES_NAME_CHK(semget)
+ _ABI_SYSCALL_RES_NAME_CHK(semctl)
+ _ABI_SYSCALL_RES_NAME_CHK(semtimedop)
+ _ABI_SYSCALL_RES_NAME_CHK(msgsnd)
+ _ABI_SYSCALL_RES_NAME_CHK(msgrcv)
+ _ABI_SYSCALL_RES_NAME_CHK(msgget)
+ _ABI_SYSCALL_RES_NAME_CHK(msgctl)
+ _ABI_SYSCALL_RES_NAME_CHK(shmat)
+ _ABI_SYSCALL_RES_NAME_CHK(shmdt)
+ _ABI_SYSCALL_RES_NAME_CHK(shmget)
+ _ABI_SYSCALL_RES_NAME_CHK(shmctl)
+
+ return arch->syscall_resolve_name_raw(name);
+}
+
+/**
+ * Resolve a syscall number to a name
+ * @param arch the arch definition
+ * @param num the syscall number
+ *
+ * Resolve the given syscall number to the syscall name using the syscall table.
+ * Returns a pointer to the syscall name string on success, including pseudo
+ * syscall names; returns NULL on failure.
+ *
+ */
+const char *abi_syscall_resolve_num_munge(const struct arch_def *arch, int num)
+{
+
+#define _ABI_SYSCALL_RES_NUM_CHK(NAME) \
+ if (num == __PNR_##NAME) return #NAME;
+
+ _ABI_SYSCALL_RES_NUM_CHK(socket)
+ _ABI_SYSCALL_RES_NUM_CHK(bind)
+ _ABI_SYSCALL_RES_NUM_CHK(connect)
+ _ABI_SYSCALL_RES_NUM_CHK(listen)
+ _ABI_SYSCALL_RES_NUM_CHK(accept)
+ _ABI_SYSCALL_RES_NUM_CHK(getsockname)
+ _ABI_SYSCALL_RES_NUM_CHK(getpeername)
+ _ABI_SYSCALL_RES_NUM_CHK(socketpair)
+ _ABI_SYSCALL_RES_NUM_CHK(send)
+ _ABI_SYSCALL_RES_NUM_CHK(recv)
+ _ABI_SYSCALL_RES_NUM_CHK(sendto)
+ _ABI_SYSCALL_RES_NUM_CHK(recvfrom)
+ _ABI_SYSCALL_RES_NUM_CHK(shutdown)
+ _ABI_SYSCALL_RES_NUM_CHK(setsockopt)
+ _ABI_SYSCALL_RES_NUM_CHK(getsockopt)
+ _ABI_SYSCALL_RES_NUM_CHK(sendmsg)
+ _ABI_SYSCALL_RES_NUM_CHK(recvmsg)
+ _ABI_SYSCALL_RES_NUM_CHK(accept4)
+ _ABI_SYSCALL_RES_NUM_CHK(recvmmsg)
+ _ABI_SYSCALL_RES_NUM_CHK(sendmmsg)
+ _ABI_SYSCALL_RES_NUM_CHK(semop)
+ _ABI_SYSCALL_RES_NUM_CHK(semget)
+ _ABI_SYSCALL_RES_NUM_CHK(semctl)
+ _ABI_SYSCALL_RES_NUM_CHK(semtimedop)
+ _ABI_SYSCALL_RES_NUM_CHK(msgsnd)
+ _ABI_SYSCALL_RES_NUM_CHK(msgrcv)
+ _ABI_SYSCALL_RES_NUM_CHK(msgget)
+ _ABI_SYSCALL_RES_NUM_CHK(msgctl)
+ _ABI_SYSCALL_RES_NUM_CHK(shmat)
+ _ABI_SYSCALL_RES_NUM_CHK(shmdt)
+ _ABI_SYSCALL_RES_NUM_CHK(shmget)
+ _ABI_SYSCALL_RES_NUM_CHK(shmctl)
+
+ return arch->syscall_resolve_num_raw(num);
+}
+
+/**
+ * Check if a syscall is a socket syscall
+ * @param arch the arch definition
+ * @param sys the syscall number
+ *
+ * Returns true if the syscall is a socket related syscall, false otherwise.
+ *
+ */
+static bool _abi_syscall_socket_test(const struct arch_def *arch, int sys)
+{
+ const char *name;
+
+ /* multiplexed pseduo-syscalls */
+ if (sys <= -100 && sys >= -120)
+ return true;
+
+ name = arch->syscall_resolve_num_raw(sys);
+ if (!name)
+ return false;
+
+#define _ABI_SYSCALL_SOCK_CHK(NAME) \
+ if (!strcmp(name, #NAME)) return true;
+
+ _ABI_SYSCALL_SOCK_CHK(socket)
+ _ABI_SYSCALL_SOCK_CHK(bind)
+ _ABI_SYSCALL_SOCK_CHK(connect)
+ _ABI_SYSCALL_SOCK_CHK(listen)
+ _ABI_SYSCALL_SOCK_CHK(accept)
+ _ABI_SYSCALL_SOCK_CHK(getsockname)
+ _ABI_SYSCALL_SOCK_CHK(getpeername)
+ _ABI_SYSCALL_SOCK_CHK(socketpair)
+ _ABI_SYSCALL_SOCK_CHK(send)
+ _ABI_SYSCALL_SOCK_CHK(recv)
+ _ABI_SYSCALL_SOCK_CHK(sendto)
+ _ABI_SYSCALL_SOCK_CHK(recvfrom)
+ _ABI_SYSCALL_SOCK_CHK(shutdown)
+ _ABI_SYSCALL_SOCK_CHK(setsockopt)
+ _ABI_SYSCALL_SOCK_CHK(getsockopt)
+ _ABI_SYSCALL_SOCK_CHK(sendmsg)
+ _ABI_SYSCALL_SOCK_CHK(recvmsg)
+ _ABI_SYSCALL_SOCK_CHK(accept4)
+ _ABI_SYSCALL_SOCK_CHK(recvmmsg)
+ _ABI_SYSCALL_SOCK_CHK(sendmmsg)
+
+ return false;
+}
+
+/**
+ * Check if a syscall is an ipc syscall
+ * @param arch the arch definition
+ * @param sys the syscall number
+ *
+ * Returns true if the syscall is an ipc related syscall, false otherwise.
+ *
+ */
+static bool _abi_syscall_ipc_test(const struct arch_def *arch, int sys)
+{
+ const char *name;
+
+ /* multiplexed pseduo-syscalls */
+ if (sys <= -200 && sys >= -224)
+ return true;
+
+ name = arch->syscall_resolve_num_raw(sys);
+ if (!name)
+ return false;
+
+#define _ABI_SYSCALL_IPC_CHK(NAME) \
+ if (!strcmp(name, #NAME)) return true;
+
+ _ABI_SYSCALL_IPC_CHK(semop)
+ _ABI_SYSCALL_IPC_CHK(semget)
+ _ABI_SYSCALL_IPC_CHK(semctl)
+ _ABI_SYSCALL_IPC_CHK(semtimedop)
+ _ABI_SYSCALL_IPC_CHK(msgsnd)
+ _ABI_SYSCALL_IPC_CHK(msgrcv)
+ _ABI_SYSCALL_IPC_CHK(msgget)
+ _ABI_SYSCALL_IPC_CHK(msgctl)
+ _ABI_SYSCALL_IPC_CHK(shmat)
+ _ABI_SYSCALL_IPC_CHK(shmdt)
+ _ABI_SYSCALL_IPC_CHK(shmget)
+ _ABI_SYSCALL_IPC_CHK(shmctl)
+
+ return false;
+}
+
+/**
+ * Convert a multiplexed pseudo syscall into a direct syscall
+ * @param arch the arch definition
+ * @param syscall 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.
+ *
+ */
+static int _abi_syscall_demux(const struct arch_def *arch, int syscall)
+{
+ int sys = __NR_SCMP_UNDEF;
+
+#define _ABI_SYSCALL_DEMUX_CHK(NAME) \
+case __PNR_##NAME: \
+ sys = arch->syscall_resolve_name_raw(#NAME); break;
+
+ switch (syscall) {
+ _ABI_SYSCALL_DEMUX_CHK(socket)
+ _ABI_SYSCALL_DEMUX_CHK(bind)
+ _ABI_SYSCALL_DEMUX_CHK(connect)
+ _ABI_SYSCALL_DEMUX_CHK(listen)
+ _ABI_SYSCALL_DEMUX_CHK(accept)
+ _ABI_SYSCALL_DEMUX_CHK(getsockname)
+ _ABI_SYSCALL_DEMUX_CHK(getpeername)
+ _ABI_SYSCALL_DEMUX_CHK(socketpair)
+ _ABI_SYSCALL_DEMUX_CHK(send)
+ _ABI_SYSCALL_DEMUX_CHK(recv)
+ _ABI_SYSCALL_DEMUX_CHK(sendto)
+ _ABI_SYSCALL_DEMUX_CHK(recvfrom)
+ _ABI_SYSCALL_DEMUX_CHK(shutdown)
+ _ABI_SYSCALL_DEMUX_CHK(setsockopt)
+ _ABI_SYSCALL_DEMUX_CHK(getsockopt)
+ _ABI_SYSCALL_DEMUX_CHK(sendmsg)
+ _ABI_SYSCALL_DEMUX_CHK(recvmsg)
+ _ABI_SYSCALL_DEMUX_CHK(accept4)
+ _ABI_SYSCALL_DEMUX_CHK(recvmmsg)
+ _ABI_SYSCALL_DEMUX_CHK(sendmmsg)
+ _ABI_SYSCALL_DEMUX_CHK(semop)
+ _ABI_SYSCALL_DEMUX_CHK(semget)
+ _ABI_SYSCALL_DEMUX_CHK(semctl)
+ _ABI_SYSCALL_DEMUX_CHK(semtimedop)
+ _ABI_SYSCALL_DEMUX_CHK(msgsnd)
+ _ABI_SYSCALL_DEMUX_CHK(msgrcv)
+ _ABI_SYSCALL_DEMUX_CHK(msgget)
+ _ABI_SYSCALL_DEMUX_CHK(msgctl)
+ _ABI_SYSCALL_DEMUX_CHK(shmat)
+ _ABI_SYSCALL_DEMUX_CHK(shmdt)
+ _ABI_SYSCALL_DEMUX_CHK(shmget)
+ _ABI_SYSCALL_DEMUX_CHK(shmctl)
+ }
+
+ /* this looks odd because the arch resolver returns _ERROR if it can't
+ * resolve the syscall, but we want to use _UNDEF for that, so we set
+ * 'sys' to a sentinel value of _UNDEF and if it is error here we know
+ * the resolve failed to find a match */
+ if (sys == __NR_SCMP_UNDEF)
+ sys = __NR_SCMP_ERROR;
+ else if (sys == __NR_SCMP_ERROR)
+ sys = __NR_SCMP_UNDEF;
+
+ return sys;
+}
+
+/**
+ * Convert a direct syscall into multiplexed pseudo socket syscall
+ * @param arch the arch definition
+ * @param syscall the direct syscall
+ *
+ * Return the related multiplexed pseudo syscall number, __NR_SCMP_UNDEF is
+ * there is no related pseudo syscall, or __NR_SCMP_ERROR otherwise.
+ *
+ */
+static int _abi_syscall_mux(const struct arch_def *arch, int syscall)
+{
+ const char *sys;
+
+ sys = arch->syscall_resolve_num_raw(syscall);
+ if (!sys)
+ return __NR_SCMP_ERROR;
+
+#define _ABI_SYSCALL_MUX_CHK(NAME) \
+ if (!strcmp(sys, #NAME)) return __PNR_##NAME;
+
+ _ABI_SYSCALL_MUX_CHK(socket)
+ _ABI_SYSCALL_MUX_CHK(bind)
+ _ABI_SYSCALL_MUX_CHK(connect)
+ _ABI_SYSCALL_MUX_CHK(listen)
+ _ABI_SYSCALL_MUX_CHK(accept)
+ _ABI_SYSCALL_MUX_CHK(getsockname)
+ _ABI_SYSCALL_MUX_CHK(getpeername)
+ _ABI_SYSCALL_MUX_CHK(socketpair)
+ _ABI_SYSCALL_MUX_CHK(send)
+ _ABI_SYSCALL_MUX_CHK(recv)
+ _ABI_SYSCALL_MUX_CHK(sendto)
+ _ABI_SYSCALL_MUX_CHK(recvfrom)
+ _ABI_SYSCALL_MUX_CHK(shutdown)
+ _ABI_SYSCALL_MUX_CHK(setsockopt)
+ _ABI_SYSCALL_MUX_CHK(getsockopt)
+ _ABI_SYSCALL_MUX_CHK(sendmsg)
+ _ABI_SYSCALL_MUX_CHK(recvmsg)
+ _ABI_SYSCALL_MUX_CHK(accept4)
+ _ABI_SYSCALL_MUX_CHK(recvmmsg)
+ _ABI_SYSCALL_MUX_CHK(sendmmsg)
+ _ABI_SYSCALL_MUX_CHK(semop)
+ _ABI_SYSCALL_MUX_CHK(semget)
+ _ABI_SYSCALL_MUX_CHK(semctl)
+ _ABI_SYSCALL_MUX_CHK(semtimedop)
+ _ABI_SYSCALL_MUX_CHK(msgsnd)
+ _ABI_SYSCALL_MUX_CHK(msgrcv)
+ _ABI_SYSCALL_MUX_CHK(msgget)
+ _ABI_SYSCALL_MUX_CHK(msgctl)
+ _ABI_SYSCALL_MUX_CHK(shmat)
+ _ABI_SYSCALL_MUX_CHK(shmdt)
+ _ABI_SYSCALL_MUX_CHK(shmget)
+ _ABI_SYSCALL_MUX_CHK(shmctl)
+
+ return __NR_SCMP_ERROR;
+}
+
+/**
+ * Rewrite a syscall value to match the architecture
+ * @param arch the arch definition
+ * @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 abi_syscall_rewrite(const struct arch_def *arch, int *syscall)
+{
+ int sys = *syscall;
+
+ if (sys <= -100 && sys >= -120)
+ *syscall = arch->sys_socketcall;
+ else if (sys <= -200 && sys >= -224)
+ *syscall = arch->sys_ipc;
+ else if (sys < 0)
+ return -EDOM;
+
+ return 0;
+}
+
+/**
+ * add a new rule to the abi seccomp filter
+ * @param db the seccomp filter db
+ * @param rule the filter rule
+ *
+ * This function adds a new syscall filter to the seccomp filter db, making any
+ * necessary adjustments for the abi ABI. Returns zero on success, negative
+ * values on failure.
+ *
+ * It is important to note that in the case of failure the db may be corrupted,
+ * the caller must use the transaction mechanism if the db integrity is
+ * important.
+ *
+ */
+int abi_rule_add(struct db_filter *db, struct db_api_rule_list *rule)
+{
+ int rc = 0;
+ unsigned int iter;
+ int sys = rule->syscall;
+ int sys_a, sys_b;
+ struct db_api_rule_list *rule_a, *rule_b, *rule_dup = NULL;
+
+ if (_abi_syscall_socket_test(db->arch, sys)) {
+ /* socket syscalls */
+
+ /* strict check for the multiplexed socket syscalls */
+ for (iter = 0; iter < ARG_COUNT_MAX; iter++) {
+ if ((rule->args[iter].valid != 0) && (rule->strict)) {
+ rc = -EINVAL;
+ goto add_return;
+ }
+ }
+
+ /* determine both the muxed and direct syscall numbers */
+ if (sys > 0) {
+ sys_a = _abi_syscall_mux(db->arch, sys);
+ if (sys_a == __NR_SCMP_ERROR) {
+ rc = __NR_SCMP_ERROR;
+ goto add_return;
+ }
+ sys_b = sys;
+ } else {
+ sys_a = sys;
+ sys_b = _abi_syscall_demux(db->arch, sys);
+ if (sys_b == __NR_SCMP_ERROR) {
+ rc = __NR_SCMP_ERROR;
+ goto add_return;
+ }
+ }
+
+ /* 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_dup = db_rule_dup(rule_a);
+ rule_b = rule_dup;
+ if (rule_b == NULL)
+ goto add_return;
+ rule_b->prev = rule_a;
+ rule_b->next = NULL;
+ rule_a->next = rule_b;
+ }
+
+ /* multiplexed socket syscalls */
+ if (rule_a != NULL) {
+ rule_a->syscall = db->arch->sys_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;
+
+ /* we should be protected by a transaction checkpoint */
+ if (rule_a != NULL) {
+ rc = db_rule_add(db, rule_a);
+ if (rc < 0)
+ goto add_return;
+ }
+ if (rule_b != NULL) {
+ rc = db_rule_add(db, rule_b);
+ if (rc < 0)
+ goto add_return;
+ }
+ } else if (_abi_syscall_ipc_test(db->arch, sys)) {
+ /* ipc syscalls */
+
+ /* strict check for the multiplexed socket syscalls */
+ for (iter = 0; iter < ARG_COUNT_MAX; iter++) {
+ if ((rule->args[iter].valid != 0) && (rule->strict)) {
+ rc = -EINVAL;
+ goto add_return;
+ }
+ }
+
+ /* determine both the muxed and direct syscall numbers */
+ if (sys > 0) {
+ sys_a = _abi_syscall_mux(db->arch, sys);
+ if (sys_a == __NR_SCMP_ERROR) {
+ rc = __NR_SCMP_ERROR;
+ goto add_return;
+ }
+ sys_b = sys;
+ } else {
+ sys_a = sys;
+ sys_b = _abi_syscall_demux(db->arch, sys);
+ if (sys_b == __NR_SCMP_ERROR) {
+ rc = __NR_SCMP_ERROR;
+ goto add_return;
+ }
+ }
+
+ /* 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_dup = db_rule_dup(rule_a);
+ rule_b = rule_dup;
+ if (rule_b == NULL)
+ goto add_return;
+ rule_b->prev = rule_a;
+ rule_b->next = NULL;
+ rule_a->next = rule_b;
+ }
+
+ /* multiplexed socket syscalls */
+ if (rule_a != NULL) {
+ rule_a->syscall = db->arch->sys_ipc;
+ 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) % 200;
+ rule_a->args[0].valid = 1;
+ }
+
+ /* direct wired socket syscalls */
+ if (rule_b != NULL)
+ rule_b->syscall = sys_b;
+
+ /* we should be protected by a transaction checkpoint */
+ if (rule_a != NULL) {
+ rc = db_rule_add(db, rule_a);
+ if (rc < 0)
+ goto add_return;
+ }
+ if (rule_b != NULL) {
+ rc = db_rule_add(db, rule_b);
+ if (rc < 0)
+ goto add_return;
+ }
+ } else if (sys >= 0) {
+ /* normal syscall processing */
+ rc = db_rule_add(db, rule);
+ if (rc < 0)
+ goto add_return;
+ } else if (rule->strict) {
+ rc = -EDOM;
+ goto add_return;
+ }
+
+add_return:
+ if (rule_dup != NULL)
+ free(rule_dup);
+ return rc;
+}