Skip to content

Commit

Permalink
Bug 1950112: Use win32k lockdown and ACG for GMP process for non-wide…
Browse files Browse the repository at this point in the history
…vine CDMs. r=yjuglaret,win-reviewers

Differential Revision: https://phabricator.services.mozilla.com/D239356
  • Loading branch information
bobowen committed Feb 27, 2025
1 parent 903705e commit 19a5f37
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 36 deletions.
22 changes: 9 additions & 13 deletions ipc/glue/GeckoChildProcessHost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1526,11 +1526,6 @@ Result<Ok, LaunchError> WindowsProcessLauncher::DoSetup() {
FilePath exePath;
BinPathType pathType = GetPathToBinary(exePath, mProcessType);

# if defined(MOZ_SANDBOX) || defined(_ARM64_)
const bool isGMP = mProcessType == GeckoProcessType_GMPlugin;
const bool isWidevine = isGMP && Contains(mChildArgs, "gmp-widevinecdm");
# endif // defined(MOZ_SANDBOX) || defined(_ARM64_)

mCmdLine.emplace(exePath.ToWStringHack());

if (pathType == BinPathType::Self) {
Expand Down Expand Up @@ -1574,14 +1569,15 @@ Result<Ok, LaunchError> WindowsProcessLauncher::DoSetup() {
break;
case GeckoProcessType_GMPlugin:
if (!PR_GetEnv("MOZ_DISABLE_GMP_SANDBOX")) {
// The Widevine CDM on Windows can only load at USER_RESTRICTED,
// not at USER_LOCKDOWN. So look in the command line arguments
// to see if we're loading the path to the Widevine CDM, and if
// so use sandbox level USER_RESTRICTED instead of USER_LOCKDOWN.
auto level =
isWidevine ? SandboxBroker::Restricted : SandboxBroker::LockDown;
if (NS_WARN_IF(
!mResults.mSandboxBroker->SetSecurityLevelForGMPlugin(level))) {
auto gmpSandboxKind = GMPSandboxKind::Default;
if (Contains(mChildArgs, "gmp-widevinecdm")) {
gmpSandboxKind = GMPSandboxKind::Widevine;
} else if (Contains(mChildArgs, "gmp-clearkey")) {
gmpSandboxKind = GMPSandboxKind::Clearkey;
}

if (NS_WARN_IF(!mResults.mSandboxBroker->SetSecurityLevelForGMPlugin(
gmpSandboxKind))) {
return Err(LaunchError("SetSecurityLevelForGMPlugin"));
}
mUseSandbox = true;
Expand Down
13 changes: 9 additions & 4 deletions modules/libpref/init/StaticPrefList.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16104,14 +16104,19 @@
# true means win32k system calls are not permitted.
- name: security.sandbox.content.win32k-disable
type: RelaxedAtomicBool
value: true
value: @IS_NIGHTLY_BUILD@
mirror: always

# Note: win32k is currently _not_ disabled for GMP due to intermittent test
# failures, where the GMP process fails very early. See bug 1449348.
# Whether win32k is disabled for compatible plugins.
- name: security.sandbox.gmp.win32k-disable
type: RelaxedAtomicBool
value: false
value: @IS_NIGHTLY_BUILD@
mirror: always

# Whether ACG is enabled (dynamic code blocked) for compatible plugins.
- name: security.sandbox.gmp.acg.enabled
type: RelaxedAtomicBool
value: true
mirror: always

# Whether win32k is disabled for socket processes.
Expand Down
27 changes: 22 additions & 5 deletions security/sandbox/win/src/sandboxbroker/sandboxBroker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1750,8 +1750,8 @@ bool SandboxBroker::SetSecurityLevelForUtilityProcess(
}
}

bool SandboxBroker::SetSecurityLevelForGMPlugin(SandboxLevel aLevel,
bool aIsRemoteLaunch) {
bool SandboxBroker::SetSecurityLevelForGMPlugin(
GMPSandboxKind aGMPSandboxKind) {
if (!mPolicy) {
return false;
}
Expand All @@ -1761,8 +1761,10 @@ bool SandboxBroker::SetSecurityLevelForGMPlugin(SandboxLevel aLevel,
SANDBOX_ENSURE_SUCCESS(
result,
"SetJobLevel should never fail with these arguments, what happened?");
auto level = (aLevel == Restricted) ? sandbox::USER_RESTRICTED
: sandbox::USER_LOCKDOWN;

// The Widevine CDM on Windows can only load at USER_RESTRICTED
auto level = (aGMPSandboxKind == Widevine) ? sandbox::USER_RESTRICTED
: sandbox::USER_LOCKDOWN;
result = mPolicy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS, level);
SANDBOX_ENSURE_SUCCESS(
result,
Expand Down Expand Up @@ -1803,13 +1805,28 @@ bool SandboxBroker::SetSecurityLevelForGMPlugin(SandboxLevel aLevel,
result = mPolicy->SetProcessMitigations(mitigations);
SANDBOX_ENSURE_SUCCESS(result, "Invalid flags for SetProcessMitigations.");

if (StaticPrefs::security_sandbox_gmp_win32k_disable()) {
// win32k is currently not disabled for clearkey due to WMF decoding or
// widevine due to intermittent test failures, where the GMP process fails
// very early. See bug 1449348.
if (StaticPrefs::security_sandbox_gmp_win32k_disable() &&
aGMPSandboxKind != Widevine && aGMPSandboxKind != Clearkey) {
result = AddWin32kLockdownPolicy(mPolicy, true);
SANDBOX_ENSURE_SUCCESS(result, "Failed to add the win32k lockdown policy");
}

mitigations = sandbox::MITIGATION_STRICT_HANDLE_CHECKS |
sandbox::MITIGATION_DLL_SEARCH_ORDER;
if (StaticPrefs::security_sandbox_gmp_acg_enabled()) {
auto acgMitigation = sandbox::MITIGATION_DYNAMIC_CODE_DISABLE;
if (aGMPSandboxKind == Widevine) {
// We can't guarantee that widevine won't use dynamic code.
acgMitigation = 0;
} else if (aGMPSandboxKind == Clearkey) {
// Clearkey uses system decoding libraries.
acgMitigation = DynamicCodeFlagForSystemMediaLibraries();
}
mitigations |= acgMitigation;
}

result = mPolicy->SetDelayedProcessMitigations(mitigations);
SANDBOX_ENSURE_SUCCESS(result,
Expand Down
6 changes: 3 additions & 3 deletions security/sandbox/win/src/sandboxbroker/sandboxBroker.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ class TargetPolicy;

namespace mozilla {

enum GMPSandboxKind { Default, Widevine, Clearkey };

class SandboxBroker {
public:
SandboxBroker();
Expand Down Expand Up @@ -56,9 +58,7 @@ class SandboxBroker {
bool SetSecurityLevelForRDDProcess();
bool SetSecurityLevelForSocketProcess();

enum SandboxLevel { LockDown, Restricted };
bool SetSecurityLevelForGMPlugin(SandboxLevel aLevel,
bool aIsRemoteLaunch = false);
bool SetSecurityLevelForGMPlugin(GMPSandboxKind aGMPSandboxKind);
bool SetSecurityLevelForUtilityProcess(mozilla::ipc::SandboxingKind aSandbox);

// File system permissions
Expand Down
7 changes: 7 additions & 0 deletions toolkit/xre/nsAppRunner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6272,6 +6272,13 @@ bool XRE_IsE10sParentProcess() {
#undef GECKO_PROCESS_TYPE

bool XRE_UseNativeEventProcessing() {
#if defined(XP_WIN)
// If win32k is locked down we can't use native event processing.
if (IsWin32kLockedDown()) {
return false;
}
#endif

switch (XRE_GetProcessType()) {
#if defined(XP_MACOSX) || defined(XP_WIN)
case GeckoProcessType_RDD:
Expand Down
28 changes: 17 additions & 11 deletions widget/windows/nsAppShell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -619,17 +619,23 @@ nsresult nsAppShell::Init() {
if (nsresult rv = this->InitEventWindow(); NS_FAILED(rv)) {
return rv;
}
} else if (XRE_IsContentProcess() && !IsWin32kLockedDown()) {
// We're not generally processing native events, but still using GDI and we
// still have some internal windows, e.g. from calling CoInitializeEx.
// So we use a class that will do a single event pump where previously we
// might have processed multiple events to make sure any occasional messages
// to these windows are processed. This also allows any internal Windows
// messages to be processed to ensure the GDI data remains fresh.
nsCOMPtr<nsIThreadInternal> threadInt =
do_QueryInterface(NS_GetCurrentThread());
if (threadInt) {
threadInt->SetObserver(new SingleNativeEventPump());
} else {
// Load winmm.dll because it is still needed by our event loop and might not
// get loaded before we lower the sandbox.
::LoadLibraryW(L"winmm.dll");

if (XRE_IsContentProcess() && !IsWin32kLockedDown()) {
// We're not generally processing native events, but still using GDI and
// we still have some internal windows, e.g. from calling CoInitializeEx.
// So we use a class that will do a single event pump where previously we
// might have processed multiple events to make sure any occasional
// messages to these windows are processed. This also allows any internal
// Windows messages to be processed to ensure the GDI data remains fresh.
nsCOMPtr<nsIThreadInternal> threadInt =
do_QueryInterface(NS_GetCurrentThread());
if (threadInt) {
threadInt->SetObserver(new SingleNativeEventPump());
}
}
}

Expand Down

0 comments on commit 19a5f37

Please sign in to comment.