| /* Copyright 2014 The Chromium Authors. All rights reserved. |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. */ |
| |
| /* NACL_IO_IRT_EXT is defined in this header */ |
| #include "nacl_io/kernel_wrap.h" |
| |
| /* |
| * The entire file is wrapped in this #if. We do this so this .c file can |
| * always be compiled. |
| */ |
| #if defined(NACL_IO_IRT_EXT) |
| |
| #include <assert.h> |
| #include <errno.h> |
| #include <irt.h> |
| #include <irt_dev.h> |
| #include <irt_extension.h> |
| #include <stdbool.h> |
| #include <string.h> |
| #include <sys/mman.h> |
| |
| #include "nacl_io/kernel_intercept.h" |
| #include "nacl_io/log.h" |
| |
| /* |
| * The following macros are used to interfact with IRT interfaces. |
| */ |
| /* This macro defines an interfact structure, use as a regular type. */ |
| #define NACL_IRT_INTERFACE(interface_type) \ |
| struct nacl_io_##interface_type { \ |
| const char *query_string; \ |
| bool queried; \ |
| bool initialized; \ |
| struct interface_type interface; \ |
| } |
| |
| /* This macro unconditionally initializes an interface (do not use directly). */ |
| #define INIT_INTERFACE_BARE(interface_struct) \ |
| if (!interface_struct.queried) { \ |
| const size_t bytes __attribute__((unused)) = \ |
| nacl_interface_query(interface_struct.query_string, \ |
| &interface_struct.interface, \ |
| sizeof(interface_struct.interface)); \ |
| interface_struct.queried = true; \ |
| interface_struct.initialized = \ |
| (bytes == sizeof(interface_struct.interface)); \ |
| } |
| |
| /* This macro initializes an interface and does not handle errors. */ |
| #define INIT_INTERFACE(interface_struct) \ |
| do { \ |
| INIT_INTERFACE_BARE(interface_struct); \ |
| } while (false) |
| |
| /* This macro initializes an interface and returns ENOSYS on failure. */ |
| #define INIT_INTERFACE_ENOSYS(interface_struct) \ |
| do { \ |
| INIT_INTERFACE_BARE(interface_struct); \ |
| if (!interface_struct.initialized) \ |
| return ENOSYS; \ |
| } while (false) |
| |
| /* This macro initializes an interface and asserts on failure. */ |
| #define INIT_INTERFACE_ASSERT(interface_struct) \ |
| do { \ |
| INIT_INTERFACE_BARE(interface_struct); \ |
| assert(interface_struct.initialized); \ |
| } while (false) |
| |
| /* This macro supplies an IRT Extension interface and asserts on failure. */ |
| #define EXT_SUPPLY_INTERFACE_ASSERT(interface_struct, supplied_struct) \ |
| do { \ |
| const size_t bytes __attribute__((unused)) = \ |
| nacl_interface_ext_supply(interface_struct.query_string, \ |
| &supplied_struct, \ |
| sizeof(supplied_struct)); \ |
| assert(bytes == sizeof(supplied_struct)); \ |
| } while (false) |
| |
| /* |
| * IRT interfaces as declared in irt.h. |
| */ |
| static NACL_IRT_INTERFACE(nacl_irt_basic) s_irt_basic = { |
| NACL_IRT_BASIC_v0_1, |
| }; |
| |
| static NACL_IRT_INTERFACE(nacl_irt_fdio) s_irt_fdio = { |
| NACL_IRT_FDIO_v0_1, |
| }; |
| |
| static NACL_IRT_INTERFACE(nacl_irt_memory) s_irt_memory = { |
| NACL_IRT_MEMORY_v0_3, |
| }; |
| |
| static NACL_IRT_INTERFACE(nacl_irt_resource_open) s_irt_resource_open = { |
| NACL_IRT_RESOURCE_OPEN_v0_1, |
| }; |
| |
| /* |
| * IRT Dev interfaces as declared in irt_dev.h. |
| */ |
| static NACL_IRT_INTERFACE(nacl_irt_dev_fdio) s_irt_dev_fdio = { |
| NACL_IRT_DEV_FDIO_v0_3, |
| }; |
| |
| static NACL_IRT_INTERFACE(nacl_irt_dev_filename) s_irt_dev_filename = { |
| NACL_IRT_DEV_FILENAME_v0_3, |
| }; |
| |
| static bool s_wrapped = false; |
| |
| /* |
| * Functions for the nacl_irt_dev_fdio interface. |
| */ |
| static int ext_close(int fd) { |
| ERRNO_RTN(ki_close(fd)); |
| } |
| |
| static int ext_dup(int fd, int *newfd) { |
| *newfd = ki_dup(fd); |
| ERRNO_RTN(*newfd); |
| } |
| |
| static int ext_dup2(int fd, int newfd) { |
| newfd = ki_dup2(fd, newfd); |
| ERRNO_RTN(newfd); |
| } |
| |
| static int ext_read(int fd, void *buf, size_t count, size_t *nread) { |
| ssize_t signed_nread = ki_read(fd, buf, count); |
| *nread = (size_t) signed_nread; |
| ERRNO_RTN(signed_nread); |
| } |
| |
| static int ext_write(int fd, const void *buf, size_t count, size_t *nwrote) { |
| ssize_t signed_nwrote = ki_write(fd, buf, count); |
| *nwrote = (size_t) signed_nwrote; |
| ERRNO_RTN(signed_nwrote); |
| } |
| |
| static int ext_seek(int fd, nacl_irt_off_t offset, int whence, |
| nacl_irt_off_t *new_offset) { |
| *new_offset = ki_lseek(fd, offset, whence); |
| ERRNO_RTN(*new_offset); |
| } |
| |
| static int ext_fstat(int fd, struct stat *buf) { |
| ERRNO_RTN(ki_fstat(fd, buf)); |
| } |
| |
| static int ext_getdents(int fd, struct dirent *ents, size_t count, |
| size_t *nread) { |
| int rtn = ki_getdents(fd, ents, count); |
| RTN_ERRNO_IF(rtn < 0); |
| *nread = rtn; |
| return 0; |
| } |
| |
| /* |
| * Functions for the nacl_irt_memory interface. |
| */ |
| static int ext_mmap(void **addr, size_t len, int prot, int flags, int fd, |
| nacl_irt_off_t off) { |
| if (flags & MAP_ANONYMOUS) |
| return s_irt_memory.interface.mmap(addr, len, prot, flags, fd, off); |
| |
| *addr = ki_mmap(*addr, len, prot, flags, fd, off); |
| RTN_ERRNO_IF(*addr == (void*)-1); |
| return 0; |
| } |
| |
| static int ext_munmap(void *addr, size_t length) { |
| /* |
| * Always let the real munmap run on the address range. It is not an error if |
| * there are no mapped pages in that range. |
| */ |
| ki_munmap(addr, length); |
| return s_irt_memory.interface.munmap(addr, length); |
| } |
| |
| /* |
| * Extra functions for the nacl_irt_dev_fdio interface. |
| */ |
| static int ext_fchdir(int fd) { |
| ERRNO_RTN(ki_fchdir(fd)); |
| } |
| |
| static int ext_fchmod(int fd, mode_t mode) { |
| ERRNO_RTN(ki_fchmod(fd, mode)); |
| } |
| |
| static int ext_fsync(int fd) { |
| ERRNO_RTN(ki_fsync(fd)); |
| } |
| |
| static int ext_fdatasync(int fd) { |
| ERRNO_RTN(ki_fdatasync(fd)); |
| } |
| |
| static int ext_ftruncate(int fd, nacl_irt_off_t length) { |
| ERRNO_RTN(ki_ftruncate(fd, length)); |
| } |
| |
| static int ext_isatty(int fd, int *result) { |
| *result = ki_isatty(fd); |
| RTN_ERRNO_IF(*result == 0); |
| return 0; |
| } |
| |
| /* |
| * Functions for the nacl_irt_dev_filename interface. |
| */ |
| static int ext_open(const char *pathname, int oflag, mode_t cmode, int *newfd) { |
| *newfd = ki_open(pathname, oflag, cmode); |
| ERRNO_RTN(*newfd); |
| } |
| |
| static int ext_stat(const char *pathname, struct stat *buf) { |
| ERRNO_RTN(ki_stat(pathname, buf)); |
| } |
| |
| static int ext_mkdir(const char *pathname, mode_t mode) { |
| ERRNO_RTN(ki_mkdir(pathname, mode)); |
| } |
| |
| static int ext_rmdir(const char *pathname) { |
| ERRNO_RTN(ki_rmdir(pathname)); |
| } |
| |
| static int ext_chdir(const char *pathname) { |
| ERRNO_RTN(ki_chdir(pathname)); |
| } |
| |
| static int ext_getcwd(char *pathname, size_t len) { |
| char *rtn = ki_getcwd(pathname, len); |
| RTN_ERRNO_IF(NULL == rtn); |
| return 0; |
| } |
| |
| static int ext_unlink(const char *pathname) { |
| ERRNO_RTN(ki_unlink(pathname)); |
| } |
| |
| static int ext_truncate(const char *pathname, nacl_irt_off_t length) { |
| ERRNO_RTN(ki_truncate(pathname, length)); |
| } |
| |
| static int ext_lstat(const char *pathname, struct stat *buf) { |
| ERRNO_RTN(ki_lstat(pathname, buf)); |
| } |
| |
| static int ext_link(const char *pathname, const char *newpath) { |
| ERRNO_RTN(ki_link(pathname, newpath)); |
| } |
| |
| static int ext_rename(const char *pathname, const char *newpath) { |
| ERRNO_RTN(ki_rename(pathname, newpath)); |
| } |
| |
| static int ext_symlink(const char *pathname, const char *newpath) { |
| ERRNO_RTN(ki_symlink(pathname, newpath)); |
| } |
| |
| static int ext_chmod(const char *pathname, mode_t mode) { |
| ERRNO_RTN(ki_chmod(pathname, mode)); |
| } |
| |
| static int ext_access(const char *pathname, int amode) { |
| ERRNO_RTN(ki_access(pathname, amode)); |
| } |
| |
| static int ext_readlink(const char *pathname, char *buf, size_t count, |
| size_t *nread) { |
| int rtn = ki_readlink(pathname, buf, count); |
| RTN_ERRNO_IF(rtn < 0); |
| *nread = rtn; |
| return 0; |
| } |
| |
| static int ext_utimes(const char *pathname, const struct timeval *times) { |
| ERRNO_RTN(ki_utimes(pathname, times)); |
| } |
| |
| /* |
| * Functions declared inside of kernel_wrap_real.h. |
| */ |
| |
| int _real_close(int fd) { |
| INIT_INTERFACE_ENOSYS(s_irt_fdio); |
| return s_irt_fdio.interface.close(fd); |
| } |
| |
| void _real_exit(int status) { |
| INIT_INTERFACE_ASSERT(s_irt_basic); |
| return s_irt_basic.interface.exit(status); |
| } |
| |
| int _real_fstat(int fd, struct stat *buf) { |
| INIT_INTERFACE_ENOSYS(s_irt_fdio); |
| return s_irt_fdio.interface.fstat(fd, buf); |
| } |
| |
| int _real_getdents(int fd, void *nacl_buf, size_t nacl_count, size_t *nread) { |
| INIT_INTERFACE_ENOSYS(s_irt_fdio); |
| return s_irt_fdio.interface.getdents(fd, (struct dirent *) nacl_buf, |
| nacl_count, nread); |
| } |
| |
| int _real_isatty(int fd, int *result) { |
| INIT_INTERFACE_ENOSYS(s_irt_dev_fdio); |
| return s_irt_dev_fdio.interface.isatty(fd, result); |
| } |
| |
| int _real_lseek(int fd, int64_t offset, int whence, int64_t *new_offset) { |
| INIT_INTERFACE_ENOSYS(s_irt_fdio); |
| return s_irt_fdio.interface.seek(fd, offset, whence, new_offset); |
| } |
| |
| int _real_mkdir(const char *pathname, mode_t mode) { |
| INIT_INTERFACE_ENOSYS(s_irt_dev_filename); |
| return s_irt_dev_filename.interface.mkdir(pathname, mode); |
| } |
| |
| int _real_mmap(void **addr, |
| size_t length, |
| int prot, |
| int flags, |
| int fd, |
| int64_t offset) { |
| INIT_INTERFACE_ENOSYS(s_irt_memory); |
| return s_irt_memory.interface.mmap(addr, length, prot, flags, fd, offset); |
| } |
| |
| int _real_munmap(void *addr, size_t length) { |
| INIT_INTERFACE_ENOSYS(s_irt_memory); |
| return s_irt_memory.interface.munmap(addr, length); |
| } |
| |
| int _real_open(const char *pathname, int oflag, mode_t mode, int *newfd) { |
| INIT_INTERFACE_ENOSYS(s_irt_dev_filename); |
| return s_irt_dev_filename.interface.open(pathname, oflag, mode, newfd); |
| } |
| |
| int _real_open_resource(const char *file, int *fd) { |
| INIT_INTERFACE_ENOSYS(s_irt_resource_open); |
| return s_irt_resource_open.interface.open_resource(file, fd); |
| } |
| |
| int _real_read(int fd, void *buf, size_t count, size_t *nread) { |
| INIT_INTERFACE_ENOSYS(s_irt_fdio); |
| return s_irt_fdio.interface.read(fd, buf, count, nread); |
| } |
| |
| int _real_rmdir(const char *pathname) { |
| INIT_INTERFACE_ENOSYS(s_irt_dev_filename); |
| return s_irt_dev_filename.interface.rmdir(pathname); |
| } |
| |
| int _real_write(int fd, const void *buf, size_t count, size_t *nwrote) { |
| INIT_INTERFACE_ENOSYS(s_irt_fdio); |
| return s_irt_fdio.interface.write(fd, buf, count, nwrote); |
| } |
| |
| int _real_getcwd(char *pathname, size_t len) { |
| INIT_INTERFACE_ENOSYS(s_irt_dev_filename); |
| return s_irt_dev_filename.interface.getcwd(pathname, len); |
| } |
| |
| /* |
| * Kernel Wrap init/uninit functions declared in kernel_wrap.h. |
| */ |
| void kernel_wrap_init() { |
| if (!s_wrapped) { |
| LOG_TRACE("kernel_wrap_init"); |
| |
| /* |
| * Register interfaces as listed in irt.h. |
| */ |
| |
| /* Register nacl_irt_basic interface. */ |
| INIT_INTERFACE_ASSERT(s_irt_basic); |
| struct nacl_irt_basic basic_calls = { |
| ki_exit, |
| s_irt_basic.interface.gettod, |
| s_irt_basic.interface.clock, |
| s_irt_basic.interface.nanosleep, |
| s_irt_basic.interface.sched_yield, |
| s_irt_basic.interface.sysconf, |
| }; |
| EXT_SUPPLY_INTERFACE_ASSERT(s_irt_basic, basic_calls); |
| |
| /* Register nacl_irt_fdio interface. */ |
| INIT_INTERFACE(s_irt_fdio); |
| struct nacl_irt_fdio fdio = { |
| ext_close, |
| ext_dup, |
| ext_dup2, |
| ext_read, |
| ext_write, |
| ext_seek, |
| ext_fstat, |
| ext_getdents, |
| }; |
| EXT_SUPPLY_INTERFACE_ASSERT(s_irt_fdio, fdio); |
| |
| /* Register nacl_irt_memory interface. */ |
| INIT_INTERFACE_ASSERT(s_irt_memory); |
| struct nacl_irt_memory mem = { |
| ext_mmap, |
| ext_munmap, |
| s_irt_memory.interface.mprotect, |
| }; |
| EXT_SUPPLY_INTERFACE_ASSERT(s_irt_memory, mem); |
| |
| /* |
| * Register interfaces as listed in irt_dev.h. |
| */ |
| |
| /* Register nacl_irt_dev_fdio interface. */ |
| INIT_INTERFACE(s_irt_dev_fdio); |
| struct nacl_irt_dev_fdio dev_fdio = { |
| ext_close, |
| ext_dup, |
| ext_dup2, |
| ext_read, |
| ext_write, |
| ext_seek, |
| ext_fstat, |
| ext_getdents, |
| ext_fchdir, |
| ext_fchmod, |
| ext_fsync, |
| ext_fdatasync, |
| ext_ftruncate, |
| ext_isatty, |
| }; |
| EXT_SUPPLY_INTERFACE_ASSERT(s_irt_dev_fdio, dev_fdio); |
| |
| /* Register nacl_irt_dev_filename interface. */ |
| INIT_INTERFACE(s_irt_dev_filename); |
| struct nacl_irt_dev_filename dev_filename = { |
| ext_open, |
| ext_stat, |
| ext_mkdir, |
| ext_rmdir, |
| ext_chdir, |
| ext_getcwd, |
| ext_unlink, |
| ext_truncate, |
| ext_lstat, |
| ext_link, |
| ext_rename, |
| ext_symlink, |
| ext_chmod, |
| ext_access, |
| ext_readlink, |
| ext_utimes, |
| }; |
| EXT_SUPPLY_INTERFACE_ASSERT(s_irt_dev_filename, dev_filename); |
| |
| s_wrapped = true; |
| } |
| } |
| |
| void kernel_wrap_uninit() { |
| if (s_wrapped) { |
| LOG_TRACE("kernel_wrap_uninit"); |
| |
| /* Register original IRT interfaces in irt.h. */ |
| EXT_SUPPLY_INTERFACE_ASSERT(s_irt_basic, |
| s_irt_basic.interface); |
| |
| EXT_SUPPLY_INTERFACE_ASSERT(s_irt_fdio, |
| s_irt_fdio.interface); |
| |
| EXT_SUPPLY_INTERFACE_ASSERT(s_irt_memory, |
| s_irt_memory.interface); |
| |
| /* |
| * Register optional original IRT dev interfaces in irt_dev.h, these |
| * may or may not exist since they are dev interfaces. If they do not |
| * exist go ahead and supply an empty interface as that's what they |
| * were originally before we supplied any extension interfaces. |
| */ |
| EXT_SUPPLY_INTERFACE_ASSERT(s_irt_dev_fdio, |
| s_irt_dev_fdio.interface); |
| |
| EXT_SUPPLY_INTERFACE_ASSERT(s_irt_dev_filename, |
| s_irt_dev_filename.interface); |
| |
| s_wrapped = false; |
| } |
| } |
| |
| #endif |