| Index: chrome/browser/zygote_main_linux.cc
|
| diff --git a/chrome/browser/zygote_main_linux.cc b/chrome/browser/zygote_main_linux.cc
|
| index 6752a068c7af28bf43bfb1cbd3a084007acf6708..2592209b4b9f9d7131e47702fb907e25a65ccebe 100644
|
| --- a/chrome/browser/zygote_main_linux.cc
|
| +++ b/chrome/browser/zygote_main_linux.cc
|
| @@ -2,6 +2,7 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| +#include <dlfcn.h>
|
| #include <unistd.h>
|
| #include <sys/epoll.h>
|
| #include <sys/types.h>
|
| @@ -205,11 +206,9 @@ class Zygote {
|
| }
|
| };
|
|
|
| -// Patched dynamic symbol wrapper functions...
|
| -namespace sandbox_wrapper {
|
| -
|
| -void do_localtime(time_t input, struct tm* output, char* timezone_out,
|
| - size_t timezone_out_len) {
|
| +static void ProxyLocaltimeCallToBrowser(time_t input, struct tm* output,
|
| + char* timezone_out,
|
| + size_t timezone_out_len) {
|
| Pickle request;
|
| request.WriteInt(LinuxSandbox::METHOD_LOCALTIME);
|
| request.WriteString(
|
| @@ -244,58 +243,75 @@ void do_localtime(time_t input, struct tm* output, char* timezone_out,
|
| }
|
| }
|
|
|
| +static bool g_am_zygote_or_renderer = false;
|
| +
|
| +// Sandbox interception of libc calls.
|
| +//
|
| +// Because we are running in a sandbox certain libc calls will fail (localtime
|
| +// being the motivating example - it needs to read /etc/localtime). We need to
|
| +// intercept these calls and proxy them to the browser. However, these calls
|
| +// may come from us or from our libraries. In some cases we can't just change
|
| +// our code.
|
| +//
|
| +// It's for these cases that we have the following setup:
|
| +//
|
| +// We define global functions for those functions which we wish to override.
|
| +// Since we will be first in the dynamic resolution order, the dynamic linker
|
| +// will point callers to our versions of these functions. However, we have the
|
| +// same binary for both the browser and the renderers, which means that our
|
| +// overrides will apply in the browser too.
|
| +//
|
| +// The global |g_am_zygote_or_renderer| is true iff we are in a zygote or
|
| +// renderer process. It's set in ZygoteMain and inherited by the renderers when
|
| +// they fork. (This means that it'll be incorrect for global constructor
|
| +// functions and before ZygoteMain is called - beware).
|
| +//
|
| +// Our replacement functions can check this global and either proxy
|
| +// the call to the browser over the sandbox IPC
|
| +// (http://code.google.com/p/chromium/wiki/LinuxSandboxIPC) or they can use
|
| +// dlsym with RTLD_NEXT to resolve the symbol, ignoring any symbols in the
|
| +// current module.
|
| +//
|
| +// Other avenues:
|
| +//
|
| +// Our first attempt involved some assembly to patch the GOT of the current
|
| +// module. This worked, but was platform specific and doesn't catch the case
|
| +// where a library makes a call rather than current module.
|
| +//
|
| +// We also considered patching the function in place, but this would again by
|
| +// platform specific and the above technique seems to work well enough.
|
| +
|
| struct tm* localtime(const time_t* timep) {
|
| - static struct tm time_struct;
|
| - static char timezone_string[64];
|
| - do_localtime(*timep, &time_struct, timezone_string, sizeof(timezone_string));
|
| - return &time_struct;
|
| + if (g_am_zygote_or_renderer) {
|
| + static struct tm time_struct;
|
| + static char timezone_string[64];
|
| + ProxyLocaltimeCallToBrowser(*timep, &time_struct, timezone_string,
|
| + sizeof(timezone_string));
|
| + return &time_struct;
|
| + } else {
|
| + typedef struct tm* (*LocaltimeFunction)(const time_t* timep);
|
| + static LocaltimeFunction libc_localtime;
|
| + if (!libc_localtime)
|
| + libc_localtime = (LocaltimeFunction) dlsym(RTLD_NEXT, "localtime");
|
| +
|
| + return libc_localtime(timep);
|
| + }
|
| }
|
|
|
| struct tm* localtime_r(const time_t* timep, struct tm* result) {
|
| - do_localtime(*timep, result, NULL, 0);
|
| - return result;
|
| -}
|
| + if (g_am_zygote_or_renderer) {
|
| + ProxyLocaltimeCallToBrowser(*timep, result, NULL, 0);
|
| + return result;
|
| + } else {
|
| + typedef struct tm* (*LocaltimeRFunction)(const time_t* timep,
|
| + struct tm* result);
|
| + static LocaltimeRFunction libc_localtime_r;
|
| + if (!libc_localtime_r)
|
| + libc_localtime_r = (LocaltimeRFunction) dlsym(RTLD_NEXT, "localtime_r");
|
|
|
| -} // namespace sandbox_wrapper
|
| -
|
| -/* On IA-32, function calls which need to be resolved by the dynamic linker are
|
| - * directed to the producure linking table (PLT). Each PLT entry contains code
|
| - * which jumps (indirectly) via the global offset table (GOT):
|
| - * Dump of assembler code for function f@plt:
|
| - * 0x0804830c <f@plt+0>: jmp *0x804a004 # GOT indirect jump
|
| - * 0x08048312 <f@plt+6>: push $0x8
|
| - * 0x08048317 <f@plt+11>: jmp 0x80482ec <_init+48>
|
| - *
|
| - * At the beginning of a process's lifetime, the GOT entry jumps back to
|
| - * <f@plt+6> end then enters the dynamic linker. Once the symbol has been
|
| - * resolved, the GOT entry is patched so that future calls go directly to the
|
| - * resolved function.
|
| - *
|
| - * This macro finds the PLT entry for a given symbol, |symbol|, and reads the
|
| - * GOT entry address from the first instruction. It then patches that address
|
| - * with the address of a replacement function, |replacement|.
|
| - */
|
| -#define PATCH_GLOBAL_OFFSET_TABLE(symbol, replacement) \
|
| - /* First, get the current instruction pointer since the PLT address */ \
|
| - /* is IP relative */ \
|
| - asm ("call 0f\n" \
|
| - "0: pop %%ecx\n" \
|
| - /* Move the IP relative address of the PLT entry into EAX */ \
|
| - "mov $" #symbol "@plt,%%eax\n" \
|
| - /* Add EAX to ECX to get an absolute entry */ \
|
| - "add %%eax,%%ecx\n" \
|
| - /* The value in ECX was relative to the add instruction, however, */ \
|
| - /* the IP value was that of the pop. The pop and mov take 6 */ \
|
| - /* bytes, so adding 6 gets us the correct address for the PLT. The */ \
|
| - /* first instruction at the PLT is FF 25 <abs address>, so we skip 2 */ \
|
| - /* bytes to get to the address. 6 + 2 = 8: */ \
|
| - "movl 8(%%ecx),%%ecx\n" \
|
| - /* Now ECX contains the address of the GOT entry, we poke our */ \
|
| - /* replacement function in there: */ \
|
| - "movl %0,(%%ecx)\n" \
|
| - : /* no output */ \
|
| - : "r" (replacement) \
|
| - : "memory", "%eax", "%ecx");
|
| + return libc_localtime_r(timep, result);
|
| + }
|
| +}
|
|
|
| static bool MaybeEnterChroot() {
|
| const char* const sandbox_fd_string = getenv("SBX_D");
|
| @@ -324,11 +340,6 @@ static bool MaybeEnterChroot() {
|
| const char* locale = setlocale(LC_ALL, "");
|
| LOG_IF(WARNING, locale == NULL) << "setlocale failed.";
|
|
|
| -#if defined(ARCH_CPU_X86)
|
| - PATCH_GLOBAL_OFFSET_TABLE(localtime, sandbox_wrapper::localtime);
|
| - PATCH_GLOBAL_OFFSET_TABLE(localtime_r, sandbox_wrapper::localtime_r);
|
| -#endif
|
| -
|
| FilePath module_path;
|
| if (PathService::Get(base::DIR_MODULE, &module_path))
|
| media::InitializeMediaLibrary(module_path);
|
| @@ -390,6 +401,8 @@ static bool MaybeEnterChroot() {
|
| }
|
|
|
| bool ZygoteMain(const MainFunctionParams& params) {
|
| + g_am_zygote_or_renderer = true;
|
| +
|
| if (!MaybeEnterChroot()) {
|
| LOG(FATAL) << "Failed to enter sandbox. Fail safe abort. (errno: "
|
| << errno << ")";
|
|
|