Exemple #1
0
int NaClAppLaunchServiceThreads(struct NaClApp *nap) {
  struct NaClManifestProxy                    *manifest_proxy = NULL;
  struct NaClKernelService                    *kernel_service = NULL;
  int                                         rv = 0;
  enum NaClReverseChannelInitializationState  init_state;

  NaClNameServiceLaunch(nap->name_service);

  kernel_service = (struct NaClKernelService *) malloc(sizeof *kernel_service);
  if (NULL == kernel_service) {
    NaClLog(LOG_ERROR,
            "NaClAppLaunchServiceThreads: No memory for kern service\n");
    goto done;
  }

  if (!NaClKernelServiceCtor(kernel_service,
                             NaClAddrSpSquattingThreadIfFactoryFunction,
                             (void *) nap,
                             nap)) {
    NaClLog(LOG_ERROR,
            "NaClAppLaunchServiceThreads: KernServiceCtor failed\n");
    free(kernel_service);
    kernel_service = NULL;
    goto done;
  }

  if (!NaClSimpleServiceStartServiceThread((struct NaClSimpleService *)
                                           kernel_service)) {
    NaClLog(LOG_ERROR,
            "NaClAppLaunchServiceThreads: KernService start service failed\n");
    goto done;
  }
  /*
   * NB: StartServiceThread grabbed another reference to kernel_service,
   * used by the service thread.  Closing the connection capability
   * should cause the service thread to shut down and in turn release
   * that reference.
   */

  /*
   * The locking here isn't really needed.  Here is why:
   * reverse_channel_initialized is written in reverse_setup RPC
   * handler of the secure command channel RPC handler thread.  and
   * the RPC order requires that the plugin invoke reverse_setup prior
   * to invoking start_module, so there will have been plenty of other
   * synchronization operations to force cache coherency
   * (module_may_start, for example, is set in the cache of the secure
   * channel RPC handler (in start_module) and read by the main
   * thread, and the synchronization operations needed to propagate
   * its value properly suffices to propagate
   * reverse_channel_initialized as well).  However, reading it while
   * holding a lock is more obviously correct for tools like tsan.
   * Due to the RPC order, it is impossible for
   * reverse_channel_initialized to get set after the unlock and
   * before the if test.
   */
  NaClXMutexLock(&nap->mu);
  /*
   * If no reverse_setup RPC was made, then we do not set up a
   * manifest proxy.  Otherwise, we make sure that the reverse channel
   * setup is done, so that the application can actually use
   * reverse-channel-based services such as the manifest proxy.
   */
  if (NACL_REVERSE_CHANNEL_UNINITIALIZED !=
      (init_state = nap->reverse_channel_initialization_state)) {
    while (NACL_REVERSE_CHANNEL_INITIALIZED !=
      (init_state = nap->reverse_channel_initialization_state)) {
      NaClXCondVarWait(&nap->cv, &nap->mu);
    }
  }
  NaClXMutexUnlock(&nap->mu);
  if (NACL_REVERSE_CHANNEL_INITIALIZED != init_state) {
    NaClLog(3,
            ("NaClAppLaunchServiceThreads: no reverse channel;"
             " launched kernel services.\n"));
    NaClLog(3,
            ("NaClAppLaunchServiceThreads: no reverse channel;"
             " NOT launching manifest proxy.\n"));
    nap->kernel_service = kernel_service;
    kernel_service = NULL;

    rv = 1;
    goto done;
  }

  /*
   * Allocate/construct the manifest proxy without grabbing global
   * locks.
   */
  NaClLog(3, "NaClAppLaunchServiceThreads: launching manifest proxy\n");

  /*
   * ReverseClientSetup RPC should be done via the command channel
   * prior to the load_module / start_module RPCs, and
   *  occurs after that, so checking
   * nap->reverse_client suffices for determining whether the proxy is
   * exporting reverse services.
   */
  manifest_proxy = (struct NaClManifestProxy *) malloc(sizeof *manifest_proxy);
  if (NULL == manifest_proxy) {
    NaClLog(LOG_ERROR, "No memory for manifest proxy\n");
    NaClDescUnref(kernel_service->base.bound_and_cap[1]);
    goto done;
  }
  if (!NaClManifestProxyCtor(manifest_proxy,
                             NaClAddrSpSquattingThreadIfFactoryFunction,
                             (void *) nap,
                             nap)) {
    NaClLog(LOG_ERROR, "ManifestProxyCtor failed\n");
    /* do not leave a non-NULL pointer to a not-fully constructed object */
    free(manifest_proxy);
    manifest_proxy = NULL;
    NaClDescUnref(kernel_service->base.bound_and_cap[1]);
    goto done;
  }

  /*
   * NaClSimpleServiceStartServiceThread requires the nap->mu lock.
   */
  if (!NaClSimpleServiceStartServiceThread((struct NaClSimpleService *)
                                           manifest_proxy)) {
    NaClLog(LOG_ERROR, "ManifestProxy start service failed\n");
    NaClDescUnref(kernel_service->base.bound_and_cap[1]);
    goto done;
  }

  NaClXMutexLock(&nap->mu);
  CHECK(NULL == nap->manifest_proxy);
  CHECK(NULL == nap->kernel_service);

  nap->manifest_proxy = manifest_proxy;
  manifest_proxy = NULL;
  nap->kernel_service = kernel_service;
  kernel_service = NULL;
  NaClXMutexUnlock(&nap->mu);
  rv = 1;

done:
  NaClXMutexLock(&nap->mu);
  if (NULL != nap->manifest_proxy) {
    NaClLog(3,
            ("NaClAppLaunchServiceThreads: adding manifest proxy to"
             " name service\n"));
    (*NACL_VTBL(NaClNameService, nap->name_service)->
     CreateDescEntry)(nap->name_service,
                      "ManifestNameService", NACL_ABI_O_RDWR,
                      NaClDescRef(nap->manifest_proxy->base.bound_and_cap[1]));
  }
  if (NULL != nap->kernel_service) {
    NaClLog(3,
            ("NaClAppLaunchServiceThreads: adding kernel service to"
             " name service\n"));
    (*NACL_VTBL(NaClNameService, nap->name_service)->
     CreateDescEntry)(nap->name_service,
                      "KernelService", NACL_ABI_O_RDWR,
                      NaClDescRef(nap->kernel_service->base.bound_and_cap[1]));
  }

  NaClXMutexUnlock(&nap->mu);

  /*
   * Single exit path.
   *
   * Error cleanup invariant.  No service thread should be running
   * (modulo asynchronous shutdown).  Automatic variables refer to
   * fully constructed objects if non-NULL, and when ownership is
   * transferred to the NaClApp object the corresponding automatic
   * variable is set to NULL.
   */
  NaClRefCountSafeUnref((struct NaClRefCount *) manifest_proxy);
  NaClRefCountSafeUnref((struct NaClRefCount *) kernel_service);
  return rv;
}
Exemple #2
0
void NaClNameServiceLaunch(struct NaClNameService *self) {

  NaClLog(4, "NaClNameServiceThread: starting service\n");
  NaClSimpleServiceStartServiceThread((struct NaClSimpleService *) self);
}