summaryrefslogtreecommitdiffstats
path: root/sandbox/linux/seccomp/tests/test_syscalls.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sandbox/linux/seccomp/tests/test_syscalls.cc')
-rw-r--r--sandbox/linux/seccomp/tests/test_syscalls.cc148
1 files changed, 145 insertions, 3 deletions
diff --git a/sandbox/linux/seccomp/tests/test_syscalls.cc b/sandbox/linux/seccomp/tests/test_syscalls.cc
index f68374a..37764be 100644
--- a/sandbox/linux/seccomp/tests/test_syscalls.cc
+++ b/sandbox/linux/seccomp/tests/test_syscalls.cc
@@ -12,6 +12,20 @@
#include "sandbox_impl.h"
+int g_intended_status_fd = -1;
+
+// Declares the wait() status that the test subprocess intends to exit with.
+void intend_exit_status(int val) {
+ if (g_intended_status_fd != -1) {
+ int sent = write(g_intended_status_fd, &val, sizeof(val));
+ assert(sent == sizeof(val));
+ }
+ else {
+ printf("Intending to exit with status %i...\n", val);
+ }
+}
+
+
// This is basically a marker to grep for.
#define TEST(name) void name()
@@ -24,6 +38,18 @@ TEST(test_dup) {
assert(rc == 0);
}
+TEST(test_segfault) {
+ // Check that the sandbox's SIGSEGV handler does not stop the
+ // process from dying cleanly in the event of a real segfault.
+ intend_exit_status(SIGSEGV);
+ asm("hlt");
+}
+
+TEST(test_exit) {
+ intend_exit_status(123 << 8);
+ _exit(123);
+}
+
// This has an off-by-three error because it counts ".", "..", and the
// FD for the /proc/self/fd directory. This doesn't matter because it
// is only used to check for differences in the number of open FDs.
@@ -339,6 +365,96 @@ TEST(test_stat) {
assert(errno == EACCES);
}
+int g_value;
+
+void signal_handler(int sig) {
+ g_value = 300;
+ printf("In signal handler\n");
+}
+
+void sigaction_handler(int sig, siginfo_t *a, void *b) {
+ g_value = 300;
+ printf("In sigaction handler\n");
+}
+
+TEST(test_signal_handler) {
+ sighandler_t result = signal(SIGTRAP, signal_handler);
+ assert(result != SIG_ERR);
+
+ StartSeccompSandbox();
+
+ // signal() is not allowed inside the sandbox yet.
+ result = signal(SIGTRAP, signal_handler);
+ assert(result == SIG_ERR);
+ assert(errno == ENOSYS);
+
+ g_value = 200;
+ asm("int3");
+ assert(g_value == 300);
+}
+
+TEST(test_sigaction_handler) {
+ struct sigaction act;
+ act.sa_sigaction = sigaction_handler;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_SIGINFO;
+ int rc = sigaction(SIGTRAP, &act, NULL);
+ assert(rc == 0);
+
+ StartSeccompSandbox();
+
+ // sigaction() is not allowed inside the sandbox yet.
+ rc = sigaction(SIGTRAP, &act, NULL);
+ assert(rc == -1);
+ assert(errno == ENOSYS);
+
+ g_value = 200;
+ asm("int3");
+ assert(g_value == 300);
+}
+
+TEST(test_blocked_signal) {
+ sighandler_t result = signal(SIGTRAP, signal_handler);
+ assert(result != SIG_ERR);
+ StartSeccompSandbox();
+
+ // Initially the signal should not be blocked.
+ sigset_t sigs;
+ sigfillset(&sigs);
+ int rc = sigprocmask(0, NULL, &sigs);
+ assert(rc == 0);
+ assert(!sigismember(&sigs, SIGTRAP));
+
+ sigemptyset(&sigs);
+ sigaddset(&sigs, SIGTRAP);
+ rc = sigprocmask(SIG_BLOCK, &sigs, NULL);
+ assert(rc == 0);
+
+ // Check that we can read back the blocked status.
+ sigemptyset(&sigs);
+ rc = sigprocmask(0, NULL, &sigs);
+ assert(rc == 0);
+ assert(sigismember(&sigs, SIGTRAP));
+
+ // Check that the signal handler really is blocked.
+ intend_exit_status(SIGTRAP);
+ asm("int3");
+}
+
+TEST(test_sigaltstack) {
+ // The sandbox does not support sigaltstack() yet. Just test that
+ // it returns an error.
+ StartSeccompSandbox();
+ stack_t st;
+ st.ss_size = 0x4000;
+ st.ss_sp = malloc(st.ss_size);
+ assert(st.ss_sp != NULL);
+ st.ss_flags = 0;
+ int rc = sigaltstack(&st, NULL);
+ assert(rc == -1);
+ assert(errno == ENOSYS);
+}
+
struct testcase {
const char *test_name;
@@ -352,15 +468,39 @@ struct testcase all_tests[] = {
int run_test_forked(struct testcase *test) {
printf("** %s\n", test->test_name);
+ int pipe_fds[2];
+ int rc = pipe(pipe_fds);
+ assert(rc == 0);
int pid = fork();
if (pid == 0) {
+ rc = close(pipe_fds[0]);
+ assert(rc == 0);
+ g_intended_status_fd = pipe_fds[1];
+
test->test_func();
+ intend_exit_status(0);
_exit(0);
}
+ rc = close(pipe_fds[1]);
+ assert(rc == 0);
+
+ int intended_status;
+ int got = read(pipe_fds[0], &intended_status, sizeof(intended_status));
+ bool got_intended_status = got == sizeof(intended_status);
+ if (!got_intended_status) {
+ printf("Test runner: Did not receive intended status\n");
+ }
+
int status;
- waitpid(pid, &status, 0);
- if (status != 0) {
- printf("Test failed with exit status %i\n", status);
+ int pid2 = waitpid(pid, &status, 0);
+ assert(pid2 == pid);
+ if (!got_intended_status) {
+ printf("Test returned exit status %i\n", status);
+ return 1;
+ }
+ else if (status != intended_status) {
+ printf("Test failed with exit status %i, expected %i\n",
+ status, intended_status);
return 1;
}
else {
@@ -372,7 +512,9 @@ int run_test_by_name(const char *name) {
struct testcase *test;
for (test = all_tests; test->test_name != NULL; test++) {
if (strcmp(name, test->test_name) == 0) {
+ printf("Running test %s...\n", name);
test->test_func();
+ printf("OK\n");
return 0;
}
}