Closed Bug 2060000 (CVE-2026-92014) Opened 3 months ago Closed 3 months ago

Heap buffer overflow in WebGL uniform upload leads to control-flow redirection in the GPU process (web-reachable via WebGL2)

Categories

(Core :: Graphics, defect)

Unspecified
macOS
defect

Tracking

()

RESOLVED FIXED
155 Branch
Tracking Status
firefox-esr115 156+ fixed
firefox-esr140 156+ fixed
firefox-esr153 154+ fixed
firefox153 --- wontfix
firefox154 + fixed
firefox155 + fixed

People

(Reporter: call_eax, Assigned: lsalzman)

Details

(6 keywords, Whiteboard: [client-bounty-form][adv-main154-][adv-esr153.1-][adv-esr115.41+][adv-esr140.16+])

Crash Data

Attachments

(5 files, 3 external files)

Attached file minimal_poc.html —

Summary

Ordinary WebGL2 content can overflow a roughly 64 KiB driver command buffer in the Firefox GPU process by calling any glUniform*v-family function with a typed array larger than the uniform array the linked program declares. WebGLContext::UniformData forwards the attacker-chosen element count straight to the GL driver without comparing it against the uniform's declared array size, and the driver copies the oversized payload without clamping. A corrupted 64-bit value at a fixed payload offset is later loaded into the program counter and tracks the planted value.

Steps to reproduce

./BrowserBuild/Release/dist/Nightly.app/Contents/MacOS/firefox minimal_poc.html

The page self-drives on load: it links a program declaring uniform vec4 u[2] (32 bytes of storage), confirms the sink runs cleanly on a correctly sized 8-float upload, then calls gl.uniform4fv with a 1 MiB Float32Array on that uniform.

Open pc_control_marker1_uiv_alternating.html and pc_control_marker2_uiv_varied.html the same way: each plants a distinct 64-bit marker via gl.uniform4uiv and crashes the GPU process with that marker in the program counter.

Observed result

ASan build, minimal_poc.html:

AddressSanitizer: heap-buffer-overflow on address 0x6310010c8818
WRITE of size 1048576 at 0x6310010c8818 thread T63
  #1 mozilla::webgl::UniformAs4fv(...)
  #2 mozilla::WebGLContext::UniformData(...) const
  #5 mozilla::dom::WebGLParent::RecvDispatchCommands(...)
0x6310010c8818 is located 0 bytes after 65560-byte region
allocated by gleInitCommandBuffer (Apple GLEngine, inside the GL driver)

Boundary, bisected to 16-byte precision: last clean payload 65504 bytes, first fatal 65520. The threshold tracks payload bytes, not the declared uniform size (49152 bytes into a 32-byte declared array is clean), so this overflows the driver's command buffer. No legitimate call can exceed 16384 bytes on this host (MAX_*_UNIFORM_VECTORS is 1024), so every fatal payload is out-of-contract.

Control-flow redirection, sanitizer-disabled build, GPU process "Nightly GPU Helper", faulting thread "CanvasRenderer". Two runs, two different planted values, same payload offset and same call site:

marker1:  pc = far = x8 = 0x4242424241414141    esr 0x8a000000  (PC alignment)
marker2:  pc = far = x8 = 0x4142434445464748    esr 0x82000004  (Instruction Abort) Translation fault
both:     lr = GLEngine+0xd0fd4 (gleCmdProcessor)
          #5 mozilla::WebGLContext::Finish()    #6 mozilla::dom::WebGLParent::RecvFinish()

Each pc holds exactly the value that run planted, so the branch target is attacker-chosen rather than merely disturbed, and both faults are instruction-side. The fault class tracks the planted value too: marker1 is not 4-byte aligned and faults on PC alignment, marker2 is aligned and reaches instruction fetch. Both .ips reports are included.

Impact

Web-reachable out-of-bounds write in the Firefox GPU process, from any origin, with a WebGL2 canvas and one uniform-upload call: no pref, no configuration, no user gesture beyond page load. The corrupted 64-bit slot is then fetched as the next instruction address.

Affected component

  • WebGLContextGL.cpp:1391 - the sink, WebGLContext::UniformData: (*pfn)(*gl, static_cast<GLint>(loc), elemCount, transpose, ptr)
  • WebGLContextGL.cpp:1361 - the only length guard, applied to non-array uniforms only, so any count is accepted for an array uniform
  • WebGLTypes.h:844 - ActiveInfo::elemCount, the declared array size, held at the sink as validationInfo.info.elemCount but never compared
  • ClientWebGLContext.cpp:5099 - client-side mirror, same gap

