| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/nacl/loader/nonsfi/nonsfi_sandbox.h" | 5 #include "components/nacl/loader/nonsfi/nonsfi_sandbox.h" |
| 6 | 6 |
| 7 #include <errno.h> | 7 #include <errno.h> |
| 8 #include <fcntl.h> | 8 #include <fcntl.h> |
| 9 #include <linux/net.h> | 9 #include <linux/net.h> |
| 10 #include <sys/prctl.h> | 10 #include <sys/prctl.h> |
| 11 #include <sys/ptrace.h> | 11 #include <sys/ptrace.h> |
| 12 #include <sys/mman.h> | 12 #include <sys/mman.h> |
| 13 #include <sys/socket.h> | 13 #include <sys/socket.h> |
| 14 #include <sys/syscall.h> | 14 #include <sys/syscall.h> |
| 15 | 15 |
| 16 #include "base/basictypes.h" | 16 #include "base/basictypes.h" |
| 17 #include "base/logging.h" | 17 #include "base/logging.h" |
| 18 #include "build/build_config.h" | 18 #include "build/build_config.h" |
| 19 #include "content/public/common/sandbox_init.h" | 19 #include "content/public/common/sandbox_init.h" |
| 20 #include "sandbox/linux/seccomp-bpf-helpers/bpf_dsl.h" |
| 20 #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h" | 21 #include "sandbox/linux/seccomp-bpf-helpers/sigsys_handlers.h" |
| 21 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" | 22 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" |
| 22 #include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h" | 23 #include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h" |
| 23 #include "sandbox/linux/seccomp-bpf/trap.h" | |
| 24 #include "sandbox/linux/services/linux_syscalls.h" | 24 #include "sandbox/linux/services/linux_syscalls.h" |
| 25 | 25 |
| 26 #if defined(__arm__) && !defined(MAP_STACK) | 26 #if defined(__arm__) && !defined(MAP_STACK) |
| 27 // Chrome OS Daisy (ARM) build environment has old headers. | 27 // Chrome OS Daisy (ARM) build environment has old headers. |
| 28 #define MAP_STACK 0x20000 | 28 #define MAP_STACK 0x20000 |
| 29 #endif | 29 #endif |
| 30 | 30 |
| 31 using sandbox::ErrorCode; | 31 using namespace sandbox::bpf_dsl; |
| 32 using sandbox::SandboxBPF; | |
| 33 | 32 |
| 34 namespace nacl { | 33 namespace nacl { |
| 35 namespace nonsfi { | 34 namespace nonsfi { |
| 36 namespace { | 35 namespace { |
| 37 | 36 |
| 38 ErrorCode RestrictFcntlCommands(SandboxBPF* sb) { | 37 ResultExpr RestrictFcntlCommands() { |
| 39 ErrorCode::ArgType mask_long_type; | |
| 40 if (sizeof(long) == 8) { | |
| 41 mask_long_type = ErrorCode::TP_64BIT; | |
| 42 } else if (sizeof(long) == 4) { | |
| 43 mask_long_type = ErrorCode::TP_32BIT; | |
| 44 } else { | |
| 45 NOTREACHED(); | |
| 46 } | |
| 47 // We allow following cases: | 38 // We allow following cases: |
| 48 // 1. F_SETFD + FD_CLOEXEC: libevent's epoll_init uses this. | 39 // 1. F_SETFD + FD_CLOEXEC: libevent's epoll_init uses this. |
| 49 // 2. F_GETFL: Used by SetNonBlocking in | 40 // 2. F_GETFL: Used by SetNonBlocking in |
| 50 // message_pump_libevent.cc and Channel::ChannelImpl::CreatePipe | 41 // message_pump_libevent.cc and Channel::ChannelImpl::CreatePipe |
| 51 // in ipc_channel_posix.cc. Note that the latter does not work | 42 // in ipc_channel_posix.cc. Note that the latter does not work |
| 52 // with EPERM. | 43 // with EPERM. |
| 53 // 3. F_SETFL: Used by evutil_make_socket_nonblocking in | 44 // 3. F_SETFL: Used by evutil_make_socket_nonblocking in |
| 54 // libevent and SetNonBlocking. As the latter mix O_NONBLOCK to | 45 // libevent and SetNonBlocking. As the latter mix O_NONBLOCK to |
| 55 // the return value of F_GETFL, so we need to allow O_ACCMODE in | 46 // the return value of F_GETFL, so we need to allow O_ACCMODE in |
| 56 // addition to O_NONBLOCK. | 47 // addition to O_NONBLOCK. |
| 57 const unsigned long denied_mask = ~(O_ACCMODE | O_NONBLOCK); | 48 const unsigned long denied_mask = ~(O_ACCMODE | O_NONBLOCK); |
| 58 return sb->Cond(1, ErrorCode::TP_32BIT, | 49 const Arg<int> cmd_arg(1); |
| 59 ErrorCode::OP_EQUAL, F_SETFD, | 50 const Arg<unsigned long> extra_arg(2); |
| 60 sb->Cond(2, mask_long_type, | 51 return If((cmd_arg == F_SETFD && extra_arg == FD_CLOEXEC) || |
| 61 ErrorCode::OP_EQUAL, FD_CLOEXEC, | 52 (cmd_arg == F_GETFL) || |
| 62 ErrorCode(ErrorCode::ERR_ALLOWED), | 53 (cmd_arg == F_SETFL && (extra_arg & denied_mask) == 0)).Then( |
| 63 sb->Trap(sandbox::CrashSIGSYS_Handler, NULL)), | 54 Allow() |
| 64 sb->Cond(1, ErrorCode::TP_32BIT, | 55 ).Else( |
| 65 ErrorCode::OP_EQUAL, F_GETFL, | 56 Trap(sandbox::CrashSIGSYS_Handler, NULL) |
| 66 ErrorCode(ErrorCode::ERR_ALLOWED), | 57 ); |
| 67 sb->Cond(1, ErrorCode::TP_32BIT, | |
| 68 ErrorCode::OP_EQUAL, F_SETFL, | |
| 69 sb->Cond(2, mask_long_type, | |
| 70 ErrorCode::OP_HAS_ANY_BITS, denied_mask, | |
| 71 sb->Trap(sandbox::CrashSIGSYS_Handler, NULL), | |
| 72 ErrorCode(ErrorCode::ERR_ALLOWED)), | |
| 73 sb->Trap(sandbox::CrashSIGSYS_Handler, NULL)))); | |
| 74 } | 58 } |
| 75 | 59 |
| 76 ErrorCode RestrictClone(SandboxBPF* sb) { | 60 ResultExpr RestrictClone() { |
| 77 // We allow clone only for new thread creation. | 61 // We allow clone only for new thread creation. |
| 78 return sb->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 62 const int kAllowableFlags = |
| 79 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | | 63 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD | |
| 80 CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS | | 64 CLONE_SYSVSEM | CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID; |
| 81 CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID, | 65 const Arg<int> flag_arg(0); |
| 82 ErrorCode(ErrorCode::ERR_ALLOWED), | 66 return If(flag_arg == kAllowableFlags).Then( |
| 83 sb->Trap(sandbox::SIGSYSCloneFailure, NULL)); | 67 Allow() |
| 68 ).Else( |
| 69 Trap(sandbox::SIGSYSCloneFailure, NULL) |
| 70 ); |
| 84 } | 71 } |
| 85 | 72 |
| 86 ErrorCode RestrictPrctl(SandboxBPF* sb) { | 73 ResultExpr RestrictPrctl() { |
| 87 // base::PlatformThread::SetName() uses PR_SET_NAME so we return | 74 // base::PlatformThread::SetName() uses PR_SET_NAME so we return |
| 88 // EPERM for it. Otherwise, we will raise SIGSYS. | 75 // EPERM for it. Otherwise, we will raise SIGSYS. |
| 89 return sb->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 76 const Arg<int> option_arg(0); |
| 90 PR_SET_NAME, ErrorCode(EPERM), | 77 return If(option_arg == PR_SET_NAME).Then( |
| 91 sb->Trap(sandbox::SIGSYSPrctlFailure, NULL)); | 78 Error(EPERM) |
| 79 ).Else( |
| 80 Trap(sandbox::SIGSYSPrctlFailure, NULL) |
| 81 ); |
| 92 } | 82 } |
| 93 | 83 |
| 94 #if defined(__i386__) | 84 #if defined(__i386__) |
| 95 ErrorCode RestrictSocketcall(SandboxBPF* sb) { | 85 ResultExpr RestrictSocketcall() { |
| 96 // We only allow socketpair, sendmsg, and recvmsg. | 86 // We only allow socketpair, sendmsg, and recvmsg. |
| 97 return sb->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 87 const Arg<int> call_arg(0); |
| 98 SYS_SOCKETPAIR, | 88 return If(call_arg == SYS_SOCKETPAIR || call_arg == SYS_SENDMSG || |
| 99 ErrorCode(ErrorCode::ERR_ALLOWED), | 89 call_arg == SYS_RECVMSG || call_arg == SYS_SHUTDOWMN).Then( |
| 100 sb->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 90 Allow() |
| 101 SYS_SENDMSG, | 91 ).Else( |
| 102 ErrorCode(ErrorCode::ERR_ALLOWED), | 92 Trap(sandbox::CrashSIGSYS_Handler, NULL) |
| 103 sb->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | 93 ); |
| 104 SYS_RECVMSG, | |
| 105 ErrorCode(ErrorCode::ERR_ALLOWED), | |
| 106 sb->Cond(0, ErrorCode::TP_32BIT, ErrorCode::OP_EQUAL, | |
| 107 SYS_SHUTDOWN, | |
| 108 ErrorCode(ErrorCode::ERR_ALLOWED), | |
| 109 sb->Trap(sandbox::CrashSIGSYS_Handler, NULL))))); | |
| 110 } | 94 } |
| 111 #endif | 95 #endif |
| 112 | 96 |
| 113 ErrorCode RestrictMprotect(SandboxBPF* sb) { | 97 ResultExpr RestrictMprotect() { |
| 114 // TODO(jln, keescook, drewry): Limit the use of mprotect by adding | 98 // TODO(jln, keescook, drewry): Limit the use of mprotect by adding |
| 115 // some features to linux kernel. | 99 // some features to linux kernel. |
| 116 const uint32_t denied_mask = ~(PROT_READ | PROT_WRITE | PROT_EXEC); | 100 const uint32_t denied_mask = ~(PROT_READ | PROT_WRITE | PROT_EXEC); |
| 117 return sb->Cond(2, ErrorCode::TP_32BIT, | 101 const Arg<int> prot_arg(2); |
| 118 ErrorCode::OP_HAS_ANY_BITS, | 102 return If((prot_arg & denied_mask) == 0).Then( |
| 119 denied_mask, | 103 Allow() |
| 120 sb->Trap(sandbox::CrashSIGSYS_Handler, NULL), | 104 ).Else( |
| 121 ErrorCode(ErrorCode::ERR_ALLOWED)); | 105 Trap(sandbox::CrashSIGSYS_Handler, NULL) |
| 106 ); |
| 122 } | 107 } |
| 123 | 108 |
| 124 ErrorCode RestrictMmap(SandboxBPF* sb) { | 109 ResultExpr RestrictMmap() { |
| 125 const uint32_t denied_flag_mask = ~(MAP_SHARED | MAP_PRIVATE | | 110 const uint32_t denied_flag_mask = ~(MAP_SHARED | MAP_PRIVATE | |
| 126 MAP_ANONYMOUS | MAP_STACK | MAP_FIXED); | 111 MAP_ANONYMOUS | MAP_STACK | MAP_FIXED); |
| 127 // When PROT_EXEC is specified, IRT mmap of Non-SFI NaCl helper | 112 // When PROT_EXEC is specified, IRT mmap of Non-SFI NaCl helper |
| 128 // calls mmap without PROT_EXEC and then adds PROT_EXEC by mprotect, | 113 // calls mmap without PROT_EXEC and then adds PROT_EXEC by mprotect, |
| 129 // so we do not need to allow PROT_EXEC in mmap. | 114 // so we do not need to allow PROT_EXEC in mmap. |
| 130 const uint32_t denied_prot_mask = ~(PROT_READ | PROT_WRITE); | 115 const uint32_t denied_prot_mask = ~(PROT_READ | PROT_WRITE); |
| 131 return sb->Cond(3, ErrorCode::TP_32BIT, | 116 const Arg<int> prot_arg(2), flags_arg(3); |
| 132 ErrorCode::OP_HAS_ANY_BITS, | 117 return If((prot_arg & denied_prot_mask) == 0 && |
| 133 denied_flag_mask, | 118 (flags_arg & denied_flag_mask) == 0).Then( |
| 134 sb->Trap(sandbox::CrashSIGSYS_Handler, NULL), | 119 Allow() |
| 135 sb->Cond(2, ErrorCode::TP_32BIT, | 120 ).Else( |
| 136 ErrorCode::OP_HAS_ANY_BITS, | 121 Trap(sandbox::CrashSIGSYS_Handler, NULL) |
| 137 denied_prot_mask, | 122 ); |
| 138 sb->Trap(sandbox::CrashSIGSYS_Handler, NULL), | |
| 139 ErrorCode(ErrorCode::ERR_ALLOWED))); | |
| 140 } | 123 } |
| 141 | 124 |
| 142 #if defined(__x86_64__) || defined(__arm__) | 125 #if defined(__x86_64__) || defined(__arm__) |
| 143 ErrorCode RestrictSocketpair(SandboxBPF* sb) { | 126 ResultExpr RestrictSocketpair() { |
| 144 // Only allow AF_UNIX, PF_UNIX. Crash if anything else is seen. | 127 // Only allow AF_UNIX, PF_UNIX. Crash if anything else is seen. |
| 145 COMPILE_ASSERT(AF_UNIX == PF_UNIX, af_unix_pf_unix_different); | 128 COMPILE_ASSERT(AF_UNIX == PF_UNIX, af_unix_pf_unix_different); |
| 146 return sb->Cond(0, ErrorCode::TP_32BIT, | 129 const Arg<int> domain_arg(0); |
| 147 ErrorCode::OP_EQUAL, AF_UNIX, | 130 return If(domain_arg == AF_UNIX).Then( |
| 148 ErrorCode(ErrorCode::ERR_ALLOWED), | 131 Allow() |
| 149 sb->Trap(sandbox::CrashSIGSYS_Handler, NULL)); | 132 ).Else( |
| 133 Trap(sandbox::CrashSIGSYS_Handler, NULL) |
| 134 ); |
| 150 } | 135 } |
| 151 #endif | 136 #endif |
| 152 | 137 |
| 153 bool IsGracefullyDenied(int sysno) { | 138 bool IsGracefullyDenied(int sysno) { |
| 154 switch (sysno) { | 139 switch (sysno) { |
| 155 // libevent tries this first and then falls back to poll if | 140 // libevent tries this first and then falls back to poll if |
| 156 // epoll_create fails. | 141 // epoll_create fails. |
| 157 case __NR_epoll_create: | 142 case __NR_epoll_create: |
| 158 // third_party/libevent uses them, but we can just return -1 from | 143 // third_party/libevent uses them, but we can just return -1 from |
| 159 // them as it is just checking getuid() != geteuid() and | 144 // them as it is just checking getuid() != geteuid() and |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 196 errno = 0; | 181 errno = 0; |
| 197 // Make a ptrace request with an invalid PID. | 182 // Make a ptrace request with an invalid PID. |
| 198 long ptrace_ret = ptrace(PTRACE_PEEKUSER, -1 /* pid */, NULL, NULL); | 183 long ptrace_ret = ptrace(PTRACE_PEEKUSER, -1 /* pid */, NULL, NULL); |
| 199 CHECK_EQ(-1, ptrace_ret); | 184 CHECK_EQ(-1, ptrace_ret); |
| 200 // Without the sandbox on, this ptrace call would ESRCH instead. | 185 // Without the sandbox on, this ptrace call would ESRCH instead. |
| 201 CHECK_EQ(EPERM, errno); | 186 CHECK_EQ(EPERM, errno); |
| 202 } | 187 } |
| 203 | 188 |
| 204 } // namespace | 189 } // namespace |
| 205 | 190 |
| 206 ErrorCode NaClNonSfiBPFSandboxPolicy::EvaluateSyscall(SandboxBPF* sb, | 191 ResultExpr NaClNonSfiBPFSandboxPolicy::EvaluateSyscall(int sysno) const { |
| 207 int sysno) const { | |
| 208 switch (sysno) { | 192 switch (sysno) { |
| 209 // Allowed syscalls. | 193 // Allowed syscalls. |
| 210 #if defined(__i386__) || defined(__arm__) | 194 #if defined(__i386__) || defined(__arm__) |
| 211 case __NR__llseek: | 195 case __NR__llseek: |
| 212 #elif defined(__x86_64__) | 196 #elif defined(__x86_64__) |
| 213 case __NR_lseek: | 197 case __NR_lseek: |
| 214 #endif | 198 #endif |
| 215 // NaCl runtime exposes clock_gettime and clock_getres to untrusted code. | 199 // NaCl runtime exposes clock_gettime and clock_getres to untrusted code. |
| 216 case __NR_clock_getres: | 200 case __NR_clock_getres: |
| 217 case __NR_clock_gettime: | 201 case __NR_clock_gettime: |
| (...skipping 25 matching lines...) Expand all Loading... |
| 243 case __NR_restart_syscall: | 227 case __NR_restart_syscall: |
| 244 case __NR_sched_yield: | 228 case __NR_sched_yield: |
| 245 // __NR_times needed as clock() is called by CommandBufferHelper, which is | 229 // __NR_times needed as clock() is called by CommandBufferHelper, which is |
| 246 // used by NaCl applications that use Pepper's 3D interfaces. | 230 // used by NaCl applications that use Pepper's 3D interfaces. |
| 247 // See crbug.com/264856 for details. | 231 // See crbug.com/264856 for details. |
| 248 case __NR_times: | 232 case __NR_times: |
| 249 case __NR_write: | 233 case __NR_write: |
| 250 #if defined(__arm__) | 234 #if defined(__arm__) |
| 251 case __ARM_NR_cacheflush: | 235 case __ARM_NR_cacheflush: |
| 252 #endif | 236 #endif |
| 253 return ErrorCode(ErrorCode::ERR_ALLOWED); | 237 return Allow(); |
| 254 | 238 |
| 255 case __NR_clone: | 239 case __NR_clone: |
| 256 return RestrictClone(sb); | 240 return RestrictClone(); |
| 257 | 241 |
| 258 #if defined(__x86_64__) | 242 #if defined(__x86_64__) |
| 259 case __NR_fcntl: | 243 case __NR_fcntl: |
| 260 #endif | 244 #endif |
| 261 #if defined(__i386__) || defined(__arm__) | 245 #if defined(__i386__) || defined(__arm__) |
| 262 case __NR_fcntl64: | 246 case __NR_fcntl64: |
| 263 #endif | 247 #endif |
| 264 return RestrictFcntlCommands(sb); | 248 return RestrictFcntlCommands(); |
| 265 | 249 |
| 266 #if defined(__x86_64__) | 250 #if defined(__x86_64__) |
| 267 case __NR_mmap: | 251 case __NR_mmap: |
| 268 #endif | 252 #endif |
| 269 #if defined(__i386__) || defined(__arm__) | 253 #if defined(__i386__) || defined(__arm__) |
| 270 case __NR_mmap2: | 254 case __NR_mmap2: |
| 271 #endif | 255 #endif |
| 272 return RestrictMmap(sb); | 256 return RestrictMmap(); |
| 273 case __NR_mprotect: | 257 case __NR_mprotect: |
| 274 return RestrictMprotect(sb); | 258 return RestrictMprotect(); |
| 275 | 259 |
| 276 case __NR_prctl: | 260 case __NR_prctl: |
| 277 return RestrictPrctl(sb); | 261 return RestrictPrctl(); |
| 278 | 262 |
| 279 #if defined(__i386__) | 263 #if defined(__i386__) |
| 280 case __NR_socketcall: | 264 case __NR_socketcall: |
| 281 return RestrictSocketcall(sb); | 265 return RestrictSocketcall(); |
| 282 #endif | 266 #endif |
| 283 #if defined(__x86_64__) || defined(__arm__) | 267 #if defined(__x86_64__) || defined(__arm__) |
| 284 case __NR_recvmsg: | 268 case __NR_recvmsg: |
| 285 case __NR_sendmsg: | 269 case __NR_sendmsg: |
| 286 case __NR_shutdown: | 270 case __NR_shutdown: |
| 287 return ErrorCode(ErrorCode::ERR_ALLOWED); | 271 return Allow(); |
| 288 case __NR_socketpair: | 272 case __NR_socketpair: |
| 289 return RestrictSocketpair(sb); | 273 return RestrictSocketpair(); |
| 290 #endif | 274 #endif |
| 291 | 275 |
| 292 case __NR_brk: | 276 case __NR_brk: |
| 293 // The behavior of brk on Linux is different from other system | 277 // The behavior of brk on Linux is different from other system |
| 294 // calls. It does not return errno but the current break on | 278 // calls. It does not return errno but the current break on |
| 295 // failure. glibc thinks brk failed if the return value of brk | 279 // failure. glibc thinks brk failed if the return value of brk |
| 296 // is less than the requested address (i.e., brk(addr) < addr). | 280 // is less than the requested address (i.e., brk(addr) < addr). |
| 297 // So, glibc thinks brk succeeded if we return -EPERM and we | 281 // So, glibc thinks brk succeeded if we return -EPERM and we |
| 298 // need to return zero instead. | 282 // need to return zero instead. |
| 299 return ErrorCode(0); | 283 return Error(0); |
| 300 | 284 |
| 301 default: | 285 default: |
| 302 if (IsGracefullyDenied(sysno)) | 286 if (IsGracefullyDenied(sysno)) |
| 303 return ErrorCode(EPERM); | 287 return Error(EPERM); |
| 304 return sb->Trap(sandbox::CrashSIGSYS_Handler, NULL); | 288 return Trap(sandbox::CrashSIGSYS_Handler, NULL); |
| 305 } | 289 } |
| 306 } | 290 } |
| 307 | 291 |
| 308 bool InitializeBPFSandbox() { | 292 bool InitializeBPFSandbox() { |
| 309 bool sandbox_is_initialized = content::InitializeSandbox( | 293 bool sandbox_is_initialized = content::InitializeSandbox( |
| 310 scoped_ptr<sandbox::SandboxBPFPolicy>( | 294 scoped_ptr<sandbox::SandboxBPFPolicy>( |
| 311 new nacl::nonsfi::NaClNonSfiBPFSandboxPolicy())); | 295 new nacl::nonsfi::NaClNonSfiBPFSandboxPolicy())); |
| 312 if (!sandbox_is_initialized) | 296 if (!sandbox_is_initialized) |
| 313 return false; | 297 return false; |
| 314 RunSandboxSanityChecks(); | 298 RunSandboxSanityChecks(); |
| 315 return true; | 299 return true; |
| 316 } | 300 } |
| 317 | 301 |
| 318 } // namespace nonsfi | 302 } // namespace nonsfi |
| 319 } // namespace nacl | 303 } // namespace nacl |
| OLD | NEW |