diff --git a/ipc/glue/Endpoint.cpp b/ipc/glue/Endpoint.cpp index 38af3c3915b2..3391f8b359f7 100644 --- a/ipc/glue/Endpoint.cpp +++ b/ipc/glue/Endpoint.cpp @@ -145,3 +145,23 @@ bool IPDLParamTraits::Read(IPC::MessageReader* aReader, } } // namespace mozilla::ipc + +namespace IPC { + +void ParamTraits::Write(MessageWriter* aWriter, + paramType&& aParam) { + IPC::WriteParam(aWriter, std::move(aParam.mPort)); + IPC::WriteParam(aWriter, aParam.mMessageChannelId); + IPC::WriteParam(aWriter, aParam.mMyPid); + IPC::WriteParam(aWriter, aParam.mOtherPid); +} + +bool ParamTraits::Read(MessageReader* aReader, + paramType* aResult) { + return IPC::ReadParam(aReader, &aResult->mPort) && + IPC::ReadParam(aReader, &aResult->mMessageChannelId) && + IPC::ReadParam(aReader, &aResult->mMyPid) && + IPC::ReadParam(aReader, &aResult->mOtherPid); +} + +} // namespace IPC diff --git a/ipc/glue/Endpoint.h b/ipc/glue/Endpoint.h index 9da641075696..d7eea94dfc60 100644 --- a/ipc/glue/Endpoint.h +++ b/ipc/glue/Endpoint.h @@ -52,9 +52,13 @@ class UntypedEndpoint { UntypedEndpoint() = default; UntypedEndpoint(const PrivateIPDLInterface&, ScopedPort aPort, + const nsID& aMessageChannelId, ProcessId aMyPid = base::kInvalidProcessId, ProcessId aOtherPid = base::kInvalidProcessId) - : mPort(std::move(aPort)), mMyPid(aMyPid), mOtherPid(aOtherPid) {} + : mPort(std::move(aPort)), + mMessageChannelId(aMessageChannelId), + mMyPid(aMyPid), + mOtherPid(aOtherPid) {} UntypedEndpoint(const UntypedEndpoint&) = delete; UntypedEndpoint(UntypedEndpoint&& aOther) = default; @@ -74,7 +78,8 @@ class UntypedEndpoint { MOZ_RELEASE_ASSERT(mMyPid == base::kInvalidProcessId || mMyPid == base::GetCurrentProcId()); MOZ_RELEASE_ASSERT(!aEventTarget || aEventTarget->IsOnCurrentThread()); - return aActor->Open(std::move(mPort), mOtherPid, aEventTarget); + return aActor->Open(std::move(mPort), mMessageChannelId, mOtherPid, + aEventTarget); } bool IsValid() const { return mPort.IsValid(); } @@ -83,6 +88,7 @@ class UntypedEndpoint { friend struct IPC::ParamTraits; ScopedPort mPort; + nsID mMessageChannelId{}; ProcessId mMyPid = base::kInvalidProcessId; ProcessId mOtherPid = base::kInvalidProcessId; }; @@ -157,8 +163,11 @@ nsresult CreateEndpoints(const PrivateIPDLInterface& aPrivate, auto [parentPort, childPort] = NodeController::GetSingleton()->CreatePortPair(); - *aParentEndpoint = Endpoint(aPrivate, std::move(parentPort)); - *aChildEndpoint = Endpoint(aPrivate, std::move(childPort)); + nsID channelId = nsID::GenerateUUID(); + *aParentEndpoint = + Endpoint(aPrivate, std::move(parentPort), channelId); + *aChildEndpoint = + Endpoint(aPrivate, std::move(childPort), channelId); return NS_OK; } @@ -173,10 +182,12 @@ nsresult CreateEndpoints(const PrivateIPDLInterface& aPrivate, auto [parentPort, childPort] = NodeController::GetSingleton()->CreatePortPair(); - *aParentEndpoint = Endpoint(aPrivate, std::move(parentPort), - aParentDestPid, aChildDestPid); - *aChildEndpoint = Endpoint(aPrivate, std::move(childPort), - aChildDestPid, aParentDestPid); + nsID channelId = nsID::GenerateUUID(); + *aParentEndpoint = + Endpoint(aPrivate, std::move(parentPort), channelId, + aParentDestPid, aChildDestPid); + *aChildEndpoint = Endpoint( + aPrivate, std::move(childPort), channelId, aChildDestPid, aParentDestPid); return NS_OK; } diff --git a/ipc/glue/GeckoChildProcessHost.cpp b/ipc/glue/GeckoChildProcessHost.cpp index 6925c41e19c9..6a824d4c542b 100644 --- a/ipc/glue/GeckoChildProcessHost.cpp +++ b/ipc/glue/GeckoChildProcessHost.cpp @@ -171,6 +171,7 @@ class BaseProcessLauncher { mTmpDirName(aHost->mTmpDirName), mChildId(++gChildCounter) { SprintfLiteral(mPidString, "%" PRIPID, base::GetCurrentProcId()); + aHost->mInitialChannelId.ToProvidedString(mInitialChannelIdString); // Compute the serial event target we'll use for launching. nsCOMPtr threadOrPool = GetIPCLauncher(); @@ -237,6 +238,7 @@ class BaseProcessLauncher { int32_t mChildId; TimeStamp mStartTimeStamp = TimeStamp::Now(); char mPidString[32]; + char mInitialChannelIdString[NSID_LENGTH]; // Set during launch. IPC::Channel::ChannelId mChannelId; @@ -386,6 +388,7 @@ GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType, mIsFileContent(aIsFileContent), mMonitor("mozilla.ipc.GeckChildProcessHost.mMonitor"), mLaunchOptions(MakeUnique()), + mInitialChannelId(nsID::GenerateUUID()), mProcessState(CREATING_CHANNEL), #ifdef XP_WIN mGroupId(u"-"), @@ -1209,6 +1212,8 @@ bool PosixProcessLauncher::DoSetup() { # endif } + mChildArgv.push_back(mInitialChannelIdString); + mChildArgv.push_back(mPidString); if (!CrashReporter::IsDummy()) { @@ -1488,6 +1493,9 @@ bool WindowsProcessLauncher::DoSetup() { // Win app model id mCmdLine->AppendLooseValue(mGroupId.get()); + // Initial MessageChannel id + mCmdLine->AppendLooseValue(UTF8ToWide(mInitialChannelIdString)); + // Process id mCmdLine->AppendLooseValue(UTF8ToWide(mPidString)); diff --git a/ipc/glue/GeckoChildProcessHost.h b/ipc/glue/GeckoChildProcessHost.h index 5d19b480c795..06f5c48e3754 100644 --- a/ipc/glue/GeckoChildProcessHost.h +++ b/ipc/glue/GeckoChildProcessHost.h @@ -130,7 +130,7 @@ class GeckoChildProcessHost : public ChildProcessHost, UntypedEndpoint TakeInitialEndpoint() { return UntypedEndpoint{PrivateIPDLInterface{}, std::move(mInitialPort), - base::GetCurrentProcId(), + mInitialChannelId, base::GetCurrentProcId(), base::GetProcId(mChildProcessHandle)}; } @@ -203,6 +203,7 @@ class GeckoChildProcessHost : public ChildProcessHost, // is set to null to free the options after the child is launched. UniquePtr mLaunchOptions; ScopedPort mInitialPort; + nsID mInitialChannelId; RefPtr mNodeController; RefPtr mNodeChannel; diff --git a/ipc/glue/MessageChannel.cpp b/ipc/glue/MessageChannel.cpp index 6ec6cac81304..fa08022149d8 100644 --- a/ipc/glue/MessageChannel.cpp +++ b/ipc/glue/MessageChannel.cpp @@ -642,6 +642,7 @@ void MessageChannel::Clear() { } bool MessageChannel::Open(ScopedPort aPort, Side aSide, + const nsID& aMessageChannelId, nsISerialEventTarget* aEventTarget) { nsCOMPtr eventTarget = aEventTarget ? aEventTarget : GetCurrentSerialEventTarget(); @@ -669,6 +670,7 @@ bool MessageChannel::Open(ScopedPort aPort, Side aSide, MOZ_RELEASE_ASSERT(ChannelClosed == mChannelState, "Not currently closed"); MOZ_ASSERT(mSide == UnknownSide); + mMessageChannelId = aMessageChannelId; mWorkerThread = eventTarget; mShutdownTask = shutdownTask; mLink = MakeUnique(this, std::move(aPort)); @@ -706,6 +708,8 @@ bool MessageChannel::Open(MessageChannel* aTargetChan, MOZ_ASSERT(aTargetChan, "Need a target channel"); + nsID channelId = nsID::GenerateUUID(); + std::pair ports = NodeController::GetSingleton()->CreatePortPair(); @@ -717,7 +721,7 @@ bool MessageChannel::Open(MessageChannel* aTargetChan, /* initially_signaled */ false); MOZ_ALWAYS_SUCCEEDS(aEventTarget->Dispatch(NS_NewCancelableRunnableFunction( "ipc::MessageChannel::OpenAsOtherThread", [&]() { - aTargetChan->Open(std::move(ports.second), GetOppSide(aSide), + aTargetChan->Open(std::move(ports.second), GetOppSide(aSide), channelId, aEventTarget); event.Signal(); }))); @@ -725,20 +729,22 @@ bool MessageChannel::Open(MessageChannel* aTargetChan, MOZ_RELEASE_ASSERT(ok); // Now that the other side has connected, open the port on our side. - return Open(std::move(ports.first), aSide); + return Open(std::move(ports.first), aSide, channelId); } bool MessageChannel::OpenOnSameThread(MessageChannel* aTargetChan, mozilla::ipc::Side aSide) { auto [porta, portb] = NodeController::GetSingleton()->CreatePortPair(); + nsID channelId = nsID::GenerateUUID(); + aTargetChan->mIsSameThreadChannel = true; mIsSameThreadChannel = true; auto* currentThread = GetCurrentSerialEventTarget(); - return aTargetChan->Open(std::move(portb), GetOppSide(aSide), + return aTargetChan->Open(std::move(portb), GetOppSide(aSide), channelId, currentThread) && - Open(std::move(porta), aSide, currentThread); + Open(std::move(porta), aSide, channelId, currentThread); } bool MessageChannel::Send(UniquePtr aMsg) { diff --git a/ipc/glue/MessageChannel.h b/ipc/glue/MessageChannel.h index 7a0882d04e0c..c7143fe38694 100644 --- a/ipc/glue/MessageChannel.h +++ b/ipc/glue/MessageChannel.h @@ -169,7 +169,7 @@ class MessageChannel : HasResultCodes { // valid and connected to a remote. // // The `aEventTarget` parameter must be on the current thread. - bool Open(ScopedPort aPort, Side aSide, + bool Open(ScopedPort aPort, Side aSide, const nsID& aMessageChannelId, nsISerialEventTarget* aEventTarget = nullptr); // "Open" a connection to another thread in the same process. @@ -314,6 +314,11 @@ class MessageChannel : HasResultCodes { bool IsCrossProcess() const MOZ_REQUIRES(*mMonitor); void SetIsCrossProcess(bool aIsCrossProcess) MOZ_REQUIRES(*mMonitor); + nsID GetMessageChannelId() const { + MonitorAutoLock lock(*mMonitor); + return mMessageChannelId; + } + #ifdef FUZZING_SNAPSHOT Maybe GetPortName() { MonitorAutoLock lock(*mMonitor); @@ -584,6 +589,13 @@ class MessageChannel : HasResultCodes { // This will be a string literal, so lifetime is not an issue. const char* const mName; + // ID for each MessageChannel. Set when it is opened, and never cleared + // afterwards. + // + // This ID is only intended for diagnostics, debugging, and reporting + // purposes, and shouldn't be used for message routing or permissions checks. + nsID mMessageChannelId MOZ_GUARDED_BY(*mMonitor) = {}; + // Based on presumption the listener owns and overlives the channel, // this is never nullified. IToplevelProtocol* const mListener; diff --git a/ipc/glue/ProcessChild.cpp b/ipc/glue/ProcessChild.cpp index a13d51c09ca0..13ff88484c6f 100644 --- a/ipc/glue/ProcessChild.cpp +++ b/ipc/glue/ProcessChild.cpp @@ -28,10 +28,11 @@ ProcessChild* ProcessChild::gProcessChild; static Atomic sExpectingShutdown(false); -ProcessChild::ProcessChild(ProcessId aParentPid) +ProcessChild::ProcessChild(ProcessId aParentPid, const nsID& aMessageChannelId) : ChildProcess(new IOThreadChild()), mUILoop(MessageLoop::current()), - mParentPid(aParentPid) { + mParentPid(aParentPid), + mMessageChannelId(aMessageChannelId) { MOZ_ASSERT(mUILoop, "UILoop should be created by now"); MOZ_ASSERT(!gProcessChild, "should only be one ProcessChild"); gProcessChild = this; @@ -86,7 +87,7 @@ void ProcessChild::QuickExit() { AppShutdown::DoImmediateExit(); } UntypedEndpoint ProcessChild::TakeInitialEndpoint() { return UntypedEndpoint{PrivateIPDLInterface{}, - child_thread()->TakeInitialPort(), + child_thread()->TakeInitialPort(), mMessageChannelId, base::GetCurrentProcId(), mParentPid}; } diff --git a/ipc/glue/ProcessChild.h b/ipc/glue/ProcessChild.h index 5118eff5e570..29948a912730 100644 --- a/ipc/glue/ProcessChild.h +++ b/ipc/glue/ProcessChild.h @@ -27,7 +27,7 @@ class ProcessChild : public ChildProcess { typedef base::ProcessId ProcessId; public: - explicit ProcessChild(ProcessId aParentPid); + explicit ProcessChild(ProcessId aParentPid, const nsID& aMessageChannelId); ProcessChild(const ProcessChild&) = delete; ProcessChild& operator=(const ProcessChild&) = delete; @@ -66,6 +66,7 @@ class ProcessChild : public ChildProcess { MessageLoop* mUILoop; ProcessId mParentPid; + nsID mMessageChannelId; }; } // namespace ipc diff --git a/ipc/glue/ProtocolMessageUtils.h b/ipc/glue/ProtocolMessageUtils.h index fc9788373120..33a2c0c4f640 100644 --- a/ipc/glue/ProtocolMessageUtils.h +++ b/ipc/glue/ProtocolMessageUtils.h @@ -71,17 +71,9 @@ template <> struct ParamTraits { using paramType = mozilla::ipc::UntypedEndpoint; - static void Write(MessageWriter* aWriter, paramType&& aParam) { - IPC::WriteParam(aWriter, std::move(aParam.mPort)); - IPC::WriteParam(aWriter, aParam.mMyPid); - IPC::WriteParam(aWriter, aParam.mOtherPid); - } + static void Write(MessageWriter* aWriter, paramType&& aParam); - static bool Read(MessageReader* aReader, paramType* aResult) { - return IPC::ReadParam(aReader, &aResult->mPort) && - IPC::ReadParam(aReader, &aResult->mMyPid) && - IPC::ReadParam(aReader, &aResult->mOtherPid); - } + static bool Read(MessageReader* aReader, paramType* aResult); static void Log(const paramType& aParam, std::wstring* aLog) { aLog->append(StringPrintf(L"Endpoint")); diff --git a/ipc/glue/ProtocolUtils.cpp b/ipc/glue/ProtocolUtils.cpp index c04dfe2e7bb8..b06c7af6b970 100644 --- a/ipc/glue/ProtocolUtils.cpp +++ b/ipc/glue/ProtocolUtils.cpp @@ -597,10 +597,12 @@ void IToplevelProtocol::SetOtherProcessId(base::ProcessId aOtherPid) { mOtherPid = aOtherPid; } -bool IToplevelProtocol::Open(ScopedPort aPort, base::ProcessId aOtherPid, +bool IToplevelProtocol::Open(ScopedPort aPort, const nsID& aMessageChannelId, + base::ProcessId aOtherPid, nsISerialEventTarget* aEventTarget) { SetOtherProcessId(aOtherPid); - return GetIPCChannel()->Open(std::move(aPort), mSide, aEventTarget); + return GetIPCChannel()->Open(std::move(aPort), mSide, aMessageChannelId, + aEventTarget); } bool IToplevelProtocol::Open(IToplevelProtocol* aTarget, diff --git a/ipc/glue/ProtocolUtils.h b/ipc/glue/ProtocolUtils.h index db1d4c56f9f8..4753486cd836 100644 --- a/ipc/glue/ProtocolUtils.h +++ b/ipc/glue/ProtocolUtils.h @@ -414,7 +414,8 @@ class IToplevelProtocol : public IProtocol { virtual void OnChannelError() = 0; virtual void ProcessingError(Result aError, const char* aMsgName) {} - bool Open(ScopedPort aPort, base::ProcessId aOtherPid, + bool Open(ScopedPort aPort, const nsID& aMessageChannelId, + base::ProcessId aOtherPid, nsISerialEventTarget* aEventTarget = nullptr); bool Open(IToplevelProtocol* aTarget, nsISerialEventTarget* aEventTarget, diff --git a/ipc/ipdl/test/gtest/IPDLUnitTest.cpp b/ipc/ipdl/test/gtest/IPDLUnitTest.cpp index 6181919328fa..66e0149dcb65 100644 --- a/ipc/ipdl/test/gtest/IPDLUnitTest.cpp +++ b/ipc/ipdl/test/gtest/IPDLUnitTest.cpp @@ -101,13 +101,14 @@ IPDLUnitTestParent::~IPDLUnitTestParent() { bool IPDLUnitTestParent::Start(const char* aName, ipc::IToplevelProtocol* aActor) { + nsID channelId = nsID::GenerateUUID(); auto [parentPort, childPort] = ipc::NodeController::GetSingleton()->CreatePortPair(); - if (!SendStart(nsDependentCString(aName), std::move(childPort))) { + if (!SendStart(nsDependentCString(aName), std::move(childPort), channelId)) { ADD_FAILURE() << "IPDLUnitTestParent::SendStart failed"; return false; } - if (!aActor->Open(std::move(parentPort), OtherPid())) { + if (!aActor->Open(std::move(parentPort), channelId, OtherPid())) { ADD_FAILURE() << "Unable to open parent actor"; return false; } @@ -160,7 +161,8 @@ void IPDLUnitTestParent::KillHard() { } ipc::IPCResult IPDLUnitTestChild::RecvStart(const nsCString& aName, - ipc::ScopedPort aPort) { + ipc::ScopedPort aPort, + const nsID& aMessageChannelId) { auto* allocChildActor = sAllocChildActorRegistry[std::string_view{aName.get()}]; if (!allocChildActor) { @@ -174,7 +176,7 @@ ipc::IPCResult IPDLUnitTestChild::RecvStart(const nsCString& aName, mojo::core::ports::PortRef port = aPort.Port(); auto* child = allocChildActor(); - if (!child->Open(std::move(aPort), OtherPid())) { + if (!child->Open(std::move(aPort), aMessageChannelId, OtherPid())) { ADD_FAILURE() << "Unable to open child actor"; return IPC_FAIL(this, "Unable to open child actor"); } @@ -291,13 +293,14 @@ class IPDLUnitTestProcessChild : public ipc::ProcessChild { // Defined in nsEmbedFunctions.cpp extern UniquePtr (*gMakeIPDLUnitTestProcessChild)( - base::ProcessId); + base::ProcessId, const nsID&); // Initialize gMakeIPDLUnitTestProcessChild in a static constructor. int _childProcessEntryPointStaticConstructor = ([] { gMakeIPDLUnitTestProcessChild = - [](base::ProcessId aParentPid) -> UniquePtr { - return MakeUnique(aParentPid); + [](base::ProcessId aParentPid, + const nsID& aMessageChannelId) -> UniquePtr { + return MakeUnique(aParentPid, aMessageChannelId); }; return 0; })(); diff --git a/ipc/ipdl/test/gtest/IPDLUnitTestChild.h b/ipc/ipdl/test/gtest/IPDLUnitTestChild.h index 62fcd93cc960..3f9243b2745d 100644 --- a/ipc/ipdl/test/gtest/IPDLUnitTestChild.h +++ b/ipc/ipdl/test/gtest/IPDLUnitTestChild.h @@ -19,7 +19,8 @@ class IPDLUnitTestChild : public PIPDLUnitTestChild { private: friend class PIPDLUnitTestChild; - ipc::IPCResult RecvStart(const nsCString& aName, ipc::ScopedPort aPort); + ipc::IPCResult RecvStart(const nsCString& aName, ipc::ScopedPort aPort, + const nsID& aChannelId); void ActorDestroy(ActorDestroyReason aReason) override; diff --git a/ipc/ipdl/test/gtest/PIPDLUnitTest.ipdl b/ipc/ipdl/test/gtest/PIPDLUnitTest.ipdl index fc2fad72dbef..2f06bccac8d0 100644 --- a/ipc/ipdl/test/gtest/PIPDLUnitTest.ipdl +++ b/ipc/ipdl/test/gtest/PIPDLUnitTest.ipdl @@ -4,6 +4,7 @@ using mozilla::dom::NativeThreadId from "mozilla/dom/NativeThreadId.h"; [MoveOnly] using class mozilla::ipc::ScopedPort from "mozilla/ipc/ScopedPort.h"; +using struct nsID from "nsID.h"; namespace mozilla { namespace _ipdltest { @@ -21,7 +22,7 @@ struct TestPartResult { // Primary actor for the IPDLUnitTest process and thread. [NeedsOtherPid] async protocol PIPDLUnitTest { child: - async Start(nsCString name, ScopedPort port); + async Start(nsCString name, ScopedPort port, nsID channelId); parent: async Report(TestPartResult result); diff --git a/toolkit/xre/nsEmbedFunctions.cpp b/toolkit/xre/nsEmbedFunctions.cpp index f05f94df0c62..8cb1132d01b8 100644 --- a/toolkit/xre/nsEmbedFunctions.cpp +++ b/toolkit/xre/nsEmbedFunctions.cpp @@ -157,7 +157,7 @@ using mozilla::startup::sChildProcessType; namespace mozilla::_ipdltest { // Set in IPDLUnitTest.cpp when running gtests. UniquePtr (*gMakeIPDLUnitTestProcessChild)( - base::ProcessId) = nullptr; + base::ProcessId, const nsID&) = nullptr; } // namespace mozilla::_ipdltest static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID); @@ -553,6 +553,16 @@ nsresult XRE_InitChildProcess(int aArgc, char* aArgv[], base::ProcessId parentPID = strtol(parentPIDString, &end, 10); MOZ_ASSERT(!*end, "invalid parent PID"); + // They also get the initial message channel ID passed in the same manner. + const char* const messageChannelIdString = aArgv[aArgc - 1]; + MOZ_ASSERT(messageChannelIdString, "NULL MessageChannel Id"); + --aArgc; + + nsID messageChannelId{}; + if (!messageChannelId.Parse(messageChannelIdString)) { + return NS_ERROR_FAILURE; + } + #if defined(XP_WIN) // On Win7+, when not running as an MSIX package, register the application // user model id passed in by parent. This ensures windows created by the @@ -649,44 +659,50 @@ nsresult XRE_InitChildProcess(int aArgc, char* aArgv[], case GeckoProcessType_Content: ioInterposerGuard.emplace(); - process = MakeUnique(parentPID); + process = MakeUnique(parentPID, messageChannelId); break; case GeckoProcessType_IPDLUnitTest: MOZ_RELEASE_ASSERT(mozilla::_ipdltest::gMakeIPDLUnitTestProcessChild, "xul-gtest not loaded!"); - process = - mozilla::_ipdltest::gMakeIPDLUnitTestProcessChild(parentPID); + process = mozilla::_ipdltest::gMakeIPDLUnitTestProcessChild( + parentPID, messageChannelId); break; case GeckoProcessType_GMPlugin: - process = MakeUnique(parentPID); + process = + MakeUnique(parentPID, messageChannelId); break; case GeckoProcessType_GPU: - process = MakeUnique(parentPID); + process = + MakeUnique(parentPID, messageChannelId); break; case GeckoProcessType_VR: - process = MakeUnique(parentPID); + process = + MakeUnique(parentPID, messageChannelId); break; case GeckoProcessType_RDD: - process = MakeUnique(parentPID); + process = MakeUnique(parentPID, messageChannelId); break; case GeckoProcessType_Socket: ioInterposerGuard.emplace(); - process = MakeUnique(parentPID); + process = + MakeUnique(parentPID, messageChannelId); break; case GeckoProcessType_Utility: - process = MakeUnique(parentPID); + process = + MakeUnique(parentPID, messageChannelId); break; #if defined(MOZ_SANDBOX) && defined(XP_WIN) case GeckoProcessType_RemoteSandboxBroker: - process = MakeUnique(parentPID); + process = MakeUnique( + parentPID, messageChannelId); break; #endif