Closed Bug 1750679 (CVE-2022-1196) Opened 11 months ago Closed 10 months ago

heap-use-after-free of VRProcessParent

Categories

(Core :: WebVR, defect)

defect

Tracking

()

RESOLVED FIXED
98 Branch
Tracking Status
firefox-esr91 99+ fixed
firefox96 --- wontfix
firefox97 --- disabled
firefox98 + fixed

People

(Reporter: bo13oy, Assigned: jld)

References

Details

(4 keywords, Whiteboard: [reporter-external] [client-bounty-form] [verif?][adv-esr91.8+][adv-main98+])

Attachments

(2 files)

Tested Version: Window 10 Pro 20H2 x64 memory 32G + win64-fuzzing-asan-opt(96.0.2)

There is no way to reproduce the vulnerability, temporarily can not provide poc samples,I feel that this is a conditional competition vulnerability,The conditions for triggering this vulnerability are demanding,the crash report is as follows:

=================================================================
==21636==ERROR: AddressSanitizer: heap-use-after-free on address 0x1254e68ea0b0 at pc 0x7fff352febc2 bp 0x00db761fc6a0 sp 0x00db761fc6e8
READ of size 8 at 0x1254e68ea0b0 thread T0
    #0 0x7fff352febc1 in mozilla::gfx::VRProcessParent::InitAfterConnect /builds/worker/checkouts/gecko/gfx/vr/ipc/VRProcessParent.cpp:165
    #1 0x7fff3360613d in mozilla::ipc::TaskFactory<mozilla::net::SocketProcessHost>::TaskWrapper<mozilla::ipc::TaskFactory<mozilla::net::SocketProcessHost>::RunnableMethod<void (mozilla::net::SocketProcessHost::*)(),Tuple0> >::Run /builds/worker/workspace/obj-build/dist/include/mozilla/ipc/TaskFactory.h:37
    #2 0x7fff324c3c5e in mozilla::RunnableTask::Run /builds/worker/checkouts/gecko/xpcom/threads/TaskController.cpp:468
    #3 0x7fff3247dc88 in mozilla::TaskController::DoExecuteNextTaskOnlyMainThreadInternal /builds/worker/checkouts/gecko/xpcom/threads/TaskController.cpp:771
    #4 0x7fff3247a62c in mozilla::TaskController::ExecuteNextTaskOnlyMainThreadInternal /builds/worker/checkouts/gecko/xpcom/threads/TaskController.cpp:607
    #5 0x7fff3247aff4 in mozilla::TaskController::ProcessPendingMTTask /builds/worker/checkouts/gecko/xpcom/threads/TaskController.cpp:391
    #6 0x7fff324ca6a1 in mozilla::detail::RunnableFunction<`lambda at /builds/worker/checkouts/gecko/xpcom/threads/TaskController.cpp:124:7'>::Run /builds/worker/checkouts/gecko/xpcom/threads/nsThreadUtils.h:531
    #7 0x7fff324a66d4 in nsThread::ProcessNextEvent /builds/worker/checkouts/gecko/xpcom/threads/nsThread.cpp:1195
    #8 0x7fff324b6b3c in NS_ProcessNextEvent /builds/worker/checkouts/gecko/xpcom/threads/nsThreadUtils.cpp:467
    #9 0x7fff338c823d in mozilla::ipc::MessagePump::Run /builds/worker/checkouts/gecko/ipc/glue/MessagePump.cpp:85
    #10 0x7fff337e12d5 in MessageLoop::RunHandler /builds/worker/checkouts/gecko/ipc/chromium/src/base/message_loop.cc:324
    #11 0x7fff337e10a5 in MessageLoop::Run /builds/worker/checkouts/gecko/ipc/chromium/src/base/message_loop.cc:306
    #12 0x7fff3b367e1a in nsBaseAppShell::Run /builds/worker/checkouts/gecko/widget/nsBaseAppShell.cpp:137
    #13 0x7fff3b554d6a in nsAppShell::Run /builds/worker/checkouts/gecko/widget/windows/nsAppShell.cpp:603
    #14 0x7fff3f3bb68b in nsAppStartup::Run /builds/worker/checkouts/gecko/toolkit/components/startup/nsAppStartup.cpp:295
    #15 0x7fff3f66f01c in XREMain::XRE_mainRun /builds/worker/checkouts/gecko/toolkit/xre/nsAppRunner.cpp:5317
    #16 0x7fff3f67518e in XREMain::XRE_main /builds/worker/checkouts/gecko/toolkit/xre/nsAppRunner.cpp:5502
    #17 0x7fff3f67640a in XRE_main /builds/worker/checkouts/gecko/toolkit/xre/nsAppRunner.cpp:5561
    #18 0x7ff7523e2588 in NS_internal_main /builds/worker/checkouts/gecko/browser/app/nsBrowserApp.cpp:395
    #19 0x7ff7523e17ad in wmain /builds/worker/checkouts/gecko/toolkit/xre/nsWindowsWMain.cpp:147
    #20 0x7ff7524dca27 in __scrt_common_main_seh d:\agent\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
    #21 0x7fff8bc37033 in BaseThreadInitThunk+0x13 (C:\WINDOWS\System32\KERNEL32.DLL+0x180017033)
    #22 0x7fff8d002650 in RtlUserThreadStart+0x20 (C:\WINDOWS\SYSTEM32\ntdll.dll+0x180052650)

