Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / ppapi / native_client / src / untrusted / pnacl_irt_shim / shim_ppapi.c
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_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"
16
17
18 /*
19  * This is a whitelist of NaCl IRT interfaces that are exposed under
20  * PNaCl.  This list omits the following:
21  *
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
25  *
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
29  *
30  *  * "irt-dyncode", which is not supported under PNaCl because
31  *    dynamically loading architecture-specific native code is not
32  *    portable.
33  *
34  *  * "irt-exception-handling", which is not supported under PNaCl
35  *    because it exposes non-portable, architecture-specific register
36  *    state.  See:
37  *    https://code.google.com/p/nativeclient/issues/detail?id=3444
38  *
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
44  *
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
52  *
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.
57  *
58  * We omit these because they are only "dev" interfaces:
59  *
60  *  * "irt-dev-getpid"
61  *  * "irt-dev-list-mappings"
62  */
63 static const char *const irt_interface_whitelist[] = {
64   NACL_IRT_BASIC_v0_1,
65   NACL_IRT_MEMORY_v0_3,
66   NACL_IRT_THREAD_v0_1,
67   NACL_IRT_FUTEX_v0_1,
68   NACL_IRT_TLS_v0_1,
69   NACL_IRT_PPAPIHOOK_v0_1,
70   NACL_IRT_RANDOM_v0_1,
71   NACL_IRT_CLOCK_v0_1,
72   /* Allowed for debugging purposes: */
73   NACL_IRT_DEV_FDIO_v0_1,
74   NACL_IRT_DEV_FILENAME_v0_2,
75 };
76
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);
81 }
82
83 static int is_irt_interface_whitelisted(const char *interface_name) {
84   int i;
85   for (i = 0; i < NACL_ARRAY_SIZE(irt_interface_whitelist); i++) {
86     if (mystrcmp(interface_name, irt_interface_whitelist[i]) == 0) {
87       return 1;
88     }
89   }
90   return 0;
91 }
92
93 TYPE_nacl_irt_query __pnacl_real_irt_interface = NULL;
94
95 /*
96  * These remember the interface pointers the user registers by calling the
97  * IRT entry point.
98  */
99 static struct PP_StartFunctions user_start_functions;
100
101 static int32_t wrap_PPPInitializeModule(PP_Module module_id,
102                                         PPB_GetInterface get_browser_intf) {
103   __set_real_Pnacl_PPBGetInterface(get_browser_intf);
104   /*
105    * Calls from user code to the PPB interfaces pass through here and may
106    * require shims to convert the ABI.
107    */
108   return (*user_start_functions.PPP_InitializeModule)(module_id,
109                                                       &__Pnacl_PPBGetInterface);
110 }
111
112 static void wrap_PPPShutdownModule() {
113   (*user_start_functions.PPP_ShutdownModule)();
114 }
115
116 static const struct PP_StartFunctions wrapped_ppapi_methods = {
117   wrap_PPPInitializeModule,
118   wrap_PPPShutdownModule,
119   /*
120    * Calls from the IRT to the user plugin pass through here and may require
121    * shims to convert the ABI.
122    */
123   __Pnacl_PPPGetInterface
124 };
125
126 static struct nacl_irt_ppapihook real_irt_ppapi_hook;
127
128 static int wrap_ppapi_start(const struct PP_StartFunctions *funcs) {
129   /*
130    * Save the user's real bindings for the start functions.
131    */
132   user_start_functions = *funcs;
133   __set_real_Pnacl_PPPGetInterface(user_start_functions.PPP_GetInterface);
134
135   /*
136    * Invoke the IRT's ppapi_start interface with the wrapped interface.
137    */
138   return (*real_irt_ppapi_hook.ppapi_start)(&wrapped_ppapi_methods);
139 }
140
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))
144     return 0;
145
146   /*
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.
152    */
153   if (0 != mystrcmp(interface_ident, NACL_IRT_PPAPIHOOK_v0_1)) {
154     /*
155      * The interface is not wrapped, so use the real interface.
156      */
157     return (*__pnacl_real_irt_interface)(interface_ident, table, tablesize);
158   }
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) {
163     return 0;
164   }
165   /*
166    * Copy the interface structure into the client.
167    */
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;
173     return sizeof *dest;
174   }
175   return 0;
176 }