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 17 matching lines...) Expand all Loading... |
28 #include "crypto/nss_util.h" | 28 #include "crypto/nss_util.h" |
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_libc_override_linux.h" |
38 #include "content/zygote/zygote_linux.h" | 39 #include "content/zygote/zygote_linux.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 27 matching lines...) Expand all Loading... |
93 if (timezone_out_len) { | 92 if (timezone_out_len) { |
94 const size_t copy_len = std::min(timezone_out_len - 1, timezone.size()); | 93 const size_t copy_len = std::min(timezone_out_len - 1, timezone.size()); |
95 memcpy(timezone_out, timezone.data(), copy_len); | 94 memcpy(timezone_out, timezone.data(), copy_len); |
96 timezone_out[copy_len] = 0; | 95 timezone_out[copy_len] = 0; |
97 output->tm_zone = timezone_out; | 96 output->tm_zone = timezone_out; |
98 } else { | 97 } else { |
99 output->tm_zone = NULL; | 98 output->tm_zone = NULL; |
100 } | 99 } |
101 } | 100 } |
102 | 101 |
103 static bool g_am_zygote_or_renderer = false; | |
104 | |
105 // Sandbox interception of libc calls. | 102 // Sandbox interception of libc calls. |
106 // | 103 // |
107 // Because we are running in a sandbox certain libc calls will fail (localtime | 104 // See zygote_libc_override_linux.cc for more details. Interception of |
108 // being the motivating example - it needs to read /etc/localtime). We need to | 105 // localtime is implemented here because it is not shared with nacl_helper. |
109 // intercept these calls and proxy them to the browser. However, these calls | |
110 // may come from us or from our libraries. In some cases we can't just change | |
111 // our code. | |
112 // | |
113 // It's for these cases that we have the following setup: | |
114 // | |
115 // We define global functions for those functions which we wish to override. | |
116 // Since we will be first in the dynamic resolution order, the dynamic linker | |
117 // will point callers to our versions of these functions. However, we have the | |
118 // same binary for both the browser and the renderers, which means that our | |
119 // overrides will apply in the browser too. | |
120 // | |
121 // The global |g_am_zygote_or_renderer| is true iff we are in a zygote or | |
122 // renderer process. It's set in ZygoteMain and inherited by the renderers when | |
123 // they fork. (This means that it'll be incorrect for global constructor | |
124 // functions and before ZygoteMain is called - beware). | |
125 // | |
126 // Our replacement functions can check this global and either proxy | |
127 // the call to the browser over the sandbox IPC | |
128 // (http://code.google.com/p/chromium/wiki/LinuxSandboxIPC) or they can use | |
129 // dlsym with RTLD_NEXT to resolve the symbol, ignoring any symbols in the | |
130 // current module. | |
131 // | |
132 // Other avenues: | |
133 // | |
134 // 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 | |
136 // where a library makes a call rather than current module. | |
137 // | |
138 // 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. | |
140 | 106 |
141 typedef struct tm* (*LocaltimeFunction)(const time_t* timep); | 107 typedef struct tm* (*LocaltimeFunction)(const time_t* timep); |
142 typedef struct tm* (*LocaltimeRFunction)(const time_t* timep, | 108 typedef struct tm* (*LocaltimeRFunction)(const time_t* timep, |
143 struct tm* result); | 109 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 | 110 |
149 static pthread_once_t g_libc_localtime_funcs_guard = PTHREAD_ONCE_INIT; | 111 static pthread_once_t g_libc_localtime_funcs_guard = PTHREAD_ONCE_INIT; |
150 static LocaltimeFunction g_libc_localtime; | 112 static LocaltimeFunction g_libc_localtime; |
151 static LocaltimeFunction g_libc_localtime64; | 113 static LocaltimeFunction g_libc_localtime64; |
152 static LocaltimeRFunction g_libc_localtime_r; | 114 static LocaltimeRFunction g_libc_localtime_r; |
153 static LocaltimeRFunction g_libc_localtime64_r; | 115 static LocaltimeRFunction g_libc_localtime64_r; |
154 | 116 |
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() { | 117 static void InitLibcLocaltimeFunctions() { |
165 g_libc_localtime = reinterpret_cast<LocaltimeFunction>( | 118 g_libc_localtime = reinterpret_cast<LocaltimeFunction>( |
166 dlsym(RTLD_NEXT, "localtime")); | 119 dlsym(RTLD_NEXT, "localtime")); |
167 g_libc_localtime64 = reinterpret_cast<LocaltimeFunction>( | 120 g_libc_localtime64 = reinterpret_cast<LocaltimeFunction>( |
168 dlsym(RTLD_NEXT, "localtime64")); | 121 dlsym(RTLD_NEXT, "localtime64")); |
169 g_libc_localtime_r = reinterpret_cast<LocaltimeRFunction>( | 122 g_libc_localtime_r = reinterpret_cast<LocaltimeRFunction>( |
170 dlsym(RTLD_NEXT, "localtime_r")); | 123 dlsym(RTLD_NEXT, "localtime_r")); |
171 g_libc_localtime64_r = reinterpret_cast<LocaltimeRFunction>( | 124 g_libc_localtime64_r = reinterpret_cast<LocaltimeRFunction>( |
172 dlsym(RTLD_NEXT, "localtime64_r")); | 125 dlsym(RTLD_NEXT, "localtime64_r")); |
173 | 126 |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
259 if (g_am_zygote_or_renderer) { | 212 if (g_am_zygote_or_renderer) { |
260 ProxyLocaltimeCallToBrowser(*timep, result, NULL, 0); | 213 ProxyLocaltimeCallToBrowser(*timep, result, NULL, 0); |
261 return result; | 214 return result; |
262 } else { | 215 } else { |
263 CHECK_EQ(0, pthread_once(&g_libc_localtime_funcs_guard, | 216 CHECK_EQ(0, pthread_once(&g_libc_localtime_funcs_guard, |
264 InitLibcLocaltimeFunctions)); | 217 InitLibcLocaltimeFunctions)); |
265 return g_libc_localtime64_r(timep, result); | 218 return g_libc_localtime64_r(timep, result); |
266 } | 219 } |
267 } | 220 } |
268 | 221 |
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 | 222 #endif // !CHROMIUM_SELINUX |
389 | 223 |
390 // This function triggers the static and lazy construction of objects that need | 224 // This function triggers the static and lazy construction of objects that need |
391 // to be created before imposing the sandbox. | 225 // to be created before imposing the sandbox. |
392 static void PreSandboxInit() { | 226 static void PreSandboxInit() { |
393 base::RandUint64(); | 227 base::RandUint64(); |
394 | 228 |
395 base::SysInfo::MaxSharedMemorySize(); | 229 base::SysInfo::MaxSharedMemorySize(); |
396 | 230 |
397 // ICU DateFormat class (used in base/time_format.cc) needs to get the | 231 // ICU DateFormat class (used in base/time_format.cc) needs to get the |
(...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
692 } | 526 } |
693 } | 527 } |
694 #endif // SECCOMP_SANDBOX | 528 #endif // SECCOMP_SANDBOX |
695 | 529 |
696 Zygote zygote(sandbox_flags, forkdelegate, proc_fd_for_seccomp); | 530 Zygote zygote(sandbox_flags, forkdelegate, proc_fd_for_seccomp); |
697 // This function call can return multiple times, once per fork(). | 531 // This function call can return multiple times, once per fork(). |
698 return zygote.ProcessRequests(); | 532 return zygote.ProcessRequests(); |
699 } | 533 } |
700 | 534 |
701 } // namespace content | 535 } // namespace content |
OLD | NEW |