diff options
11 files changed, 169 insertions, 19 deletions
diff --git a/components/nacl/loader/sandbox_linux/nacl_bpf_sandbox_linux.cc b/components/nacl/loader/sandbox_linux/nacl_bpf_sandbox_linux.cc index e123523..8071d4f 100644 --- a/components/nacl/loader/sandbox_linux/nacl_bpf_sandbox_linux.cc +++ b/components/nacl/loader/sandbox_linux/nacl_bpf_sandbox_linux.cc @@ -74,6 +74,7 @@ ErrorCode NaClBPFSandboxPolicy::EvaluateSyscall( sandbox::SandboxBPF* sb, int sysno) const { DCHECK(baseline_policy_); switch (sysno) { + case __NR_clone: // TODO(jln): restrict parameters. // TODO(jln): NaCl's GDB debug stub uses the following socket system calls, // see if it can be restricted a bit. #if defined(__x86_64__) || defined(__arm__) diff --git a/content/common/sandbox_linux/android/sandbox_bpf_base_policy_android.cc b/content/common/sandbox_linux/android/sandbox_bpf_base_policy_android.cc index 6335dfc..b7bd3fa 100644 --- a/content/common/sandbox_linux/android/sandbox_bpf_base_policy_android.cc +++ b/content/common/sandbox_linux/android/sandbox_bpf_base_policy_android.cc @@ -21,6 +21,8 @@ sandbox::ErrorCode SandboxBPFBasePolicyAndroid::EvaluateSyscall( bool override_and_allow = false; switch (sysno) { + // TODO(rsesek): restrict clone parameters. + case __NR_clone: case __NR_epoll_pwait: case __NR_flock: case __NR_getpriority: diff --git a/content/common/sandbox_linux/bpf_gpu_policy_linux.cc b/content/common/sandbox_linux/bpf_gpu_policy_linux.cc index 1570114..2ad07a3 100644 --- a/content/common/sandbox_linux/bpf_gpu_policy_linux.cc +++ b/content/common/sandbox_linux/bpf_gpu_policy_linux.cc @@ -166,6 +166,8 @@ GpuProcessPolicy::~GpuProcessPolicy() {} ErrorCode GpuProcessPolicy::EvaluateSyscall(SandboxBPF* sandbox, int sysno) const { switch (sysno) { + // TODO(jln): restrict clone. + case __NR_clone: case __NR_ioctl: #if defined(__i386__) || defined(__x86_64__) // The Nvidia driver uses flags not in the baseline policy diff --git a/content/common/sandbox_linux/bpf_ppapi_policy_linux.cc b/content/common/sandbox_linux/bpf_ppapi_policy_linux.cc index 3a59bfc..4c80622 100644 --- a/content/common/sandbox_linux/bpf_ppapi_policy_linux.cc +++ b/content/common/sandbox_linux/bpf_ppapi_policy_linux.cc @@ -24,8 +24,6 @@ PpapiProcessPolicy::~PpapiProcessPolicy() {} ErrorCode PpapiProcessPolicy::EvaluateSyscall(SandboxBPF* sandbox, int sysno) const { switch (sysno) { - case __NR_clone: - return sandbox::RestrictCloneToThreadsAndEPERMFork(sandbox); case __NR_pread64: case __NR_pwrite64: case __NR_sched_get_priority_max: diff --git a/content/common/sandbox_linux/bpf_renderer_policy_linux.cc b/content/common/sandbox_linux/bpf_renderer_policy_linux.cc index eba2eca..2679778 100644 --- a/content/common/sandbox_linux/bpf_renderer_policy_linux.cc +++ b/content/common/sandbox_linux/bpf_renderer_policy_linux.cc @@ -24,8 +24,6 @@ RendererProcessPolicy::~RendererProcessPolicy() {} ErrorCode RendererProcessPolicy::EvaluateSyscall(SandboxBPF* sandbox, int sysno) const { switch (sysno) { - case __NR_clone: - return sandbox::RestrictCloneToThreadsAndEPERMFork(sandbox); case __NR_ioctl: return sandbox::RestrictIoctl(sandbox); case __NR_prctl: diff --git a/sandbox/linux/sandbox_linux_test_sources.gypi b/sandbox/linux/sandbox_linux_test_sources.gypi index b2ecac5..bf41471 100644 --- a/sandbox/linux/sandbox_linux_test_sources.gypi +++ b/sandbox/linux/sandbox_linux_test_sources.gypi @@ -31,6 +31,7 @@ }], [ 'use_seccomp_bpf==1', { 'sources': [ + 'seccomp-bpf-helpers/baseline_policy_unittest.cc', 'seccomp-bpf/bpf_tests_unittest.cc', 'seccomp-bpf/codegen_unittest.cc', 'seccomp-bpf/errorcode_unittest.cc', diff --git a/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc b/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc index 79b5b02..217bdac 100644 --- a/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc +++ b/sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc @@ -97,6 +97,10 @@ ErrorCode EvaluateSyscallImpl(int fs_denied_errno, return ErrorCode(ErrorCode::ERR_ALLOWED); } + if (sysno == __NR_clone) { + return RestrictCloneToThreadsAndEPERMFork(sandbox); + } + #if defined(__x86_64__) || defined(__arm__) if (sysno == __NR_socketpair) { // Only allow AF_UNIX, PF_UNIX. Crash if anything else is seen. diff --git a/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc b/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc new file mode 100644 index 0000000..281d09a --- /dev/null +++ b/sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc @@ -0,0 +1,114 @@ +// Copyright 2014 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 "sandbox/linux/seccomp-bpf-helpers/baseline_policy.h" + +#include <errno.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +#include "base/posix/eintr_wrapper.h" +#include "base/threading/thread.h" +#include "build/build_config.h" +#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h" +#include "sandbox/linux/seccomp-bpf/bpf_tests.h" +#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" +#include "sandbox/linux/services/linux_syscalls.h" +#include "sandbox/linux/services/thread_helpers.h" +#include "sandbox/linux/tests/unit_tests.h" + +namespace sandbox { + +namespace { + +// |pid| is the return value of a fork()-like call. This +// makes sure that if fork() succeeded the child exits +// and the parent waits for it. +void HandlePostForkReturn(pid_t pid) { + const int kChildExitCode = 1; + if (pid > 0) { + int status = 0; + PCHECK(pid == HANDLE_EINTR(waitpid(pid, &status, 0))); + CHECK(WIFEXITED(status)); + CHECK_EQ(kChildExitCode, WEXITSTATUS(status)); + } else if (pid == 0) { + _exit(kChildExitCode); + } +} + +// Check that HandlePostForkReturn works. +TEST(BaselinePolicy, HandlePostForkReturn) { + pid_t pid = fork(); + HandlePostForkReturn(pid); +} + +BPF_TEST_C(BaselinePolicy, FchmodErrno, BaselinePolicy) { + int ret = fchmod(-1, 07777); + BPF_ASSERT_EQ(-1, ret); + // Without the sandbox, this would EBADF instead. + BPF_ASSERT_EQ(EPERM, errno); +} + +// TODO(jln): make this work with the sanitizers. +#if !defined(ADDRESS_SANITIZER) && !defined(THREAD_SANITIZER) + +BPF_TEST_C(BaselinePolicy, ForkErrno, BaselinePolicy) { + errno = 0; + pid_t pid = fork(); + const int fork_errno = errno; + HandlePostForkReturn(pid); + + BPF_ASSERT_EQ(-1, pid); + BPF_ASSERT_EQ(EPERM, fork_errno); +} + +pid_t ForkX86Glibc() { + return syscall(__NR_clone, CLONE_PARENT_SETTID | SIGCHLD); +} + +BPF_TEST_C(BaselinePolicy, ForkX86Eperm, BaselinePolicy) { + errno = 0; + pid_t pid = ForkX86Glibc(); + const int fork_errno = errno; + HandlePostForkReturn(pid); + + BPF_ASSERT_EQ(-1, pid); + BPF_ASSERT_EQ(EPERM, fork_errno); +} + +pid_t ForkARMGlibc() { + return syscall(__NR_clone, + CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD); +} + +BPF_TEST_C(BaselinePolicy, ForkArmEperm, BaselinePolicy) { + errno = 0; + pid_t pid = ForkARMGlibc(); + const int fork_errno = errno; + HandlePostForkReturn(pid); + + BPF_ASSERT_EQ(-1, pid); + BPF_ASSERT_EQ(EPERM, fork_errno); +} + +BPF_TEST_C(BaselinePolicy, CreateThread, BaselinePolicy) { + base::Thread thread("sandbox_tests"); + BPF_ASSERT(thread.Start()); +} + +BPF_DEATH_TEST_C(BaselinePolicy, + DisallowedCloneFlagCrashes, + DEATH_MESSAGE(GetCloneErrorMessageContentForTests()), + BaselinePolicy) { + pid_t pid = syscall(__NR_clone, CLONE_THREAD | SIGCHLD); + HandlePostForkReturn(pid); +} + +#endif // !defined(ADDRESS_SANITIZER) && !defined(THREAD_SANITIZER) + +} // namespace + +} // namespace sandbox diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc index 2f46401..29c5910 100644 --- a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc +++ b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc @@ -19,6 +19,7 @@ #include "base/basictypes.h" #include "base/logging.h" +#include "build/build_config.h" #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h" #include "sandbox/linux/seccomp-bpf/linux_seccomp.h" #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" @@ -51,25 +52,53 @@ inline bool IsArchitectureI386() { #endif } +inline bool IsAndroid() { +#if defined(OS_ANDROID) + return true; +#else + return false; +#endif +} + } // namespace. namespace sandbox { +// Allow Glibc's and Android pthread creation flags, crash on any other +// thread creation attempts and EPERM attempts to use neither +// CLONE_VM, nor CLONE_THREAD, which includes all fork() implementations. ErrorCode RestrictCloneToThreadsAndEPERMFork(SandboxBPF* sandbox) { - // Glibc's pthread. - return sandbox->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), - sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, - CLONE_PARENT_SETTID | SIGCHLD, - ErrorCode(EPERM), - // ARM - sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, - CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, - ErrorCode(EPERM), - sandbox->Trap(SIGSYSCloneFailure, NULL)))); + if (!IsAndroid()) { + const uint64_t kGlibcPthreadFlags = + CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD | + CLONE_SYSVSEM | CLONE_SETTLS | CLONE_PARENT_SETTID | + CLONE_CHILD_CLEARTID; + + return sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, + kGlibcPthreadFlags, + ErrorCode(ErrorCode::ERR_ALLOWED), + sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ANY_BITS, + CLONE_VM | CLONE_THREAD, + sandbox->Trap(SIGSYSCloneFailure, NULL), + ErrorCode(EPERM))); + } else { + const uint64_t kAndroidCloneMask = CLONE_VM | CLONE_FS | CLONE_FILES | + CLONE_SIGHAND | CLONE_THREAD | + CLONE_SYSVSEM; + const uint64_t kObsoleteAndroidCloneMask = + kAndroidCloneMask | CLONE_DETACHED; + + return sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, + kAndroidCloneMask, + ErrorCode(ErrorCode::ERR_ALLOWED), + sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, + kObsoleteAndroidCloneMask, + ErrorCode(ErrorCode::ERR_ALLOWED), + sandbox->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_HAS_ANY_BITS, + CLONE_VM | CLONE_THREAD, + sandbox->Trap(SIGSYSCloneFailure, NULL), + ErrorCode(EPERM)))); + } } ErrorCode RestrictPrctl(SandboxBPF* sandbox) { diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc b/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc index 792807a..5f8785e 100644 --- a/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc +++ b/sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc @@ -350,7 +350,6 @@ bool SyscallSets::IsKernelInternalApi(int sysno) { // This should be thought through in conjunction with IsFutex(). bool SyscallSets::IsAllowedProcessStartOrDeath(int sysno) { switch (sysno) { - case __NR_clone: // TODO(jln): restrict flags. case __NR_exit: case __NR_exit_group: case __NR_wait4: @@ -359,6 +358,7 @@ bool SyscallSets::IsAllowedProcessStartOrDeath(int sysno) { case __NR_waitpid: #endif return true; + case __NR_clone: // Should be parameter-restricted. case __NR_setns: // Privileged. case __NR_fork: #if defined(__i386__) || defined(__x86_64__) diff --git a/sandbox/linux/tests/unit_tests.cc b/sandbox/linux/tests/unit_tests.cc index 282c718..d3ee81b 100644 --- a/sandbox/linux/tests/unit_tests.cc +++ b/sandbox/linux/tests/unit_tests.cc @@ -12,6 +12,7 @@ #include <unistd.h> #include "base/file_util.h" +#include "base/posix/eintr_wrapper.h" #include "base/third_party/valgrind/valgrind.h" #include "build/build_config.h" #include "sandbox/linux/tests/unit_tests.h" |