Overview

Critical
Severity
9.6
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in WebGL
DescriptionUse after free in WebGL
ComponentWebGL
Sub-componentGL
Bug ClassUAF
Action tierwatch — corruption primitive but gated (uncommon) — not default-reachable
Computed by PatchGap's deterministic exploitability ruler from the fixing commit. patch-now = RCE-class & attacker-reachable in a default config, or exploited in the wild; watch = real security signal below that bar; noise = no security relevance.
Tracker544163112
Fix commit87f5655006e4 (angle/angle) +132/-86
CWECWE-416 (Use-after-free)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H
CISA KEVNot listed
CreditedLexi Groves (49016)
Reported2026-08-08 · bounty $2,500 (per vendor advisory)
Fix landed2026-08-19 (public git)
Disclosed2026-09-08
Patch gap20 days — fix public in source before the advisory

Background

ANGLE
Chrome’s translation layer that implements the WebGL/OpenGL ES API on top of native graphics backends, including the GL backend where this bug lives.
`TextureGL::setStorage()`
the ANGLE GL-backend routine that allocates immutable texture storage in response to glTexStorage3D-style calls.
`reattachTextureToFboAfterLayerIncrease`
an ANGLE feature flag whose workaround forces framebuffers to re-bind to a texture after its layer count grows and its backing storage is reallocated.
`TextureLayerCountIncreased`
a SubjectMessage broadcast to observers (such as an attached FBO) signaling that a _2DArray texture gained layers and must be re-attached to fresh storage.

Root Cause Analysis

When an FBO is attached to a layer of a gl::TextureType::_2DArray texture and the texture’s immutable storage is then (re)allocated through TextureGL::setStorage() with a larger size.depth (more array layers), the native GL driver allocates a new backing object, but the framebuffer attachment was left pointing at the old, now-freed storage. The pre-existing reattachTextureToFboAfterLayerIncrease workaround already emitted angle::SubjectMessage::TextureLayerCountIncreased on the mutable glTexImage3D path so observers would reattach, but setStorage() (the glTexStorage3D immutable path) never issued that notification, violating the invariant that any layer-count increase which reallocates storage must notify attached FBOs.

The fix mirrors the mutable-path logic inside setStorage(): it iterates the mip levels, compares the incoming size.depth against each gl::ImageDesc’s previous depth, and calls onStateChange(angle::SubjectMessage::TextureLayerCountIncreased) when depth grows, so the FBO reattaches to the new storage instead of dereferencing the stale one.

Key insight
The single mistake was that the FBO-reattachment workaround was implemented only for the mutable-storage code path and never applied to the immutable glTexStorage3D path, leaving attached framebuffers pointing at freed storage after a layer-count increase; the fix closes the gap by emitting the same TextureLayerCountIncreased notification from TextureGL::setStorage().

Attack Path

  1. Create and attach A page’s WebGL2 code creates a 2D_ARRAY texture, gives it storage, and attaches layer 0 of it to a framebuffer color attachment via glFramebufferTextureLayer.
  2. Reallocate via TexStorage3D The page calls glTexStorage3D (or otherwise re-drives setStorage()) with an increased depth, causing ANGLE to allocate new backing storage and free the old one without notifying the attached FBO.
  3. Dangle the attachment Because setStorage() never emitted TextureLayerCountIncreased, the framebuffer still references the freed storage, producing a use-after-free.
  4. Trigger the UAF The page renders to or samples from the framebuffer/texture, driving reads or writes through the dangling pointer to reclaimed GPU-process memory.

Impact Assessment

An attacker with a malicious WebGL2 page gains a use-after-free in Chrome’s GPU process, where ANGLE’s GL backend executes, potentially enabling controlled reads/writes into reclaimed memory and a path toward remote code execution in that process. Preconditions are only that the target uses the ANGLE GL backend with the affected code path and that the page can issue standard WebGL2 2D_ARRAY texture and framebuffer-layer calls; no special permissions are required beyond loading the page.

Files Changed

  • src/tests/gl_tests/TextureTest.cpp
  • src/libANGLE/renderer/gl/TextureGL.cpp

Audit Directions

  • Paired mutable/immutable paths
    When a workaround or invariant is added to a mutable resource-allocation path (glTexImage*), audit the immutable counterpart (glTexStorage*/setStorage) for the same notification or reattachment logic.
  • Reallocation without observer notification
    Flag any code that frees and reallocates backing storage but does not broadcast a SubjectMessage (e.g. ObjectReallocated, TextureLayerCountIncreased) to attachments such as FBOs.
  • Feature-flag-gated fixes
    Verify that security workarounds behind flags like reattachTextureToFboAfterLayerIncrease are consistently applied to every entry point that can trigger the vulnerable condition, not just the first one discovered.
From 87f5655006e4a66842c004a722440a643cc03c22 Mon Sep 17 00:00:00 2001
From: Zhenyao Mo <[email protected]>
Date: Tue, 18 Aug 2026 14:49:13 -0700
Subject: [PATCH] GL: Apply reattachTextureToFboAfterLayerIncrease to TexStorage3D

This adds the workaround logic inside TextureGL::setStorage() for cases
where an FBO is attached before the immutable storage is allocated. Also
updates the related tests to verify this with both TexImage3D and
TexStorage3D.

Bug: chromium:544163112
Change-Id: Ibb50ffeed6eaa369bed4ab25b625c16a1e63796c
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/8266365
Reviewed-by: Kenneth Russell <[email protected]>
Reviewed-by: Geoff Lang <[email protected]>
Commit-Queue: Zhenyao Mo <[email protected]>
---
diff --git a/src/libANGLE/renderer/gl/TextureGL.cpp b/src/libANGLE/renderer/gl/TextureGL.cpp
index be2ccee..45ea907 100644
--- a/src/libANGLE/renderer/gl/TextureGL.cpp
+++ b/src/libANGLE/renderer/gl/TextureGL.cpp
@@ -1300,6 +1300,20 @@
         onStateChange(angle::SubjectMessage::ObjectReallocated);
     }
 
