LCOV - code coverage report
Current view: directory - src/trusted/service_runtime/name_service - name_service.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 235 96 40.9 %
Date: 2014-06-18 Functions: 0 0 -

       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             295 : int NaClNameServiceCtor(struct NaClNameService      *self,
      56             295 :                         NaClThreadIfFactoryFunction thread_factory_fn,
      57             295 :                         void                        *thread_factory_data) {
      58             295 :   int     retval = 0;  /* fail */
      59                 : 
      60             295 :   NaClLog(4, "Entered NaClNameServiceCtor\n");
      61             295 :   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             295 :   if (!NaClMutexCtor(&self->mu)) {
      70               0 :     NaClLog(4, "NaClMutexCtor failed\n");
      71               0 :     goto abort_mu;
      72                 :   }
      73             295 :   NACL_VTBL(NaClRefCount, self) = (struct NaClRefCountVtbl *)
      74                 :       &kNaClNameServiceVtbl;
      75                 :   /* success return path */
      76             295 :   self->head = (struct NaClNameServiceEntry *) NULL;
      77             295 :   retval = 1;
      78             295 :   goto done;
      79                 : 
      80                 :   /* cleanup unwind */
      81                 :  abort_mu:  /* mutex ctor failed */
      82               0 :   (*NACL_VTBL(NaClRefCount, self)->Dtor)((struct NaClRefCount *) self);
      83                 :  done:
      84             295 :   return retval;
      85                 : }
      86                 : 
      87               0 : void NaClNameServiceDtor(struct NaClRefCount *vself) {
      88               0 :   struct NaClNameService      *self = (struct NaClNameService *) vself;
      89                 : 
      90               0 :   struct NaClNameServiceEntry *p;
      91               0 :   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               0 :     } 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               0 :   }
     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             558 :     struct NaClNameServiceEntry **hd,
     113             558 :     char const                  *name) {
     114            1651 :   while (NULL != *hd && 0 != strcmp((*hd)->name, name)) {
     115             265 :     hd = &(*hd)->next;
     116             265 :   }
     117             558 :   return hd;
     118                 : }
     119                 : 
     120                 : 
     121                 : int NaClNameServiceCreateDescEntry(
     122             553 :     struct NaClNameService  *nnsp,
     123             553 :     char const              *name,
     124             553 :     int                     mode,
     125             553 :     struct NaClDesc         *new_desc) {
     126             553 :   int                         retval = NACL_NAME_SERVICE_INSUFFICIENT_RESOURCES;
     127             553 :   struct NaClNameServiceEntry *name_entry = NULL;
     128             553 :   struct NaClNameServiceEntry *found = NULL;
     129             553 :   char                        *dup_name = STRDUP(name);
     130                 : 
     131             553 :   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             553 :   if (NULL == dup_name) {
     141               0 :     goto dup_failed;
     142                 :   }
     143             553 :   name_entry = (struct NaClNameServiceEntry *) malloc(sizeof *name_entry);
     144             553 :   if (NULL == name_entry) {
     145               0 :     goto entry_alloc_failed;
     146                 :   }
     147                 : 
     148             553 :   NaClXMutexLock(&nnsp->mu);
     149             553 :   found = *NameServiceSearch(&nnsp->head, name);
     150             553 :   if (NULL != found) {
     151               0 :     retval = NACL_NAME_SERVICE_DUPLICATE_NAME;
     152               0 :     goto unlock_and_cleanup;
     153                 :   }
     154             553 :   name_entry->next = nnsp->head;
     155             553 :   name_entry->name = dup_name;
     156             553 :   dup_name = (char *) NULL;
     157             553 :   name_entry->mode = mode;
     158             553 :   name_entry->entry = new_desc;
     159             553 :   name_entry->factory = (NaClNameServiceFactoryFn_t) NULL;
     160             553 :   name_entry->state = (void *) NULL;
     161             553 :   nnsp->head = name_entry;
     162             553 :   name_entry = NULL;
     163             553 :   retval = NACL_NAME_SERVICE_SUCCESS;
     164                 : 
     165                 :  unlock_and_cleanup:
     166             553 :   NaClXMutexUnlock(&nnsp->mu);
     167             553 :   free(name_entry);
     168                 :  entry_alloc_failed:
     169             553 :   free(dup_name);
     170                 :  dup_failed:
     171             553 :   return retval;
     172                 : }
     173                 : 
     174                 : int NaClNameServiceCreateFactoryEntry(
     175               0 :     struct NaClNameService      *nnsp,
     176               0 :     char const                  *name,
     177               0 :     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                 :  unlock_and_cleanup:
     220               0 :   NaClXMutexUnlock(&nnsp->mu);
     221               0 :   free(name_entry);
     222                 :  entry_alloc_failed:
     223               0 :   free(dup_name);
     224                 :  dup_failed:
     225               0 :   return retval;
     226                 : }
     227                 : 
     228               5 : int NaClNameServiceResolveName(struct NaClNameService  *nnsp,
     229               5 :                                char const              *name,
     230               5 :                                int                     flags,
     231               5 :                                struct NaClDesc         **out) {
     232               5 :   struct NaClNameServiceEntry *nnsep;
     233               5 :   int                         status = NACL_NAME_SERVICE_NAME_NOT_FOUND;
     234                 : 
     235               5 :   NaClLog(3,
     236                 :           "NaClNameServiceResolveName: looking up %s, flags %d (0x%x)\n",
     237                 :           name,
     238                 :           flags, flags);
     239               5 :   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               5 :   NaClXMutexLock(&nnsp->mu);
     246               5 :   nnsep = *NameServiceSearch(&nnsp->head, name);
     247               5 :   if (NULL != nnsep) {
     248               5 :     if (NULL != nnsep->entry) {
     249               5 :       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               5 :       NaClLog(4,
     255                 :               ("NaClNameServiceResolveName: checking mode/flags"
     256                 :                " compatibility\n"));
     257               5 :       switch (flags) {
     258                 :         case NACL_ABI_O_RDONLY:
     259               5 :           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               5 :           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               5 :       NaClLog(4, "NaClNameServiceResolveName: mode and flags are compatible\n");
     290               5 :       *out = NaClDescRef(nnsep->entry);
     291               5 :       status = NACL_NAME_SERVICE_SUCCESS;
     292               5 :     } else {
     293               0 :       status = (*nnsep->factory)(nnsep->state, name, flags, out);
     294                 :     }
     295              10 :   }
     296                 :  unlock_and_quit:
     297               5 :   nnsep = NULL;
     298               5 :   NaClXMutexUnlock(&nnsp->mu);
     299                 :  quit:
     300               5 :   return status;
     301                 : }
     302                 : 
     303               0 : int NaClNameServiceDeleteName(struct NaClNameService *nnsp,
     304               0 :                               char const             *name) {
     305               0 :   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               0 :   }
     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               0 :     }
     327               0 :     free((void *) to_free->name);
     328               0 :     free(to_free);
     329               0 :   }
     330               0 :   return status;
     331                 : }
     332                 : 
     333                 : static void NaClNameServiceNameInsertRpc(
     334               0 :     struct NaClSrpcRpc      *rpc,
     335               0 :     struct NaClSrpcArg      **in_args,
     336               0 :     struct NaClSrpcArg      **out_args,
     337               0 :     struct NaClSrpcClosure  *done_cls) {
     338               0 :   struct NaClNameService  *nnsp =
     339                 :       (struct NaClNameService *) rpc->channel->server_instance_data;
     340               0 :   char                    *name = in_args[0]->arrays.str;
     341               0 :   int                     mode  = in_args[1]->u.ival;
     342               0 :   struct NaClDesc         *desc = in_args[2]->u.hval;
     343                 : 
     344               0 :   NaClLog(3,
     345                 :           "NaClNameServiceNameInsertRpc: inserting %s, %d (0x%x)\n",
     346                 :           name,
     347                 :           mode, mode);
     348               0 :   out_args[0]->u.ival = (*NACL_VTBL(NaClNameService, nnsp)->CreateDescEntry)(
     349                 :       nnsp, name, mode, desc);
     350               0 :   rpc->result = NACL_SRPC_RESULT_OK;
     351               0 :   (*done_cls->Run)(done_cls);
     352               0 : }
     353                 : 
     354                 : static void NaClNameServiceNameLookupOldRpc(
     355               0 :     struct NaClSrpcRpc      *rpc,
     356               0 :     struct NaClSrpcArg      **in_args,
     357               0 :     struct NaClSrpcArg      **out_args,
     358               0 :     struct NaClSrpcClosure  *done_cls) {
     359               0 :   struct NaClNameService  *nnsp =
     360                 :       (struct NaClNameService *) rpc->channel->server_instance_data;
     361               0 :   char                    *name = in_args[0]->arrays.str;
     362               0 :   int                     status;
     363               0 :   struct NaClDesc         *desc;
     364                 : 
     365               0 :   NaClLog(LOG_WARNING,
     366                 :           "NaClNameServiceNameLookupOldRpc: DEPRECATED interface used.\n");
     367               0 :   NaClLog(3, "NaClNameServiceNameLookupOldRpc: looking up %s\n", name);
     368               0 :   status = (*NACL_VTBL(NaClNameService, nnsp)->ResolveName)(
     369                 :       nnsp, name, NACL_ABI_O_RDONLY, &desc);
     370               0 :   out_args[0]->u.ival = status;
     371               0 :   out_args[1]->u.hval = (NACL_NAME_SERVICE_SUCCESS == status)
     372                 :       ? desc
     373               0 :       : (struct NaClDesc *) NaClDescInvalidMake();
     374               0 :   rpc->result = NACL_SRPC_RESULT_OK;
     375               0 :   (*done_cls->Run)(done_cls);
     376               0 : }
     377                 : 
     378                 : static void NaClNameServiceNameLookupRpc(
     379               5 :     struct NaClSrpcRpc      *rpc,
     380               5 :     struct NaClSrpcArg      **in_args,
     381               5 :     struct NaClSrpcArg      **out_args,
     382               5 :     struct NaClSrpcClosure  *done_cls) {
     383               5 :   struct NaClNameService  *nnsp =
     384                 :       (struct NaClNameService *) rpc->channel->server_instance_data;
     385               5 :   char                    *name = in_args[0]->arrays.str;
     386               5 :   int                     flags = in_args[1]->u.ival;
     387               5 :   int                     status;
     388               5 :   struct NaClDesc         *desc;
     389                 : 
     390               5 :   NaClLog(3, "NaClNameServiceNameLookupRpc: looking up %s\n", name);
     391               5 :   NaClLog(3, "NaClNameServiceNameLookupRpc: flags %d (0x%x)\n", flags, flags);
     392               5 :   status = (*NACL_VTBL(NaClNameService, nnsp)->ResolveName)(
     393                 :       nnsp, name, flags, &desc);
     394               5 :   out_args[0]->u.ival = status;
     395              10 :   out_args[1]->u.hval = (NACL_NAME_SERVICE_SUCCESS == status)
     396                 :       ? desc
     397               5 :       : (struct NaClDesc *) NaClDescInvalidMake();
     398               5 :   NaClLog(3, "NaClNameServiceNameLookupRpc: status %d\n", status);
     399               5 :   NaClLog(3, "NaClNameServiceNameLookupRpc: desc 0x%"NACL_PRIxPTR"\n",
     400                 :           (uintptr_t) desc);
     401               5 :   rpc->result = NACL_SRPC_RESULT_OK;
     402               5 :   (*done_cls->Run)(done_cls);
     403               5 : }
     404                 : 
     405                 : static void NaClNameServiceNameDeleteRpc(
     406               0 :     struct NaClSrpcRpc      *rpc,
     407               0 :     struct NaClSrpcArg      **in_args,
     408               0 :     struct NaClSrpcArg      **out_args,
     409               0 :     struct NaClSrpcClosure  *done_cls) {
     410               0 :   struct NaClNameService  *nnsp =
     411                 :       (struct NaClNameService *) rpc->channel->server_instance_data;
     412               0 :   char                    *name = in_args[0]->arrays.str;
     413                 : 
     414               0 :   out_args[0]->u.ival = (*NACL_VTBL(NaClNameService, nnsp)->DeleteName)(
     415                 :       nnsp, name);
     416               0 :   rpc->result = NACL_SRPC_RESULT_OK;
     417               0 :   (*done_cls->Run)(done_cls);
     418               0 : }
     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             255 : void NaClNameServiceLaunch(struct NaClNameService *self) {
     429                 : 
     430             255 :   NaClLog(4, "NaClNameServiceThread: starting service\n");
     431             255 :   NaClSimpleServiceStartServiceThread((struct NaClSimpleService *) self);
     432             255 : }
     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                 : };

Generated by: LCOV version 1.7