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