OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2008 The Native Client Authors. All rights reserved. | |
3 * Use of this source code is governed by a BSD-style license that can | |
4 * be found in the LICENSE file. | |
5 */ | |
6 | |
7 | |
8 #include <errno.h> | |
9 #include <signal.h> | |
10 #include <string.h> | |
11 | |
12 #include "native_client/src/include/checked_cast.h" | |
13 #include "native_client/src/include/nacl_platform.h" | |
14 | |
15 #include "native_client/src/shared/platform/nacl_host_desc.h" | |
16 #include "native_client/src/shared/imc/nacl_imc.h" | |
17 | |
18 #include "native_client/src/trusted/plugin/srpc/plugin.h" | |
19 #include "native_client/src/trusted/plugin/srpc/shared_memory.h" | |
20 #include "native_client/src/trusted/plugin/srpc/utility.h" | |
21 | |
22 #include "native_client/src/trusted/service_runtime/include/bits/mman.h" | |
23 #include "native_client/src/trusted/service_runtime/include/sys/stat.h" | |
24 #include "native_client/src/trusted/service_runtime/internal_errno.h" | |
25 #include "native_client/src/trusted/service_runtime/sel_util.h" | |
26 | |
27 | |
28 namespace { | |
29 | |
30 bool RpcRead(void* obj, plugin::SrpcParams* params) { | |
31 plugin::SharedMemory* shared_memory = | |
32 reinterpret_cast<plugin::SharedMemory*>(obj); | |
33 uint32_t offset; | |
34 uint32_t len; | |
35 | |
36 // TODO(gregoryd) - the old code was able to handle both ints and doubles | |
37 // it should be handled in the marshalling code, | |
38 // otherwise the call will be rejected | |
39 if (params->ins()[0]->tag == NACL_SRPC_ARG_TYPE_DOUBLE) { | |
40 offset = static_cast<uint32_t>(params->ins()[0]->u.dval); | |
41 } else { | |
42 offset = static_cast<uint32_t>(params->ins()[0]->u.ival); | |
43 } | |
44 | |
45 if (params->ins()[1]->tag == NACL_SRPC_ARG_TYPE_DOUBLE) { | |
46 len = static_cast<uint32_t>(params->ins()[1]->u.dval); | |
47 } else { | |
48 len = static_cast<uint32_t>(params->ins()[1]->u.ival); | |
49 } | |
50 | |
51 // Ensure we will access valid addresses. | |
52 if (NULL == shared_memory->shm_addr()) { | |
53 params->set_exception_string("Shared memory not mapped"); | |
54 return false; | |
55 } | |
56 if (offset + len < offset) { | |
57 params->set_exception_string("Offset + length overflows"); | |
58 return false; | |
59 } | |
60 if (offset + len > shared_memory->shm_size()) { | |
61 params->set_exception_string( | |
62 "Offset + length overlaps end of shared memory"); | |
63 return false; | |
64 } | |
65 | |
66 // TODO(mseaborn): Change this function to use ByteStringAsUTF8(). | |
67 // UTF-8 encoding may result in a 2x size increase at the most. | |
68 // TODO(sehr): should we do a pre-scan to get the real size? | |
69 uint32_t utf8_buffer_len = 2 * len; | |
70 if ((utf8_buffer_len < len) || | |
71 (utf8_buffer_len + 1 < utf8_buffer_len)) { | |
72 // Unsigned overflow. | |
73 params->set_exception_string("len too large to hold requested UTF8 chars"); | |
74 return false; | |
75 } | |
76 | |
77 char* ret_string = reinterpret_cast<char*>(malloc(utf8_buffer_len + 1)); | |
78 if (NULL == ret_string) { | |
79 params->set_exception_string("out of memory"); | |
80 return false; | |
81 } | |
82 | |
83 unsigned char* shm_addr = | |
84 reinterpret_cast<unsigned char*>(shared_memory->shm_addr()) + offset; | |
85 unsigned char* out = reinterpret_cast<unsigned char*>(ret_string); | |
86 // NPAPI wants length to be the number of bytes, not UTF-8 characters. | |
87 for (unsigned int i = 0; i < len; ++i) { | |
88 unsigned char c = *shm_addr; | |
89 if (c < 128) { | |
90 // Code results in a one byte encoding | |
91 *out = c; | |
92 ++out; | |
93 } else { | |
94 // Code results in a two byte encoding | |
95 out[0] = 0xc0 | (c >> 6); | |
96 out[1] = 0x80 | (c & 0x3f); | |
97 out += 2; | |
98 } | |
99 ++shm_addr; | |
100 } | |
101 // Terminate the result string with 0. | |
102 *out = 0; | |
103 | |
104 params->outs()[0]->tag = NACL_SRPC_ARG_TYPE_STRING; | |
105 params->outs()[0]->u.sval = ret_string; | |
106 | |
107 return true; | |
108 } | |
109 | |
110 bool RpcWrite(void* obj, plugin::SrpcParams* params) { | |
111 plugin::SharedMemory* shared_memory = | |
112 reinterpret_cast<plugin::SharedMemory*>(obj); | |
113 uint32_t offset; | |
114 uint32_t len; | |
115 | |
116 // TODO(gregoryd) - the old code was able to handle both ints and doubles | |
117 // it should be handled in the marshalling code, | |
118 // otherwise the call will be rejected | |
119 if (params->ins()[0]->tag == NACL_SRPC_ARG_TYPE_DOUBLE) { | |
120 offset = static_cast<uint32_t>(params->ins()[0]->u.dval); | |
121 } else { | |
122 offset = static_cast<uint32_t>(params->ins()[0]->u.ival); | |
123 } | |
124 | |
125 if (params->ins()[1]->tag == NACL_SRPC_ARG_TYPE_DOUBLE) { | |
126 len = static_cast<uint32_t>(params->ins()[1]->u.dval); | |
127 } else { | |
128 len = static_cast<uint32_t>(params->ins()[1]->u.ival); | |
129 } | |
130 | |
131 // Ensure we will access valid addresses. | |
132 if (NULL == shared_memory->shm_addr()) { | |
133 params->set_exception_string("Shared memory not mapped"); | |
134 return false; | |
135 } | |
136 if (offset + len < offset) { | |
137 params->set_exception_string("Offset + length overflows"); | |
138 return false; | |
139 } | |
140 if (offset + len > shared_memory->shm_size()) { | |
141 params->set_exception_string( | |
142 "Offset + length overlaps end of shared memory"); | |
143 return false; | |
144 } | |
145 | |
146 // The input is a JavaScript string, which must consist of UFT-8 | |
147 // characters with character codes between 0 and 255 inclusive. | |
148 NaClSrpcArg* str_param = params->ins()[2]; | |
149 const unsigned char* str = | |
150 reinterpret_cast<unsigned const char*>(str_param->u.sval); | |
151 uint32_t utf_bytes = nacl::saturate_cast<uint32_t>(strlen(str_param->u.sval)); | |
152 unsigned char* shm_addr = | |
153 reinterpret_cast<unsigned char*>(shared_memory->shm_addr()) + offset; | |
154 | |
155 // TODO(mseaborn): Change this function to use ByteStringFromUTF8(). | |
156 for (unsigned int i = 0; i < len;) { | |
157 unsigned char c1 = str[0]; | |
158 unsigned char c2 = 0; | |
159 | |
160 // Check that we are still pointing into the JavaScript string we were | |
161 // passed. | |
162 if (i >= utf_bytes) { | |
163 return false; | |
164 } | |
165 // Process the byte in the string as UTF-8 characters. | |
166 if (c1 & 0x80) { | |
167 // str[1] will not access out of bounds because sval is a NUL-terminated | |
168 // sequence of bytes. However, NUL would fail the content test just | |
169 // below, so failing here seems a good thing anyway. | |
170 if (i == len - 1) { | |
171 return false; | |
172 } | |
173 c2 = str[1]; | |
174 // Assert two byte encoding. | |
175 // The first character must contain 110xxxxxb and the | |
176 // second must contain 10xxxxxxb. | |
177 if (((c1 & 0xc3) != c1) || ((c2 & 0xbf) != c2)) { | |
178 params->set_exception_string("Bad utf8 character value"); | |
179 return false; | |
180 } | |
181 *shm_addr = (c1 << 6) | (c2 & 0x3f); | |
182 str += 2; | |
183 i += 2; | |
184 } else { | |
185 // One-byte encoding. | |
186 *shm_addr = c1; | |
187 ++str; | |
188 ++i; | |
189 } | |
190 ++shm_addr; | |
191 } | |
192 return true; | |
193 } | |
194 | |
195 } // namespace | |
196 | |
197 namespace plugin { | |
198 | |
199 void SharedMemory::LoadMethods() { | |
200 AddMethodCall(RpcRead, "read", "ii", "s"); | |
201 AddMethodCall(RpcWrite, "write", "iis", ""); | |
202 } | |
203 | |
204 bool SharedMemory::Init(Plugin* plugin, | |
205 nacl::DescWrapper* wrapper, | |
206 off_t length) { | |
207 bool allocated_memory = false; | |
208 | |
209 if (NULL == wrapper) { | |
210 // Creating a new object by size | |
211 size_t size = static_cast<size_t>(length); | |
212 // The Map virtual function rounds up to the nearest AllocPage. | |
213 size_t rounded_size = NaClRoundAllocPage(size); | |
214 wrapper = plugin->wrapper_factory()->MakeShm(rounded_size); | |
215 if (NULL == wrapper) { | |
216 return false; | |
217 } | |
218 | |
219 PLUGIN_PRINTF(("SharedMemory::Init(%p, 0x%08x)\n", | |
220 static_cast<void*>(plugin), | |
221 static_cast<unsigned>(length))); | |
222 // Now allocate the object through the canonical factory and return. | |
223 allocated_memory = true; | |
224 } | |
225 | |
226 if (!DescBasedHandle::Init(plugin, wrapper)) { | |
227 if (allocated_memory) { | |
228 wrapper->Delete(); | |
229 } | |
230 return false; | |
231 } | |
232 | |
233 if (0 > wrapper->Map(&addr_, &size_)) { | |
234 // BUG: we are leaking the shared memory object here. | |
235 return false; | |
236 } | |
237 | |
238 LoadMethods(); | |
239 return true; | |
240 } | |
241 | |
242 SharedMemory* SharedMemory::New(Plugin* plugin, nacl::DescWrapper* wrapper) { | |
243 PLUGIN_PRINTF(("SharedMemory::New()\n")); | |
244 | |
245 SharedMemory* shared_memory = new(std::nothrow) SharedMemory(); | |
246 if (shared_memory == NULL || !shared_memory->Init(plugin, wrapper, 0)) { | |
247 return NULL; | |
248 } | |
249 return shared_memory; | |
250 } | |
251 | |
252 SharedMemory* SharedMemory::New(Plugin* plugin, off_t length) { | |
253 PLUGIN_PRINTF(("SharedMemory::New()\n")); | |
254 | |
255 SharedMemory* shared_memory = new(std::nothrow) SharedMemory(); | |
256 if (shared_memory == NULL || !shared_memory->Init(plugin, NULL, length)) { | |
257 return NULL; | |
258 } | |
259 return shared_memory; | |
260 } | |
261 | |
262 SharedMemory::SharedMemory() : handle_(0), | |
263 addr_(NULL), | |
264 size_(0) { | |
265 PLUGIN_PRINTF(("SharedMemory::SharedMemory(%p)\n", | |
266 static_cast<void*>(this))); | |
267 } | |
268 | |
269 SharedMemory::~SharedMemory() { | |
270 PLUGIN_PRINTF(("SharedMemory::~SharedMemory(%p)\n", | |
271 static_cast<void*>(this))); | |
272 | |
273 // Invalidates are called by Firefox in abitrary order. Hence, the plugin | |
274 // could have been freed/trashed before we get invalidated. Therefore, we | |
275 // cannot use the effp_ member of the plugin object. | |
276 // TODO(sehr): fix the resulting address space leak. | |
277 // Free the memory that was mapped to the descriptor. | |
278 // shared_memory->desc_->vtbl->Unmap(shared_memory->desc_, | |
279 // shared_memory->plugin_->effp_, | |
280 // shared_memory->addr_, | |
281 // shared_memory->size_); | |
282 // After invalidation, the browser does not respect reference counting, | |
283 // so we shut down here what we can and prevent attempts to shut down | |
284 // other linked structures in Deallocate. | |
285 | |
286 // Free the memory that was mapped to the descriptor. | |
287 // if (desc() && plugin_) { | |
288 // desc()->vtbl->Unmap(desc(), | |
289 // plugin_->effp_, | |
290 // addr_, | |
291 // size_); | |
292 // } | |
293 // TODO(sehr): is there a missing delete desc() here? | |
294 // TODO(gregoryd): in addition, should we unref the descriptor if it was | |
295 // constructed during the initialization of this object? | |
296 } | |
297 | |
298 } // namespace plugin | |
OLD | NEW |