Closed Bug 1758070 (CVE-2022-26486) Opened 2 years ago Closed 2 years ago

UAF in Webgpu status manager [exploited in the wild]

Categories

(Core :: Graphics: WebGPU, defect)

defect

Tracking

()

RESOLVED FIXED
Tracking Status
firefox-esr91 97+ fixed
firefox97 + fixed
firefox98 --- unaffected
firefox99 --- unaffected

People

(Reporter: m.cooolie, Assigned: nical)

References

Details

(Keywords: csectype-sandbox-escape, csectype-uaf, sec-critical, Whiteboard: [adv-main97.0.2+]{adv-esr91.6.1+][reporter-external] [client-bounty-form] [verif?][sec-survey])

Attachments

(4 files, 1 obsolete file)

#Summary
UAF in Webgpu status manager[exploited in the wild]

#Type
GPU process RCE

#NOTE
We have evidence that the following bug is being explot in the wild.

This problem has been fixed in the latest beta version,
the reason for the fix is an accident(https://bugzilla.mozilla.org/show_bug.cgi?id=1746538),
but the stable version (97.0.1) has not been synchronized.
Therefore, we think it is necessary to report this vulnerability in detail, so that the stable version can be fixed as soon as possible,
and at the same time apply for a CVE number to track this vulnerability

#CREDIT
wang gang&liu jialei&du sihang&huang yi&yang kang of 360 ATA

#MINIPOC

mov     rax, [rsp+0E38h+var_DF8]
mov     qword ptr [rax+198h], 0
mov     rax, [rsp+0E38h+var_DF8]
add     rax, 198h
xor     edx, edx
mov     rcx, rax
call    [rsp+0E38h+mozilla::webgpu::Instance::Create]		<<[1]
mov     rax, [rsp+0E38h+var_DF8]
mov     rax, [rax+198h]
mov     rcx, [rax+20h]
call    [rsp+0E38h+mozilla::webgpu::PWebGPUChild::SendShutdown] <<[2]
mov     [rsp+0E38h+var_DEC], 0		

#RCA

  1. Get Render side RCE,we already reported in https://bugzilla.mozilla.org/show_bug.cgi?id=1758062
  2. Run shellcode in compromised Render process call mozilla::webgpu::Instance::Create then call mozilla::webgpu::PWebGPUChild::SendShutdown
    to get a webgpu with wrong status.
  3. After a clever heap layout call mozilla::webgpu::PWebGPUChild::SendShaderModuleDestroy get RCE

ipc::IPCResult WebGPUParent::RecvShutdown() {
  mTimer.Stop();
  for (const auto& p : mCanvasMap) {
    const wr::ExternalImageId extId = {p.first};
    layers::TextureHost::DestroyRenderTexture(extId);
  }
  mCanvasMap.clear();
  ffi::wgpu_server_poll_all_devices(mContext, true);
  ffi::wgpu_server_delete(const_cast<ffi::WGPUGlobal*>(mContext));	<<
  return IPC_OK();
}
Flags: sec-bounty?

Because the GPU process is a high-privileged process in Firefox on windows, attackers use this vulnerability for sandbox escape.

Group: firefox-core-security → gfx-core-security
Component: Security → Graphics: WebGPU
Keywords: csectype-uaf
Product: Firefox → Core

We are still investigating this issue but there is one thing that is unclear to us: We already deployed a fix in Firefox 94 (and ESR91/78) that would check if WebGPU is enabled or not, and if not, it would never allocate a WebGPUParent in the first place.

This fix landed here longer ago: https://hg.mozilla.org/mozilla-central/rev/33918b139eff#l2.17

Can you elaborate on how you are able to SendShutdown to the parent when the parent cannot even be allocated? Note that WebGPU is disabled by default in all versions of Firefox.

Flags: needinfo?(m.cooolie)

The debug looks like this function is called and left and returns, I will continue to analyze it in depth
xul!mozilla::layers::PCompositorBridgeParent::RecvPWebGPUConstructor

Flags: needinfo?(m.cooolie)

alloc in this function xul!mozilla::layers::ContentCompositorBridgeParent::AllocPWebGPUParent

What is surprising to us is that webgpu is disabled by default - Can you confirm the state of the preference dom.webgpu.enabled in about:config?

Flags: needinfo?(m.cooolie)

Patched because compromised Render process

 v29 = *mozilla::gfx::sConfig + 0x1760i64;
  *v29 = 0;
 *(v29 + 0x148) = 0x1D;
Flags: needinfo?(m.cooolie)
Assignee: nobody → nical.bugzilla
Status: UNCONFIRMED → ASSIGNED
Ever confirmed: true

Comment on attachment 9266493 [details]
WIP: Bug 1758070 - Null out mContext during shutdown.

Beta/Release Uplift Approval Request

  • User impact if declined: Exploitable sandbox escape
  • Is this code covered by automated tests?: No
  • Has the fix been verified in Nightly?: No
  • Needs manual test from QE?: No
  • If yes, steps to reproduce: We know how to reproduce the exploit.
  • List of other uplifts needed: None
  • Risk to taking this patch: Low
  • Why is the change risky/not risky? (and alternatives if risky): Not risky because
  • Trivial change. we null out a pointer after calling a function that deallocates it.
  • It affects a code path that is preffed off by default on release
  • String changes made/needed:
Attachment #9266493 - Flags: approval-mozilla-release?

Comment on attachment 9266493 [details]
WIP: Bug 1758070 - Null out mContext during shutdown.

ESR Uplift Approval Request

  • If this is not a sec:{high,crit} bug, please state case for ESR consideration:
  • User impact if declined: Exploitable sandbox escape
  • Fix Landed on Version:
  • Risk to taking this patch: Low
  • Why is the change risky/not risky? (and alternatives if risky): - Trivial change. we null out a pointer after calling a function that deallocates it.
  • It affects a code path that is preffed off by default on release
Attachment #9266493 - Flags: approval-mozilla-esr91?

Comment on attachment 9266493 [details]
WIP: Bug 1758070 - Null out mContext during shutdown.

Approved to land

Attachment #9266493 - Flags: sec-approval+

When able, we would appreciate being able to see the "clever heap layout" steps in the exploit - we are very interested to see examples of cross-IPC heap grooming to see what may make those techniques more difficult/less reliable.

Flags: needinfo?(m.cooolie)

The attacker does a lot of preparation and then lays out the heap by calling mozilla::layers::PWebRenderBridgeChild::SendSetDisplayList.

Flags: needinfo?(m.cooolie)
Summary: UAF in Webgpu status manager[exploited in th wild] → UAF in Webgpu status manager [exploited in the wild]
Attachment #9266493 - Flags: approval-mozilla-release?
Attachment #9266493 - Flags: approval-mozilla-release+
Attachment #9266493 - Flags: approval-mozilla-esr91?
Attachment #9266493 - Flags: approval-mozilla-esr91+
See Also: → CVE-2022-26485

Is there any way QA can verify this?

Blocks: 1758156

Comment on attachment 9266533 [details]
WIP: Bug 1758070 - Better check the webgpu pref.

Revision D140362 was moved to bug 1758156. Setting attachment 9266533 [details] to obsolete.

Attachment #9266533 - Attachment is obsolete: true

Follow-up work is happening in bug 1758156. Closing this out for the work which already landed for better tracking.

Group: gfx-core-security → core-security-release
Status: ASSIGNED → RESOLVED
Closed: 2 years ago
Resolution: --- → FIXED
Alias: CVE-2022-26486

We currently do not understand how the exploit works in Firefox 97 if the WebGPU pref is disabled. We have a check in CompositorBridgeParent::AllocPWebGPUParent which checks mOptions.UseWebGPU():

  // We should only ever get this if WebGPU is enabled in this compositor.
  MOZ_RELEASE_ASSERT(mOptions.UseWebGPU());

The only way to influence mOptions is from the CompositorBridgeParent constructor, which is only called from two places:

But the call in CompositorManagerParent::AllocPCompositorBridgeParent is in the CompositorBridgeOptions::TWidgetCompositorOptions branch, which has the following check:

      gfx::GPUParent* gpu = gfx::GPUParent::GetSingleton();
      if (NS_WARN_IF(!gpu || OtherPid() != gpu->OtherPid())) {
        MOZ_ASSERT_UNREACHABLE("Child cannot create widget compositor!");
        break;
      }

So if this method is called in response to a message from the content process, the OtherPid() != gpu->OtherPid() check should fail, and we should bail out.

So I don't know how content can cause the creation of a CompositorBridgeParent whose mOptions has UseWebGPU() == true, unless the WebGPU pref is enabled.

It would be great to get more insight regarding comment 21, can you provide more details as to how mOptions got influenced here? Thanks!

Flags: needinfo?(m.cooolie)

(In reply to Markus Stange [:mstange] from comment #21)

We currently do not understand how the exploit works in Firefox 97 if the WebGPU pref is disabled. We have a check in CompositorBridgeParent::AllocPWebGPUParent which checks mOptions.UseWebGPU():

  // We should only ever get this if WebGPU is enabled in this compositor.
  MOZ_RELEASE_ASSERT(mOptions.UseWebGPU());

Ah, this check is in the wrong AllocPWebGPUParent method. It's only on CompositorBridgeParent::AllocPWebGPUParent. But we also have ContentCompositorBridgeParent::AllocPWebGPUParent, which does not have the check, and that's the one that's called by content:

webgpu::PWebGPUParent* ContentCompositorBridgeParent::AllocPWebGPUParent() {
  webgpu::WebGPUParent* parent = new webgpu::WebGPUParent();
  parent->AddRef();  // IPDL reference
  return parent;
}
Flags: needinfo?(m.cooolie)

(In reply to Markus Stange [:mstange] from comment #23)

But we also have ContentCompositorBridgeParent::AllocPWebGPUParent, which does not have the check, and that's the one that's called by content

And that's the one to which nical is adding the check, in bug 1758156.

Whiteboard: [reporter-external] [client-bounty-form] [verif?] → [adv-main97.0.2+]{adv-esr91.6.1+][reporter-external] [client-bounty-form] [verif?]
Flags: sec-bounty? → sec-bounty+

As part of a security bug pattern analysis, we are requesting your help with a high level analysis of this bug. It is our hope to develop static analysis (or potentially runtime/dynamic analysis) in the future to identify classes of bugs.

Please visit this google form to reply.

Flags: needinfo?(nical.bugzilla)
Whiteboard: [adv-main97.0.2+]{adv-esr91.6.1+][reporter-external] [client-bounty-form] [verif?] → [adv-main97.0.2+]{adv-esr91.6.1+][reporter-external] [client-bounty-form] [verif?][sec-survey]
Flags: needinfo?(nical.bugzilla)
Group: core-security-release
See Also: → 1725854
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: