summaryrefslogtreecommitdiffstats
path: root/chromium/sandbox
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/sandbox')
-rw-r--r--chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy_android.cc9
-rw-r--r--chromium/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc22
-rw-r--r--chromium/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h10
-rw-r--r--chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc33
-rw-r--r--chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h4
-rw-r--r--chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc231
-rw-r--r--chromium/sandbox/win/fuzzer/fuzzer_types.h38
-rw-r--r--chromium/sandbox/win/fuzzer/sandbox_ipc_fuzzer.cc28
8 files changed, 301 insertions, 74 deletions
diff --git a/chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy_android.cc b/chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy_android.cc
index a4124ba74ef..ba2d363a225 100644
--- a/chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy_android.cc
+++ b/chromium/sandbox/linux/seccomp-bpf-helpers/baseline_policy_android.cc
@@ -140,9 +140,6 @@ ResultExpr BaselinePolicyAndroid::EvaluateSyscall(int sysno) const {
case __NR_socket:
#endif
- // Ptrace is allowed so the Breakpad Microdumper can fork in a renderer
- // and then ptrace the parent.
- case __NR_ptrace:
override_and_allow = true;
break;
}
@@ -152,6 +149,12 @@ ResultExpr BaselinePolicyAndroid::EvaluateSyscall(int sysno) const {
return Allow();
}
+ // Ptrace is allowed so the crash reporter can fork in a renderer
+ // and then ptrace the parent. https://crbug.com/933418
+ if (sysno == __NR_ptrace) {
+ return RestrictPtrace();
+ }
+
// https://crbug.com/644759
if (sysno == __NR_rt_tgsigqueueinfo) {
const Arg<pid_t> tgid(0);
diff --git a/chromium/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc b/chromium/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc
index 5adc1a7a4d4..7514f9a4a0a 100644
--- a/chromium/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc
+++ b/chromium/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.cc
@@ -33,6 +33,7 @@
#define SECCOMP_MESSAGE_IOCTL_CONTENT "ioctl() failure"
#define SECCOMP_MESSAGE_KILL_CONTENT "(tg)kill() failure"
#define SECCOMP_MESSAGE_FUTEX_CONTENT "futex() failure"
+#define SECCOMP_MESSAGE_PTRACE_CONTENT "ptrace() failure"
namespace {
@@ -305,6 +306,19 @@ intptr_t SIGSYSFutexFailure(const struct arch_seccomp_data& args,
_exit(1);
}
+intptr_t SIGSYSPtraceFailure(const struct arch_seccomp_data& args,
+ void* /* aux */) {
+ static const char kSeccompPtraceError[] =
+ __FILE__ ":**CRASHING**:" SECCOMP_MESSAGE_PTRACE_CONTENT "\n";
+ WriteToStdErr(kSeccompPtraceError, sizeof(kSeccompPtraceError) - 1);
+ SetSeccompCrashKey(args);
+ volatile int ptrace_op = args.args[0];
+ volatile char* addr = reinterpret_cast<volatile char*>(ptrace_op & 0xFFF);
+ *addr = '\0';
+ for (;;)
+ _exit(1);
+}
+
intptr_t SIGSYSSchedHandler(const struct arch_seccomp_data& args,
void* aux) {
switch (args.nr) {
@@ -363,6 +377,10 @@ bpf_dsl::ResultExpr CrashSIGSYSFutex() {
return bpf_dsl::Trap(SIGSYSFutexFailure, NULL);
}
+bpf_dsl::ResultExpr CrashSIGSYSPtrace() {
+ return bpf_dsl::Trap(SIGSYSPtraceFailure, NULL);
+}
+
bpf_dsl::ResultExpr RewriteSchedSIGSYS() {
return bpf_dsl::Trap(SIGSYSSchedHandler, NULL);
}
@@ -401,4 +419,8 @@ const char* GetFutexErrorMessageContentForTests() {
return SECCOMP_MESSAGE_FUTEX_CONTENT;
}
+const char* GetPtraceErrorMessageContentForTests() {
+ return SECCOMP_MESSAGE_PTRACE_CONTENT;
+}
+
} // namespace sandbox.
diff --git a/chromium/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h b/chromium/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h
index b32fd6fedd4..baac3b61447 100644
--- a/chromium/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h
+++ b/chromium/sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h
@@ -25,8 +25,8 @@ struct arch_seccomp_data;
SANDBOX_EXPORT intptr_t
CrashSIGSYS_Handler(const struct arch_seccomp_data& args, void* aux);
-// The following three handlers are suitable to report failures with the
-// clone(), prctl() and ioctl() system calls respectively.
+// The following seven handlers are suitable to report failures for specific
+// system calls with additional information.
// The crashing address will be (clone_flags & 0xFFFFFF), where clone_flags is
// the clone(2) argument, extracted from |args|.
@@ -48,6 +48,10 @@ SANDBOX_EXPORT intptr_t
// argument.
SANDBOX_EXPORT intptr_t
SIGSYSFutexFailure(const struct arch_seccomp_data& args, void* aux);
+// The crashing address will be (op & 0xFFF), where op is the second
+// argument.
+SANDBOX_EXPORT intptr_t
+SIGSYSPtraceFailure(const struct arch_seccomp_data& args, void* aux);
// If the syscall is not being called on the current tid, crashes in the same
// way as CrashSIGSYS_Handler. Otherwise, returns the result of calling the
// syscall with the pid argument set to 0 (which for these calls means the
@@ -66,6 +70,7 @@ SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSPrctl();
SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSIoctl();
SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSKill();
SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSFutex();
+SANDBOX_EXPORT bpf_dsl::ResultExpr CrashSIGSYSPtrace();
SANDBOX_EXPORT bpf_dsl::ResultExpr RewriteSchedSIGSYS();
// Allocates a crash key so that Seccomp information can be recorded.
@@ -79,6 +84,7 @@ SANDBOX_EXPORT const char* GetPrctlErrorMessageContentForTests();
SANDBOX_EXPORT const char* GetIoctlErrorMessageContentForTests();
SANDBOX_EXPORT const char* GetKillErrorMessageContentForTests();
SANDBOX_EXPORT const char* GetFutexErrorMessageContentForTests();
+SANDBOX_EXPORT const char* GetPtraceErrorMessageContentForTests();
} // namespace sandbox.
diff --git a/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc b/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
index 2577f02f2e9..55394a791a5 100644
--- a/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
+++ b/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc
@@ -6,7 +6,6 @@
#include <errno.h>
#include <fcntl.h>
-#include <fcntl.h>
#include <linux/net.h>
#include <sched.h>
#include <signal.h>
@@ -31,10 +30,17 @@
#include "sandbox/linux/system_headers/linux_syscalls.h"
#include "sandbox/linux/system_headers/linux_time.h"
-// PNaCl toolchain does not provide sys/ioctl.h header.
+// PNaCl toolchain does not provide sys/ioctl.h and sys/ptrace.h headers.
#if !defined(OS_NACL_NONSFI)
#include <sys/ioctl.h>
-#endif
+#include <sys/ptrace.h>
+#if !defined(PTRACE_GET_THREAD_AREA) && defined(OS_LINUX) && \
+ !defined(OS_CHROMEOS)
+// Also include asm/ptrace-abi.h since ptrace.h in older libc (for instance
+// the one in Ubuntu 16.04 LTS) is missing PTRACE_GET_THREAD_AREA.
+#include <asm/ptrace-abi.h>
+#endif // !PTRACE_GET_THREAD_AREA && OS_LINUX && !OS_CHROMEOS
+#endif // !OS_NACL_NONSFI
#if defined(OS_ANDROID)
@@ -383,4 +389,25 @@ ResultExpr RestrictPrlimit(pid_t target_pid) {
return If(AnyOf(pid == 0, pid == target_pid), Allow()).Else(Error(EPERM));
}
+#if !defined(OS_NACL_NONSFI)
+ResultExpr RestrictPtrace() {
+ const Arg<int> request(0);
+ return Switch(request).CASES((
+#if !defined(__aarch64__)
+ PTRACE_GETREGS,
+ PTRACE_GETFPREGS,
+ PTRACE_GET_THREAD_AREA,
+#endif
+#if defined(__arm__)
+ PTRACE_GETVFPREGS,
+#endif
+ PTRACE_GETREGSET,
+ PTRACE_PEEKDATA,
+ PTRACE_ATTACH,
+ PTRACE_DETACH),
+ Allow())
+ .Default(CrashSIGSYSPtrace());
+}
+#endif // defined(OS_NACL_NONSFI)
+
} // namespace sandbox.
diff --git a/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h b/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h
index 71c56093d92..cb563dfc550 100644
--- a/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h
+++ b/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h
@@ -103,6 +103,10 @@ SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictGetRandom();
// gracefully; see crbug.com/160157.
SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictPrlimit(pid_t target_pid);
+// Restrict ptrace() to just read operations that are needed for crash
+// reporting. See https://crbug.com/933418 for details.
+SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictPtrace();
+
} // namespace sandbox.
#endif // SANDBOX_LINUX_SECCOMP_BPF_HELPERS_SYSCALL_PARAMETERS_RESTRICTIONS_H_
diff --git a/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc b/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc
index 327da2bea41..d109c6186c9 100644
--- a/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc
+++ b/chromium/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions_unittests.cc
@@ -5,14 +5,20 @@
#include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h"
#include <errno.h>
+#include <fcntl.h>
+#include <linux/elf.h>
#include <sched.h>
+#include <sys/prctl.h>
+#include <sys/ptrace.h>
#include <sys/resource.h>
#include <sys/syscall.h>
#include <sys/types.h>
+#include <sys/user.h>
#include <time.h>
#include <unistd.h>
#include "base/bind.h"
+#include "base/posix/eintr_wrapper.h"
#include "base/single_thread_task_runner.h"
#include "base/synchronization/waitable_event.h"
#include "base/system/sys_info.h"
@@ -242,6 +248,231 @@ BPF_DEATH_TEST_C(ParameterRestrictions,
getrusage(RUSAGE_CHILDREN, &usage);
}
+// ptace() Tests ///////////////////////////////////////////////////////////////
+
+// Tests for ptrace involve a slightly complex setup in order to properly test
+// ptrace and the variety of ways it is access-checked. The BPF_TEST macro,
+// the body of which already runs in its own process, spawns another process
+// called the "tracee". The "tracee" then spawns another process called the
+// "tracer". The child then traces the parent and performs the test operations.
+// The tracee must be careful to un-stop the tracer if the tracee expects to
+// die.
+
+class RestrictPtracePolicy : public bpf_dsl::Policy {
+ public:
+ RestrictPtracePolicy() = default;
+ ~RestrictPtracePolicy() override = default;
+
+ ResultExpr EvaluateSyscall(int sysno) const override {
+ switch (sysno) {
+ case __NR_ptrace:
+ return RestrictPtrace();
+ default:
+ return Allow();
+ }
+ }
+};
+
+constexpr char kExitPtraceChildClean = '!';
+
+class PtraceTestHarness {
+ public:
+ using PtraceChildTracerFunc = void (*)(pid_t tracee);
+
+ PtraceTestHarness(PtraceChildTracerFunc tracer_func, bool expect_death)
+ : tracer_func_(tracer_func), expect_death_(expect_death) {}
+ ~PtraceTestHarness() = default;
+
+ void Run() {
+ // Fork the tracee process that will be traced by its child.
+ pid_t pid = fork();
+ BPF_ASSERT_GE(pid, 0);
+
+ if (pid == 0) {
+ RunTracee();
+ } else {
+ // The tracee should always exit cleanly.
+ int status = 0;
+ int rv = waitpid(pid, &status, 0);
+ BPF_ASSERT_EQ(pid, rv);
+ BPF_ASSERT_EQ(0, WEXITSTATUS(status));
+ }
+ }
+
+ private:
+ void RunTracee() {
+ // Create a communications pipe between tracer and tracee.
+ int rv = pipe2(pipes_, O_NONBLOCK);
+ BPF_ASSERT_EQ(0, rv);
+
+ // Pipes for redirecting output.
+ int output_pipes[2];
+ BPF_ASSERT_EQ(0, pipe(output_pipes));
+
+ // Create the tracer process.
+ pid_t pid = fork();
+ BPF_ASSERT_GE(pid, 0);
+
+ if (pid == 0) {
+ // Close the pipe read ends and redirect output.
+ close(pipes_[0]);
+ close(output_pipes[0]);
+
+ close(STDOUT_FILENO);
+ dup2(output_pipes[1], STDOUT_FILENO);
+
+ close(STDERR_FILENO);
+ dup2(output_pipes[1], STDERR_FILENO);
+
+ RunTracer();
+
+ close(output_pipes[1]);
+ } else {
+ close(pipes_[1]);
+ close(output_pipes[1]);
+
+ // Ensure the tracer can trace the tracee. This may fail on systems
+ // without YAMA, so the result is not checked.
+ prctl(PR_SET_PTRACER, pid);
+
+ char c = 0;
+ while (c != kExitPtraceChildClean) {
+ // Read from the control channel in a non-blocking fashion.
+ // If no data are present, loop.
+ ignore_result(read(pipes_[0], &c, 1));
+
+ // Poll the exit status of the child.
+ int status = 0;
+ rv = waitpid(pid, &status, WNOHANG);
+ if (rv != 0) {
+ BPF_ASSERT_EQ(pid, rv);
+ CheckTracerStatus(status, output_pipes[0]);
+ _exit(0);
+ }
+ }
+
+ _exit(0);
+ }
+ }
+
+ void RunTracer() {
+ pid_t ppid = getppid();
+ BPF_ASSERT_NE(0, ppid);
+
+ // Attach to the tracee and then call out to the test function.
+ BPF_ASSERT_EQ(0, ptrace(PTRACE_ATTACH, ppid, nullptr, nullptr));
+
+ tracer_func_(ppid);
+
+ BPF_ASSERT_EQ(1, HANDLE_EINTR(write(pipes_[1], &kExitPtraceChildClean, 1)));
+ close(pipes_[1]);
+
+ _exit(0);
+ }
+
+ void CheckTracerStatus(int status, int output_pipe) {
+ // The child has exited. Test that it did so in the way we were
+ // expecting.
+ if (expect_death_) {
+ // This duplicates a bit of what //sandbox/linux/tests/unit_tests.cc does
+ // but that code is not shareable here.
+ std::string output;
+ const size_t kBufferSize = 1024;
+ size_t total_bytes_read = 0;
+ ssize_t read_this_pass = 0;
+ do {
+ output.resize(output.size() + kBufferSize);
+ read_this_pass = HANDLE_EINTR(
+ read(output_pipe, &output[total_bytes_read], kBufferSize));
+ if (read_this_pass >= 0) {
+ total_bytes_read += read_this_pass;
+ output.resize(total_bytes_read);
+ }
+ } while (read_this_pass > 0);
+
+#if !defined(SANDBOX_USES_BASE_TEST_SUITE)
+ const bool subprocess_got_sigsegv =
+ WIFSIGNALED(status) && (SIGSEGV == WTERMSIG(status));
+#else
+ // This hack is required when a signal handler is installed
+ // for SEGV that will _exit(1).
+ const bool subprocess_got_sigsegv =
+ WIFEXITED(status) && (1 == WEXITSTATUS(status));
+#endif
+ BPF_ASSERT(subprocess_got_sigsegv);
+ BPF_ASSERT_NE(output.find(GetPtraceErrorMessageContentForTests()),
+ std::string::npos);
+ } else {
+ BPF_ASSERT(WIFEXITED(status));
+ BPF_ASSERT_EQ(0, WEXITSTATUS(status));
+ }
+ }
+
+ PtraceChildTracerFunc tracer_func_;
+ bool expect_death_;
+ int pipes_[2];
+
+ DISALLOW_COPY_AND_ASSIGN(PtraceTestHarness);
+};
+
+BPF_TEST_C(ParameterRestrictions,
+ ptrace_getregs_allowed,
+ RestrictPtracePolicy) {
+ auto tracer = [](pid_t pid) {
+#if defined(__arm__)
+ user_regs regs;
+#else
+ user_regs_struct regs;
+#endif
+ iovec iov;
+ iov.iov_base = &regs;
+ iov.iov_len = sizeof(regs);
+ BPF_ASSERT_EQ(0, ptrace(PTRACE_GETREGSET, pid,
+ reinterpret_cast<void*>(NT_PRSTATUS), &iov));
+
+ BPF_ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, nullptr, nullptr));
+ };
+ PtraceTestHarness(tracer, false).Run();
+}
+
+BPF_TEST_C(ParameterRestrictions,
+ ptrace_syscall_blocked,
+ RestrictPtracePolicy) {
+ auto tracer = [](pid_t pid) {
+ // The tracer is about to die. Make sure the tracee is not stopped so it
+ // can reap it and inspect its death signal.
+ kill(pid, SIGCONT);
+
+ BPF_ASSERT_NE(0, ptrace(PTRACE_SYSCALL, 0, nullptr, nullptr));
+ };
+ PtraceTestHarness(tracer, true).Run();
+}
+
+BPF_TEST_C(ParameterRestrictions,
+ ptrace_setregs_blocked,
+ RestrictPtracePolicy) {
+ auto tracer = [](pid_t pid) {
+#if defined(__arm__)
+ user_regs regs;
+#else
+ user_regs_struct regs;
+#endif
+ iovec iov;
+ iov.iov_base = &regs;
+ iov.iov_len = sizeof(regs);
+ BPF_ASSERT_EQ(0, ptrace(PTRACE_GETREGSET, pid,
+ reinterpret_cast<void*>(NT_PRSTATUS), &iov));
+
+ // The tracer is about to die. Make sure the tracee is not stopped so it
+ // can reap it and inspect its death signal.
+ kill(pid, SIGCONT);
+
+ BPF_ASSERT_NE(0, ptrace(PTRACE_SETREGSET, pid,
+ reinterpret_cast<void*>(NT_PRSTATUS), &iov));
+ };
+ PtraceTestHarness(tracer, true).Run();
+}
+
} // namespace
} // namespace sandbox
diff --git a/chromium/sandbox/win/fuzzer/fuzzer_types.h b/chromium/sandbox/win/fuzzer/fuzzer_types.h
deleted file mode 100644
index 8ff06d0d15c..00000000000
--- a/chromium/sandbox/win/fuzzer/fuzzer_types.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2017 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.
-
-#ifndef SANDBOX_FUZZER_TYPES_H_
-#define SANDBOX_FUZZER_TYPES_H_
-
-#include <stdint.h>
-
-// This file defines Windows types for the sandbox_ipc_fuzzer target when
-// compiled on Linux.
-//
-// It also disables Windows exception handling to ensure any crashes are
-// captured by the fuzzing harness.
-
-// Disable exceptions.
-#if defined(__try)
-#undef __try
-#endif
-#define __try if(true)
-#if defined(__except)
-#undef __except
-#endif
-#define __except(...) if(false)
-
-// Windows types used in sandbox.
-typedef void* HANDLE;
-typedef uint32_t DWORD;
-typedef int32_t LONG;
-typedef uint32_t ULONG;
-typedef uint32_t* ULONG_PTR;
-typedef LONG NTSTATUS;
-typedef void PROCESS_INFORMATION;
-
-// __stdcall is used in one place. TODO(wfh): replace with WINAPI.
-#define __stdcall
-
-#endif // SANDBOX_FUZZER_TYPES_H_
diff --git a/chromium/sandbox/win/fuzzer/sandbox_ipc_fuzzer.cc b/chromium/sandbox/win/fuzzer/sandbox_ipc_fuzzer.cc
deleted file mode 100644
index 1c2ea8c5430..00000000000
--- a/chromium/sandbox/win/fuzzer/sandbox_ipc_fuzzer.cc
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2017 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 <stddef.h>
-#include <stdint.h>
-
-#include "sandbox/win/src/crosscall_server.h"
-#include "sandbox/win/src/ipc_args.h"
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- using namespace sandbox;
-
- uint32_t output_size = 0;
- std::unique_ptr<CrossCallParamsEx> params(CrossCallParamsEx::CreateFromBuffer(
- const_cast<uint8_t*>(data), size, &output_size));
-
- if (!params.get())
- return 0;
-
- uint32_t tag = params->GetTag();
- IPCParams ipc_params = {0};
- ipc_params.ipc_tag = tag;
- void* args[kMaxIpcParams];
- GetArgs(params.get(), &ipc_params, args);
- ReleaseArgs(&ipc_params, args);
- return 0;
-}