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 |