+    if (features.reattachTextureToFboAfterLayerIncrease.enabled &&
+        getType() == gl::TextureType::_2DArray)
+    {
+        for (size_t level = 0; level < levels; level++)
+        {
+            const gl::ImageDesc &desc = mState.getImageDesc(gl::TextureTarget::_2DArray, level);
+            if (size.depth > desc.size.depth)
+            {
+                onStateChange(angle::SubjectMessage::TextureLayerCountIncreased);
+                break;
+            }
+        }
+    }
+
     const gl::InternalFormat &originalInternalFormatInfo =
         gl::GetSizedInternalFormatInfo(internalFormat);
     nativegl::TexStorageFormat texStorageFormat =
diff --git a/src/tests/gl_tests/TextureTest.cpp b/src/tests/gl_tests/TextureTest.cpp
index 3e6bc69..f391bdd 100644
--- a/src/tests/gl_tests/TextureTest.cpp
+++ b/src/tests/gl_tests/TextureTest.cpp
@@ -9363,54 +9363,70 @@
     // layer count without releasing storage.
     ANGLE_SKIP_TEST_IF(IsMetal());
 
-    glBindTexture(GL_TEXTURE_2D_ARRAY, m2DArrayTexture);
-    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    for (bool useTexStorage : {false, true})
+    {
+        glDeleteTextures(1, &m2DArrayTexture);
+        glGenTextures(1, &m2DArrayTexture);
 
-    std::vector<GLColor> pixelsRed(4 * 4 * 1, GLColor::red);
-    glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
-                 pixelsRed.data());
-    ASSERT_GL_NO_ERROR();
+        glBindTexture(GL_TEXTURE_2D_ARRAY, m2DArrayTexture);
+        glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+        glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 
-    GLFramebuffer fbo;
-    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
-    glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m2DArrayTexture, 0, 0);
-    EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::red);
+        std::vector<GLColor> pixelsRed(4 * 4 * 1, GLColor::red);
+        glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+                     pixelsRed.data());
+        ASSERT_GL_NO_ERROR();
 
-    // Increase layer count to 2.
-    std::vector<GLColor> pixelsGreen(4 * 4 * 2, GLColor::green);
-    glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 4, 4, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
-                 pixelsGreen.data());
-    ASSERT_GL_NO_ERROR();
+        GLFramebuffer fbo;
+        glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+        glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m2DArrayTexture, 0, 0);
 
-    // Verify layer 0 points to the new memory (green).
-    EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::green);
+        EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::red);
 
-    // Verify layer 1 is also green.
-    glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m2DArrayTexture, 0, 1);
-    EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::green);
+        // Increase layer count to 2.
+        std::vector<GLColor> pixelsGreen(4 * 4 * 2, GLColor::green);
+        if (useTexStorage)
+        {
+            glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, 4, 4, 2);
+            glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, 4, 4, 2, GL_RGBA, GL_UNSIGNED_BYTE,
+                            pixelsGreen.data());
+        }
+        else
+        {
+            glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 4, 4, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+                         pixelsGreen.data());
+        }
+        ASSERT_GL_NO_ERROR();
 
-    // Clear layer 1 to blue and verify.
-    glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
-    glClear(GL_COLOR_BUFFER_BIT);
-    EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::blue);
+        // Verify layer 0 points to the new memory (green).
+        EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::green);
 
-    // Now sample from layer 0 and layer 1 using a shader to ensure texture memory matches FBO
-    // memory.
-    glBindFramebuffer(GL_FRAMEBUFFER, 0);
-    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, 0);
-    glUseProgram(mProgram);
-    glUniform1i(mTextureArrayLocation, 0);
+        // Verify layer 1 is also green.
+        glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m2DArrayTexture, 0, 1);
+        EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::green);
 
-    // Verify layer 0 is green.
-    glUniform1i(mTextureArraySliceUniformLocation, 0);
-    drawQuad(mProgram, "position", 0.5f);
-    EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::green);
+        // Clear layer 1 to blue and verify.
+        glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
+        glClear(GL_COLOR_BUFFER_BIT);
+        EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::blue);
 
-    // Verify layer 1 is blue.
-    glUniform1i(mTextureArraySliceUniformLocation, 1);
-    drawQuad(mProgram, "position", 0.5f);
-    EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::blue);
+        // Now sample from layer 0 and layer 1 using a shader to ensure texture memory matches FBO
+        // memory.
+        glBindFramebuffer(GL_FRAMEBUFFER, 0);
+        glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, 0);
+        glUseProgram(mProgram);
+        glUniform1i(mTextureArrayLocation, 0);
+
+        // Verify layer 0 is green.
+        glUniform1i(mTextureArraySliceUniformLocation, 0);
+        drawQuad(mProgram, "position", 0.5f);
+        EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::green);
+
+        // Verify layer 1 is blue.
+        glUniform1i(mTextureArraySliceUniformLocation, 1);
+        drawQuad(mProgram, "position", 0.5f);
+        EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::blue);
+    }
 }
 
 // Test increasing layer count of a 2D array texture when one of its layers is attached to a
@@ -9423,62 +9439,78 @@
     // layer count without releasing storage.
     ANGLE_SKIP_TEST_IF(IsMetal());
 
