kernel_intercept.cc revision 010d83a9304c5a91596085d917d248abff47903a
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 "nacl_io/kernel_intercept.h" 6 7#include <assert.h> 8#include <errno.h> 9#include <string.h> 10 11#include "nacl_io/kernel_proxy.h" 12#include "nacl_io/kernel_wrap.h" 13#include "nacl_io/kernel_wrap_real.h" 14#include "nacl_io/osmman.h" 15#include "nacl_io/ossocket.h" 16#include "nacl_io/pepper_interface.h" 17#include "nacl_io/real_pepper_interface.h" 18 19using namespace nacl_io; 20 21#define ON_NOSYS_RETURN(x) \ 22 if (!ki_is_initialized()) { \ 23 errno = ENOSYS; \ 24 return x; \ 25 } 26 27struct KernelInterceptState { 28 KernelProxy* kp; 29 PepperInterface* ppapi; 30 bool kp_owned; 31}; 32 33static KernelInterceptState s_state; 34 35// The the test code we want to be able to save the previous kernel 36// proxy when intialising and restore it on uninit. 37static KernelInterceptState s_saved_state; 38 39int ki_push_state_for_testing() { 40 assert(s_saved_state.kp == NULL); 41 if (s_saved_state.kp != NULL) 42 return 1; 43 s_saved_state = s_state; 44 s_state.kp = NULL; 45 s_state.ppapi = NULL; 46 s_state.kp_owned = false; 47 return 0; 48} 49 50int ki_init(void* kp) { 51 return ki_init_ppapi(kp, 0, NULL); 52} 53 54int ki_init_ppapi(void* kp, 55 PP_Instance instance, 56 PPB_GetInterface get_browser_interface) { 57 assert(!s_state.kp); 58 if (s_state.kp != NULL) 59 return 1; 60 PepperInterface* ppapi = NULL; 61 if (instance && get_browser_interface) { 62 ppapi = new RealPepperInterface(instance, get_browser_interface); 63 s_state.ppapi = ppapi; 64 } 65 int rtn = ki_init_interface(kp, ppapi); 66 return rtn; 67} 68 69int ki_init_interface(void* kp, void* pepper_interface) { 70 assert(!s_state.kp); 71 if (s_state.kp != NULL) 72 return 1; 73 PepperInterface* ppapi = static_cast<PepperInterface*>(pepper_interface); 74 kernel_wrap_init(); 75 76 if (kp == NULL) { 77 s_state.kp = new KernelProxy(); 78 s_state.kp_owned = true; 79 } else { 80 s_state.kp = static_cast<KernelProxy*>(kp); 81 s_state.kp_owned = false; 82 } 83 84 if (s_state.kp->Init(ppapi) != 0) 85 return 1; 86 87 return 0; 88} 89 90int ki_is_initialized() { 91 return s_state.kp != NULL; 92} 93 94void ki_uninit() { 95 if (s_saved_state.kp == NULL) 96 kernel_wrap_uninit(); 97 98 // If we are going to delete the KernelProxy don't do it 99 // until we've swapped it out. 100 KernelInterceptState state_to_delete = s_state; 101 102 // Swap out the KernelProxy. This will normally reset the 103 // proxy to NULL, aside from in test code that has called 104 // ki_push_state_for_testing(). 105 s_state = s_saved_state; 106 s_saved_state.kp = NULL; 107 s_saved_state.ppapi = NULL; 108 s_saved_state.kp_owned = false; 109 110 if (state_to_delete.kp_owned) 111 delete state_to_delete.kp; 112 113 delete state_to_delete.ppapi; 114} 115 116nacl_io::KernelProxy* ki_get_proxy() { 117 return s_state.kp; 118} 119 120int ki_chdir(const char* path) { 121 ON_NOSYS_RETURN(-1); 122 return s_state.kp->chdir(path); 123} 124 125void ki_exit(int status) { 126 if (ki_is_initialized()) 127 s_state.kp->exit(status); 128 129 _real_exit(status); 130} 131 132char* ki_getcwd(char* buf, size_t size) { 133 // gtest uses getcwd in a static initializer. If we haven't initialized the 134 // kernel-intercept yet, just return ".". 135 if (!ki_is_initialized()) { 136 if (size < 2) { 137 errno = ERANGE; 138 return NULL; 139 } 140 buf[0] = '.'; 141 buf[1] = 0; 142 return buf; 143 } 144 return s_state.kp->getcwd(buf, size); 145} 146 147char* ki_getwd(char* buf) { 148 ON_NOSYS_RETURN(NULL); 149 return s_state.kp->getwd(buf); 150} 151 152int ki_dup(int oldfd) { 153 ON_NOSYS_RETURN(-1); 154 return s_state.kp->dup(oldfd); 155} 156 157int ki_dup2(int oldfd, int newfd) { 158 ON_NOSYS_RETURN(-1); 159 return s_state.kp->dup2(oldfd, newfd); 160} 161 162int ki_chmod(const char *path, mode_t mode) { 163 ON_NOSYS_RETURN(-1); 164 return s_state.kp->chmod(path, mode); 165} 166 167int ki_fchdir(int fd) { 168 ON_NOSYS_RETURN(-1); 169 return s_state.kp->fchdir(fd); 170} 171 172int ki_fchmod(int fd, mode_t mode) { 173 ON_NOSYS_RETURN(-1); 174 return s_state.kp->fchmod(fd, mode); 175} 176 177int ki_stat(const char *path, struct stat *buf) { 178 ON_NOSYS_RETURN(-1); 179 return s_state.kp->stat(path, buf); 180} 181 182int ki_mkdir(const char *path, mode_t mode) { 183 ON_NOSYS_RETURN(-1); 184 return s_state.kp->mkdir(path, mode); 185} 186 187int ki_rmdir(const char *path) { 188 ON_NOSYS_RETURN(-1); 189 return s_state.kp->rmdir(path); 190} 191 192int ki_mount(const char *source, const char *target, const char *filesystemtype, 193 unsigned long mountflags, const void *data) { 194 ON_NOSYS_RETURN(-1); 195 return s_state.kp->mount(source, target, filesystemtype, mountflags, data); 196} 197 198int ki_umount(const char *path) { 199 ON_NOSYS_RETURN(-1); 200 return s_state.kp->umount(path); 201} 202 203int ki_open(const char *path, int oflag) { 204 ON_NOSYS_RETURN(-1); 205 return s_state.kp->open(path, oflag); 206} 207 208int ki_pipe(int pipefds[2]) { 209 ON_NOSYS_RETURN(-1); 210 return s_state.kp->pipe(pipefds); 211} 212 213ssize_t ki_read(int fd, void *buf, size_t nbyte) { 214 ON_NOSYS_RETURN(-1); 215 return s_state.kp->read(fd, buf, nbyte); 216} 217 218ssize_t ki_write(int fd, const void *buf, size_t nbyte) { 219 ON_NOSYS_RETURN(-1); 220 return s_state.kp->write(fd, buf, nbyte); 221} 222 223int ki_fstat(int fd, struct stat *buf){ 224 ON_NOSYS_RETURN(-1); 225 return s_state.kp->fstat(fd, buf); 226} 227 228int ki_getdents(int fd, void *buf, unsigned int count) { 229 ON_NOSYS_RETURN(-1); 230 return s_state.kp->getdents(fd, buf, count); 231} 232 233int ki_ftruncate(int fd, off_t length) { 234 ON_NOSYS_RETURN(-1); 235 return s_state.kp->ftruncate(fd, length); 236} 237 238int ki_fsync(int fd) { 239 ON_NOSYS_RETURN(-1); 240 return s_state.kp->fsync(fd); 241} 242 243int ki_fdatasync(int fd) { 244 ON_NOSYS_RETURN(-1); 245 return s_state.kp->fdatasync(fd); 246} 247 248int ki_isatty(int fd) { 249 ON_NOSYS_RETURN(0); 250 return s_state.kp->isatty(fd); 251} 252 253int ki_close(int fd) { 254 ON_NOSYS_RETURN(-1); 255 return s_state.kp->close(fd); 256} 257 258off_t ki_lseek(int fd, off_t offset, int whence) { 259 ON_NOSYS_RETURN(-1); 260 return s_state.kp->lseek(fd, offset, whence); 261} 262 263int ki_remove(const char* path) { 264 ON_NOSYS_RETURN(-1); 265 return s_state.kp->remove(path); 266} 267 268int ki_unlink(const char* path) { 269 ON_NOSYS_RETURN(-1); 270 return s_state.kp->unlink(path); 271} 272 273int ki_truncate(const char* path, off_t length) { 274 ON_NOSYS_RETURN(-1); 275 return s_state.kp->truncate(path, length); 276} 277 278int ki_lstat(const char* path, struct stat* buf) { 279 ON_NOSYS_RETURN(-1); 280 return s_state.kp->lstat(path, buf); 281} 282 283int ki_link(const char* oldpath, const char* newpath) { 284 ON_NOSYS_RETURN(-1); 285 return s_state.kp->link(oldpath, newpath); 286} 287 288int ki_rename(const char* path, const char* newpath) { 289 ON_NOSYS_RETURN(-1); 290 return s_state.kp->rename(path, newpath); 291} 292 293int ki_symlink(const char* oldpath, const char* newpath) { 294 ON_NOSYS_RETURN(-1); 295 return s_state.kp->symlink(oldpath, newpath); 296} 297 298int ki_access(const char* path, int amode) { 299 ON_NOSYS_RETURN(-1); 300 return s_state.kp->access(path, amode); 301} 302 303int ki_readlink(const char *path, char *buf, size_t count) { 304 ON_NOSYS_RETURN(-1); 305 return s_state.kp->readlink(path, buf, count); 306} 307 308int ki_utimes(const char *path, const struct timeval times[2]) { 309 ON_NOSYS_RETURN(-1); 310 return s_state.kp->utimes(path, times); 311} 312 313void* ki_mmap(void* addr, size_t length, int prot, int flags, int fd, 314 off_t offset) { 315 ON_NOSYS_RETURN(MAP_FAILED); 316 return s_state.kp->mmap(addr, length, prot, flags, fd, offset); 317} 318 319int ki_munmap(void* addr, size_t length) { 320 ON_NOSYS_RETURN(-1); 321 return s_state.kp->munmap(addr, length); 322} 323 324int ki_open_resource(const char* file) { 325 ON_NOSYS_RETURN(-1); return s_state.kp->open_resource(file); 326} 327 328int ki_fcntl(int d, int request, va_list args) { 329 ON_NOSYS_RETURN(-1); 330 return s_state.kp->fcntl(d, request, args); 331} 332 333int ki_ioctl(int d, int request, va_list args) { 334 ON_NOSYS_RETURN(-1); 335 return s_state.kp->ioctl(d, request, args); 336} 337 338int ki_chown(const char* path, uid_t owner, gid_t group) { 339 ON_NOSYS_RETURN(-1); 340 return s_state.kp->chown(path, owner, group); 341} 342 343int ki_fchown(int fd, uid_t owner, gid_t group) { 344 ON_NOSYS_RETURN(-1); 345 return s_state.kp->fchown(fd, owner, group); 346} 347 348int ki_lchown(const char* path, uid_t owner, gid_t group) { 349 ON_NOSYS_RETURN(-1); 350 return s_state.kp->lchown(path, owner, group); 351} 352 353int ki_utime(const char* filename, const struct utimbuf* times) { 354 ON_NOSYS_RETURN(-1); 355 return s_state.kp->utime(filename, times); 356} 357 358int ki_poll(struct pollfd *fds, nfds_t nfds, int timeout) { 359 return s_state.kp->poll(fds, nfds, timeout); 360} 361 362int ki_select(int nfds, fd_set* readfds, fd_set* writefds, 363 fd_set* exceptfds, struct timeval* timeout) { 364 return s_state.kp->select(nfds, readfds, writefds, exceptfds, timeout); 365} 366 367int ki_tcflush(int fd, int queue_selector) { 368 ON_NOSYS_RETURN(-1); 369 return s_state.kp->tcflush(fd, queue_selector); 370} 371 372int ki_tcgetattr(int fd, struct termios* termios_p) { 373 ON_NOSYS_RETURN(-1); 374 return s_state.kp->tcgetattr(fd, termios_p); 375} 376 377int ki_tcsetattr(int fd, int optional_actions, 378 const struct termios *termios_p) { 379 ON_NOSYS_RETURN(-1); 380 return s_state.kp->tcsetattr(fd, optional_actions, termios_p); 381} 382 383int ki_kill(pid_t pid, int sig) { 384 ON_NOSYS_RETURN(-1); 385 return s_state.kp->kill(pid, sig); 386} 387 388int ki_killpg(pid_t pid, int sig) { 389 errno = ENOSYS; 390 return -1; 391} 392 393int ki_sigaction(int signum, const struct sigaction* action, 394 struct sigaction* oaction) { 395 ON_NOSYS_RETURN(-1); 396 return s_state.kp->sigaction(signum, action, oaction); 397} 398 399int ki_sigpause(int sigmask) { 400 errno = ENOSYS; 401 return -1; 402} 403 404int ki_sigpending(sigset_t* set) { 405 errno = ENOSYS; 406 return -1; 407} 408 409int ki_sigsuspend(const sigset_t* set) { 410 errno = ENOSYS; 411 return -1; 412} 413 414sighandler_t ki_signal(int signum, sighandler_t handler) { 415 return ki_sigset(signum, handler); 416} 417 418sighandler_t ki_sigset(int signum, sighandler_t handler) { 419 ON_NOSYS_RETURN(SIG_ERR); 420 // Implement sigset(2) in terms of sigaction(2). 421 struct sigaction action; 422 struct sigaction oaction; 423 memset(&action, 0, sizeof(action)); 424 memset(&oaction, 0, sizeof(oaction)); 425 action.sa_handler = handler; 426 int rtn = s_state.kp->sigaction(signum, &action, &oaction); 427 if (rtn) 428 return SIG_ERR; 429 return oaction.sa_handler; 430} 431 432#ifdef PROVIDES_SOCKET_API 433// Socket Functions 434int ki_accept(int fd, struct sockaddr* addr, socklen_t* len) { 435 ON_NOSYS_RETURN(-1); 436 return s_state.kp->accept(fd, addr, len); 437} 438 439int ki_bind(int fd, const struct sockaddr* addr, socklen_t len) { 440 ON_NOSYS_RETURN(-1); 441 return s_state.kp->bind(fd, addr, len); 442} 443 444int ki_connect(int fd, const struct sockaddr* addr, socklen_t len) { 445 ON_NOSYS_RETURN(-1); 446 return s_state.kp->connect(fd, addr, len); 447} 448 449struct hostent* ki_gethostbyname(const char* name) { 450 ON_NOSYS_RETURN(NULL); 451 return s_state.kp->gethostbyname(name); 452} 453 454int ki_getaddrinfo(const char *node, const char *service, 455 const struct addrinfo *hints, 456 struct addrinfo **res) { 457 ON_NOSYS_RETURN(EAI_SYSTEM); 458 return s_state.kp->getaddrinfo(node, service, hints, res); 459} 460 461void ki_freeaddrinfo(struct addrinfo *res) { 462 s_state.kp->freeaddrinfo(res); 463} 464 465int ki_getpeername(int fd, struct sockaddr* addr, socklen_t* len) { 466 ON_NOSYS_RETURN(-1); 467 return s_state.kp->getpeername(fd, addr, len); 468} 469 470int ki_getsockname(int fd, struct sockaddr* addr, socklen_t* len) { 471 ON_NOSYS_RETURN(-1); 472 return s_state.kp->getsockname(fd, addr, len); 473} 474 475int ki_getsockopt(int fd, int lvl, int optname, void* optval, socklen_t* len) { 476 ON_NOSYS_RETURN(-1); 477 return s_state.kp->getsockopt(fd, lvl, optname, optval, len); 478} 479 480int ki_listen(int fd, int backlog) { 481 ON_NOSYS_RETURN(-1); 482 return s_state.kp->listen(fd, backlog); 483} 484 485ssize_t ki_recv(int fd, void* buf, size_t len, int flags) { 486 ON_NOSYS_RETURN(-1); 487 return s_state.kp->recv(fd, buf, len, flags); 488} 489 490ssize_t ki_recvfrom(int fd, void* buf, size_t len, int flags, 491 struct sockaddr* addr, socklen_t* addrlen) { 492 ON_NOSYS_RETURN(-1); 493 return s_state.kp->recvfrom(fd, buf, len, flags, addr, addrlen); 494} 495 496ssize_t ki_recvmsg(int fd, struct msghdr* msg, int flags) { 497 ON_NOSYS_RETURN(-1); 498 return s_state.kp->recvmsg(fd, msg, flags); 499} 500 501ssize_t ki_send(int fd, const void* buf, size_t len, int flags) { 502 ON_NOSYS_RETURN(-1); 503 return s_state.kp->send(fd, buf, len, flags); 504} 505 506ssize_t ki_sendto(int fd, const void* buf, size_t len, int flags, 507 const struct sockaddr* addr, socklen_t addrlen) { 508 ON_NOSYS_RETURN(-1); 509 return s_state.kp->sendto(fd, buf, len, flags, addr, addrlen); 510} 511 512ssize_t ki_sendmsg(int fd, const struct msghdr* msg, int flags) { 513 ON_NOSYS_RETURN(-1); 514 return s_state.kp->sendmsg(fd, msg, flags); 515} 516 517int ki_setsockopt(int fd, int lvl, int optname, const void* optval, 518 socklen_t len) { 519 ON_NOSYS_RETURN(-1); 520 return s_state.kp->setsockopt(fd, lvl, optname, optval, len); 521} 522 523int ki_shutdown(int fd, int how) { 524 ON_NOSYS_RETURN(-1); 525 return s_state.kp->shutdown(fd, how); 526} 527 528int ki_socket(int domain, int type, int protocol) { 529 ON_NOSYS_RETURN(-1); 530 return s_state.kp->socket(domain, type, protocol); 531} 532 533int ki_socketpair(int domain, int type, int protocol, int* sv) { 534 ON_NOSYS_RETURN(-1); 535 return s_state.kp->socketpair(domain, type, protocol, sv); 536} 537#endif // PROVIDES_SOCKET_API 538