OLD | NEW |
---|---|
(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 | |
OLD | NEW |