-    glBindTexture(GL_TEXTURE_2D_ARRAY, m2DArrayTexture);
-    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    for (bool useTexStorage : {false, true})
+    {
+        glDeleteTextures(1, &m2DArrayTexture);
+        glGenTextures(1, &m2DArrayTexture);
 
-    std::vector<GLColor> pixelsRed(4 * 4 * 1, GLColor::red);
-    glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
-                 pixelsRed.data());
-    ASSERT_GL_NO_ERROR();
+        glBindTexture(GL_TEXTURE_2D_ARRAY, m2DArrayTexture);
+        glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+        glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 
-    GLFramebuffer fbo;
-    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
-    glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m2DArrayTexture, 0, 0);
-    EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::red);
+        std::vector<GLColor> pixelsRed(4 * 4 * 1, GLColor::red);
+        glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+                     pixelsRed.data());
+        ASSERT_GL_NO_ERROR();
 
-    // Set up and switch to a secondary context sharing resources with the current context.
-    EGLWindow *window          = getEGLWindow();
-    EGLDisplay display         = window->getDisplay();
-    EGLConfig config           = window->getConfig();
-    EGLSurface surface         = window->getSurface();
-    EGLint contextAttributes[] = {
-        EGL_CONTEXT_MAJOR_VERSION_KHR,
-        GetParam().majorVersion,
-        EGL_CONTEXT_MINOR_VERSION_KHR,
-        GetParam().minorVersion,
-        EGL_NONE,
-    };
-    EGLContext context1 = eglGetCurrentContext();
-    EGLContext context2 = eglCreateContext(display, config, context1, contextAttributes);
-    ASSERT_NE(context2, EGL_NO_CONTEXT);
-    eglMakeCurrent(display, surface, surface, context2);
+        GLFramebuffer fbo;
+        glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+        glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m2DArrayTexture, 0, 0);
 
-    // In the secondary context, bind the texture and increase layer count to 2.
-    glBindTexture(GL_TEXTURE_2D_ARRAY, m2DArrayTexture);
-    std::vector<GLColor> pixelsGreen(4 * 4 * 2, GLColor::green);
-    glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 4, 4, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
-                 pixelsGreen.data());
-    ASSERT_GL_NO_ERROR();
+        EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::red);
 
-    // Switch back to the primary context.
-    eglMakeCurrent(display, surface, surface, context1);
+        // Set up and switch to a secondary context sharing resources with the current context.
+        EGLWindow *window          = getEGLWindow();
+        EGLDisplay display         = window->getDisplay();
+        EGLConfig config           = window->getConfig();
+        EGLSurface surface         = window->getSurface();
+        EGLint contextAttributes[] = {
+            EGL_CONTEXT_MAJOR_VERSION_KHR,
+            GetParam().majorVersion,
+            EGL_CONTEXT_MINOR_VERSION_KHR,
+            GetParam().minorVersion,
+            EGL_NONE,
+        };
+        EGLContext context1 = eglGetCurrentContext();
+        EGLContext context2 = eglCreateContext(display, config, context1, contextAttributes);
+        ASSERT_NE(context2, EGL_NO_CONTEXT);
+        eglMakeCurrent(display, surface, surface, context2);
 
-    // Verify layer 0 points to the new memory (green).
-    EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::green);
+        // In the secondary context, bind the texture and increase layer count to 2.
+        glBindTexture(GL_TEXTURE_2D_ARRAY, m2DArrayTexture);
+        std::vector<GLColor> pixelsGreen(4 * 4 * 2, GLColor::green);
+        if (useTexStorage)
+        {
+            glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, 4, 4, 2);
+            glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, 4, 4, 2, GL_RGBA, GL_UNSIGNED_BYTE,
+                            pixelsGreen.data());
+        }
+        else
+        {
+            glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 4, 4, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+                         pixelsGreen.data());
+        }
+        ASSERT_GL_NO_ERROR();
 
-    // Attach layer 1 to the FBO in context1 and verify. Explicitly calling
-    // glFramebufferTextureLayer attaches to the newly allocated texture storage.
-    glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m2DArrayTexture, 0, 1);
-    EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::green);
+        // Switch back to the primary context.
+        eglMakeCurrent(display, surface, surface, context1);
 
-    // Clear layer 1 to blue and verify.
-    glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
-    glClear(GL_COLOR_BUFFER_BIT);
-    EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::blue);
+        // Verify layer 0 points to the new memory (green).
+        EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::green);
 
-    // Clean up secondary context.
-    eglDestroyContext(display, context2);
+        // Attach layer 1 to the FBO in context1 and verify. Explicitly calling
+        // glFramebufferTextureLayer attaches to the newly allocated texture storage.
+        glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m2DArrayTexture, 0, 1);
+        EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::green);
+
+        // Clear layer 1 to blue and verify.
+        glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
+        glClear(GL_COLOR_BUFFER_BIT);
+        EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::blue);
+
+        // Clean up secondary context.
+        eglDestroyContext(display, context2);
+    }
 }
 
 // Create a 3D texture, use it, then redefine one level without changing dimensions.
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/src/tests/gl_tests/TextureTest.cpp b/src/tests/gl_tests/TextureTest.cpp
index 3e6bc69..f391bdd 100644
--- a/src/tests/gl_tests/TextureTest.cpp
+++ b/src/tests/gl_tests/TextureTest.cpp
@@ -9363,54 +9363,70 @@
     // layer count without releasing storage.
     ANGLE_SKIP_TEST_IF(IsMetal());
 
