2 * Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
7 #include "ppapi/native_client/src/untrusted/pnacl_irt_shim/shim_ppapi.h"
10 #include "native_client/src/include/nacl_macros.h"
11 #include "native_client/src/untrusted/irt/irt.h"
12 #include "native_client/src/untrusted/irt/irt_dev.h"
13 #include "ppapi/generators/pnacl_shim.h"
14 #include "ppapi/nacl_irt/irt_ppapi.h"
15 #include "ppapi/native_client/src/shared/ppapi_proxy/ppruntime.h"
19 * This is a whitelist of NaCl IRT interfaces that are exposed under
20 * PNaCl. This list omits the following:
22 * * The old versions of "irt-memory", v0.1 and v0.2, which contain
23 * the deprecated sysbrk() function. See:
24 * https://code.google.com/p/nativeclient/issues/detail?id=3542
26 * * "irt-mutex", "irt-cond" and "irt-sem", which are deprecated and
27 * are superseded by the "irt-futex" interface. See:
28 * https://code.google.com/p/nativeclient/issues/detail?id=3484
30 * * "irt-dyncode", which is not supported under PNaCl because
31 * dynamically loading architecture-specific native code is not
34 * * "irt-exception-handling", which is not supported under PNaCl
35 * because it exposes non-portable, architecture-specific register
37 * https://code.google.com/p/nativeclient/issues/detail?id=3444
39 * * "irt-blockhook", which is deprecated. It was provided for
40 * implementing thread suspension for conservative garbage
41 * collection, but this is probably not a portable use case under
42 * PNaCl, so this interface is disabled under PNaCl. See:
43 * https://code.google.com/p/nativeclient/issues/detail?id=3539
45 * * "irt-resource-open". This was primarily provided for use by
46 * nacl-glibc's dynamic linker, which is not supported under PNaCl.
47 * open_resource() returns a file descriptor, but it is the only
48 * interface in NaCl to do so inside Chromium. This is
49 * inconsistent with PPAPI, which does not expose file descriptors
50 * (except in private/dev interfaces). See:
51 * https://code.google.com/p/nativeclient/issues/detail?id=3574
53 * * "irt-fdio" and "irt-filename". Under PNaCl, where
54 * open_resource() open is disallowed, these are only useful for
55 * debugging. They are only allowed via the "dev" query strings;
56 * the non-"dev" query strings are disallowed.
58 * We omit these because they are only "dev" interfaces:
61 * * "irt-dev-list-mappings"
63 static const char *const irt_interface_whitelist[] = {
69 NACL_IRT_PPAPIHOOK_v0_1,
72 /* Allowed for debugging purposes: */
73 NACL_IRT_DEV_FDIO_v0_1,
74 NACL_IRT_DEV_FILENAME_v0_2,
77 /* Use local strcmp to avoid dependency on libc. */
78 static int mystrcmp(const char* s1, const char *s2) {
79 while((*s1 && *s2) && (*s1++ == *s2++));
80 return *(--s1) - *(--s2);
83 static int is_irt_interface_whitelisted(const char *interface_name) {
85 for (i = 0; i < NACL_ARRAY_SIZE(irt_interface_whitelist); i++) {
86 if (mystrcmp(interface_name, irt_interface_whitelist[i]) == 0) {
93 TYPE_nacl_irt_query __pnacl_real_irt_interface = NULL;
96 * These remember the interface pointers the user registers by calling the
99 static struct PP_StartFunctions user_start_functions;
101 static int32_t wrap_PPPInitializeModule(PP_Module module_id,
102 PPB_GetInterface get_browser_intf) {
103 __set_real_Pnacl_PPBGetInterface(get_browser_intf);
105 * Calls from user code to the PPB interfaces pass through here and may
106 * require shims to convert the ABI.
108 return (*user_start_functions.PPP_InitializeModule)(module_id,
109 &__Pnacl_PPBGetInterface);
112 static void wrap_PPPShutdownModule() {
113 (*user_start_functions.PPP_ShutdownModule)();
116 static const struct PP_StartFunctions wrapped_ppapi_methods = {
117 wrap_PPPInitializeModule,
118 wrap_PPPShutdownModule,
120 * Calls from the IRT to the user plugin pass through here and may require
121 * shims to convert the ABI.
123 __Pnacl_PPPGetInterface
126 static struct nacl_irt_ppapihook real_irt_ppapi_hook;
128 static int wrap_ppapi_start(const struct PP_StartFunctions *funcs) {
130 * Save the user's real bindings for the start functions.
132 user_start_functions = *funcs;
133 __set_real_Pnacl_PPPGetInterface(user_start_functions.PPP_GetInterface);
136 * Invoke the IRT's ppapi_start interface with the wrapped interface.
138 return (*real_irt_ppapi_hook.ppapi_start)(&wrapped_ppapi_methods);
141 size_t __pnacl_irt_interface_wrapper(const char *interface_ident,
142 void *table, size_t tablesize) {
143 if (!is_irt_interface_whitelisted(interface_ident))
147 * Note there is a benign race in initializing the wrapper.
148 * We build the "hook" structure by copying from the IRT's hook and then
149 * writing our wrapper for the ppapi method. Two threads may end up
150 * attempting to do this simultaneously, which should not be a problem,
151 * as they are writing the same values.
153 if (0 != mystrcmp(interface_ident, NACL_IRT_PPAPIHOOK_v0_1)) {
155 * The interface is not wrapped, so use the real interface.
157 return (*__pnacl_real_irt_interface)(interface_ident, table, tablesize);
159 if ((*__pnacl_real_irt_interface)(NACL_IRT_PPAPIHOOK_v0_1,
160 &real_irt_ppapi_hook,
161 sizeof real_irt_ppapi_hook) !=
162 sizeof real_irt_ppapi_hook) {
166 * Copy the interface structure into the client.
168 struct nacl_irt_ppapihook *dest = table;
169 if (sizeof *dest <= tablesize) {
170 dest->ppapi_start = wrap_ppapi_start;
171 dest->ppapi_register_thread_creator =
172 real_irt_ppapi_hook.ppapi_register_thread_creator;