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