Home | History | Annotate | Download | only in nacl_io
      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 <sys/types.h>  // Include something that will define __GLIBC__.
      6 
      7 // The entire file is wrapped in this #if. We do this so this .cc file can be
      8 // compiled, even on a non-glibc build.
      9 #if defined(__native_client__) && defined(__GLIBC__)
     10 
     11 #include "nacl_io/kernel_wrap.h"
     12 
     13 #include <alloca.h>
     14 #include <assert.h>
     15 #include <dirent.h>
     16 #include <errno.h>
     17 #include <irt.h>
     18 #include <irt_syscalls.h>
     19 #include <nacl_stat.h>
     20 #include <string.h>
     21 #include <sys/stat.h>
     22 #include <sys/time.h>
     23 
     24 #include "nacl_io/kernel_intercept.h"
     25 #include "nacl_io/kernel_wrap_real.h"
     26 #include "nacl_io/osmman.h"
     27 
     28 
     29 namespace {
     30 
     31 void stat_to_nacl_stat(const struct stat* buf, nacl_abi_stat* nacl_buf) {
     32   memset(nacl_buf, 0, sizeof(struct nacl_abi_stat));
     33   nacl_buf->nacl_abi_st_dev = buf->st_dev;
     34   nacl_buf->nacl_abi_st_ino = buf->st_ino;
     35   nacl_buf->nacl_abi_st_mode = buf->st_mode;
     36   nacl_buf->nacl_abi_st_nlink = buf->st_nlink;
     37   nacl_buf->nacl_abi_st_uid = buf->st_uid;
     38   nacl_buf->nacl_abi_st_gid = buf->st_gid;
     39   nacl_buf->nacl_abi_st_rdev = buf->st_rdev;
     40   nacl_buf->nacl_abi_st_size = buf->st_size;
     41   nacl_buf->nacl_abi_st_blksize = buf->st_blksize;
     42   nacl_buf->nacl_abi_st_blocks = buf->st_blocks;
     43   nacl_buf->nacl_abi_st_atime = buf->st_atime;
     44   nacl_buf->nacl_abi_st_mtime = buf->st_mtime;
     45   nacl_buf->nacl_abi_st_ctime = buf->st_ctime;
     46 }
     47 
     48 void nacl_stat_to_stat(const nacl_abi_stat* nacl_buf, struct stat* buf) {
     49   memset(buf, 0, sizeof(struct stat));
     50   buf->st_dev = nacl_buf->nacl_abi_st_dev;
     51   buf->st_ino = nacl_buf->nacl_abi_st_ino;
     52   buf->st_mode = nacl_buf->nacl_abi_st_mode;
     53   buf->st_nlink = nacl_buf->nacl_abi_st_nlink;
     54   buf->st_uid = nacl_buf->nacl_abi_st_uid;
     55   buf->st_gid = nacl_buf->nacl_abi_st_gid;
     56   buf->st_rdev = nacl_buf->nacl_abi_st_rdev;
     57   buf->st_size = nacl_buf->nacl_abi_st_size ;
     58   buf->st_blksize = nacl_buf->nacl_abi_st_blksize;
     59   buf->st_blocks = nacl_buf->nacl_abi_st_blocks;
     60   buf->st_atime = nacl_buf->nacl_abi_st_atime;
     61   buf->st_mtime = nacl_buf->nacl_abi_st_mtime;
     62   buf->st_ctime = nacl_buf->nacl_abi_st_ctime;
     63 }
     64 
     65 }  // namespace
     66 
     67 // From native_client/src/trusted/service_runtime/include/sys/dirent.h
     68 
     69 #ifndef nacl_abi___ino_t_defined
     70 #define nacl_abi___ino_t_defined
     71 typedef int64_t nacl_abi___ino_t;
     72 typedef nacl_abi___ino_t nacl_abi_ino_t;
     73 #endif
     74 
     75 #ifndef nacl_abi___off_t_defined
     76 #define nacl_abi___off_t_defined
     77 typedef int64_t nacl_abi__off_t;
     78 typedef nacl_abi__off_t nacl_abi_off_t;
     79 #endif
     80 
     81 /* We need a way to define the maximum size of a name. */
     82 #ifndef MAXNAMLEN
     83 # ifdef NAME_MAX
     84 #  define MAXNAMLEN NAME_MAX
     85 # else
     86 #  define MAXNAMLEN 255
     87 # endif
     88 #endif
     89 
     90 struct nacl_abi_dirent {
     91   nacl_abi_ino_t nacl_abi_d_ino;
     92   nacl_abi_off_t nacl_abi_d_off;
     93   uint16_t       nacl_abi_d_reclen;
     94   char           nacl_abi_d_name[MAXNAMLEN + 1];
     95 };
     96 
     97 static const int d_name_shift = offsetof (dirent, d_name) -
     98   offsetof (struct nacl_abi_dirent, nacl_abi_d_name);
     99 
    100 EXTERN_C_BEGIN
    101 
    102 // Macro to get the REAL function pointer
    103 #define REAL(name) __nacl_irt_##name##_real
    104 
    105 // Macro to get the WRAP function
    106 #define WRAP(name) __nacl_irt_##name##_wrap
    107 
    108 // Declare REAL function pointer.
    109 #define DECLARE_REAL_PTR(name) \
    110   typeof(__nacl_irt_##name) REAL(name);
    111 
    112 // Assign the REAL function pointer.
    113 #define ASSIGN_REAL_PTR(name) \
    114   assert(__nacl_irt_##name != NULL); \
    115   REAL(name) = __nacl_irt_##name;
    116 
    117 // Switch IRT's pointer to the REAL pointer
    118 #define USE_REAL(name) \
    119   __nacl_irt_##name = (typeof(__nacl_irt_##name)) REAL(name)
    120 
    121 // Switch IRT's pointer to the WRAP function
    122 #define USE_WRAP(name) \
    123   __nacl_irt_##name = (typeof(__nacl_irt_##name)) WRAP(name)
    124 
    125 
    126 #define EXPAND_SYMBOL_LIST_OPERATION(OP) \
    127   OP(chdir); \
    128   OP(close); \
    129   OP(dup); \
    130   OP(dup2);  \
    131   OP(fstat); \
    132   OP(getcwd);  \
    133   OP(getdents);  \
    134   OP(mkdir); \
    135   OP(open); \
    136   OP(poll);\
    137   OP(read); \
    138   OP(rmdir); \
    139   OP(seek); \
    140   OP(stat); \
    141   OP(select); \
    142   OP(write); \
    143   OP(mmap); \
    144   OP(munmap); \
    145   OP(open_resource);
    146 
    147 EXPAND_SYMBOL_LIST_OPERATION(DECLARE_REAL_PTR);
    148 
    149 int WRAP(chdir) (const char* pathname) {
    150   return (ki_chdir(pathname)) ? errno : 0;
    151 }
    152 
    153 int WRAP(close)(int fd) {
    154   return (ki_close(fd) < 0) ? errno : 0;
    155 }
    156 
    157 int WRAP(dup)(int fd, int* newfd) NOTHROW {
    158   *newfd = ki_dup(fd);
    159   return (*newfd < 0) ? errno : 0;
    160 }
    161 
    162 int WRAP(dup2)(int fd, int newfd) NOTHROW {
    163   return (ki_dup2(fd, newfd) < 0) ? errno : 0;
    164 }
    165 
    166 int WRAP(fstat)(int fd, struct nacl_abi_stat *nacl_buf) {
    167   struct stat buf;
    168   memset(&buf, 0, sizeof(struct stat));
    169   int res = ki_fstat(fd, &buf);
    170   if (res < 0)
    171     return errno;
    172   stat_to_nacl_stat(&buf, nacl_buf);
    173   return 0;
    174 }
    175 
    176 char* WRAP(getcwd)(char* buf, size_t size) {
    177   return ki_getcwd(buf, size);
    178 }
    179 
    180 int WRAP(getdents)(int fd, dirent* nacl_buf, size_t nacl_count, size_t *nread) {
    181   int nacl_offset = 0;
    182   // "buf" contains dirent(s); "nacl_buf" contains nacl_abi_dirent(s).
    183   // nacl_abi_dirent(s) are smaller than dirent(s), so nacl_count bytes buffer
    184   // is enough
    185   char* buf = (char*)alloca(nacl_count);
    186   int offset = 0;
    187   int count;
    188 
    189   count = ki_getdents(fd, buf, nacl_count);
    190   if (count < 0)
    191     return errno;
    192 
    193   while (offset < count) {
    194     dirent* d = (dirent*)(buf + offset);
    195     nacl_abi_dirent* nacl_d = (nacl_abi_dirent*)((char*)nacl_buf + nacl_offset);
    196     nacl_d->nacl_abi_d_ino = d->d_ino;
    197     nacl_d->nacl_abi_d_off = d->d_off;
    198     nacl_d->nacl_abi_d_reclen = d->d_reclen - d_name_shift;
    199     size_t d_name_len = d->d_reclen - offsetof(dirent, d_name);
    200     memcpy(nacl_d->nacl_abi_d_name, d->d_name, d_name_len);
    201 
    202     offset += d->d_reclen;
    203     nacl_offset += nacl_d->nacl_abi_d_reclen;
    204   }
    205 
    206   *nread = nacl_offset;
    207   return 0;
    208 }
    209 
    210 int WRAP(mkdir)(const char* pathname, mode_t mode) {
    211   return (ki_mkdir(pathname, mode)) ? errno : 0;
    212 }
    213 
    214 int WRAP(mmap)(void** addr, size_t length, int prot, int flags, int fd,
    215                off_t offset) {
    216   if (flags & MAP_ANONYMOUS)
    217     return REAL(mmap)(addr, length, prot, flags, fd, offset);
    218 
    219   *addr = ki_mmap(*addr, length, prot, flags, fd, offset);
    220   return *addr == (void*)-1 ? errno : 0;
    221 }
    222 
    223 int WRAP(munmap)(void* addr, size_t length) {
    224   // Always let the real munmap run on the address range. It is not an error if
    225   // there are no mapped pages in that range.
    226   ki_munmap(addr, length);
    227   return REAL(munmap)(addr, length);
    228 }
    229 
    230 int WRAP(open)(const char* pathname, int oflag, mode_t cmode, int* newfd) {
    231   *newfd = ki_open(pathname, oflag);
    232   return (*newfd < 0) ? errno : 0;
    233 }
    234 
    235 int WRAP(open_resource)(const char* file, int* fd) {
    236   *fd = ki_open_resource(file);
    237   return (*fd < 0) ? errno : 0;
    238 }
    239 
    240 int WRAP(poll)(struct pollfd *fds, nfds_t nfds, int timeout, int* count) {
    241   *count = ki_poll(fds, nfds, timeout);
    242   return (*count < 0) ? errno : 0;
    243 
    244 }
    245 
    246 int WRAP(read)(int fd, void *buf, size_t count, size_t *nread) {
    247   ssize_t signed_nread = ki_read(fd, buf, count);
    248   *nread = static_cast<size_t>(signed_nread);
    249   return (signed_nread < 0) ? errno : 0;
    250 }
    251 
    252 int WRAP(rmdir)(const char* pathname) {
    253   return (ki_rmdir(pathname) < 0) ? errno : 0;
    254 }
    255 
    256 int WRAP(seek)(int fd, off_t offset, int whence, off_t* new_offset) {
    257   *new_offset = ki_lseek(fd, offset, whence);
    258   return (*new_offset < 0) ? errno : 0;
    259 }
    260 
    261 int WRAP(select)(int nfds, fd_set* readfds, fd_set* writefds,
    262                  fd_set* exceptfds, struct timeval* timeout, int* count) {
    263   *count = ki_select(nfds, readfds, writefds, exceptfds, timeout);
    264   return (*count < 0) ? errno : 0;
    265 }
    266 
    267 int WRAP(stat)(const char *pathname, struct nacl_abi_stat *nacl_buf) {
    268   struct stat buf;
    269   memset(&buf, 0, sizeof(struct stat));
    270   int res = ki_stat(pathname, &buf);
    271   if (res < 0)
    272     return errno;
    273   stat_to_nacl_stat(&buf, nacl_buf);
    274   return 0;
    275 }
    276 
    277 int WRAP(write)(int fd, const void* buf, size_t count, size_t* nwrote) {
    278   ssize_t signed_nwrote = ki_write(fd, buf, count);
    279   *nwrote = static_cast<size_t>(signed_nwrote);
    280   return (signed_nwrote < 0) ? errno : 0;
    281 }
    282 
    283 static void assign_real_pointers() {
    284   static bool assigned = false;
    285   if (!assigned) {
    286     EXPAND_SYMBOL_LIST_OPERATION(ASSIGN_REAL_PTR)
    287     assigned = true;
    288   }
    289 }
    290 
    291 #define CHECK_REAL(func) \
    292   if (!REAL(func)) \
    293     assign_real_pointers();
    294 
    295 // "real" functions, i.e. the unwrapped original functions.
    296 
    297 int _real_close(int fd) {
    298   CHECK_REAL(close);
    299   return REAL(close)(fd);
    300 }
    301 
    302 int _real_fstat(int fd, struct stat* buf) {
    303   struct nacl_abi_stat st;
    304   CHECK_REAL(fstat);
    305   int err = REAL(fstat)(fd, &st);
    306   if (err) {
    307     errno = err;
    308     return -1;
    309   }
    310 
    311   nacl_stat_to_stat(&st, buf);
    312   return 0;
    313 }
    314 
    315 int _real_getdents(int fd, void* buf, size_t count, size_t* nread) {
    316   // "buf" contains dirent(s); "nacl_buf" contains nacl_abi_dirent(s).
    317   // See WRAP(getdents) above.
    318   char* nacl_buf = (char*)alloca(count);
    319   size_t offset = 0;
    320   size_t nacl_offset = 0;
    321   size_t nacl_nread;
    322   CHECK_REAL(getdents);
    323   int err = REAL(getdents)(fd, (dirent*)nacl_buf, count, &nacl_nread);
    324   if (err)
    325     return err;
    326 
    327   while (nacl_offset < nacl_nread) {
    328     dirent* d = (dirent*)((char*)buf + offset);
    329     nacl_abi_dirent* nacl_d = (nacl_abi_dirent*)(nacl_buf + nacl_offset);
    330     d->d_ino = nacl_d->nacl_abi_d_ino;
    331     d->d_off = nacl_d->nacl_abi_d_off;
    332     d->d_reclen = nacl_d->nacl_abi_d_reclen + d_name_shift;
    333     size_t d_name_len = nacl_d->nacl_abi_d_reclen -
    334         offsetof(nacl_abi_dirent, nacl_abi_d_name);
    335     memcpy(d->d_name, nacl_d->nacl_abi_d_name, d_name_len);
    336 
    337     offset += d->d_reclen;
    338     offset += nacl_d->nacl_abi_d_reclen;
    339   }
    340 
    341   *nread = offset;
    342   return 0;
    343 }
    344 
    345 int _real_lseek(int fd, off_t offset, int whence, off_t* new_offset) {
    346   CHECK_REAL(seek);
    347   return REAL(seek)(fd, offset, whence, new_offset);
    348 }
    349 
    350 int _real_mkdir(const char* pathname, mode_t mode) {
    351   CHECK_REAL(mkdir);
    352   return REAL(mkdir)(pathname, mode);
    353 }
    354 
    355 int _real_mmap(void** addr, size_t length, int prot, int flags, int fd,
    356                off_t offset) {
    357   CHECK_REAL(mmap);
    358   return REAL(mmap)(addr, length, prot, flags, fd, offset);
    359 }
    360 
    361 int _real_munmap(void* addr, size_t length) {
    362   CHECK_REAL(munmap);
    363   return REAL(munmap)(addr, length);
    364 }
    365 
    366 int _real_open(const char* pathname, int oflag, mode_t cmode, int* newfd) {
    367   CHECK_REAL(open);
    368   return REAL(open)(pathname, oflag, cmode, newfd);
    369 }
    370 
    371 int _real_open_resource(const char* file, int* fd) {
    372   CHECK_REAL(open_resource);
    373   return REAL(open_resource)(file, fd);
    374 }
    375 
    376 int _real_read(int fd, void *buf, size_t count, size_t *nread) {
    377   CHECK_REAL(read);
    378   return REAL(read)(fd, buf, count, nread);
    379 }
    380 
    381 int _real_rmdir(const char* pathname) {
    382   CHECK_REAL(rmdir);
    383   return REAL(rmdir)(pathname);
    384 }
    385 
    386 int _real_write(int fd, const void *buf, size_t count, size_t *nwrote) {
    387   CHECK_REAL(write);
    388   return REAL(write)(fd, buf, count, nwrote);
    389 }
    390 
    391 static bool s_wrapped = false;
    392 void kernel_wrap_init() {
    393   if (!s_wrapped) {
    394     assign_real_pointers();
    395     EXPAND_SYMBOL_LIST_OPERATION(USE_WRAP)
    396     s_wrapped = true;
    397   }
    398 }
    399 
    400 void kernel_wrap_uninit() {
    401   if (s_wrapped) {
    402     EXPAND_SYMBOL_LIST_OPERATION(USE_REAL)
    403     s_wrapped = false;
    404   }
    405 }
    406 
    407 EXTERN_C_END
    408 
    409 #endif  // defined(__native_client__) && defined(__GLIBC__)
    410