diff options
author | mseaborn@chromium.org <mseaborn@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-05-18 18:57:33 +0000 |
---|---|---|
committer | mseaborn@chromium.org <mseaborn@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-05-18 18:57:33 +0000 |
commit | a823a7b08a35f35067c8d4c98069d0f8d52d10ec (patch) | |
tree | 232364e42c093a40bcadef5a95a9521edadfd1df /sandbox | |
parent | 898bbd3c04dafd8148bb8af0b7b211883767da82 (diff) | |
download | chromium_src-a823a7b08a35f35067c8d4c98069d0f8d52d10ec.zip chromium_src-a823a7b08a35f35067c8d4c98069d0f8d52d10ec.tar.gz chromium_src-a823a7b08a35f35067c8d4c98069d0f8d52d10ec.tar.bz2 |
seccomp sandbox: Add tests for signal handling
Test that signal handlers can be run OK. This tests the support
for sigreturn() (that involves patching the VDSO) that was added
in r76 of the non-Chromium version of the sandbox.
Test that signal masks can be set and read. This tests the
sigprocmask() support that was added in r70.
Add a mechanism for checking that a test exits with an expected
non-zero exit status, such as SIGSEGV.
BUG=none
TEST=test_syscalls
Review URL: http://codereview.chromium.org/2087013
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@47541 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sandbox')
-rw-r--r-- | sandbox/linux/seccomp/tests/test_syscalls.cc | 148 |
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; } } |