-    glBindTexture(GL_TEXTURE_2D_ARRAY, m2DArrayTexture);
-    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    for (bool useTexStorage : {false, true})
+    {
+        glDeleteTextures(1, &m2DArrayTexture);
+        glGenTextures(1, &m2DArrayTexture);
 
-    std::vector<GLColor> pixelsRed(4 * 4 * 1, GLColor::red);
-    glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
-                 pixelsRed.data());
-    ASSERT_GL_NO_ERROR();
+        glBindTexture(GL_TEXTURE_2D_ARRAY, m2DArrayTexture);
+        glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+        glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 
-    GLFramebuffer fbo;
-    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
-    glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m2DArrayTexture, 0, 0);
-    EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::red);
+        std::vector<GLColor> pixelsRed(4 * 4 * 1, GLColor::red);
+        glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+                     pixelsRed.data());
+        ASSERT_GL_NO_ERROR();
 
-    // Increase layer count to 2.
-    std::vector<GLColor> pixelsGreen(4 * 4 * 2, GLColor::green);
-    glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 4, 4, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
-                 pixelsGreen.data());
-    ASSERT_GL_NO_ERROR();
+        GLFramebuffer fbo;
+        glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+        glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m2DArrayTexture, 0, 0);
 
-    // Verify layer 0 points to the new memory (green).
-    EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::green);
+        EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::red);
 
-    // Verify layer 1 is also green.
-    glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m2DArrayTexture, 0, 1);
-    EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::green);
+        // Increase layer count to 2.
+        std::vector<GLColor> pixelsGreen(4 * 4 * 2, GLColor::green);
+        if (useTexStorage)
+        {
+            glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, 4, 4, 2);
+            glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, 4, 4, 2, GL_RGBA, GL_UNSIGNED_BYTE,
+                            pixelsGreen.data());
+        }
+        else
+        {
+            glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 4, 4, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+                         pixelsGreen.data());
+        }
+        ASSERT_GL_NO_ERROR();
 
-    // Clear layer 1 to blue and verify.
-    glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
-    glClear(GL_COLOR_BUFFER_BIT);
-    EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::blue);
+        // Verify layer 0 points to the new memory (green).
+        EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::green);
 
-    // Now sample from layer 0 and layer 1 using a shader to ensure texture memory matches FBO
-    // memory.
-    glBindFramebuffer(GL_FRAMEBUFFER, 0);
-    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, 0);
-    glUseProgram(mProgram);
-    glUniform1i(mTextureArrayLocation, 0);
+        // Verify layer 1 is also green.
+        glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m2DArrayTexture, 0, 1);
+        EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::green);
 
-    // Verify layer 0 is green.
-    glUniform1i(mTextureArraySliceUniformLocation, 0);
-    drawQuad(mProgram, "position", 0.5f);
-    EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::green);
+        // Clear layer 1 to blue and verify.
+        glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
+        glClear(GL_COLOR_BUFFER_BIT);
+        EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::blue);
 
-    // Verify layer 1 is blue.
-    glUniform1i(mTextureArraySliceUniformLocation, 1);
-    drawQuad(mProgram, "position", 0.5f);
-    EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::blue);
+        // Now sample from layer 0 and layer 1 using a shader to ensure texture memory matches FBO
+        // memory.
+        glBindFramebuffer(GL_FRAMEBUFFER, 0);
+        glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, 0);
+        glUseProgram(mProgram);
+        glUniform1i(mTextureArrayLocation, 0);
+
+        // Verify layer 0 is green.
+        glUniform1i(mTextureArraySliceUniformLocation, 0);
+        drawQuad(mProgram, "position", 0.5f);
+        EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::green);
+
+        // Verify layer 1 is blue.
+        glUniform1i(mTextureArraySliceUniformLocation, 1);
+        drawQuad(mProgram, "position", 0.5f);
+        EXPECT_PIXEL_RECT_EQ(0, 0, getWindowWidth(), getWindowHeight(), GLColor::blue);
+    }
 }
 
 // Test increasing layer count of a 2D array texture when one of its layers is attached to a
@@ -9423,62 +9439,78 @@
     // layer count without releasing storage.
     ANGLE_SKIP_TEST_IF(IsMetal());
 
-    glBindTexture(GL_TEXTURE_2D_ARRAY, m2DArrayTexture);
-    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    for (bool useTexStorage : {false, true})
+    {
+        glDeleteTextures(1, &m2DArrayTexture);
+        glGenTextures(1, &m2DArrayTexture);
 
-    std::vector<GLColor> pixelsRed(4 * 4 * 1, GLColor::red);
-    glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
-                 pixelsRed.data());
-    ASSERT_GL_NO_ERROR();
+        glBindTexture(GL_TEXTURE_2D_ARRAY, m2DArrayTexture);
+        glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+        glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 
-    GLFramebuffer fbo;
-    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
-    glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m2DArrayTexture, 0, 0);
-    EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::red);
+        std::vector<GLColor> pixelsRed(4 * 4 * 1, GLColor::red);
+        glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+                     pixelsRed.data());
+        ASSERT_GL_NO_ERROR();
 
-    // Set up and switch to a secondary context sharing resources with the current context.
-    EGLWindow *window          = getEGLWindow();
-    EGLDisplay display         = window->getDisplay();
-    EGLConfig config           = window->getConfig();
-    EGLSurface surface         = window->getSurface();
-    EGLint contextAttributes[] = {
-        EGL_CONTEXT_MAJOR_VERSION_KHR,
-        GetParam().majorVersion,
-        EGL_CONTEXT_MINOR_VERSION_KHR,
-        GetParam().minorVersion,
-        EGL_NONE,
-    };
-    EGLContext context1 = eglGetCurrentContext();
-    EGLContext context2 = eglCreateContext(display, config, context1, contextAttributes);
-    ASSERT_NE(context2, EGL_NO_CONTEXT);
-    eglMakeCurrent(display, surface, surface, context2);
+        GLFramebuffer fbo;
+        glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+        glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m2DArrayTexture, 0, 0);
 
