commit 0bbe44dca1adbb9348458d1bb0fce2c4afdca5e6
parent 4c3085209276b3265e6970307ca9d03f94d60b2d
Author: alwu <alwu@mozilla.com>
Date: Thu, 23 Oct 2025 18:13:14 +0000
Bug 1891952 - avoid dereferencing a null factory and ensure IMFExtendedDRMTypeSupport remains alive during usage. r=jolin
`sMediaEngineClassFactory` is created in `MFCDMParent::LoadFactory()` and
destroyed in `MFCDMParent::Shutdown()`. Other methods that access the factory
should always verify that the factory is valid before use, and ensure it stays
alive for the duration of its usage.
Differential Revision: https://phabricator.services.mozilla.com/D268452
Diffstat:
1 file changed, 41 insertions(+), 36 deletions(-)
diff --git a/dom/media/ipc/MFCDMParent.cpp b/dom/media/ipc/MFCDMParent.cpp
@@ -662,12 +662,13 @@ static nsString GetRobustnessStringForKeySystem(const nsString& aKeySystem,
// equivalent.
// https://learn.microsoft.com/en-us/uwp/api/windows.media.protection.protectioncapabilities.istypesupported?view=winrt-22621
// https://learn.microsoft.com/en-us/windows/win32/api/mfmediaengine/nf-mfmediaengine-imfextendeddrmtypesupport-istypesupportedex
-static bool FactorySupports(ComPtr<IMFContentDecryptionModuleFactory>& aFactory,
- const nsString& aKeySystem,
- const nsCString& aVideoCodec,
- const nsCString& aAudioCodec = nsCString(""),
- const nsString& aAdditionalFeatures = nsString(u""),
- bool aIsHWSecure = false) {
+static bool FactorySupports(
+ ComPtr<IMFContentDecryptionModuleFactory>& aFactory,
+ ComPtr<IMFExtendedDRMTypeSupport>& aExtendedDrmTypeSupport,
+ const nsString& aKeySystem, const nsCString& aVideoCodec,
+ const nsCString& aAudioCodec = nsCString(""),
+ const nsString& aAdditionalFeatures = nsString(u""),
+ bool aIsHWSecure = false) {
// Create query string, MP4 is the only container supported.
nsString contentType(u"video/mp4;codecs=\"");
MOZ_ASSERT(!aVideoCodec.IsEmpty());
@@ -700,24 +701,19 @@ static bool FactorySupports(ComPtr<IMFContentDecryptionModuleFactory>& aFactory,
// PlayReady doesn't implement IsTypeSupported properly, so it requires us to
// use another way to check the capabilities.
if (IsPlayReadyKeySystemAndSupported(aKeySystem)) {
- ComPtr<IMFExtendedDRMTypeSupport> spDrmTypeSupport;
- {
- auto mediaEngineClassFactory = sMediaEngineClassFactory.Lock();
- MFCDM_RETURN_BOOL_IF_FAILED(
- (*mediaEngineClassFactory).As(&spDrmTypeSupport));
- }
+ MOZ_ASSERT(aExtendedDrmTypeSupport);
BSTR keySystem = aIsHWSecure
? CreateBSTRFromConstChar(kPlayReadyKeySystemHardware)
: CreateBSTRFromConstChar(kPlayReadyKeySystemName);
MF_MEDIA_ENGINE_CANPLAY canPlay;
- spDrmTypeSupport->IsTypeSupportedEx(SysAllocString(contentType.get()),
- keySystem, &canPlay);
+ aExtendedDrmTypeSupport->IsTypeSupportedEx(
+ SysAllocString(contentType.get()), keySystem, &canPlay);
bool support =
canPlay !=
MF_MEDIA_ENGINE_CANPLAY::MF_MEDIA_ENGINE_CANPLAY_NOT_SUPPORTED;
- MFCDM_PARENT_SLOG("IsTypeSupportedEx=%d (key-system=%ls, content-type=%s)",
- support, keySystem,
- NS_ConvertUTF16toUTF8(contentType).get());
+ MFCDM_PARENT_SLOG(
+ "IsTypeSupportedEx=%d, canPlay=%d (key-system=%ls, content-type=%s)",
+ support, canPlay, keySystem, NS_ConvertUTF16toUTF8(contentType).get());
if (aIsHWSecure && support) {
// For HWDRM, `IsTypeSupportedEx` might still return the wrong answer on
// certain devices, so we need to create a dummy CDM to see if the HWDRM
@@ -792,14 +788,13 @@ static MF_MEDIA_ENGINE_CANPLAY RunHDCPSupportCheck(
getHDCPPolicyValue(aMinHdcpVersion));
MOZ_ASSERT(!contentType.IsEmpty());
ComPtr<IMFExtendedDRMTypeSupport> spDrmTypeSupport;
- {
- auto mediaEngineClassFactory = sMediaEngineClassFactory.Lock();
- HRESULT rv = (*mediaEngineClassFactory).As(&spDrmTypeSupport);
- if (FAILED(rv)) {
- MFCDM_PARENT_SLOG("Failed to get IMFExtendedDRMTypeSupport!");
- return MF_MEDIA_ENGINE_CANPLAY_NOT_SUPPORTED;
- }
+ auto mediaEngineClassFactory = sMediaEngineClassFactory.Lock();
+ if (!*mediaEngineClassFactory ||
+ FAILED((*mediaEngineClassFactory).As(&spDrmTypeSupport))) {
+ MFCDM_PARENT_SLOG("Failed to get IMFExtendedDRMTypeSupport!");
+ return MF_MEDIA_ENGINE_CANPLAY_NOT_SUPPORTED;
}
+
// Remove clearlead postfix if needed.
nsCString keySystemWithoutPostfix =
NS_ConvertUTF16toUTF8(MapKeySystem(aKeySystem));
@@ -966,11 +961,6 @@ void MFCDMParent::GetCapabilities(const nsString& aKeySystem,
return;
}
- ComPtr<IMFContentDecryptionModuleFactory> factory = aFactory;
- if (!factory) {
- RETURN_VOID_IF_FAILED(GetOrCreateFactory(aKeySystem, factory));
- }
-
auto capabilitiesUnlocked = sCapabilities.Lock();
for (auto& capabilities : *capabilitiesUnlocked) {
if (capabilities.keySystem().Equals(aKeySystem) &&
@@ -987,6 +977,19 @@ void MFCDMParent::GetCapabilities(const nsString& aKeySystem,
"Query capabilities for %s from the factory (hardwareDecryption=%d)",
NS_ConvertUTF16toUTF8(aKeySystem).get(), isHardwareDecryption);
+ ComPtr<IMFContentDecryptionModuleFactory> factory = aFactory;
+ if (!factory) {
+ RETURN_VOID_IF_FAILED(GetOrCreateFactory(aKeySystem, factory));
+ }
+
+ ComPtr<IMFExtendedDRMTypeSupport> spDrmTypeSupport;
+ auto mediaEngineClassFactory = sMediaEngineClassFactory.Lock();
+ if (!*mediaEngineClassFactory ||
+ FAILED((*mediaEngineClassFactory).As(&spDrmTypeSupport))) {
+ MFCDM_PARENT_SLOG("Failed to get IMFExtendedDRMTypeSupport!");
+ return;
+ }
+
// Widevine requires codec type to be four CC, PlayReady is fine with both.
static auto convertCodecToFourCC =
[](const KeySystemConfig::EMECodecString& aCodec) {
@@ -1058,7 +1061,7 @@ void MFCDMParent::GetCapabilities(const nsString& aKeySystem,
} else {
additionalFeature.AppendLiteral(u"cbcs-clearlead,");
}
- bool rv = FactorySupports(factory, aKeySystem,
+ bool rv = FactorySupports(factory, spDrmTypeSupport, aKeySystem,
convertCodecToFourCC(codec), nsCString(""),
additionalFeature, isHardwareDecryption);
MFCDM_PARENT_SLOG("clearlead %s IV 8 bytes %s %s",
@@ -1070,9 +1073,9 @@ void MFCDMParent::GetCapabilities(const nsString& aKeySystem,
}
// Try 16 bytes IV.
additionalFeature.AppendLiteral(u"encryption-iv-size=16,");
- rv = FactorySupports(factory, aKeySystem, convertCodecToFourCC(codec),
- nsCString(""), additionalFeature,
- isHardwareDecryption);
+ rv = FactorySupports(factory, spDrmTypeSupport, aKeySystem,
+ convertCodecToFourCC(codec), nsCString(""),
+ additionalFeature, isHardwareDecryption);
MFCDM_PARENT_SLOG("clearlead %s IV 16 bytes %s %s",
EnumValueToString(scheme), codec.get(),
rv ? "supported" : "not supported");
@@ -1107,7 +1110,8 @@ void MFCDMParent::GetCapabilities(const nsString& aKeySystem,
!StaticPrefs::media_hevc_enabled()) {
continue;
}
- if (FactorySupports(factory, aKeySystem, convertCodecToFourCC(codec),
+ if (FactorySupports(factory, spDrmTypeSupport, aKeySystem,
+ convertCodecToFourCC(codec),
KeySystemConfig::EMECodecString(""), nsString(u""),
isHardwareDecryption)) {
MFCDMMediaCapability* c =
@@ -1121,7 +1125,8 @@ void MFCDMParent::GetCapabilities(const nsString& aKeySystem,
MFCDM_PARENT_SLOG("%s: +video:%s (cenc)", __func__, codec.get());
// Check cbcs scheme support
if (FactorySupports(
- factory, aKeySystem, convertCodecToFourCC(codec),
+ factory, spDrmTypeSupport, aKeySystem,
+ convertCodecToFourCC(codec),
KeySystemConfig::EMECodecString(""),
nsString(u"encryption-type=cbcs,encryption-iv-size=16,"),
isHardwareDecryption)) {
@@ -1149,7 +1154,7 @@ void MFCDMParent::GetCapabilities(const nsString& aKeySystem,
// the software capabilities for audio in order to save some time. As the
// media foundation would create a new D3D device everytime when we check
// hardware decryption, which takes way longer time.
- if (FactorySupports(factory, aKeySystem,
+ if (FactorySupports(factory, spDrmTypeSupport, aKeySystem,
convertCodecToFourCC(supportedVideoCodecs[0]),
convertCodecToFourCC(codec), nsString(u""),
false /* aIsHWSecure */)) {