diff options
author | markus@chromium.org <markus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-22 23:20:17 +0000 |
---|---|---|
committer | markus@chromium.org <markus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-04-22 23:20:17 +0000 |
commit | a1170ed12a730f79d4224779b90e35923c7bb729 (patch) | |
tree | 5991ab0bc1bf159e16fde015952704c04a9b8277 /sandbox | |
parent | 18cec742ac18f7c99a357e57a659eed68397f8c6 (diff) | |
download | chromium_src-a1170ed12a730f79d4224779b90e35923c7bb729.zip chromium_src-a1170ed12a730f79d4224779b90e35923c7bb729.tar.gz chromium_src-a1170ed12a730f79d4224779b90e35923c7bb729.tar.bz2 |
Merged Mark Seaborn's changes:
Add some automated tests for seccomp-sandbox
This covers some of the syscalls that are proxied by the trusted process.
This adds a basic test runner framework.
Fix error return code for open() and other syscalls on x86-64
On error, the open() syscall was returning errno & 0xffffffff in %rax
on x86-64 instead of -errno. This stops glibc from regarding this as
an error, and so its syscall wrapper returns -errno instead of -1 and
does not set errno.
I have fixed up the other syscalls to use long (64-bit) instead of int
(32-bit) as well. Not all of them were affected by the problem: it
depends on gcc's code generation. Sometimes casting to int truncates
a value, sometimes it doesn't. It seems better to be consistent
though.
Adds a test for open() and some other syscalls.
TODO: Need to figure out how to run the tests automatically
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/1729003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@45379 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sandbox')
-rw-r--r-- | sandbox/linux/seccomp/Makefile | 56 | ||||
-rw-r--r-- | sandbox/linux/seccomp/access.cc | 4 | ||||
-rw-r--r-- | sandbox/linux/seccomp/clone.cc | 6 | ||||
-rw-r--r-- | sandbox/linux/seccomp/exit.cc | 2 | ||||
-rw-r--r-- | sandbox/linux/seccomp/getpid.cc | 2 | ||||
-rw-r--r-- | sandbox/linux/seccomp/gettid.cc | 2 | ||||
-rw-r--r-- | sandbox/linux/seccomp/ioctl.cc | 4 | ||||
-rw-r--r-- | sandbox/linux/seccomp/ipc.cc | 16 | ||||
-rw-r--r-- | sandbox/linux/seccomp/madvise.cc | 4 | ||||
-rw-r--r-- | sandbox/linux/seccomp/mprotect.cc | 4 | ||||
-rw-r--r-- | sandbox/linux/seccomp/munmap.cc | 4 | ||||
-rw-r--r-- | sandbox/linux/seccomp/open.cc | 4 | ||||
-rw-r--r-- | sandbox/linux/seccomp/sandbox_impl.h | 50 | ||||
-rw-r--r-- | sandbox/linux/seccomp/sigprocmask.cc | 10 | ||||
-rw-r--r-- | sandbox/linux/seccomp/socketcall.cc | 24 | ||||
-rw-r--r-- | sandbox/linux/seccomp/stat.cc | 16 | ||||
-rw-r--r-- | sandbox/linux/seccomp/tests/list_tests.py | 22 | ||||
-rw-r--r-- | sandbox/linux/seccomp/tests/test_syscalls.cc | 273 |
18 files changed, 427 insertions, 76 deletions
diff --git a/sandbox/linux/seccomp/Makefile b/sandbox/linux/seccomp/Makefile new file mode 100644 index 0000000..5fde2d2 --- /dev/null +++ b/sandbox/linux/seccomp/Makefile @@ -0,0 +1,56 @@ +# Copyright (c) 2010 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# This Makefile temporarily has been checked into the source tree so that +# we can run the tests. It will be replaced with a proper gyp file. + +CFLAGS = -g -O0 -Wall -Werror -Wextra -Wno-missing-field-initializers \ + -Wno-unused-parameter -I. +LDFLAGS = -g +CPPFLAGS = +MODS := allocator library debug maps x86_decode securemem sandbox \ + syscall syscall_table trusted_thread trusted_process \ + access exit clone getpid gettid ioctl ipc madvise mmap mprotect \ + munmap open sigprocmask socketcall stat +OBJS64 := $(shell echo ${MODS} | xargs -n 1 | sed -e 's/$$/.o64/') +OBJS32 := $(shell echo ${MODS} | xargs -n 1 | sed -e 's/$$/.o32/') +HEADERS:= $(shell for i in ${MODS}; do [ -r "$$i" ] && echo "$$i"; done) + +.SUFFIXES: .o64 .o32 + +all: test + +clean: + -rm -f *.o *.o32 *.o64 tests/*.o32 tests/*.o.64 + -rm -f core core.* vgcore vgcore.* strace.log* + +test: run_tests_64 run_tests_32 + ./run_tests_64 + ./run_tests_32 + +# TODO: Track header file dependencies properly +tests/test_syscalls.o64 tests/test_syscalls.o32: tests/test-list.h + +tests/test-list.h: tests/list_tests.py tests/test_syscalls.cc + python tests/list_tests.py tests/test_syscalls.cc > $@ + +run_tests_64: $(OBJS64) tests/test_syscalls.o64 tests/test-list.h + g++ -m64 tests/test_syscalls.o64 $(OBJS64) -lpthread -lutil -o $@ +run_tests_32: $(OBJS32) tests/test_syscalls.o32 tests/test-list.h + g++ -m32 tests/test_syscalls.o32 $(OBJS32) -lpthread -lutil -o $@ + +.cc.o: ${HEADERS} + ${CXX} ${CFLAGS} ${CPPFLAGS} -c -o $@ $< + +.cc.o64: ${HEADERS} + ${CXX} ${CFLAGS} ${CPPFLAGS} -fPIC -c -o $@ $< + +.c.o64: ${HEADERS} + ${CC} ${CFLAGS} ${CPPFLAGS} --std=gnu99 -fPIC -c -o $@ $< + +.cc.o32: ${HEADERS} + ${CXX} ${CFLAGS} ${CPPFLAGS} -m32 -fPIC -c -o $@ $< + +.c.o32: ${HEADERS} + ${CC} ${CFLAGS} ${CPPFLAGS} -m32 --std=gnu99 -fPIC -c -o $@ $< diff --git a/sandbox/linux/seccomp/access.cc b/sandbox/linux/seccomp/access.cc index 50e94bb..a318e92 100644 --- a/sandbox/linux/seccomp/access.cc +++ b/sandbox/linux/seccomp/access.cc @@ -7,7 +7,7 @@ namespace playground { -int Sandbox::sandbox_access(const char *pathname, int mode) { +long Sandbox::sandbox_access(const char *pathname, int mode) { long long tm; Debug::syscall(&tm, __NR_access, "Executing handler"); size_t len = strlen(pathname); @@ -32,7 +32,7 @@ int Sandbox::sandbox_access(const char *pathname, int mode) { die("Failed to forward access() request [sandbox]"); } Debug::elapsed(tm, __NR_access); - return static_cast<int>(rc); + return rc; } bool Sandbox::process_access(int parentMapsFd, int sandboxFd, int threadFdPub, diff --git a/sandbox/linux/seccomp/clone.cc b/sandbox/linux/seccomp/clone.cc index 0bf91c1..957ae2c 100644 --- a/sandbox/linux/seccomp/clone.cc +++ b/sandbox/linux/seccomp/clone.cc @@ -7,8 +7,8 @@ namespace playground { -int Sandbox::sandbox_clone(int flags, char* stack, int* pid, int* ctid, - void* tls, void *wrapper_sp) { +long Sandbox::sandbox_clone(int flags, char* stack, int* pid, int* ctid, + void* tls, void *wrapper_sp) { long long tm; Debug::syscall(&tm, __NR_clone, "Executing handler"); struct { @@ -97,7 +97,7 @@ int Sandbox::sandbox_clone(int flags, char* stack, int* pid, int* ctid, } } Debug::elapsed(tm, __NR_clone); - return static_cast<int>(rc); + return rc; } bool Sandbox::process_clone(int parentMapsFd, int sandboxFd, int threadFdPub, diff --git a/sandbox/linux/seccomp/exit.cc b/sandbox/linux/seccomp/exit.cc index 5da9f97..f4db643 100644 --- a/sandbox/linux/seccomp/exit.cc +++ b/sandbox/linux/seccomp/exit.cc @@ -7,7 +7,7 @@ namespace playground { -int Sandbox::sandbox_exit(int status) { +long Sandbox::sandbox_exit(int status) { long long tm; Debug::syscall(&tm, __NR_exit, "Executing handler"); struct { diff --git a/sandbox/linux/seccomp/getpid.cc b/sandbox/linux/seccomp/getpid.cc index 5b4239b..be5449b 100644 --- a/sandbox/linux/seccomp/getpid.cc +++ b/sandbox/linux/seccomp/getpid.cc @@ -7,7 +7,7 @@ namespace playground { -int Sandbox::sandbox_getpid() { +long Sandbox::sandbox_getpid() { long long tm; Debug::syscall(&tm, __NR_getpid, "Executing handler"); Debug::elapsed(tm, __NR_getpid); diff --git a/sandbox/linux/seccomp/gettid.cc b/sandbox/linux/seccomp/gettid.cc index 1423383..699774a 100644 --- a/sandbox/linux/seccomp/gettid.cc +++ b/sandbox/linux/seccomp/gettid.cc @@ -7,7 +7,7 @@ namespace playground { -int Sandbox::sandbox_gettid() { +long Sandbox::sandbox_gettid() { long long tm; Debug::syscall(&tm, __NR_gettid, "Executing handler"); pid_t t = tid(); diff --git a/sandbox/linux/seccomp/ioctl.cc b/sandbox/linux/seccomp/ioctl.cc index 75330e1..07f1aa3 100644 --- a/sandbox/linux/seccomp/ioctl.cc +++ b/sandbox/linux/seccomp/ioctl.cc @@ -7,7 +7,7 @@ namespace playground { -int Sandbox::sandbox_ioctl(int d, int req, void *arg) { +long Sandbox::sandbox_ioctl(int d, int req, void *arg) { long long tm; Debug::syscall(&tm, __NR_ioctl, "Executing handler"); struct { @@ -29,7 +29,7 @@ int Sandbox::sandbox_ioctl(int d, int req, void *arg) { die("Failed to forward ioctl() request [sandbox]"); } Debug::elapsed(tm, __NR_ioctl); - return static_cast<int>(rc); + return rc; } bool Sandbox::process_ioctl(int parentMapsFd, int sandboxFd, int threadFdPub, diff --git a/sandbox/linux/seccomp/ipc.cc b/sandbox/linux/seccomp/ipc.cc index 3cfcbf0..67a4e34 100644 --- a/sandbox/linux/seccomp/ipc.cc +++ b/sandbox/linux/seccomp/ipc.cc @@ -44,7 +44,7 @@ void* Sandbox::sandbox_shmat(int shmid, const void* shmaddr, int shmflg) { return reinterpret_cast<void *>(rc); } -int Sandbox::sandbox_shmctl(int shmid, int cmd, void* buf) { +long Sandbox::sandbox_shmctl(int shmid, int cmd, void* buf) { long long tm; Debug::syscall(&tm, __NR_shmctl, "Executing handler"); @@ -67,10 +67,10 @@ int Sandbox::sandbox_shmctl(int shmid, int cmd, void* buf) { die("Failed to forward shmctl() request [sandbox]"); } Debug::elapsed(tm, __NR_shmctl); - return static_cast<int>(rc); + return rc; } -int Sandbox::sandbox_shmdt(const void* shmaddr) { +long Sandbox::sandbox_shmdt(const void* shmaddr) { long long tm; Debug::syscall(&tm, __NR_shmdt, "Executing handler"); @@ -91,10 +91,10 @@ int Sandbox::sandbox_shmdt(const void* shmaddr) { die("Failed to forward shmdt() request [sandbox]"); } Debug::elapsed(tm, __NR_shmdt); - return static_cast<int>(rc); + return rc; } -int Sandbox::sandbox_shmget(int key, size_t size, int shmflg) { +long Sandbox::sandbox_shmget(int key, size_t size, int shmflg) { long long tm; Debug::syscall(&tm, __NR_shmget, "Executing handler"); @@ -117,7 +117,7 @@ int Sandbox::sandbox_shmget(int key, size_t size, int shmflg) { die("Failed to forward shmget() request [sandbox]"); } Debug::elapsed(tm, __NR_shmget); - return static_cast<int>(rc); + return rc; } bool Sandbox::process_shmat(int parentMapsFd, int sandboxFd, int threadFdPub, @@ -246,7 +246,7 @@ bool Sandbox::process_shmget(int parentMapsFd, int sandboxFd, int threadFdPub, #define SHMCTL 24 #endif -int Sandbox::sandbox_ipc(unsigned call, int first, int second, int third, +long Sandbox::sandbox_ipc(unsigned call, int first, int second, int third, void* ptr, long fifth) { long long tm; Debug::syscall(&tm, __NR_ipc, "Executing handler", call); @@ -272,7 +272,7 @@ int Sandbox::sandbox_ipc(unsigned call, int first, int second, int third, die("Failed to forward ipc() request [sandbox]"); } Debug::elapsed(tm, __NR_ipc, call); - return static_cast<int>(rc); + return rc; } bool Sandbox::process_ipc(int parentMapsFd, int sandboxFd, int threadFdPub, diff --git a/sandbox/linux/seccomp/madvise.cc b/sandbox/linux/seccomp/madvise.cc index 0df3be8..70c594f 100644 --- a/sandbox/linux/seccomp/madvise.cc +++ b/sandbox/linux/seccomp/madvise.cc @@ -7,7 +7,7 @@ namespace playground { -int Sandbox::sandbox_madvise(void* start, size_t length, int advice) { +long Sandbox::sandbox_madvise(void* start, size_t length, int advice) { long long tm; Debug::syscall(&tm, __NR_madvise, "Executing handler"); struct { @@ -29,7 +29,7 @@ int Sandbox::sandbox_madvise(void* start, size_t length, int advice) { die("Failed to forward madvise() request [sandbox]"); } Debug::elapsed(tm, __NR_madvise); - return static_cast<int>(rc); + return rc; } bool Sandbox::process_madvise(int parentMapsFd, int sandboxFd, int threadFdPub, diff --git a/sandbox/linux/seccomp/mprotect.cc b/sandbox/linux/seccomp/mprotect.cc index d079104..548199d 100644 --- a/sandbox/linux/seccomp/mprotect.cc +++ b/sandbox/linux/seccomp/mprotect.cc @@ -7,7 +7,7 @@ namespace playground { -int Sandbox::sandbox_mprotect(const void *addr, size_t len, int prot) { +long Sandbox::sandbox_mprotect(const void *addr, size_t len, int prot) { long long tm; Debug::syscall(&tm, __NR_mprotect, "Executing handler"); struct { @@ -29,7 +29,7 @@ int Sandbox::sandbox_mprotect(const void *addr, size_t len, int prot) { die("Failed to forward mprotect() request [sandbox]"); } Debug::elapsed(tm, __NR_mprotect); - return static_cast<int>(rc); + return rc; } bool Sandbox::process_mprotect(int parentMapsFd, int sandboxFd, diff --git a/sandbox/linux/seccomp/munmap.cc b/sandbox/linux/seccomp/munmap.cc index 0c1a41c..dde7c7a 100644 --- a/sandbox/linux/seccomp/munmap.cc +++ b/sandbox/linux/seccomp/munmap.cc @@ -7,7 +7,7 @@ namespace playground { -int Sandbox::sandbox_munmap(void* start, size_t length) { +long Sandbox::sandbox_munmap(void* start, size_t length) { long long tm; Debug::syscall(&tm, __NR_munmap, "Executing handler"); struct { @@ -28,7 +28,7 @@ int Sandbox::sandbox_munmap(void* start, size_t length) { die("Failed to forward munmap() request [sandbox]"); } Debug::elapsed(tm, __NR_munmap); - return static_cast<int>(rc); + return rc; } bool Sandbox::process_munmap(int parentMapsFd, int sandboxFd, int threadFdPub, diff --git a/sandbox/linux/seccomp/open.cc b/sandbox/linux/seccomp/open.cc index 83db243..73263d1 100644 --- a/sandbox/linux/seccomp/open.cc +++ b/sandbox/linux/seccomp/open.cc @@ -7,7 +7,7 @@ namespace playground { -int Sandbox::sandbox_open(const char *pathname, int flags, mode_t mode) { +long Sandbox::sandbox_open(const char *pathname, int flags, mode_t mode) { long long tm; Debug::syscall(&tm, __NR_open, "Executing handler"); size_t len = strlen(pathname); @@ -33,7 +33,7 @@ int Sandbox::sandbox_open(const char *pathname, int flags, mode_t mode) { die("Failed to forward open() request [sandbox]"); } Debug::elapsed(tm, __NR_open); - return static_cast<int>(rc); + return rc; } bool Sandbox::process_open(int parentMapsFd, int sandboxFd, int threadFdPub, diff --git a/sandbox/linux/seccomp/sandbox_impl.h b/sandbox/linux/seccomp/sandbox_impl.h index 36f01c8..38a1803 100644 --- a/sandbox/linux/seccomp/sandbox_impl.h +++ b/sandbox/linux/seccomp/sandbox_impl.h @@ -84,8 +84,8 @@ class Sandbox { // Clone() is special as it has a wrapper in syscall_table.c. The wrapper // adds one extra argument (the pointer to the saved registers) and then // calls playground$sandbox__clone(). - static int sandbox_clone(int flags, char* stack, int* pid, int* ctid, - void* tls, void* wrapper_sp) + static long sandbox_clone(int flags, char* stack, int* pid, int* ctid, + void* tls, void* wrapper_sp) asm("playground$sandbox__clone") #if defined(__x86_64__) __attribute__((visibility("internal"))) @@ -96,42 +96,42 @@ class Sandbox { #define bool int #define SecureMemArgs void // This is the wrapper entry point that is found in the syscall_table. - int sandbox_clone(int flags, char* stack, int* pid, int* ctid, void* tls) + long sandbox_clone(int flags, char* stack, int* pid, int* ctid, void* tls) asm("playground$sandbox_clone"); #endif // Entry points for sandboxed code that is attempting to make system calls - STATIC int sandbox_access(const char*, int) + STATIC long sandbox_access(const char*, int) asm("playground$sandbox_access"); - STATIC int sandbox_exit(int status) asm("playground$sandbox_exit"); - STATIC int sandbox_getpid() asm("playground$sandbox_getpid"); + STATIC long sandbox_exit(int status) asm("playground$sandbox_exit"); + STATIC long sandbox_getpid() asm("playground$sandbox_getpid"); #if defined(__NR_getsockopt) - STATIC int sandbox_getsockopt(int, int, int, void*, socklen_t*) + STATIC long sandbox_getsockopt(int, int, int, void*, socklen_t*) asm("playground$sandbox_getsockopt"); #endif - STATIC int sandbox_gettid() asm("playground$sandbox_gettid"); - STATIC int sandbox_ioctl(int d, int req, void* arg) + STATIC long sandbox_gettid() asm("playground$sandbox_gettid"); + STATIC long sandbox_ioctl(int d, int req, void* arg) asm("playground$sandbox_ioctl"); #if defined(__NR_ipc) - STATIC int sandbox_ipc(unsigned, int, int, int, void*, long) + STATIC long sandbox_ipc(unsigned, int, int, int, void*, long) asm("playground$sandbox_ipc"); #endif - STATIC int sandbox_lstat(const char* path, void* buf) + STATIC long sandbox_lstat(const char* path, void* buf) asm("playground$sandbox_lstat"); #if defined(__NR_lstat64) - STATIC int sandbox_lstat64(const char *path, void* b) + STATIC long sandbox_lstat64(const char *path, void* b) asm("playground$sandbox_lstat64"); #endif - STATIC int sandbox_madvise(void*, size_t, int) + STATIC long sandbox_madvise(void*, size_t, int) asm("playground$sandbox_madvise"); STATIC void *sandbox_mmap(void* start, size_t length, int prot, int flags, int fd, off_t offset) asm("playground$sandbox_mmap"); - STATIC int sandbox_mprotect(const void*, size_t, int) + STATIC long sandbox_mprotect(const void*, size_t, int) asm("playground$sandbox_mprotect"); - STATIC int sandbox_munmap(void* start, size_t length) + STATIC long sandbox_munmap(void* start, size_t length) asm("playground$sandbox_munmap"); - STATIC int sandbox_open(const char*, int, mode_t) + STATIC long sandbox_open(const char*, int, mode_t) asm("playground$sandbox_open"); #if defined(__NR_recvfrom) STATIC ssize_t sandbox_recvfrom(int, void*, size_t, int, void*, socklen_t*) @@ -140,7 +140,7 @@ class Sandbox { asm("playground$sandbox_recvmsg"); #endif #if defined(__NR_rt_sigprocmask) - STATIC int sandbox_rt_sigprocmask(int how, const void*, void*, size_t) + STATIC long sandbox_rt_sigprocmask(int how, const void*, void*, size_t) asm("playground$sandbox_rt_sigprocmask"); #endif #if defined(__NR_sendmsg) @@ -152,28 +152,28 @@ class Sandbox { #if defined(__NR_shmat) STATIC void* sandbox_shmat(int, const void*, int) asm("playground$sandbox_shmat"); - STATIC int sandbox_shmctl(int, int, void*) + STATIC long sandbox_shmctl(int, int, void*) asm("playground$sandbox_shmctl"); - STATIC int sandbox_shmdt(const void*) asm("playground$sandbox_shmdt"); - STATIC int sandbox_shmget(int, size_t, int) + STATIC long sandbox_shmdt(const void*) asm("playground$sandbox_shmdt"); + STATIC long sandbox_shmget(int, size_t, int) asm("playground$sandbox_shmget"); #endif #if defined(__NR_setsockopt) - STATIC int sandbox_setsockopt(int, int, int, const void*, socklen_t) + STATIC long sandbox_setsockopt(int, int, int, const void*, socklen_t) asm("playground$sandbox_setsockopt"); #endif #if defined(__NR_sigprocmask) - STATIC int sandbox_sigprocmask(int how, const void*, void*) + STATIC long sandbox_sigprocmask(int how, const void*, void*) asm("playground$sandbox_sigprocmask"); #endif #if defined(__NR_socketcall) - STATIC int sandbox_socketcall(int call, void* args) + STATIC long sandbox_socketcall(int call, void* args) asm("playground$sandbox_socketcall"); #endif - STATIC int sandbox_stat(const char* path, void* buf) + STATIC long sandbox_stat(const char* path, void* buf) asm("playground$sandbox_stat"); #if defined(__NR_stat64) - STATIC int sandbox_stat64(const char *path, void* b) + STATIC long sandbox_stat64(const char *path, void* b) asm("playground$sandbox_stat64"); #endif diff --git a/sandbox/linux/seccomp/sigprocmask.cc b/sandbox/linux/seccomp/sigprocmask.cc index f3ad1fb..9ff2922 100644 --- a/sandbox/linux/seccomp/sigprocmask.cc +++ b/sandbox/linux/seccomp/sigprocmask.cc @@ -13,7 +13,7 @@ namespace playground { // we really need this. Masking of synchronous signals is rarely necessary. #if defined(__NR_sigprocmask) -int Sandbox::sandbox_sigprocmask(int how, const void* set, void* old_set) { +long Sandbox::sandbox_sigprocmask(int how, const void* set, void* old_set) { long long tm; Debug::syscall(&tm, __NR_sigprocmask, "Executing handler"); @@ -57,13 +57,13 @@ int Sandbox::sandbox_sigprocmask(int how, const void* set, void* old_set) { Debug::elapsed(tm, __NR_sigprocmask); - return (int)res; + return res; } #endif #if defined(__NR_rt_sigprocmask) -int Sandbox::sandbox_rt_sigprocmask(int how, const void* set, void* old_set, - size_t bytes) { +long Sandbox::sandbox_rt_sigprocmask(int how, const void* set, void* old_set, + size_t bytes) { long long tm; Debug::syscall(&tm, __NR_rt_sigprocmask, "Executing handler"); @@ -113,7 +113,7 @@ int Sandbox::sandbox_rt_sigprocmask(int how, const void* set, void* old_set, Debug::elapsed(tm, __NR_rt_sigprocmask); - return (int)res; + return res; } #endif diff --git a/sandbox/linux/seccomp/socketcall.cc b/sandbox/linux/seccomp/socketcall.cc index 497e5e2..c7b2015 100644 --- a/sandbox/linux/seccomp/socketcall.cc +++ b/sandbox/linux/seccomp/socketcall.cc @@ -50,7 +50,7 @@ ssize_t Sandbox::sandbox_recvfrom(int sockfd, void* buf, size_t len, int flags, die("Failed to forward recvfrom() request [sandbox]"); } Debug::elapsed(tm, __NR_recvfrom); - return static_cast<int>(rc); + return static_cast<ssize_t>(rc); } ssize_t Sandbox::sandbox_recvmsg(int sockfd, struct msghdr* msg, int flags) { @@ -78,7 +78,7 @@ ssize_t Sandbox::sandbox_recvmsg(int sockfd, struct msghdr* msg, int flags) { die("Failed to forward recvmsg() request [sandbox]"); } Debug::elapsed(tm, __NR_recvmsg); - return static_cast<int>(rc); + return static_cast<ssize_t>(rc); } size_t Sandbox::sandbox_sendmsg(int sockfd, const struct msghdr* msg, @@ -119,7 +119,7 @@ size_t Sandbox::sandbox_sendmsg(int sockfd, const struct msghdr* msg, die("Failed to forward sendmsg() request [sandbox]"); } Debug::elapsed(tm, __NR_sendmsg); - return static_cast<int>(rc); + return static_cast<ssize_t>(rc); } ssize_t Sandbox::sandbox_sendto(int sockfd, const void* buf, size_t len, @@ -163,11 +163,11 @@ ssize_t Sandbox::sandbox_sendto(int sockfd, const void* buf, size_t len, die("Failed to forward sendto() request [sandbox]"); } Debug::elapsed(tm, __NR_sendto); - return static_cast<int>(rc); + return static_cast<ssize_t>(rc); } -int Sandbox::sandbox_setsockopt(int sockfd, int level, int optname, - const void* optval, socklen_t optlen) { +long Sandbox::sandbox_setsockopt(int sockfd, int level, int optname, + const void* optval, socklen_t optlen) { long long tm; Debug::syscall(&tm, __NR_setsockopt, "Executing handler"); @@ -192,11 +192,11 @@ int Sandbox::sandbox_setsockopt(int sockfd, int level, int optname, die("Failed to forward setsockopt() request [sandbox]"); } Debug::elapsed(tm, __NR_setsockopt); - return static_cast<int>(rc); + return rc; } -int Sandbox::sandbox_getsockopt(int sockfd, int level, int optname, - void* optval, socklen_t* optlen) { +long Sandbox::sandbox_getsockopt(int sockfd, int level, int optname, + void* optval, socklen_t* optlen) { long long tm; Debug::syscall(&tm, __NR_getsockopt, "Executing handler"); @@ -221,7 +221,7 @@ int Sandbox::sandbox_getsockopt(int sockfd, int level, int optname, die("Failed to forward getsockopt() request [sandbox]"); } Debug::elapsed(tm, __NR_getsockopt); - return static_cast<int>(rc); + return rc; } bool Sandbox::process_recvfrom(int parentMapsFd, int sandboxFd, @@ -567,7 +567,7 @@ const struct Sandbox::SocketCallArgInfo Sandbox::socketCallArgInfo[] = { #undef OFF }; -int Sandbox::sandbox_socketcall(int call, void* args) { +long Sandbox::sandbox_socketcall(int call, void* args) { long long tm; Debug::syscall(&tm, __NR_socketcall, "Executing handler", call); @@ -730,7 +730,7 @@ int Sandbox::sandbox_socketcall(int call, void* args) { die("Failed to forward socketcall() request [sandbox]"); } Debug::elapsed(tm, __NR_socketcall, call); - return static_cast<int>(rc); + return rc; } bool Sandbox::process_socketcall(int parentMapsFd, int sandboxFd, diff --git a/sandbox/linux/seccomp/stat.cc b/sandbox/linux/seccomp/stat.cc index 53e7e14..9277663 100644 --- a/sandbox/linux/seccomp/stat.cc +++ b/sandbox/linux/seccomp/stat.cc @@ -7,7 +7,7 @@ namespace playground { -int Sandbox::sandbox_stat(const char *path, void *buf) { +long Sandbox::sandbox_stat(const char *path, void *buf) { long long tm; Debug::syscall(&tm, __NR_stat, "Executing handler"); size_t len = strlen(path); @@ -33,10 +33,10 @@ int Sandbox::sandbox_stat(const char *path, void *buf) { die("Failed to forward stat() request [sandbox]"); } Debug::elapsed(tm, __NR_stat); - return static_cast<int>(rc); + return rc; } -int Sandbox::sandbox_lstat(const char *path, void *buf) { +long Sandbox::sandbox_lstat(const char *path, void *buf) { long long tm; Debug::syscall(&tm, __NR_lstat, "Executing handler"); size_t len = strlen(path); @@ -62,11 +62,11 @@ int Sandbox::sandbox_lstat(const char *path, void *buf) { die("Failed to forward lstat() request [sandbox]"); } Debug::elapsed(tm, __NR_lstat); - return static_cast<int>(rc); + return rc; } #if defined(__NR_stat64) -int Sandbox::sandbox_stat64(const char *path, void *buf) { +long Sandbox::sandbox_stat64(const char *path, void *buf) { long long tm; Debug::syscall(&tm, __NR_stat64, "Executing handler"); size_t len = strlen(path); @@ -92,10 +92,10 @@ int Sandbox::sandbox_stat64(const char *path, void *buf) { die("Failed to forward stat64() request [sandbox]"); } Debug::elapsed(tm, __NR_stat64); - return static_cast<int>(rc); + return rc; } -int Sandbox::sandbox_lstat64(const char *path, void *buf) { +long Sandbox::sandbox_lstat64(const char *path, void *buf) { long long tm; Debug::syscall(&tm, __NR_lstat64, "Executing handler"); size_t len = strlen(path); @@ -121,7 +121,7 @@ int Sandbox::sandbox_lstat64(const char *path, void *buf) { die("Failed to forward lstat64() request [sandbox]"); } Debug::elapsed(tm, __NR_lstat64); - return static_cast<int>(rc); + return rc; } #endif diff --git a/sandbox/linux/seccomp/tests/list_tests.py b/sandbox/linux/seccomp/tests/list_tests.py new file mode 100644 index 0000000..011a52e --- /dev/null +++ b/sandbox/linux/seccomp/tests/list_tests.py @@ -0,0 +1,22 @@ +# Copyright (c) 2010 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import re +import sys + + +def get_tests(filename): + for line in open(filename): + match = re.match(r"TEST\((\w+)\)", line) + if match is not None: + yield match.group(1) + + +def main(args): + for name in get_tests(args[0]): + print ' { "%s", %s },' % (name, name) + + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/sandbox/linux/seccomp/tests/test_syscalls.cc b/sandbox/linux/seccomp/tests/test_syscalls.cc new file mode 100644 index 0000000..917ffa5 --- /dev/null +++ b/sandbox/linux/seccomp/tests/test_syscalls.cc @@ -0,0 +1,273 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <assert.h> +#include <pthread.h> +#include <pty.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include "sandbox_impl.h" + + +// This is basically a marker to grep for. +#define TEST(name) void name() + +void *thread_func(void *x) { + int *ptr = (int *) x; + *ptr = 123; + printf("In new thread\n"); + return (void *) 456; +} + +TEST(test_thread) { + StartSeccompSandbox(); + pthread_t tid; + int x; + void *result; + pthread_create(&tid, NULL, thread_func, &x); + printf("Waiting for thread\n"); + pthread_join(tid, &result); + assert(result == (void *) 456); + assert(x == 123); +} + +int clone_func(void *x) { + printf("In thread func, which shouldn't happen\n"); + return 1; +} + +TEST(test_clone_disallowed_flags) { + StartSeccompSandbox(); + int stack_size = 4096; + char *stack = (char *) malloc(stack_size); + assert(stack != NULL); + /* We omit the flags CLONE_SETTLS, CLONE_PARENT_SETTID and + CLONE_CHILD_CLEARTID, which is disallowed by the sandbox. */ + int flags = CLONE_VM | CLONE_FS | CLONE_FILES | + CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM; + int rc = clone(clone_func, (void *) (stack + stack_size), flags, NULL, + NULL, NULL, NULL); + assert(rc == -1); + assert(errno == EPERM); +} + +long long read_tsc() { + long long rc; + asm volatile( + "rdtsc\n" + "mov %%eax, (%0)\n" + "mov %%edx, 4(%0)\n" + : + : "c"(&rc), "a"(-1), "d"(-1)); + return rc; +} + +TEST(test_rdtsc) { + StartSeccompSandbox(); + // Just check that we can do the instruction. + read_tsc(); +} + +TEST(test_getpid) { + int pid1 = getpid(); + StartSeccompSandbox(); + int pid2 = getpid(); + assert(pid1 == pid2); + // Bypass any caching that glibc's getpid() wrapper might do. + int pid3 = syscall(__NR_getpid); + assert(pid1 == pid3); +} + +TEST(test_gettid) { + // glibc doesn't provide a gettid() wrapper. + int tid1 = syscall(__NR_gettid); + assert(tid1 > 0); + StartSeccompSandbox(); + int tid2 = syscall(__NR_gettid); + assert(tid1 == tid2); +} + +void *map_something() { + void *addr = mmap(NULL, 0x1000, PROT_READ, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + assert(addr != MAP_FAILED); + return addr; +} + +TEST(test_mmap_disallows_remapping) { + void *addr = map_something(); + StartSeccompSandbox(); + // Overwriting a mapping that was created before the sandbox was + // enabled is not allowed. + void *result = mmap(addr, 0x1000, PROT_READ, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); + assert(result == MAP_FAILED); + assert(errno == EINVAL); +} + +TEST(test_mmap_disallows_low_address) { + StartSeccompSandbox(); + // Mapping pages at low addresses is not allowed because this helps + // with exploiting buggy kernels. + void *result = mmap(NULL, 0x1000, PROT_READ, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); + assert(result == MAP_FAILED); + assert(errno == EINVAL); +} + +TEST(test_munmap_allowed) { + StartSeccompSandbox(); + void *addr = map_something(); + int result = munmap(addr, 0x1000); + assert(result == 0); +} + +TEST(test_munmap_disallowed) { + void *addr = map_something(); + StartSeccompSandbox(); + int result = munmap(addr, 0x1000); + assert(result == -1); + assert(errno == EINVAL); +} + +TEST(test_mprotect_allowed) { + StartSeccompSandbox(); + void *addr = map_something(); + int result = mprotect(addr, 0x1000, PROT_READ | PROT_WRITE); + assert(result == 0); +} + +TEST(test_mprotect_disallowed) { + void *addr = map_something(); + StartSeccompSandbox(); + int result = mprotect(addr, 0x1000, PROT_READ | PROT_WRITE); + assert(result == -1); + assert(errno == EINVAL); +} + +int get_tty_fd() { + int master_fd, tty_fd; + int rc = openpty(&master_fd, &tty_fd, NULL, NULL, NULL); + assert(rc == 0); + return tty_fd; +} + +TEST(test_ioctl_tiocgwinsz_allowed) { + int tty_fd = get_tty_fd(); + StartSeccompSandbox(); + int size[2]; + // Get terminal width and height. + int result = ioctl(tty_fd, TIOCGWINSZ, size); + assert(result == 0); +} + +TEST(test_ioctl_disallowed) { + int tty_fd = get_tty_fd(); + StartSeccompSandbox(); + // This ioctl call inserts a character into the tty's input queue, + // which provides a way to send commands to an interactive shell. + char c = 'x'; + int result = ioctl(tty_fd, TIOCSTI, &c); + assert(result == -1); + assert(errno == EINVAL); +} + +TEST(test_socket) { + StartSeccompSandbox(); + int fd = socket(AF_UNIX, SOCK_STREAM, 0); + assert(fd == -1); + // TODO: Make it consistent between i386 and x86-64. + assert(errno == EINVAL || errno == ENOSYS); +} + +TEST(test_open) { + StartSeccompSandbox(); + int fd = open("/dev/null", O_RDONLY); + assert(fd >= 0); + int rc = close(fd); + assert(rc == 0); + fd = open("/dev/null", O_WRONLY); + assert(fd == -1); + assert(errno == EACCES); +} + +TEST(test_access) { + StartSeccompSandbox(); + int rc = access("/dev/null", R_OK); + assert(rc == 0); + rc = access("path-that-does-not-exist", R_OK); + assert(rc == -1); + assert(errno == ENOENT); +} + +TEST(test_stat) { + StartSeccompSandbox(); + struct stat st; + // All file accesses are denied. TODO: Update if the sandbox gets a more + // fine-grained policy + int rc = stat("/dev/null", &st); + assert(rc == -1); + rc = stat("path-that-does-not-exist", &st); + assert(rc == -1); + assert(errno == EACCES); +} + + +struct testcase { + const char *test_name; + void (*test_func)(); +}; + +struct testcase all_tests[] = { +#include "test-list.h" + { NULL, NULL }, +}; + +void run_test_forked(struct testcase *test) { + printf("** %s\n", test->test_name); + int pid = fork(); + if (pid == 0) { + test->test_func(); + _exit(0); + } + int status; + waitpid(pid, &status, 0); + if (status != 0) { + printf("Test failed with exit status %i\n", status); + exit(1); + } +} + +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) { + test->test_func(); + return 0; + } + } + fprintf(stderr, "Test '%s' not found\n", name); + return 1; +} + +int main(int argc, char **argv) { + if (argc == 2) { + // Run one test without forking, to aid debugging. + return run_test_by_name(argv[1]); + } + else if (argc > 2) { + // TODO: run multiple tests. + fprintf(stderr, "Too many arguments\n"); + return 1; + } + else { + // Run all tests. + struct testcase *test; + for (test = all_tests; test->test_name != NULL; test++) { + run_test_forked(test); + } + } + return 0; +} |