blob: e73326e0602c0c6f8c92a65408a4d85a06456581 [file] [log] [blame]
/*
* Copyright (c) 2012 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.
*/
#include "ppapi/native_client/src/untrusted/pnacl_irt_shim/shim_ppapi.h"
#include <string.h>
#include "native_client/src/include/nacl_macros.h"
#include "native_client/src/untrusted/irt/irt.h"
#include "native_client/src/untrusted/irt/irt_ppapi.h"
#include "ppapi/generators/pnacl_shim.h"
#include "ppapi/native_client/src/shared/ppapi_proxy/ppruntime.h"
/*
* This is a whitelist of NaCl IRT interfaces that are exposed under
* PNaCl. This list omits the following:
*
* * The old versions of "irt-memory", v0.1 and v0.2, which contain
* the deprecated sysbrk() function. See:
* https://code.google.com/p/nativeclient/issues/detail?id=3542
*
* * "irt-mutex", "irt-cond" and "irt-sem", which are deprecated and
* are superseded by the "irt-futex" interface. See:
* https://code.google.com/p/nativeclient/issues/detail?id=3484
*
* * "irt-dyncode", which is not supported under PNaCl because
* dynamically loading architecture-specific native code is not
* portable.
*
* * "irt-exception-handling", which is not supported under PNaCl
* because it exposes non-portable, architecture-specific register
* state. See:
* https://code.google.com/p/nativeclient/issues/detail?id=3444
*
* * "irt-blockhook", which is deprecated. It was provided for
* implementing thread suspension for conservative garbage
* collection, but this is probably not a portable use case under
* PNaCl, so this interface is disabled under PNaCl. See:
* https://code.google.com/p/nativeclient/issues/detail?id=3539
*
* * "irt-resource-open". This was primarily provided for use by
* nacl-glibc's dynamic linker, which is not supported under PNaCl.
* open_resource() returns a file descriptor, but it is the only
* interface in NaCl to do so inside Chromium. This is
* inconsistent with PPAPI, which does not expose file descriptors
* (except in private/dev interfaces). See:
* https://code.google.com/p/nativeclient/issues/detail?id=3574
*
* * "irt-fdio" and "irt-filename". Under PNaCl, where
* open_resource() open is disallowed, these are only useful for
* debugging. They are only allowed via the "dev" query strings;
* the non-"dev" query strings are disallowed.
*
* We omit these because they are only "dev" interfaces:
*
* * "irt-dev-getpid"
* * "irt-dev-list-mappings"
*/
static const char *const irt_interface_whitelist[] = {
NACL_IRT_BASIC_v0_1,
NACL_IRT_MEMORY_v0_3,
NACL_IRT_THREAD_v0_1,
NACL_IRT_FUTEX_v0_1,
NACL_IRT_TLS_v0_1,
NACL_IRT_PPAPIHOOK_v0_1,
NACL_IRT_RANDOM_v0_1,
NACL_IRT_CLOCK_v0_1,
/* Allowed for debugging purposes: */
NACL_IRT_DEV_FDIO_v0_1,
NACL_IRT_DEV_FILENAME_v0_2,
};
/* Use local strcmp to avoid dependency on libc. */
static int mystrcmp(const char* s1, const char *s2) {
while((*s1 && *s2) && (*s1++ == *s2++));
return *(--s1) - *(--s2);
}
static int is_irt_interface_whitelisted(const char *interface_name) {
int i;
for (i = 0; i < NACL_ARRAY_SIZE(irt_interface_whitelist); i++) {
if (mystrcmp(interface_name, irt_interface_whitelist[i]) == 0) {
return 1;
}
}
return 0;
}
TYPE_nacl_irt_query __pnacl_real_irt_interface;
/*
* These remember the interface pointers the user registers by calling the
* IRT entry point.
*/
static struct PP_StartFunctions user_start_functions;
static int32_t wrap_PPPInitializeModule(PP_Module module_id,
PPB_GetInterface get_browser_intf) {
__set_real_Pnacl_PPBGetInterface(get_browser_intf);
/*
* Calls from user code to the PPB interfaces pass through here and may
* require shims to convert the ABI.
*/
return (*user_start_functions.PPP_InitializeModule)(module_id,
&__Pnacl_PPBGetInterface);
}
static void wrap_PPPShutdownModule() {
(*user_start_functions.PPP_ShutdownModule)();
}
static const struct PP_StartFunctions wrapped_ppapi_methods = {
wrap_PPPInitializeModule,
wrap_PPPShutdownModule,
/*
* Calls from the IRT to the user plugin pass through here and may require
* shims to convert the ABI.
*/
__Pnacl_PPPGetInterface
};
static struct nacl_irt_ppapihook real_irt_ppapi_hook;
static int wrap_ppapi_start(const struct PP_StartFunctions *funcs) {
/*
* Save the user's real bindings for the start functions.
*/
user_start_functions = *funcs;
__set_real_Pnacl_PPPGetInterface(user_start_functions.PPP_GetInterface);
/*
* Invoke the IRT's ppapi_start interface with the wrapped interface.
*/
return (*real_irt_ppapi_hook.ppapi_start)(&wrapped_ppapi_methods);
}
size_t __pnacl_irt_interface_wrapper(const char *interface_ident,
void *table, size_t tablesize) {
if (!is_irt_interface_whitelisted(interface_ident))
return 0;
/*
* Note there is a benign race in initializing the wrapper.
* We build the "hook" structure by copying from the IRT's hook and then
* writing our wrapper for the ppapi method. Two threads may end up
* attempting to do this simultaneously, which should not be a problem,
* as they are writing the same values.
*/
if (0 != mystrcmp(interface_ident, NACL_IRT_PPAPIHOOK_v0_1)) {
/*
* The interface is not wrapped, so use the real interface.
*/
return (*__pnacl_real_irt_interface)(interface_ident, table, tablesize);
}
if ((*__pnacl_real_irt_interface)(NACL_IRT_PPAPIHOOK_v0_1,
&real_irt_ppapi_hook,
sizeof real_irt_ppapi_hook) !=
sizeof real_irt_ppapi_hook) {
return 0;
}
/*
* Copy the interface structure into the client.
*/
struct nacl_irt_ppapihook *dest = table;
if (sizeof *dest <= tablesize) {
dest->ppapi_start = wrap_ppapi_start;
dest->ppapi_register_thread_creator =
real_irt_ppapi_hook.ppapi_register_thread_creator;
return sizeof *dest;
}
return 0;
}