Firefox · Networking
CVE-2026-100766
Logic Error in Networking
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
Mutatornetwerk/protocol/res/SubstitutingJARURI.h |
modified | |
ifnetwerk/protocol/res/SubstitutingProtocolHandler.cpp |
modified |
Files Changed
modules/libjar/nsJARURI.cppnetwerk/protocol/res/SubstitutingJARURI.hnetwerk/protocol/res/SubstitutingProtocolHandler.cpp
Patch
diff --git a/modules/libjar/nsJARURI.cpp b/modules/libjar/nsJARURI.cpp
index 65a70e2c558..b14bb34dd55 100644
--- a/modules/libjar/nsJARURI.cpp
+++ b/modules/libjar/nsJARURI.cpp
@@ -685,6 +685,23 @@ nsJARURI::GetInnermostURI(nsIURI** uri) {
return NS_ImplGetInnermostURI(this, uri);
}
+// Make sure the deserialized IPC URL is valid.
+static bool AreJARPartsCanonical(nsIURI* aJARFile, nsIURL* aJAREntry) {
+ nsAutoCString entrySpec;
+ if (NS_FAILED(aJAREntry->GetSpec(entrySpec))) {
+ return false;
+ }
+
+ // Parsing a jar: spec splits it at the last "!/", so an entry can neither
+ // carry a delimiter of its own nor use a scheme other than the bogus one.
+ if (!StringBeginsWith(entrySpec, NS_BOGUS_ENTRY_SCHEME) ||
+ entrySpec.Find(NS_JAR_DELIMITER) != kNotFound) {
+ return false;
+ }
+
+ return true;
+}
+
void nsJARURI::Serialize(URIParams& aParams) {
JARURIParams params;
@@ -721,6 +738,11 @@ bool nsJARURI::Deserialize(const URIParams& aParams) {
return false;
}
+ if (!AreJARPartsCanonical(file, entryURL)) {
+ NS_WARNING("Received structurally invalid jar URI parts!");
+ return false;
+ }
+
mJARFile.swap(file);
mJAREntry.swap(entryURL);
mCharsetHint = params.charset();
diff --git a/netwerk/protocol/res/SubstitutingJARURI.h b/netwerk/protocol/res/SubstitutingJARURI.h
index 0e2e89f7a24..690b10364f1 100644
--- a/netwerk/protocol/res/SubstitutingJARURI.h
+++ b/netwerk/protocol/res/SubstitutingJARURI.h
@@ -200,6 +200,9 @@ class SubstitutingJARURI : public nsIJARURI,
bool Deserialize(const mozilla::ipc::URIParams& aParams);
nsresult ReadPrivate(nsIObjectInputStream* aStream);
+ // Builds the URI aSource resolves to
+ static nsresult ResolveSource(nsIURI* aSource, SubstitutingJARURI** aResult);
+
public:
class Mutator final : public nsIURIMutator,
public BaseURIMutator<SubstitutingJARURI>,
diff --git a/netwerk/protocol/res/SubstitutingProtocolHandler.cpp b/netwerk/protocol/res/SubstitutingProtocolHandler.cpp
index 12bcacd12a7..8aa1a50f0c6 100644
--- a/netwerk/protocol/res/SubstitutingProtocolHandler.cpp
+++ b/netwerk/protocol/res/SubstitutingProtocolHandler.cpp
@@ -172,6 +172,33 @@ size_t SubstitutingJARURI::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) {
return 0;
};
+/* static */
+nsresult SubstitutingJARURI::ResolveSource(nsIURI* aSource,
+ SubstitutingJARURI** aResult) {
+ if (!aSource) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ nsAutoCString spec;
+ nsresult rv = aSource->GetSpec(spec);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsCOMPtr<nsIURI> resolved;
+ rv = NS_NewURI(getter_AddRefs(resolved), spec);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ // Only a substitution carrying the RESOLVE_JAR_URI flag resolves to a
+ // SubstitutingJARURI, and ResolveJARURI has checked that it maps to a local
+ // jar file.
+ RefPtr<SubstitutingJARURI> uri;
+ rv =
+ resolved->QueryInterface(kSubstitutingJARURIImplCID, getter_AddRefs(uri));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ uri.forget(aResult);
+ return NS_OK;
+}
+
// SubstitutingJARURI::nsISerializable
NS_IMETHODIMP
@@ -185,16 +212,21 @@ SubstitutingJARURI::Read(nsIObjectInputStream* aStream) {
rv = aStream->ReadObject(true, getter_AddRefs(source));
NS_ENSURE_SUCCESS(rv, rv);
- mSource = do_QueryInterface(source, &rv);
- NS_ENSURE_SUCCESS(rv, rv);
-
+ // Read the resolved URI too so the stream stays in sync, but don't use it.
nsCOMPtr<nsISupports> resolved;
rv = aStream->ReadObject(true, getter_AddRefs(resolved));
NS_ENSURE_SUCCESS(rv, rv);
- mResolved = do_QueryInterface(resolved, &rv);
+ nsCOMPtr<nsIURI> sourceURI = do_QueryInterface(source, &rv);
NS_ENSURE_SUCCESS(rv, rv);
+ RefPtr<SubstitutingJARURI> uri;
+ rv = ResolveSource(sourceURI, getter_AddRefs(uri));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ mSource = uri->mSource;
+ mResolved = uri->mResolved;
+
return NS_OK;
}
@@ -267,15 +299,16 @@ bool SubstitutingJARURI::Deserialize(const mozilla::ipc::URIParams& aParams) {
const SubstitutingJARURIParams& jarUriParams =
aParams.get_SubstitutingJARURIParams();
+ // The resolved URI in the params is deliberately ignored, see ResolveSource.
nsCOMPtr<nsIURI> source = DeserializeURI(jarUriParams.source());
- nsresult rv;
- mSource = do_QueryInterface(source, &rv);
- if (NS_FAILED(rv)) {
+ RefPtr<SubstitutingJARURI> uri;
+ if (NS_FAILED(ResolveSource(source, getter_AddRefs(uri)))) {
return false;
}
- nsCOMPtr<nsIURI> jarUri = DeserializeURI(jarUriParams.resolved());
- mResolved = do_QueryInterface(jarUri, &rv);
- return NS_SUCCEEDED(rv);
+
+ mSource = uri->mSource;
+ mResolved = uri->mResolved;
+ return true;
}
nsresult SubstitutingJARURI::ReadPrivate(nsIObjectInputStream* aStream) {
Loading diff…
References
On This Page