-    // In the secondary context, bind the texture and increase layer count to 2.
-    glBindTexture(GL_TEXTURE_2D_ARRAY, m2DArrayTexture);
-    std::vector<GLColor> pixelsGreen(4 * 4 * 2, GLColor::green);
-    glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 4, 4, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
-                 pixelsGreen.data());
-    ASSERT_GL_NO_ERROR();
+        EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::red);
 
-    // Switch back to the primary context.
-    eglMakeCurrent(display, surface, surface, context1);
+        // Set up and switch to a secondary context sharing resources with the current context.
+        EGLWindow *window          = getEGLWindow();
+        EGLDisplay display         = window->getDisplay();
+        EGLConfig config           = window->getConfig();
+        EGLSurface surface         = window->getSurface();
+        EGLint contextAttributes[] = {
+            EGL_CONTEXT_MAJOR_VERSION_KHR,
+            GetParam().majorVersion,
+            EGL_CONTEXT_MINOR_VERSION_KHR,
+            GetParam().minorVersion,
+            EGL_NONE,
+        };
+        EGLContext context1 = eglGetCurrentContext();
+        EGLContext context2 = eglCreateContext(display, config, context1, contextAttributes);
+        ASSERT_NE(context2, EGL_NO_CONTEXT);
+        eglMakeCurrent(display, surface, surface, context2);
 
-    // Verify layer 0 points to the new memory (green).
-    EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::green);
+        // In the secondary context, bind the texture and increase layer count to 2.
+        glBindTexture(GL_TEXTURE_2D_ARRAY, m2DArrayTexture);
+        std::vector<GLColor> pixelsGreen(4 * 4 * 2, GLColor::green);
+        if (useTexStorage)
+        {
+            glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, 4, 4, 2);
+            glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, 4, 4, 2, GL_RGBA, GL_UNSIGNED_BYTE,
+                            pixelsGreen.data());
+        }
+        else
+        {
+            glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 4, 4, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+                         pixelsGreen.data());
+        }
+        ASSERT_GL_NO_ERROR();
 
-    // Attach layer 1 to the FBO in context1 and verify. Explicitly calling
-    // glFramebufferTextureLayer attaches to the newly allocated texture storage.
-    glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m2DArrayTexture, 0, 1);
-    EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::green);
+        // Switch back to the primary context.
+        eglMakeCurrent(display, surface, surface, context1);
 
-    // Clear layer 1 to blue and verify.
-    glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
-    glClear(GL_COLOR_BUFFER_BIT);
-    EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::blue);
+        // Verify layer 0 points to the new memory (green).
+        EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::green);
 
-    // Clean up secondary context.
-    eglDestroyContext(display, context2);
+        // Attach layer 1 to the FBO in context1 and verify. Explicitly calling
+        // glFramebufferTextureLayer attaches to the newly allocated texture storage.
+        glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m2DArrayTexture, 0, 1);
+        EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::green);
+
+        // Clear layer 1 to blue and verify.
+        glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
+        glClear(GL_COLOR_BUFFER_BIT);
+        EXPECT_PIXEL_RECT_EQ(0, 0, 4, 4, GLColor::blue);
+
+        // Clean up secondary context.
+        eglDestroyContext(display, context2);
+    }
 }
 
 // Create a 3D texture, use it, then redefine one level without changing dimensions.
Loading diff…

Original Bug Report

reported by [email protected]

PowerVR `texStorage3D` attachment lifetime bug yields address-selected native CPU r/w/RCE from WebGL

Steps to reproduce the problem

  1. Use a Pixel 10 Pro running the latest stock security update (July 5) Google build shown below. HAS TO BE EXACTLY A PIXEL 10 PRO,
  2. Open the attached PoC.html in Chrome Canary.
  3. Observe the page output and adb logcat.
  4. The page first proves an address-selected native read and write against a safe in-process allocation. It then changes the same native destination pointer to 0x0000414141414000 and submits one more uniform update.
  5. Chrome’s GPU process terminates with SIGSEGV; the tombstone reports fault address 0x0000414141414000, and register x8 contains the same attacker-selected value.

Hosted copy used for this run:

https://payload.engineering/14184-24622-23478/FUCK/B0018_8dcf_selected_write_7f3a.html

26f71e7f26cf3a96edb8d02f9c4078d8ebef1b1f6f5b21b72e85f3e8ccfb8f80 PoC.html

Problem Description

I will provide a full system() exploit as soon as possible. Preliminary findings:

The WebGL2 page obtains two stale native mip-record aliases after growing attached TEXTURE_2D_ARRAY storage with texStorage3D. It uses the aliases and deterministic 0x2600/0x3c0 allocation reuse to leave a native program object reachable after its backing record has been freed and reclaimed.

The reclaimed GLES3ProgramRec can be shaped so that its default uniform-store pointer names an address selected by the page. The PoC demonstrates both directions before crashing:

alias 1: controller=0 marker=0 object=0xb4000077bd549290
alias 2: controller=1 marker=1 object=0xb4000077bd547010
address-selected native read proven; native program name=13
address-selected native write proven at 0xb4000077bd549600
ARMED: next native uniform write destination=0x0000414141414000
Submitting 16 bytes of 0x41; inspect logcat for the GPU-process write fault.
WebGL context lost after native write submission

The safe write is verified through a second, independent WebGL uniform view of the reclaimed native allocation. The final deliberately unmapped destination faults on the driver’s preparatory read before the write, producing a stable attacker-selected native-pointer tombstone:

