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 <dlfcn.h> | 5 #include <dlfcn.h> |
6 #include <fcntl.h> | 6 #include <fcntl.h> |
7 #include <pthread.h> | 7 #include <pthread.h> |
8 #include <stdio.h> | 8 #include <stdio.h> |
9 #include <sys/socket.h> | 9 #include <sys/socket.h> |
10 #include <sys/stat.h> | 10 #include <sys/stat.h> |
(...skipping 18 matching lines...) Expand all Loading... |
29 #include "content/common/font_config_ipc_linux.h" | 29 #include "content/common/font_config_ipc_linux.h" |
30 #include "content/common/pepper_plugin_registry.h" | 30 #include "content/common/pepper_plugin_registry.h" |
31 #include "content/common/sandbox_methods_linux.h" | 31 #include "content/common/sandbox_methods_linux.h" |
32 #include "content/common/seccomp_sandbox.h" | 32 #include "content/common/seccomp_sandbox.h" |
33 #include "content/common/zygote_commands_linux.h" | 33 #include "content/common/zygote_commands_linux.h" |
34 #include "content/public/common/content_switches.h" | 34 #include "content/public/common/content_switches.h" |
35 #include "content/public/common/main_function_params.h" | 35 #include "content/public/common/main_function_params.h" |
36 #include "content/public/common/sandbox_linux.h" | 36 #include "content/public/common/sandbox_linux.h" |
37 #include "content/public/common/zygote_fork_delegate_linux.h" | 37 #include "content/public/common/zygote_fork_delegate_linux.h" |
38 #include "content/zygote/zygote_linux.h" | 38 #include "content/zygote/zygote_linux.h" |
| 39 #include "sandbox/linux/services/libc_urandom_override.h" |
39 #include "skia/ext/SkFontHost_fontconfig_control.h" | 40 #include "skia/ext/SkFontHost_fontconfig_control.h" |
40 #include "unicode/timezone.h" | 41 #include "unicode/timezone.h" |
41 | 42 |
42 #if defined(OS_LINUX) | 43 #if defined(OS_LINUX) |
43 #include <sys/epoll.h> | 44 #include <sys/epoll.h> |
44 #include <sys/prctl.h> | 45 #include <sys/prctl.h> |
45 #include <sys/signal.h> | 46 #include <sys/signal.h> |
46 #else | 47 #else |
47 #include <signal.h> | 48 #include <signal.h> |
48 #endif | 49 #endif |
49 | 50 |
50 namespace content { | 51 namespace content { |
51 | 52 |
52 // See http://code.google.com/p/chromium/wiki/LinuxZygote | 53 // See http://code.google.com/p/chromium/wiki/LinuxZygote |
53 | 54 |
54 static const char kUrandomDevPath[] = "/dev/urandom"; | |
55 | |
56 // The SUID sandbox sets this environment variable to a file descriptor | 55 // The SUID sandbox sets this environment variable to a file descriptor |
57 // over which we can signal that we have completed our startup and can be | 56 // over which we can signal that we have completed our startup and can be |
58 // chrooted. | 57 // chrooted. |
59 static const char kSUIDSandboxVar[] = "SBX_D"; | 58 static const char kSUIDSandboxVar[] = "SBX_D"; |
60 | 59 |
61 // With SELinux we can carve out a precise sandbox, so we don't have to play | 60 // With SELinux we can carve out a precise sandbox, so we don't have to play |
62 // with intercepting libc calls. | 61 // with intercepting libc calls. |
63 #if !defined(CHROMIUM_SELINUX) | 62 #if !defined(CHROMIUM_SELINUX) |
64 | 63 |
65 static void ProxyLocaltimeCallToBrowser(time_t input, struct tm* output, | 64 static void ProxyLocaltimeCallToBrowser(time_t input, struct tm* output, |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
134 // Our first attempt involved some assembly to patch the GOT of the current | 133 // Our first attempt involved some assembly to patch the GOT of the current |
135 // module. This worked, but was platform specific and doesn't catch the case | 134 // module. This worked, but was platform specific and doesn't catch the case |
136 // where a library makes a call rather than current module. | 135 // where a library makes a call rather than current module. |
137 // | 136 // |
138 // We also considered patching the function in place, but this would again by | 137 // We also considered patching the function in place, but this would again by |
139 // platform specific and the above technique seems to work well enough. | 138 // platform specific and the above technique seems to work well enough. |
140 | 139 |
141 typedef struct tm* (*LocaltimeFunction)(const time_t* timep); | 140 typedef struct tm* (*LocaltimeFunction)(const time_t* timep); |
142 typedef struct tm* (*LocaltimeRFunction)(const time_t* timep, | 141 typedef struct tm* (*LocaltimeRFunction)(const time_t* timep, |
143 struct tm* result); | 142 struct tm* result); |
144 typedef FILE* (*FopenFunction)(const char* path, const char* mode); | |
145 typedef int (*XstatFunction)(int version, const char *path, struct stat *buf); | |
146 typedef int (*Xstat64Function)(int version, const char *path, | |
147 struct stat64 *buf); | |
148 | 143 |
149 static pthread_once_t g_libc_localtime_funcs_guard = PTHREAD_ONCE_INIT; | 144 static pthread_once_t g_libc_localtime_funcs_guard = PTHREAD_ONCE_INIT; |
150 static LocaltimeFunction g_libc_localtime; | 145 static LocaltimeFunction g_libc_localtime; |
151 static LocaltimeFunction g_libc_localtime64; | 146 static LocaltimeFunction g_libc_localtime64; |
152 static LocaltimeRFunction g_libc_localtime_r; | 147 static LocaltimeRFunction g_libc_localtime_r; |
153 static LocaltimeRFunction g_libc_localtime64_r; | 148 static LocaltimeRFunction g_libc_localtime64_r; |
154 | 149 |
155 // http://crbug.com/123263, see below. | |
156 #if !defined(ADDRESS_SANITIZER) | |
157 static pthread_once_t g_libc_file_io_funcs_guard = PTHREAD_ONCE_INIT; | |
158 static FopenFunction g_libc_fopen; | |
159 static FopenFunction g_libc_fopen64; | |
160 static XstatFunction g_libc_xstat; | |
161 static Xstat64Function g_libc_xstat64; | |
162 #endif | |
163 | |
164 static void InitLibcLocaltimeFunctions() { | 150 static void InitLibcLocaltimeFunctions() { |
165 g_libc_localtime = reinterpret_cast<LocaltimeFunction>( | 151 g_libc_localtime = reinterpret_cast<LocaltimeFunction>( |
166 dlsym(RTLD_NEXT, "localtime")); | 152 dlsym(RTLD_NEXT, "localtime")); |
167 g_libc_localtime64 = reinterpret_cast<LocaltimeFunction>( | 153 g_libc_localtime64 = reinterpret_cast<LocaltimeFunction>( |
168 dlsym(RTLD_NEXT, "localtime64")); | 154 dlsym(RTLD_NEXT, "localtime64")); |
169 g_libc_localtime_r = reinterpret_cast<LocaltimeRFunction>( | 155 g_libc_localtime_r = reinterpret_cast<LocaltimeRFunction>( |
170 dlsym(RTLD_NEXT, "localtime_r")); | 156 dlsym(RTLD_NEXT, "localtime_r")); |
171 g_libc_localtime64_r = reinterpret_cast<LocaltimeRFunction>( | 157 g_libc_localtime64_r = reinterpret_cast<LocaltimeRFunction>( |
172 dlsym(RTLD_NEXT, "localtime64_r")); | 158 dlsym(RTLD_NEXT, "localtime64_r")); |
173 | 159 |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
259 if (g_am_zygote_or_renderer) { | 245 if (g_am_zygote_or_renderer) { |
260 ProxyLocaltimeCallToBrowser(*timep, result, NULL, 0); | 246 ProxyLocaltimeCallToBrowser(*timep, result, NULL, 0); |
261 return result; | 247 return result; |
262 } else { | 248 } else { |
263 CHECK_EQ(0, pthread_once(&g_libc_localtime_funcs_guard, | 249 CHECK_EQ(0, pthread_once(&g_libc_localtime_funcs_guard, |
264 InitLibcLocaltimeFunctions)); | 250 InitLibcLocaltimeFunctions)); |
265 return g_libc_localtime64_r(timep, result); | 251 return g_libc_localtime64_r(timep, result); |
266 } | 252 } |
267 } | 253 } |
268 | 254 |
269 // TODO(sergeyu): Currently this code doesn't work properly under ASAN | |
270 // - it crashes content_unittests. Make sure it works properly and | |
271 // enable it here. http://crbug.com/123263 | |
272 #if !defined(ADDRESS_SANITIZER) | |
273 | |
274 static void InitLibcFileIOFunctions() { | |
275 g_libc_fopen = reinterpret_cast<FopenFunction>( | |
276 dlsym(RTLD_NEXT, "fopen")); | |
277 g_libc_fopen64 = reinterpret_cast<FopenFunction>( | |
278 dlsym(RTLD_NEXT, "fopen64")); | |
279 | |
280 if (!g_libc_fopen) { | |
281 LOG(FATAL) << "Failed to get fopen() from libc."; | |
282 } else if (!g_libc_fopen64) { | |
283 #if !defined(OS_OPENBSD) && !defined(OS_FREEBSD) | |
284 LOG(WARNING) << "Failed to get fopen64() from libc. Using fopen() instead."; | |
285 #endif // !defined(OS_OPENBSD) && !defined(OS_FREEBSD) | |
286 g_libc_fopen64 = g_libc_fopen; | |
287 } | |
288 | |
289 // TODO(sergeyu): This works only on systems with glibc. Fix it to | |
290 // work properly on other systems if necessary. | |
291 g_libc_xstat = reinterpret_cast<XstatFunction>( | |
292 dlsym(RTLD_NEXT, "__xstat")); | |
293 g_libc_xstat64 = reinterpret_cast<Xstat64Function>( | |
294 dlsym(RTLD_NEXT, "__xstat64")); | |
295 | |
296 if (!g_libc_xstat) { | |
297 LOG(FATAL) << "Failed to get __xstat() from libc."; | |
298 } | |
299 if (!g_libc_xstat64) { | |
300 LOG(WARNING) << "Failed to get __xstat64() from libc."; | |
301 } | |
302 } | |
303 | |
304 // fopen() and fopen64() are intercepted here so that NSS can open | |
305 // /dev/urandom to seed its random number generator. NSS is used by | |
306 // remoting in the sendbox. | |
307 | |
308 // fopen() call may be redirected to fopen64() in stdio.h using | |
309 // __REDIRECT(), which sets asm name for fopen() to "fopen64". This | |
310 // means that we cannot override fopen() directly here. Instead the | |
311 // the code below defines fopen_override() function with asm name | |
312 // "fopen", so that all references to fopen() will resolve to this | |
313 // function. | |
314 __attribute__ ((__visibility__("default"))) | |
315 FILE* fopen_override(const char* path, const char* mode) __asm__ ("fopen"); | |
316 | |
317 __attribute__ ((__visibility__("default"))) | |
318 FILE* fopen_override(const char* path, const char* mode) { | |
319 if (g_am_zygote_or_renderer && strcmp(path, kUrandomDevPath) == 0) { | |
320 int fd = HANDLE_EINTR(dup(base::GetUrandomFD())); | |
321 if (fd < 0) { | |
322 PLOG(ERROR) << "dup() failed."; | |
323 return NULL; | |
324 } | |
325 return fdopen(fd, mode); | |
326 } else { | |
327 CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard, | |
328 InitLibcFileIOFunctions)); | |
329 return g_libc_fopen(path, mode); | |
330 } | |
331 } | |
332 | |
333 __attribute__ ((__visibility__("default"))) | |
334 FILE* fopen64(const char* path, const char* mode) { | |
335 if (g_am_zygote_or_renderer && strcmp(path, kUrandomDevPath) == 0) { | |
336 int fd = HANDLE_EINTR(dup(base::GetUrandomFD())); | |
337 if (fd < 0) { | |
338 PLOG(ERROR) << "dup() failed."; | |
339 return NULL; | |
340 } | |
341 return fdopen(fd, mode); | |
342 } else { | |
343 CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard, | |
344 InitLibcFileIOFunctions)); | |
345 return g_libc_fopen64(path, mode); | |
346 } | |
347 } | |
348 | |
349 // stat() is subject to the same problem as fopen(), so we have to use | |
350 // the same trick to override it. | |
351 __attribute__ ((__visibility__("default"))) | |
352 int xstat_override(int version, | |
353 const char *path, | |
354 struct stat *buf) __asm__ ("__xstat"); | |
355 | |
356 __attribute__ ((__visibility__("default"))) | |
357 int xstat_override(int version, const char *path, struct stat *buf) { | |
358 if (g_am_zygote_or_renderer && strcmp(path, kUrandomDevPath) == 0) { | |
359 int result = __fxstat(version, base::GetUrandomFD(), buf); | |
360 return result; | |
361 } else { | |
362 CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard, | |
363 InitLibcFileIOFunctions)); | |
364 return g_libc_xstat(version, path, buf); | |
365 } | |
366 } | |
367 | |
368 __attribute__ ((__visibility__("default"))) | |
369 int xstat64_override(int version, | |
370 const char *path, | |
371 struct stat64 *buf) __asm__ ("__xstat64"); | |
372 | |
373 __attribute__ ((__visibility__("default"))) | |
374 int xstat64_override(int version, const char *path, struct stat64 *buf) { | |
375 if (g_am_zygote_or_renderer && strcmp(path, kUrandomDevPath) == 0) { | |
376 int result = __fxstat64(version, base::GetUrandomFD(), buf); | |
377 return result; | |
378 } else { | |
379 CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard, | |
380 InitLibcFileIOFunctions)); | |
381 CHECK(g_libc_xstat64); | |
382 return g_libc_xstat64(version, path, buf); | |
383 } | |
384 } | |
385 | |
386 #endif // !ADDRESS_SANITIZER | |
387 | |
388 #endif // !CHROMIUM_SELINUX | 255 #endif // !CHROMIUM_SELINUX |
389 | 256 |
390 // This function triggers the static and lazy construction of objects that need | 257 // This function triggers the static and lazy construction of objects that need |
391 // to be created before imposing the sandbox. | 258 // to be created before imposing the sandbox. |
392 static void PreSandboxInit() { | 259 static void PreSandboxInit() { |
393 base::RandUint64(); | 260 base::RandUint64(); |
394 | 261 |
395 base::SysInfo::MaxSharedMemorySize(); | 262 base::SysInfo::MaxSharedMemorySize(); |
396 | 263 |
397 // ICU DateFormat class (used in base/time_format.cc) needs to get the | 264 // ICU DateFormat class (used in base/time_format.cc) needs to get the |
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
615 new FontConfigIPC(Zygote::kMagicSandboxIPCDescriptor)); | 482 new FontConfigIPC(Zygote::kMagicSandboxIPCDescriptor)); |
616 return true; | 483 return true; |
617 } | 484 } |
618 | 485 |
619 #endif // CHROMIUM_SELINUX | 486 #endif // CHROMIUM_SELINUX |
620 | 487 |
621 bool ZygoteMain(const MainFunctionParams& params, | 488 bool ZygoteMain(const MainFunctionParams& params, |
622 ZygoteForkDelegate* forkdelegate) { | 489 ZygoteForkDelegate* forkdelegate) { |
623 #if !defined(CHROMIUM_SELINUX) | 490 #if !defined(CHROMIUM_SELINUX) |
624 g_am_zygote_or_renderer = true; | 491 g_am_zygote_or_renderer = true; |
| 492 sandbox::InitLibcUrandomOverrides(); |
625 #endif | 493 #endif |
626 | 494 |
627 int proc_fd_for_seccomp = -1; | 495 int proc_fd_for_seccomp = -1; |
628 #if defined(SECCOMP_SANDBOX) | 496 #if defined(SECCOMP_SANDBOX) |
629 if (SeccompSandboxEnabled()) { | 497 if (SeccompSandboxEnabled()) { |
630 // The seccomp sandbox needs access to files in /proc, which might be denied | 498 // The seccomp sandbox needs access to files in /proc, which might be denied |
631 // after one of the other sandboxes have been started. So, obtain a suitable | 499 // after one of the other sandboxes have been started. So, obtain a suitable |
632 // file handle in advance. | 500 // file handle in advance. |
633 proc_fd_for_seccomp = open("/proc", O_DIRECTORY | O_RDONLY); | 501 proc_fd_for_seccomp = open("/proc", O_DIRECTORY | O_RDONLY); |
634 if (proc_fd_for_seccomp < 0) { | 502 if (proc_fd_for_seccomp < 0) { |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
692 } | 560 } |
693 } | 561 } |
694 #endif // SECCOMP_SANDBOX | 562 #endif // SECCOMP_SANDBOX |
695 | 563 |
696 Zygote zygote(sandbox_flags, forkdelegate, proc_fd_for_seccomp); | 564 Zygote zygote(sandbox_flags, forkdelegate, proc_fd_for_seccomp); |
697 // This function call can return multiple times, once per fork(). | 565 // This function call can return multiple times, once per fork(). |
698 return zygote.ProcessRequests(); | 566 return zygote.ProcessRequests(); |
699 } | 567 } |
700 | 568 |
701 } // namespace content | 569 } // namespace content |
OLD | NEW |