1 /* 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. 5 */ 6 7 #include "ppapi/native_client/src/untrusted/pnacl_irt_shim/shim_ppapi.h" 8 9 #include <string.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_ppapi.h" 13 #include "ppapi/generators/pnacl_shim.h" 14 #include "ppapi/native_client/src/shared/ppapi_proxy/ppruntime.h" 15 16 17 /* 18 * This is a whitelist of NaCl IRT interfaces that are exposed under 19 * PNaCl. This list omits the following: 20 * 21 * * The old versions of "irt-memory", v0.1 and v0.2, which contain 22 * the deprecated sysbrk() function. See: 23 * https://code.google.com/p/nativeclient/issues/detail?id=3542 24 * 25 * * "irt-mutex", "irt-cond" and "irt-sem", which are deprecated and 26 * are superseded by the "irt-futex" interface. See: 27 * https://code.google.com/p/nativeclient/issues/detail?id=3484 28 * 29 * * "irt-dyncode", which is not supported under PNaCl because 30 * dynamically loading architecture-specific native code is not 31 * portable. 32 * 33 * * "irt-exception-handling", which is not supported under PNaCl 34 * because it exposes non-portable, architecture-specific register 35 * state. See: 36 * https://code.google.com/p/nativeclient/issues/detail?id=3444 37 * 38 * * "irt-blockhook", which is deprecated. It was provided for 39 * implementing thread suspension for conservative garbage 40 * collection, but this is probably not a portable use case under 41 * PNaCl, so this interface is disabled under PNaCl. See: 42 * https://code.google.com/p/nativeclient/issues/detail?id=3539 43 * 44 * * "irt-resource-open". This was primarily provided for use by 45 * nacl-glibc's dynamic linker, which is not supported under PNaCl. 46 * open_resource() returns a file descriptor, but it is the only 47 * interface in NaCl to do so inside Chromium. This is 48 * inconsistent with PPAPI, which does not expose file descriptors 49 * (except in private/dev interfaces). See: 50 * https://code.google.com/p/nativeclient/issues/detail?id=3574 51 * 52 * * "irt-fdio" and "irt-filename". Under PNaCl, where 53 * open_resource() open is disallowed, these are only useful for 54 * debugging. They are only allowed via the "dev" query strings; 55 * the non-"dev" query strings are disallowed. 56 * 57 * We omit these because they are only "dev" interfaces: 58 * 59 * * "irt-dev-getpid" 60 * * "irt-dev-list-mappings" 61 */ 62 static const char *const irt_interface_whitelist[] = { 63 NACL_IRT_BASIC_v0_1, 64 NACL_IRT_MEMORY_v0_3, 65 NACL_IRT_THREAD_v0_1, 66 NACL_IRT_FUTEX_v0_1, 67 NACL_IRT_TLS_v0_1, 68 NACL_IRT_PPAPIHOOK_v0_1, 69 NACL_IRT_RANDOM_v0_1, 70 NACL_IRT_CLOCK_v0_1, 71 /* Allowed for debugging purposes: */ 72 NACL_IRT_DEV_FDIO_v0_1, 73 NACL_IRT_DEV_FILENAME_v0_2, 74 }; 75 76 /* Use local strcmp to avoid dependency on libc. */ 77 static int mystrcmp(const char* s1, const char *s2) { 78 while((*s1 && *s2) && (*s1++ == *s2++)); 79 return *(--s1) - *(--s2); 80 } 81 82 static int is_irt_interface_whitelisted(const char *interface_name) { 83 int i; 84 for (i = 0; i < NACL_ARRAY_SIZE(irt_interface_whitelist); i++) { 85 if (mystrcmp(interface_name, irt_interface_whitelist[i]) == 0) { 86 return 1; 87 } 88 } 89 return 0; 90 } 91 92 TYPE_nacl_irt_query __pnacl_real_irt_interface; 93 94 /* 95 * These remember the interface pointers the user registers by calling the 96 * IRT entry point. 97 */ 98 static struct PP_StartFunctions user_start_functions; 99 100 static int32_t wrap_PPPInitializeModule(PP_Module module_id, 101 PPB_GetInterface get_browser_intf) { 102 __set_real_Pnacl_PPBGetInterface(get_browser_intf); 103 /* 104 * Calls from user code to the PPB interfaces pass through here and may 105 * require shims to convert the ABI. 106 */ 107 return (*user_start_functions.PPP_InitializeModule)(module_id, 108 &__Pnacl_PPBGetInterface); 109 } 110 111 static void wrap_PPPShutdownModule() { 112 (*user_start_functions.PPP_ShutdownModule)(); 113 } 114 115 static const struct PP_StartFunctions wrapped_ppapi_methods = { 116 wrap_PPPInitializeModule, 117 wrap_PPPShutdownModule, 118 /* 119 * Calls from the IRT to the user plugin pass through here and may require 120 * shims to convert the ABI. 121 */ 122 __Pnacl_PPPGetInterface 123 }; 124 125 static struct nacl_irt_ppapihook real_irt_ppapi_hook; 126 127 static int wrap_ppapi_start(const struct PP_StartFunctions *funcs) { 128 /* 129 * Save the user's real bindings for the start functions. 130 */ 131 user_start_functions = *funcs; 132 __set_real_Pnacl_PPPGetInterface(user_start_functions.PPP_GetInterface); 133 134 /* 135 * Invoke the IRT's ppapi_start interface with the wrapped interface. 136 */ 137 return (*real_irt_ppapi_hook.ppapi_start)(&wrapped_ppapi_methods); 138 } 139 140 size_t __pnacl_irt_interface_wrapper(const char *interface_ident, 141 void *table, size_t tablesize) { 142 if (!is_irt_interface_whitelisted(interface_ident)) 143 return 0; 144 145 /* 146 * Note there is a benign race in initializing the wrapper. 147 * We build the "hook" structure by copying from the IRT's hook and then 148 * writing our wrapper for the ppapi method. Two threads may end up 149 * attempting to do this simultaneously, which should not be a problem, 150 * as they are writing the same values. 151 */ 152 if (0 != mystrcmp(interface_ident, NACL_IRT_PPAPIHOOK_v0_1)) { 153 /* 154 * The interface is not wrapped, so use the real interface. 155 */ 156 return (*__pnacl_real_irt_interface)(interface_ident, table, tablesize); 157 } 158 if ((*__pnacl_real_irt_interface)(NACL_IRT_PPAPIHOOK_v0_1, 159 &real_irt_ppapi_hook, 160 sizeof real_irt_ppapi_hook) != 161 sizeof real_irt_ppapi_hook) { 162 return 0; 163 } 164 /* 165 * Copy the interface structure into the client. 166 */ 167 struct nacl_irt_ppapihook *dest = table; 168 if (sizeof *dest <= tablesize) { 169 dest->ppapi_start = wrap_ppapi_start; 170 dest->ppapi_register_thread_creator = 171 real_irt_ppapi_hook.ppapi_register_thread_creator; 172 return sizeof *dest; 173 } 174 return 0; 175 } 176