F libc    : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR),
            fault addr 0x414141414000 in tid 17828 (CrGpuMain)

F DEBUG   : Cmdline: com.chrome.canary:privileged_process0
F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR),
            fault addr 0x0000414141414000 (read)
F DEBUG   :     x8  0000414141414000
F DEBUG   :     pc  000000773313ba2c
F DEBUG   : backtrace:
F DEBUG   :   #00 pc 0000000000127a2c  /vendor/lib64/egl/libGLESv2_powervr.so
F DEBUG   :       (GLES3ProgramUniformScalarVector(...)+188)
F DEBUG   :       (BuildId: 8dcf1f5c390a11f44a0be224d4d3f31d)
F DEBUG   :   #01 pc 00000000001a14dc  /vendor/lib64/egl/libGLESv2_powervr.so
F DEBUG   :       (glProgramUniform4uiv+124)
F DEBUG   :       (BuildId: 8dcf1f5c390a11f44a0be224d4d3f31d)

The complete logcat and a screenshot containing the successful safe read/write proof immediately before the crash are attached.

Expected result

Changing or replacing texture storage while the texture is attached must not leave a native driver record referencing freed or subsequently reused CPU memory. WebGL object operations must not permit a page to select a native pointer used by glGetUniform*/glProgramUniform*.

Security impact

This is not only a null dereference or GPU denial of service. The page demonstrates:

  1. A stale native PowerVR object alias reachable from WebGL2.
  2. Controlled reclaim as a live GLES3ProgramRec.
  3. Address-selected native CPU read.
  4. Address-selected 16-byte native CPU write, verified at a safe mapped target.
  5. A final native access using the page-selected pointer 0x0000414141414000, confirmed in the GPU-process tombstone and register state.

The current PoC intentionally stops at a controlled GPU-process crash. We have not included a code-execution payload.

Tested environment

Device: Pixel 10 Pro (blazer)
Build fingerprint: google/blazer/blazer:17/CP2A.260705.006/15641320:user/release-keys
Security patch: 2026-07-05
Chrome Canary: 153.0.7997.0 (799700004)
Chrome GPU-process UID: 10325

libGLESv2_powervr.so
BuildId: 8dcf1f5c390a11f44a0be224d4d3f31d
SHA-256: 6956f1f4ec041b66692518d1e47db738d78bce47692ac68b26bda2f090e7226e

The OS/vendor binaries are stock Google and the device is unrooted. The bootloader was already unlocked; the PoC does not require root, debugging APIs, native code, command-line flags, or user interaction beyond opening the page.

Note: I reported the root cause already here: https://issues.chromium.org/issues/543660458

Summary

PowerVR texStorage3D attachment lifetime bug yields address-selected native CPU r/w/RCE from WebGL

Custom Questions

Type of crash:

GPU

Crash state:

