0

Added support for NaCl IO to use the IRT Extension API.

In order to better integrate the IRT Extension API into NaCl IO, the
first implementation mirrors the other kernel_wrap_* files. All the
unit tests should therefore still be valid. Eventually it may be
easier to just have a separate version of kernel_intercept which
utilizes the IRT extension API directly.

Currently the IRT Extension interface is only supported within newlib,
so I have enabled it for newlib only.

BUG= https://code.google.com/p/nativeclient/issues/detail?id=3918
TEST= trybots

Review URL: https://codereview.chromium.org/608913003

Cr-Commit-Position: refs/heads/master@{#299938}
This commit is contained in:
dyen
2014-10-16 11:31:40 -07:00
committed by Commit bot
parent 6bd0638f54
commit 3183230ac5
7 changed files with 515 additions and 8 deletions

@@ -242,6 +242,7 @@ NACL_HEADER_MAP = {
('native_client/src/include/nacl/nacl_minidump.h', 'nacl/'),
('native_client/src/untrusted/irt/irt.h', ''),
('native_client/src/untrusted/irt/irt_dev.h', ''),
('native_client/src/untrusted/irt/irt_extension.h', ''),
('native_client/src/untrusted/nacl/nacl_dyncode.h', 'nacl/'),
('native_client/src/untrusted/nacl/nacl_startup.h', 'nacl/'),
('native_client/src/untrusted/pthread/pthread.h', ''),

@@ -13,11 +13,17 @@
#include <sys/ioctl.h>
#include <sys/types.h>
#include "nacl_io/ossignal.h"
#include "nacl_io/ossocket.h"
#include "nacl_io/ostypes.h"
#include "nacl_io/osutime.h"
#include "sdk_util/macros.h"
// Curently enable NaCl IO IRT Extension when using newlib
#if defined(__native_client__) && defined(_NEWLIB_VERSION)
# define NACL_IO_IRT_EXT 1
#endif
#if defined(__GLIBC__)
#include <sys/cdefs.h>
#define NOTHROW __THROW

@@ -4,10 +4,14 @@
#include <sys/types.h> // Include something that will define __BIONIC__.
#include "nacl_io/kernel_wrap.h" // IRT_EXT is turned on in this header.
// The entire file is wrapped in this #if. We do this so this .cc file can be
// compiled, even on a non-bionic build.
#if defined(__native_client__) && defined(__BIONIC__)
#if !defined(NACL_IO_IRT_EXT) && defined(__native_client__) && \
defined(__BIONIC__)
#include <alloca.h>
#include <assert.h>
#include <dirent.h>
@@ -18,7 +22,6 @@
#include <sys/time.h>
#include "nacl_io/kernel_intercept.h"
#include "nacl_io/kernel_wrap.h"
#include "nacl_io/kernel_wrap_real.h"
#include "nacl_io/osmman.h"

@@ -3,12 +3,12 @@
// found in the LICENSE file.
#include <sys/types.h> // Include something that will define __GLIBC__.
#include "nacl_io/kernel_wrap.h" // IRT_EXT is turned on in this header.
// The entire file is wrapped in this #if. We do this so this .cc file can be
// compiled, even on a non-glibc build.
#if defined(__native_client__) && defined(__GLIBC__)
#include "nacl_io/kernel_wrap.h"
#if !defined(NACL_IO_IRT_EXT) && defined(__native_client__) && \
defined(__GLIBC__)
#include <alloca.h>
#include <assert.h>

@@ -0,0 +1,496 @@
/* 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

@@ -3,12 +3,12 @@
// found in the LICENSE file.
#include <sys/types.h> // Include something that will define __GLIBC__.
#include "nacl_io/kernel_wrap.h" // IRT_EXT is turned on in this header.
// The entire file is wrapped in this #if. We do this so this .cc file can be
// compiled, even on a non-newlib build.
#if defined(__native_client__) && !defined(__GLIBC__) && !defined(__BIONIC__)
#include "nacl_io/kernel_wrap.h"
#if !defined(NACL_IO_IRT_EXT) && defined(__native_client__) && \
!defined(__GLIBC__) && !defined(__BIONIC__)
#include <dirent.h>
#include <errno.h>

@@ -40,6 +40,7 @@
"kernel_wrap_bionic.cc",
"kernel_wrap_dummy.cc",
"kernel_wrap_glibc.cc",
"kernel_wrap_irt_ext.c",
"kernel_wrap_newlib.cc",
"kernel_wrap_win.cc",
"log.c",