Firefox · DOM
CVE-2025-9179
Memory Corruption in DOM
Overview
High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifdom/media/gmp/ChromiumCDMChild.cpp |
modified | |
ifdom/media/gmp/ChromiumCDMParent.cpp |
modified | |
ifdom/media/gmp/DecryptJob.cpp |
modified |
Files Changed
dom/media/gmp/ChromiumCDMChild.cppdom/media/gmp/ChromiumCDMParent.cppdom/media/gmp/ChromiumCDMParent.hdom/media/gmp/DecryptJob.cppdom/media/gmp/PChromiumCDM.ipdl
Patch
diff --git a/dom/media/gmp/ChromiumCDMChild.cpp b/dom/media/gmp/ChromiumCDMChild.cpp
index c7a6aad89dd..3181a66f514 100644
--- a/dom/media/gmp/ChromiumCDMChild.cpp
+++ b/dom/media/gmp/ChromiumCDMChild.cpp
@@ -645,25 +645,32 @@ mozilla::ipc::IPCResult ChromiumCDMChild::RecvDecrypt(
cdm::Status status = mCDM->Decrypt(input, &output);
// CDM should have allocated a cdm::Buffer for output.
- CDMShmemBuffer* buffer =
- output.DecryptedBuffer()
- ? static_cast<CDMShmemBuffer*>(output.DecryptedBuffer())
- : nullptr;
- MOZ_ASSERT_IF(buffer, buffer->AsShmemBuffer());
- if (status != cdm::kSuccess || !buffer) {
+ if (status != cdm::kSuccess || !output.DecryptedBuffer()) {
Unused << SendDecryptFailed(aId, status);
return IPC_OK();
}
- // Success! Return the decrypted sample to parent.
- MOZ_ASSERT(!HasShmemOfSize(outputShmemSize));
- ipc::Shmem shmem = buffer->ExtractShmem();
- if (SendDecrypted(aId, cdm::kSuccess, std::move(shmem))) {
- // No need to deallocate the output shmem; it should have been returned
- // to the content process.
- autoDeallocateOutputShmem.release();
+ auto* buffer = static_cast<CDMBuffer*>(output.DecryptedBuffer());
+ if (auto* shmemBuffer = buffer->AsShmemBuffer()) {
+ MOZ_ASSERT(!HasShmemOfSize(outputShmemSize));
+ ipc::Shmem shmem = shmemBuffer->ExtractShmem();
+ if (SendDecryptedShmem(aId, cdm::kSuccess, std::move(shmem))) {
+ // No need to deallocate the output shmem; it should have been returned
+ // to the content process.
+ autoDeallocateOutputShmem.release();
+ }
+ return IPC_OK();
+ }
+
+ if (auto* arrayBuffer = buffer->AsArrayBuffer()) {
+ Unused << SendDecryptedData(aId, cdm::kSuccess,
+ arrayBuffer->ExtractBuffer());
+ return IPC_OK();
}
+ MOZ_ASSERT_UNREACHABLE("Unexpected CDMBuffer type!");
+ GMP_LOG_DEBUG("ChromiumCDMChild::RecvDecrypt() unexpected CDMBuffer type");
+ Unused << SendDecryptFailed(aId, cdm::kDecryptError);
return IPC_OK();
}
@@ -805,13 +812,18 @@ void ChromiumCDMChild::ReturnOutput(WidevineVideoFrame& aFrame) {
}
CDMBuffer* base = reinterpret_cast<CDMBuffer*>(aFrame.FrameBuffer());
- if (base->AsShmemBuffer()) {
- ipc::Shmem shmem = base->AsShmemBuffer()->ExtractShmem();
+ if (auto* shmemBase = base->AsShmemBuffer()) {
+ ipc::Shmem shmem = shmemBase->ExtractShmem();
Unused << SendDecodedShmem(output, std::move(shmem));
- } else {
- MOZ_ASSERT(base->AsArrayBuffer());
- Unused << SendDecodedData(output, base->AsArrayBuffer()->ExtractBuffer());
+ return;
}
+
+ if (auto* arrayBase = base->AsArrayBuffer()) {
+ Unused << SendDecodedData(output, arrayBase->ExtractBuffer());
+ return;
+ }
+
+ MOZ_ASSERT_UNREACHABLE("Unexpected CDMBuffer type!");
}
mozilla::ipc::IPCResult ChromiumCDMChild::RecvDrain() {
diff --git a/dom/media/gmp/ChromiumCDMParent.cpp b/dom/media/gmp/ChromiumCDMParent.cpp
index 90a73c89c5b..f1f6bf55bec 100644
--- a/dom/media/gmp/ChromiumCDMParent.cpp
+++ b/dom/media/gmp/ChromiumCDMParent.cpp
@@ -686,11 +686,11 @@ ipc::IPCResult ChromiumCDMParent::RecvDecryptFailed(const uint32_t& aId,
return IPC_OK();
}
-ipc::IPCResult ChromiumCDMParent::RecvDecrypted(const uint32_t& aId,
- const uint32_t& aStatus,
- ipc::Shmem&& aShmem) {
+ipc::IPCResult ChromiumCDMParent::RecvDecryptedShmem(const uint32_t& aId,
+ const uint32_t& aStatus,
+ ipc::Shmem&& aShmem) {
MOZ_ASSERT(mGMPThread->IsOnCurrentThread());
- GMP_LOG_DEBUG("ChromiumCDMParent::RecvDecrypted(this=%p, id=%" PRIu32
+ GMP_LOG_DEBUG("ChromiumCDMParent::RecvDecryptedShmem(this=%p, id=%" PRIu32
", status=%" PRIu32 ")",
this, aId, aStatus);
@@ -704,9 +704,33 @@ ipc::IPCResult ChromiumCDMParent::RecvDecrypted(const uint32_t& aId,
}
for (size_t i = 0; i < mDecrypts.Length(); i++) {
if (mDecrypts[i]->mId == aId) {
- mDecrypts[i]->PostResult(
- ToDecryptStatus(aStatus),
- Span<const uint8_t>(aShmem.get<uint8_t>(), aShmem.Size<uint8_t>()));
+ mDecrypts[i]->PostResult(ToDecryptStatus(aStatus),
+ aShmem.IsReadable()
+ ? Span<const uint8_t>(aShmem.get<uint8_t>(),
+ aShmem.Size<uint8_t>())
+ : Span<const uint8_t>());
+ mDecrypts.RemoveElementAt(i);
+ break;
+ }
+ }
+ return IPC_OK();
+}
+
+ipc::IPCResult ChromiumCDMParent::RecvDecryptedData(const uint32_t& aId,
+ const uint32_t& aStatus,
+ nsTArray<uint8_t>&& aData) {
+ MOZ_ASSERT(mGMPThread->IsOnCurrentThread());
+ GMP_LOG_DEBUG("ChromiumCDMParent::RecvDecryptedData(this=%p, id=%" PRIu32
+ ", status=%" PRIu32 ")",
+ this, aId, aStatus);
+
+ if (mIsShutdown) {
+ MOZ_ASSERT(mDecrypts.IsEmpty());
+ return IPC_OK();
+ }
+ for (size_t i = 0; i < mDecrypts.Length(); i++) {
+ if (mDecrypts[i]->mId == aId) {
+ mDecrypts[i]->PostResult(ToDecryptStatus(aStatus), aData);
mDecrypts.RemoveElementAt(i);
break;
}
diff --git a/dom/media/gmp/ChromiumCDMParent.h b/dom/media/gmp/ChromiumCDMParent.h
index e26512c8a94..88bf64ecb4d 100644
--- a/dom/media/gmp/ChromiumCDMParent.h
+++ b/dom/media/gmp/ChromiumCDMParent.h
@@ -126,8 +126,11 @@ class ChromiumCDMParent final : public PChromiumCDMParent,
const double& aSecondsSinceEpoch);
ipc::IPCResult RecvOnSessionClosed(const nsCString& aSessionId);
ipc::IPCResult RecvOnQueryOutputProtectionStatus();
- ipc::IPCResult RecvDecrypted(const uint32_t& aId, const uint32_t& aStatus,
- ipc::Shmem&& aData);
+ ipc::IPCResult RecvDecryptedShmem(const uint32_t& aId,
+ const uint32_t& aStatus,
+ ipc::Shmem&& aData);
+ ipc::IPCResult RecvDecryptedData(const uint32_t& aId, const uint32_t& aStatus,
+ nsTArray<uint8_t>&& aData);
ipc::IPCResult RecvDecryptFailed(const uint32_t& aId,
const uint32_t& aStatus);
ipc::IPCResult RecvOnDecoderInitDone(const uint32_t& aStatus);
diff --git a/dom/media/gmp/DecryptJob.cpp b/dom/media/gmp/DecryptJob.cpp
index 03fbfdbf0c7..0794faece80 100644
--- a/dom/media/gmp/DecryptJob.cpp
+++ b/dom/media/gmp/DecryptJob.cpp
@@ -28,11 +28,13 @@ void DecryptJob::PostResult(DecryptStatus aResult,
if (aDecryptedData.Length() != mSample->Size()) {
NS_WARNING("CDM returned incorrect number of decrypted bytes");
}
- if (aResult == eme::Ok) {
+ if (aResult == DecryptStatus::Ok) {
UniquePtr<MediaRawDataWriter> writer(mSample->CreateWriter());
- PodCopy(writer->Data(), aDecryptedData.Elements(),
- std::min<size_t>(aDecryptedData.Length(), mSample->Size()));
- } else if (aResult == eme::NoKeyErr) {
+ if (NS_WARN_IF(!writer->Replace(aDecryptedData.Elements(),
+ aDecryptedData.Length()))) {
+ aResult = DecryptStatus::GenericErr;
+ }
+ } else if (aResult == DecryptStatus::NoKeyErr) {
NS_WARNING("CDM returned NoKeyErr");
// We still have the encrypted sample, so we can re-enqueue it to be
// decrypted again once the key is usable again.
diff --git a/dom/media/gmp/PChromiumCDM.ipdl b/dom/media/gmp/PChromiumCDM.ipdl
index 2bd2103477e..e7aaf3bbab8 100644
--- a/dom/media/gmp/PChromiumCDM.ipdl
+++ b/dom/media/gmp/PChromiumCDM.ipdl
@@ -106,7 +106,8 @@ parent:
async ResolveLoadSessionPromise(uint32_t aPromiseId, bool aSuccessful);
// Return values of cdm::ContentDecryptionModule_10::Decrypt
- async Decrypted(uint32_t aId, uint32_t aStatus, Shmem aDecryptedData);
+ async DecryptedShmem(uint32_t aId, uint32_t aStatus, Shmem aData);
+ async DecryptedData(uint32_t aId, uint32_t aStatus, uint8_t[] aData);
async DecryptFailed(uint32_t aId, uint32_t aStatus);
async OnDecoderInitDone(uint32_t aStatus);
Loading diff…
References
On This Page