0x1254e68ea0b0 is located 560 bytes inside of 584-byte region [0x1254e68e9e80,0x1254e68ea0c8)
freed by thread T5 here:
    #0 0x7fff58067cdb in free Z:\task_163722766350223\fetches\llvm-project\llvm\projects\compiler-rt\lib\asan\asan_malloc_win.cpp:82
    #1 0x7fff352ff30c in mozilla::gfx::VRProcessParent::~VRProcessParent /builds/worker/checkouts/gecko/gfx/vr/ipc/VRProcessParent.cpp:45
    #2 0x7fff33891303 in mozilla::MozPromise<void *,mozilla::ipc::LaunchError,0>::ThenValue<`lambda at /builds/worker/checkouts/gecko/ipc/glue/GeckoChildProcessHost.cpp:487:19'>::DoResolveOrRejectInternal /builds/worker/workspace/obj-build/dist/include/mozilla/MozPromise.h:914
    #3 0x7fff3190552e in mozilla::MozPromise<bool,nsresult,1>::ThenValueBase::ResolveOrRejectRunnable::Run /builds/worker/workspace/obj-build/dist/include/mozilla/MozPromise.h:487
    #4 0x7fff337e2ab4 in MessageLoop::DeferOrRunPendingTask /builds/worker/checkouts/gecko/ipc/chromium/src/base/message_loop.cc:463
    #5 0x7fff337e4120 in MessageLoop::DoWork /builds/worker/checkouts/gecko/ipc/chromium/src/base/message_loop.cc:538
    #6 0x7fff337b537b in base::MessagePumpForIO::DoRunLoop /builds/worker/checkouts/gecko/ipc/chromium/src/base/message_pump_win.cc:419
    #7 0x7fff337b6198 in base::MessagePumpWin::Run /builds/worker/checkouts/gecko/ipc/chromium/src/base/message_pump_win.h:79
    #8 0x7fff337e12d5 in MessageLoop::RunHandler /builds/worker/checkouts/gecko/ipc/chromium/src/base/message_loop.cc:324
    #9 0x7fff337f1f9e in base::Thread::ThreadMain /builds/worker/checkouts/gecko/ipc/chromium/src/base/thread.cc:187
    #10 0x7fff337b77d6 in `anonymous namespace'::ThreadFunc /builds/worker/checkouts/gecko/ipc/chromium/src/base/platform_thread_win.cc:19
    #11 0x7fff58072273 in __asan::AsanThread::ThreadStart Z:\task_163722766350223\fetches\llvm-project\llvm\projects\compiler-rt\lib\asan\asan_thread.cpp:278
    #12 0x7fff8bc37033 in BaseThreadInitThunk+0x13 (C:\WINDOWS\System32\KERNEL32.DLL+0x180017033)
    #13 0x7fff66783817 in patched_BaseThreadInitThunk /builds/worker/checkouts/gecko/toolkit/xre/dllservices/mozglue/WindowsDllBlocklist.cpp:570
    #14 0x7fff8d002650 in RtlUserThreadStart+0x20 (C:\WINDOWS\SYSTEM32\ntdll.dll+0x180052650)

