Home | History | Annotate | Download | only in services
      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 
     19 #if !defined(HAVE_XSTAT) && defined(LIBC_GLIBC)
     20 #define HAVE_XSTAT 1
     21 #endif
     22 
     23 namespace sandbox {
     24 
     25 static bool g_override_urandom = false;
     26 
     27 // TODO(sergeyu): Currently InitLibcUrandomOverrides() doesn't work properly
     28 // under ASan or MSan - it crashes content_unittests. Make sure it works
     29 // properly and enable it here. http://crbug.com/123263
     30 #if !(defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER))
     31 static void InitLibcFileIOFunctions();
     32 static pthread_once_t g_libc_file_io_funcs_guard = PTHREAD_ONCE_INIT;
     33 #endif
     34 
     35 void InitLibcUrandomOverrides() {
     36   // Make sure /dev/urandom is open.
     37   base::GetUrandomFD();
     38   g_override_urandom = true;
     39 
     40 #if !(defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER))
     41   CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
     42                            InitLibcFileIOFunctions));
     43 #endif
     44 }
     45 
     46 #if !(defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER))
     47 
     48 static const char kUrandomDevPath[] = "/dev/urandom";
     49 
     50 typedef FILE* (*FopenFunction)(const char* path, const char* mode);
     51 
     52 static FopenFunction g_libc_fopen = NULL;
     53 static FopenFunction g_libc_fopen64 = NULL;
     54 
     55 #if HAVE_XSTAT
     56 typedef int (*XstatFunction)(int version, const char *path, struct stat *buf);
     57 typedef int (*Xstat64Function)(int version, const char *path,
     58                                struct stat64 *buf);
     59 
     60 static XstatFunction g_libc_xstat = NULL;
     61 static Xstat64Function g_libc_xstat64 = NULL;
     62 #else
     63 typedef int (*StatFunction)(const char *path, struct stat *buf);
     64 typedef int (*Stat64Function)(const char *path, struct stat64 *buf);
     65 
     66 static StatFunction g_libc_stat = NULL;
     67 static Stat64Function g_libc_stat64 = NULL;
     68 #endif  // HAVE_XSTAT
     69 
     70 // Find the libc's real fopen* and *stat* functions. This should only be
     71 // called once, and should be guarded by g_libc_file_io_funcs_guard.
     72 static void InitLibcFileIOFunctions() {
     73   g_libc_fopen = reinterpret_cast<FopenFunction>(
     74       dlsym(RTLD_NEXT, "fopen"));
     75   g_libc_fopen64 = reinterpret_cast<FopenFunction>(
     76       dlsym(RTLD_NEXT, "fopen64"));
     77 
     78   if (!g_libc_fopen) {
     79     LOG(FATAL) << "Failed to get fopen() from libc.";
     80   } else if (!g_libc_fopen64) {
     81 #if !defined(OS_OPENBSD) && !defined(OS_FREEBSD)
     82     LOG(WARNING) << "Failed to get fopen64() from libc. Using fopen() instead.";
     83 #endif  // !defined(OS_OPENBSD) && !defined(OS_FREEBSD)
     84     g_libc_fopen64 = g_libc_fopen;
     85   }
     86 
     87 #if HAVE_XSTAT
     88   g_libc_xstat = reinterpret_cast<XstatFunction>(
     89       dlsym(RTLD_NEXT, "__xstat"));
     90   g_libc_xstat64 = reinterpret_cast<Xstat64Function>(
     91       dlsym(RTLD_NEXT, "__xstat64"));
     92 
     93   if (!g_libc_xstat) {
     94     LOG(FATAL) << "Failed to get __xstat() from libc.";
     95   }
     96   if (!g_libc_xstat64) {
     97     LOG(FATAL) << "Failed to get __xstat64() from libc.";
     98   }
     99 #else
    100   g_libc_stat = reinterpret_cast<StatFunction>(
    101       dlsym(RTLD_NEXT, "stat"));
    102   g_libc_stat64 = reinterpret_cast<Stat64Function>(
    103       dlsym(RTLD_NEXT, "stat64"));
    104 
    105   if (!g_libc_stat) {
    106     LOG(FATAL) << "Failed to get stat() from libc.";
    107   }
    108   if (!g_libc_stat64) {
    109     LOG(FATAL) << "Failed to get stat64() from libc.";
    110   }
    111 #endif  // HAVE_XSTAT
    112 }
    113 
    114 // fopen() and fopen64() are intercepted here so that NSS can open
    115 // /dev/urandom to seed its random number generator. NSS is used by
    116 // remoting in the sendbox.
    117 
    118 // fopen() call may be redirected to fopen64() in stdio.h using
    119 // __REDIRECT(), which sets asm name for fopen() to "fopen64". This
    120 // means that we cannot override fopen() directly here. Instead the
    121 // the code below defines fopen_override() function with asm name
    122 // "fopen", so that all references to fopen() will resolve to this
    123 // function.
    124 __attribute__ ((__visibility__("default")))
    125 FILE* fopen_override(const char* path, const char* mode)  __asm__ ("fopen");
    126 
    127 __attribute__ ((__visibility__("default")))
    128 FILE* fopen_override(const char* path, const char* mode) {
    129   if (g_override_urandom && strcmp(path, kUrandomDevPath) == 0) {
    130     int fd = HANDLE_EINTR(dup(base::GetUrandomFD()));
    131     if (fd < 0) {
    132       PLOG(ERROR) << "dup() failed.";
    133       return NULL;
    134     }
    135     return fdopen(fd, mode);
    136   } else {
    137     CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
    138                              InitLibcFileIOFunctions));
    139     return g_libc_fopen(path, mode);
    140   }
    141 }
    142 
    143 __attribute__ ((__visibility__("default")))
    144 FILE* fopen64(const char* path, const char* mode) {
    145   if (g_override_urandom && strcmp(path, kUrandomDevPath) == 0) {
    146     int fd = HANDLE_EINTR(dup(base::GetUrandomFD()));
    147     if (fd < 0) {
    148       PLOG(ERROR) << "dup() failed.";
    149       return NULL;
    150     }
    151     return fdopen(fd, mode);
    152   } else {
    153     CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
    154                              InitLibcFileIOFunctions));
    155     return g_libc_fopen64(path, mode);
    156   }
    157 }
    158 
    159 // The stat() family of functions are subject to the same problem as
    160 // fopen(), so we have to use the same trick to override them.
    161 
    162 #if HAVE_XSTAT
    163 
    164 __attribute__ ((__visibility__("default")))
    165 int xstat_override(int version,
    166                    const char *path,
    167                    struct stat *buf)  __asm__ ("__xstat");
    168 
    169 __attribute__ ((__visibility__("default")))
    170 int xstat_override(int version, const char *path, struct stat *buf) {
    171   if (g_override_urandom && strcmp(path, kUrandomDevPath) == 0) {
    172     int result = __fxstat(version, base::GetUrandomFD(), buf);
    173     return result;
    174   } else {
    175     CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
    176                              InitLibcFileIOFunctions));
    177     return g_libc_xstat(version, path, buf);
    178   }
    179 }
    180 
    181 __attribute__ ((__visibility__("default")))
    182 int xstat64_override(int version,
    183                      const char *path,
    184                      struct stat64 *buf)  __asm__ ("__xstat64");
    185 
    186 __attribute__ ((__visibility__("default")))
    187 int xstat64_override(int version, const char *path, struct stat64 *buf) {
    188   if (g_override_urandom && strcmp(path, kUrandomDevPath) == 0) {
    189     int result = __fxstat64(version, base::GetUrandomFD(), buf);
    190     return result;
    191   } else {
    192     CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
    193                              InitLibcFileIOFunctions));
    194     return g_libc_xstat64(version, path, buf);
    195   }
    196 }
    197 
    198 #else
    199 
    200 __attribute__ ((__visibility__("default")))
    201 int stat_override(const char *path,
    202                   struct stat *buf)  __asm__ ("stat");
    203 
    204 __attribute__ ((__visibility__("default")))
    205 int stat_override(const char *path, struct stat *buf) {
    206   if (g_override_urandom && strcmp(path, kUrandomDevPath) == 0) {
    207     int result = fstat(base::GetUrandomFD(), buf);
    208     return result;
    209   } else {
    210     CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
    211                              InitLibcFileIOFunctions));
    212     return g_libc_stat(path, buf);
    213   }
    214 }
    215 
    216 __attribute__ ((__visibility__("default")))
    217 int stat64_override(const char *path,
    218                     struct stat64 *buf)  __asm__ ("stat64");
    219 
    220 __attribute__ ((__visibility__("default")))
    221 int stat64_override(const char *path, struct stat64 *buf) {
    222   if (g_override_urandom && strcmp(path, kUrandomDevPath) == 0) {
    223     int result = fstat64(base::GetUrandomFD(), buf);
    224     return result;
    225   } else {
    226     CHECK_EQ(0, pthread_once(&g_libc_file_io_funcs_guard,
    227                              InitLibcFileIOFunctions));
    228     return g_libc_stat64(path, buf);
    229   }
    230 }
    231 
    232 #endif  // HAVE_XSTAT
    233 
    234 #endif  // !(defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER))
    235 
    236 }  // namespace content
    237