Windows Sandbox and delayed DLL load

370 views
Skip to first unread message

Igor Bukanov

unread,
Nov 6, 2021, 8:54:25 AM11/6/21
to Chromium-dev
Hi,

there are a few LoadLibrray() calls that pre-load librraries before sandbox initialization on Windows, like in https://source.chromium.org/chromium/chromium/src/+/main:media/gpu/windows/dxva_video_decode_accelerator_win.cc;drc=643cdf61903e99f27c3d80daee67e217e9d280e0;l=1458 . This is presumably done because inside the sandbox LoadLibrray() does not work. 

This is done  even for libraries that are linked into the executable via the delayed load, like mfplat.dll. Yet for other DLLs linked in this way like mfreadwrite.dll this is not done. So is it really necessary to preload a DLL via LoadLibrary() if it is linked via the delayed load?

Regards, Igor

Bruce Dawson

unread,
Nov 8, 2021, 12:08:16 PM11/8/21
to Chromium-dev, ig...@vivaldi.com
Delay loading works by inserting code into the first-use pass to call LoadLibrary and GetProcAddress. Therefore delay loading doesn't get any special privileges and has to follow the same rules and restrictions as regular LoadLibrary calls.

Perhaps mfreadwrite.dll is implicitly loaded earlier, by the load of mdplat.dll or by usage. You can use windbg to set breakpoints when a DLL loads in order to investigate.

Austin Orion

unread,
May 24, 2022, 9:06:27 PM5/24/22
to Chromium-dev, Bruce Dawson, ig...@vivaldi.com, wic...@microsoft.com

I ran into this when dynamically loading the mfaacenc.dll in the GPU process, I was surprised to see it succeed without preloading, and I ensured it was actually loading and wasn't implicitly loaded earlier. So, I asked around a bit, and this is what I heard back:

"First thing to be aware of is Tokens. Every process running in Windows is operating with some token and in some cases a thread may also have something called an impersonation token. In WinDBG you can inspect the token for a thread using the !token command. Tokens are basically your keys. In Chromium when a child process (such as GPU) is launched the process itself has two tokens the initial token & the lockdown token (*technically in some cases there can be a third token, the lowbox_token, but ignore that for now*). The child process always runs with the lockdown token however the child process is started suspended and the browser process will set the initial token as an impersonation token on the main thread. When we lock the sandbox in Chromium (TargetServicesBase::LowerToken) the main thread calls RevertToSelf so that all threads are now running with the lockdown token (in addition to doing things like closing open handles & lowering the process integrity level, which is another aspect of the token).

Second there are Security Descriptors. These are basically the locks in Windows which apply to securable objects in the System (this can be file system objects such as Files, Folders, etc.). Part of the security descriptor can be a Discretionary Access Control List (or DACL) which tells the system how certain users & groups may access the secured object.

Finally there is the Access Check, AccessCheck function (securitybaseapi.h) - Win32 apps | Microsoft Docs, this is where the token is checked against the security descriptor.

When we talk about loading a DLL there’s potentially a number of AccessChecks that will occur any of which may fail. One of the first ones will be for the actual LoadLibrary call which attempts to read the file, so we’ll check against the file + folder location. Locations such as System32 or the folder where your executable sits tend to be more accessible than a random folder like c:\foo. However – just because we can successfully call LoadLibrary doesn’t always mean that we can use everything inside the library. What you may find is that some of the DLLs which we need to preload do not have a problem during the file load portion but instead they may have a problem latter on in the DLL initialization process (e.g. DllMain) – for a lot of Windows DLLs this could be because they attempt to do something like initializing COM (CoInitializeEx) which requires another round of AccessChecks which will have different Security Descriptors."

TL;DR some DLLs from certain locations are not prevented from being dynamically loaded after the sandbox is initialized.

Bruce Dawson

unread,
May 26, 2022, 12:51:09 PM5/26/22
to Bang He, Chromium-dev, auo...@microsoft.com, ig...@vivaldi.com, wic...@microsoft.com
The browser process is the first process launched when running Chrome.

The browser process is the parent (creator) of the GPU process, and of essentially all other processes. I believe that there is a crashpad watchdog process that may spawn a child process but I'm not sure if that still happens.

If you look at a process tree of Chromium running you can see this.

On Wed, May 25, 2022 at 4:21 PM Bang He <hezha...@gmail.com> wrote:
is the browser process is first launched process in chromium/chrome?
is the browser process is the father of GPU process in chromium/chrome? 


On Wednesday, May 25, 2022 at 9:06:27 AM UTC+8 auo...@microsoft.com wrote:

 The child process always runs with the lockdown token however the child process is started suspended and the browser process will set the initial token as an impersonation token on the main thread. When we lock the sandbox in Chromium (TargetServicesBase::LowerToken) the main thread calls RevertToSelf so that all threads are now running with the lockdown token (in addition to doing things like closing open handles & lowering the process integrity level, which is another aspect of the token).


--
Bruce Dawson, he/him

Will Harris

unread,
May 26, 2022, 1:21:49 PM5/26/22
to bruce...@google.com, Bang He, Chromium-dev, auo...@microsoft.com, ig...@vivaldi.com, wic...@microsoft.com
Sorry I missed this email until now.

>This is presumably done because inside the sandbox LoadLibrray() does not work.

Yes, once sandbox has been locked down then, depending on the sandbox, it will not have access to DLLs on disk so will fail to load them regardless of whether the call is a LoadLibrary call or a delay load. Some sandbox types e.g. LPAC (App Container) might still retain some access to the OS to delay load or LoadLibrary DLLs after startup.

For delay load, as you state, the DLL will be loaded by the delay load linker at the time it's needed, which can sometimes be non-deterministic e.g. someone moves some code to elsewhere in the process startup and suddenly it starts failing, that is an undesirable property, as we prefer behavior to remain deterministic.

The way we try and solve this is either explicitly LoadLibrary in pre-sandbox to ensure it's mapped or use __HrLoadAllImportsForDll to load the imports before they are dynamically loaded by the delay loader, before sandbox lockdown.

I recently added a number of stronger CHECKs in the delay load helper for both chrome.exe and chrome.dll which should mean deterministic behavior for failed delay loads.

Hope that helps!

Will


--
--
Chromium Developers mailing list: chromi...@chromium.org
View archives, change email options, or unsubscribe:
http://groups.google.com/a/chromium.org/group/chromium-dev
---
You received this message because you are subscribed to the Google Groups "Chromium-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-dev...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/chromium-dev/CAE5mQiOidUiRMkJPb1WVnWC1OcFu4ZK7N%2BXNokAC8uKKLxiExg%40mail.gmail.com.

Bang He

unread,
May 26, 2022, 7:40:48 PM5/26/22
to Chromium-dev, auo...@microsoft.com, Bruce Dawson, ig...@vivaldi.com, wic...@microsoft.com
is the browser process is first launched process in chromium/chrome?
is the browser process is the father of GPU process in chromium/chrome? 

On Wednesday, May 25, 2022 at 9:06:27 AM UTC+8 auo...@microsoft.com wrote:
Reply all
Reply to author
Forward
0 new messages