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

Side by Side Diff: content/zygote/zygote_libc_override_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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include <dlfcn.h>
6 #include <pthread.h>
7 #include <stdio.h>
8 #include <sys/stat.h>
9
10 #include "base/eintr_wrapper.h"
11 #include "base/logging.h"
12 #include "base/rand_util.h"
13
14 // Note: this file is used by the zygote and nacl_helper.
15
16 namespace content {
17
18 // With SELinux we can carve out a precise sandbox, so we don't have to play
19 // with intercepting libc calls.
20 #if !defined(CHROMIUM_SELINUX)
21
22 bool g_am_zygote_or_renderer = false;
23
24 // TODO(sergeyu): Currently this code doesn't work properly under ASAN
25 // - it crashes content_unittests. Make sure it works properly and
26 // enable it here. http://crbug.com/123263
27 #if !defined(ADDRESS_SANITIZER)
28
29 static const char kUrandomDevPath[] = "/dev/urandom";
30
31 // Sandbox interception of libc calls.
32 //
33 // Because we are running in a sandbox certain libc calls will fail (localtime
34 // being the motivating example - it needs to read /etc/localtime). We need to
Sergey Ulanov 2012/07/10 22:42:04 this comment is about localtime(), so it should be
Nick Bray (chromium) 2012/07/11 00:06:11 Done.
35 // intercept these calls and proxy them to the browser. However, these calls
36 // may come from us or from our libraries. In some cases we can't just change
37 // our code.
38 //
39 // It's for these cases that we have the following setup:
40 //
41 // We define global functions for those functions which we wish to override.
42 // Since we will be first in the dynamic resolution order, the dynamic linker
43 // will point callers to our versions of these functions. However, we have the
44 // same binary for both the browser and the renderers, which means that our
45 // overrides will apply in the browser too.
46 //
47 // The global |g_am_zygote_or_renderer| is true iff we are in a zygote or
48 // renderer process. It's set in ZygoteMain and inherited by the renderers when
49 // they fork. (This means that it'll be incorrect for global constructor
50 // functions and before ZygoteMain is called - beware).
51 //
52 // Our replacement functions can check this global and either proxy
53 // the call to the browser over the sandbox IPC
54 // (http://code.google.com/p/chromium/wiki/LinuxSandboxIPC) or they can use
55 // dlsym with RTLD_NEXT to resolve the symbol, ignoring any symbols in the
56 // current module.
57 //
58 // Other avenues:
59 //
60 // Our first attempt involved some assembly to patch the GOT of the current
61 // module. This worked, but was platform specific and doesn't catch the case
62 // where a library makes a call rather than current module.
63 //
64 // We also considered patching the function in place, but this would again by
65 // platform specific and the above technique seems to work well enough.
66
67 typedef FILE* (*FopenFunction)(const char* path, const char* mode);
68 typedef int (*XstatFunction)(int version, const char *path, struct stat *buf);
69 typedef int (*Xstat64Function)(int version, const char *path,
70 struct stat64 *buf);
71
72 static pthread_once_t g_libc_file_io_funcs_guard = PTHREAD_ONCE_INIT;
73 static FopenFunction g_libc_fopen;
74 static FopenFunction g_libc_fopen64;
75 static XstatFunction g_libc_xstat;
76 static Xstat64Function g_libc_xstat64;
77
78 static void InitLibcFileIOFunctions() {
79 g_libc_fopen = reinterpret_cast<FopenFunction>(
80 dlsym(RTLD_NEXT, "fopen"));
81 g_libc_fopen64 = reinterpret_cast<FopenFunction>(
82 dlsym(RTLD_NEXT, "fopen64"));
83
84 if (!g_libc_fopen) {
85 LOG(FATAL) << "Failed to get fopen() from libc.";
86 } else if (!g_libc_fopen64) {
87 #if !defined(OS_OPENBSD) && !defined(OS_FREEBSD)
88 LOG(WARNING) << "Failed to get fopen64() from libc. Using fopen() instead.";
89 #endif // !defined(OS_OPENBSD) && !defined(OS_FREEBSD)
90 g_libc_fopen64 = g_libc_fopen;
91 }
92
93 // TODO(sergeyu): This works only on systems with glibc. Fix it to
94 // work properly on other systems if necessary.
95 g_libc_xstat = reinterpret_cast<XstatFunction>(
96 dlsym(RTLD_NEXT, "__xstat"));
97 g_libc_xstat64 = reinterpret_cast<Xstat64Function>(
98 dlsym(RTLD_NEXT, "__xstat64"));
99
100 if (!g_libc_xstat) {
101 LOG(FATAL) << "Failed to get __xstat() from libc.";
102 }
103 if (!g_libc_xstat64) {
104 LOG(WARNING) << "Failed to get __xstat64() from libc.";
105 }
106 }
107
108 // fopen() and fopen64() are intercepted here so that NSS can open
109 // /dev/urandom to seed its random number generator. NSS is used by
110 // remoting in the sendbox.
111
112 // fopen() call may be redirected to fopen64() in stdio.h using
113 // __REDIRECT(), which sets asm name for fopen() to "fopen64". This
114 // means that we cannot override fopen() directly here. Instead the
115 // the code below defines fopen_override() function with asm name
116 // "fopen", so that all references to fopen() will resolve to this
117 // function.
118 __attribute__ ((__visibility__("default")))
119 FILE* fopen_override(const char* path, const char* mode) __asm__ ("fopen");
120
121 __attribute__ ((__visibility__("default")))
122 FILE* fopen_override(const char* path, const char* mode) {
123 if (g_am_zygote_or_renderer && strcmp(path, kUrandomDevPath) == 0) {
124 int fd = HANDLE_EINTR(dup(base::GetUrandomFD()));
125 if (fd < 0) {
126 PLOG(ERROR) << "dup() failed.";
127 return NULL;
128 }
129 return fdopen(fd, mode);
130 } else {
131 CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
132 InitLibcFileIOFunctions));
133 return g_libc_fopen(path, mode);
134 }
135 }
136
137 __attribute__ ((__visibility__("default")))
138 FILE* fopen64(const char* path, const char* mode) {
139 if (g_am_zygote_or_renderer && strcmp(path, kUrandomDevPath) == 0) {
140 int fd = HANDLE_EINTR(dup(base::GetUrandomFD()));
141 if (fd < 0) {
142 PLOG(ERROR) << "dup() failed.";
143 return NULL;
144 }
145 return fdopen(fd, mode);
146 } else {
147 CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
148 InitLibcFileIOFunctions));
149 return g_libc_fopen64(path, mode);
150 }
151 }
152
153 // stat() is subject to the same problem as fopen(), so we have to use
154 // the same trick to override it.
155 __attribute__ ((__visibility__("default")))
156 int xstat_override(int version,
157 const char *path,
158 struct stat *buf) __asm__ ("__xstat");
159
160 __attribute__ ((__visibility__("default")))
161 int xstat_override(int version, const char *path, struct stat *buf) {
162 if (g_am_zygote_or_renderer && strcmp(path, kUrandomDevPath) == 0) {
163 int result = __fxstat(version, base::GetUrandomFD(), buf);
164 return result;
165 } else {
166 CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
167 InitLibcFileIOFunctions));
168 return g_libc_xstat(version, path, buf);
169 }
170 }
171
172 __attribute__ ((__visibility__("default")))
173 int xstat64_override(int version,
174 const char *path,
175 struct stat64 *buf) __asm__ ("__xstat64");
176
177 __attribute__ ((__visibility__("default")))
178 int xstat64_override(int version, const char *path, struct stat64 *buf) {
179 if (g_am_zygote_or_renderer && strcmp(path, kUrandomDevPath) == 0) {
180 int result = __fxstat64(version, base::GetUrandomFD(), buf);
181 return result;
182 } else {
183 CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
184 InitLibcFileIOFunctions));
185 CHECK(g_libc_xstat64);
186 return g_libc_xstat64(version, path, buf);
187 }
188 }
189
190 #endif // !ADDRESS_SANITIZER
191
192 #endif // !CHROMIUM_SELINUX
193
194 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698