Firefox · DOM
CVE-2026-16387
Logic Error in DOM
Overview
Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
RegisterChannelnetwerk/base/RedirectChannelRegistrar.cpp |
modified |
Files Changed
docshell/base/nsDocShell.cppdom/ipc/ContentParent.cppmobile/android/components/geckoview/GeckoViewContentChannelParent.cppnetwerk/base/RedirectChannelRegistrar.cppnetwerk/base/RedirectChannelRegistrar.hnetwerk/base/nsIRedirectChannelRegistrar.idlnetwerk/base/nsNetUtil.cppnetwerk/base/nsNetUtil.hnetwerk/ipc/DocumentLoadListener.cppnetwerk/ipc/NeckoParent.cppnetwerk/ipc/ParentChannelWrapper.cppnetwerk/ipc/ParentChannelWrapper.hnetwerk/ipc/ParentProcessDocumentChannel.cppnetwerk/protocol/http/HttpChannelParent.cpp
Patch
diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp
index f1b0b1f7b6c..9b78ed2be44 100644
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -10433,7 +10433,9 @@ nsresult nsDocShell::OpenRedirectedChannel(nsDocShellLoadState* aLoadState) {
// that forwards functionality as needed, and then we register
// it under the provided identifier.
RefPtr wrapper = MakeRefPtr<ParentChannelWrapper>(channel, loader);
- wrapper->Register(aLoadState->GetPendingRedirectChannelRegistrarId());
+ // We're in the parent process, so the redirect is owned by the parent
+ // process (ContentParentId 0).
+ wrapper->Register(aLoadState->GetPendingRedirectChannelRegistrarId(), 0);
mLoadGroup->AddRequest(channel, nullptr);
} else if (nsCOMPtr<nsIChildChannel> childChannel =
diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp
index 517aa43bd05..a35f7e4e082 100644
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -4846,14 +4846,16 @@ mozilla::ipc::IPCResult ContentParent::RecvExtProtocolChannelConnectParent(
// First get the real channel created before redirect on the parent.
nsCOMPtr<nsIChannel> channel;
- rv = NS_LinkRedirectChannels(registrarId, nullptr, getter_AddRefs(channel));
+ rv = NS_LinkRedirectChannels(registrarId, ChildID(), nullptr,
+ getter_AddRefs(channel));
NS_ENSURE_SUCCESS(rv, IPC_OK());
nsCOMPtr<nsIParentChannel> parent = do_QueryInterface(channel, &rv);
NS_ENSURE_SUCCESS(rv, IPC_OK());
// The channel itself is its own (faked) parent, link it.
- rv = NS_LinkRedirectChannels(registrarId, parent, getter_AddRefs(channel));
+ rv = NS_LinkRedirectChannels(registrarId, ChildID(), parent,
+ getter_AddRefs(channel));
NS_ENSURE_SUCCESS(rv, IPC_OK());
// Signal the parent channel that it's a redirect-to parent. This will
diff --git a/mobile/android/components/geckoview/GeckoViewContentChannelParent.cpp b/mobile/android/components/geckoview/GeckoViewContentChannelParent.cpp
index aa72b5131ca..01d3225f2bc 100644
--- a/mobile/android/components/geckoview/GeckoViewContentChannelParent.cpp
+++ b/mobile/android/components/geckoview/GeckoViewContentChannelParent.cpp
@@ -197,8 +197,10 @@ bool GeckoViewContentChannelParent::Init(
bool GeckoViewContentChannelParent::Init(
const GeckoViewContentChannelConnectArgs& aArgs) {
nsCOMPtr<nsIChannel> channel;
- nsresult rv =
- NS_LinkRedirectChannels(aArgs.channelId(), this, getter_AddRefs(channel));
+ dom::ContentParentId cpId =
+ static_cast<dom::ContentParent*>(Manager()->Manager())->ChildID();
+ nsresult rv = NS_LinkRedirectChannels(aArgs.channelId(), cpId, this,
+ getter_AddRefs(channel));
if (NS_SUCCEEDED(rv)) {
mChannel = channel;
}
diff --git a/netwerk/base/RedirectChannelRegistrar.cpp b/netwerk/base/RedirectChannelRegistrar.cpp
index 9aa687ed88d..8fbc36e4faa 100644
--- a/netwerk/base/RedirectChannelRegistrar.cpp
+++ b/netwerk/base/RedirectChannelRegistrar.cpp
@@ -34,10 +34,12 @@ RedirectChannelRegistrar::GetOrCreate() {
}
NS_IMETHODIMP
-RedirectChannelRegistrar::RegisterChannel(nsIChannel* channel, uint64_t id) {
+RedirectChannelRegistrar::RegisterChannel(nsIChannel* channel, uint64_t id,
+ uint64_t aContentParentId) {
MutexAutoLock lock(mLock);
mRealChannels.InsertOrUpdate(id, channel);
+ mChannelOwners.InsertOrUpdate(id, aContentParentId);
return NS_OK;
}
@@ -53,10 +55,19 @@ RedirectChannelRegistrar::GetRegisteredChannel(uint64_t id,
}
NS_IMETHODIMP
-RedirectChannelRegistrar::LinkChannels(uint64_t id, nsIParentChannel* channel,
+RedirectChannelRegistrar::LinkChannels(uint64_t id, uint64_t aContentParentId,
+ nsIParentChannel* channel,
nsIChannel** _retval) {
MutexAutoLock lock(mLock);
+ // Only hand back the registered channel if it was registered for the
+ // requesting content process, since the id is supplied by the content
+ // process.
+ uint64_t owner;
+ if (!mChannelOwners.Get(id, &owner) || owner != aContentParentId) {
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
if (!mRealChannels.Get(id, _retval)) return NS_ERROR_NOT_AVAILABLE;
mParentChannels.InsertOrUpdate(id, channel);
@@ -79,6 +90,7 @@ RedirectChannelRegistrar::DeregisterChannels(uint64_t id) {
mRealChannels.Remove(id);
mParentChannels.Remove(id);
+ mChannelOwners.Remove(id);
return NS_OK;
}
diff --git a/netwerk/base/RedirectChannelRegistrar.h b/netwerk/base/RedirectChannelRegistrar.h
index 1d5b14a4d71..48acea2c606 100644
--- a/netwerk/base/RedirectChannelRegistrar.h
+++ b/netwerk/base/RedirectChannelRegistrar.h
@@ -10,6 +10,7 @@
#include "nsIChannel.h"
#include "nsIParentChannel.h"
#include "nsInterfaceHashtable.h"
+#include "nsTHashMap.h"
#include "mozilla/Mutex.h"
namespace mozilla {
@@ -35,6 +36,13 @@ class RedirectChannelRegistrar final : public nsIRedirectChannelRegistrar {
ChannelHashtable mRealChannels MOZ_GUARDED_BY(mLock);
ParentChannelHashtable mParentChannels MOZ_GUARDED_BY(mLock);
+
+ // Maps a registered channel id to the ContentParentId (as a raw uint64_t,
+ // 0 for the parent process) of the process the redirect is destined for.
+ // linkChannels refuses to pair a real channel with a parent actor coming
+ // from any other process.
+ nsTHashMap<nsUint64HashKey, uint64_t> mChannelOwners MOZ_GUARDED_BY(mLock);
+
Mutex mLock;
static StaticRefPtr<RedirectChannelRegistrar> gSingleton;
diff --git a/netwerk/base/nsIRedirectChannelRegistrar.idl b/netwerk/base/nsIRedirectChannelRegistrar.idl
index 26dfdf3c6f1..15e522bd883 100644
--- a/netwerk/base/nsIRedirectChannelRegistrar.idl
+++ b/netwerk/base/nsIRedirectChannelRegistrar.idl
@@ -15,30 +15,37 @@ interface nsIParentChannel;
* See also nsIChildChannel and nsIParentChannel.
*/
-[scriptable, uuid (efa36ea2-5b07-46fc-9534-a5acb8b77b72)]
+[scriptable, uuid (1f2c5e0a-9b3d-4d8e-8c4a-6d7e0b1a2c3d)]
interface nsIRedirectChannelRegistrar : nsISupports
{
/**
* Register the redirect target channel. The passed id needs to be a
* unique ID for that channel (see `nsContentUtils::GenerateLoadIdentifier`).
+ * aContentParentId identifies the content process the redirect is destined
+ * for (0 for the parent process); linkChannels will only pair the channel
+ * with a parent actor coming from that same process.
*
* Primarily used in ParentChannelListener::AsyncOnChannelRedirect to get
* a channel id sent to the HttpChannelChild being redirected.
*/
- void registerChannel(in nsIChannel channel, in uint64_t id);
+ void registerChannel(in nsIChannel channel, in uint64_t id,
+ in uint64_t aContentParentId);
/**
- * First, search for the channel registered under the id. If found return
- * it. Then, register under the same id the parent side of IPC protocol
- * to let it be later grabbed back by the originator of the redirect and
- * notifications from the real channel could be forwarded to this parent
- * channel.
+ * First, search for the channel registered under the id. If found, and the
+ * registered channel is owned by aContentParentId, return it. Then, register
+ * under the same id the parent side of IPC protocol to let it be later
+ * grabbed back by the originator of the redirect and notifications from the
+ * real channel could be forwarded to this parent channel. Fails with
+ * NS_ERROR_NOT_AVAILABLE if no channel is registered under the id for the
+ * given content process.
*
* Primarily used in parent side of an IPC protocol implementation
* in reaction to nsIChildChannel.connectParent(id) called from the child
- * process.
+ * process. aContentParentId is the process that made that request.
*/
- nsIChannel linkChannels(in uint64_t id, in nsIParentChannel channel);
+ nsIChannel linkChannels(in uint64_t id, in uint64_t aContentParentId,
+ in nsIParentChannel channel);
/**
* Returns back the channel previously registered under the ID with
diff --git a/netwerk/base/nsNetUtil.cpp b/netwerk/base/nsNetUtil.cpp
index 9941a85331b..5b27e9190c2 100644
--- a/netwerk/base/nsNetUtil.cpp
+++ b/netwerk/base/nsNetUtil.cpp
@@ -2637,14 +2637,15 @@ bool NS_ShouldRemoveAuthHeaderOnRedirect(nsIChannel* aOldChannel,
return NS_FAILED(rv);
}
-nsresult NS_LinkRedirectChannels(uint64_t channelId,
+nsresult NS_LinkRedirectChannels(uint64_t channelId, uint64_t aContentParentId,
nsIParentChannel* parentChannel,
nsIChannel** _result) {
nsCOMPtr<nsIRedirectChannelRegistrar> registrar =
RedirectChannelRegistrar::GetOrCreate();
MOZ_ASSERT(registrar);
- return registrar->LinkChannels(channelId, parentChannel, _result);
+ return registrar->LinkChannels(channelId, aContentParentId, parentChannel,
+ _result);
}
Loading diff…
References
On This Page