summaryrefslogtreecommitdiffstats
path: root/sandbox
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 /sandbox
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
Diffstat (limited to 'sandbox')
-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
6 files changed, 164 insertions, 15 deletions
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"