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