OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "content/public/common/sandbox_init.h" |
| 6 |
| 7 #if defined(OS_LINUX) && defined(__x86_64__) |
| 8 |
| 9 #include <asm/unistd.h> |
| 10 #include <errno.h> |
| 11 #include <linux/audit.h> |
| 12 #include <linux/filter.h> |
| 13 #include <signal.h> |
| 14 #include <string.h> |
| 15 #include <sys/prctl.h> |
| 16 #include <ucontext.h> |
| 17 #include <unistd.h> |
| 18 |
| 19 #include <vector> |
| 20 |
| 21 #include "base/command_line.h" |
| 22 #include "base/file_util.h" |
| 23 #include "base/logging.h" |
| 24 #include "base/time.h" |
| 25 #include "content/public/common/content_switches.h" |
| 26 |
| 27 #ifndef PR_SET_NO_NEW_PRIVS |
| 28 #define PR_SET_NO_NEW_PRIVS 38 |
| 29 #endif |
| 30 |
| 31 #ifndef SYS_SECCOMP |
| 32 #define SYS_SECCOMP 1 |
| 33 #endif |
| 34 |
| 35 #ifndef __NR_eventfd2 |
| 36 #define __NR_eventfd2 290 |
| 37 #endif |
| 38 |
| 39 // Constants from very new header files that we can't yet include. |
| 40 #ifndef SECCOMP_MODE_FILTER |
| 41 #define SECCOMP_MODE_FILTER 2 |
| 42 #define SECCOMP_RET_KILL 0x00000000U |
| 43 #define SECCOMP_RET_TRAP 0x00030000U |
| 44 #define SECCOMP_RET_ERRNO 0x00050000U |
| 45 #define SECCOMP_RET_ALLOW 0x7fff0000U |
| 46 #endif |
| 47 |
| 48 |
| 49 namespace { |
| 50 |
| 51 static void CheckSingleThreaded() { |
| 52 int num_threads = file_util::CountFilesCreatedAfter( |
| 53 FilePath("/proc/self/task"), base::Time::UnixEpoch()); |
| 54 // Possibly racy, but it's ok because this is more of a debug check to catch |
| 55 // new threaded situations arising during development. |
| 56 CHECK_EQ(num_threads, 1); |
| 57 } |
| 58 |
| 59 static void SIGSYS_Handler(int signal, siginfo_t* info, void* void_context) { |
| 60 if (signal != SIGSYS) |
| 61 return; |
| 62 if (info->si_code != SYS_SECCOMP) |
| 63 return; |
| 64 if (!void_context) |
| 65 return; |
| 66 ucontext_t* context = reinterpret_cast<ucontext_t*>(void_context); |
| 67 unsigned int syscall = context->uc_mcontext.gregs[REG_RAX]; |
| 68 if (syscall >= 1024) |
| 69 syscall = 0; |
| 70 // Purposefully dereference the syscall as an address so it'll show up very |
| 71 // clearly and easily in crash dumps. |
| 72 volatile char* addr = reinterpret_cast<volatile char*>(syscall); |
| 73 *addr = '\0'; |
| 74 _exit(1); |
| 75 } |
| 76 |
| 77 static void InstallSIGSYSHandler() { |
| 78 struct sigaction sa; |
| 79 memset(&sa, 0, sizeof(sa)); |
| 80 sa.sa_flags = SA_SIGINFO; |
| 81 sa.sa_sigaction = SIGSYS_Handler; |
| 82 int ret = sigaction(SIGSYS, &sa, NULL); |
| 83 PLOG_IF(FATAL, ret != 0) << "Failed to install SIGSYS handler."; |
| 84 } |
| 85 |
| 86 static void EmitLoad(int offset, std::vector<struct sock_filter>* program) { |
| 87 struct sock_filter filter; |
| 88 filter.code = BPF_LD+BPF_W+BPF_ABS; |
| 89 filter.jt = 0; |
| 90 filter.jf = 0; |
| 91 filter.k = offset; |
| 92 program->push_back(filter); |
| 93 } |
| 94 |
| 95 static void EmitJEQJT1(int value, std::vector<struct sock_filter>* program) { |
| 96 struct sock_filter filter; |
| 97 filter.code = BPF_JMP+BPF_JEQ+BPF_K; |
| 98 filter.jt = 1; |
| 99 filter.jf = 0; |
| 100 filter.k = value; |
| 101 program->push_back(filter); |
| 102 } |
| 103 |
| 104 static void EmitJEQJF1(int value, std::vector<struct sock_filter>* program) { |
| 105 struct sock_filter filter; |
| 106 filter.code = BPF_JMP+BPF_JEQ+BPF_K; |
| 107 filter.jt = 0; |
| 108 filter.jf = 1; |
| 109 filter.k = value; |
| 110 program->push_back(filter); |
| 111 } |
| 112 |
| 113 static void EmitRet(int value, std::vector<struct sock_filter>* program) { |
| 114 struct sock_filter filter; |
| 115 filter.code = BPF_RET+BPF_K; |
| 116 filter.jt = 0; |
| 117 filter.jf = 0; |
| 118 filter.k = value; |
| 119 program->push_back(filter); |
| 120 } |
| 121 |
| 122 static void EmitPreamble(std::vector<struct sock_filter>* program) { |
| 123 // First, check correct syscall arch. |
| 124 // "4" is magic offset for the arch number. |
| 125 EmitLoad(4, program); |
| 126 EmitJEQJT1(AUDIT_ARCH_X86_64, program); |
| 127 EmitRet(SECCOMP_RET_KILL, program); |
| 128 |
| 129 // Load the syscall number. |
| 130 // "0" is magic offset for the syscall number. |
| 131 EmitLoad(0, program); |
| 132 } |
| 133 |
| 134 static void EmitAllowSyscall(int nr, std::vector<struct sock_filter>* program) { |
| 135 EmitJEQJF1(nr, program); |
| 136 EmitRet(SECCOMP_RET_ALLOW, program); |
| 137 } |
| 138 |
| 139 static void EmitFailSyscall(int nr, int err, |
| 140 std::vector<struct sock_filter>* program) { |
| 141 EmitJEQJF1(nr, program); |
| 142 EmitRet(SECCOMP_RET_ERRNO | err, program); |
| 143 } |
| 144 |
| 145 static void EmitTrap(std::vector<struct sock_filter>* program) { |
| 146 EmitRet(SECCOMP_RET_TRAP, program); |
| 147 } |
| 148 |
| 149 static void ApplyGPUPolicy(std::vector<struct sock_filter>* program) { |
| 150 // "Hot" syscalls go first. |
| 151 EmitAllowSyscall(__NR_read, program); |
| 152 EmitAllowSyscall(__NR_ioctl, program); |
| 153 EmitAllowSyscall(__NR_poll, program); |
| 154 EmitAllowSyscall(__NR_epoll_wait, program); |
| 155 EmitAllowSyscall(__NR_recvfrom, program); |
| 156 EmitAllowSyscall(__NR_write, program); |
| 157 EmitAllowSyscall(__NR_writev, program); |
| 158 EmitAllowSyscall(__NR_gettid, program); |
| 159 |
| 160 // Less hot syscalls. |
| 161 EmitAllowSyscall(__NR_futex, program); |
| 162 EmitAllowSyscall(__NR_madvise, program); |
| 163 EmitAllowSyscall(__NR_sendmsg, program); |
| 164 EmitAllowSyscall(__NR_recvmsg, program); |
| 165 EmitAllowSyscall(__NR_eventfd2, program); |
| 166 EmitAllowSyscall(__NR_pipe, program); |
| 167 EmitAllowSyscall(__NR_mmap, program); |
| 168 EmitAllowSyscall(__NR_mprotect, program); |
| 169 EmitAllowSyscall(__NR_clone, program); |
| 170 EmitAllowSyscall(__NR_set_robust_list, program); |
| 171 EmitAllowSyscall(__NR_getuid, program); |
| 172 EmitAllowSyscall(__NR_geteuid, program); |
| 173 EmitAllowSyscall(__NR_getgid, program); |
| 174 EmitAllowSyscall(__NR_getegid, program); |
| 175 EmitAllowSyscall(__NR_epoll_create, program); |
| 176 EmitAllowSyscall(__NR_fcntl, program); |
| 177 EmitAllowSyscall(__NR_socketpair, program); |
| 178 EmitAllowSyscall(__NR_epoll_ctl, program); |
| 179 EmitAllowSyscall(__NR_prctl, program); |
| 180 EmitAllowSyscall(__NR_fstat, program); |
| 181 EmitAllowSyscall(__NR_close, program); |
| 182 EmitAllowSyscall(__NR_restart_syscall, program); |
| 183 EmitAllowSyscall(__NR_rt_sigreturn, program); |
| 184 EmitAllowSyscall(__NR_brk, program); |
| 185 EmitAllowSyscall(__NR_rt_sigprocmask, program); |
| 186 EmitAllowSyscall(__NR_munmap, program); |
| 187 EmitAllowSyscall(__NR_dup, program); |
| 188 EmitAllowSyscall(__NR_mlock, program); |
| 189 EmitAllowSyscall(__NR_munlock, program); |
| 190 EmitAllowSyscall(__NR_exit, program); |
| 191 EmitAllowSyscall(__NR_exit_group, program); |
| 192 |
| 193 EmitFailSyscall(__NR_open, ENOENT, program); |
| 194 EmitFailSyscall(__NR_access, ENOENT, program); |
| 195 } |
| 196 |
| 197 static bool CanUseSeccompFilters() { |
| 198 int ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, 0, 0, 0); |
| 199 if (ret != 0 && errno == EFAULT) |
| 200 return true; |
| 201 return false; |
| 202 } |
| 203 |
| 204 static void InstallFilter(const std::vector<struct sock_filter>& program) { |
| 205 int ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); |
| 206 PLOG_IF(FATAL, ret != 0) << "prctl(PR_SET_NO_NEW_PRIVS) failed"; |
| 207 |
| 208 struct sock_fprog fprog; |
| 209 fprog.len = program.size(); |
| 210 fprog.filter = const_cast<struct sock_filter*>(&program[0]); |
| 211 |
| 212 ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &fprog, 0, 0); |
| 213 PLOG_IF(FATAL, ret != 0) << "Failed to install filter."; |
| 214 } |
| 215 |
| 216 } // anonymous namespace |
| 217 |
| 218 namespace content { |
| 219 |
| 220 void InitializeSandbox() { |
| 221 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
| 222 if (command_line.HasSwitch(switches::kNoSandbox)) |
| 223 return; |
| 224 |
| 225 std::string process_type = |
| 226 command_line.GetSwitchValueASCII(switches::kProcessType); |
| 227 if (process_type == switches::kGpuProcess && |
| 228 command_line.HasSwitch(switches::kDisableGpuSandbox)) |
| 229 return; |
| 230 |
| 231 if (!CanUseSeccompFilters()) |
| 232 return; |
| 233 |
| 234 CheckSingleThreaded(); |
| 235 |
| 236 std::vector<struct sock_filter> program; |
| 237 EmitPreamble(&program); |
| 238 |
| 239 if (process_type == switches::kGpuProcess) { |
| 240 ApplyGPUPolicy(&program); |
| 241 } else { |
| 242 NOTREACHED(); |
| 243 } |
| 244 |
| 245 EmitTrap(&program); |
| 246 |
| 247 InstallSIGSYSHandler(); |
| 248 InstallFilter(program); |
| 249 } |
| 250 |
| 251 } // namespace content |
| 252 |
| 253 #else |
| 254 |
| 255 namespace content { |
| 256 |
| 257 void InitializeSandbox() { |
| 258 } |
| 259 |
| 260 } // namespace content |
| 261 |
| 262 #endif |
| 263 |
OLD | NEW |