| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (c) 2011 The Native Client 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 <string.h> | |
| 8 | |
| 9 #include "native_client/src/include/portability.h" | |
| 10 #include "native_client/src/include/portability_string.h" | |
| 11 | |
| 12 #include "native_client/src/trusted/service_runtime/name_service/name_service.h" | |
| 13 | |
| 14 #include "native_client/src/public/name_service.h" | |
| 15 | |
| 16 #include "native_client/src/shared/platform/nacl_log.h" | |
| 17 #include "native_client/src/shared/platform/nacl_sync.h" | |
| 18 #include "native_client/src/shared/platform/nacl_sync_checked.h" | |
| 19 | |
| 20 #include "native_client/src/shared/srpc/nacl_srpc.h" | |
| 21 | |
| 22 #include "native_client/src/trusted/desc/nacl_desc_base.h" | |
| 23 #include "native_client/src/trusted/desc/nacl_desc_conn_cap.h" | |
| 24 #include "native_client/src/trusted/desc/nacl_desc_invalid.h" | |
| 25 #include "native_client/src/trusted/desc/nrd_xfer.h" | |
| 26 | |
| 27 #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h" | |
| 28 #include "native_client/src/trusted/service_runtime/sel_ldr.h" | |
| 29 | |
| 30 #include "native_client/src/trusted/simple_service/nacl_simple_service.h" | |
| 31 #include "native_client/src/trusted/simple_service/nacl_simple_ltd_service.h" | |
| 32 #include "native_client/src/trusted/threading/nacl_thread_interface.h" | |
| 33 | |
| 34 | |
| 35 /* | |
| 36 * Name service is a linear linked list. We could use a hash | |
| 37 * container eventually, but performance is not a goal for this simple | |
| 38 * bootstrap name service. Static entry and factory-based generation | |
| 39 * are mutually exclusive; the |factory| function is used iff |entry| | |
| 40 * is NULL. Client code is expected to cache lookup results. | |
| 41 */ | |
| 42 struct NaClNameServiceEntry { | |
| 43 struct NaClNameServiceEntry *next; | |
| 44 char const *name; | |
| 45 int mode; | |
| 46 struct NaClDesc *entry; /* static entry, or, ... */ | |
| 47 | |
| 48 NaClNameServiceFactoryFn_t factory; | |
| 49 void *state; | |
| 50 }; | |
| 51 | |
| 52 struct NaClSrpcHandlerDesc const kNaClNameServiceHandlers[]; | |
| 53 /* fwd */ | |
| 54 | |
| 55 int NaClNameServiceCtor(struct NaClNameService *self, | |
| 56 NaClThreadIfFactoryFunction thread_factory_fn, | |
| 57 void *thread_factory_data) { | |
| 58 int retval = 0; /* fail */ | |
| 59 | |
| 60 NaClLog(4, "Entered NaClNameServiceCtor\n"); | |
| 61 if (!NaClSimpleLtdServiceCtor(&self->base, | |
| 62 kNaClNameServiceHandlers, | |
| 63 NACL_NAME_SERVICE_CONNECTION_MAX, | |
| 64 thread_factory_fn, | |
| 65 thread_factory_data)) { | |
| 66 NaClLog(4, "NaClSimpleLtdServiceCtor failed\n"); | |
| 67 goto done; | |
| 68 } | |
| 69 if (!NaClMutexCtor(&self->mu)) { | |
| 70 NaClLog(4, "NaClMutexCtor failed\n"); | |
| 71 goto abort_mu; | |
| 72 } | |
| 73 NACL_VTBL(NaClRefCount, self) = (struct NaClRefCountVtbl *) | |
| 74 &kNaClNameServiceVtbl; | |
| 75 /* success return path */ | |
| 76 self->head = (struct NaClNameServiceEntry *) NULL; | |
| 77 retval = 1; | |
| 78 goto done; | |
| 79 | |
| 80 /* cleanup unwind */ | |
| 81 abort_mu: /* mutex ctor failed */ | |
| 82 (*NACL_VTBL(NaClRefCount, self)->Dtor)((struct NaClRefCount *) self); | |
| 83 done: | |
| 84 return retval; | |
| 85 } | |
| 86 | |
| 87 void NaClNameServiceDtor(struct NaClRefCount *vself) { | |
| 88 struct NaClNameService *self = (struct NaClNameService *) vself; | |
| 89 | |
| 90 struct NaClNameServiceEntry *p; | |
| 91 struct NaClNameServiceEntry *next; | |
| 92 | |
| 93 for (p = self->head; NULL != p; p = next) { | |
| 94 next = p->next; | |
| 95 if (NULL != p->entry) { | |
| 96 NaClRefCountUnref((struct NaClRefCount *) p->entry); | |
| 97 } else { | |
| 98 /* | |
| 99 * Tell the factory fn that this particular use can be GC'd. | |
| 100 */ | |
| 101 (void) (*p->factory)(p->state, p->name, 0, (struct NaClDesc **) NULL); | |
| 102 } | |
| 103 free(p); | |
| 104 } | |
| 105 NaClMutexDtor(&self->mu); | |
| 106 NACL_VTBL(NaClRefCount, self) = (struct NaClRefCountVtbl *) | |
| 107 &kNaClSimpleLtdServiceVtbl; | |
| 108 (*NACL_VTBL(NaClRefCount, self)->Dtor)((struct NaClRefCount *) self); | |
| 109 } | |
| 110 | |
| 111 static struct NaClNameServiceEntry **NameServiceSearch( | |
| 112 struct NaClNameServiceEntry **hd, | |
| 113 char const *name) { | |
| 114 while (NULL != *hd && 0 != strcmp((*hd)->name, name)) { | |
| 115 hd = &(*hd)->next; | |
| 116 } | |
| 117 return hd; | |
| 118 } | |
| 119 | |
| 120 | |
| 121 int NaClNameServiceCreateDescEntry( | |
| 122 struct NaClNameService *nnsp, | |
| 123 char const *name, | |
| 124 int mode, | |
| 125 struct NaClDesc *new_desc) { | |
| 126 int retval = NACL_NAME_SERVICE_INSUFFICIENT_RESOURCES; | |
| 127 struct NaClNameServiceEntry *name_entry = NULL; | |
| 128 struct NaClNameServiceEntry *found = NULL; | |
| 129 char *dup_name = STRDUP(name); | |
| 130 | |
| 131 NaClLog(3, | |
| 132 "NaClNameServiceCreateDescEntry: entering %s, %d (0x%x)\n", | |
| 133 name, | |
| 134 mode, mode); | |
| 135 /* | |
| 136 * common case is insertion success, so we pre-allocate memory | |
| 137 * (strdup, malloc) to avoid doing memory allocations while holding | |
| 138 * the name service lock. | |
| 139 */ | |
| 140 if (NULL == dup_name) { | |
| 141 goto dup_failed; | |
| 142 } | |
| 143 name_entry = (struct NaClNameServiceEntry *) malloc(sizeof *name_entry); | |
| 144 if (NULL == name_entry) { | |
| 145 goto entry_alloc_failed; | |
| 146 } | |
| 147 | |
| 148 NaClXMutexLock(&nnsp->mu); | |
| 149 found = *NameServiceSearch(&nnsp->head, name); | |
| 150 if (NULL != found) { | |
| 151 retval = NACL_NAME_SERVICE_DUPLICATE_NAME; | |
| 152 goto unlock_and_cleanup; | |
| 153 } | |
| 154 name_entry->next = nnsp->head; | |
| 155 name_entry->name = dup_name; | |
| 156 dup_name = (char *) NULL; | |
| 157 name_entry->mode = mode; | |
| 158 name_entry->entry = new_desc; | |
| 159 name_entry->factory = (NaClNameServiceFactoryFn_t) NULL; | |
| 160 name_entry->state = (void *) NULL; | |
| 161 nnsp->head = name_entry; | |
| 162 name_entry = NULL; | |
| 163 retval = NACL_NAME_SERVICE_SUCCESS; | |
| 164 | |
| 165 unlock_and_cleanup: | |
| 166 NaClXMutexUnlock(&nnsp->mu); | |
| 167 free(name_entry); | |
| 168 entry_alloc_failed: | |
| 169 free(dup_name); | |
| 170 dup_failed: | |
| 171 return retval; | |
| 172 } | |
| 173 | |
| 174 int NaClNameServiceCreateFactoryEntry( | |
| 175 struct NaClNameService *nnsp, | |
| 176 char const *name, | |
| 177 NaClNameServiceFactoryFn_t factory_fn, | |
| 178 void *factory_state) { | |
| 179 int retval = NACL_NAME_SERVICE_INSUFFICIENT_RESOURCES; | |
| 180 struct NaClNameServiceEntry *name_entry = NULL; | |
| 181 struct NaClNameServiceEntry *found = NULL; | |
| 182 char *dup_name = STRDUP(name); | |
| 183 | |
| 184 NaClLog(3, | |
| 185 ("NaClNameServiceCreateFactoryEntry: entering %s," | |
| 186 " 0x%"NACL_PRIxPTR", 0x%"NACL_PRIxPTR"\n"), | |
| 187 name, | |
| 188 (uintptr_t) factory_fn, | |
| 189 (uintptr_t) factory_state); | |
| 190 /* | |
| 191 * common case is insertion success, so we pre-allocate memory | |
| 192 * (strdup, malloc) to avoid doing memory allocation while holding | |
| 193 * the name service lock. | |
| 194 */ | |
| 195 if (NULL == dup_name) { | |
| 196 goto dup_failed; | |
| 197 } | |
| 198 name_entry = (struct NaClNameServiceEntry *) malloc(sizeof *name_entry); | |
| 199 if (NULL == name_entry) { | |
| 200 goto entry_alloc_failed; | |
| 201 } | |
| 202 | |
| 203 NaClXMutexLock(&nnsp->mu); | |
| 204 found = *NameServiceSearch(&nnsp->head, name); | |
| 205 if (NULL != found) { | |
| 206 retval = NACL_NAME_SERVICE_DUPLICATE_NAME; | |
| 207 goto unlock_and_cleanup; | |
| 208 } | |
| 209 name_entry->next = nnsp->head; | |
| 210 name_entry->name = dup_name; | |
| 211 dup_name = (char *) NULL; | |
| 212 name_entry->entry = (struct NaClDesc *) NULL; | |
| 213 name_entry->factory = factory_fn; | |
| 214 name_entry->state = factory_state; | |
| 215 nnsp->head = name_entry; | |
| 216 name_entry = NULL; | |
| 217 retval = NACL_NAME_SERVICE_SUCCESS; | |
| 218 | |
| 219 unlock_and_cleanup: | |
| 220 NaClXMutexUnlock(&nnsp->mu); | |
| 221 free(name_entry); | |
| 222 entry_alloc_failed: | |
| 223 free(dup_name); | |
| 224 dup_failed: | |
| 225 return retval; | |
| 226 } | |
| 227 | |
| 228 int NaClNameServiceResolveName(struct NaClNameService *nnsp, | |
| 229 char const *name, | |
| 230 int flags, | |
| 231 struct NaClDesc **out) { | |
| 232 struct NaClNameServiceEntry *nnsep; | |
| 233 int status = NACL_NAME_SERVICE_NAME_NOT_FOUND; | |
| 234 | |
| 235 NaClLog(3, | |
| 236 "NaClNameServiceResolveName: looking up %s, flags %d (0x%x)\n", | |
| 237 name, | |
| 238 flags, flags); | |
| 239 if (0 != (flags & ~NACL_ABI_O_ACCMODE)) { | |
| 240 NaClLog(2, "NaClNameServiceResolveName: bad flags!\n"); | |
| 241 status = NACL_NAME_SERVICE_PERMISSION_DENIED; | |
| 242 goto quit; | |
| 243 } | |
| 244 | |
| 245 NaClXMutexLock(&nnsp->mu); | |
| 246 nnsep = *NameServiceSearch(&nnsp->head, name); | |
| 247 if (NULL != nnsep) { | |
| 248 if (NULL != nnsep->entry) { | |
| 249 NaClLog(3, | |
| 250 "NaClNameServiceResolveName: found %s, mode %d (0x%x)\n", | |
| 251 name, | |
| 252 nnsep->mode, nnsep->mode); | |
| 253 /* check flags against nnsep->mode */ | |
| 254 NaClLog(4, | |
| 255 ("NaClNameServiceResolveName: checking mode/flags" | |
| 256 " compatibility\n")); | |
| 257 switch (flags) { | |
| 258 case NACL_ABI_O_RDONLY: | |
| 259 if (NACL_ABI_O_WRONLY == nnsep->mode) { | |
| 260 status = NACL_NAME_SERVICE_PERMISSION_DENIED; | |
| 261 NaClLog(4, | |
| 262 "NaClNameServiceResolveName: incompatible," | |
| 263 " not readable\n"); | |
| 264 goto unlock_and_quit; | |
| 265 } | |
| 266 break; | |
| 267 case NACL_ABI_O_WRONLY: | |
| 268 if (NACL_ABI_O_RDONLY == nnsep->mode) { | |
| 269 status = NACL_NAME_SERVICE_PERMISSION_DENIED; | |
| 270 NaClLog(4, | |
| 271 "NaClNameServiceResolveName: incompatible," | |
| 272 " not writeable\n"); | |
| 273 goto unlock_and_quit; | |
| 274 } | |
| 275 break; | |
| 276 case NACL_ABI_O_RDWR: | |
| 277 if (NACL_ABI_O_RDWR != nnsep->mode) { | |
| 278 status = NACL_NAME_SERVICE_PERMISSION_DENIED; | |
| 279 NaClLog(4, "NaClNameServiceResolveName: incompatible," | |
| 280 " not for both read and write\n"); | |
| 281 goto unlock_and_quit; | |
| 282 } | |
| 283 break; | |
| 284 default: | |
| 285 status = NACL_NAME_SERVICE_INVALID_ARGUMENT; | |
| 286 NaClLog(4, "NaClNameServiceResolveName: invalid flag\n"); | |
| 287 goto unlock_and_quit; | |
| 288 } | |
| 289 NaClLog(4, "NaClNameServiceResolveName: mode and flags are compatible\n"); | |
| 290 *out = NaClDescRef(nnsep->entry); | |
| 291 status = NACL_NAME_SERVICE_SUCCESS; | |
| 292 } else { | |
| 293 status = (*nnsep->factory)(nnsep->state, name, flags, out); | |
| 294 } | |
| 295 } | |
| 296 unlock_and_quit: | |
| 297 nnsep = NULL; | |
| 298 NaClXMutexUnlock(&nnsp->mu); | |
| 299 quit: | |
| 300 return status; | |
| 301 } | |
| 302 | |
| 303 int NaClNameServiceDeleteName(struct NaClNameService *nnsp, | |
| 304 char const *name) { | |
| 305 struct NaClNameServiceEntry **nnsepp; | |
| 306 struct NaClNameServiceEntry *to_free = NULL; | |
| 307 int status = NACL_NAME_SERVICE_NAME_NOT_FOUND; | |
| 308 | |
| 309 NaClXMutexLock(&nnsp->mu); | |
| 310 nnsepp = NameServiceSearch(&nnsp->head, name); | |
| 311 if (NULL != *nnsepp) { | |
| 312 to_free = *nnsepp; | |
| 313 *nnsepp = to_free->next; | |
| 314 status = NACL_NAME_SERVICE_SUCCESS; | |
| 315 } | |
| 316 NaClXMutexUnlock(&nnsp->mu); | |
| 317 | |
| 318 /* do the free operations w/o holding the lock */ | |
| 319 if (NULL != to_free) { | |
| 320 NaClDescSafeUnref(to_free->entry); | |
| 321 if (NULL != to_free->factory) { | |
| 322 (void) (*to_free->factory)(to_free->state, | |
| 323 to_free->name, | |
| 324 0, | |
| 325 (struct NaClDesc **) NULL); | |
| 326 } | |
| 327 free((void *) to_free->name); | |
| 328 free(to_free); | |
| 329 } | |
| 330 return status; | |
| 331 } | |
| 332 | |
| 333 static void NaClNameServiceNameInsertRpc( | |
| 334 struct NaClSrpcRpc *rpc, | |
| 335 struct NaClSrpcArg **in_args, | |
| 336 struct NaClSrpcArg **out_args, | |
| 337 struct NaClSrpcClosure *done_cls) { | |
| 338 struct NaClNameService *nnsp = | |
| 339 (struct NaClNameService *) rpc->channel->server_instance_data; | |
| 340 char *name = in_args[0]->arrays.str; | |
| 341 int mode = in_args[1]->u.ival; | |
| 342 struct NaClDesc *desc = in_args[2]->u.hval; | |
| 343 | |
| 344 NaClLog(3, | |
| 345 "NaClNameServiceNameInsertRpc: inserting %s, %d (0x%x)\n", | |
| 346 name, | |
| 347 mode, mode); | |
| 348 out_args[0]->u.ival = (*NACL_VTBL(NaClNameService, nnsp)->CreateDescEntry)( | |
| 349 nnsp, name, mode, desc); | |
| 350 rpc->result = NACL_SRPC_RESULT_OK; | |
| 351 (*done_cls->Run)(done_cls); | |
| 352 } | |
| 353 | |
| 354 static void NaClNameServiceNameLookupOldRpc( | |
| 355 struct NaClSrpcRpc *rpc, | |
| 356 struct NaClSrpcArg **in_args, | |
| 357 struct NaClSrpcArg **out_args, | |
| 358 struct NaClSrpcClosure *done_cls) { | |
| 359 struct NaClNameService *nnsp = | |
| 360 (struct NaClNameService *) rpc->channel->server_instance_data; | |
| 361 char *name = in_args[0]->arrays.str; | |
| 362 int status; | |
| 363 struct NaClDesc *desc; | |
| 364 | |
| 365 NaClLog(LOG_WARNING, | |
| 366 "NaClNameServiceNameLookupOldRpc: DEPRECATED interface used.\n"); | |
| 367 NaClLog(3, "NaClNameServiceNameLookupOldRpc: looking up %s\n", name); | |
| 368 status = (*NACL_VTBL(NaClNameService, nnsp)->ResolveName)( | |
| 369 nnsp, name, NACL_ABI_O_RDONLY, &desc); | |
| 370 out_args[0]->u.ival = status; | |
| 371 out_args[1]->u.hval = (NACL_NAME_SERVICE_SUCCESS == status) | |
| 372 ? desc | |
| 373 : (struct NaClDesc *) NaClDescInvalidMake(); | |
| 374 rpc->result = NACL_SRPC_RESULT_OK; | |
| 375 (*done_cls->Run)(done_cls); | |
| 376 } | |
| 377 | |
| 378 static void NaClNameServiceNameLookupRpc( | |
| 379 struct NaClSrpcRpc *rpc, | |
| 380 struct NaClSrpcArg **in_args, | |
| 381 struct NaClSrpcArg **out_args, | |
| 382 struct NaClSrpcClosure *done_cls) { | |
| 383 struct NaClNameService *nnsp = | |
| 384 (struct NaClNameService *) rpc->channel->server_instance_data; | |
| 385 char *name = in_args[0]->arrays.str; | |
| 386 int flags = in_args[1]->u.ival; | |
| 387 int status; | |
| 388 struct NaClDesc *desc; | |
| 389 | |
| 390 NaClLog(3, "NaClNameServiceNameLookupRpc: looking up %s\n", name); | |
| 391 NaClLog(3, "NaClNameServiceNameLookupRpc: flags %d (0x%x)\n", flags, flags); | |
| 392 status = (*NACL_VTBL(NaClNameService, nnsp)->ResolveName)( | |
| 393 nnsp, name, flags, &desc); | |
| 394 out_args[0]->u.ival = status; | |
| 395 out_args[1]->u.hval = (NACL_NAME_SERVICE_SUCCESS == status) | |
| 396 ? desc | |
| 397 : (struct NaClDesc *) NaClDescInvalidMake(); | |
| 398 NaClLog(3, "NaClNameServiceNameLookupRpc: status %d\n", status); | |
| 399 NaClLog(3, "NaClNameServiceNameLookupRpc: desc 0x%"NACL_PRIxPTR"\n", | |
| 400 (uintptr_t) desc); | |
| 401 rpc->result = NACL_SRPC_RESULT_OK; | |
| 402 (*done_cls->Run)(done_cls); | |
| 403 } | |
| 404 | |
| 405 static void NaClNameServiceNameDeleteRpc( | |
| 406 struct NaClSrpcRpc *rpc, | |
| 407 struct NaClSrpcArg **in_args, | |
| 408 struct NaClSrpcArg **out_args, | |
| 409 struct NaClSrpcClosure *done_cls) { | |
| 410 struct NaClNameService *nnsp = | |
| 411 (struct NaClNameService *) rpc->channel->server_instance_data; | |
| 412 char *name = in_args[0]->arrays.str; | |
| 413 | |
| 414 out_args[0]->u.ival = (*NACL_VTBL(NaClNameService, nnsp)->DeleteName)( | |
| 415 nnsp, name); | |
| 416 rpc->result = NACL_SRPC_RESULT_OK; | |
| 417 (*done_cls->Run)(done_cls); | |
| 418 } | |
| 419 | |
| 420 struct NaClSrpcHandlerDesc const kNaClNameServiceHandlers[] = { | |
| 421 { NACL_NAME_SERVICE_INSERT, NaClNameServiceNameInsertRpc, }, | |
| 422 { NACL_NAME_SERVICE_LOOKUP_DEPRECATED, NaClNameServiceNameLookupOldRpc, }, | |
| 423 { NACL_NAME_SERVICE_LOOKUP, NaClNameServiceNameLookupRpc, }, | |
| 424 { NACL_NAME_SERVICE_DELETE, NaClNameServiceNameDeleteRpc, }, | |
| 425 { (char const *) NULL, (NaClSrpcMethod) NULL, }, | |
| 426 }; | |
| 427 | |
| 428 void NaClNameServiceLaunch(struct NaClNameService *self) { | |
| 429 | |
| 430 NaClLog(4, "NaClNameServiceThread: starting service\n"); | |
| 431 NaClSimpleServiceStartServiceThread((struct NaClSimpleService *) self); | |
| 432 } | |
| 433 | |
| 434 struct NaClNameServiceVtbl kNaClNameServiceVtbl = { | |
| 435 { | |
| 436 /* really NaClSimpleLtdServiceVtbl contents */ | |
| 437 { | |
| 438 NaClNameServiceDtor, | |
| 439 }, | |
| 440 NaClSimpleServiceConnectionFactory, | |
| 441 /* | |
| 442 * To implement name service ownership, the ConnectionFactory will | |
| 443 * need to build a subclass of a NaClSimpleServiceConnection where | |
| 444 * the connection can be marked as an owner, and the NameService | |
| 445 * would contain a mutex protected flag specifying whether it is | |
| 446 * owned that blocks mutations by all but the owning connection. | |
| 447 * The Connection object's Dtor can release ownership. | |
| 448 */ | |
| 449 NaClSimpleLtdServiceAcceptConnection, | |
| 450 NaClSimpleServiceAcceptAndSpawnHandler, | |
| 451 NaClSimpleLtdServiceRpcHandler, | |
| 452 }, | |
| 453 NaClNameServiceCreateDescEntry, | |
| 454 NaClNameServiceCreateFactoryEntry, | |
| 455 NaClNameServiceResolveName, | |
| 456 NaClNameServiceDeleteName, | |
| 457 }; | |
| OLD | NEW |