summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormdempsky <mdempsky@chromium.org>2014-09-09 02:10:31 -0700
committerCommit bot <commit-bot@chromium.org>2014-09-09 09:14:21 +0000
commite0dd0295045531750465047312651a30aab5d6a2 (patch)
treea3f9ade34e4ec95f2d8ed2bde2db8e267fa2ac64
parent948ce92d41501beacc70936f6b9104d51844ecca (diff)
downloadchromium_src-e0dd0295045531750465047312651a30aab5d6a2.zip
chromium_src-e0dd0295045531750465047312651a30aab5d6a2.tar.gz
chromium_src-e0dd0295045531750465047312651a30aab5d6a2.tar.bz2
sandbox: remove seccomp-bpf demo program
The demo program has served its purpose, and it's no longer necessary to demonstrate how to use seccomp-bpf. Review URL: https://codereview.chromium.org/554743006 Cr-Commit-Position: refs/heads/master@{#293901}
-rw-r--r--sandbox/linux/BUILD.gn12
-rw-r--r--sandbox/linux/sandbox_linux.gypi20
-rw-r--r--sandbox/linux/seccomp-bpf/demo.cc542
3 files changed, 0 insertions, 574 deletions
diff --git a/sandbox/linux/BUILD.gn b/sandbox/linux/BUILD.gn
index 3b941d72..754664d 100644
--- a/sandbox/linux/BUILD.gn
+++ b/sandbox/linux/BUILD.gn
@@ -186,18 +186,6 @@ component("seccomp_bpf_helpers") {
]
}
-if (compile_seccomp_bpf_demo) {
- # A demonstration program for the seccomp-bpf sandbox.
- executable("seccomp_bpf_demo") {
- sources = [
- "seccomp-bpf/demo.cc",
- ]
- deps = [
- ":seccomp_bpf",
- ]
- }
-}
-
# The setuid sandbox for Linux.
executable("chrome_sandbox") {
sources = [
diff --git a/sandbox/linux/sandbox_linux.gypi b/sandbox/linux/sandbox_linux.gypi
index 69b7823..5a1e65c 100644
--- a/sandbox/linux/sandbox_linux.gypi
+++ b/sandbox/linux/sandbox_linux.gypi
@@ -181,26 +181,6 @@
],
},
{
- # A demonstration program for the seccomp-bpf sandbox.
- 'target_name': 'seccomp_bpf_demo',
- 'conditions': [
- ['compile_seccomp_bpf_demo==1', {
- 'type': 'executable',
- 'sources': [
- 'seccomp-bpf/demo.cc',
- ],
- 'dependencies': [
- 'seccomp_bpf',
- ],
- }, {
- 'type': 'none',
- }],
- ],
- 'include_dirs': [
- '../../',
- ],
- },
- {
# The setuid sandbox, for Linux
'target_name': 'chrome_sandbox',
'type': 'executable',
diff --git a/sandbox/linux/seccomp-bpf/demo.cc b/sandbox/linux/seccomp-bpf/demo.cc
deleted file mode 100644
index d9fd342..0000000
--- a/sandbox/linux/seccomp-bpf/demo.cc
+++ /dev/null
@@ -1,542 +0,0 @@
-// Copyright (c) 2012 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 <errno.h>
-#include <fcntl.h>
-#include <linux/unistd.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <netinet/udp.h>
-#include <pthread.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/ipc.h>
-#include <sys/mman.h>
-#include <sys/prctl.h>
-#include <sys/resource.h>
-#include <sys/shm.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "base/macros.h"
-#include "base/posix/eintr_wrapper.h"
-#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
-#include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h"
-#include "sandbox/linux/services/linux_syscalls.h"
-
-using sandbox::ErrorCode;
-using sandbox::SandboxBPF;
-using sandbox::SandboxBPFPolicy;
-using sandbox::arch_seccomp_data;
-
-#define ERR EPERM
-
-// We don't expect our sandbox to do anything useful yet. So, we will fail
-// almost immediately. For now, force the code to continue running. The
-// following line should be removed as soon as the sandbox is starting to
-// actually enforce restrictions in a meaningful way:
-#define _exit(x) do { } while (0)
-
-namespace {
-
-bool SendFds(int transport, const void *buf, size_t len, ...) {
- int count = 0;
- va_list ap;
- va_start(ap, len);
- while (va_arg(ap, int) >= 0) {
- ++count;
- }
- va_end(ap);
- if (!count) {
- return false;
- }
- char cmsg_buf[CMSG_SPACE(count*sizeof(int))];
- memset(cmsg_buf, 0, sizeof(cmsg_buf));
- struct iovec iov[2] = { { 0 } };
- struct msghdr msg = { 0 };
- int dummy = 0;
- iov[0].iov_base = &dummy;
- iov[0].iov_len = sizeof(dummy);
- if (buf && len > 0) {
- iov[1].iov_base = const_cast<void *>(buf);
- iov[1].iov_len = len;
- }
- msg.msg_iov = iov;
- msg.msg_iovlen = (buf && len > 0) ? 2 : 1;
- msg.msg_control = cmsg_buf;
- msg.msg_controllen = CMSG_LEN(count*sizeof(int));
- struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(count*sizeof(int));
- va_start(ap, len);
- for (int i = 0, fd; (fd = va_arg(ap, int)) >= 0; ++i) {
- (reinterpret_cast<int *>(CMSG_DATA(cmsg)))[i] = fd;
- }
- return sendmsg(transport, &msg, 0) ==
- static_cast<ssize_t>(sizeof(dummy) + ((buf && len > 0) ? len : 0));
-}
-
-bool GetFds(int transport, void *buf, size_t *len, ...) {
- int count = 0;
- va_list ap;
- va_start(ap, len);
- for (int *fd; (fd = va_arg(ap, int *)) != NULL; ++count) {
- *fd = -1;
- }
- va_end(ap);
- if (!count) {
- return false;
- }
- char cmsg_buf[CMSG_SPACE(count*sizeof(int))];
- memset(cmsg_buf, 0, sizeof(cmsg_buf));
- struct iovec iov[2] = { { 0 } };
- struct msghdr msg = { 0 };
- int err;
- iov[0].iov_base = &err;
- iov[0].iov_len = sizeof(int);
- if (buf && len && *len > 0) {
- iov[1].iov_base = buf;
- iov[1].iov_len = *len;
- }
- msg.msg_iov = iov;
- msg.msg_iovlen = (buf && len && *len > 0) ? 2 : 1;
- msg.msg_control = cmsg_buf;
- msg.msg_controllen = CMSG_LEN(count*sizeof(int));
- ssize_t bytes = recvmsg(transport, &msg, 0);
- if (len) {
- *len = bytes > static_cast<int>(sizeof(int)) ? bytes - sizeof(int) : 0;
- }
- if (bytes != static_cast<ssize_t>(sizeof(int) + iov[1].iov_len)) {
- if (bytes >= 0) {
- errno = 0;
- }
- return false;
- }
- if (err) {
- // "err" is the first four bytes of the payload. If these are non-zero,
- // the sender on the other side of the socketpair sent us an errno value.
- // We don't expect to get any file handles in this case.
- errno = err;
- return false;
- }
- struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
- if ((msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) ||
- !cmsg ||
- cmsg->cmsg_level != SOL_SOCKET ||
- cmsg->cmsg_type != SCM_RIGHTS ||
- cmsg->cmsg_len != CMSG_LEN(count*sizeof(int))) {
- errno = EBADF;
- return false;
- }
- va_start(ap, len);
- for (int *fd, i = 0; (fd = va_arg(ap, int *)) != NULL; ++i) {
- *fd = (reinterpret_cast<int *>(CMSG_DATA(cmsg)))[i];
- }
- va_end(ap);
- return true;
-}
-
-
-// POSIX doesn't define any async-signal safe function for converting
-// an integer to ASCII. We'll have to define our own version.
-// itoa_r() converts a (signed) integer to ASCII. It returns "buf", if the
-// conversion was successful or NULL otherwise. It never writes more than "sz"
-// bytes. Output will be truncated as needed, and a NUL character is always
-// appended.
-char *itoa_r(int i, char *buf, size_t sz) {
- // Make sure we can write at least one NUL byte.
- size_t n = 1;
- if (n > sz) {
- return NULL;
- }
-
- // Handle negative numbers.
- char *start = buf;
- int minint = 0;
- if (i < 0) {
- // Make sure we can write the '-' character.
- if (++n > sz) {
- *start = '\000';
- return NULL;
- }
- *start++ = '-';
-
- // Turn our number positive.
- if (i == -i) {
- // The lowest-most negative integer needs special treatment.
- minint = 1;
- i = -(i + 1);
- } else {
- // "Normal" negative numbers are easy.
- i = -i;
- }
- }
-
- // Loop until we have converted the entire number. Output at least one
- // character (i.e. '0').
- char *ptr = start;
- do {
- // Make sure there is still enough space left in our output buffer.
- if (++n > sz) {
- buf = NULL;
- goto truncate;
- }
-
- // Output the next digit and (if necessary) compensate for the lowest-most
- // negative integer needing special treatment. This works because, no
- // matter the bit width of the integer, the lowest-most integer always ends
- // in 2, 4, 6, or 8.
- *ptr++ = i%10 + '0' + minint;
- minint = 0;
- i /= 10;
- } while (i);
- truncate: // Terminate the output with a NUL character.
- *ptr = '\000';
-
- // Conversion to ASCII actually resulted in the digits being in reverse
- // order. We can't easily generate them in forward order, as we can't tell
- // the number of characters needed until we are done converting.
- // So, now, we reverse the string (except for the possible "-" sign).
- while (--ptr > start) {
- char ch = *ptr;
- *ptr = *start;
- *start++ = ch;
- }
- return buf;
-}
-
-// This handler gets called, whenever we encounter a system call that we
-// don't recognize explicitly. For the purposes of this program, we just
-// log the system call and then deny it. More elaborate sandbox policies
-// might try to evaluate the system call in user-space, instead.
-// The only notable complication is that this function must be async-signal
-// safe. This restricts the libary functions that we can call.
-intptr_t DefaultHandler(const struct arch_seccomp_data& data, void *) {
- static const char msg0[] = "Disallowed system call #";
- static const char msg1[] = "\n";
- char buf[sizeof(msg0) - 1 + 25 + sizeof(msg1)];
-
- *buf = '\000';
- strncat(buf, msg0, sizeof(buf) - 1);
-
- char *ptr = strrchr(buf, '\000');
- itoa_r(data.nr, ptr, sizeof(buf) - (ptr - buf));
-
- ptr = strrchr(ptr, '\000');
- strncat(ptr, msg1, sizeof(buf) - (ptr - buf));
-
- ptr = strrchr(ptr, '\000');
- if (HANDLE_EINTR(write(2, buf, ptr - buf))) { }
-
- return -ERR;
-}
-
-class DemoPolicy : public SandboxBPFPolicy {
- public:
- DemoPolicy() {}
- virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox,
- int sysno) const OVERRIDE;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DemoPolicy);
-};
-
-ErrorCode DemoPolicy::EvaluateSyscall(SandboxBPF* sandbox, int sysno) const {
- switch (sysno) {
-#if defined(__NR_accept)
- case __NR_accept: case __NR_accept4:
-#endif
- case __NR_alarm:
- case __NR_brk:
- case __NR_clock_gettime:
- case __NR_close:
- case __NR_dup: case __NR_dup2:
- case __NR_epoll_create: case __NR_epoll_ctl: case __NR_epoll_wait:
- case __NR_exit: case __NR_exit_group:
- case __NR_fcntl:
-#if defined(__NR_fcntl64)
- case __NR_fcntl64:
-#endif
- case __NR_fdatasync:
- case __NR_fstat:
-#if defined(__NR_fstat64)
- case __NR_fstat64:
-#endif
- case __NR_ftruncate:
- case __NR_futex:
- case __NR_getdents: case __NR_getdents64:
- case __NR_getegid:
-#if defined(__NR_getegid32)
- case __NR_getegid32:
-#endif
- case __NR_geteuid:
-#if defined(__NR_geteuid32)
- case __NR_geteuid32:
-#endif
- case __NR_getgid:
-#if defined(__NR_getgid32)
- case __NR_getgid32:
-#endif
- case __NR_getitimer: case __NR_setitimer:
-#if defined(__NR_getpeername)
- case __NR_getpeername:
-#endif
- case __NR_getpid: case __NR_gettid:
-#if defined(__NR_getsockname)
- case __NR_getsockname:
-#endif
- case __NR_gettimeofday:
- case __NR_getuid:
-#if defined(__NR_getuid32)
- case __NR_getuid32:
-#endif
-#if defined(__NR__llseek)
- case __NR__llseek:
-#endif
- case __NR_lseek:
- case __NR_nanosleep:
- case __NR_pipe: case __NR_pipe2:
- case __NR_poll:
- case __NR_pread64: case __NR_preadv:
- case __NR_pwrite64: case __NR_pwritev:
- case __NR_read: case __NR_readv:
- case __NR_restart_syscall:
- case __NR_set_robust_list:
- case __NR_rt_sigaction:
-#if defined(__NR_sigaction)
- case __NR_sigaction:
-#endif
-#if defined(__NR_signal)
- case __NR_signal:
-#endif
- case __NR_rt_sigprocmask:
-#if defined(__NR_sigprocmask)
- case __NR_sigprocmask:
-#endif
-#if defined(__NR_shutdown)
- case __NR_shutdown:
-#endif
- case __NR_rt_sigreturn:
-#if defined(__NR_sigreturn)
- case __NR_sigreturn:
-#endif
-#if defined(__NR_socketpair)
- case __NR_socketpair:
-#endif
- case __NR_time:
- case __NR_uname:
- case __NR_write: case __NR_writev:
- return ErrorCode(ErrorCode::ERR_ALLOWED);
-
- case __NR_prctl:
- // Allow PR_SET_DUMPABLE and PR_GET_DUMPABLE. Do not allow anything else.
- return sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
- PR_SET_DUMPABLE,
- ErrorCode(ErrorCode::ERR_ALLOWED),
- sandbox->Cond(1, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
- PR_GET_DUMPABLE,
- ErrorCode(ErrorCode::ERR_ALLOWED),
- sandbox->Trap(DefaultHandler, NULL)));
-
- // The following system calls are temporarily permitted. This must be
- // tightened later. But we currently don't implement enough of the sandboxing
- // API to do so.
- // As is, this sandbox isn't exactly safe :-/
-#if defined(__NR_sendmsg)
- case __NR_sendmsg: case __NR_sendto:
- case __NR_recvmsg: case __NR_recvfrom:
- case __NR_getsockopt: case __NR_setsockopt:
-#elif defined(__NR_socketcall)
- case __NR_socketcall:
-#endif
-#if defined(__NR_shmat)
- case __NR_shmat: case __NR_shmctl: case __NR_shmdt: case __NR_shmget:
-#elif defined(__NR_ipc)
- case __NR_ipc:
-#endif
-#if defined(__NR_mmap2)
- case __NR_mmap2:
-#else
- case __NR_mmap:
-#endif
-#if defined(__NR_ugetrlimit)
- case __NR_ugetrlimit:
-#endif
- case __NR_getrlimit:
- case __NR_ioctl:
- case __NR_clone:
- case __NR_munmap: case __NR_mprotect: case __NR_madvise:
- case __NR_remap_file_pages:
- return ErrorCode(ErrorCode::ERR_ALLOWED);
-
- // Everything that isn't explicitly allowed is denied.
- default:
- return sandbox->Trap(DefaultHandler, NULL);
- }
-}
-
-void *ThreadFnc(void *arg) {
- return arg;
-}
-
-void *SendmsgStressThreadFnc(void *arg) {
- if (arg) { }
- static const int repetitions = 100;
- static const int kNumFds = 3;
- for (int rep = 0; rep < repetitions; ++rep) {
- int fds[2 + kNumFds];
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) {
- perror("socketpair()");
- _exit(1);
- }
- size_t len = 4;
- char buf[4];
- if (!SendFds(fds[0], "test", 4, fds[1], fds[1], fds[1], -1) ||
- !GetFds(fds[1], buf, &len, fds+2, fds+3, fds+4, NULL) ||
- len != 4 ||
- memcmp(buf, "test", len) ||
- write(fds[2], "demo", 4) != 4 ||
- read(fds[0], buf, 4) != 4 ||
- memcmp(buf, "demo", 4)) {
- perror("sending/receiving of fds");
- _exit(1);
- }
- for (int i = 0; i < 2+kNumFds; ++i) {
- if (close(fds[i])) {
- perror("close");
- _exit(1);
- }
- }
- }
- return NULL;
-}
-
-} // namespace
-
-int main(int argc, char *argv[]) {
- if (argc) { }
- if (argv) { }
- int proc_fd = open("/proc", O_RDONLY|O_DIRECTORY);
- if (SandboxBPF::SupportsSeccompSandbox(proc_fd) !=
- SandboxBPF::STATUS_AVAILABLE) {
- perror("sandbox");
- _exit(1);
- }
- SandboxBPF sandbox;
- sandbox.set_proc_fd(proc_fd);
- sandbox.SetSandboxPolicy(new DemoPolicy());
- if (!sandbox.StartSandbox(SandboxBPF::PROCESS_SINGLE_THREADED)) {
- fprintf(stderr, "StartSandbox() failed");
- _exit(1);
- }
-
- // Check that we can create threads
- pthread_t thr;
- if (!pthread_create(&thr, NULL, ThreadFnc,
- reinterpret_cast<void *>(0x1234))) {
- void *ret;
- pthread_join(thr, &ret);
- if (ret != reinterpret_cast<void *>(0x1234)) {
- perror("clone() failed");
- _exit(1);
- }
- } else {
- perror("clone() failed");
- _exit(1);
- }
-
- // Check that we handle restart_syscall() without dieing. This is a little
- // tricky to trigger. And I can't think of a good way to verify whether it
- // actually executed.
- signal(SIGALRM, SIG_IGN);
- const struct itimerval tv = { { 0, 0 }, { 0, 5*1000 } };
- const struct timespec tmo = { 0, 100*1000*1000 };
- setitimer(ITIMER_REAL, &tv, NULL);
- nanosleep(&tmo, NULL);
-
- // Check that we can query the size of the stack, but that all other
- // calls to getrlimit() fail.
- if (((errno = 0), !getrlimit(RLIMIT_STACK, NULL)) || errno != EFAULT ||
- ((errno = 0), !getrlimit(RLIMIT_CORE, NULL)) || errno != ERR) {
- perror("getrlimit()");
- _exit(1);
- }
-
- // Check that we can query TCGETS and TIOCGWINSZ, but no other ioctls().
- if (((errno = 0), !ioctl(2, TCGETS, NULL)) || errno != EFAULT ||
- ((errno = 0), !ioctl(2, TIOCGWINSZ, NULL)) || errno != EFAULT ||
- ((errno = 0), !ioctl(2, TCSETS, NULL)) || errno != ERR) {
- perror("ioctl()");
- _exit(1);
- }
-
- // Check that prctl() can manipulate the dumpable flag, but nothing else.
- if (((errno = 0), !prctl(PR_GET_DUMPABLE)) || errno ||
- ((errno = 0), prctl(PR_SET_DUMPABLE, 1)) || errno ||
- ((errno = 0), !prctl(PR_SET_SECCOMP, 0)) || errno != ERR) {
- perror("prctl()");
- _exit(1);
- }
-
- // Check that we can send and receive file handles.
- int fds[3];
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) {
- perror("socketpair()");
- _exit(1);
- }
- size_t len = 4;
- char buf[4];
- if (!SendFds(fds[0], "test", 4, fds[1], -1) ||
- !GetFds(fds[1], buf, &len, fds+2, NULL) ||
- len != 4 ||
- memcmp(buf, "test", len) ||
- write(fds[2], "demo", 4) != 4 ||
- read(fds[0], buf, 4) != 4 ||
- memcmp(buf, "demo", 4) ||
- close(fds[0]) ||
- close(fds[1]) ||
- close(fds[2])) {
- perror("sending/receiving of fds");
- _exit(1);
- }
-
- // Check whether SysV IPC works.
- int shmid;
- void *addr;
- if ((shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT|0600)) < 0 ||
- (addr = shmat(shmid, NULL, 0)) == reinterpret_cast<void *>(-1) ||
- shmdt(addr) ||
- shmctl(shmid, IPC_RMID, NULL)) {
- perror("sysv IPC");
- _exit(1);
- }
-
- // Print a message so that the user can see the sandbox is activated.
- time_t tm = time(NULL);
- printf("Sandbox has been started at %s", ctime(&tm));
-
- // Stress-test the sendmsg() code
- static const int kSendmsgStressNumThreads = 10;
- pthread_t sendmsgStressThreads[kSendmsgStressNumThreads];
- for (int i = 0; i < kSendmsgStressNumThreads; ++i) {
- if (pthread_create(sendmsgStressThreads + i, NULL,
- SendmsgStressThreadFnc, NULL)) {
- perror("pthread_create");
- _exit(1);
- }
- }
- for (int i = 0; i < kSendmsgStressNumThreads; ++i) {
- pthread_join(sendmsgStressThreads[i], NULL);
- }
-
- return 0;
-}