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; }
void NaClNameServiceLaunch(struct NaClNameService *self) { NaClLog(4, "NaClNameServiceThread: starting service\n"); NaClSimpleServiceStartServiceThread((struct NaClSimpleService *) self); }