libc_urandom_override.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
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 "sandbox/linux/services/libc_urandom_override.h" 6 7#include <dlfcn.h> 8#include <pthread.h> 9#include <stdio.h> 10#include <sys/stat.h> 11#include <unistd.h> 12 13#include "base/logging.h" 14#include "base/posix/eintr_wrapper.h" 15#include "base/rand_util.h" 16 17// Note: this file is used by the zygote and nacl_helper. 18 19namespace sandbox { 20 21static bool g_override_urandom = false; 22 23void InitLibcUrandomOverrides() { 24 // Make sure /dev/urandom is open. 25 base::GetUrandomFD(); 26 g_override_urandom = true; 27} 28 29// TODO(sergeyu): Currently this code doesn't work properly under ASAN 30// - it crashes content_unittests. Make sure it works properly and 31// enable it here. http://crbug.com/123263 32#if !defined(ADDRESS_SANITIZER) 33 34static const char kUrandomDevPath[] = "/dev/urandom"; 35 36typedef FILE* (*FopenFunction)(const char* path, const char* mode); 37typedef int (*XstatFunction)(int version, const char *path, struct stat *buf); 38typedef int (*Xstat64Function)(int version, const char *path, 39 struct stat64 *buf); 40 41static pthread_once_t g_libc_file_io_funcs_guard = PTHREAD_ONCE_INIT; 42static FopenFunction g_libc_fopen; 43static FopenFunction g_libc_fopen64; 44static XstatFunction g_libc_xstat; 45static Xstat64Function g_libc_xstat64; 46 47static void InitLibcFileIOFunctions() { 48 g_libc_fopen = reinterpret_cast<FopenFunction>( 49 dlsym(RTLD_NEXT, "fopen")); 50 g_libc_fopen64 = reinterpret_cast<FopenFunction>( 51 dlsym(RTLD_NEXT, "fopen64")); 52 53 if (!g_libc_fopen) { 54 LOG(FATAL) << "Failed to get fopen() from libc."; 55 } else if (!g_libc_fopen64) { 56#if !defined(OS_OPENBSD) && !defined(OS_FREEBSD) 57 LOG(WARNING) << "Failed to get fopen64() from libc. Using fopen() instead."; 58#endif // !defined(OS_OPENBSD) && !defined(OS_FREEBSD) 59 g_libc_fopen64 = g_libc_fopen; 60 } 61 62 // TODO(sergeyu): This works only on systems with glibc. Fix it to 63 // work properly on other systems if necessary. 64 g_libc_xstat = reinterpret_cast<XstatFunction>( 65 dlsym(RTLD_NEXT, "__xstat")); 66 g_libc_xstat64 = reinterpret_cast<Xstat64Function>( 67 dlsym(RTLD_NEXT, "__xstat64")); 68 69 if (!g_libc_xstat) { 70 LOG(FATAL) << "Failed to get __xstat() from libc."; 71 } 72 if (!g_libc_xstat64) { 73 LOG(WARNING) << "Failed to get __xstat64() from libc."; 74 } 75} 76 77// fopen() and fopen64() are intercepted here so that NSS can open 78// /dev/urandom to seed its random number generator. NSS is used by 79// remoting in the sendbox. 80 81// fopen() call may be redirected to fopen64() in stdio.h using 82// __REDIRECT(), which sets asm name for fopen() to "fopen64". This 83// means that we cannot override fopen() directly here. Instead the 84// the code below defines fopen_override() function with asm name 85// "fopen", so that all references to fopen() will resolve to this 86// function. 87__attribute__ ((__visibility__("default"))) 88FILE* fopen_override(const char* path, const char* mode) __asm__ ("fopen"); 89 90__attribute__ ((__visibility__("default"))) 91FILE* fopen_override(const char* path, const char* mode) { 92 if (g_override_urandom && strcmp(path, kUrandomDevPath) == 0) { 93 int fd = HANDLE_EINTR(dup(base::GetUrandomFD())); 94 if (fd < 0) { 95 PLOG(ERROR) << "dup() failed."; 96 return NULL; 97 } 98 return fdopen(fd, mode); 99 } else { 100 CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard, 101 InitLibcFileIOFunctions)); 102 return g_libc_fopen(path, mode); 103 } 104} 105 106__attribute__ ((__visibility__("default"))) 107FILE* fopen64(const char* path, const char* mode) { 108 if (g_override_urandom && strcmp(path, kUrandomDevPath) == 0) { 109 int fd = HANDLE_EINTR(dup(base::GetUrandomFD())); 110 if (fd < 0) { 111 PLOG(ERROR) << "dup() failed."; 112 return NULL; 113 } 114 return fdopen(fd, mode); 115 } else { 116 CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard, 117 InitLibcFileIOFunctions)); 118 return g_libc_fopen64(path, mode); 119 } 120} 121 122// stat() is subject to the same problem as fopen(), so we have to use 123// the same trick to override it. 124__attribute__ ((__visibility__("default"))) 125int xstat_override(int version, 126 const char *path, 127 struct stat *buf) __asm__ ("__xstat"); 128 129__attribute__ ((__visibility__("default"))) 130int xstat_override(int version, const char *path, struct stat *buf) { 131 if (g_override_urandom && strcmp(path, kUrandomDevPath) == 0) { 132 int result = __fxstat(version, base::GetUrandomFD(), buf); 133 return result; 134 } else { 135 CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard, 136 InitLibcFileIOFunctions)); 137 return g_libc_xstat(version, path, buf); 138 } 139} 140 141__attribute__ ((__visibility__("default"))) 142int xstat64_override(int version, 143 const char *path, 144 struct stat64 *buf) __asm__ ("__xstat64"); 145 146__attribute__ ((__visibility__("default"))) 147int xstat64_override(int version, const char *path, struct stat64 *buf) { 148 if (g_override_urandom && strcmp(path, kUrandomDevPath) == 0) { 149 int result = __fxstat64(version, base::GetUrandomFD(), buf); 150 return result; 151 } else { 152 CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard, 153 InitLibcFileIOFunctions)); 154 CHECK(g_libc_xstat64); 155 return g_libc_xstat64(version, path, buf); 156 } 157} 158 159#endif // !ADDRESS_SANITIZER 160 161} // namespace content 162