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