previously allocated by thread T0 here:
    #0 0x7fff58067deb in malloc Z:\task_163722766350223\fetches\llvm-project\llvm\projects\compiler-rt\lib\asan\asan_malloc_win.cpp:98
    #1 0x7fff6667134d in moz_xmalloc /builds/worker/checkouts/gecko/memory/mozalloc/mozalloc.cpp:52
    #2 0x7fff352fc9a0 in mozilla::gfx::VRProcessManager::LaunchVRProcess /builds/worker/checkouts/gecko/gfx/vr/ipc/VRProcessManager.cpp:67
    #3 0x7fff3529d926 in mozilla::gfx::GPUChild::RecvCreateVRProcess /builds/worker/checkouts/gecko/gfx/ipc/GPUChild.cpp:147
    #4 0x7fff33c694f7 in mozilla::gfx::PGPUChild::OnMessageReceived /builds/worker/workspace/obj-build/ipc/ipdl/PGPUChild.cpp:1253
    #5 0x7fff338becf4 in mozilla::ipc::MessageChannel::DispatchAsyncMessage /builds/worker/checkouts/gecko/ipc/glue/MessageChannel.cpp:2043
    #6 0x7fff338bb160 in mozilla::ipc::MessageChannel::DispatchMessage /builds/worker/checkouts/gecko/ipc/glue/MessageChannel.cpp:1968
    #7 0x7fff338bcf37 in mozilla::ipc::MessageChannel::RunMessage /builds/worker/checkouts/gecko/ipc/glue/MessageChannel.cpp:1827
    #8 0x7fff338bd4e8 in mozilla::ipc::MessageChannel::MessageTask::Run /builds/worker/checkouts/gecko/ipc/glue/MessageChannel.cpp:1855
    #9 0x7fff324c3c5e in mozilla::RunnableTask::Run /builds/worker/checkouts/gecko/xpcom/threads/TaskController.cpp:468
    #10 0x7fff3247dc88 in mozilla::TaskController::DoExecuteNextTaskOnlyMainThreadInternal /builds/worker/checkouts/gecko/xpcom/threads/TaskController.cpp:771
    #11 0x7fff3247a62c in mozilla::TaskController::ExecuteNextTaskOnlyMainThreadInternal /builds/worker/checkouts/gecko/xpcom/threads/TaskController.cpp:607
    #12 0x7fff3247aff4 in mozilla::TaskController::ProcessPendingMTTask /builds/worker/checkouts/gecko/xpcom/threads/TaskController.cpp:391
    #13 0x7fff324ca6a1 in mozilla::detail::RunnableFunction<`lambda at /builds/worker/checkouts/gecko/xpcom/threads/TaskController.cpp:124:7'>::Run /builds/worker/checkouts/gecko/xpcom/threads/nsThreadUtils.h:531
    #14 0x7fff324a66d4 in nsThread::ProcessNextEvent /builds/worker/checkouts/gecko/xpcom/threads/nsThread.cpp:1195
    #15 0x7fff324b6b3c in NS_ProcessNextEvent /builds/worker/checkouts/gecko/xpcom/threads/nsThreadUtils.cpp:467
    #16 0x7fff338c823d in mozilla::ipc::MessagePump::Run /builds/worker/checkouts/gecko/ipc/glue/MessagePump.cpp:85
    #17 0x7fff337e12d5 in MessageLoop::RunHandler /builds/worker/checkouts/gecko/ipc/chromium/src/base/message_loop.cc:324

