bool RDDParent::Init(base::ProcessId aParentPid, const char* aParentBuildID, MessageLoop* aIOLoop, IPC::Channel* aChannel) { // Initialize the thread manager before starting IPC. Otherwise, messages // may be posted to the main thread and we won't be able to process them. if (NS_WARN_IF(NS_FAILED(nsThreadManager::get().Init()))) { return false; } // Now it's safe to start IPC. if (NS_WARN_IF(!Open(aChannel, aParentPid, aIOLoop))) { return false; } nsDebugImpl::SetMultiprocessMode("RDD"); // This must be checked before any IPDL message, which may hit sentinel // errors due to parent and content processes having different // versions. MessageChannel* channel = GetIPCChannel(); if (channel && !channel->SendBuildIDsMatchMessage(aParentBuildID)) { // We need to quit this process if the buildID doesn't match the parent's. // This can occur when an update occurred in the background. ProcessChild::QuickExit(); } // Init crash reporter support. CrashReporterClient::InitSingleton(this); if (NS_FAILED(NS_InitMinimalXPCOM())) { return false; } mozilla::ipc::SetThisProcessName("RDD Process"); return true; }
bool JavaScriptParent::allowMessage(JSContext* cx) { MessageChannel* channel = GetIPCChannel(); if (channel->IsInTransaction()) return true; if (ForbidUnsafeBrowserCPOWs()) { if (JSObject* global = JS::CurrentGlobalOrNull(cx)) { if (!JS::AddonIdOfObject(global)) { JS_ReportError(cx, "unsafe CPOW usage forbidden"); return false; } } } static bool disableUnsafeCPOWWarnings = PR_GetEnv("DISABLE_UNSAFE_CPOW_WARNINGS"); if (!disableUnsafeCPOWWarnings) { nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID)); if (console && cx) { nsAutoString filename; uint32_t lineno = 0, column = 0; nsJSUtils::GetCallingLocation(cx, filename, &lineno, &column); nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID)); error->Init(NS_LITERAL_STRING("unsafe CPOW usage"), filename, EmptyString(), lineno, column, nsIScriptError::warningFlag, "chrome javascript"); console->LogMessage(error); } else { NS_WARNING("Unsafe synchronous IPC message"); } } return true; }
JSValue jsMessageChannelPort2(ExecState* exec, JSValue slotBase, const Identifier&) { JSMessageChannel* castedThis = static_cast<JSMessageChannel*>(asObject(slotBase)); UNUSED_PARAM(exec); MessageChannel* imp = static_cast<MessageChannel*>(castedThis->impl()); JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(imp->port2())); return result; }
// nsAppShell's notification that gecko events are being processed. // If we are here and there is an Interrupt Incall active, we are spinning // a nested gecko event loop. In which case the remote process needs // to know about it. void /* static */ MessageChannel::NotifyGeckoEventDispatch() { // sStaticTopFrame is only valid for Interrupt channels if (!sStaticTopFrame || sStaticTopFrame->mListenerNotified) return; sStaticTopFrame->mListenerNotified = true; MessageChannel* channel = static_cast<MessageChannel*>(sStaticTopFrame->mChannel); channel->Listener()->ProcessRemoteNativeEventsInInterruptCall(); }
static v8::Handle<v8::Value> port2AttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) { INC_STATS("DOM.MessageChannel.port2._get"); MessageChannel* imp = V8MessageChannel::toNative(info.Holder()); RefPtr<MessagePort> result = imp->port2(); v8::Handle<v8::Value> wrapper = result.get() ? getActiveDOMObjectMap().get(result.get()) : v8::Handle<v8::Value>(); if (wrapper.IsEmpty()) { wrapper = toV8(result.get()); if (!wrapper.IsEmpty()) V8DOMWrapper::setNamedHiddenReference(info.Holder(), "port2", wrapper); } return wrapper; }
virtual void sendStartupInfo(MessageChannel &channel) { channel.write("HelperAgent info", requestSocketFilename.c_str(), Base64::encode(requestSocketPassword).c_str(), messageSocketFilename.c_str(), Base64::encode(messageSocketPassword).c_str(), NULL); }
/** * The entry point of the thread that handles the client connection. */ void threadMain(const weak_ptr<Client> self) { vector<string> args; try { while (!this_thread::interruption_requested()) { try { if (!channel.read(args)) { // Client closed connection. break; } } catch (const SystemException &e) { P_TRACE(2, "Exception in ApplicationPoolServer client thread during " "reading of a message: " << e.what()); break; } P_TRACE(4, "Client " << this << ": received message: " << toString(args)); if (args[0] == "get" && args.size() == 7) { processGet(args); } else if (args[0] == "close" && args.size() == 2) { processClose(args); } else if (args[0] == "clear" && args.size() == 1) { processClear(args); } else if (args[0] == "setMaxIdleTime" && args.size() == 2) { processSetMaxIdleTime(args); } else if (args[0] == "setMax" && args.size() == 2) { processSetMax(args); } else if (args[0] == "getActive" && args.size() == 1) { processGetActive(args); } else if (args[0] == "getCount" && args.size() == 1) { processGetCount(args); } else if (args[0] == "setMaxPerApp" && args.size() == 2) { processSetMaxPerApp(atoi(args[1])); } else if (args[0] == "getSpawnServerPid" && args.size() == 1) { processGetSpawnServerPid(args); } else { processUnknownMessage(args); break; } args.clear(); } } catch (const boost::thread_interrupted &) { P_TRACE(2, "Client thread " << this << " interrupted."); } catch (const exception &e) { P_TRACE(2, "Uncaught exception in ApplicationPoolServer client thread:\n" << " message: " << toString(args) << "\n" << " exception: " << e.what()); } mutex::scoped_lock l(server.lock); ClientPtr myself(self.lock()); if (myself != NULL) { server.clients.erase(myself); } }
void processGet(const vector<string> &args) { TRACE_POINT(); Application::SessionPtr session; bool failed = false; try { session = server.pool.get(SpawnOptions( args[1], args[2] == "true", args[3], args[4], args[5], args[6], atoi(args[7]), atoi(args[8]))); sessions[lastSessionID] = session; lastSessionID++; } catch (const SpawnException &e) { UPDATE_TRACE_POINT(); this_thread::disable_syscall_interruption dsi; if (e.hasErrorPage()) { P_TRACE(3, "Client " << this << ": SpawnException " "occured (with error page)"); channel.write("SpawnException", e.what(), "true", NULL); channel.writeScalar(e.getErrorPage()); } else { P_TRACE(3, "Client " << this << ": SpawnException " "occured (no error page)"); channel.write("SpawnException", e.what(), "false", NULL); } failed = true; } catch (const BusyException &e) { UPDATE_TRACE_POINT(); this_thread::disable_syscall_interruption dsi; channel.write("BusyException", e.what(), NULL); failed = true; } catch (const IOException &e) { UPDATE_TRACE_POINT(); this_thread::disable_syscall_interruption dsi; channel.write("IOException", e.what(), NULL); failed = true; } UPDATE_TRACE_POINT(); if (!failed) { this_thread::disable_syscall_interruption dsi; try { UPDATE_TRACE_POINT(); channel.write("ok", toString(session->getPid()).c_str(), toString(lastSessionID - 1).c_str(), NULL); channel.writeFileDescriptor(session->getStream()); session->closeStream(); } catch (const exception &) { UPDATE_TRACE_POINT(); P_TRACE(3, "Client " << this << ": something went wrong " "while sending 'ok' back to the client."); sessions.erase(lastSessionID - 1); throw; } } }
string receivePassword() { TRACE_POINT(); vector<string> args; if (!feedbackChannel.read(args)) { throw IOException("The watchdog unexpectedly closed the connection."); } if (args[0] != "request socket password" && args[0] != "message socket password") { throw IOException("Unexpected input message '" + args[0] + "'"); } return Base64::decode(args[1]); }
int main(int argc, char** argv) { pid_t childpid; MessageChannel calling; if (!calling.isOk()) { perror("MessageChannel calling failed"); exit(1); } MessageChannel returning; if (!returning.isOk()) { perror("MessageChannel returning failed"); exit(1); } if((childpid = fork()) < 0) { perror("Fork Failed"); exit(1); } if(childpid != 0) // child process { std::string rets = childwrap_func(calling,returning,27); printf("func returned %s\n", rets.c_str()); int reti = childwrap_func2(calling,returning,"my string."); printf("func2 returned %i\n", reti); } else // parent process { handleMessage(calling,returning); handleMessage(calling,returning); } }
void V8MessageChannel::constructorCustom(const v8::FunctionCallbackInfo<v8::Value>& info) { ExecutionContext* context = currentExecutionContext(info.GetIsolate()); MessageChannel* channel = MessageChannel::create(context); v8::Local<v8::Object> wrapper = info.Holder(); // Create references from the MessageChannel wrapper to the two // MessagePort wrappers to make sure that the MessagePort wrappers // stay alive as long as the MessageChannel wrapper is around. V8HiddenValue::setHiddenValue(info.GetIsolate(), wrapper, V8HiddenValue::port1(info.GetIsolate()), toV8(channel->port1(), info.Holder(), info.GetIsolate())); V8HiddenValue::setHiddenValue(info.GetIsolate(), wrapper, V8HiddenValue::port2(info.GetIsolate()), toV8(channel->port2(), info.Holder(), info.GetIsolate())); V8DOMWrapper::associateObjectWithWrapper(info.GetIsolate(), channel, &wrapperTypeInfo, wrapper); info.GetReturnValue().Set(wrapper); }
void processGetSpawnServerPid(const vector<string> &args) { TRACE_POINT(); channel.write(toString(server.pool->getSpawnServerPid()).c_str(), NULL); }
void processGetCount(const vector<string> &args) { TRACE_POINT(); channel.write(toString(server.pool.getCount()).c_str(), NULL); }
static v8::Handle<v8::Value> port2AttrGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info) { INC_STATS("DOM.MessageChannel.port2._get"); MessageChannel* imp = V8MessageChannel::toNative(info.Holder()); return toV8(imp->port2()); }
virtual void sendStartupInfo(MessageChannel &channel) { channel.write("LoggingServer info", loggingAgentAddress.c_str(), loggingAgentPassword.c_str(), NULL); }
Server(FileDescriptor feedbackFd, pid_t webServerPid, const string &tempDir, bool userSwitching, const string &defaultUser, const string &defaultGroup, const string &passengerRoot, const string &rubyCommand, unsigned int generationNumber, unsigned int maxPoolSize, unsigned int maxInstancesPerApp, unsigned int poolIdleTime, const VariantMap &options) : serverInstanceDir(webServerPid, tempDir, false), resourceLocator(passengerRoot) { TRACE_POINT(); string messageSocketPassword; string loggingAgentPassword; this->feedbackFd = feedbackFd; feedbackChannel = MessageChannel(feedbackFd); UPDATE_TRACE_POINT(); messageSocketPassword = Base64::decode(options.get("message_socket_password")); loggingAgentPassword = options.get("logging_agent_password"); generation = serverInstanceDir.getGeneration(generationNumber); accountsDatabase = AccountsDatabase::createDefault(generation, userSwitching, defaultUser, defaultGroup); accountsDatabase->add("_web_server", messageSocketPassword, false, Account::GET | Account::DETACH | Account::SET_PARAMETERS | Account::EXIT); messageServer = ptr(new MessageServer(generation->getPath() + "/socket", accountsDatabase)); createFile(generation->getPath() + "/helper_server.pid", toString(getpid()), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (geteuid() == 0 && !userSwitching) { lowerPrivilege(defaultUser, defaultGroup); } UPDATE_TRACE_POINT(); analyticsLogger = ptr(new AnalyticsLogger(options.get("logging_agent_address"), "logging", loggingAgentPassword)); pool = ptr(new ApplicationPool::Pool( resourceLocator.getSpawnServerFilename(), generation, accountsDatabase, rubyCommand, analyticsLogger, options.getInt("log_level"), options.get("debug_log_file", false) )); pool->setMax(maxPoolSize); pool->setMaxPerApp(maxInstancesPerApp); pool->setMaxIdleTime(poolIdleTime); messageServer->addHandler(ptr(new TimerUpdateHandler(exitTimer))); messageServer->addHandler(ptr(new ApplicationPool::Server(pool))); messageServer->addHandler(ptr(new BacktracesServer())); messageServer->addHandler(ptr(new ExitHandler(exitEvent))); UPDATE_TRACE_POINT(); feedbackChannel.write("initialized", "", // Request socket filename; not available in the Apache helper server. messageServer->getSocketFilename().c_str(), NULL); prestarterThread = ptr(new oxt::thread( boost::bind(prestartWebApps, resourceLocator, options.get("prestart_urls")) )); }
void processGetActive(const vector<string> &args) { channel.write(toString(server.pool.getActive()).c_str(), NULL); }
void processGetSpawnServerPid(const vector<string> &args) { channel.write(toString(server.pool.getSpawnServerPid()).c_str(), NULL); }
bool JavaScriptParent::allowMessage(JSContext* cx) { // If we're running browser code, then we allow all safe CPOWs and forbid // unsafe CPOWs based on a pref (which defaults to forbidden). We also allow // CPOWs unconditionally in selected globals (based on // Cu.permitCPOWsInScope). // // If we're running add-on code, then we check if the add-on is multiprocess // compatible (which eventually translates to a given setting of allowCPOWs // on the scopw). If it's not compatible, then we allow the CPOW but // warn. If it is marked as compatible, then we check the // ForbidCPOWsInCompatibleAddon; see the comment there. MessageChannel* channel = GetIPCChannel(); bool isSafe = channel->IsInTransaction(); bool warn = !isSafe; nsIGlobalObject* global = dom::GetIncumbentGlobal(); JS::Rooted<JSObject*> jsGlobal(cx, global ? global->GetGlobalJSObject() : nullptr); if (jsGlobal) { JSAutoCompartment ac(cx, jsGlobal); JSAddonId* addonId = JS::AddonIdOfObject(jsGlobal); if (!xpc::CompartmentPrivate::Get(jsGlobal)->allowCPOWs) { if (!addonId && ForbidUnsafeBrowserCPOWs() && !isSafe) { Telemetry::Accumulate(Telemetry::BROWSER_SHIM_USAGE_BLOCKED, 1); JS_ReportErrorASCII(cx, "unsafe CPOW usage forbidden"); return false; } if (addonId) { JSFlatString* flat = JS_ASSERT_STRING_IS_FLAT(JS::StringOfAddonId(addonId)); nsString addonIdString; AssignJSFlatString(addonIdString, flat); NS_ConvertUTF16toUTF8 addonIdCString(addonIdString); Telemetry::Accumulate(Telemetry::ADDON_FORBIDDEN_CPOW_USAGE, addonIdCString); if (ForbidCPOWsInCompatibleAddon(addonIdCString)) { JS_ReportErrorASCII(cx, "CPOW usage forbidden in this add-on"); return false; } warn = true; } } } if (!warn) return true; static bool disableUnsafeCPOWWarnings = PR_GetEnv("DISABLE_UNSAFE_CPOW_WARNINGS"); if (!disableUnsafeCPOWWarnings) { nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID)); if (console && cx) { nsAutoString filename; uint32_t lineno = 0, column = 0; nsJSUtils::GetCallingLocation(cx, filename, &lineno, &column); nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID)); error->Init(NS_LITERAL_STRING("unsafe/forbidden CPOW usage"), filename, EmptyString(), lineno, column, nsIScriptError::warningFlag, "chrome javascript"); console->LogMessage(error); } else { NS_WARNING("Unsafe synchronous IPC message"); } } return true; }