CVE-2025-24201
Overview
Background
- ANGLE
- WebKit’s translation layer running WebGL on native GPU APIs; its Metal backend executes in the GPU/WebContent graphics path.
- PRIMITIVE_RESTART_FIXED_INDEX
- A GL capability controlling primitive-restart in indexed draws; in WebGL2 it is implicitly always on and not app-toggleable, and absent in WebGL1.
- WebGL enable/disable
- APIs that set GL capabilities; forwarding an implementation-managed capability from untrusted content desynchronizes GL state.
Root Cause Analysis
This is a supplementary fix (exploited in the wild before iOS 17.2) for an out-of-bounds sandbox escape via WebGL primitive-restart state in the ANGLE Metal backend. WebGL exposes enable(cap)/disable(cap); GraphicsContextGLANGLE::enable/disable forwarded the capability straight to GL_Enable/GL_Disable. PRIMITIVE_RESTART_FIXED_INDEX must not be toggled by web content: in WebGL2 it is always enabled and managed by the implementation, and in WebGL1 it does not exist. Allowing content to enable or disable it drove ANGLE/GL into an inconsistent primitive-restart configuration that, combined with index buffers during geometry processing, produced out-of-bounds memory access in the GPU pipeline — a corruption primitive used to break out of the WebContent sandbox.
The fix special-cases the capability: disable(PRIMITIVE_RESTART_FIXED_INDEX) raises InvalidOperation in WebGL2 and returns without forwarding to GL; enable(PRIMITIVE_RESTART_FIXED_INDEX) raises InvalidOperation when NOT in WebGL2 and returns.
The restored invariant is that primitive-restart state is controlled by the implementation per WebGL version, never by untrusted enable/disable calls.
Attack Path
- Create a WebGL context Open a WebGL1 or WebGL2 context from web content.
- Toggle the forbidden capability Call gl.enable/gl.disable(PRIMITIVE_RESTART_FIXED_INDEX), which pre-patch forwarded straight to ANGLE/GL.
- Desynchronize primitive-restart state Combined with crafted index buffers, the inconsistent state drives out-of-bounds access in the GPU geometry pipeline.
- Escape the sandbox Leverage the OOB corruption to break out of the WebContent sandbox (observed in a sophisticated in-the-wild attack).
Impact Assessment
Changed Functions
| Function | Change | Notes |
|---|---|---|
GraphicsContextGLANGLE::disableSource/WebCore/platform/graphics/angle/GraphicsContextGLANGLE.cpp |
modified | For PRIMITIVE_RESTART_FIXED_INDEX raises InvalidOperation in WebGL2 and returns without forwarding to GL_Disable. |
GraphicsContextGLANGLE::enableSource/WebCore/platform/graphics/angle/GraphicsContextGLANGLE.cpp |
modified | For PRIMITIVE_RESTART_FIXED_INDEX raises InvalidOperation when not WebGL2 and returns without forwarding to GL_Enable. |
Audit Directions
- Other implementation-managed capabilitiesAudit GraphicsContextGLANGLE::enable/disable and cap-forwarding for other GL capabilities that WebGL1/WebGL2 must manage internally rather than accept from content.
- WebGL version gatingGrep for m_isForWebGL2 checks around GL state to find capabilities/queries valid in only one WebGL version that are not gated.