summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjln@chromium.org <jln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-09 00:04:16 +0000
committerjln@chromium.org <jln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-09 00:04:16 +0000
commit632f4add724e1c0dcf5f811abac85f4da1a72a20 (patch)
treee56006650c59d31fa6b425314cfaaab71b9662ed
parent88f73bd643e264b2df0b5ec8199263f09b368159 (diff)
downloadchromium_src-632f4add724e1c0dcf5f811abac85f4da1a72a20.zip
chromium_src-632f4add724e1c0dcf5f811abac85f4da1a72a20.tar.gz
chromium_src-632f4add724e1c0dcf5f811abac85f4da1a72a20.tar.bz2
Linux sandbox: always restrict clone() in baseline policy.
Always restrict clone() to thread creation in the baseline policy. This CL does the following - Extend RestrictCloneToThreadsAndEPERMFork to support Android. - Always EPERM anything that looks like fork() - Add unit tests to the baseline policy related to clone() and fork(). This CL also modifies any other BPF policy so that if clone() was not restricted before, it remains so. That is, only renderers and PPAPI processes have clone() restrictions applied to them, as before. BUG=367986 R=jorgelo@chromium.org, mdempsky@chromium.org Review URL: https://codereview.chromium.org/270613008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@269114 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--components/nacl/loader/sandbox_linux/nacl_bpf_sandbox_linux.cc1
-rw-r--r--content/common/sandbox_linux/android/sandbox_bpf_base_policy_android.cc2
-rw-r--r--content/common/sandbox_linux/bpf_gpu_policy_linux.cc2
-rw-r--r--content/common/sandbox_linux/bpf_ppapi_policy_linux.cc2
-rw-r--r--content/common/sandbox_linux/bpf_renderer_policy_linux.cc2
-rw-r--r--sandbox/linux/sandbox_linux_test_sources.gypi1
-rw-r--r--sandbox/linux/seccomp-bpf-helpers/baseline_policy.cc4
-rw-r--r--sandbox/linux/seccomp-bpf-helpers/baseline_policy_unittest.cc114
-rw-r--r--sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc57
-rw-r--r--sandbox/linux/seccomp-bpf-helpers/syscall_sets.cc2
-rw-r--r--sandbox/linux/tests/unit_tests.cc1
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"