Home | History | Annotate | Download | only in pnacl_irt_shim
      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