Firefox · DOM
CVE-2026-109744
Logic Error in DOM
Overview
Moderate
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifdom/file/FileBlobImpl.cpp |
modified |
Files Changed
dom/file/BaseBlobImpl.hdom/file/BlobImpl.cppdom/file/BlobImpl.hdom/file/FileBlobImpl.cppdom/file/FileBlobImpl.hdom/file/MultipartBlobImpl.hdom/indexedDB/ActorsParent.cpp
Patch
diff --git a/dom/file/BaseBlobImpl.h b/dom/file/BaseBlobImpl.h
index b43e2a31969..28f7dc201d3 100644
--- a/dom/file/BaseBlobImpl.h
+++ b/dom/file/BaseBlobImpl.h
@@ -66,7 +66,7 @@ class BaseBlobImpl : public BlobImpl {
void GetMozFullPathInternal(nsAString& aFileName, ErrorResult& aRv) override;
- uint64_t GetSize(ErrorResult& aRv) override { return mLength; }
+ uint64_t GetSize(ErrorResult& aRv) const override { return mLength; }
void GetType(nsAString& aType) override;
diff --git a/dom/file/BlobImpl.cpp b/dom/file/BlobImpl.cpp
index b561758fab8..38e328ebf23 100644
--- a/dom/file/BlobImpl.cpp
+++ b/dom/file/BlobImpl.cpp
@@ -67,13 +67,16 @@ nsresult BlobImpl::GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength,
ErrorResult rv;
- nsCOMPtr<nsIInputStream> stream;
- CreateInputStream(getter_AddRefs(stream), rv);
+ // Query the size before creating the stream: blobs with a lazy size (e.g.
+ // FileBlobImpl) snapshot it on first use, and the stream handed out below
+ // must be capped at the very same size we declare as the Content-Length.
+ *aContentLength = GetSize(rv);
if (NS_WARN_IF(rv.Failed())) {
return rv.StealNSResult();
}
- *aContentLength = GetSize(rv);
+ nsCOMPtr<nsIInputStream> stream;
+ CreateInputStream(getter_AddRefs(stream), rv);
if (NS_WARN_IF(rv.Failed())) {
return rv.StealNSResult();
}
diff --git a/dom/file/BlobImpl.h b/dom/file/BlobImpl.h
index fea43f77b98..b973b3b69da 100644
--- a/dom/file/BlobImpl.h
+++ b/dom/file/BlobImpl.h
@@ -53,7 +53,7 @@ class BlobImpl : public SupportsThreadSafeWeakPtr<BlobImpl>,
virtual void GetMozFullPathInternal(nsAString& aFileName,
ErrorResult& aRv) = 0;
- virtual uint64_t GetSize(ErrorResult& aRv) = 0;
+ virtual uint64_t GetSize(ErrorResult& aRv) const = 0;
virtual void GetType(nsAString& aType) = 0;
diff --git a/dom/file/FileBlobImpl.cpp b/dom/file/FileBlobImpl.cpp
index 13bd025b9bf..2adad00e896 100644
--- a/dom/file/FileBlobImpl.cpp
+++ b/dom/file/FileBlobImpl.cpp
@@ -134,7 +134,7 @@ void FileBlobImpl::GetMozFullPathInternal(nsAString& aFilename,
mMozFullPath = aFilename;
}
-uint64_t FileBlobImpl::GetSize(ErrorResult& aRv) {
+uint64_t FileBlobImpl::GetSize(ErrorResult& aRv) const {
MutexAutoLock lock(mMutex);
if (mLength.isNothing()) {
@@ -272,6 +272,11 @@ const uint32_t sFileStreamFlags =
void FileBlobImpl::CreateInputStream(nsIInputStream** aStream,
ErrorResult& aRv) const {
+ const uint64_t length = GetSize(aRv);
+ if (NS_WARN_IF(aRv.Failed())) {
+ return;
+ }
+
nsCOMPtr<nsIInputStream> stream;
aRv = NS_NewLocalFileInputStream(getter_AddRefs(stream), mFile, -1, -1,
sFileStreamFlags);
@@ -280,14 +285,14 @@ void FileBlobImpl::CreateInputStream(nsIInputStream** aStream,
}
if (mWholeFile) {
- stream.forget(aStream);
+ RefPtr<SlicedInputStream> slicedInputStream =
+ new SlicedInputStream(stream.forget(), 0, length);
+ slicedInputStream.forget(aStream);
return;
}
- MOZ_ASSERT(mLength.isSome());
-
RefPtr<SlicedInputStream> slicedInputStream =
- new SlicedInputStream(stream.forget(), mStart, mLength.value());
+ new SlicedInputStream(stream.forget(), mStart, length);
slicedInputStream.forget(aStream);
}
diff --git a/dom/file/FileBlobImpl.h b/dom/file/FileBlobImpl.h
index 7a2e606d275..c0b9d86c027 100644
--- a/dom/file/FileBlobImpl.h
+++ b/dom/file/FileBlobImpl.h
@@ -61,7 +61,7 @@ class FileBlobImpl : public BlobImpl {
void GetMozFullPathInternal(nsAString& aFilename, ErrorResult& aRv) override;
- uint64_t GetSize(ErrorResult& aRv) override;
+ uint64_t GetSize(ErrorResult& aRv) const override;
void GetType(nsAString& aType) override;
@@ -127,7 +127,7 @@ class FileBlobImpl : public BlobImpl {
// FileBlobImpl has getter methods with lazy initialization. Because any
// BlobImpl must work thread-safe, we use a mutex.
- Mutex mMutex MOZ_UNANNOTATED;
+ mutable Mutex mMutex MOZ_UNANNOTATED;
nsCOMPtr<nsIFile> mFile;
@@ -141,7 +141,7 @@ class FileBlobImpl : public BlobImpl {
int64_t mFileId;
- Maybe<uint64_t> mLength;
+ mutable Maybe<uint64_t> mLength;
Maybe<int64_t> mLastModified;
diff --git a/dom/file/MultipartBlobImpl.h b/dom/file/MultipartBlobImpl.h
index 131727dd12f..47567de9d52 100644
--- a/dom/file/MultipartBlobImpl.h
+++ b/dom/file/MultipartBlobImpl.h
@@ -56,7 +56,7 @@ class MultipartBlobImpl final : public BaseBlobImpl {
const nsAString& aContentType,
ErrorResult& aRv) const override;
- uint64_t GetSize(ErrorResult& aRv) override { return mLength; }
+ uint64_t GetSize(ErrorResult& aRv) const override { return mLength; }
void CreateInputStream(nsIInputStream** aStream,
ErrorResult& aRv) const override;
diff --git a/dom/indexedDB/ActorsParent.cpp b/dom/indexedDB/ActorsParent.cpp
index 3fd600c60a1..fa7f9b8e0b2 100644
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -5490,7 +5490,7 @@ class EncryptedFileBlobImpl final : public FileBlobImpl {
// only accesses it. And the reason why 0 is returned, even when the size is
// not set in a child process, is is because the spec doesn't allow Blob.size
// to throw.
- uint64_t GetSize(ErrorResult& aRv) override {
+ uint64_t GetSize(ErrorResult& aRv) const override {
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess() || mLength.isSome());
return mLength.valueOr(0);
}
Loading diff…
References
On This Page