OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 <asm/unistd.h> | 5 #include <asm/unistd.h> |
6 #include <dlfcn.h> | 6 #include <dlfcn.h> |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <fcntl.h> | 8 #include <fcntl.h> |
9 #include <linux/audit.h> | 9 #include <linux/audit.h> |
10 #include <linux/filter.h> | 10 #include <linux/filter.h> |
11 #include <signal.h> | 11 #include <signal.h> |
12 #include <string.h> | 12 #include <string.h> |
13 #include <sys/prctl.h> | 13 #include <sys/prctl.h> |
14 #include <sys/stat.h> | 14 #include <sys/stat.h> |
15 #include <sys/types.h> | 15 #include <sys/types.h> |
16 #include <ucontext.h> | 16 #include <ucontext.h> |
17 #include <unistd.h> | 17 #include <unistd.h> |
18 | 18 |
19 #include <vector> | 19 #include <vector> |
20 | 20 |
21 #include "base/command_line.h" | 21 #include "base/command_line.h" |
22 #include "base/logging.h" | 22 #include "base/logging.h" |
23 #include "content/common/sandbox_linux.h" | 23 #include "content/common/sandbox_linux.h" |
24 #include "content/common/sandbox_seccomp_bpf_linux.h" | 24 #include "content/common/sandbox_seccomp_bpf_linux.h" |
25 #include "content/public/common/content_switches.h" | 25 #include "content/public/common/content_switches.h" |
26 #include "sandbox/linux/services/broker_process.h" | |
26 | 27 |
27 // These are the only architectures supported for now. | 28 // These are the only architectures supported for now. |
28 #if defined(__i386__) || defined(__x86_64__) || \ | 29 #if defined(__i386__) || defined(__x86_64__) || \ |
29 (defined(__arm__) && (defined(__thumb__) || defined(__ARM_EABI__))) | 30 (defined(__arm__) && (defined(__thumb__) || defined(__ARM_EABI__))) |
30 #define SECCOMP_BPF_SANDBOX | 31 #define SECCOMP_BPF_SANDBOX |
31 #endif | 32 #endif |
32 | 33 |
33 #if defined(SECCOMP_BPF_SANDBOX) | 34 #if defined(SECCOMP_BPF_SANDBOX) |
34 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" | 35 #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" |
35 #include "sandbox/linux/services/linux_syscalls.h" | 36 #include "sandbox/linux/services/linux_syscalls.h" |
36 | 37 |
37 using playground2::arch_seccomp_data; | 38 using playground2::arch_seccomp_data; |
38 using playground2::ErrorCode; | 39 using playground2::ErrorCode; |
39 using playground2::Sandbox; | 40 using playground2::Sandbox; |
41 using sandbox::BrokerProcess; | |
40 | 42 |
41 namespace { | 43 namespace { |
42 | 44 |
45 void StartSandboxWithPolicy(Sandbox::EvaluateSyscall syscall_policy, | |
46 BrokerProcess* broker_process); | |
47 | |
43 inline bool IsChromeOS() { | 48 inline bool IsChromeOS() { |
44 #if defined(OS_CHROMEOS) | 49 #if defined(OS_CHROMEOS) |
45 return true; | 50 return true; |
46 #else | 51 #else |
47 return false; | 52 return false; |
48 #endif | 53 #endif |
49 } | 54 } |
50 | 55 |
51 inline bool IsArchitectureI386() { | 56 inline bool IsArchitectureI386() { |
52 #if defined(__i386__) | 57 #if defined(__i386__) |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
93 // but not on Linux: crbug.com/137247. | 98 // but not on Linux: crbug.com/137247. |
94 bool is_enabled = IsChromeOS(); | 99 bool is_enabled = IsChromeOS(); |
95 | 100 |
96 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); | 101 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
97 is_enabled = is_enabled && | 102 is_enabled = is_enabled && |
98 !command_line.HasSwitch(switches::kDisableAcceleratedVideoDecode); | 103 !command_line.HasSwitch(switches::kDisableAcceleratedVideoDecode); |
99 | 104 |
100 return is_enabled; | 105 return is_enabled; |
101 } | 106 } |
102 | 107 |
103 static const char kDriRcPath[] = "/etc/drirc"; | 108 intptr_t GpuOpenSIGSYS_Handler(const struct arch_seccomp_data& args, |
Markus (顧孟勤)
2012/12/14 20:23:29
Just a nitpick. I prefer if you didn't refer to SI
| |
104 | 109 void* aux_broker_process) { |
105 // TODO(jorgelo): limited to /etc/drirc for now, extend this to cover | 110 RAW_CHECK(aux_broker_process); |
106 // other sandboxed file access cases. | 111 BrokerProcess* broker_process = |
107 int OpenWithCache(const char* pathname, int flags) { | 112 static_cast<BrokerProcess*>(aux_broker_process); |
108 static int drircfd = -1; | 113 switch(args.nr) { |
109 static bool do_open = true; | 114 case __NR_open: |
110 int res = -1; | 115 return broker_process->Open(reinterpret_cast<const char*>(args.args[0]), |
111 | 116 static_cast<int>(args.args[1])); |
112 if (strcmp(pathname, kDriRcPath) == 0 && flags == O_RDONLY) { | 117 case __NR_openat: |
113 if (do_open) { | 118 // We only call open() so if we arrive here, it's because glibc uses |
114 drircfd = open(pathname, flags); | 119 // the openat() system call. |
115 do_open = false; | 120 if (static_cast<int>(args.args[0]) == AT_FDCWD) { |
116 res = drircfd; | 121 return |
117 } else { | 122 broker_process->Open(reinterpret_cast<const char*>(args.args[1]), |
118 // dup() man page: | 123 static_cast<int>(args.args[2])); |
119 // "After a successful return from one of these system calls, | 124 } else { |
120 // the old and new file descriptors may be used interchangeably. | 125 return -EPERM; |
121 // They refer to the same open file description and thus share | |
122 // file offset and file status flags; for example, if the file offset | |
123 // is modified by using lseek(2) on one of the descriptors, | |
124 // the offset is also changed for the other." | |
125 // Since |drircfd| can be dup()'ed and read many times, we need to | |
126 // lseek() it to the beginning of the file before returning. | |
127 // We assume the caller will not keep more than one fd open at any | |
128 // one time. Intel driver code in Mesa that parses /etc/drirc does | |
129 // open()/read()/close() in the same function. | |
130 if (drircfd < 0) { | |
131 errno = ENOENT; | |
132 return -1; | |
133 } | 126 } |
134 int newfd = dup(drircfd); | 127 default: |
135 if (newfd < 0) { | 128 RAW_CHECK(false); |
136 errno = ENOMEM; | 129 return -ENOSYS; |
137 return -1; | |
138 } | |
139 if (lseek(newfd, 0, SEEK_SET) == static_cast<off_t>(-1)) { | |
140 (void) HANDLE_EINTR(close(newfd)); | |
141 errno = ENOMEM; | |
142 return -1; | |
143 } | |
144 res = newfd; | |
145 } | |
146 } else { | |
147 res = open(pathname, flags); | |
148 } | |
149 | |
150 return res; | |
151 } | |
152 | |
153 // We allow the GPU process to open /etc/drirc because it's needed by Mesa. | |
154 // OpenWithCache() has been called before enabling the sandbox, and has cached | |
155 // a file descriptor for /etc/drirc. | |
156 intptr_t GpuOpenSIGSYS_Handler(const struct arch_seccomp_data& args, | |
157 void* aux) { | |
158 uint64_t arg0 = args.args[0]; | |
159 uint64_t arg1 = args.args[1]; | |
160 const char* pathname = reinterpret_cast<const char*>(arg0); | |
161 int flags = static_cast<int>(arg1); | |
162 | |
163 if (strcmp(pathname, kDriRcPath) == 0) { | |
164 int ret = OpenWithCache(pathname, flags); | |
165 return (ret == -1) ? -errno : ret; | |
166 } else { | |
167 return -ENOENT; | |
168 } | 130 } |
169 } | 131 } |
170 | 132 |
171 // The functions below cover all existing i386, x86_64, and ARM system calls; | 133 // The functions below cover all existing i386, x86_64, and ARM system calls; |
172 // excluding syscalls made obsolete in ARM EABI. | 134 // excluding syscalls made obsolete in ARM EABI. |
173 // The implicitly defined sets form a partition of the sets of | 135 // The implicitly defined sets form a partition of the sets of |
174 // system calls. | 136 // system calls. |
175 | 137 |
176 // TODO(jln) we need to restrict the first parameter! | 138 // TODO(jln) we need to restrict the first parameter! |
177 bool IsKill(int sysno) { | 139 bool IsKill(int sysno) { |
(...skipping 1049 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1227 if (IsBaselinePolicyWatched(sysno)) { | 1189 if (IsBaselinePolicyWatched(sysno)) { |
1228 // Previously unseen syscalls. TODO(jln): some of these should | 1190 // Previously unseen syscalls. TODO(jln): some of these should |
1229 // be denied gracefully right away. | 1191 // be denied gracefully right away. |
1230 return Sandbox::Trap(CrashSIGSYS_Handler, NULL); | 1192 return Sandbox::Trap(CrashSIGSYS_Handler, NULL); |
1231 } | 1193 } |
1232 // In any other case crash the program with our SIGSYS handler | 1194 // In any other case crash the program with our SIGSYS handler |
1233 return Sandbox::Trap(CrashSIGSYS_Handler, NULL); | 1195 return Sandbox::Trap(CrashSIGSYS_Handler, NULL); |
1234 } | 1196 } |
1235 | 1197 |
1236 // x86_64 only for now. Needs to be adapted and tested for i386/ARM. | 1198 // x86_64 only for now. Needs to be adapted and tested for i386/ARM. |
1237 ErrorCode GpuProcessPolicy_x86_64(int sysno, void *) { | 1199 ErrorCode GpuProcessPolicy_x86_64(int sysno, void *broker_process) { |
1238 switch(sysno) { | 1200 switch(sysno) { |
1239 case __NR_ioctl: | 1201 case __NR_ioctl: |
1240 #if defined(ADDRESS_SANITIZER) | 1202 #if defined(ADDRESS_SANITIZER) |
1241 // Allow to call sched_getaffinity under AddressSanitizer. | 1203 // Allow to call sched_getaffinity under AddressSanitizer. |
1242 case __NR_sched_getaffinity: | 1204 case __NR_sched_getaffinity: |
1243 #endif | 1205 #endif |
1244 return ErrorCode(ErrorCode::ERR_ALLOWED); | 1206 return ErrorCode(ErrorCode::ERR_ALLOWED); |
1245 case __NR_open: | 1207 case __NR_open: |
1246 // Accelerated video decode is enabled by default only on Chrome OS. | 1208 case __NR_openat: |
1247 if (IsAcceleratedVideoDecodeEnabled()) { | 1209 return Sandbox::Trap(GpuOpenSIGSYS_Handler, broker_process); |
1248 // Accelerated video decode needs to open /dev/dri/card0, and | |
1249 // dup()'ing an already open file descriptor does not work. | |
1250 // Allow open() even though it severely weakens the sandbox, | |
1251 // to test the sandboxing mechanism in general. | |
1252 // TODO(jorgelo): remove this once we solve the libva issue. | |
1253 return ErrorCode(ErrorCode::ERR_ALLOWED); | |
1254 } else { | |
1255 // Hook open() in the GPU process to allow opening /etc/drirc, | |
1256 // needed by Mesa. | |
1257 // The hook needs dup(), lseek(), and close() to be allowed. | |
1258 return Sandbox::Trap(GpuOpenSIGSYS_Handler, NULL); | |
1259 } | |
1260 default: | 1210 default: |
1261 if (IsEventFd(sysno)) | 1211 if (IsEventFd(sysno)) |
1262 return ErrorCode(ErrorCode::ERR_ALLOWED); | 1212 return ErrorCode(ErrorCode::ERR_ALLOWED); |
1263 | 1213 |
1264 // Default on the baseline policy. | 1214 // Default on the baseline policy. |
1265 return BaselinePolicy(sysno); | 1215 return BaselinePolicy(sysno); |
1266 } | 1216 } |
1267 } | 1217 } |
1268 | 1218 |
1219 // x86_64 only for now. Needs to be adapted and tested for i386/ARM. | |
1220 // A GPU broker policy is the same as a GPU policy with open and | |
1221 // openat allowed. | |
1222 ErrorCode GpuBrokerProcessPolicy_x86_64(int sysno, void*) { | |
1223 switch(sysno) { | |
1224 case __NR_open: | |
1225 case __NR_openat: | |
1226 return ErrorCode(ErrorCode::ERR_ALLOWED); | |
1227 default: | |
1228 return GpuProcessPolicy_x86_64(sysno, NULL); | |
1229 } | |
1230 } | |
1231 | |
1269 ErrorCode RendererOrWorkerProcessPolicy(int sysno, void *) { | 1232 ErrorCode RendererOrWorkerProcessPolicy(int sysno, void *) { |
1270 switch (sysno) { | 1233 switch (sysno) { |
1271 case __NR_ioctl: // TODO(jln) investigate legitimate use in the renderer | 1234 case __NR_ioctl: // TODO(jln) investigate legitimate use in the renderer |
1272 // and see if alternatives can be used. | 1235 // and see if alternatives can be used. |
1273 case __NR_fdatasync: | 1236 case __NR_fdatasync: |
1274 case __NR_fsync: | 1237 case __NR_fsync: |
1275 #if defined(__i386__) || defined(__x86_64__) | 1238 #if defined(__i386__) || defined(__x86_64__) |
1276 case __NR_getrlimit: | 1239 case __NR_getrlimit: |
1277 #endif | 1240 #endif |
1278 case __NR_mremap: // See crbug.com/149834. | 1241 case __NR_mremap: // See crbug.com/149834. |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1351 // 64 bits system calls in compatibility mode. | 1314 // 64 bits system calls in compatibility mode. |
1352 ErrorCode AllowAllPolicy(int sysno, void *) { | 1315 ErrorCode AllowAllPolicy(int sysno, void *) { |
1353 if (!Sandbox::isValidSyscallNumber(sysno)) { | 1316 if (!Sandbox::isValidSyscallNumber(sysno)) { |
1354 // TODO(jln) we should not have to do that in a trivial policy. | 1317 // TODO(jln) we should not have to do that in a trivial policy. |
1355 return ErrorCode(ENOSYS); | 1318 return ErrorCode(ENOSYS); |
1356 } else { | 1319 } else { |
1357 return ErrorCode(ErrorCode::ERR_ALLOWED); | 1320 return ErrorCode(ErrorCode::ERR_ALLOWED); |
1358 } | 1321 } |
1359 } | 1322 } |
1360 | 1323 |
1324 bool EnableGpuBrokerPolicyCallBack() { | |
1325 StartSandboxWithPolicy(GpuBrokerProcessPolicy_x86_64, NULL); | |
1326 return true; | |
1327 } | |
1328 | |
1329 // Start a broker process to handle open() inside the sandbox. | |
1330 void InitGpu64BrokerProcess(BrokerProcess** broker_process) { | |
1331 static const char kDriRcPath[] = "/etc/drirc"; | |
1332 static const char kDriCard0Path[] = "/dev/dri/card0"; | |
1333 | |
1334 CHECK(broker_process); | |
1335 CHECK(*broker_process == NULL); | |
1336 | |
1337 std::vector<std::string> read_whitelist; | |
1338 read_whitelist.push_back(kDriCard0Path); | |
1339 read_whitelist.push_back(kDriRcPath); | |
1340 std::vector<std::string> write_whitelist; | |
1341 write_whitelist.push_back(kDriCard0Path); | |
1342 | |
1343 *broker_process = new BrokerProcess(read_whitelist, write_whitelist); | |
1344 // Initialize the broker process and give it a sandbox call back. | |
1345 CHECK((*broker_process)->Init(EnableGpuBrokerPolicyCallBack)); | |
1346 } | |
1347 | |
1361 // Warms up/preloads resources needed by the policies. | 1348 // Warms up/preloads resources needed by the policies. |
1362 void WarmupPolicy(Sandbox::EvaluateSyscall policy) { | 1349 void WarmupPolicy(Sandbox::EvaluateSyscall policy, |
1350 BrokerProcess** broker_process) { | |
1363 #if defined(__x86_64__) | 1351 #if defined(__x86_64__) |
1364 if (policy == GpuProcessPolicy_x86_64) { | 1352 if (policy == GpuProcessPolicy_x86_64) { |
1365 OpenWithCache(kDriRcPath, O_RDONLY); | |
1366 // Accelerated video decode dlopen()'s this shared object | 1353 // Accelerated video decode dlopen()'s this shared object |
1367 // inside the sandbox, so preload it now. | 1354 // inside the sandbox, so preload it now. |
1368 // TODO(jorgelo): generalize this to other platforms. | 1355 // TODO(jorgelo): generalize this to other platforms. |
1369 if (IsAcceleratedVideoDecodeEnabled()) { | 1356 if (IsAcceleratedVideoDecodeEnabled()) { |
1370 const char kI965DrvVideoPath_64[] = | 1357 const char kI965DrvVideoPath_64[] = |
1371 "/usr/lib64/va/drivers/i965_drv_video.so"; | 1358 "/usr/lib64/va/drivers/i965_drv_video.so"; |
1372 dlopen(kI965DrvVideoPath_64, RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE); | 1359 dlopen(kI965DrvVideoPath_64, RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE); |
1373 } | 1360 } |
1361 InitGpu64BrokerProcess(broker_process); | |
1374 } | 1362 } |
1375 #endif | 1363 #endif |
1376 } | 1364 } |
1377 | 1365 |
1378 Sandbox::EvaluateSyscall GetProcessSyscallPolicy( | 1366 Sandbox::EvaluateSyscall GetProcessSyscallPolicy( |
1379 const CommandLine& command_line, | 1367 const CommandLine& command_line, |
1380 const std::string& process_type) { | 1368 const std::string& process_type) { |
1381 if (process_type == switches::kGpuProcess) { | 1369 if (process_type == switches::kGpuProcess) { |
1382 // On Chrome OS, --enable-gpu-sandbox enables the more restrictive policy. | 1370 // On Chrome OS, --enable-gpu-sandbox enables the more restrictive policy. |
1383 // However, we don't yet enable the more restrictive GPU process policy | 1371 // However, we don't yet enable the more restrictive GPU process policy |
(...skipping 18 matching lines...) Expand all Loading... | |
1402 | 1390 |
1403 if (process_type == switches::kUtilityProcess) { | 1391 if (process_type == switches::kUtilityProcess) { |
1404 return BlacklistDebugAndNumaPolicy; | 1392 return BlacklistDebugAndNumaPolicy; |
1405 } | 1393 } |
1406 | 1394 |
1407 NOTREACHED(); | 1395 NOTREACHED(); |
1408 // This will be our default if we need one. | 1396 // This will be our default if we need one. |
1409 return AllowAllPolicy; | 1397 return AllowAllPolicy; |
1410 } | 1398 } |
1411 | 1399 |
1400 // broker_process can be NULL if there is no need for one. | |
1401 void StartSandboxWithPolicy(Sandbox::EvaluateSyscall syscall_policy, | |
1402 BrokerProcess* broker_process) { | |
1403 | |
1404 Sandbox::setSandboxPolicy(syscall_policy, broker_process); | |
1405 Sandbox::startSandbox(); | |
1406 } | |
1407 | |
1412 // Initialize the seccomp-bpf sandbox. | 1408 // Initialize the seccomp-bpf sandbox. |
1409 // Eventually create a BrokerProcess and return it to broker_process. | |
1413 bool StartBpfSandbox(const CommandLine& command_line, | 1410 bool StartBpfSandbox(const CommandLine& command_line, |
1414 const std::string& process_type) { | 1411 const std::string& process_type) { |
1415 Sandbox::EvaluateSyscall SyscallPolicy = | 1412 Sandbox::EvaluateSyscall syscall_policy = |
1416 GetProcessSyscallPolicy(command_line, process_type); | 1413 GetProcessSyscallPolicy(command_line, process_type); |
1417 | 1414 |
1418 // Warms up resources needed by the policy we're about to enable. | 1415 BrokerProcess* broker_process = NULL; |
1419 WarmupPolicy(SyscallPolicy); | 1416 // Warms up resources needed by the policy we're about to enable and |
1417 // eventually start a broker process. | |
1418 WarmupPolicy(syscall_policy, &broker_process); | |
1420 | 1419 |
1421 Sandbox::setSandboxPolicy(SyscallPolicy, NULL); | 1420 StartSandboxWithPolicy(syscall_policy, broker_process); |
1422 Sandbox::startSandbox(); | |
1423 | 1421 |
1424 return true; | 1422 return true; |
1425 } | 1423 } |
1426 | 1424 |
1427 } // namespace | 1425 } // namespace |
1428 | 1426 |
1429 #endif // SECCOMP_BPF_SANDBOX | 1427 #endif // SECCOMP_BPF_SANDBOX |
1430 | 1428 |
1431 namespace content { | 1429 namespace content { |
1432 | 1430 |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1481 // should enable it, enable it or die. | 1479 // should enable it, enable it or die. |
1482 bool started_sandbox = StartBpfSandbox(command_line, process_type); | 1480 bool started_sandbox = StartBpfSandbox(command_line, process_type); |
1483 CHECK(started_sandbox); | 1481 CHECK(started_sandbox); |
1484 return true; | 1482 return true; |
1485 } | 1483 } |
1486 #endif | 1484 #endif |
1487 return false; | 1485 return false; |
1488 } | 1486 } |
1489 | 1487 |
1490 } // namespace content | 1488 } // namespace content |
OLD | NEW |