Thread T5 created by T0 here:
    #0 0x7fff580731d2 in __asan_wrap_CreateThread Z:\task_163722766350223\fetches\llvm-project\llvm\projects\compiler-rt\lib\asan\asan_win.cpp:146
    #1 0x7fff337b776c in PlatformThread::Create /builds/worker/checkouts/gecko/ipc/chromium/src/base/platform_thread_win.cc:57
    #2 0x7fff337f15bc in base::Thread::StartWithOptions /builds/worker/checkouts/gecko/ipc/chromium/src/base/thread.cc:93
    #3 0x7fff3253aa6a in NS_InitXPCOM /builds/worker/checkouts/gecko/xpcom/build/XPCOMInit.cpp:318
    #4 0x7fff3f650270 in ScopedXPCOMStartup::Initialize /builds/worker/checkouts/gecko/toolkit/xre/nsAppRunner.cpp:1731
    #5 0x7fff3f67516f in XREMain::XRE_main /builds/worker/checkouts/gecko/toolkit/xre/nsAppRunner.cpp:5498
    #6 0x7fff3f67640a in XRE_main /builds/worker/checkouts/gecko/toolkit/xre/nsAppRunner.cpp:5561
    #7 0x7ff7523e2588 in NS_internal_main /builds/worker/checkouts/gecko/browser/app/nsBrowserApp.cpp:395
    #8 0x7ff7523e17ad in wmain /builds/worker/checkouts/gecko/toolkit/xre/nsWindowsWMain.cpp:147
    #9 0x7ff7524dca27 in __scrt_common_main_seh d:\agent\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
    #10 0x7fff8bc37033 in BaseThreadInitThunk+0x13 (C:\WINDOWS\System32\KERNEL32.DLL+0x180017033)
    #11 0x7fff8d002650 in RtlUserThreadStart+0x20 (C:\WINDOWS\SYSTEM32\ntdll.dll+0x180052650)

SUMMARY: AddressSanitizer: heap-use-after-free /builds/worker/checkouts/gecko/gfx/vr/ipc/VRProcessParent.cpp:165 in mozilla::gfx::VRProcessParent::InitAfterConnect
Shadow bytes around the buggy address:
  0x04738311d3c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x04738311d3d0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x04738311d3e0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x04738311d3f0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x04738311d400: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
=>0x04738311d410: fd fd fd fd fd fd[fd]fd fd fa fa fa fa fa fa fa
  0x04738311d420: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x04738311d430: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x04738311d440: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x04738311d450: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x04738311d460: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==21636==ABORTING

This vuln is discovered by bo13oy of Cyber Kunlun Lab.

Thanks.

Flags: sec-bounty?
Group: firefox-core-security → gfx-core-security
Component: Security → WebVR
Product: Firefox → Core

From skimming the stacks, it looks like starting the VR process failed, causing us to destroy a VRProcessParent, but then later we touch the VR process parent anyways. I see some SocketProcessHost in the stack, too, so maybe the socket process is involved somehow? Jed, given that we don't have anybody actively working on VR and this seems to be mostly about a process launch issue, maybe you could take a look? Thanks.

Flags: needinfo?(jld)
Keywords: csectype-uaf

I don't think that's actually the socket process — that frame looks like some kind of runnable wrapper trampoline, so probably simple enough to be identical-code-folded. Some preliminary observations:

The location of the bad use is interesting: to reach that point aSucceeded must be true (meaning the launch worked), and it's also not the first access to *this, but note that the object is used on the main thread and freed on the IPC I/O thread (i.e., this is probably a race). Specifically, from the lack of other things on the stack above InitAfterConnect, it looks like the use was via VRProcessParent::OnChannelConnectedTask.