08-08 20:57:58.996 18480 18480 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
08-08 20:57:58.996 18480 18480 F DEBUG   : Build fingerprint: 'google/blazer/blazer:17/CP2A.260705.006/15641320:user/release-keys'
08-08 20:57:58.996 18480 18480 F DEBUG   : Kernel Release: '6.6.118-android15-8-g53e6e091166e-ab15266607-4k'
08-08 20:57:58.996 18480 18480 F DEBUG   : Revision: 'MP1.0'
08-08 20:57:58.996 18480 18480 F DEBUG   : ABI: 'arm64'
08-08 20:57:58.996 18480 18480 F DEBUG   : Timestamp: 2026-08-08 20:57:58.890241123+0200
08-08 20:57:58.996 18480 18480 F DEBUG   : Process uptime: 22s
08-08 20:57:58.996 18480 18480 F DEBUG   : Executable: /system/bin/app_process64
08-08 20:57:58.996 18480 18480 F DEBUG   : Cmdline: com.chrome.canary:privileged_process6
08-08 20:57:58.996 18480 18480 F DEBUG   : pid: 18428, ppid: 1003, tid: 18441, name: CrGpuMain  >>> com.chrome.canary:privileged_process6 <<<
08-08 20:57:58.996 18480 18480 F DEBUG   : uid: 10325
08-08 20:57:58.996 18480 18480 F DEBUG   : tagged_addr_ctrl: 0000000000000001 (PR_TAGGED_ADDR_ENABLE)
08-08 20:57:58.996 18480 18480 F DEBUG   : pac_enabled_keys: 000000000000000f (PR_PAC_APIAKEY, PR_PAC_APIBKEY, PR_PAC_APDAKEY, PR_PAC_APDBKEY)
08-08 20:57:58.996 18480 18480 F DEBUG   : esr: 0000000092000004 (Data Abort Exception 0x24)
08-08 20:57:58.996 18480 18480 F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0000414141414000 (read)
08-08 20:57:58.996 18480 18480 F DEBUG   :     x0  b4000077bd55cf80  x1  b4000077bd55cd60  x2  0000000000000010  x3  0000000000000001
08-08 20:57:58.996 18480 18480 F DEBUG   :     x4  000000773304377c  x5  0000007784967e94  x6  00000077331f0e40  x7  000000000000000e
08-08 20:57:58.996 18480 18480 F DEBUG   :     x8  0000414141414000  x9  0000000000000004  x10 0000000000000000  x11 0000000000000001
08-08 20:57:58.996 18480 18480 F DEBUG   :     x12 0000000000000001  x13 0000000000000001  x14 0000007200d3aa90  x15 ffffffffff00ffff
08-08 20:57:58.996 18480 18480 F DEBUG   :     x16 000000773e8f95a0  x17 0000007a4e953180  x18 00000076e6e14000  x19 b40000797d4b1080
08-08 20:57:58.996 18480 18480 F DEBUG   :     x20 0000007784967e94  x21 000000773304377c  x22 0000000000000004  x23 0000000000000001
08-08 20:57:58.996 18480 18480 F DEBUG   :     x24 0000000000000000  x25 b4000077bd55cd60  x26 00000077331f0e40  x27 000000000000000e
08-08 20:57:58.996 18480 18480 F DEBUG   :     x28 0000000000000007  x29 00000076e78d5590
08-08 20:57:58.996 18480 18480 F DEBUG   :     lr  002b24773313b9c0  sp  00000076e78d5480  pc  000000773313ba2c  pst 0000000080001000
08-08 20:57:58.996 18480 18480 F DEBUG   :     esr 0000000092000004  vg  0000000000000002
08-08 20:57:58.996 18480 18480 F DEBUG   : 29 total frames
08-08 20:57:58.996 18480 18480 F DEBUG   : backtrace:
08-08 20:57:58.996 18480 18480 F DEBUG   :       #00 pc 0000000000127a2c  /vendor/lib64/egl/libGLESv2_powervr.so (GLES3ProgramUniformScalarVector(GLES3Context_TAG*, GLES3ProgramRec*, unsigned int, int, int, void const*, char const* const*, GLSLTypeSpecifierTAG, GLES3UniformTypeTAG, char const*) (.__uniq.175030908309407430927784858702543253136)+188) (BuildId: 8dcf1f5c390a11f44a0be224d4d3f31d)
08-08 20:57:58.996 18480 18480 F DEBUG   :       #01 pc 00000000001a14dc  /vendor/lib64/egl/libGLESv2_powervr.so (glProgramUniform4uiv+124) (BuildId: 8dcf1f5c390a11f44a0be224d4d3f31d)
08-08 20:57:58.996 18480 18480 F DEBUG   :       #02 pc 00000000097d7a48  /data/app/~~baPAwlVs5Yy4AjAz63MIeg==/com.chrome.canary-c_DMREJulaN92SuKHIA2fQ==/base.apk!libchrome.so (offset 0xf78000) (BuildId: 3e2f88e3eafde15b51dd0c5af94c81c8fdba410f)
08-08 20:57:58.996 18480 18480 F DEBUG   :       #03 pc 00000000097c8a50  /data/app/~~baPAwlVs5Yy4AjAz63MIeg==/com.chrome.canary-c_DMREJulaN92SuKHIA2fQ==/base.apk!libchrome.so (offset 0xf78000) (BuildId: 3e2f88e3eafde15b51dd0c5af94c81c8fdba410f)
08-08 20:57:58.996 18480 18480 F DEBUG   :       #04 pc 0000000007988314  /data/app/~~baPAwlVs5Yy4AjAz63MIeg==/com.chrome.canary-c_DMREJulaN92SuKHIA2fQ==/base.apk!libchrome.so (offset 0xf78000) (BuildId: 3e2f88e3eafde15b51dd0c5af94c81c8fdba410f)
08-08 20:57:58.996 18480 18480 F DEBUG   :       #05 pc 0000000007987808  /data/app/~~baPAwlVs5Yy4AjAz63MIeg==/com.chrome.canary-c_DMREJulaN92SuKHIA2fQ==/base.apk!libchrome.so (offset 0xf78000) (BuildId: 3e2f88e3eafde15b51dd0c5af94c81c8fdba410f)
08-08 20:57:58.996 18480 18480 F DEBUG   :       #06 pc 000000000798751c  /data/app/~~baPAwlVs5Yy4AjAz63MIeg==/com.chrome.canary-c_DMREJulaN92SuKHIA2fQ==/base.apk!libchrome.so (offset 0xf78000) (BuildId: 3e2f88e3eafde15b51dd0c5af94c81c8fdba410f)
08-08 20:57:58.996 18480 18480 F DEBUG   :       #07 pc 00000000079873c8  /data/app/~~baPAwlVs5Yy4AjAz63MIeg==/com.chrome.canary-c_DMREJulaN92SuKHIA2fQ==/base.apk!libchrome.so (offset 0xf78000) (BuildId: 3e2f88e3eafde15b51dd0c5af94c81c8fdba410f)
08-08 20:57:58.996 18480 18480 F DEBUG   :       #08 pc 0000000007987338  /data/app/~~baPAwlVs5Yy4AjAz63MIeg==/com.chrome.canary-c_DMREJulaN92SuKHIA2fQ==/base.apk!libchrome.so (offset 0xf78000) (BuildId: 3e2f88e3eafde15b51dd0c5af94c81c8fdba410f)
08-08 20:57:58.996 18480 18480 F DEBUG   :       #09 pc 00000000079600fc  /data/app/~~baPAwlVs5Yy4AjAz63MIeg==/com.chrome.canary-c_DMREJulaN92SuKHIA2fQ==/base.apk!libchrome.so (offset 0xf78000) (BuildId: 3e2f88e3eafde15b51dd0c5af94c81c8fdba410f)
08-08 20:57:58.996 18480 18480 F DEBUG   :       #10 pc 0000000007d18bc4  /data/app/~~baPAwlVs5Yy4AjAz63MIeg==/com.chrome.canary-c_DMREJulaN92SuKHIA2fQ==/base.apk!libchrome.so (offset 0xf78000) (BuildId: 3e2f88e3eafde15b51dd0c5af94c81c8fdba410f)
08-08 20:57:58.996 18480 18480 F DEBUG   :       #11 pc 000000000641a3c4  /data/app/~~baPAwlVs5Yy4AjAz63MIeg==/com.chrome.canary-c_DMREJulaN92SuKHIA2fQ==/base.apk!libchrome.so (offset 0xf78000) (BuildId: 3e2f88e3eafde15b51dd0c5af94c81c8fdba410f)
08-08 20:57:58.996 18480 18480 F DEBUG   :       #12 pc 00000000062b24d0  /data/app/~~baPAwlVs5Yy4AjAz63MIeg==/com.chrome.canary-c_DMREJulaN92SuKHIA2fQ==/base.apk!libchrome.so (offset 0xf78000) (BuildId: 3e2f88e3eafde15b51dd0c5af94c81c8fdba410f)
08-08 20:57:58.996 18480 18480 F DEBUG   :       #13 pc 00000000062b2020  /data/app/~~baPAwlVs5Yy4AjAz63MIeg==/com.chrome.canary-c_DMREJulaN92SuKHIA2fQ==/base.apk!libchrome.so (offset 0xf78000) (BuildId: 3e2f88e3eafde15b51dd0c5af94c81c8fdba410f)
08-08 20:57:58.996 18480 18480 F DEBUG   :       #14 pc 0000000007c7ff90  /data/app/~~baPAwlVs5Yy4AjAz63MIeg==/com.chrome.canary-c_DMREJulaN92SuKHIA2fQ==/base.apk!libchrome.so (offset 0xf78000) (BuildId: 3e2f88e3eafde15b51dd0c5af94c81c8fdba410f)
08-08 20:57:58.996 18480 18480 F DEBUG   :       #15 pc 000000000638c994  /data/app/~~baPAwlVs5Yy4AjAz63MIeg==/com.chrome.canary-c_DMREJulaN92SuKHIA2fQ==/base.apk!libchrome.so (offset 0xf78000) (BuildId: 3e2f88e3eafde15b51dd0c5af94c81c8fdba410f)
08-08 20:57:58.996 18480 18480 F DEBUG   :       #16 pc 00000000062ce0fc  /data/app/~~baPAwlVs5Yy4AjAz63MIeg==/com.chrome.canary-c_DMREJulaN92SuKHIA2fQ==/base.apk!libchrome.so (offset 0xf78000) (BuildId: 3e2f88e3eafde15b51dd0c5af94c81c8fdba410f)
08-08 20:57:58.996 18480 18480 F DEBUG   :       #17 pc 00000000062cd4ac  /data/app/~~baPAwlVs5Yy4AjAz63MIeg==/com.chrome.canary-c_DMREJulaN92SuKHIA2fQ==/base.apk!libchrome.so (offset 0xf78000) (BuildId: 3e2f88e3eafde15b51dd0c5af94c81c8fdba410f)
08-08 20:57:58.996 18480 18480 F DEBUG   :       #18 pc 00000000062cd1f8  /data/app/~~baPAwlVs5Yy4AjAz63MIeg==/com.chrome.canary-c_DMREJulaN92SuKHIA2fQ==/base.apk!libchrome.so (offset 0xf78000) (BuildId: 3e2f88e3eafde15b51dd0c5af94c81c8fdba410f)
08-08 20:57:58.996 18480 18480 F DEBUG   :       #19 pc 00000000002e42b8  /system/framework/arm64/boot.oat (art_jni_trampoline+104) (BuildId: 4d093721a5cd1aa2dbff309faa61a2832807aef9)
08-08 20:57:58.996 18480 18480 F DEBUG   :       #20 pc 000000000072c104  /apex/com.android.art/lib64/libart.so (nterp_helper+116) (BuildId: 1f156fc62660d075a8d675db850b95d5)
08-08 20:57:58.996 18480 18480 F DEBUG   :       #21 pc 00000000000fcd42  /data/app/~~baPAwlVs5Yy4AjAz63MIeg==/com.chrome.canary-c_DMREJulaN92SuKHIA2fQ==/base.apk (offset 0xbea000) (lb4.run+582)
08-08 20:57:58.996 18480 18480 F DEBUG   :       #22 pc 00000000000a9d10  /system/framework/arm64/boot.oat (java.lang.Thread.run+64) (BuildId: 4d093721a5cd1aa2dbff309faa61a2832807aef9)
08-08 20:57:58.996 18480 18480 F DEBUG   :       #23 pc 0000000000298f94  /apex/com.android.art/lib64/libart.so (art_quick_invoke_stub+612) (BuildId: 1f156fc62660d075a8d675db850b95d5)
08-08 20:57:58.996 18480 18480 F DEBUG   :       #24 pc 000000000029738c  /apex/com.android.art/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+148) (BuildId: 1f156fc62660d075a8d675db850b95d5)
08-08 20:57:58.996 18480 18480 F DEBUG   :       #25 pc 00000000004d5fd0  /apex/com.android.art/lib64/libart.so (art::Thread::CreateCallback(void*)+1384) (BuildId: 1f156fc62660d075a8d675db850b95d5)
08-08 20:57:58.996 18480 18480 F DEBUG   :       #26 pc 00000000004d5a54  /apex/com.android.art/lib64/libart.so (art::Thread::CreateCallbackWithUffdGc(void*)+12) (BuildId: 1f156fc62660d075a8d675db850b95d5)
08-08 20:57:58.996 18480 18480 F DEBUG   :       #27 pc 000000000008d954  /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*) (.__uniq.67847048707805468364044055584648682506)+180) (BuildId: bff603430d1ad139d4f0e6a78f542c4d)
08-08 20:57:58.996 18480 18480 F DEBUG   :       #28 pc 000000000007da64  /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+68) (BuildId: bff603430d1ad139d4f0e6a78f542c4d)

Reporter credit:

Lexi Groves (49016)

Additional Data

Category: Security
Chrome Channel: Canary
Regression: N/A \

View on issue tracker