| 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 |