[4] WebGL provoking vertex with uint16 primitive restart causes GPU OOB access
Severity: High | Component: ANGLE Metal backend (fixIndexBuffer kernel) | e298509
High로 평가된 근거는 다음과 같습니다. 공격자가 제어하는 0xFFFF index marker를 통해 GPU process에서 vertex-attribute 메모리에 대한 매번 재현 가능한 OOB read가 발생하며, Metal Shader Validation regression test에서 crash가 확인되었습니다. stride를 조작한 tight relative read primitive로의 확장 가능성은 GPU heap groomability에 의해 제한됩니다.
Source/ThirdParty/ANGLE/src/libANGLE/renderer/metal/shaders/rewrite_indices.metal
+constant uint restartIndex = indexBufferIsUint16 ? 0xFFFF : 0xFFFFFFFF;
static inline uint readIdx(
const device ushort *indexBufferUint16,
const device uint *indexBufferUint32,
- const uint restartIndex,
const uint indexCount,
uint idx, ...)
{
...
if(doPrimRestart && !foundRestart && inIndex == restartIndex)
{ foundRestart = true; ... }
}
kernel void fixIndexBuffer(...)
{
- constexpr uint restartIndex = 0xFFFFFFFF;
uint baseIndex = 0;
...
- outputPrimitive(..., restartIndex, indexCount, ...);
+ outputPrimitive(..., indexCount, ...);
}
LayoutTests/webgl/webgl2-provoking-vertex-primitive-restart-uint16-nocrash.html
+ext.provokingVertexWEBGL(0x8E4E); // FIRST_VERTEX_CONVENTION
+const indices = new Uint16Array([
+ 0, 1, 2, 3,
+ 0xFFFF,
+ 4, 5, 6
+]);
+gl.drawElements(gl.TRIANGLE_STRIP, 8, gl.UNSIGNED_SHORT, 0);
Patch Details
ANGLE이 WEBGL_provoking_vertex 에뮬레이션을 위해 index buffer를 재작성할 때 fixIndexBuffer kernel이 호출됩니다. 이 kernel은 기존에 constexpr uint restartIndex = 0xFFFFFFFF를 지역 상수로 선언하고 있었습니다. 수정에서는 이 하드코딩된 지역 상수를 제거하고, 기존 indexBufferIsUint16 / indexBufferIsUint32 function constant 옆에 파일 스코프의 constant uint restartIndex = indexBufferIsUint16 ? 0xFFFF : 0xFFFFFFFF;를 새로 배치했습니다. restartIndex 매개변수는 readIdx와 outputPrimitive(READ_IDX macro 포함)에서 제거되었으며, 이제 kernel은 항상 올바른 타입의 compile-time constant를 직접 참조하게 됩니다. 동일한 변경이 rewrite_indices.metal, mtl_internal_shaders_src_autogen.metal, 그리고 mtl_internal_shaders_src_autogen.h 내 C++ string에도 적용되었습니다.
operand 너비와 sentinel 값 불일치 — 더 넓은 index type 기준으로 하드코딩된 primitive-restart marker가 더 좁은 타입에서 실제 index로 묵시적으로 해석되는 패턴.
Background
Primitive restart는 OpenGL/WebGL2의 기능으로, sentinel index 값이 vertex를 참조하는 대신 현재 strip/fan을 끊고 새로운 primitive를 시작하는 데 사용됩니다. sentinel 값은 타입에 따라 결정되며, GL_UNSIGNED_SHORT의 경우 0xFFFF, GL_UNSIGNED_INT의 경우 0xFFFFFFFF입니다. WEBGL_provoking_vertex는 WebGL2 extension으로, 스크립트가 primitive의 어느 vertex가 flat 한정자가 붙은 varying 값을 제공할지 선택할 수 있게 합니다. ANGLE은 WebKit의 Metal 기반 WebGL 구현입니다. Metal이 GL provoking-vertex semantics를 기본적으로 지원하지 않기 때문에, ANGLE은 fixIndexBuffer compute kernel로 index buffer를 재작성하여 indexed draw가 GL 사양에 맞게 동작하도록 합니다. Metal function constants는 pipeline-state-object 생성 시 제공되는 값으로, Metal 컴파일러가 이를 기반으로 특수화를 수행합니다. indexBufferIsUint16이 이 중 하나입니다. Metal Shader Validation은 선택적으로 활성화하는 런타임 모드로, shader 측 메모리 위반을 감지합니다. regression test에서 이를 활성화했기 때문에 OOB 접근이 조용한 메모리 오염 대신 매번 재현 가능한 crash로 드러납니다.
Analysis
kernel은 readIdx에 0xFFFFFFFF를 전달했습니다. 이 함수는 indexBufferUint16[inIndex](uint로 zero-extend됨) 또는 indexBufferUint32[inIndex]를 읽은 뒤 inIndex == restartIndex를 비교하는데, uint16 입력에서는 모든 원소가 [0, 0xFFFF] 범위에 속하므로 이 비교가 true가 되는 경우는 없습니다. 결과적으로 정상적인 0xFFFF restart marker도 일반 vertex index로 처리됩니다.
Aaaaaaaa Aaaaaaa Aaaaaaa Aaa Aaaaaa Aaaaa Aaaaaaaa Aaaaaaaaaaaaaaaaa Aaaaaa Aaaa Aaaaaa Aaaaa Aaaaaaaa Aaaaaaaaa Aaa Aaaaaa Aa Aaaaaaaaa Aa Aaaaaa Aaaaaa Aaaa Aaa Aaaaaaa Aa Aaa Aaaaaa Aa Aaaaa Aaaaaa Aaaaa Aaaaa Aaaaaaaaaaaaaaaa Aaaaaaa Aaaaaaa a Aaaaaaa Aaa Aaaa Aaaaaa Aaaa Aaaaaa Aaa Aa Aaaa Aaa Aaaaaa Aaaaaa Aaa Aaaa Aaaaaa Aaaaa Aaaa a Aaaa Aaa Aaaa Aa Aaa Aaa Aaaaaa
Aaaa Aaa Aaaaa Aaaaaaaa Aaaaaaaaa Aaaa Aaa Aaa Aaaaaa a Aaaa Aaaaaaaaa Aaaaaa Aa Aaa Aaaaaaaaa Aaa a Aaaaa a a Aa Aa Aaa Aaaaaaaaaaaaa Aaa Aaaaa Aaaaaaa Aaaaaa Aaaaaaa Aaaa Aaaaa Aaaaaaaaaaaaa Aaa Aaaaaaaaaa Aaa Aaa Aa Aaaa Aaaaa
Aaaaa Aaaaaa Aaaaaaaaaaa Aaaaa Aaaaa Aaa Aaaaa Aaa Aaaaa Aaa Aaaa Aaaaaa Aaaaaa Aaaa Aaaaaaaa a Aa Aaaaaa Aaaaaaa Aa Aa Aaaaaaaa Aaaaaa Aaaaaaa Aaaaa Aaaaaaaaaaa Aaaaaa Aaaa Aaaa Aaaaaaaaaaaaa Aaa a Aa Aaaa a Aa Aaa Aaaaaa Aaaa Aaaaaaaaaaa Aaaaaaaaaaa Aaa Aaaa Aaaaa Aa Aa Aaaa Aaaa Aaaaaaa Aaa Aaaa Aa Aaa Aaaaaaa Aaaaaa
a Aaaaaaaaaaaaaa a Aaa Aaaa Aaa Aaaaaaaa Aaa Aaaa Aaaaaaa Aaaaaa Aaa Aaaaaaaaa Aaaaa a Aaaaaaaa Aa Aaaa Aa Aaaaaaaaa Aaaaaaaa Aaaa Aaa Aa Aaaaaa Aa Aaaaaaaaaaa Aaaa Aaa Aaa Aaaaaaa Aaaaaaa Aaaaaaa Aaaaaa a Aaaaaaaaaaaaa Aaaaa Aaaa Aaaaa Aaa Aaa Aaaaaa Aaaaaaaaaaa Aaaa Aa Aaa Aaaa Aaa Aaaaaa
🔒A close look at how a single hardcoded sentinel in a Metal compute kernel turns an attacker-controlled index value into a GPU-process out-of-bounds access — and how far that primitive can plausibly be pushed.
더 확인하려면 구독해 주세요
Audit directions
a Aaaa Aa Aaaaaaa Aaaa Aaa Aaaaaaaaaaaaaaa Aaa a Aa Aaaa Aaaaa Aaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa a Aa Aaaaa Aaaaaaaa Aaaaaaaaaa Aaaaaaaaaa Aaaaaaaaaaa Aaaaaaa Aaaa Aaaaa Aaaaaaaaaaaaa Aaaaaaaaa Aaaaaaa Aaaaa Aaa Aaaa Aaaa a Aaa Aaaaa Aaaaaa Aaa Aaaa Aa Aaa Aaaaaaaaaaaaaaaaaaa Aaaaa Aaaa Aaaa Aaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaa Aaaa Aa Aaaaaa
a Aaaa Aaaa Aa Aaaaaaa Aaaa Aaaaaaaaa Aa a Aaaaaaa Aa Aaaaaaaaaaaaaaaaaa Aaa Aaaaaaaa a Aa Aa Aaa Aaaa Aa Aaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaa Aaaaaaaaaaaaaa Aa Aaa Aaaaaaaa Aaaaa Aa Aaa Aaaa Aaaa Aaaaaaaaa Aaa Aaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaa Aa Aaa Aaaaa Aaaa Aaaa Aa Aaaa Aaaaaaaaa Aaaaa Aaa Aaaa Aaa Aaaaaa
a Aaaaaaaaaa Aaaaaaa Aaaaaaa Aa Aaaaaaa Aaaa Aaa Aaaaaaaa Aaaaaaaaaa Aaaaa Aaaaaaa Aaaaa Aaaa Aa Aaaaaa Aaaaa Aaaa Aaaa Aaaaaaaaaaaaaaaa Aaaa Aaaaaa Aaaaa Aa Aaaaa Aaaa Aa Aaaaaa Aaaa Aaaaaa Aaaa Aa Aaaaa Aaaaa Aaaaaaa Aaaaaa a Aaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaa a a Aaaa Aaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaa Aa Aaaaaa
a Aaaaa Aaaaaaaaaa Aaaa Aaaaa Aaaaa Aaaaaaaaa Aaa Aaaa Aaaaa Aa Aaaaaaaa Aa Aaaaaaaa Aa Aaaaa Aaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaa a Aaaaaaaaa Aaaaaaa a Aaaaaaaaaa a Aaaaaaaaa Aaaaaaaa a Aaaaaaaaa Aaaaaaaaaa Aaa Aa Aaaaa Aaaaa Aa Aaaaa Aaaa Aaaa Aaa Aa Aaaaaaa Aaaaaaaaa Aaaa Aaaa
🔒Several reusable audit patterns identified across ANGLE's Metal shaders and host-side index handling, with concrete files and grep targets for variant discovery.
더 확인하려면 구독해 주세요