It's harder to see what's going on with the free, but MozPromise<void *,mozilla::ipc::LaunchError,0> is ProcessHandlePromise, and the demangled symbol name has the source location for the lambda (which is nice and I don't think we have that on Unix?): the delete this in GeckoChildProcessHost::Destroy. That's from VRProcessParent::DestroyProcess, which has several call chains that can reach it.

Flags: needinfo?(jld)
Keywords: csectype-race

Part of the problem here seems to be TaskFactory, which dates back to the original Chromium IPC import in 2009. If I'm reading it right, it uses RevocableStore to check that the TaskFactory (in this case, owned by the VRProcessParent) hasn't been destroyed before executing the runnable. But there's nothing to prevent the destruction happening after the Run method has already been entered (i.e., RevokeAll just sets a flag; it has no facility for observing that runnables are running, let alone blocking until they complete).

There's a similar pattern in the GPU process, but we revoke any tasks on the main thread and return to the event loop before calling Destroy, and the task factory is used only to send runnables to the main thread. So that should be safe (assuming the runnables in question don't spin a nested event loop, but I don't think they do). The problem for the VR process is that the RevokeAll is too late and on the wrong thread, but if we change VRProcessParent::DestroyProcess to look more like GPUProcessHost::DestroyProcess then that should fix this.

As far as a test case / STR: I think if the child process crashes immediately after connecting the IPC channel, that will set up the situation where this can happen, but it's still going to be timing-sensitive.

(In reply to Jed Davis [:jld] ⟨⏰|UTC-7⟩ ⟦he/him⟧ from comment #4)

As far as a test case / STR: I think if the child process crashes immediately after connecting the IPC channel, that will set up the situation where this can happen, but it's still going to be timing-sensitive.

On further inspection, no: I think it has to be a deliberate shutdown from the parent side, either via this branch in OnChannelClosed or the !mVRChild case in the Shutdown method. So, maybe something like starting to use WebVR and then immediately closing the window / destroying the frame.

Assignee: nobody → jld
Status: NEW → ASSIGNED

Have you been able to find a test case for this? Alternately, if this is something that reproduces randomly during testing, is it possible to see if the attached patch (D137359) fixes it?

Flags: needinfo?(bo13oy)

The condition of trigger is too picky, i am not capable to provide test case, so far as i see the fixed patch is available, but i am not familiar with this part. Just for your information.

Flags: needinfo?(bo13oy)

The severity field is not set for this bug.
:jimm, could you have a look please?

For more information, please visit auto_nag documentation.

Flags: needinfo?(jmathies)

WebVR has been disabled by default in bug 1750902 (filed after this issue), which should also effectively address this issue.

Blocks: 1750902
Summary: heap-use-after-free of VRProcessParent → heap-use-after-free of VRProcessParent
Group: gfx-core-security → core-security-release
Status: ASSIGNED → RESOLVED
Closed: 10 months ago
Resolution: --- → FIXED
Target Milestone: --- → 98 Branch
Flags: needinfo?(jmathies)
Flags: qe-verify-
Flags: sec-bounty? → sec-bounty+

Comment on attachment 9261368 [details]
Bug 1750679.

ESR Uplift Approval Request

  • If this is not a sec:{high,crit} bug, please state case for ESR consideration: sec-moderate and very low risk (see below)
  • User impact if declined: Possible exposure to a use-after-free bug — WebVR was preffed off on ESR91 in bug 1750902, but I'm not as sure as I'd like to be that a compromised content process couldn't cause the VR process to be spawned anyway (i.e., I'm concerned that there might not be checks of the pref in a trusted process on all paths).
  • Fix Landed on Version: 98
  • Risk to taking this patch: Low
  • Why is the change risky/not risky? (and alternatives if risky): There should be essentially no risk: the pref exposing this feature is turned off, so this code shouldn't be reachable in normal operation (unless it's changed in about:config, but we warn people not to do that).
Attachment #9261368 - Flags: approval-mozilla-esr91?

Seems like a good fix to take in the upcoming 91.7.1esr build along with the WebGPU follow-up. Thanks for raising this.

(In reply to Ryan VanderMeulen [:RyanVM] from comment #13)

Seems like a good fix to take in the upcoming 91.7.1esr build along with the WebGPU follow-up. Thanks for raising this.

This missed the 91.7.1esr release unfortunately. Retargeting 91.8esr instead.

Comment on attachment 9261368 [details]
Bug 1750679.

Approved for 91.8esr.

Attachment #9261368 - Flags: approval-mozilla-esr91? → approval-mozilla-esr91+
Attached file advisory.txt
Alias: CVE-2022-1196
Whiteboard: [reporter-external] [client-bounty-form] [verif?] → [reporter-external] [client-bounty-form] [verif?][adv-esr91.8+][adv-main98+]
See Also: → 1758549
Group: core-security-release
You need to log in before you can comment on or make changes to this bug.