[16] ANGLE Metal: initialize missing fragment shader output components
Severity: Medium | Component: ANGLE MSL translator (ModifyStruct) | 3043c63
Rated Medium because the observable effect is uninitialised G/B/A bytes from a narrow fragment output reaching readPixels (per-pixel one-byte/four-byte residue), passively readable from any web origin; controllability is low (depends on Metal register allocator state).
Source/ThirdParty/ANGLE/src/compiler/translator/msl/ModifyStruct.cpp
+ for (uint8_t d = dim; d < saturation; ++d)
+ {
+ state.addConversion([=](Access::Env &, OriginalAccess &, ModifiedAccess &m) {
+ auto &m_ = AccessIndex(m, d);
+ return Access{*CreateZeroNode(m_.getType()), m_};
+ });
+ }
Patch Details
A second loop in SaturateScalarOrVectorCommon emits zero-initialisation conversion lambdas for component indices [dim, saturation) — components present in the expanded Metal-friendly struct but absent from the original GLSL fragment shader output. For each missing component d, it registers a conversion wrapping AccessIndex(m, d) with CreateZeroNode of the matching type. A regression test declares layout(location=0) out float outColor;, draws to an RGBA target, and asserts readPixels returns (255, 0, 0, 0).
Uninitialized expanded-output components in a shader-translation widening pass leak through to attacker-readable framebuffer pixels.
Background
WebGL2 lets a fragment shader declare an output with fewer components than the bound color attachment; the spec requires missing components to read as zero. To satisfy Metal's stricter struct-layout rules, ANGLE's ModifyStruct pass widens the user's output struct: ConvertStructState accumulates ConversionFunc lambdas via state.addConversion(...) that the pass later emits as MSL assignments from original to modified struct fields. SaturateScalarOrVectorCommon widens a scalar/vector field from dim to saturation.
Analysis
Pre-fix the helper emitted conversion lambdas only for [0, dim) — copying outColor into modified[0]. The components [dim, saturation) had no conversion registered, so the generated MSL wrote whatever the shader's local/register state contained into the framebuffer.
Aaaaaaaaaaaaaaaaa Aaaaaaaa Aaaaaa Aaa a Aaaaaaaaa Aaaaaa Aa Aaaaaaaaaaa Aaaaa Aaa Aaaa a Aaaaaaaa Aaaaaaaa a Aaaaaa Aaaaaaaaaaaaaaaaa Aaaa Aaaa a Aaaaa Aaaaaaaaaaaaaa Aaaa Aa Aaaaaaa a Aaaaaaaaa Aaaaaa Aaaaaa Aaa Aaa Aaaaa Aaaa Aaaaaaaa Aaaaaaaaa Aa Aaa Aaaaaa Aaaaaaaaa Aaaaaaaaa Aa Aaaaaaaa Aaaaaaaaa Aaa Aaaa Aaaaa Aaaaaa Aa Aaaaaaaaaaaaaaa Aaaaaaaaa Aaaaaaa Aaaaaaaaaaa Aaaaaaaaa Aaa Aaaaaaaaaaaaaa Aaaaaa Aaaaaaaa
Aaaa Aaaaaaaaaaaaa Aaaaaaa Aaaaaaaaaaa Aaaaaa Aaaaaaaaaaaaaaa Aaaa Aaa Aaaaaaaa Aa Aaaaaaaa Aaaaa Aa a Aaaaa Aaaaaaaaaa Aaa Aaaaaaaa Aaaaaaa Aaa Aaaaaaaaaaaaa Aaa Aaaaaa Aaaaaaa Aaaaaaa Aa Aaaaaaa Aaaaaaaa Aaaaaaaaaa Aaa Aaaaa Aaa Aaaaaa Aaaaaa
🔒Detailed look at how a shader-translation widening pass turns into a cross-process information-disclosure primitive readable from JavaScript, and the bounds of what an attacker can actually scrape.
Subscribe to read more
Audit directions
a Aaaaaaaaaaaaa Aaaaaa Aaaaaaaa Aaaaaa Aaaa Aaaaa Aaaa Aaaaa Aaaaaaa Aaaaaaaa Aaaa Aaaaaaaaaaa Aaaaaa Aaaaaaaaa Aaaaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaa Aaaa Aaaaa Aaaa Aaaa Aaa Aaaaaaaaa Aaaaaa Aaa Aaaaaaaaa Aa Aaaaaa Aaaaaaaaaaa Aaaaaaaaaaaaaaa Aaaaaaaaaaa Aaa Aaaaaaaaaaaaaaaa Aaaaaaaaaaaa
a Aaaaaaaaaaaaaaa Aaaaaaaa Aaaa Aaaaaaaaa Aaaaaaaaaaa Aaaaaaaaa Aaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaa Aaaaaaaa Aaaaa Aaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aa Aaaaaaa Aaa Aaaaaaaaaaa
a Aaaaaaaaaaaaaaa Aaaaaaaaa Aaaaaaaaa Aaaaaaaaaaa Aa Aaa Aaaaaaa Aaaaaa Aaaa Aaa Aaaaaaaaaaaa Aaaaaaa Aaaaaaaaaaaaaaaaa Aaaaaaaaaaaa Aaaaaaaaaaaa Aaaaa Aa Aaaaaaaaaaaaaaaaaa Aaa Aaaaaaaaa Aaaaaaaaaa Aaaaaa
a Aaaaaaaaa Aaaaaaaa Aa Aaaaa Aaaa Aaaa Aaaaaaaaaa Aaa Aaa Aaaa Aaaaa Aaaaaaa Aa Aaaa Aaaaaa Aaaaa Aaaaaaaaaaaaaaa Aaaaaaa Aaaaa Aaaaaa Aaa Aaaaaaaaaaaaaaaaaaaaa
🔒Multiple reusable audit patterns identified — translation-layer widening, readback-surface guarantees, and cross-backend parity — each with concrete starting points in ANGLE's translator tree.
Subscribe to read more