diff options
author | hidehiko <hidehiko@chromium.org> | 2015-04-30 22:16:05 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-05-01 05:16:34 +0000 |
commit | aca25fdd9772e974b0399c24590fd864cebfcbab (patch) | |
tree | 04504d176310117a6a6f2c214a56587d3f5468ee | |
parent | 7f841930479d87f5c65082d26cc764883c1cd5dc (diff) | |
download | chromium_src-aca25fdd9772e974b0399c24590fd864cebfcbab.zip chromium_src-aca25fdd9772e974b0399c24590fd864cebfcbab.tar.gz chromium_src-aca25fdd9772e974b0399c24590fd864cebfcbab.tar.bz2 |
Non-SFI mode: Enable seccomp-bpf sandbox on nacl_helper_nonsfi.
This CL enables seccomp-bpf sandbox on nacl_helper_nonsfi.
In codegen.cc, static_cast is added as implicit narrowing triggers compiler warning (= error with -Werror), with PNaCl toolchain.
TEST=Ran bots. Ran ./sandbox_linux_unittests and ./nacl_loader_unittests locally with {Debug,Release} * {clang,gcc,msan,tsan} combinations. Ran ./browser_tests --gtest_filter=*NaCl*:*PPAPI* locally with {Release} * {clang,gcc,msan} combinations. Test an app using Non-SFI mode already with --use-nacl-helper-nonsfi.
BUG=358465
Review URL: https://codereview.chromium.org/1104993002
Cr-Commit-Position: refs/heads/master@{#327880}
19 files changed, 166 insertions, 99 deletions
diff --git a/components/nacl/loader/nacl_helper_linux.cc b/components/nacl/loader/nacl_helper_linux.cc index e7e75fb..8206eca 100644 --- a/components/nacl/loader/nacl_helper_linux.cc +++ b/components/nacl/loader/nacl_helper_linux.cc @@ -108,11 +108,7 @@ void BecomeNaClLoader(base::ScopedFD browser_fd, // Finish layer-1 sandbox initialization and initialize the layer-2 sandbox. CHECK(!nacl_sandbox->HasOpenDirectory()); -#if !defined(OS_NACL_NONSFI) - // Currently Layer-two sandbox is not yet supported on nacl_helper_nonsfi. - // TODO(hidehiko): Enable the sandbox. nacl_sandbox->InitializeLayerTwoSandbox(uses_nonsfi_mode); -#endif nacl_sandbox->SealLayerOneSandbox(); nacl_sandbox->CheckSandboxingStateWithPolicy(); diff --git a/components/nacl/loader/nonsfi/nonsfi_sandbox.cc b/components/nacl/loader/nonsfi/nonsfi_sandbox.cc index 2a6d5bc9..25493d6 100644 --- a/components/nacl/loader/nonsfi/nonsfi_sandbox.cc +++ b/components/nacl/loader/nonsfi/nonsfi_sandbox.cc @@ -6,7 +6,6 @@ #include <errno.h> #include <fcntl.h> -#include <linux/futex.h> #include <linux/net.h> #include <sys/mman.h> #include <sys/prctl.h> @@ -22,12 +21,21 @@ #include "sandbox/linux/bpf_dsl/bpf_dsl.h" #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h" #include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h" +#include "sandbox/linux/system_headers/linux_futex.h" #include "sandbox/linux/system_headers/linux_syscalls.h" -#if defined(__arm__) && !defined(MAP_STACK) -// Chrome OS Daisy (ARM) build environment has old headers. -#define MAP_STACK 0x20000 -#endif +// Chrome OS Daisy (ARM) build environment and PNaCl toolchain do not define +// MAP_STACK. +#if !defined(MAP_STACK) +# if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY) +# define MAP_STACK 0x20000 +# else +// Note that, on other architecture, MAP_STACK has different value (e.g. mips' +// MAP_STACK is 0x40000), though Non-SFI is not supported on such +// architectures. +# error "Unknown platform." +# endif +#endif // !defined(MAP_STACK) #define CASES SANDBOX_BPF_DSL_CASES @@ -68,11 +76,14 @@ ResultExpr RestrictFcntlCommands() { ResultExpr RestrictClone() { // We allow clone only for new thread creation. + int clone_flags = + CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | + CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS; +#if !defined(OS_NACL_NONSFI) + clone_flags |= CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID; +#endif const Arg<int> flags(0); - return If(flags == (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | - CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS | - CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID), - Allow()).Else(CrashSIGSYSClone()); + return If(flags == clone_flags, Allow()).Else(CrashSIGSYSClone()); } ResultExpr RestrictFutexOperation() { @@ -131,7 +142,10 @@ ResultExpr RestrictMmap() { #if defined(__x86_64__) || defined(__arm__) ResultExpr RestrictSocketpair() { // Only allow AF_UNIX, PF_UNIX. Crash if anything else is seen. + // Note: PNaCl toolchain does not define PF_UNIX. +#if !defined(OS_NACL_NONSFI) static_assert(AF_UNIX == PF_UNIX, "AF_UNIX must equal PF_UNIX."); +#endif const Arg<int> domain(0); return If(domain == AF_UNIX, Allow()).Else(CrashSIGSYS()); } diff --git a/components/nacl/loader/sandbox_linux/nacl_sandbox_linux.cc b/components/nacl/loader/sandbox_linux/nacl_sandbox_linux.cc index 17b7b84..869658f 100644 --- a/components/nacl/loader/sandbox_linux/nacl_sandbox_linux.cc +++ b/components/nacl/loader/sandbox_linux/nacl_sandbox_linux.cc @@ -30,13 +30,10 @@ #include "sandbox/linux/services/credentials.h" #include "sandbox/linux/services/namespace_sandbox.h" #include "sandbox/linux/services/proc_util.h" +#include "sandbox/linux/services/resource_limits.h" #include "sandbox/linux/services/thread_helpers.h" #include "sandbox/linux/suid/client/setuid_sandbox_client.h" -#if !defined(OS_NACL_NONSFI) -#include "sandbox/linux/services/resource_limits.h" -#endif - namespace nacl { namespace { @@ -66,10 +63,6 @@ bool MaybeSetProcessNonDumpable() { return prctl(PR_GET_DUMPABLE) == 0; } -#if !defined(OS_NACL_NONSFI) -// Currently Layer-two sandbox is not yet supported on nacl_helper_nonsfi. -// This function is used only in InitializeLayerTwoSandbox(). -// TODO(hidehiko): Enable the sandbox. void RestrictAddressSpaceUsage() { #if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \ defined(THREAD_SANITIZER) @@ -100,7 +93,6 @@ void RestrictAddressSpaceUsage() { #endif CHECK(sandbox::ResourceLimits::Lower(RLIMIT_AS, kNewAddressSpaceLimit)); } -#endif // !OS_NACL_NONSFI } // namespace @@ -156,11 +148,6 @@ void NaClSandbox::InitializeLayerOneSandbox() { } } -#if !defined(OS_NACL_NONSFI) -// Currently Layer-two sandbox is not yet supported on nacl_helper_nonsfi. -// TODO(hidehiko): Enable the sandbox. -// Note that CheckForExpectedNumberOfOpenFds() is just referred from -// InitializeLayerTwoSandbox(). Enable them together. void NaClSandbox::CheckForExpectedNumberOfOpenFds() { // We expect to have the following FDs open: // 1-3) stdin, stdout, stderr. @@ -198,10 +185,13 @@ void NaClSandbox::InitializeLayerTwoSandbox(bool uses_nonsfi_mode) { layer_two_enabled_ = nacl::nonsfi::InitializeBPFSandbox(proc_fd_.Pass()); layer_two_is_nonsfi_ = true; } else { +#if defined(OS_NACL_NONSFI) + LOG(FATAL) << "nacl_helper_nonsfi can run only Non-SFI plugin."; +#else layer_two_enabled_ = nacl::InitializeBPFSandbox(proc_fd_.Pass()); +#endif } } -#endif // OS_NACL_NONSFI void NaClSandbox::SealLayerOneSandbox() { if (proc_fd_.is_valid() && !layer_two_enabled_) { @@ -219,8 +209,16 @@ void NaClSandbox::CheckSandboxingStateWithPolicy() { " this is not allowed in this configuration."; const bool no_sandbox_for_nonsfi_ok = +#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || \ + defined(MEMORY_SANITIZER) || defined(LEAK_SANITIZER) + // Sanitizer tests run with --no-sandbox, but without + // --nacl-dangerous-no-sandbox-nonsfi. Allow that case. + true; +#else base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kNaClDangerousNoSandboxNonSfi); +#endif + const bool can_be_no_sandbox = !layer_two_is_nonsfi_ || no_sandbox_for_nonsfi_ok; @@ -233,9 +231,6 @@ void NaClSandbox::CheckSandboxingStateWithPolicy() { LOG(FATAL) << kNoSuidMsg << kItIsNotAllowedMsg; } -#if !defined(OS_NACL_NONSFI) - // Currently Layer-two sandbox is not yet supported on nacl_helper_nonsfi. - // TODO(hidehiko): Enable the sandbox. if (!layer_two_enabled_) { static const char kNoBpfMsg[] = "The seccomp-bpf sandbox is not engaged for NaCl:"; @@ -244,7 +239,6 @@ void NaClSandbox::CheckSandboxingStateWithPolicy() { else LOG(FATAL) << kNoBpfMsg << kItIsNotAllowedMsg; } -#endif } } // namespace nacl diff --git a/components/nacl_nonsfi.gyp b/components/nacl_nonsfi.gyp index 3df9c45..53ff394 100644 --- a/components/nacl_nonsfi.gyp +++ b/components/nacl_nonsfi.gyp @@ -56,6 +56,7 @@ 'nacl/loader/nacl_trusted_listener.cc', 'nacl/loader/nonsfi/nonsfi_listener.cc', 'nacl/loader/nonsfi/nonsfi_main.cc', + 'nacl/loader/nonsfi/nonsfi_sandbox.cc', 'nacl/loader/sandbox_linux/nacl_sandbox_linux.cc', ], diff --git a/content/common/sandbox_linux/sandbox_init_linux.cc b/content/common/sandbox_linux/sandbox_init_linux.cc index b6f1f7c..146b352 100644 --- a/content/common/sandbox_linux/sandbox_init_linux.cc +++ b/content/common/sandbox_linux/sandbox_init_linux.cc @@ -17,8 +17,10 @@ bool InitializeSandbox(scoped_ptr<sandbox::bpf_dsl::Policy> policy, proc_fd.Pass()); } +#if !defined(OS_NACL_NONSFI) scoped_ptr<sandbox::bpf_dsl::Policy> GetBPFSandboxBaselinePolicy() { return SandboxSeccompBPF::GetBaselinePolicy().Pass(); } +#endif // !defined(OS_NACL_NONSFI) } // namespace content diff --git a/content/common/sandbox_linux/sandbox_seccomp_bpf_linux.cc b/content/common/sandbox_linux/sandbox_seccomp_bpf_linux.cc index 2f24b62..79adbee 100644 --- a/content/common/sandbox_linux/sandbox_seccomp_bpf_linux.cc +++ b/content/common/sandbox_linux/sandbox_seccomp_bpf_linux.cc @@ -28,7 +28,6 @@ #include "content/common/sandbox_linux/bpf_renderer_policy_linux.h" #include "content/common/sandbox_linux/bpf_utility_policy_linux.h" #include "content/common/sandbox_linux/sandbox_bpf_base_policy_linux.h" -#include "content/common/sandbox_linux/sandbox_linux.h" #include "sandbox/linux/seccomp-bpf-helpers/baseline_policy.h" #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h" #include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h" @@ -38,7 +37,7 @@ #if !defined(IN_NACL_HELPER) #include "ui/gl/gl_switches.h" -#endif +#endif // !defined(IN_NACL_HELPER) using sandbox::BaselinePolicy; using sandbox::SandboxBPF; @@ -61,8 +60,21 @@ namespace content { #if defined(USE_SECCOMP_BPF) namespace { +// This function takes ownership of |policy|. void StartSandboxWithPolicy(sandbox::bpf_dsl::Policy* policy, - base::ScopedFD proc_fd); + base::ScopedFD proc_fd) { + // Starting the sandbox is a one-way operation. The kernel doesn't allow + // us to unload a sandbox policy after it has been started. Nonetheless, + // in order to make the use of the "Sandbox" object easier, we allow for + // the object to be destroyed after the sandbox has been started. Note that + // doing so does not stop the sandbox. + SandboxBPF sandbox(policy); + + sandbox.SetProcFd(proc_fd.Pass()); + CHECK(sandbox.StartSandbox(SandboxBPF::SeccompLevel::SINGLE_THREADED)); +} + +#if !defined(OS_NACL_NONSFI) inline bool IsChromeOS() { #if defined(OS_CHROMEOS) @@ -145,21 +157,6 @@ void RunSandboxSanityChecks(const std::string& process_type) { } } - -// This function takes ownership of |policy|. -void StartSandboxWithPolicy(sandbox::bpf_dsl::Policy* policy, - base::ScopedFD proc_fd) { - // Starting the sandbox is a one-way operation. The kernel doesn't allow - // us to unload a sandbox policy after it has been started. Nonetheless, - // in order to make the use of the "Sandbox" object easier, we allow for - // the object to be destroyed after the sandbox has been started. Note that - // doing so does not stop the sandbox. - SandboxBPF sandbox(policy); - - sandbox.SetProcFd(proc_fd.Pass()); - CHECK(sandbox.StartSandbox(SandboxBPF::SeccompLevel::SINGLE_THREADED)); -} - // nacl_helper needs to be tiny and includes only part of content/ // in its dependencies. Make sure to not link things that are not needed. #if !defined(IN_NACL_HELPER) @@ -220,6 +217,7 @@ bool StartBPFSandbox(const base::CommandLine& command_line, return false; } #endif // !defined(IN_NACL_HELPER) +#endif // !defined(OS_NACL_NONSFI) } // namespace @@ -237,6 +235,7 @@ bool SandboxSeccompBPF::IsSeccompBPFDesired() { } } +#if !defined(OS_NACL_NONSFI) bool SandboxSeccompBPF::ShouldEnableSeccompBPF( const std::string& process_type) { #if defined(USE_SECCOMP_BPF) @@ -249,6 +248,7 @@ bool SandboxSeccompBPF::ShouldEnableSeccompBPF( #endif // USE_SECCOMP_BPF return false; } +#endif // !defined(OS_NACL_NONSFI) bool SandboxSeccompBPF::SupportsSandbox() { #if defined(USE_SECCOMP_BPF) @@ -258,6 +258,7 @@ bool SandboxSeccompBPF::SupportsSandbox() { return false; } +#if !defined(OS_NACL_NONSFI) bool SandboxSeccompBPF::SupportsSandboxWithTsync() { #if defined(USE_SECCOMP_BPF) return SandboxBPF::SupportsSeccompSandbox( @@ -285,6 +286,7 @@ bool SandboxSeccompBPF::StartSandbox(const std::string& process_type, #endif return false; } +#endif // !defined(OS_NACL_NONSFI) bool SandboxSeccompBPF::StartSandboxWithExternalPolicy( scoped_ptr<sandbox::bpf_dsl::Policy> policy, @@ -299,6 +301,7 @@ bool SandboxSeccompBPF::StartSandboxWithExternalPolicy( return false; } +#if !defined(OS_NACL_NONSFI) scoped_ptr<sandbox::bpf_dsl::Policy> SandboxSeccompBPF::GetBaselinePolicy() { #if defined(USE_SECCOMP_BPF) return scoped_ptr<sandbox::bpf_dsl::Policy>(new BaselinePolicy); @@ -306,5 +309,6 @@ scoped_ptr<sandbox::bpf_dsl::Policy> SandboxSeccompBPF::GetBaselinePolicy() { return scoped_ptr<sandbox::bpf_dsl::Policy>(); #endif // defined(USE_SECCOMP_BPF) } +#endif // !defined(OS_NACL_NONSFI) } // namespace content diff --git a/content/content_nacl_nonsfi.gyp b/content/content_nacl_nonsfi.gyp index f60f120..cfff0a5 100644 --- a/content/content_nacl_nonsfi.gyp +++ b/content/content_nacl_nonsfi.gyp @@ -25,11 +25,15 @@ 'build_nonsfi_helper': 1, 'sources': [ + 'common/sandbox_linux/sandbox_init_linux.cc', + 'common/sandbox_linux/sandbox_seccomp_bpf_linux.cc', 'common/send_zygote_child_ping_linux.cc', 'public/common/content_switches.cc', - # TODO(hidehiko): Add sandbox code. ], }, + 'defines': [ + 'USE_SECCOMP_BPF=1', + ], 'dependencies': [ '../base/base_nacl.gyp:base_nacl_nonsfi', ], diff --git a/content/public/common/sandbox_init.h b/content/public/common/sandbox_init.h index bd12ff8..6f4b19c 100644 --- a/content/public/common/sandbox_init.h +++ b/content/public/common/sandbox_init.h @@ -82,7 +82,7 @@ CONTENT_EXPORT base::Process StartSandboxedProcess( CONTENT_EXPORT bool InitializeSandbox(int sandbox_type, const base::FilePath& allowed_path); -#elif defined(OS_LINUX) +#elif defined(OS_LINUX) || defined(OS_NACL_NONSFI) class SandboxInitializerDelegate; @@ -98,7 +98,7 @@ CONTENT_EXPORT bool InitializeSandbox( // implement a policy that is derived from the baseline. CONTENT_EXPORT scoped_ptr<sandbox::bpf_dsl::Policy> GetBPFSandboxBaselinePolicy(); -#endif // defined(OS_LINUX) +#endif // defined(OS_LINUX) || defined(OS_NACL_NONSFI) } // namespace content diff --git a/sandbox/linux/bpf_dsl/codegen.cc b/sandbox/linux/bpf_dsl/codegen.cc index 99b78ed..bc2c7a2 100644 --- a/sandbox/linux/bpf_dsl/codegen.cc +++ b/sandbox/linux/bpf_dsl/codegen.cc @@ -131,7 +131,8 @@ CodeGen::Node CodeGen::Append(uint16_t code, uint32_t k, size_t jt, size_t jf) { CHECK_EQ(program_.size(), equivalent_.size()); Node res = program_.size(); - program_.push_back(sock_filter{code, jt, jf, k}); + program_.push_back(sock_filter{ + code, static_cast<uint8_t>(jt), static_cast<uint8_t>(jf), k}); equivalent_.push_back(res); return res; } diff --git a/sandbox/linux/bpf_dsl/policy_compiler.cc b/sandbox/linux/bpf_dsl/policy_compiler.cc index d4d52801..f38232f 100644 --- a/sandbox/linux/bpf_dsl/policy_compiler.cc +++ b/sandbox/linux/bpf_dsl/policy_compiler.cc @@ -22,6 +22,7 @@ #include "sandbox/linux/seccomp-bpf/errorcode.h" #include "sandbox/linux/system_headers/linux_filter.h" #include "sandbox/linux/system_headers/linux_seccomp.h" +#include "sandbox/linux/system_headers/linux_syscalls.h" namespace sandbox { namespace bpf_dsl { diff --git a/sandbox/linux/bpf_dsl/seccomp_macros.h b/sandbox/linux/bpf_dsl/seccomp_macros.h index 7f4866d..ca28c1d 100644 --- a/sandbox/linux/bpf_dsl/seccomp_macros.h +++ b/sandbox/linux/bpf_dsl/seccomp_macros.h @@ -11,7 +11,9 @@ // All x86_64 builds use a new enough bionic to have sys/user.h. #if !defined(__BIONIC__) || defined(__x86_64__) #include <sys/types.h> // Fix for gcc 4.7, make sure __uint16_t is defined. +#if !defined(__native_client_nonsfi__) #include <sys/user.h> +#endif #if defined(__mips__) // sys/user.h in eglibc misses size_t definition #include <stddef.h> @@ -50,10 +52,10 @@ 8*(nr) + 0) -#if defined(__BIONIC__) -// Old Bionic versions don't have sys/user.h, so we just define regs_struct -// directly. This can be removed once we no longer need to support these old -// Bionic versions. +#if defined(__BIONIC__) || defined(__native_client_nonsfi__) +// Old Bionic versions and PNaCl toolchain don't have sys/user.h, so we just +// define regs_struct directly. This can be removed once we no longer need to +// support these old Bionic versions and PNaCl toolchain. struct regs_struct { long int ebx; long int ecx; @@ -149,10 +151,10 @@ typedef user_regs_struct regs_struct; #define SECCOMP_ARG_LSB_IDX(nr) (offsetof(struct arch_seccomp_data, args) + \ 8*(nr) + 0) -#if defined(__BIONIC__) -// Old Bionic versions don't have sys/user.h, so we just define regs_struct -// directly. This can be removed once we no longer need to support these old -// Bionic versions. +#if defined(__BIONIC__) || defined(__native_client_nonsfi__) +// Old Bionic versions and PNaCl toolchain don't have sys/user.h, so we just +// define regs_struct directly. This can be removed once we no longer need to +// support these old Bionic versions and PNaCl toolchain. struct regs_struct { unsigned long uregs[18]; }; diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc index 282e727..60c16d3 100644 --- a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc +++ b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc @@ -11,7 +11,6 @@ #include <sched.h> #include <signal.h> #include <stdint.h> -#include <sys/ioctl.h> #include <sys/mman.h> #include <sys/prctl.h> #include <sys/resource.h> @@ -32,6 +31,11 @@ #include "sandbox/linux/system_headers/linux_futex.h" #include "sandbox/linux/system_headers/linux_syscalls.h" +// PNaCl toolchain does not provide sys/ioctl.h header. +#if !defined(OS_NACL_NONSFI) +#include <sys/ioctl.h> +#endif + #if defined(OS_ANDROID) #if !defined(F_DUPFD_CLOEXEC) @@ -104,6 +108,7 @@ using sandbox::bpf_dsl::ResultExpr; namespace sandbox { +#if !defined(OS_NACL_NONSFI) // 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. @@ -261,21 +266,6 @@ ResultExpr RestrictGetSetpriority(pid_t target_pid) { .Else(CrashSIGSYS()); } -ResultExpr RestrictClockID() { - static_assert(4 == sizeof(clockid_t), "clockid_t is not 32bit"); - const Arg<clockid_t> clockid(0); - return If( -#if defined(OS_CHROMEOS) - // Allow the special clock for Chrome OS used by Chrome tracing. - clockid == base::TimeTicks::kClockSystemTrace || -#endif - clockid == CLOCK_MONOTONIC || - clockid == CLOCK_PROCESS_CPUTIME_ID || - clockid == CLOCK_REALTIME || - clockid == CLOCK_THREAD_CPUTIME_ID, - Allow()).Else(CrashSIGSYS()); -} - ResultExpr RestrictSchedTarget(pid_t target_pid, int sysno) { switch (sysno) { case __NR_sched_getaffinity: @@ -306,5 +296,21 @@ ResultExpr RestrictGetrusage() { const Arg<int> who(0); return If(who == RUSAGE_SELF, Allow()).Else(CrashSIGSYS()); } +#endif // !defined(OS_NACL_NONSFI) + +ResultExpr RestrictClockID() { + static_assert(4 == sizeof(clockid_t), "clockid_t is not 32bit"); + const Arg<clockid_t> clockid(0); + return If( +#if defined(OS_CHROMEOS) + // Allow the special clock for Chrome OS used by Chrome tracing. + clockid == base::TimeTicks::kClockSystemTrace || +#endif + clockid == CLOCK_MONOTONIC || + clockid == CLOCK_PROCESS_CPUTIME_ID || + clockid == CLOCK_REALTIME || + clockid == CLOCK_THREAD_CPUTIME_ID, + Allow()).Else(CrashSIGSYS()); +} } // namespace sandbox. diff --git a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h index d557c5f..0ec396d 100644 --- a/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h +++ b/sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h @@ -67,15 +67,6 @@ SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictFutex(); // |target_pid| while calling setpriority(2) / getpriority(2). SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictGetSetpriority(pid_t target_pid); -// Restrict |clk_id| for clock_getres(), clock_gettime() and clock_settime(). -// We allow accessing only CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID, -// CLOCK_REALTIME, and CLOCK_THREAD_CPUTIME_ID. In particular, this disallows -// access to arbitrary per-{process,thread} CPU-time clock IDs (such as those -// returned by {clock,pthread}_getcpuclockid), which can leak information -// about the state of the host OS. -// On Chrome OS, base::TimeTicks::kClockSystemTrace is also allowed. -SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictClockID(); - // Restricts |pid| for sched_* syscalls which take a pid as the first argument. // We only allow calling these syscalls if the pid argument is equal to the pid // of the sandboxed process or 0 (indicating the current thread). The following @@ -95,6 +86,15 @@ SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictPrlimit64(pid_t target_pid); // process). SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictGetrusage(); +// Restrict |clk_id| for clock_getres(), clock_gettime() and clock_settime(). +// We allow accessing only CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID, +// CLOCK_REALTIME, and CLOCK_THREAD_CPUTIME_ID. In particular, this disallows +// access to arbitrary per-{process,thread} CPU-time clock IDs (such as those +// returned by {clock,pthread}_getcpuclockid), which can leak information +// about the state of the host OS. +// On Chrome OS, base::TimeTicks::kClockSystemTrace is also allowed. +SANDBOX_EXPORT bpf_dsl::ResultExpr RestrictClockID(); + } // namespace sandbox. #endif // SANDBOX_LINUX_SECCOMP_BPF_HELPERS_SYSCALL_PARAMETERS_RESTRICTIONS_H_ diff --git a/sandbox/linux/seccomp-bpf/syscall.cc b/sandbox/linux/seccomp-bpf/syscall.cc index 3b3c8db..1c77533 100644 --- a/sandbox/linux/seccomp-bpf/syscall.cc +++ b/sandbox/linux/seccomp-bpf/syscall.cc @@ -133,7 +133,13 @@ asm(// We need to be able to tell the kernel exactly where we made a #else ".arm\n" #endif - "SyscallAsm:.fnstart\n" + "SyscallAsm:\n" +#if !defined(__native_client_nonsfi__) + // .fnstart and .fnend pseudo operations creates unwind table. + // It also creates a reference to the symbol __aeabi_unwind_cpp_pr0, which + // is not provided by PNaCl toolchain. Disable it. + ".fnstart\n" +#endif "@ args = 0, pretend = 0, frame = 8\n" "@ frame_needed = 1, uses_anonymous_args = 0\n" #if defined(__thumb__) @@ -177,7 +183,11 @@ asm(// We need to be able to tell the kernel exactly where we made a #else "2:ldmfd sp!, {fp, pc}\n" #endif +#if !defined(__native_client_nonsfi__) + // Do not use .fnstart and .fnend for PNaCl toolchain. See above comment, + // for more details. ".fnend\n" +#endif "9:.size SyscallAsm, 9b-SyscallAsm\n" #elif defined(__mips__) ".text\n" diff --git a/sandbox/linux/seccomp-bpf/trap.cc b/sandbox/linux/seccomp-bpf/trap.cc index 79b7569..8f559e5 100644 --- a/sandbox/linux/seccomp-bpf/trap.cc +++ b/sandbox/linux/seccomp-bpf/trap.cc @@ -12,6 +12,7 @@ #include <algorithm> #include <limits> +#include "base/compiler_specific.h" #include "base/logging.h" #include "build/build_config.h" #include "sandbox/linux/bpf_dsl/seccomp_macros.h" @@ -121,15 +122,26 @@ bpf_dsl::TrapRegistry* Trap::Registry() { } void Trap::SigSysAction(int nr, LinuxSigInfo* info, void* void_context) { + if (info) { + MSAN_UNPOISON(info, sizeof(*info)); + } + + // Obtain the signal context. This, most notably, gives us access to + // all CPU registers at the time of the signal. + ucontext_t* ctx = reinterpret_cast<ucontext_t*>(void_context); + if (ctx) { + MSAN_UNPOISON(ctx, sizeof(*ctx)); + } + if (!global_trap_) { RAW_SANDBOX_DIE( "This can't happen. Found no global singleton instance " "for Trap() handling."); } - global_trap_->SigSys(nr, info, void_context); + global_trap_->SigSys(nr, info, ctx); } -void Trap::SigSys(int nr, LinuxSigInfo* info, void* void_context) { +void Trap::SigSys(int nr, LinuxSigInfo* info, ucontext_t* ctx) { // Signal handlers should always preserve "errno". Otherwise, we could // trigger really subtle bugs. const int old_errno = errno; @@ -137,7 +149,7 @@ void Trap::SigSys(int nr, LinuxSigInfo* info, void* void_context) { // Various sanity checks to make sure we actually received a signal // triggered by a BPF filter. If something else triggered SIGSYS // (e.g. kill()), there is really nothing we can do with this signal. - if (nr != LINUX_SIGSYS || info->si_code != SYS_SECCOMP || !void_context || + if (nr != LINUX_SIGSYS || info->si_code != SYS_SECCOMP || !ctx || info->si_errno <= 0 || static_cast<size_t>(info->si_errno) > trap_array_size_) { // ATI drivers seem to send SIGSYS, so this cannot be FATAL. @@ -148,9 +160,6 @@ void Trap::SigSys(int nr, LinuxSigInfo* info, void* void_context) { return; } - // Obtain the signal context. This, most notably, gives us access to - // all CPU registers at the time of the signal. - ucontext_t* ctx = reinterpret_cast<ucontext_t*>(void_context); // Obtain the siginfo information that is specific to SIGSYS. Unfortunately, // most versions of glibc don't include this information in siginfo_t. So, diff --git a/sandbox/linux/seccomp-bpf/trap.h b/sandbox/linux/seccomp-bpf/trap.h index bbddeb7..50ac3fd 100644 --- a/sandbox/linux/seccomp-bpf/trap.h +++ b/sandbox/linux/seccomp-bpf/trap.h @@ -61,7 +61,7 @@ class SANDBOX_EXPORT Trap : public bpf_dsl::TrapRegistry { // Make sure that SigSys is not inlined in order to get slightly better crash // dumps. - void SigSys(int nr, LinuxSigInfo* info, void* void_context) + void SigSys(int nr, LinuxSigInfo* info, ucontext_t* ctx) __attribute__((noinline)); // We have a global singleton that handles all of our SIGSYS traps. This // variable must never be deallocated after it has been set up initially, as diff --git a/sandbox/linux/services/syscall_wrappers.cc b/sandbox/linux/services/syscall_wrappers.cc index a84d329..264eb68 100644 --- a/sandbox/linux/services/syscall_wrappers.cc +++ b/sandbox/linux/services/syscall_wrappers.cc @@ -148,8 +148,9 @@ int sys_sigprocmask(int how, const sigset_t* set, decltype(nullptr) oldset) { sizeof(linux_value)); } -#if defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \ - (defined(ARCH_CPU_X86_64) && !defined(__clang__)) +#if (defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \ + (defined(ARCH_CPU_X86_64) && !defined(__clang__))) && \ + !defined(OS_NACL_NONSFI) // If MEMORY_SANITIZER or THREAD_SANITIZER is enabled, it is necessary to call // sigaction() here, rather than the direct syscall (sys_sigaction() defined // by ourselves). @@ -173,6 +174,12 @@ int sys_sigprocmask(int how, const sigset_t* set, decltype(nullptr) oldset) { // of function is actually very small (only two instructions), but we need to // define much debug information in addition, otherwise backtrace() used by // base::StackTrace would not work so that some tests would fail. +// +// When this is built with PNaCl toolchain, we should always use sys_sigaction +// below, because sigaction() provided by the toolchain is incompatible with +// Linux's ABI. So, otherwise, it would just fail. Note that it is not +// necessary to think about sigaction() invocation in other places even with +// MEMORY_SANITIZER or THREAD_SANITIZER, because it would just fail there. int sys_sigaction(int signum, const struct sigaction* act, struct sigaction* oldact) { diff --git a/sandbox/linux/system_headers/linux_futex.h b/sandbox/linux/system_headers/linux_futex.h index 91733a8..4e28403 100644 --- a/sandbox/linux/system_headers/linux_futex.h +++ b/sandbox/linux/system_headers/linux_futex.h @@ -5,7 +5,9 @@ #ifndef SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FUTEX_H_ #define SANDBOX_LINUX_SYSTEM_HEADERS_LINUX_FUTEX_H_ +#if !defined(__native_client_nonsfi__) #include <linux/futex.h> +#endif // !defined(__native_client_nonsfi__) #if !defined(FUTEX_WAIT) #define FUTEX_WAIT 0 diff --git a/sandbox/sandbox_nacl_nonsfi.gyp b/sandbox/sandbox_nacl_nonsfi.gyp index 781df42..906fc7b 100644 --- a/sandbox/sandbox_nacl_nonsfi.gyp +++ b/sandbox/sandbox_nacl_nonsfi.gyp @@ -27,14 +27,28 @@ 'sources': [ # This is the subset of linux build target, needed for # nacl_helper_nonsfi's sandbox implementation. + 'linux/bpf_dsl/bpf_dsl.cc', + 'linux/bpf_dsl/codegen.cc', + 'linux/bpf_dsl/dump_bpf.cc', + 'linux/bpf_dsl/policy.cc', + 'linux/bpf_dsl/policy_compiler.cc', + 'linux/bpf_dsl/syscall_set.cc', + 'linux/bpf_dsl/verifier.cc', + 'linux/seccomp-bpf-helpers/sigsys_handlers.cc', + 'linux/seccomp-bpf-helpers/syscall_parameters_restrictions.cc', + 'linux/seccomp-bpf/die.cc', + 'linux/seccomp-bpf/errorcode.cc', + 'linux/seccomp-bpf/sandbox_bpf.cc', + 'linux/seccomp-bpf/syscall.cc', + 'linux/seccomp-bpf/trap.cc', 'linux/services/credentials.cc', - 'linux/services/namespace_utils.cc', 'linux/services/namespace_sandbox.cc', + 'linux/services/namespace_utils.cc', 'linux/services/proc_util.cc', + 'linux/services/resource_limits.cc', 'linux/services/syscall_wrappers.cc', 'linux/services/thread_helpers.cc', 'linux/suid/client/setuid_sandbox_client.cc', - # TODO(hidehiko): Support seccomp-bpf sandbox. ], }, 'dependencies': [ |