예제 #1
0
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;
}
예제 #2
0
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;
}
예제 #3
0
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;
}
예제 #4
0
// 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();
}
예제 #5
0
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;
}
예제 #6
0
	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;
			}
		}
	}
예제 #9
0
	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]);
	}
예제 #10
0
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);
	}
예제 #14
0
 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());
 }
예제 #15
0
	virtual void sendStartupInfo(MessageChannel &channel) {
		channel.write("LoggingServer info",
			loggingAgentAddress.c_str(),
			loggingAgentPassword.c_str(),
			NULL);
	}
예제 #16
0
	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);
	}
예제 #19
0
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;
}