Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(377)

Unified Diff: components/nacl/loader/nacl_sandbox_linux.cc

Issue 196793023: Add seccomp sandbox for non-SFI NaCl (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/nacl/loader/nacl_sandbox_linux.cc
diff --git a/components/nacl/loader/nacl_sandbox_linux.cc b/components/nacl/loader/nacl_sandbox_linux.cc
index f1e4a49a4f71b1ab1efaaade862ea8a9d9f399b2..755fe52bc2f77bc5253497609f81a42f6cc871ac 100644
--- a/components/nacl/loader/nacl_sandbox_linux.cc
+++ b/components/nacl/loader/nacl_sandbox_linux.cc
@@ -5,8 +5,14 @@
#include "components/nacl/loader/nacl_sandbox_linux.h"
#include <errno.h>
+#include <fcntl.h>
+#include <linux/net.h>
#include <signal.h>
+#include <sys/prctl.h>
#include <sys/ptrace.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
#include "base/basictypes.h"
#include "base/callback.h"
@@ -16,10 +22,16 @@
#if defined(USE_SECCOMP_BPF)
#include "content/public/common/sandbox_init.h"
+#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h"
#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
#include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h"
+#include "sandbox/linux/seccomp-bpf/trap.h"
#include "sandbox/linux/services/linux_syscalls.h"
+#if defined(__arm__) && !defined(MAP_STACK)
+#define MAP_STACK 0x20000 // Daisy build environment has old headers.
+#endif
+
using sandbox::ErrorCode;
using sandbox::SandboxBPF;
using sandbox::SandboxBPFPolicy;
@@ -122,6 +134,7 @@ ErrorCode NaClBPFSandboxPolicy::EvaluateSyscall(
case __NR_uname:
return ErrorCode(ErrorCode::ERR_ALLOWED);
case __NR_ptrace:
+ // For RunSandboxSanityChecks().
return ErrorCode(EPERM);
default:
// TODO(jln): look into getting rid of System V shared memory:
@@ -142,6 +155,249 @@ ErrorCode NaClBPFSandboxPolicy::EvaluateSyscall(
return ErrorCode(EPERM);
}
+ErrorCode RestrictFcntlCommandsForNonSfiNaCl(SandboxBPF* sb) {
+ ErrorCode::ArgType mask_long_type;
+ if (sizeof(long) == 8)
+ mask_long_type = ErrorCode::TP_64BIT;
+ else if (sizeof(long) == 4)
+ mask_long_type = ErrorCode::TP_32BIT;
+ else
+ NOTREACHED();
+ // We allow following cases:
+ // 1. F_SETFD + FD_CLOEXEC: libevent's epoll_init uses this.
+ // 2. F_GETFL: Used by SetNonBlocking in
+ // message_pump_libevent.cc and Channel::ChannelImpl::CreatePipe
+ // in ipc_channel_posix.cc. Note that the latter does not work
+ // with EPERM.
+ // 3. F_SETFL: Used by evutil_make_socket_nonblocking in
+ // libevent and SetNonBlocking. As the latter mix O_NONBLOCK to
+ // the return value of F_GETFL, so we need to allow O_ACCMODE in
+ // addition to O_NONBLOCK.
+ unsigned long denied_mask = ~(O_ACCMODE | O_NONBLOCK);
+ return sb->Cond(1, ErrorCode::TP_32BIT,
+ ErrorCode::OP_EQUAL, F_SETFD,
+ sb->Cond(2, mask_long_type,
+ ErrorCode::OP_EQUAL, FD_CLOEXEC,
+ ErrorCode(ErrorCode::ERR_ALLOWED),
+ sb->Trap(sandbox::CrashSIGSYS_Handler, NULL)),
+ sb->Cond(1, ErrorCode::TP_32BIT,
+ ErrorCode::OP_EQUAL, F_GETFL,
+ ErrorCode(ErrorCode::ERR_ALLOWED),
+ sb->Cond(1, ErrorCode::TP_32BIT,
+ ErrorCode::OP_EQUAL, F_SETFL,
+ sb->Cond(2, mask_long_type,
+ ErrorCode::OP_HAS_ANY_BITS, denied_mask,
+ sb->Trap(sandbox::CrashSIGSYS_Handler, NULL),
+ ErrorCode(ErrorCode::ERR_ALLOWED)),
+ sb->Trap(sandbox::CrashSIGSYS_Handler, NULL))));
+}
+
+// The seccomp sandbox policy for NaCl non-SFI mode. Note that this
+// policy must be as strong as possible, as non-SFI mode heavily
+// depends on seccomp sandbox.
+class NonSfiNaClBPFSandboxPolicy : public SandboxBPFPolicy {
Mark Seaborn 2014/03/28 01:38:25 Can we put the Non-SFI Mode sandbox policy in a se
hamaji 2014/03/28 12:06:10 Thanks, will do!
+ public:
+ explicit NonSfiNaClBPFSandboxPolicy() {
+ }
+ virtual ~NonSfiNaClBPFSandboxPolicy() {}
+
+ virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox_compiler,
+ int system_call_number) const OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NonSfiNaClBPFSandboxPolicy);
+};
+
+ErrorCode NonSfiNaClBPFSandboxPolicy::EvaluateSyscall(
+ sandbox::SandboxBPF* sb, int sysno) const {
+ ErrorCode ret = sb->Trap(sandbox::CrashSIGSYS_Handler, NULL);
+ switch (sysno) {
+ // Allowed syscalls.
hamaji 2014/03/24 15:56:37 I have a question about sigaction and sigaltstack.
+ case __NR__llseek:
+ case __NR_clock_gettime:
+ case __NR_close:
+ case __NR_dup:
+ case __NR_dup2:
+ case __NR_epoll_create:
+ case __NR_epoll_ctl:
hamaji 2014/03/24 15:56:37 Would it be better to check the operation type is
+ case __NR_epoll_wait:
+ case __NR_exit:
+ case __NR_exit_group:
+ case __NR_fstat64:
+ case __NR_futex:
hamaji 2014/03/24 16:25:43 Maybe better to restrict the operation of futex?
+ case __NR_gettid:
+ case __NR_gettimeofday:
+ case __NR_munmap:
+ case __NR_nanosleep:
+ case __NR_pipe:
+ case __NR_read:
+ case __NR_restart_syscall:
+ case __NR_sched_yield:
+ case __NR_write:
+#if defined(__arm__)
+ case __ARM_NR_cacheflush:
+#endif
+ ret = ErrorCode(ErrorCode::ERR_ALLOWED);
+ break;
+
+ // __NR_times needed as clock() is called by CommandBufferHelper, which is
+ // used by NaCl applications that use Pepper's 3D interfaces.
+ // See crbug.com/264856 for details.
+ case __NR_times:
+ // NaCl runtime exposes clock_getres to untrusted code.
+ case __NR_clock_getres:
hamaji 2014/03/24 16:25:43 Do we need to restrict clk_id for gettime and getr
+ ret = ErrorCode(ErrorCode::ERR_ALLOWED);
+ break;
+
+ // Conditionally allowed syscalls:
+ case __NR_clone: {
+ // We allow clone only for new thread creation.
+ ret = sb->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
+ CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
+ CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS |
+ CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID,
+ ErrorCode(ErrorCode::ERR_ALLOWED),
+ sb->Trap(sandbox::SIGSYSCloneFailure, NULL));
+ break;
+ }
+ case __NR_prctl:
+ // base::PlatformThread::SetName() uses PR_SET_NAME so we return
+ // EPERM for it. Otherwise, we will raise SIGSYS.
+ ret = sb->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
+ PR_SET_NAME, ErrorCode(EPERM),
+ sb->Trap(sandbox::SIGSYSPrctlFailure, NULL));
+
+#if defined(__i386__)
+ case __NR_socketcall: {
+ // We only allow socketpair, sendmsg, and recvmsg.
+ ret = sb->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
+ SYS_SOCKETPAIR, ErrorCode(ErrorCode::ERR_ALLOWED),
+ sb->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
+ SYS_SENDMSG, ErrorCode(ErrorCode::ERR_ALLOWED),
+ sb->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL,
+ SYS_RECVMSG, ErrorCode(ErrorCode::ERR_ALLOWED),
+ ErrorCode(EPERM))));
+ break;
+ }
+#endif
+#if defined(__x86_64__) || defined(__arm__)
+ case __NR_recvmsg:
+ case __NR_sendmsg:
+ ret = ErrorCode(ErrorCode::ERR_ALLOWED);
+ break;
+
+ case __NR_socketpair:
+ // Only allow AF_UNIX, PF_UNIX. Crash if anything else is seen.
+ COMPILE_ASSERT(AF_UNIX == PF_UNIX, af_unix_pf_unix_different);
+ return sb->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, AF_UNIX,
+ ErrorCode(ErrorCode::ERR_ALLOWED),
+ sb->Trap(sandbox::CrashSIGSYS_Handler, NULL));
+ break;
+#endif
+
+ // It is allowed to call the following syscalls, but they just
+ // return EPERM.
+ case __NR_ptrace:
+ // For RunSandboxSanityChecks().
+ ret = ErrorCode(EPERM);
+ break;
+ case __NR_set_robust_list:
+ // glibc uses this for its pthread implementation. If we return
+ // EPERM for this, glibc will stop using this.
+ // TODO(hamaji): newlib does not use this. Make this SIGTRAP once
+ // we have switched to newlib.
+ ret = ErrorCode(EPERM);
+ break;
+#if !defined(__x86_64__)
+ case __NR_getegid32:
+ case __NR_geteuid32:
+ case __NR_getgid32:
+ case __NR_getuid32:
+#endif
+ // third_party/libevent uses them, but we can just return -1 from
+ // them as it is just checking getuid() != geteuid() and
+ // getgid() != getegid()
+ ret = ErrorCode(EPERM);
+ break;
+#if defined(__i386__) || defined(__x86_64__)
+ case __NR_time:
+ // This is obsolete in ARM EABI, but x86 glibc indirectly calls
+ // this in sysconf.
+ ret = ErrorCode(EPERM);
+ break;
+#endif
+
+#if defined(__x86_64__)
+ case __NR_fcntl:
+#endif
+#if defined(__i386__) || defined(__arm__)
+ case __NR_fcntl64:
+#endif
+ ret = RestrictFcntlCommandsForNonSfiNaCl(sb);
+ break;
+
+#if defined(__x86_64__)
+ case __NR_mmap:
+#endif
+#if defined(__i386__) || defined(__arm__)
+ case __NR_mmap2:
+#endif
+ {
+ uint32_t denied_flag_mask = ~(MAP_SHARED | MAP_PRIVATE | MAP_ANONYMOUS |
+ MAP_STACK | MAP_FIXED);
+ // switch to newlib. Currently, it is used by glibc's pthread_create.
+ // TODO(jln, keescook, drewry): Limit the use of mmap by adding
+ // some features to linux kernel.
+ uint32_t denied_prot_mask = ~(PROT_READ | PROT_WRITE | PROT_EXEC);
+ return sb->Cond(3, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ANY_BITS,
+ denied_flag_mask,
+ sb->Trap(sandbox::CrashSIGSYS_Handler, NULL),
+ sb->Cond(2, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ANY_BITS,
+ denied_prot_mask,
+ sb->Trap(sandbox::CrashSIGSYS_Handler, NULL),
+ ErrorCode(ErrorCode::ERR_ALLOWED)));
+ break;
+ }
+
+ case __NR_mprotect: {
+ // TODO(jln, keescook, drewry): Limit the use of mmap by adding
+ // some features to linux kernel.
+ uint32_t denied_mask = ~(PROT_READ | PROT_WRITE | PROT_EXEC);
+ return sb->Cond(2, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ANY_BITS,
+ denied_mask,
+ sb->Trap(sandbox::CrashSIGSYS_Handler, NULL),
+ ErrorCode(ErrorCode::ERR_ALLOWED));
+ break;
+ }
+
+ case __NR_open:
+ // EPERM instead of SIGSYS as glibc tries to open files in /proc.
+ // TODO(hamaji): Remove this when we switch to newlib.
+ ret = ErrorCode(EPERM);
+ break;
+
+ case __NR_brk:
+ // tcmalloc uses brk because HAVE_SBRK is set in
+ // third_party/tcmalloc/chromium/src/config_linux.h
+ // TODO(hamaji): We can get rid of this when we stop using
+ // tcmalloc for non-SFI nacl_helper.
+ ret = ErrorCode(ErrorCode::ERR_ALLOWED);
+ break;
+
+ case __NR_madvise:
+ // tcmalloc calls madvise in TCMalloc_SystemRelease.
+ // TODO(hamaji): We can get rid of this when we stop using
+ // tcmalloc for non-SFI nacl_helper.
+ ret = ErrorCode(EPERM);
+ break;
+
+ default:
+ ret = sb->Trap(sandbox::CrashSIGSYS_Handler, NULL);
+ break;
+ }
+ return ret;
+}
+
void RunSandboxSanityChecks() {
errno = 0;
// Make a ptrace request with an invalid PID.
@@ -172,3 +428,16 @@ bool InitializeBPFSandbox() {
#endif // defined(USE_SECCOMP_BPF)
return false;
}
+
+bool InitializeBPFSandboxForNonSfi() {
+#if defined(USE_SECCOMP_BPF)
+ bool sandbox_is_initialized = content::InitializeSandbox(
+ scoped_ptr<SandboxBPFPolicy>(new NonSfiNaClBPFSandboxPolicy()));
+ if (sandbox_is_initialized) {
+ RunSandboxSanityChecks();
+ return true;
+ }
+#endif // defined(USE_SECCOMP_BPF)
+ LOG(FATAL) << "InitializeBPFSandboxForNonSfi failed";
+ return false;
+}

Powered by Google App Engine
This is Rietveld 408576698