Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(103)

Side by Side Diff: content/zygote/zygote_main_linux.cc

Issue 10736017: Share the zygote's fopen overrides with nacl_helper. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
OLDNEW
« content/zygote/zygote_libc_override_linux.cc ('K') | « content/zygote/zygote_libc_override_linux.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698