aboutgitcodelistschat:MatrixIRC
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/unit/Makefile8
-rw-r--r--tests/unit/test_operations.c177
-rw-r--r--tests/unit/testutil.h45
-rw-r--r--tests/unit/util.c184
4 files changed, 238 insertions, 176 deletions
diff --git a/tests/unit/Makefile b/tests/unit/Makefile
index aad8549..1c3a413 100644
--- a/tests/unit/Makefile
+++ b/tests/unit/Makefile
@@ -13,9 +13,9 @@ HEADERS_FILTER := $(COOKER_DIR)/filter.h $(DBG_DIR)/disasm.h $(COMMON_DIR)/commo
HEADERS_OP_CALL := $(COMMON_DIR)/gluten.h $(OP_DIR)/operations.h
SRCS_OP_CALL := $(OP_DIR)/operations.c
-HEADERS_OP_CALL := $(COMMON_DIR)/gluten.h $(OP_DIR)/operations.h \
- $(COMMON_DIR)/common.h
-SRCS_OP := $(COMMON_DIR)/common.c $(OP_DIR)/operations.c
+HEADERS_OP := $(COMMON_DIR)/gluten.h $(OP_DIR)/operations.h \
+ $(COMMON_DIR)/common.h testutil.h
+SRCS_OP := $(COMMON_DIR)/common.c $(OP_DIR)/operations.c util.c
TARGET := $(shell $(CC) -dumpmachine)
TARGET_ARCH := $(shell echo $(TARGET) | cut -f1 -d- | tr [A-Z] [a-z])
@@ -43,7 +43,7 @@ test-op-call: test_op_call.c $(SRCS_OP_CALL) $(HEADERS_OP_CALL)
test_op_call.c
./test-op-call
-test-operations: test_operations.c $(SRCS_OP) $(HEADERS_OP_CALL)
+test-operations: test_operations.c $(SRCS_OP) $(HEADERS_OP)
$(CC) $(CFLAGS) -o test-operations $(SRCS_OP) \
test_operations.c
./test-operations
diff --git a/tests/unit/test_operations.c b/tests/unit/test_operations.c
index c60fa4f..bb098b8 100644
--- a/tests/unit/test_operations.c
+++ b/tests/unit/test_operations.c
@@ -28,187 +28,17 @@
#include "gluten.h"
#include "operations.h"
#include "common.h"
-#include "util.h"
+#include "testutil.h"
#define MAX_TEST_PATH 250
-struct args_target {
- long ret;
- int err;
- bool check_fd;
- bool open_path;
- int fd;
- int nr;
- void *args[6];
-};
-
-struct seccomp_notif req;
-int notifyfd;
-struct args_target *at;
-int pipefd[2];
-pid_t pid;
-char path[] = "/tmp/test-seitan";
-
-uint16_t tmp_data[TMP_DATA_SIZE];
-
-static int install_notification_filter(int nr)
-{
- int fd;
- /* filter a single syscall for the tests */
- struct sock_filter filter[] = {
- BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
- (offsetof(struct seccomp_data, arch))),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SEITAN_AUDIT_ARCH, 0, 3),
- BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
- (offsetof(struct seccomp_data, nr))),
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, nr, 0, 1),
- BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_USER_NOTIF),
- BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
- };
- return install_filter(
- &filter, (unsigned short)(sizeof(filter) / sizeof(filter[0])));
-}
-
-static int create_test_fd()
-{
- return open("/tmp", O_RDWR | O_TMPFILE);
-}
-
-static int target()
-{
- int buf = 0;
- if (install_notification_filter(at->nr) < 0) {
- return -1;
- }
-
- at->ret = syscall(at->nr, at->args[0], at->args[1], at->args[2],
- at->args[3], at->args[4], at->args[5]);
- at->err = errno;
- if (at->open_path) {
- if ((at->fd = open(path, O_CREAT | O_RDONLY)) < 0) {
- perror("open");
- return -1;
- }
- }
- if (at->check_fd)
- read(pipefd[0], &buf, 1);
-
- close(pipefd[0]);
-
- write(pipefd[1], &buf, 1);
- close(pipefd[1]);
- exit(0);
-}
-
-static pid_t do_clone(int (*fn)(void *), void *arg)
-{
- char stack[STACK_SIZE];
- pid_t child;
- int flags = SIGCHLD;
-
- child = clone(fn, stack + sizeof(stack), flags, arg);
- if (child == -1) {
- perror("clone");
- return -1;
- }
- return child;
-}
-
-int get_fd_notifier(pid_t pid)
-{
- char path[PATH_MAX + 1];
- int pidfd, notifier;
- int fd = -1;
-
- snprintf(path, sizeof(path), "/proc/%d/fd", pid);
- while (fd < 0) {
- sleep(2);
- fd = find_fd_seccomp_notifier(path);
- }
- ck_assert_int_ge(fd, 0);
- pidfd = syscall(SYS_pidfd_open, pid, 0);
- ck_assert_msg(pidfd >= 0, strerror(errno));
- sleep(1);
- notifier = syscall(SYS_pidfd_getfd, pidfd, fd, 0);
- ck_assert_msg(notifier >= 0, strerror(errno));
- return notifier;
-}
-
-static void check_target_result(long ret, int err, bool ignore_ret)
-{
- int buf;
-
- read(pipefd[0], &buf, 1);
- if (!ignore_ret)
- ck_assert_msg(at->ret == ret,
- "expect return value %ld to be equal to %ld",
- at->ret, ret);
- ck_assert_int_eq(at->err, err);
- ck_assert_int_eq(close(pipefd[0]), 0);
-}
-
-void target_exit()
-{
- int status;
-
- waitpid(-1, &status, WUNTRACED | WNOHANG);
- if (WEXITSTATUS(status) != 0) {
- fprintf(stderr, "target process exited with an error\n");
- exit(-1);
- }
-}
-
-static bool has_fd(int pid, int fd)
-{
- char path[PATH_MAX + 1];
-
- snprintf(path, sizeof(path), "/proc/%d/fd/%d", pid, fd);
- return access(path, F_OK) == 0;
-}
-
-static void check_target_fd(int pid, int fd)
-{
- int buf = 0;
-
- ck_assert(has_fd(pid, fd));
- write(pipefd[1], &buf, 1);
- close(pipefd[1]);
-}
-
-void setup()
-{
- int ret;
-
- signal(SIGCHLD, target_exit);
- ck_assert_int_ne(pipe(pipefd), -1);
- pid = do_clone(target, NULL);
- ck_assert_int_ge(pid, 0);
-
- /* Use write pipe to sync the target for checking the existance of the fd */
- if (!at->check_fd)
- ck_assert_int_ne(close(pipefd[1]), -1);
-
- notifyfd = get_fd_notifier(pid);
-
- memset(&req, 0, sizeof(req));
- ret = ioctl(notifyfd, SECCOMP_IOCTL_NOTIF_RECV, &req);
- ck_assert_msg(ret == 0, strerror(errno));
- ck_assert_msg((req.data).nr == at->nr, "filter syscall nr: %d",
- (req.data).nr);
-}
-
-void teardown()
-{
- if (at != NULL)
- munmap(at, sizeof(struct args_target));
-}
-
void setup_without_fd()
{
at = mmap(NULL, sizeof(struct args_target), PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
at->check_fd = false;
at->nr = __NR_getpid;
+ at->install_filter = install_notification_filter;
setup();
}
void setup_fd()
@@ -217,6 +47,7 @@ void setup_fd()
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
at->check_fd = true;
at->nr = __NR_getpid;
+ at->install_filter = install_notification_filter;
setup();
}
@@ -226,6 +57,7 @@ void setup_path()
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
at->open_path = true;
at->nr = __NR_getpid;
+ at->install_filter = install_notification_filter;
setup();
}
@@ -248,6 +80,7 @@ void setup_target_connect()
at->args[0] = (void *)(long)fd;
at->args[1] = (void *)&addr;
at->args[2] = (void *)(long)len;
+ at->install_filter = install_notification_filter;
setup();
}
diff --git a/tests/unit/testutil.h b/tests/unit/testutil.h
new file mode 100644
index 0000000..896d690
--- /dev/null
+++ b/tests/unit/testutil.h
@@ -0,0 +1,45 @@
+#ifndef TESTUTIL_H
+#define TESTUTIL_H
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#include <check.h>
+
+#define STACK_SIZE (1024 * 1024 / 8)
+
+struct args_target {
+ long ret;
+ int err;
+ bool check_fd;
+ bool open_path;
+ int fd;
+ int nr;
+ void *args[6];
+ int (*install_filter)(struct args_target *at);
+};
+
+extern struct seccomp_notif req;
+extern int notifyfd;
+extern struct args_target *at;
+extern int pipefd[2];
+extern pid_t pid;
+extern char path[100];
+
+extern uint16_t tmp_data[TMP_DATA_SIZE];
+
+int target();
+pid_t do_clone(int (*fn)(void *), void *arg);
+int create_test_fd();
+int get_fd_notifier(pid_t pid);
+void target_exit();
+void check_target_fd(int pid, int fd);
+bool has_fd(int pid, int fd);
+void check_target_result(long ret, int err, bool ignore_ret);
+void setup();
+void teardown();
+int install_notification_filter(struct args_target *at);
+
+#endif /* TESTUTIL_H */
diff --git a/tests/unit/util.c b/tests/unit/util.c
new file mode 100644
index 0000000..d4109b0
--- /dev/null
+++ b/tests/unit/util.c
@@ -0,0 +1,184 @@
+#define _GNU_SOURCE
+
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <sched.h>
+#include <unistd.h>
+#include <signal.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/prctl.h>
+#include <sys/syscall.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <linux/audit.h>
+#include <linux/filter.h>
+#include <linux/seccomp.h>
+#include <sys/mman.h>
+#include <sys/un.h>
+#include <sys/socket.h>
+
+#include "testutil.h"
+#include "common.h"
+#include "filter.h"
+
+struct seccomp_notif req;
+int notifyfd;
+struct args_target *at;
+int pipefd[2];
+pid_t pid;
+char path[] = "/tmp/test-seitan";
+uint16_t tmp_data[TMP_DATA_SIZE];
+
+int install_notification_filter(struct args_target *at)
+{
+ /* filter a single syscall for the tests */
+ struct sock_filter filter[] = {
+ BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
+ (offsetof(struct seccomp_data, arch))),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, SEITAN_AUDIT_ARCH, 0, 3),
+ BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
+ (offsetof(struct seccomp_data, nr))),
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, at->nr, 0, 1),
+ BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_USER_NOTIF),
+ BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
+ };
+ return install_filter(
+ filter, (unsigned short)(sizeof(filter) / sizeof(filter[0])));
+}
+
+int target()
+{
+ int buf = 0;
+ if (at->install_filter(at) < 0) {
+ return -1;
+ }
+
+ at->ret = syscall(at->nr, at->args[0], at->args[1], at->args[2],
+ at->args[3], at->args[4], at->args[5]);
+ at->err = errno;
+ if (at->open_path) {
+ if ((at->fd = open(path, O_CREAT | O_RDONLY)) < 0) {
+ perror("open");
+ return -1;
+ }
+ }
+ if (at->check_fd)
+ read(pipefd[0], &buf, 1);
+
+ close(pipefd[0]);
+
+ write(pipefd[1], &buf, 1);
+ close(pipefd[1]);
+ exit(0);
+}
+
+pid_t do_clone(int (*fn)(void *), void *arg)
+{
+ char stack[STACK_SIZE];
+ pid_t child;
+ int flags = SIGCHLD;
+
+ child = clone(fn, stack + sizeof(stack), flags, arg);
+ if (child == -1) {
+ perror("clone");
+ return -1;
+ }
+ return child;
+}
+
+int create_test_fd()
+{
+ return open("/tmp", O_RDWR | O_TMPFILE);
+}
+
+int get_fd_notifier(pid_t pid)
+{
+ char path[PATH_MAX + 1];
+ int pidfd, notifier;
+ int fd = -1;
+
+ snprintf(path, sizeof(path), "/proc/%d/fd", pid);
+ while (fd < 0) {
+ sleep(2);
+ fd = find_fd_seccomp_notifier(path);
+ }
+ ck_assert_int_ge(fd, 0);
+ pidfd = syscall(SYS_pidfd_open, pid, 0);
+ ck_assert_msg(pidfd >= 0, strerror(errno));
+ sleep(1);
+ notifier = syscall(SYS_pidfd_getfd, pidfd, fd, 0);
+ ck_assert_msg(notifier >= 0, strerror(errno));
+ return notifier;
+}
+
+void target_exit()
+{
+ int status;
+
+ waitpid(-1, &status, WUNTRACED | WNOHANG);
+ if (WEXITSTATUS(status) != 0) {
+ fprintf(stderr, "target process exited with an error\n");
+ exit(-1);
+ }
+}
+
+void check_target_fd(int pid, int fd)
+{
+ int buf = 0;
+
+ ck_assert(has_fd(pid, fd));
+ write(pipefd[1], &buf, 1);
+ close(pipefd[1]);
+}
+
+bool has_fd(int pid, int fd)
+{
+ char path[PATH_MAX + 1];
+
+ snprintf(path, sizeof(path), "/proc/%d/fd/%d", pid, fd);
+ return access(path, F_OK) == 0;
+}
+
+void check_target_result(long ret, int err, bool ignore_ret)
+{
+ int buf;
+
+ read(pipefd[0], &buf, 1);
+ if (!ignore_ret)
+ ck_assert_msg(at->ret == ret,
+ "expect return value %ld to be equal to %ld",
+ at->ret, ret);
+ ck_assert_int_eq(at->err, err);
+ ck_assert_int_eq(close(pipefd[0]), 0);
+}
+
+void setup()
+{
+ int ret;
+
+ signal(SIGCHLD, target_exit);
+ ck_assert_int_ne(pipe(pipefd), -1);
+ pid = do_clone(target, NULL);
+ ck_assert_int_ge(pid, 0);
+
+ /* Use write pipe to sync the target for checking the existance of the fd */
+ if (!at->check_fd)
+ ck_assert_int_ne(close(pipefd[1]), -1);
+
+ notifyfd = get_fd_notifier(pid);
+
+ memset(&req, 0, sizeof(req));
+ ret = ioctl(notifyfd, SECCOMP_IOCTL_NOTIF_RECV, &req);
+ ck_assert_msg(ret == 0, strerror(errno));
+ ck_assert_msg((req.data).nr == at->nr, "filter syscall nr: %d",
+ (req.data).nr);
+}
+
+void teardown()
+{
+ if (at != NULL)
+ munmap(at, sizeof(struct args_target));
+}