diff --git a/src/libANGLE/Framebuffer.cpp b/src/libANGLE/Framebuffer.cpp index 0672c1298a..e23c49f520 100644 --- a/src/libANGLE/Framebuffer.cpp +++ b/src/libANGLE/Framebuffer.cpp @@ -2519,11 +2519,46 @@ angle::Result Framebuffer::ensureClearAttachmentsInitialized(const Context *cont // but are explicitly masked out here for clarity. const DrawBufferMask colorAttachmentsNeedingInit(mState.mResourceNeedsInit.bits() & DrawBufferMask().set().bits()); - if (partialClearNeedsInit(context, colorAttachmentsNeedingInit, depth, stencil)) + const bool partialNeedsInit = + partialClearNeedsInit(context, colorAttachmentsNeedingInit, depth, stencil); + if (partialNeedsInit) { ANGLE_TRY(ensureDrawAttachmentsInitialized(context)); } + // ---- POC DETECTION HOOK (not part of upstream) ------------------------------ + // This is a logic bug (CWE-908), not memory corruption, so ASAN will not catch + // it directly. This hook converts the bypass into a deterministic crash so the + // exploit path is observable regardless of whether the underlying GPU driver + // happens to zero freshly allocated VRAM. + // + // It fires when ALL of the following hold: + // * The application is clearing the stencil buffer (stencil == true). + // * The stencil attachment is currently uninitialized (resource-needs-init + // bit is set). + // * partialClearNeedsInit() returned false, so robust-resource-init will be + // SKIPPED and the attachment is about to be marked Initialized below. + // * The stencil writemask does NOT cover all 8 bits, so the upcoming masked + // clear will leave some bits containing whatever was previously in VRAM. + if (stencil && !partialNeedsInit && + mState.mResourceNeedsInit.test(DIRTY_BIT_STENCIL_ATTACHMENT) && + ((depthStencil.stencilWritemask & 0xFF) != 0xFF || + (depthStencil.stencilBackWritemask & 0xFF) != 0xFF)) + { + FATAL() << "POC: robust-resource-init BYPASS reached. " + << "stencilWritemask=0x" << std::hex + << (depthStencil.stencilWritemask & 0xFF) + << " stencilBackWritemask=0x" + << (depthStencil.stencilBackWritemask & 0xFF) + << " stencilValueMask=0x" << (depthStencil.stencilMask & 0xFF) + << " stencilBackValueMask=0x" + << (depthStencil.stencilBackMask & 0xFF) + << " -- partialClearNeedsInit() returned false; uninitialized " + "stencil bits 4-7 are about to be marked Initialized and " + "exposed to web content."; + } + // ---------------------------------------------------------------------------- + // If the impl encounters an error during a a full (non-partial) clear, the attachments will // still be marked initialized. This simplifies design, allowing this method to be called before // the clear.