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