Chrome · WebGL › WebGL
CVE-2026-79215
Integer Overflow in WebGL (WebGL)
Overview
Medium
Severity
8.8
CVSS
No
Exploited ITW
Fixed
Fix Status
Background
- Transform feedback
- a WebGL 2.0 feature that captures vertex-shader outputs into buffer objects; a program must be flagged active while it participates, via
WebGLProgram::active_transform_feedback_count_. - `current_program_`
- the currently bound program (set by
useProgram), which per WebGL 2.0 may be swapped while transform feedback is paused, so it need not equal the program that began transform feedback. - `transform_feedback_binding_`
- the bound
WebGLTransformFeedbackobject, which independently records the program that actually started transform feedback viaGetProgram(). - `active_transform_feedback_count_`
- an
unsignedcounter guarding safety checks inlinkProgram; decrementing it below0wraps toUINT_MAX(4294967295).
Root Cause Analysis
WebGL2RenderingContextBase::endTransformFeedback called current_program_->DecreaseActiveTransformFeedbackCount(), assuming the program bound at end time was the one that started transform feedback. WebGL 2.0 permits useProgram to change current_program_ while transform feedback is paused, so at endTransformFeedback time current_program_ can point to a different program than the one whose count was incremented in beginTransformFeedback. The decrement therefore lands on the wrong WebGLProgram. Because active_transform_feedback_count_ is unsigned and initialized to 0, decrementing a program that never had its count raised underflows to UINT_MAX. Meanwhile the program that truly began transform feedback keeps a stale nonzero count, and the wrongly-decremented program now falsely appears to have a huge active count. The corrupted counter defeats linkProgram’s guard that forbids relinking a program still active in transform feedback.Key insight
The active-transform-feedback count must be charged against the program recorded by the transform-feedback object (
transform_feedback_binding_->GetProgram()), not whatever program happens to be bound at end time, because useProgram can decouple the two while paused.Attack Path
- Begin feedback
Bind a transform-feedback object and call
beginTransformFeedbackwith programA, incrementingA’s count and recordingAintransform_feedback_binding_. - Pause and swap
Call
pauseTransformFeedback, thenuseProgram(B)socurrent_program_becomes programBwhileAremains the feedback program. - End against wrong program
Call
endTransformFeedback, which decrementsB’s count; sinceBwas never started,B’sactive_transform_feedback_count_underflows toUINT_MAX. - Bypass link guard
Relink or otherwise operate on program
A(whose count is now falsely stale) or exploitB’s bogus count to slip pastlinkProgramsafety checks while a program is effectively active in transform feedback.
Impact Assessment
The unsigned underflow corrupts
active_transform_feedback_count_, letting linkProgram safety checks be bypassed while a program is active in transform feedback, which can drive the GL backend into an inconsistent state. This is an integer-overflow bug in WebGL reachable from untrusted web content and forms a primitive toward memory corruption in the renderer.Files Changed
third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.ccthird_party/blink/renderer/modules/webgl/webgl_program.cc
Audit Directions
- Wrong-object accounting across pause/resumeAudit any counter or ref incremented in a
begin/startpath and decremented in the matchingend/stoppath where the target object (herecurrent_program_vstransform_feedback_binding_->GetProgram()) can change in between via state-setters likeuseProgram. - Unsigned decrements without floor checksSearch
WebGL/GPU code for--countorDecrease*Countonunsignedmembers lacking aCHECK_GT(x, 0u)guard, since these wrap toUINT_MAXand defeat downstream validation. - Guards keyed on corruptible countsReview safety checks like
linkProgram’s active-transform-feedback guard that trust a mutable count; confirm the count cannot be desynchronized from the actual active state through legal API reordering.
Patch
From 03c1c9015ca0e22259104d9099812d332d6e009d Mon Sep 17 00:00:00 2001 From: Le Hoang Quyen <[email protected]> Date: Fri, 17 Jul 2026 09:28:04 -0700 Subject: [PATCH] [webgl] Fix transform feedback program counter underflow In WebGL2RenderingContextBase::endTransformFeedback, when transform feedback ends, Blink previously decremented the active transform feedback count of current_program_. However, per the WebGL 2.0 specification, useProgram can change current_program_ while transform feedback is paused. If current_program_ was swapped while transform feedback was paused, endTransformFeedback incorrectly decremented current_program_ instead of the program associated with the transform feedback object. Because active_transform_feedback_count_ is unsigned and initialized to 0, decrementing a program that was never started caused an underflow to UINT_MAX (4294967295), which could be leveraged to bypass linkProgram safety checks while a program is active in transform feedback. This patch updates endTransformFeedback to decrement the counter on transform_feedback_binding_->GetProgram(), and adds a CHECK_GT in WebGLProgram::DecreaseActiveTransformFeedbackCount to guard against underflows. Bug: 513760788 Change-Id: I8881c16783399255d796f3f4a35ac83fcefd2679 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8107215 Reviewed-by: Kenneth Russell <[email protected]> Commit-Queue: Kenneth Russell <[email protected]> Reviewed-by: Geoff Lang <[email protected]> Auto-Submit: Quyen Le <[email protected]> Cr-Commit-Position: refs/heads/main@{#1663963} --- diff --git a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc index 40ea7b6..1e2b512 100644 --- a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc +++ b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc @@ -4214,8 +4214,10 @@ transform_feedback_binding_->SetPaused(false); transform_feedback_binding_->SetActive(false); - if (current_program_) - current_program_->DecreaseActiveTransformFeedbackCount(); + if (transform_feedback_binding_->GetProgram()) { + transform_feedback_binding_->GetProgram() + ->DecreaseActiveTransformFeedbackCount(); + } } void WebGL2RenderingContextBase::transformFeedbackVaryings( diff --git a/third_party/blink/renderer/modules/webgl/webgl_program.cc b/third_party/blink/renderer/modules/webgl/webgl_program.cc index 33698c3..f5d8c36e 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_program.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_program.cc @@ -25,6 +25,7 @@ #include "third_party/blink/renderer/modules/webgl/webgl_program.h" +#include "base/check_op.h" #include "gpu/command_buffer/client/gles2_interface.h" #include "third_party/blink/renderer/modules/webgl/webgl_context_object_support.h" #include "third_party/blink/renderer/modules/webgl/webgl_shader.h" @@ -86,6 +87,7 @@ } void WebGLProgram::DecreaseActiveTransformFeedbackCount() { + CHECK_GT(active_transform_feedback_count_, 0u); --active_transform_feedback_count_; }
Loading diff…
Original Bug Report
The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.
References
On This Page