Affected version: Nightly 155.0a1, on two local builds of that revision: one ASan, one sanitizer-disabled. default-on WebGL2, no pref or flag. The sink and its guard carry no preprocessor conditionals and no assert gating, so the missing validation is present on every channel rather than Nightly-only. The crash was tested on the GPU process on macOS / Apple Silicon (Apple's native GL driver).

Flags: sec-bounty?
Group: firefox-core-security → gfx-core-security
Component: Security → Graphics
Keywords: ai-involved
Product: Firefox → Core

glUniform is supposed to signal an error of GL_INVALID_OPERATION if the size of the underlying type doesn't match the size passed in, rather than do an out-of-bounds copy. So even though we don't check that higher up, the driver itself is the source of the bug, not us - therefor sec-vector. As far as we know, this is only on macOS so far, and we can't verify what versions. Given that this is also only in the GPU process, this is priv escalation, but not a parent process sandbox escape.

Severity: -- → S2
OS: Unspecified → macOS
Keywords: 64bit
Attached file (secure) —
Assignee: nobody → lsalzman
Status: UNCONFIRMED → ASSIGNED
Ever confirmed: true

Thanks for the follow up lsalzman. I figured similar but wasnt quite sure. And yes even in my testing, it currently only worked on macOS. For version reference, I tested on macOS Tahoe Beta 26.6. I could not get it to reproduce on Linux (Ubuntu 24.04.4 LTS) or Android, I also didnt do a deeper dive on either of those.

:lsalzman, please update all release status flags to reflect the affected/unaffected/disabled state correctly. Which branches (beta, release, and/or ESR) are affected by this flaw?

Flags: needinfo?(lsalzman)
Pushed by agoloman@mozilla.com: https://github.com/mozilla-firefox/firefox/commit/7f451c7918ff https://hg.mozilla.org/integration/autoland/rev/7cffe0640121 Revert "Bug 2060000. r=gfx-reviewers,nical" for causing mochitest failures @test_conformance__more__functions__uniformfArrayLen1.html.

TEST-UNEXPECTED-FAIL | dom/canvas/test/webgl-conf/generated/test_conformance__more__functions__uniformfArrayLen1.html | testUniformArray
followed by more failures

Flags: needinfo?(lsalzman)
Flags: needinfo?(lsalzman)
Group: gfx-core-security → core-security-release
Status: ASSIGNED → RESOLVED
Closed: 3 months ago
Resolution: --- → FIXED
Target Milestone: --- → 155 Branch

The patch landed in nightly and beta is affected, along with ESR.
:lsalzman, is this bug important enough to require an uplift?

For more information, please visit BugBot documentation.

Flags: needinfo?(lsalzman)

Comment on attachment 9621063 [details]
(secure)

ESR Uplift Approval Request

  • If this is not a sec:{high,crit} bug, please state case for ESR consideration: GL driver can cause out-of-bounds write
  • User impact if declined: Priv escalation
  • Fix Landed on Version: 155
  • Risk to taking this patch: Low
  • Why is the change risky/not risky? (and alternatives if risky): Avoids supplying tricky value to GL driver

Beta/Release Uplift Approval Request

  • User impact if declined/Reason for urgency: GL driver out-of-bounds write
  • Is this code covered by automated tests?: Yes
  • Has the fix been verified in Nightly?: Yes
  • Needs manual test from QE?: No
  • If yes, steps to reproduce:
  • List of other uplifts needed: None
  • Risk to taking this patch: Low
  • Why is the change risky/not risky? (and alternatives if risky): Avoids supply tricky value to GL driver
  • String changes made/needed: None
  • Is Android affected?: Unknown
Flags: needinfo?(lsalzman)
Attachment #9621063 - Flags: approval-mozilla-esr153?
Attachment #9621063 - Flags: approval-mozilla-beta?

Comment on attachment 9621063 [details]
(secure)

Approved for 154.0b8

Attachment #9621063 - Flags: approval-mozilla-beta? → approval-mozilla-beta+

Comment on attachment 9621063 [details]
(secure)

Approved for 153.1esr

Attachment #9621063 - Flags: approval-mozilla-esr153? → approval-mozilla-esr153+
QA Whiteboard: [sec] [uplift] [qa-triage-done-c155/b154]
Whiteboard: [client-bounty-form] → [client-bounty-form][adv-main154+]
Whiteboard: [client-bounty-form][adv-main154+] → [client-bounty-form][adv-main154-]
Whiteboard: [client-bounty-form][adv-main154-] → [client-bounty-form][adv-main154-][adv-esr153.1-]
Flags: sec-bounty? → sec-bounty-

(In reply to Lee Salzman [:lsalzman] from comment #5)

the driver itself is the source of the bug, not us - therefor sec-vector.

Although "sec-vector" conveys the blame for the bug, it doesn't usefully capture the risk to Firefox users on macOS who don't get a choice of what driver they use. For similar reasons we couldn't protect our users by blocklisting a buggy driver version like we can on other platforms, because that would kill major functionality for all Mac users. This bug should have been tagged sec-high in addition to the sec-vector.

Thankfully you were able to work around the driver's compliance issue. In cases where we can't we can add the blocked-thirdparty keyword so the nagbot and release managers know why there's a stale sec-high.

Keywords: sec-high

We should reconsider fixing this on ESR-140
bp-57e0adca-4cd1-4af0-9238-3e8100260902

Crash Signature: [@ mozilla::gl::GLContext::fUniform4fv ] [@ glFinish_ExecThread ]
Attached file (secure) —

Original Revision: https://phabricator.services.mozilla.com/D315942

(cherry picked from commit 373c8e078e64ccc0ad9df7d4e4737fc71b916c55)

Attachment #9635619 - Flags: approval-mozilla-esr140?

firefox-esr140 Uplift Approval Request

  • User impact if declined/Reason for urgency: GL driver out-of-bounds write
  • Code covered by automated testing?: yes
  • Fix verified in Nightly?: yes
  • Needs manual QE testing?: no
  • Steps to reproduce for manual QE testing: n/a
  • Risk associated with taking this patch: low
  • Explanation of risk level: Avoids supply tricky value to GL driver. Already shipped to Release.
  • String changes made/needed?: None
  • Is Android affected?: unknown
Attached file (secure) —

Original Revision: https://phabricator.services.mozilla.com/D315942

(cherry picked from commit 373c8e078e64ccc0ad9df7d4e4737fc71b916c55)

Attachment #9635629 - Flags: approval-mozilla-esr115?

firefox-esr115 Uplift Approval Request

  • User impact if declined/Reason for urgency: GL driver out-of-bounds write
  • Code covered by automated testing?: yes
  • Fix verified in Nightly?: yes
  • Needs manual QE testing?: no
  • Steps to reproduce for manual QE testing: n/a
  • Risk associated with taking this patch: low
  • Explanation of risk level: Avoids supply tricky value to GL driver. Already shipped to Release.
  • String changes made/needed?: None
  • Is Android affected?: unknown

(In reply to Daniel Veditz [:dveditz] from comment #20)

(In reply to Lee Salzman [:lsalzman] from comment #5)

the driver itself is the source of the bug, not us - therefor sec-vector.

Although "sec-vector" conveys the blame for the bug, it doesn't usefully capture the risk to Firefox users on macOS who don't get a choice of what driver they use. For similar reasons we couldn't protect our users by blocklisting a buggy driver version like we can on other platforms, because that would kill major functionality for all Mac users. This bug should have been tagged sec-high in addition to the sec-vector.

Thankfully you were able to work around the driver's compliance issue. In cases where we can't we can add the blocked-thirdparty keyword so the nagbot and release managers know why there's a stale sec-high.

I'm a bit confused and hoping you can help me understand. It was tagged sec-vector (yes technically a driver bug reached through Firefox), but there was a fix on the Firefox side for the missing bounds check, and it's now rated sec-high as this is a path to privesc. Can you help me understand why this doesn't meet the bounty criteria?

Attachment #9635619 - Flags: approval-mozilla-esr140? → approval-mozilla-esr140+
Attachment #9635629 - Flags: approval-mozilla-esr115? → approval-mozilla-esr115+
Whiteboard: [client-bounty-form][adv-main154-][adv-esr153.1-] → [client-bounty-form][adv-main154-][adv-esr153.1-][adv-esr115.41+][adv-esr140.16+]
Alias: CVE-2026-92014
Group: core-security-release
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: