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/log.h" 27#include "nacl_io/osmman.h" 28#include "nacl_io/ostime.h" 29 30namespace { 31 32void stat_to_nacl_stat(const struct stat* buf, nacl_abi_stat* nacl_buf) { 33 memset(nacl_buf, 0, sizeof(struct nacl_abi_stat)); 34 nacl_buf->nacl_abi_st_dev = buf->st_dev; 35 nacl_buf->nacl_abi_st_ino = buf->st_ino; 36 nacl_buf->nacl_abi_st_mode = buf->st_mode; 37 nacl_buf->nacl_abi_st_nlink = buf->st_nlink; 38 nacl_buf->nacl_abi_st_uid = buf->st_uid; 39 nacl_buf->nacl_abi_st_gid = buf->st_gid; 40 nacl_buf->nacl_abi_st_rdev = buf->st_rdev; 41 nacl_buf->nacl_abi_st_size = buf->st_size; 42 nacl_buf->nacl_abi_st_blksize = buf->st_blksize; 43 nacl_buf->nacl_abi_st_blocks = buf->st_blocks; 44 nacl_buf->nacl_abi_st_atime = buf->st_atime; 45 nacl_buf->nacl_abi_st_atimensec = buf->st_atimensec; 46 nacl_buf->nacl_abi_st_mtime = buf->st_mtime; 47 nacl_buf->nacl_abi_st_mtimensec = buf->st_mtimensec; 48 nacl_buf->nacl_abi_st_ctime = buf->st_ctime; 49 nacl_buf->nacl_abi_st_ctimensec = buf->st_ctimensec; 50} 51 52void nacl_stat_to_stat(const nacl_abi_stat* nacl_buf, struct stat* buf) { 53 memset(buf, 0, sizeof(struct stat)); 54 buf->st_dev = nacl_buf->nacl_abi_st_dev; 55 buf->st_ino = nacl_buf->nacl_abi_st_ino; 56 buf->st_mode = nacl_buf->nacl_abi_st_mode; 57 buf->st_nlink = nacl_buf->nacl_abi_st_nlink; 58 buf->st_uid = nacl_buf->nacl_abi_st_uid; 59 buf->st_gid = nacl_buf->nacl_abi_st_gid; 60 buf->st_rdev = nacl_buf->nacl_abi_st_rdev; 61 buf->st_size = nacl_buf->nacl_abi_st_size; 62 buf->st_blksize = nacl_buf->nacl_abi_st_blksize; 63 buf->st_blocks = nacl_buf->nacl_abi_st_blocks; 64 buf->st_atime = nacl_buf->nacl_abi_st_atime; 65 buf->st_atimensec = nacl_buf->nacl_abi_st_atimensec; 66 buf->st_mtime = nacl_buf->nacl_abi_st_mtime; 67 buf->st_mtimensec = nacl_buf->nacl_abi_st_mtimensec; 68 buf->st_ctime = nacl_buf->nacl_abi_st_ctime; 69 buf->st_ctimensec = nacl_buf->nacl_abi_st_ctimensec; 70} 71 72} // namespace 73 74// From native_client/src/trusted/service_runtime/include/sys/dirent.h 75 76#ifndef nacl_abi___ino_t_defined 77#define nacl_abi___ino_t_defined 78typedef int64_t nacl_abi___ino_t; 79typedef nacl_abi___ino_t nacl_abi_ino_t; 80#endif 81 82#ifndef nacl_abi___off_t_defined 83#define nacl_abi___off_t_defined 84typedef int64_t nacl_abi__off_t; 85typedef nacl_abi__off_t nacl_abi_off_t; 86#endif 87 88/* We need a way to define the maximum size of a name. */ 89#ifndef MAXNAMLEN 90# ifdef NAME_MAX 91# define MAXNAMLEN NAME_MAX 92# else 93# define MAXNAMLEN 255 94# endif 95#endif 96 97struct nacl_abi_dirent { 98 nacl_abi_ino_t nacl_abi_d_ino; 99 nacl_abi_off_t nacl_abi_d_off; 100 uint16_t nacl_abi_d_reclen; 101 char nacl_abi_d_name[MAXNAMLEN + 1]; 102}; 103 104static const int d_name_shift = offsetof (dirent, d_name) - 105 offsetof (struct nacl_abi_dirent, nacl_abi_d_name); 106 107EXTERN_C_BEGIN 108 109// Macro to get the REAL function pointer 110#define REAL(name) __nacl_irt_##name##_real 111 112// Macro to get the WRAP function 113#define WRAP(name) __nacl_irt_##name##_wrap 114 115// Declare REAL function pointer. 116#define DECLARE_REAL_PTR(name) typeof(__nacl_irt_##name) REAL(name); 117 118// Assign the REAL function pointer. 119#define ASSIGN_REAL_PTR(name) \ 120 assert(__nacl_irt_##name != NULL); \ 121 REAL(name) = __nacl_irt_##name; 122 123// Switch IRT's pointer to the REAL pointer 124#define USE_REAL(name) __nacl_irt_##name = (typeof(__nacl_irt_##name))REAL(name) 125 126// Switch IRT's pointer to the WRAP function 127#define USE_WRAP(name) __nacl_irt_##name = (typeof(__nacl_irt_##name))WRAP(name) 128 129#define EXPAND_SYMBOL_LIST_OPERATION(OP) \ 130 OP(chdir); \ 131 OP(close); \ 132 OP(dup); \ 133 OP(dup2); \ 134 OP(exit); \ 135 OP(fstat); \ 136 OP(getcwd); \ 137 OP(getdents); \ 138 OP(mkdir); \ 139 OP(open); \ 140 OP(poll); \ 141 OP(read); \ 142 OP(rmdir); \ 143 OP(seek); \ 144 OP(stat); \ 145 OP(select); \ 146 OP(write); \ 147 OP(mmap); \ 148 OP(munmap); \ 149 OP(open_resource); \ 150 \ 151 OP(socket); \ 152 OP(accept); \ 153 OP(bind); \ 154 OP(listen); \ 155 OP(connect); \ 156 OP(send); \ 157 OP(sendmsg); \ 158 OP(sendto); \ 159 OP(recv); \ 160 OP(recvmsg); \ 161 OP(recvfrom); \ 162 OP(getpeername); \ 163 OP(getsockname); \ 164 OP(getsockopt); \ 165 OP(setsockopt); \ 166 OP(socketpair); \ 167 OP(shutdown); \ 168 \ 169 OP(chmod); \ 170 OP(access); \ 171 OP(unlink); \ 172 OP(fchdir); \ 173 OP(fchmod); \ 174 OP(fsync); \ 175 OP(fdatasync); \ 176 OP(lstat); \ 177 OP(link); \ 178 OP(readlink); \ 179 OP(utimes); 180 181// TODO(bradnelson): Add these as well. 182// OP(epoll_create); 183// OP(epoll_create1); 184// OP(epoll_ctl); 185// OP(epoll_pwait); 186// OP(ppoll); 187// OP(pselect); 188 189EXPAND_SYMBOL_LIST_OPERATION(DECLARE_REAL_PTR); 190 191int WRAP(chdir)(const char* pathname) { 192 ERRNO_RTN(ki_chdir(pathname)); 193} 194 195int WRAP(close)(int fd) { 196 ERRNO_RTN(ki_close(fd)); 197} 198 199int WRAP(dup)(int fd, int* newfd) NOTHROW { 200 *newfd = ki_dup(fd); 201 RTN_ERRNO_IF(*newfd < 0); 202 return 0; 203} 204 205int WRAP(dup2)(int fd, int newfd) NOTHROW { 206 ERRNO_RTN(ki_dup2(fd, newfd)); 207} 208 209void WRAP(exit)(int status) { 210 ki_exit(status); 211} 212 213int WRAP(fstat)(int fd, struct nacl_abi_stat* nacl_buf) { 214 struct stat buf; 215 memset(&buf, 0, sizeof(struct stat)); 216 int res = ki_fstat(fd, &buf); 217 RTN_ERRNO_IF(res < 0); 218 stat_to_nacl_stat(&buf, nacl_buf); 219 return 0; 220} 221 222int WRAP(getcwd)(char* buf, size_t size) { 223 RTN_ERRNO_IF(ki_getcwd(buf, size) == NULL); 224 return 0; 225} 226 227int WRAP(getdents)(int fd, dirent* nacl_buf, size_t nacl_count, size_t* nread) { 228 int nacl_offset = 0; 229 // "buf" contains dirent(s); "nacl_buf" contains nacl_abi_dirent(s). 230 // nacl_abi_dirent(s) are smaller than dirent(s), so nacl_count bytes buffer 231 // is enough 232 char* buf = (char*)alloca(nacl_count); 233 int offset = 0; 234 int count; 235 236 count = ki_getdents(fd, buf, nacl_count); 237 RTN_ERRNO_IF(count < 0); 238 239 while (offset < count) { 240 dirent* d = (dirent*)(buf + offset); 241 nacl_abi_dirent* nacl_d = (nacl_abi_dirent*)((char*)nacl_buf + nacl_offset); 242 nacl_d->nacl_abi_d_ino = d->d_ino; 243 nacl_d->nacl_abi_d_off = d->d_off; 244 nacl_d->nacl_abi_d_reclen = d->d_reclen - d_name_shift; 245 size_t d_name_len = d->d_reclen - offsetof(dirent, d_name); 246 memcpy(nacl_d->nacl_abi_d_name, d->d_name, d_name_len); 247 248 offset += d->d_reclen; 249 nacl_offset += nacl_d->nacl_abi_d_reclen; 250 } 251 252 *nread = nacl_offset; 253 return 0; 254} 255 256int WRAP(mkdir)(const char* pathname, mode_t mode) { 257 RTN_ERRNO_IF(ki_mkdir(pathname, mode) < 0); 258 return 0; 259} 260 261int WRAP(mmap)(void** addr, 262 size_t length, 263 int prot, 264 int flags, 265 int fd, 266 off_t offset) { 267 if (flags & MAP_ANONYMOUS) 268 return REAL(mmap)(addr, length, prot, flags, fd, offset); 269 270 *addr = ki_mmap(*addr, length, prot, flags, fd, offset); 271 RTN_ERRNO_IF(*addr == (void*)-1); 272 return 0; 273} 274 275int WRAP(munmap)(void* addr, size_t length) { 276 // Always let the real munmap run on the address range. It is not an error if 277 // there are no mapped pages in that range. 278 ki_munmap(addr, length); 279 return REAL(munmap)(addr, length); 280} 281 282int WRAP(open)(const char* pathname, int oflag, mode_t mode, int* newfd) { 283 *newfd = ki_open(pathname, oflag, mode); 284 RTN_ERRNO_IF(*newfd < 0); 285 return 0; 286} 287 288int WRAP(open_resource)(const char* file, int* fd) { 289 *fd = ki_open_resource(file); 290 RTN_ERRNO_IF(*fd < 0); 291 return 0; 292} 293 294int WRAP(poll)(struct pollfd* fds, nfds_t nfds, int timeout, int* count) { 295 *count = ki_poll(fds, nfds, timeout); 296 RTN_ERRNO_IF(*count < 0); 297 return 0; 298} 299 300int WRAP(read)(int fd, void* buf, size_t count, size_t* nread) { 301 ssize_t signed_nread = ki_read(fd, buf, count); 302 *nread = static_cast<size_t>(signed_nread); 303 RTN_ERRNO_IF(signed_nread < 0); 304 return 0; 305} 306 307int WRAP(rmdir)(const char* pathname) { 308 RTN_ERRNO_IF(ki_rmdir(pathname) < 0); 309 return 0; 310} 311 312int WRAP(seek)(int fd, off_t offset, int whence, off_t* new_offset) { 313 *new_offset = ki_lseek(fd, offset, whence); 314 RTN_ERRNO_IF(*new_offset < 0); 315 return 0; 316} 317 318int WRAP(select)(int nfds, 319 fd_set* readfds, 320 fd_set* writefds, 321 fd_set* exceptfds, 322 struct timeval* timeout, 323 int* count) { 324 *count = ki_select(nfds, readfds, writefds, exceptfds, timeout); 325 RTN_ERRNO_IF(*count < 0); 326 return 0; 327} 328 329int WRAP(stat)(const char* pathname, struct nacl_abi_stat* nacl_buf) { 330 struct stat buf; 331 memset(&buf, 0, sizeof(struct stat)); 332 int res = ki_stat(pathname, &buf); 333 RTN_ERRNO_IF(res < 0); 334 stat_to_nacl_stat(&buf, nacl_buf); 335 return 0; 336} 337 338int WRAP(lstat)(const char* pathname, struct nacl_abi_stat* nacl_buf) { 339 struct stat buf; 340 memset(&buf, 0, sizeof(struct stat)); 341 int res = ki_lstat(pathname, &buf); 342 RTN_ERRNO_IF(res < 0); 343 stat_to_nacl_stat(&buf, nacl_buf); 344 return 0; 345} 346 347int WRAP(link)(const char* pathname, const char* newpath) { 348 ERRNO_RTN(ki_link(pathname, newpath)); 349} 350 351int WRAP(readlink)(const char* pathname, 352 char* buf, 353 size_t count, 354 size_t* nread) { 355 int rtn = ki_readlink(pathname, buf, count); 356 RTN_ERRNO_IF(rtn < 0); 357 *nread = rtn; 358 return 0; 359} 360 361int WRAP(utimes)(const char *filename, const struct timeval *times) { 362 ERRNO_RTN(ki_utimes(filename, times)); 363} 364 365int WRAP(chmod)(const char* pathname, mode_t mode) { 366 ERRNO_RTN(ki_chmod(pathname, mode)); 367} 368 369int WRAP(access)(const char* pathname, int amode) { 370 ERRNO_RTN(ki_access(pathname, amode)); 371} 372 373int WRAP(unlink)(const char* pathname) { 374 ERRNO_RTN(ki_unlink(pathname)); 375} 376 377int WRAP(fchdir)(int fd) { 378 ERRNO_RTN(ki_fchdir(fd)); 379} 380 381int WRAP(fchmod)(int fd, mode_t mode) { 382 ERRNO_RTN(ki_fchmod(fd, mode)); 383} 384 385int WRAP(fsync)(int fd) { 386 ERRNO_RTN(ki_fsync(fd)); 387} 388 389int WRAP(fdatasync)(int fd) { 390 ERRNO_RTN(ki_fdatasync(fd)); 391} 392 393int WRAP(write)(int fd, const void* buf, size_t count, size_t* nwrote) { 394 ssize_t signed_nwrote = ki_write(fd, buf, count); 395 *nwrote = static_cast<size_t>(signed_nwrote); 396 RTN_ERRNO_IF(signed_nwrote < 0); 397 return 0; 398} 399 400int WRAP(accept)(int sockfd, 401 struct sockaddr* addr, 402 socklen_t* addrlen, 403 int* sd) { 404 *sd = ki_accept(sockfd, addr, addrlen); 405 RTN_ERRNO_IF(*sd < 0); 406 return 0; 407} 408 409int WRAP(bind)(int sockfd, const struct sockaddr* addr, socklen_t addrlen) { 410 ERRNO_RTN(ki_bind(sockfd, addr, addrlen)); 411} 412 413int WRAP(connect)(int sockfd, const struct sockaddr* addr, socklen_t addrlen) { 414 ERRNO_RTN(ki_connect(sockfd, addr, addrlen)); 415} 416 417int WRAP(getpeername)(int sockfd, struct sockaddr* addr, socklen_t* addrlen) { 418 ERRNO_RTN(ki_getpeername(sockfd, addr, addrlen)); 419} 420 421int WRAP(getsockname)(int sockfd, struct sockaddr* addr, socklen_t* addrlen) { 422 ERRNO_RTN(ki_getsockname(sockfd, addr, addrlen)); 423} 424 425int WRAP(getsockopt)(int sockfd, 426 int level, 427 int optname, 428 void* optval, 429 socklen_t* optlen) { 430 ERRNO_RTN(ki_getsockopt(sockfd, level, optname, optval, optlen)); 431} 432 433int WRAP(setsockopt)(int sockfd, 434 int level, 435 int optname, 436 const void* optval, 437 socklen_t optlen) { 438 ERRNO_RTN(ki_setsockopt(sockfd, level, optname, optval, optlen)); 439} 440 441int WRAP(listen)(int sockfd, int backlog) { 442 ERRNO_RTN(ki_listen(sockfd, backlog)); 443} 444 445int WRAP(recv)(int sockfd, void* buf, size_t len, int flags, int* count) { 446 ssize_t signed_nread = ki_recv(sockfd, buf, len, flags); 447 *count = static_cast<int>(signed_nread); 448 RTN_ERRNO_IF(signed_nread < 0); 449 return 0; 450} 451 452int WRAP(recvfrom)(int sockfd, 453 void* buf, 454 size_t len, 455 int flags, 456 struct sockaddr* addr, 457 socklen_t* addrlen, 458 int* count) { 459 ssize_t signed_nread = ki_recvfrom(sockfd, buf, len, flags, addr, addrlen); 460 *count = static_cast<int>(signed_nread); 461 RTN_ERRNO_IF(signed_nread < 0); 462 return 0; 463} 464 465int WRAP(recvmsg)(int sockfd, struct msghdr* msg, int flags, int* count) { 466 ssize_t signed_nread = ki_recvmsg(sockfd, msg, flags); 467 *count = static_cast<int>(signed_nread); 468 RTN_ERRNO_IF(signed_nread < 0); 469 return 0; 470} 471 472ssize_t WRAP(send)(int sockfd, const void* buf, size_t len, int flags, 473 int* count) { 474 ssize_t signed_nread = ki_send(sockfd, buf, len, flags); 475 *count = static_cast<int>(signed_nread); 476 RTN_ERRNO_IF(signed_nread < 0); 477 return 0; 478} 479 480ssize_t WRAP(sendto)(int sockfd, 481 const void* buf, 482 size_t len, 483 int flags, 484 const struct sockaddr* addr, 485 socklen_t addrlen, 486 int* count) { 487 ssize_t signed_nread = ki_sendto(sockfd, buf, len, flags, addr, addrlen); 488 *count = static_cast<int>(signed_nread); 489 RTN_ERRNO_IF(signed_nread < 0); 490 return 0; 491} 492 493ssize_t WRAP(sendmsg)(int sockfd, 494 const struct msghdr* msg, 495 int flags, 496 int* count) { 497 ssize_t signed_nread = ki_sendmsg(sockfd, msg, flags); 498 *count = static_cast<int>(signed_nread); 499 RTN_ERRNO_IF(signed_nread < 0); 500 return 0; 501} 502 503int WRAP(shutdown)(int sockfd, int how) { 504 RTN_ERRNO_IF(ki_shutdown(sockfd, how) < 0); 505 return 0; 506} 507 508int WRAP(socket)(int domain, int type, int protocol, int* sd) { 509 *sd = ki_socket(domain, type, protocol); 510 RTN_ERRNO_IF(*sd < 0); 511 return 0; 512} 513 514int WRAP(socketpair)(int domain, int type, int protocol, int* sv) { 515 RTN_ERRNO_IF(ki_socketpair(domain, type, protocol, sv) < 0); 516 return 0; 517} 518 519static void assign_real_pointers() { 520 static bool assigned = false; 521 if (!assigned) { 522 EXPAND_SYMBOL_LIST_OPERATION(ASSIGN_REAL_PTR) 523 assigned = true; 524 } 525} 526 527#define CHECK_REAL(func) \ 528 if (!REAL(func)) { \ 529 assign_real_pointers(); \ 530 if (!REAL(func)) \ 531 return ENOSYS; \ 532 } 533 534// "real" functions, i.e. the unwrapped original functions. 535 536int _real_close(int fd) { 537 CHECK_REAL(close); 538 return REAL(close)(fd); 539} 540 541void _real_exit(int status) { 542 if (!REAL(exit)) 543 assign_real_pointers(); 544 REAL(exit)(status); 545} 546 547int _real_fstat(int fd, struct stat* buf) { 548 struct nacl_abi_stat st; 549 CHECK_REAL(fstat); 550 int err = REAL(fstat)(fd, &st); 551 if (err) { 552 errno = err; 553 return -1; 554 } 555 556 nacl_stat_to_stat(&st, buf); 557 return 0; 558} 559 560int _real_getdents(int fd, void* buf, size_t count, size_t* nread) { 561 // "buf" contains dirent(s); "nacl_buf" contains nacl_abi_dirent(s). 562 // See WRAP(getdents) above. 563 char* nacl_buf = (char*)alloca(count); 564 size_t offset = 0; 565 size_t nacl_offset = 0; 566 size_t nacl_nread; 567 CHECK_REAL(getdents); 568 int err = REAL(getdents)(fd, (dirent*)nacl_buf, count, &nacl_nread); 569 if (err) 570 return err; 571 572 while (nacl_offset < nacl_nread) { 573 dirent* d = (dirent*)((char*)buf + offset); 574 nacl_abi_dirent* nacl_d = (nacl_abi_dirent*)(nacl_buf + nacl_offset); 575 d->d_ino = nacl_d->nacl_abi_d_ino; 576 d->d_off = nacl_d->nacl_abi_d_off; 577 d->d_reclen = nacl_d->nacl_abi_d_reclen + d_name_shift; 578 size_t d_name_len = 579 nacl_d->nacl_abi_d_reclen - offsetof(nacl_abi_dirent, nacl_abi_d_name); 580 memcpy(d->d_name, nacl_d->nacl_abi_d_name, d_name_len); 581 582 offset += d->d_reclen; 583 offset += nacl_d->nacl_abi_d_reclen; 584 } 585 586 *nread = offset; 587 return 0; 588} 589 590int _real_lseek(int fd, off_t offset, int whence, off_t* new_offset) { 591 CHECK_REAL(seek); 592 return REAL(seek)(fd, offset, whence, new_offset); 593} 594 595int _real_mkdir(const char* pathname, mode_t mode) { 596 CHECK_REAL(mkdir); 597 return REAL(mkdir)(pathname, mode); 598} 599 600int _real_mmap(void** addr, 601 size_t length, 602 int prot, 603 int flags, 604 int fd, 605 off_t offset) { 606 CHECK_REAL(mmap); 607 return REAL(mmap)(addr, length, prot, flags, fd, offset); 608} 609 610int _real_munmap(void* addr, size_t length) { 611 CHECK_REAL(munmap); 612 return REAL(munmap)(addr, length); 613} 614 615int _real_open(const char* pathname, int oflag, mode_t mode, int* newfd) { 616 CHECK_REAL(open); 617 return REAL(open)(pathname, oflag, mode, newfd); 618} 619 620int _real_open_resource(const char* file, int* fd) { 621 CHECK_REAL(open_resource); 622 return REAL(open_resource)(file, fd); 623} 624 625int _real_read(int fd, void* buf, size_t count, size_t* nread) { 626 CHECK_REAL(read); 627 return REAL(read)(fd, buf, count, nread); 628} 629 630int _real_rmdir(const char* pathname) { 631 CHECK_REAL(rmdir); 632 return REAL(rmdir)(pathname); 633} 634 635int _real_write(int fd, const void* buf, size_t count, size_t* nwrote) { 636 CHECK_REAL(write); 637 return REAL(write)(fd, buf, count, nwrote); 638} 639 640int _real_getcwd(char* pathname, size_t len) { 641 CHECK_REAL(getcwd); 642 return REAL(getcwd)(pathname, len); 643} 644 645static bool s_wrapped = false; 646void kernel_wrap_init() { 647 if (!s_wrapped) { 648 LOG_TRACE("kernel_wrap_init"); 649 assign_real_pointers(); 650 EXPAND_SYMBOL_LIST_OPERATION(USE_WRAP) 651 s_wrapped = true; 652 } 653} 654 655void kernel_wrap_uninit() { 656 if (s_wrapped) { 657 LOG_TRACE("kernel_wrap_uninit"); 658 EXPAND_SYMBOL_LIST_OPERATION(USE_REAL) 659 s_wrapped = false; 660 } 661} 662 663EXTERN_C_END 664 665#endif // defined(__native_client__) && defined(__GLIBC__) 666