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 |
43 inline bool IsChromeOS() { | 45 inline bool IsChromeOS() { |
44 #if defined(OS_CHROMEOS) | 46 #if defined(OS_CHROMEOS) |
45 return true; | 47 return true; |
46 #else | 48 #else |
47 return false; | 49 return false; |
48 #endif | 50 #endif |
49 } | 51 } |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
93 // but not on Linux: crbug.com/137247. | 95 // but not on Linux: crbug.com/137247. |
94 bool is_enabled = IsChromeOS(); | 96 bool is_enabled = IsChromeOS(); |
95 | 97 |
96 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); | 98 const CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
97 is_enabled = is_enabled && | 99 is_enabled = is_enabled && |
98 !command_line.HasSwitch(switches::kDisableAcceleratedVideoDecode); | 100 !command_line.HasSwitch(switches::kDisableAcceleratedVideoDecode); |
99 | 101 |
100 return is_enabled; | 102 return is_enabled; |
101 } | 103 } |
102 | 104 |
103 static const char kDriRcPath[] = "/etc/drirc"; | 105 intptr_t GpuOpenSIGSYS_Handler(const struct arch_seccomp_data& args, |
104 | 106 void* aux_broker_process) { |
105 // TODO(jorgelo): limited to /etc/drirc for now, extend this to cover | 107 RAW_CHECK(aux_broker_process); |
106 // other sandboxed file access cases. | 108 BrokerProcess* broker_process = |
107 int OpenWithCache(const char* pathname, int flags) { | 109 static_cast<BrokerProcess*>(aux_broker_process); |
108 static int drircfd = -1; | 110 switch(args.nr) { |
109 static bool do_open = true; | 111 case __NR_open: |
110 int res = -1; | 112 return broker_process->Open(reinterpret_cast<const char*>(args.args[0]), |
111 | 113 static_cast<int>(args.args[1])); |
112 if (strcmp(pathname, kDriRcPath) == 0 && flags == O_RDONLY) { | 114 case __NR_openat: |
113 if (do_open) { | 115 // We only call open() so if we arrive here, it's because glibc uses |
114 drircfd = open(pathname, flags); | 116 // the openat() system call. |
115 do_open = false; | 117 if (static_cast<int>(args.args[0]) == AT_FDCWD) { |
116 res = drircfd; | 118 return |
117 } else { | 119 broker_process->Open(reinterpret_cast<const char*>(args.args[1]), |
118 // dup() man page: | 120 static_cast<int>(args.args[2])); |
119 // "After a successful return from one of these system calls, | 121 } else { |
120 // the old and new file descriptors may be used interchangeably. | 122 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 } | 123 } |
134 int newfd = dup(drircfd); | 124 default: |
135 if (newfd < 0) { | 125 RAW_CHECK(false); |
136 errno = ENOMEM; | 126 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 } | 127 } |
169 } | 128 } |
170 | 129 |
171 // The functions below cover all existing i386, x86_64, and ARM system calls; | 130 // The functions below cover all existing i386, x86_64, and ARM system calls; |
172 // excluding syscalls made obsolete in ARM EABI. | 131 // excluding syscalls made obsolete in ARM EABI. |
173 // The implicitly defined sets form a partition of the sets of | 132 // The implicitly defined sets form a partition of the sets of |
174 // system calls. | 133 // system calls. |
175 | 134 |
176 // TODO(jln) we need to restrict the first parameter! | 135 // TODO(jln) we need to restrict the first parameter! |
177 bool IsKill(int sysno) { | 136 bool IsKill(int sysno) { |
(...skipping 1049 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1227 if (IsBaselinePolicyWatched(sysno)) { | 1186 if (IsBaselinePolicyWatched(sysno)) { |
1228 // Previously unseen syscalls. TODO(jln): some of these should | 1187 // Previously unseen syscalls. TODO(jln): some of these should |
1229 // be denied gracefully right away. | 1188 // be denied gracefully right away. |
1230 return Sandbox::Trap(CrashSIGSYS_Handler, NULL); | 1189 return Sandbox::Trap(CrashSIGSYS_Handler, NULL); |
1231 } | 1190 } |
1232 // In any other case crash the program with our SIGSYS handler | 1191 // In any other case crash the program with our SIGSYS handler |
1233 return Sandbox::Trap(CrashSIGSYS_Handler, NULL); | 1192 return Sandbox::Trap(CrashSIGSYS_Handler, NULL); |
1234 } | 1193 } |
1235 | 1194 |
1236 // x86_64 only for now. Needs to be adapted and tested for i386/ARM. | 1195 // x86_64 only for now. Needs to be adapted and tested for i386/ARM. |
1237 ErrorCode GpuProcessPolicy_x86_64(int sysno, void *) { | 1196 ErrorCode GpuProcessPolicy_x86_64(int sysno, void *broker_process) { |
1238 switch(sysno) { | 1197 switch(sysno) { |
1239 case __NR_ioctl: | 1198 case __NR_ioctl: |
1240 #if defined(ADDRESS_SANITIZER) | 1199 #if defined(ADDRESS_SANITIZER) |
1241 // Allow to call sched_getaffinity under AddressSanitizer. | 1200 // Allow to call sched_getaffinity under AddressSanitizer. |
1242 case __NR_sched_getaffinity: | 1201 case __NR_sched_getaffinity: |
1243 #endif | 1202 #endif |
1244 return ErrorCode(ErrorCode::ERR_ALLOWED); | 1203 return ErrorCode(ErrorCode::ERR_ALLOWED); |
1245 case __NR_open: | 1204 case __NR_open: |
1246 // Accelerated video decode is enabled by default only on Chrome OS. | 1205 case __NR_openat: |
1247 if (IsAcceleratedVideoDecodeEnabled()) { | 1206 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: | 1207 default: |
1261 if (IsEventFd(sysno)) | 1208 if (IsEventFd(sysno)) |
1262 return ErrorCode(ErrorCode::ERR_ALLOWED); | 1209 return ErrorCode(ErrorCode::ERR_ALLOWED); |
1263 | 1210 |
1264 // Default on the baseline policy. | 1211 // Default on the baseline policy. |
1265 return BaselinePolicy(sysno); | 1212 return BaselinePolicy(sysno); |
1266 } | 1213 } |
1267 } | 1214 } |
1268 | 1215 |
1269 ErrorCode RendererOrWorkerProcessPolicy(int sysno, void *) { | 1216 ErrorCode RendererOrWorkerProcessPolicy(int sysno, void *) { |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1351 // 64 bits system calls in compatibility mode. | 1298 // 64 bits system calls in compatibility mode. |
1352 ErrorCode AllowAllPolicy(int sysno, void *) { | 1299 ErrorCode AllowAllPolicy(int sysno, void *) { |
1353 if (!Sandbox::isValidSyscallNumber(sysno)) { | 1300 if (!Sandbox::isValidSyscallNumber(sysno)) { |
1354 // TODO(jln) we should not have to do that in a trivial policy. | 1301 // TODO(jln) we should not have to do that in a trivial policy. |
1355 return ErrorCode(ENOSYS); | 1302 return ErrorCode(ENOSYS); |
1356 } else { | 1303 } else { |
1357 return ErrorCode(ErrorCode::ERR_ALLOWED); | 1304 return ErrorCode(ErrorCode::ERR_ALLOWED); |
1358 } | 1305 } |
1359 } | 1306 } |
1360 | 1307 |
1308 // Start a broker process to handle open() inside the sandbox. | |
1309 void InitGpu64BrokerProcess(BrokerProcess** broker_process) { | |
Jorge Lucangeli Obes
2012/12/14 19:13:22
X86_64 I guess, although it does make the name of
jln (very slow on Chromium)
2012/12/14 20:30:25
Done.
| |
1310 static const char kDriRcPath[] = "/etc/drirc"; | |
1311 static const char kDriCard0Path[] = "/dev/dri/card0"; | |
1312 | |
1313 CHECK(broker_process); | |
1314 CHECK(*broker_process == NULL); | |
1315 | |
1316 std::vector<std::string> read_whitelist; | |
1317 read_whitelist.push_back(kDriCard0Path); | |
1318 read_whitelist.push_back(kDriRcPath); | |
1319 std::vector<std::string> write_whitelist; | |
1320 write_whitelist.push_back(kDriCard0Path); | |
1321 | |
1322 *broker_process = new BrokerProcess(read_whitelist, write_whitelist); | |
1323 CHECK((*broker_process)->Init(NULL)); | |
1324 } | |
1325 | |
1361 // Warms up/preloads resources needed by the policies. | 1326 // Warms up/preloads resources needed by the policies. |
1362 void WarmupPolicy(Sandbox::EvaluateSyscall policy) { | 1327 void WarmupPolicy(Sandbox::EvaluateSyscall policy, |
1328 BrokerProcess** broker_process) { | |
1363 #if defined(__x86_64__) | 1329 #if defined(__x86_64__) |
1364 if (policy == GpuProcessPolicy_x86_64) { | 1330 if (policy == GpuProcessPolicy_x86_64) { |
1365 OpenWithCache(kDriRcPath, O_RDONLY); | |
1366 // Accelerated video decode dlopen()'s this shared object | 1331 // Accelerated video decode dlopen()'s this shared object |
1367 // inside the sandbox, so preload it now. | 1332 // inside the sandbox, so preload it now. |
1368 // TODO(jorgelo): generalize this to other platforms. | 1333 // TODO(jorgelo): generalize this to other platforms. |
1369 if (IsAcceleratedVideoDecodeEnabled()) { | 1334 if (IsAcceleratedVideoDecodeEnabled()) { |
1370 const char kI965DrvVideoPath_64[] = | 1335 const char kI965DrvVideoPath_64[] = |
1371 "/usr/lib64/va/drivers/i965_drv_video.so"; | 1336 "/usr/lib64/va/drivers/i965_drv_video.so"; |
1372 dlopen(kI965DrvVideoPath_64, RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE); | 1337 dlopen(kI965DrvVideoPath_64, RTLD_NOW|RTLD_GLOBAL|RTLD_NODELETE); |
1373 } | 1338 } |
1339 InitGpu64BrokerProcess(broker_process); | |
1374 } | 1340 } |
1375 #endif | 1341 #endif |
1376 } | 1342 } |
1377 | 1343 |
1378 Sandbox::EvaluateSyscall GetProcessSyscallPolicy( | 1344 Sandbox::EvaluateSyscall GetProcessSyscallPolicy( |
1379 const CommandLine& command_line, | 1345 const CommandLine& command_line, |
1380 const std::string& process_type) { | 1346 const std::string& process_type) { |
1381 if (process_type == switches::kGpuProcess) { | 1347 if (process_type == switches::kGpuProcess) { |
1382 // On Chrome OS, --enable-gpu-sandbox enables the more restrictive policy. | 1348 // On Chrome OS, --enable-gpu-sandbox enables the more restrictive policy. |
1383 // However, we don't yet enable the more restrictive GPU process policy | 1349 // However, we don't yet enable the more restrictive GPU process policy |
(...skipping 19 matching lines...) Expand all Loading... | |
1403 if (process_type == switches::kUtilityProcess) { | 1369 if (process_type == switches::kUtilityProcess) { |
1404 return BlacklistDebugAndNumaPolicy; | 1370 return BlacklistDebugAndNumaPolicy; |
1405 } | 1371 } |
1406 | 1372 |
1407 NOTREACHED(); | 1373 NOTREACHED(); |
1408 // This will be our default if we need one. | 1374 // This will be our default if we need one. |
1409 return AllowAllPolicy; | 1375 return AllowAllPolicy; |
1410 } | 1376 } |
1411 | 1377 |
1412 // Initialize the seccomp-bpf sandbox. | 1378 // Initialize the seccomp-bpf sandbox. |
1379 // Eventually create a BrokerProcess and return it to broker_process. | |
1413 bool StartBpfSandbox(const CommandLine& command_line, | 1380 bool StartBpfSandbox(const CommandLine& command_line, |
1414 const std::string& process_type) { | 1381 const std::string& process_type) { |
1415 Sandbox::EvaluateSyscall SyscallPolicy = | 1382 Sandbox::EvaluateSyscall SyscallPolicy = |
1416 GetProcessSyscallPolicy(command_line, process_type); | 1383 GetProcessSyscallPolicy(command_line, process_type); |
1417 | 1384 |
1418 // Warms up resources needed by the policy we're about to enable. | 1385 BrokerProcess* broker_process = NULL; |
1419 WarmupPolicy(SyscallPolicy); | 1386 // Warms up resources needed by the policy we're about to enable and |
1387 // eventually start a broker process. | |
Jorge Lucangeli Obes
2012/12/14 19:13:22
'starts' to match 'Warms'.
jln (very slow on Chromium)
2012/12/14 20:30:25
Done.
| |
1388 WarmupPolicy(SyscallPolicy, &broker_process); | |
1420 | 1389 |
1421 Sandbox::setSandboxPolicy(SyscallPolicy, NULL); | 1390 Sandbox::setSandboxPolicy(SyscallPolicy, broker_process); |
1422 Sandbox::startSandbox(); | 1391 Sandbox::startSandbox(); |
1423 | 1392 |
1424 return true; | 1393 return true; |
1425 } | 1394 } |
1426 | 1395 |
1427 } // namespace | 1396 } // namespace |
1428 | 1397 |
1429 #endif // SECCOMP_BPF_SANDBOX | 1398 #endif // SECCOMP_BPF_SANDBOX |
1430 | 1399 |
1431 namespace content { | 1400 namespace content { |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1481 // should enable it, enable it or die. | 1450 // should enable it, enable it or die. |
1482 bool started_sandbox = StartBpfSandbox(command_line, process_type); | 1451 bool started_sandbox = StartBpfSandbox(command_line, process_type); |
1483 CHECK(started_sandbox); | 1452 CHECK(started_sandbox); |
1484 return true; | 1453 return true; |
1485 } | 1454 } |
1486 #endif | 1455 #endif |
1487 return false; | 1456 return false; |
1488 } | 1457 } |
1489 | 1458 |
1490 } // namespace content | 1459 } // namespace content |
OLD | NEW |