Chromium Code Reviews| Index: components/nacl/loader/nacl_sandbox_linux.cc |
| diff --git a/components/nacl/loader/nacl_sandbox_linux.cc b/components/nacl/loader/nacl_sandbox_linux.cc |
| index f1e4a49a4f71b1ab1efaaade862ea8a9d9f399b2..f49695cb1f4e4a6730e4713191f649de1d23cf4b 100644 |
| --- a/components/nacl/loader/nacl_sandbox_linux.cc |
| +++ b/components/nacl/loader/nacl_sandbox_linux.cc |
| @@ -5,8 +5,10 @@ |
| #include "components/nacl/loader/nacl_sandbox_linux.h" |
| #include <errno.h> |
| +#include <linux/net.h> |
| #include <signal.h> |
| #include <sys/ptrace.h> |
| +#include <sys/syscall.h> |
| #include "base/basictypes.h" |
| #include "base/callback.h" |
| @@ -16,8 +18,11 @@ |
| #if defined(USE_SECCOMP_BPF) |
| #include "content/public/common/sandbox_init.h" |
| +#include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h" |
| +#include "sandbox/linux/seccomp-bpf-helpers/syscall_parameters_restrictions.h" |
| #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" |
| #include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h" |
| +#include "sandbox/linux/seccomp-bpf/trap.h" |
| #include "sandbox/linux/services/linux_syscalls.h" |
| using sandbox::ErrorCode; |
| @@ -122,6 +127,7 @@ ErrorCode NaClBPFSandboxPolicy::EvaluateSyscall( |
| case __NR_uname: |
| return ErrorCode(ErrorCode::ERR_ALLOWED); |
| case __NR_ptrace: |
| + // For RunSandboxSanityChecks(). |
| return ErrorCode(EPERM); |
| default: |
| // TODO(jln): look into getting rid of System V shared memory: |
| @@ -142,6 +148,175 @@ ErrorCode NaClBPFSandboxPolicy::EvaluateSyscall( |
| return ErrorCode(EPERM); |
| } |
| +// The seccomp sandbox policy for NaCl non-SFI mode. Note that this |
| +// policy must be as strong as possible, as non-SFI mode heavily |
| +// depends on seccomp sandbox. |
| +class NonSfiNaClBPFSandboxPolicy : public SandboxBPFPolicy { |
| + public: |
| + explicit NonSfiNaClBPFSandboxPolicy() |
| + : baseline_policy_(content::GetBPFSandboxBaselinePolicy()) { |
| + } |
| + virtual ~NonSfiNaClBPFSandboxPolicy() {} |
| + |
| + virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox_compiler, |
| + int system_call_number) const OVERRIDE; |
| + |
| + private: |
| + scoped_ptr<SandboxBPFPolicy> baseline_policy_; |
| + DISALLOW_COPY_AND_ASSIGN(NonSfiNaClBPFSandboxPolicy); |
| +}; |
| + |
| +ErrorCode NonSfiNaClBPFSandboxPolicy::EvaluateSyscall( |
| + sandbox::SandboxBPF* sb, int sysno) const { |
| + DCHECK(baseline_policy_); |
| + ErrorCode ret = baseline_policy_->EvaluateSyscall(sb, sysno); |
|
Mark Seaborn
2014/03/18 23:53:58
You're falling through to the baseline policy. I
jln (very slow on Chromium)
2014/03/20 00:54:53
I absolutely agree with Mark here. We need a short
hamaji
2014/03/24 15:56:37
Done. I also stopped using sandbox::Restrict* as t
|
| + switch (sysno) { |
| + // __NR_times needed as clock() is called by CommandBufferHelper, which is |
| + // used by NaCl applications that use Pepper's 3D interfaces. |
| + // See crbug.com/264856 for details. |
| + case __NR_times: |
| + ret = ErrorCode(ErrorCode::ERR_ALLOWED); |
| + break; |
| + |
| + // Conditionally allowed syscalls: |
| + case __NR_clone: { |
| + // We allow clone only for new thread creation. |
| + ret = sb->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), |
| + sb->Trap(sandbox::SIGSYSCloneFailure, NULL)); |
| + break; |
| + } |
| + case __NR_prctl: |
| + // We only allow PR_SET_NAME, PR_SET_DUMPABLE, and PR_GET_DUMPABLE. |
|
Mark Seaborn
2014/03/18 23:53:58
I don't think these are operations that should be
hamaji
2014/03/24 15:56:37
I stopped using RestrictPrctl. Now it returns EPER
|
| + ret = sandbox::RestrictPrctl(sb); |
| + break; |
| +#if defined(__i686__) |
|
Mark Seaborn
2014/03/18 23:53:58
__i386__ would be preferred.
hamaji
2014/03/24 15:56:37
Done.
|
| + case __NR_socketcall: { |
| + // We only allow socketpair, sendmsg, and recvmsg. |
| + ret = sb->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, |
| + SYS_SOCKETPAIR, ErrorCode(ErrorCode::ERR_ALLOWED), |
| + sb->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, |
| + SYS_SENDMSG, ErrorCode(ErrorCode::ERR_ALLOWED), |
| + sb->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, |
| + SYS_RECVMSG, ErrorCode(ErrorCode::ERR_ALLOWED), |
| + ErrorCode(EPERM)))); |
| + break; |
| + } |
| +#endif |
| + |
| + // It is allowed to call the following syscalls, but they just |
| + // return EPERM. |
| + case __NR_ptrace: |
| + // For RunSandboxSanityChecks(). |
| + ret = ErrorCode(EPERM); |
| + break; |
| + case __NR_set_robust_list: |
| + // glibc uses this for its pthread implementation. If we return |
| + // EPERM for this, glibc will stop using this. |
| + // TODO(hamaji): newlib does not use this. Make this SIGTRAP once |
| + // we have switched to newlib. |
| + ret = ErrorCode(EPERM); |
| + break; |
| +#if !defined(__x86_64__) |
| + case __NR_getegid32: |
| + case __NR_geteuid32: |
| + case __NR_getgid32: |
| + case __NR_getuid32: |
| +#endif |
| + // third_party/libevent uses them, but we can just return -1 from |
| + // them as it is just checking getuid() != geteuid() and |
| + // getgid() != getegid() |
| + ret = ErrorCode(EPERM); |
| + break; |
| +#if !defined(__arm__) |
|
Mark Seaborn
2014/03/18 23:53:58
Should be "defined(__i386__) || defined(__x86_64__
hamaji
2014/03/24 15:56:37
Done.
|
| + case __NR_time: |
| + // This is obsolete in ARM EABI, but x86 glibc indirectly calls |
| + // this in sysconf. |
| + case __NR_modify_ldt: |
| + // nacl_helper calls this from service_runtime/linux/x86/nacl_ldt.c |
|
Mark Seaborn
2014/03/18 23:53:58
But this doesn't apply to Non-SFI Mode.
hamaji
2014/03/24 15:56:37
It seems current nacl_helper always calls NaClTlsI
|
| + ret = ErrorCode(EPERM); |
| + break; |
| +#endif |
| + |
| + // Followings are restricted syscalls. |
| + |
| + // glibc internally calls brk in its memory allocation. |
|
Mark Seaborn
2014/03/18 23:53:58
glibc does call brk(), but it doesn't require it t
jln (very slow on Chromium)
2014/03/20 00:54:53
Yes, in other words, just EPERM it.
hamaji
2014/03/24 15:56:37
Oops, my comment was wrong. brk was called by tcma
Mark Seaborn
2014/03/28 16:41:39
Does tcmalloc currently require brk(), or does it
|
| + // TODO(hamaji): Uncomment this once newlib switch has been done. |
| + // case __NR_brk: |
| + case __NR_capget: |
|
Mark Seaborn
2014/03/18 23:53:58
This is a blacklist of disallowed syscalls, but I
hamaji
2014/03/24 15:56:37
Done.
|
| + case __NR_dup3: |
| + case __NR_epoll_create1: |
| + case __NR_fcntl: |
| + case __NR_fork: |
| + case __NR_get_robust_list: |
| + case __NR_getgroups: |
| + case __NR_getpid: |
| + case __NR_getppid: |
| + case __NR_getresgid: |
| + case __NR_getresuid: |
| + case __NR_getsid: |
| + case __NR_kill: |
| + case __NR_mlock: |
| + case __NR_munlock: |
| + case __NR_pause: |
| + case __NR_pipe2: |
| + case __NR_poll: |
| + case __NR_ppoll: |
| + case __NR_pselect6: |
| + case __NR_readv: |
| + case __NR_recvmmsg: |
| + case __NR_rt_sigaction: |
| + case __NR_sendmmsg: |
| + case __NR_tgkill: |
| + case __NR_tkill: |
| + case __NR_wait4: |
| + case __NR_waitid: |
| + case __NR_writev: |
| + // We do not need 32bit versions of them. |
| + case __NR_fstat: |
| + case __NR_lseek: |
| +#if !defined(__arm__) |
| + // They do not exist on ARM EABI. |
| + case __NR_select: |
| +#endif |
| +#if defined(__i686__) |
| + // This is i686 only. |
| + case __NR_waitpid: |
| +#endif |
| +#if !defined(__i686__) |
| + // i686 uses socketcall instead of them. |
| + case __NR_sendto: |
| + case __NR_shutdown: |
| + case __NR_recvfrom: |
| +#if defined(__arm__) |
| + case __NR_send: |
| + case __NR_recv: |
| +#endif |
| +#endif |
| +#if !defined(__x86_64__) |
| + // They do not exist on x86-64. |
| + case __NR__newselect: |
| + case __NR_getegid: |
| + case __NR_geteuid: |
| + case __NR_getgid: |
| + case __NR_getgroups32: |
| + case __NR_getresgid32: |
| + case __NR_getresuid32: |
| + case __NR_getuid: |
| + case __NR_rt_sigprocmask: |
| + case __NR_rt_sigreturn: |
| + case __NR_sigprocmask: |
| + case __NR_sigreturn: |
| +#endif |
| + ret = sb->Trap(sandbox::CrashSIGSYS_Handler, NULL); |
| + break; |
| + } |
| + return ret; |
| +} |
| + |
| void RunSandboxSanityChecks() { |
| errno = 0; |
| // Make a ptrace request with an invalid PID. |
| @@ -172,3 +347,15 @@ bool InitializeBPFSandbox() { |
| #endif // defined(USE_SECCOMP_BPF) |
| return false; |
| } |
| + |
| +bool InitializeBPFSandboxForNonSfi() { |
| +#if defined(USE_SECCOMP_BPF) |
| + bool sandbox_is_initialized = content::InitializeSandbox( |
|
hamaji
2014/03/14 12:46:23
I thought we should add something like
#if !defi
jln (very slow on Chromium)
2014/03/20 00:54:53
We should not return false in non SFI mode. We sho
hamaji
2014/03/24 15:56:37
Done.
|
| + scoped_ptr<SandboxBPFPolicy>(new NonSfiNaClBPFSandboxPolicy())); |
| + if (sandbox_is_initialized) { |
| + RunSandboxSanityChecks(); |
| + return true; |
| + } |
| +#endif // defined(USE_SECCOMP_BPF) |
| + return false; |
| +} |