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 :
15 : #include "native_client/src/shared/platform/nacl_log.h"
16 : #include "native_client/src/shared/platform/nacl_sync.h"
17 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
18 :
19 : #include "native_client/src/shared/srpc/nacl_srpc.h"
20 :
21 : #include "native_client/src/trusted/desc/nacl_desc_base.h"
22 : #include "native_client/src/trusted/desc/nacl_desc_conn_cap.h"
23 : #include "native_client/src/trusted/desc/nacl_desc_invalid.h"
24 : #include "native_client/src/trusted/desc/nrd_xfer.h"
25 :
26 : #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
27 : #include "native_client/src/trusted/service_runtime/include/sys/nacl_name_service.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 19 : void *thread_factory_data) {
58 19 : int retval = 0; /* fail */
59 :
60 19 : NaClLog(4, "Entered NaClNameServiceCtor\n");
61 19 : if (!NaClSimpleLtdServiceCtor(&self->base,
62 : kNaClNameServiceHandlers,
63 : NACL_NAME_SERVICE_CONNECTION_MAX,
64 : thread_factory_fn,
65 : thread_factory_data)) {
66 0 : NaClLog(4, "NaClSimpleLtdServiceCtor failed\n");
67 0 : goto done;
68 : }
69 19 : if (!NaClMutexCtor(&self->mu)) {
70 0 : NaClLog(4, "NaClMutexCtor failed\n");
71 0 : goto abort_mu;
72 : }
73 19 : NACL_VTBL(NaClRefCount, self) = (struct NaClRefCountVtbl *)
74 : &kNaClNameServiceVtbl;
75 : /* success return path */
76 19 : self->head = (struct NaClNameServiceEntry *) NULL;
77 19 : retval = 1;
78 19 : goto done;
79 :
80 : /* cleanup unwind */
81 0 : abort_mu: /* mutex ctor failed */
82 0 : (*NACL_VTBL(NaClRefCount, self)->Dtor)((struct NaClRefCount *) self);
83 19 : done:
84 19 : return retval;
85 : }
86 :
87 0 : void NaClNameServiceDtor(struct NaClRefCount *vself) {
88 0 : struct NaClNameService *self = (struct NaClNameService *) vself;
89 :
90 : struct NaClNameServiceEntry *p;
91 : struct NaClNameServiceEntry *next;
92 :
93 0 : for (p = self->head; NULL != p; p = next) {
94 0 : next = p->next;
95 0 : if (NULL != p->entry) {
96 0 : NaClRefCountUnref((struct NaClRefCount *) p->entry);
97 : } else {
98 : /*
99 : * Tell the factory fn that this particular use can be GC'd.
100 : */
101 0 : (void) (*p->factory)(p->state, p->name, 0, (struct NaClDesc **) NULL);
102 : }
103 0 : free(p);
104 : }
105 0 : NaClMutexDtor(&self->mu);
106 0 : NACL_VTBL(NaClRefCount, self) = (struct NaClRefCountVtbl *)
107 : &kNaClSimpleLtdServiceVtbl;
108 0 : (*NACL_VTBL(NaClRefCount, self)->Dtor)((struct NaClRefCount *) self);
109 0 : }
110 :
111 : static struct NaClNameServiceEntry **NameServiceSearch(
112 : struct NaClNameServiceEntry **hd,
113 22 : char const *name) {
114 47 : while (NULL != *hd && 0 != strcmp((*hd)->name, name)) {
115 3 : hd = &(*hd)->next;
116 : }
117 22 : return hd;
118 : }
119 :
120 :
121 : int NaClNameServiceCreateDescEntry(
122 : struct NaClNameService *nnsp,
123 : char const *name,
124 : int mode,
125 22 : struct NaClDesc *new_desc) {
126 22 : int retval = NACL_NAME_SERVICE_INSUFFICIENT_RESOURCES;
127 22 : struct NaClNameServiceEntry *name_entry = NULL;
128 22 : struct NaClNameServiceEntry *found = NULL;
129 22 : char *dup_name = STRDUP(name);
130 :
131 22 : 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 22 : if (NULL == dup_name) {
141 0 : goto dup_failed;
142 : }
143 22 : name_entry = (struct NaClNameServiceEntry *) malloc(sizeof *name_entry);
144 22 : if (NULL == name_entry) {
145 0 : goto entry_alloc_failed;
146 : }
147 :
148 22 : NaClXMutexLock(&nnsp->mu);
149 22 : found = *NameServiceSearch(&nnsp->head, name);
150 22 : if (NULL != found) {
151 0 : retval = NACL_NAME_SERVICE_DUPLICATE_NAME;
152 0 : goto unlock_and_cleanup;
153 : }
154 22 : name_entry->next = nnsp->head;
155 22 : name_entry->name = dup_name;
156 22 : dup_name = (char *) NULL;
157 22 : name_entry->mode = mode;
158 22 : name_entry->entry = new_desc;
159 22 : name_entry->factory = (NaClNameServiceFactoryFn_t) NULL;
160 22 : name_entry->state = (void *) NULL;
161 22 : nnsp->head = name_entry;
162 22 : name_entry = NULL;
163 22 : retval = NACL_NAME_SERVICE_SUCCESS;
164 :
165 22 : unlock_and_cleanup:
166 22 : NaClXMutexUnlock(&nnsp->mu);
167 22 : free(name_entry);
168 22 : entry_alloc_failed:
169 22 : free(dup_name);
170 22 : dup_failed:
171 22 : return retval;
172 : }
173 :
174 : int NaClNameServiceCreateFactoryEntry(
175 : struct NaClNameService *nnsp,
176 : char const *name,
177 : NaClNameServiceFactoryFn_t factory_fn,
178 0 : void *factory_state) {
179 0 : int retval = NACL_NAME_SERVICE_INSUFFICIENT_RESOURCES;
180 0 : struct NaClNameServiceEntry *name_entry = NULL;
181 0 : struct NaClNameServiceEntry *found = NULL;
182 0 : char *dup_name = STRDUP(name);
183 :
184 0 : 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 0 : if (NULL == dup_name) {
196 0 : goto dup_failed;
197 : }
198 0 : name_entry = (struct NaClNameServiceEntry *) malloc(sizeof *name_entry);
199 0 : if (NULL == name_entry) {
200 0 : goto entry_alloc_failed;
201 : }
202 :
203 0 : NaClXMutexLock(&nnsp->mu);
204 0 : found = *NameServiceSearch(&nnsp->head, name);
205 0 : if (NULL != found) {
206 0 : retval = NACL_NAME_SERVICE_DUPLICATE_NAME;
207 0 : goto unlock_and_cleanup;
208 : }
209 0 : name_entry->next = nnsp->head;
210 0 : name_entry->name = dup_name;
211 0 : dup_name = (char *) NULL;
212 0 : name_entry->entry = (struct NaClDesc *) NULL;
213 0 : name_entry->factory = factory_fn;
214 0 : name_entry->state = factory_state;
215 0 : nnsp->head = name_entry;
216 0 : name_entry = NULL;
217 0 : retval = NACL_NAME_SERVICE_SUCCESS;
218 :
219 0 : unlock_and_cleanup:
220 0 : NaClXMutexUnlock(&nnsp->mu);
221 0 : free(name_entry);
222 0 : entry_alloc_failed:
223 0 : free(dup_name);
224 0 : dup_failed:
225 0 : return retval;
226 : }
227 :
228 : int NaClNameServiceResolveName(struct NaClNameService *nnsp,
229 : char const *name,
230 : int flags,
231 0 : struct NaClDesc **out) {
232 : struct NaClNameServiceEntry *nnsep;
233 0 : int status = NACL_NAME_SERVICE_NAME_NOT_FOUND;
234 :
235 0 : NaClLog(3,
236 : "NaClNameServiceResolveName: looking up %s, flags %d (0x%x)\n",
237 : name,
238 : flags, flags);
239 0 : if (0 != (flags & ~NACL_ABI_O_ACCMODE)) {
240 0 : NaClLog(2, "NaClNameServiceResolveName: bad flags!\n");
241 0 : status = NACL_NAME_SERVICE_PERMISSION_DENIED;
242 0 : goto quit;
243 : }
244 :
245 0 : NaClXMutexLock(&nnsp->mu);
246 0 : nnsep = *NameServiceSearch(&nnsp->head, name);
247 0 : if (NULL != nnsep) {
248 0 : if (NULL != nnsep->entry) {
249 0 : 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 0 : NaClLog(4,
255 : ("NaClNameServiceResolveName: checking mode/flags"
256 : " compatibility\n"));
257 0 : switch (flags) {
258 : case NACL_ABI_O_RDONLY:
259 0 : if (NACL_ABI_O_WRONLY == nnsep->mode) {
260 0 : status = NACL_NAME_SERVICE_PERMISSION_DENIED;
261 0 : NaClLog(4,
262 : "NaClNameServiceResolveName: incompatible,"
263 : " not readable\n");
264 0 : goto unlock_and_quit;
265 : }
266 0 : break;
267 : case NACL_ABI_O_WRONLY:
268 0 : if (NACL_ABI_O_RDONLY == nnsep->mode) {
269 0 : status = NACL_NAME_SERVICE_PERMISSION_DENIED;
270 0 : NaClLog(4,
271 : "NaClNameServiceResolveName: incompatible,"
272 : " not writeable\n");
273 0 : goto unlock_and_quit;
274 : }
275 0 : break;
276 : case NACL_ABI_O_RDWR:
277 0 : if (NACL_ABI_O_RDWR != nnsep->mode) {
278 0 : status = NACL_NAME_SERVICE_PERMISSION_DENIED;
279 0 : NaClLog(4, "NaClNameServiceResolveName: incompatible,"
280 : " not for both read and write\n");
281 0 : goto unlock_and_quit;
282 : }
283 0 : break;
284 : default:
285 0 : status = NACL_NAME_SERVICE_INVALID_ARGUMENT;
286 0 : NaClLog(4, "NaClNameServiceResolveName: invalid flag\n");
287 0 : goto unlock_and_quit;
288 : }
289 0 : NaClLog(4, "NaClNameServiceResolveName: mode and flags are compatible\n");
290 0 : *out = NaClDescRef(nnsep->entry);
291 0 : status = NACL_NAME_SERVICE_SUCCESS;
292 : } else {
293 0 : status = (*nnsep->factory)(nnsep->state, name, flags, out);
294 : }
295 : }
296 0 : unlock_and_quit:
297 0 : nnsep = NULL;
298 0 : NaClXMutexUnlock(&nnsp->mu);
299 0 : quit:
300 0 : return status;
301 : }
302 :
303 : int NaClNameServiceDeleteName(struct NaClNameService *nnsp,
304 0 : char const *name) {
305 : struct NaClNameServiceEntry **nnsepp;
306 0 : struct NaClNameServiceEntry *to_free = NULL;
307 0 : int status = NACL_NAME_SERVICE_NAME_NOT_FOUND;
308 :
309 0 : NaClXMutexLock(&nnsp->mu);
310 0 : nnsepp = NameServiceSearch(&nnsp->head, name);
311 0 : if (NULL != *nnsepp) {
312 0 : to_free = *nnsepp;
313 0 : *nnsepp = to_free->next;
314 0 : status = NACL_NAME_SERVICE_SUCCESS;
315 : }
316 0 : NaClXMutexUnlock(&nnsp->mu);
317 :
318 : /* do the free operations w/o holding the lock */
319 0 : if (NULL != to_free) {
320 0 : NaClDescSafeUnref(to_free->entry);
321 0 : if (NULL != to_free->factory) {
322 0 : (void) (*to_free->factory)(to_free->state,
323 : to_free->name,
324 : 0,
325 : (struct NaClDesc **) NULL);
326 : }
327 0 : free((void *) to_free->name);
328 0 : free(to_free);
329 : }
330 0 : return status;
331 : }
332 :
333 : size_t NaClNameServiceEnumerate(struct NaClNameService *nnsp,
334 : char *dest,
335 0 : size_t nbytes) {
336 : struct NaClNameServiceEntry *p;
337 : size_t written;
338 : size_t to_write;
339 : size_t name_len;
340 :
341 0 : NaClXMutexLock(&nnsp->mu);
342 :
343 0 : for (p = nnsp->head, written = 0;
344 0 : NULL != p && written < nbytes;
345 0 : p = p->next, written += to_write) {
346 0 : name_len = strlen(p->name) + 1; /* cannot overflow */
347 0 : to_write = (name_len < nbytes - written) ? name_len
348 : : nbytes - written;
349 : /* written + to_write <= nbytes */
350 0 : strncpy(dest, p->name, to_write);
351 0 : dest += to_write;
352 : }
353 :
354 0 : NaClXMutexUnlock(&nnsp->mu);
355 0 : return written;
356 : }
357 :
358 : static void NaClNameServiceNameInsertRpc(
359 : struct NaClSrpcRpc *rpc,
360 : struct NaClSrpcArg **in_args,
361 : struct NaClSrpcArg **out_args,
362 0 : struct NaClSrpcClosure *done_cls) {
363 : struct NaClNameService *nnsp =
364 0 : (struct NaClNameService *) rpc->channel->server_instance_data;
365 0 : char *name = in_args[0]->arrays.str;
366 0 : int mode = in_args[1]->u.ival;
367 0 : struct NaClDesc *desc = in_args[2]->u.hval;
368 :
369 0 : NaClLog(3,
370 : "NaClNameServiceNameInsertRpc: inserting %s, %d (0x%x)\n",
371 : name,
372 : mode, mode);
373 0 : out_args[0]->u.ival = (*NACL_VTBL(NaClNameService, nnsp)->CreateDescEntry)(
374 : nnsp, name, mode, desc);
375 0 : rpc->result = NACL_SRPC_RESULT_OK;
376 0 : (*done_cls->Run)(done_cls);
377 0 : }
378 :
379 : static void NaClNameServiceNameLookupOldRpc(
380 : struct NaClSrpcRpc *rpc,
381 : struct NaClSrpcArg **in_args,
382 : struct NaClSrpcArg **out_args,
383 0 : struct NaClSrpcClosure *done_cls) {
384 : struct NaClNameService *nnsp =
385 0 : (struct NaClNameService *) rpc->channel->server_instance_data;
386 0 : char *name = in_args[0]->arrays.str;
387 : int status;
388 : struct NaClDesc *desc;
389 :
390 0 : NaClLog(LOG_WARNING,
391 : "NaClNameServiceNameLookupOldRpc: DEPRECATED interface used.\n");
392 0 : NaClLog(3, "NaClNameServiceNameLookupOldRpc: looking up %s\n", name);
393 0 : status = (*NACL_VTBL(NaClNameService, nnsp)->ResolveName)(
394 : nnsp, name, NACL_ABI_O_RDONLY, &desc);
395 0 : out_args[0]->u.ival = status;
396 0 : out_args[1]->u.hval = (NACL_NAME_SERVICE_SUCCESS == status)
397 : ? desc
398 : : (struct NaClDesc *) NaClDescInvalidMake();
399 0 : rpc->result = NACL_SRPC_RESULT_OK;
400 0 : (*done_cls->Run)(done_cls);
401 0 : }
402 :
403 : static void NaClNameServiceNameLookupRpc(
404 : struct NaClSrpcRpc *rpc,
405 : struct NaClSrpcArg **in_args,
406 : struct NaClSrpcArg **out_args,
407 0 : struct NaClSrpcClosure *done_cls) {
408 : struct NaClNameService *nnsp =
409 0 : (struct NaClNameService *) rpc->channel->server_instance_data;
410 0 : char *name = in_args[0]->arrays.str;
411 0 : int flags = in_args[1]->u.ival;
412 : int status;
413 : struct NaClDesc *desc;
414 :
415 0 : NaClLog(3, "NaClNameServiceNameLookupRpc: looking up %s\n", name);
416 0 : NaClLog(3, "NaClNameServiceNameLookupRpc: flags %d (0x%x)\n", flags, flags);
417 0 : status = (*NACL_VTBL(NaClNameService, nnsp)->ResolveName)(
418 : nnsp, name, flags, &desc);
419 0 : out_args[0]->u.ival = status;
420 0 : out_args[1]->u.hval = (NACL_NAME_SERVICE_SUCCESS == status)
421 : ? desc
422 : : (struct NaClDesc *) NaClDescInvalidMake();
423 0 : NaClLog(3, "NaClNameServiceNameLookupRpc: status %d\n", status);
424 0 : NaClLog(3, "NaClNameServiceNameLookupRpc: desc 0x%"NACL_PRIxPTR"\n",
425 : (uintptr_t) desc);
426 0 : rpc->result = NACL_SRPC_RESULT_OK;
427 0 : (*done_cls->Run)(done_cls);
428 0 : }
429 :
430 : static void NaClNameServiceNameDeleteRpc(
431 : struct NaClSrpcRpc *rpc,
432 : struct NaClSrpcArg **in_args,
433 : struct NaClSrpcArg **out_args,
434 0 : struct NaClSrpcClosure *done_cls) {
435 : struct NaClNameService *nnsp =
436 0 : (struct NaClNameService *) rpc->channel->server_instance_data;
437 0 : char *name = in_args[0]->arrays.str;
438 :
439 0 : out_args[0]->u.ival = (*NACL_VTBL(NaClNameService, nnsp)->DeleteName)(
440 : nnsp, name);
441 0 : rpc->result = NACL_SRPC_RESULT_OK;
442 0 : (*done_cls->Run)(done_cls);
443 0 : }
444 :
445 : static void NaClNameServiceListRpc(
446 : struct NaClSrpcRpc *rpc,
447 : struct NaClSrpcArg **in_args,
448 : struct NaClSrpcArg **out_args,
449 0 : struct NaClSrpcClosure *done_cls) {
450 : struct NaClNameService *nnsp =
451 0 : (struct NaClNameService *) rpc->channel->server_instance_data;
452 0 : size_t nbytes = out_args[0]->u.count;
453 0 : char *dest = out_args[0]->arrays.carr;
454 :
455 : UNREFERENCED_PARAMETER(in_args);
456 0 : out_args[0]->u.count = (uint32_t) (*NACL_VTBL(NaClNameService, nnsp)->
457 : Enumerate)(nnsp, dest, nbytes);
458 0 : rpc->result = NACL_SRPC_RESULT_OK;
459 0 : (*done_cls->Run)(done_cls);
460 0 : }
461 :
462 : struct NaClSrpcHandlerDesc const kNaClNameServiceHandlers[] = {
463 : { NACL_NAME_SERVICE_LIST, NaClNameServiceListRpc, },
464 : { NACL_NAME_SERVICE_INSERT, NaClNameServiceNameInsertRpc, },
465 : { NACL_NAME_SERVICE_LOOKUP_DEPRECATED, NaClNameServiceNameLookupOldRpc, },
466 : { NACL_NAME_SERVICE_LOOKUP, NaClNameServiceNameLookupRpc, },
467 : { NACL_NAME_SERVICE_DELETE, NaClNameServiceNameDeleteRpc, },
468 : { (char const *) NULL, (NaClSrpcMethod) NULL, },
469 : };
470 :
471 3 : void NaClNameServiceLaunch(struct NaClNameService *self) {
472 :
473 3 : NaClLog(4, "NaClNameServiceThread: starting service\n");
474 3 : NaClSimpleServiceStartServiceThread((struct NaClSimpleService *) self);
475 3 : }
476 :
477 : struct NaClNameServiceVtbl kNaClNameServiceVtbl = {
478 : {
479 : /* really NaClSimpleLtdServiceVtbl contents */
480 : {
481 : NaClNameServiceDtor,
482 : },
483 : NaClSimpleServiceConnectionFactory,
484 : /*
485 : * To implement name service ownership, the ConnectionFactory will
486 : * need to build a subclass of a NaClSimpleServiceConnection where
487 : * the connection can be marked as an owner, and the NameService
488 : * would contain a mutex protected flag specifying whether it is
489 : * owned that blocks mutations by all but the owning connection.
490 : * The Connection object's Dtor can release ownership.
491 : */
492 : NaClSimpleLtdServiceAcceptConnection,
493 : NaClSimpleServiceAcceptAndSpawnHandler,
494 : NaClSimpleLtdServiceRpcHandler,
495 : },
496 : NaClNameServiceCreateDescEntry,
497 : NaClNameServiceCreateFactoryEntry,
498 : NaClNameServiceResolveName,
499 : NaClNameServiceDeleteName,
500 : NaClNameServiceEnumerate,
501 : };
|