CVE-2026-14408
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
BlitTextureToBufferTestsrc/dawn/tests/end2end/CopyTests.cpp |
modified | |
TEST_Psrc/dawn/tests/end2end/CopyTests.cpp |
modified |
Files Changed
src/dawn/native/BlitTextureToBuffer.cppsrc/dawn/tests/end2end/BufferZeroInitTests.cppsrc/dawn/tests/end2end/CopyTests.cppsrc/dawn/tests/end2end/TextureZeroInitTests.cpp
Patch
From 6ea97833a636247bc137ee6d24efd0ac7a68111d Mon Sep 17 00:00:00 2001 From: Shrek Shao <[email protected]> Date: Wed, 20 May 2026 11:06:10 -0700 Subject: [PATCH] Remove the optimization of a clearing buffer in BlitTextureToBuffer This optimization is temporarily removed because we cannot mark the buffer as initialized until the command buffer is submitted. FIXED: 513631768 Change-Id: Ie6f539e07139c5eefef9ddf87231af346d7a9e28 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/309588 Auto-Submit: Shrek Shao <[email protected]> Reviewed-by: Loko Kung <[email protected]> Commit-Queue: Shrek Shao <[email protected]> --- diff --git a/src/dawn/native/BlitTextureToBuffer.cpp b/src/dawn/native/BlitTextureToBuffer.cpp index 22fa7f2..b663bfc 100644 --- a/src/dawn/native/BlitTextureToBuffer.cpp +++ b/src/dawn/native/BlitTextureToBuffer.cpp @@ -1354,8 +1354,11 @@ UsageValidationMode::Internal)); } - // Skip clearing the buffer if this is full size copy. - dst.buffer->SetInitialized(fullSizeCopy || dst.buffer->IsInitialized()); + // TODO(b/513631768): Skip clearing the buffer if this is full size copy. + // dst.buffer->SetInitialized(fullSizeCopy || dst.buffer->IsInitialized()); + // + // This optimization is temporarily removed because we cannot mark the buffer as initialized + // until the command buffer is submitted. Ref<ComputePassEncoder> pass = commandEncoder->BeginComputePass(); pass->APISetPipeline(pipeline.Get()); diff --git a/src/dawn/tests/end2end/BufferZeroInitTests.cpp b/src/dawn/tests/end2end/BufferZeroInitTests.cpp index 6d86a10..625446a 100644 --- a/src/dawn/tests/end2end/BufferZeroInitTests.cpp +++ b/src/dawn/tests/end2end/BufferZeroInitTests.cpp @@ -145,7 +145,14 @@ wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); encoder.CopyTextureToBuffer(&texelCopyTextureInfo, &texelCopyBufferInfo, &spec.textureSize); wgpu::CommandBuffer commandBuffer = encoder.Finish(); - EXPECT_LAZY_CLEAR(spec.lazyClearCount, queue.Submit(1, &commandBuffer)); + + // TODO(b/513631768): SetInitialized is now skipped for use_blit_for_t2b path. + uint32_t expectedLazyClearCount = spec.lazyClearCount; + if (expectedLazyClearCount == 0u && (HasToggleEnabled("use_blit_for_t2b"))) { + expectedLazyClearCount = 1u; + } + + EXPECT_LAZY_CLEAR(expectedLazyClearCount, queue.Submit(1, &commandBuffer)); const uint64_t expectedValueCount = bufferSize / sizeof(float); std::vector<float> expectedValues(expectedValueCount, 0.f); @@ -1153,6 +1160,10 @@ // TODO(crbug.com/473593119): [Capture] size not multiple of 4. DAWN_SUPPRESS_TEST_IF(IsCaptureReplayCheckingEnabled()); + // TODO(crbug.com/513631768): Skip D3D11 as they may use intermediate buffer for blit + // path and fail for EXPECT_LAZY_CLEAR. + DAWN_SUPPRESS_TEST_IF(IsD3D11()); + constexpr wgpu::TextureFormat kColorAttachmentFormat = wgpu::TextureFormat::RGBA8Unorm; // A small sub-4-byte format means a single vertex can fit entirely within the padded buffer, // touching some of the padding. Test a small format, as well as larger formats. @@ -1222,7 +1233,13 @@ encoder.CopyTextureToBuffer(&zeroTextureSrc, &dst, &extent); wgpu::CommandBuffer commandBuffer = encoder.Finish(); - EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commandBuffer)); + + // TODO(b/513631768): SetInitialized is now skipped for use_blit_for_t2b path. + uint32_t expectedLazyClearCount = 0u; + if (HasToggleEnabled("use_blit_for_t2b")) { + expectedLazyClearCount = 1u; + } + EXPECT_LAZY_CLEAR(expectedLazyClearCount, queue.Submit(1, &commandBuffer)); } wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); diff --git a/src/dawn/tests/end2end/CopyTests.cpp b/src/dawn/tests/end2end/CopyTests.cpp index 64da8d2..baad726 100644 --- a/src/dawn/tests/end2end/CopyTests.cpp +++ b/src/dawn/tests/end2end/CopyTests.cpp @@ -4302,5 +4302,65 @@ // clang-format on })); +class BlitTextureToBufferTest : public DawnTest {}; + +// Test that encoding a CopyTextureToBuffer but not submitting it doesn't mark the buffer as +// initialized. +TEST_P(BlitTextureToBufferTest, NoSubmitDoesNotMarkInitialized) { + DAWN_TEST_UNSUPPORTED_IF(UsesWire()); + + // Create a buffer that we will use as the destination of a CopyTextureToBuffer. + wgpu::BufferDescriptor bufferDesc; + bufferDesc.size = 256; + bufferDesc.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst; + wgpu::Buffer buffer = device.CreateBuffer(&bufferDesc); + + // Create a source texture. + wgpu::TextureDescriptor textureDesc; + textureDesc.size = {64, 1, 1}; + textureDesc.format = wgpu::TextureFormat::R32Float; + textureDesc.usage = wgpu::TextureUsage::CopySrc; + wgpu::Texture texture = device.CreateTexture(&textureDesc); + + wgpu::TexelCopyTextureInfo src = utils::CreateTexelCopyTextureInfo(texture, 0, {0, 0, 0}); + wgpu::TexelCopyBufferInfo dst = utils::CreateTexelCopyBufferInfo(buffer, 0, 256, 1); + wgpu::Extent3D copySize = {64, 1, 1}; + + // Encode the CopyTextureToBuffer. + wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); + encoder.CopyTextureToBuffer(&src, &dst, ©Size); + // Finish the encoder, but do NOT submit the command buffer. + encoder.Finish(); + + // Now, if we use the buffer in a way that requires initialization (e.g., as a source of a + // copy), it should be lazy-cleared because the previous CopyTextureToBuffer was never + // submitted. + wgpu::BufferDescriptor dstBufferDesc; + dstBufferDesc.size = 256; + dstBufferDesc.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::CopySrc; + wgpu::Buffer dstBuffer = device.CreateBuffer(&dstBufferDesc); + + wgpu::CommandEncoder encoder2 = device.CreateCommandEncoder(); + encoder2.CopyBufferToBuffer(buffer, 0, dstBuffer, 0, 256); + wgpu::CommandBuffer cb = encoder2.Finish(); + + size_t lazyClearsBefore = native::GetLazyClearCountForTesting(device.Get()); + queue.Submit(1, &cb); + size_t lazyClearsAfter = native::GetLazyClearCountForTesting(device.Get()); + + // If the buffer was incorrectly marked as initialized during encoding of the first command, + // lazyClearsAfter - lazyClearsBefore will be 0. + // Otherwise, it should be 1. + EXPECT_EQ(lazyClearsAfter - lazyClearsBefore, 1u); +} + +DAWN_INSTANTIATE_TEST(BlitTextureToBufferTest, + D3D11Backend({"use_blit_for_t2b"}), + D3D12Backend({"use_blit_for_t2b"}), + MetalBackend({"use_blit_for_t2b"}), + OpenGLBackend({"use_blit_for_t2b"}), + OpenGLESBackend({"use_blit_for_t2b"}), + VulkanBackend({"use_blit_for_t2b"})); + } // anonymous namespace } // namespace dawn diff --git a/src/dawn/tests/end2end/TextureZeroInitTests.cpp b/src/dawn/tests/end2end/TextureZeroInitTests.cpp index 7f6f0d7..97a5481 100644 --- a/src/dawn/tests/end2end/TextureZeroInitTests.cpp +++ b/src/dawn/tests/end2end/TextureZeroInitTests.cpp @@ -311,7 +311,14 @@ wgpu::CommandBuffer commandBuffer = encoder.Finish(); // Expect texture to be lazy initialized. - EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commandBuffer)); + // TODO(b/513631768): SetInitialized is now skipped for use_blit_for_t2b path. + // If blit is used for T2B, the destination buffer is NOT marked as initialized during encoding, + // so it will also be lazy cleared during the first usage (which is the blit itself). + uint32_t expectedLazyClearCount = 1u; + if (HasToggleEnabled("use_blit_for_t2b")) { + expectedLazyClearCount++; + } + EXPECT_LAZY_CLEAR(expectedLazyClearCount, queue.Submit(1, &commandBuffer)); // Expect texture subresource initialized to be true EXPECT_TRUE(native::IsTextureSubresourceInitialized(texture.Get(), 0, 1, 0, kArrayLayers));
Regression Test / PoC
diff --git a/src/dawn/tests/end2end/BufferZeroInitTests.cpp b/src/dawn/tests/end2end/BufferZeroInitTests.cpp
index 6d86a10..625446a 100644
--- a/src/dawn/tests/end2end/BufferZeroInitTests.cpp
+++ b/src/dawn/tests/end2end/BufferZeroInitTests.cpp
@@ -145,7 +145,14 @@
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
encoder.CopyTextureToBuffer(&texelCopyTextureInfo, &texelCopyBufferInfo, &spec.textureSize);
wgpu::CommandBuffer commandBuffer = encoder.Finish();
- EXPECT_LAZY_CLEAR(spec.lazyClearCount, queue.Submit(1, &commandBuffer));
+
+ // TODO(b/513631768): SetInitialized is now skipped for use_blit_for_t2b path.
+ uint32_t expectedLazyClearCount = spec.lazyClearCount;
+ if (expectedLazyClearCount == 0u && (HasToggleEnabled("use_blit_for_t2b"))) {
+ expectedLazyClearCount = 1u;
+ }
+
+ EXPECT_LAZY_CLEAR(expectedLazyClearCount, queue.Submit(1, &commandBuffer));
const uint64_t expectedValueCount = bufferSize / sizeof(float);
std::vector<float> expectedValues(expectedValueCount, 0.f);
@@ -1153,6 +1160,10 @@
// TODO(crbug.com/473593119): [Capture] size not multiple of 4.
DAWN_SUPPRESS_TEST_IF(IsCaptureReplayCheckingEnabled());
+ // TODO(crbug.com/513631768): Skip D3D11 as they may use intermediate buffer for blit
+ // path and fail for EXPECT_LAZY_CLEAR.
+ DAWN_SUPPRESS_TEST_IF(IsD3D11());
+
constexpr wgpu::TextureFormat kColorAttachmentFormat = wgpu::TextureFormat::RGBA8Unorm;
// A small sub-4-byte format means a single vertex can fit entirely within the padded buffer,
// touching some of the padding. Test a small format, as well as larger formats.
@@ -1222,7 +1233,13 @@
encoder.CopyTextureToBuffer(&zeroTextureSrc, &dst, &extent);
wgpu::CommandBuffer commandBuffer = encoder.Finish();
- EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commandBuffer));
+
+ // TODO(b/513631768): SetInitialized is now skipped for use_blit_for_t2b path.
+ uint32_t expectedLazyClearCount = 0u;
+ if (HasToggleEnabled("use_blit_for_t2b")) {
+ expectedLazyClearCount = 1u;
+ }
+ EXPECT_LAZY_CLEAR(expectedLazyClearCount, queue.Submit(1, &commandBuffer));
}
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
diff --git a/src/dawn/tests/end2end/CopyTests.cpp b/src/dawn/tests/end2end/CopyTests.cpp
index 64da8d2..baad726 100644
--- a/src/dawn/tests/end2end/CopyTests.cpp
+++ b/src/dawn/tests/end2end/CopyTests.cpp
@@ -4302,5 +4302,65 @@
// clang-format on
}));
+class BlitTextureToBufferTest : public DawnTest {};
+
+// Test that encoding a CopyTextureToBuffer but not submitting it doesn't mark the buffer as
+// initialized.
+TEST_P(BlitTextureToBufferTest, NoSubmitDoesNotMarkInitialized) {
+ DAWN_TEST_UNSUPPORTED_IF(UsesWire());
+
+ // Create a buffer that we will use as the destination of a CopyTextureToBuffer.
+ wgpu::BufferDescriptor bufferDesc;
+ bufferDesc.size = 256;
+ bufferDesc.usage = wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
+ wgpu::Buffer buffer = device.CreateBuffer(&bufferDesc);
+
+ // Create a source texture.
+ wgpu::TextureDescriptor textureDesc;
+ textureDesc.size = {64, 1, 1};
+ textureDesc.format = wgpu::TextureFormat::R32Float;
+ textureDesc.usage = wgpu::TextureUsage::CopySrc;
+ wgpu::Texture texture = device.CreateTexture(&textureDesc);
+
+ wgpu::TexelCopyTextureInfo src = utils::CreateTexelCopyTextureInfo(texture, 0, {0, 0, 0});
+ wgpu::TexelCopyBufferInfo dst = utils::CreateTexelCopyBufferInfo(buffer, 0, 256, 1);
+ wgpu::Extent3D copySize = {64, 1, 1};
+
+ // Encode the CopyTextureToBuffer.
+ wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+ encoder.CopyTextureToBuffer(&src, &dst, ©Size);
+ // Finish the encoder, but do NOT submit the command buffer.
+ encoder.Finish();
+
+ // Now, if we use the buffer in a way that requires initialization (e.g., as a source of a
+ // copy), it should be lazy-cleared because the previous CopyTextureToBuffer was never
+ // submitted.
+ wgpu::BufferDescriptor dstBufferDesc;
+ dstBufferDesc.size = 256;
+ dstBufferDesc.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::CopySrc;
+ wgpu::Buffer dstBuffer = device.CreateBuffer(&dstBufferDesc);
+
+ wgpu::CommandEncoder encoder2 = device.CreateCommandEncoder();
+ encoder2.CopyBufferToBuffer(buffer, 0, dstBuffer, 0, 256);
+ wgpu::CommandBuffer cb = encoder2.Finish();
+
+ size_t lazyClearsBefore = native::GetLazyClearCountForTesting(device.Get());
+ queue.Submit(1, &cb);
+ size_t lazyClearsAfter = native::GetLazyClearCountForTesting(device.Get());
+
+ // If the buffer was incorrectly marked as initialized during encoding of the first command,
+ // lazyClearsAfter - lazyClearsBefore will be 0.
+ // Otherwise, it should be 1.
+ EXPECT_EQ(lazyClearsAfter - lazyClearsBefore, 1u);
+}
+
+DAWN_INSTANTIATE_TEST(BlitTextureToBufferTest,
+ D3D11Backend({"use_blit_for_t2b"}),
+ D3D12Backend({"use_blit_for_t2b"}),
+ MetalBackend({"use_blit_for_t2b"}),
+ OpenGLBackend({"use_blit_for_t2b"}),
+ OpenGLESBackend({"use_blit_for_t2b"}),
+ VulkanBackend({"use_blit_for_t2b"}));
+
} // anonymous namespace
} // namespace dawn
diff --git a/src/dawn/tests/end2end/TextureZeroInitTests.cpp b/src/dawn/tests/end2end/TextureZeroInitTests.cpp
index 7f6f0d7..97a5481 100644
--- a/src/dawn/tests/end2end/TextureZeroInitTests.cpp
+++ b/src/dawn/tests/end2end/TextureZeroInitTests.cpp
@@ -311,7 +311,14 @@
wgpu::CommandBuffer commandBuffer = encoder.Finish();
// Expect texture to be lazy initialized.
- EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commandBuffer));
+ // TODO(b/513631768): SetInitialized is now skipped for use_blit_for_t2b path.
+ // If blit is used for T2B, the destination buffer is NOT marked as initialized during encoding,
+ // so it will also be lazy cleared during the first usage (which is the blit itself).
+ uint32_t expectedLazyClearCount = 1u;
+ if (HasToggleEnabled("use_blit_for_t2b")) {
+ expectedLazyClearCount++;
+ }
+ EXPECT_LAZY_CLEAR(expectedLazyClearCount, queue.Submit(1, &commandBuffer));
// Expect texture subresource initialized to be true
EXPECT_TRUE(native::IsTextureSubresourceInitialized(texture.Get(), 0, 1, 0, kArrayLayers));
Original Bug Report
WebGPU T2B Compute-Blit No-Submit Stale Buffer Disclosure
Security Bug
Important: Please do not change the component of this bug manually.
Please READ THIS FAQ before filing a bug: https://chromium.googlesource.com/chromium/src/+/HEAD/docs/security/faq.md
Please see the following link for instructions on filing security bugs: https://www.chromium.org/Home/chromium-security/reporting-security-bugs
Reports may be eligible for reward payments under the Chrome VRP: https://g.co/chrome/vrp
NOTE: Security bugs are normally made public once a fix has been widely deployed.
VULNERABILITY DETAILS
third_party/dawn/src/dawn/native/BlitTextureToBuffer.cpp marks a WebGPU
destination buffer initialized while encoding a copyTextureToBuffer() command
that uses Dawn’s T2B compute-blit path:
// Skip clearing the buffer if this is full size copy.
dst.buffer->SetInitialized(fullSizeCopy || dst.buffer->IsInitialized());
This is a security issue because WebGPU command buffers do not have to be
submitted. A web page can call encoder.finish() and intentionally drop the
returned GPUCommandBuffer. In that case the compute blit never executes and
never writes the destination buffer, but Dawn’s persistent buffer metadata still
says the buffer is initialized.
A later submitted copyBufferToBuffer() from the same destination buffer then
skips Dawn’s lazy zero-initialization path and exposes stale GPU allocation
contents to JavaScript through a MAP_READ buffer.
The broken invariant is:
BufferBase::mIsDataInitialized must become true only after the buffer contents
were actually initialized by submitted GPU work, CPU upload, map-at-creation
initialization, or allocator-level clearing.
fullSizeCopy only proves that the encoded T2B operation would overwrite the
whole buffer if it executed. It does not prove that the command buffer will ever
be submitted.
This is the same bug class as the timestamp resolveQuerySet no-submit issue
fixed in Dawn by b073946efb / Chromium backport 36a8c01, where an analogous
encode-time SetInitialized(true) call was removed because encoded work may
never execute.
DEMONSTRATED IMPACT
The demonstrated impact is stale GPU allocation disclosure within one Dawn
GPUDevice allocator scope when the use_blit_for_t2b path is reachable.
Script with access to a GPUDevice can recover bytes from WebGPU resources
that were previously destroyed or dropped within that same GPUDevice, if it
can allocate a matching buffer size class and trigger the no-submit T2B
compute-blit path.
This can expose application-level GPU data such as image-processing intermediates, ML/inference tensors, render targets, texture readback buffers, or other transient WebGPU resources after the application has dropped or destroyed the original resource.
A practical attacking scenario
A same-origin third-party script (e.g. imported <script src=xxx> tags, which can be compromised analytics, ad, or CDN dependency) — that
activates after the destroy step has full access to that GPUDevice but no API path to the
destroyed weights or activations. This bug provides the path: allocate a matching-size
buffer, no-submit T2B, read back the destroyed allocation slot.
VERSION
Chrome Version: 148.0.7778.167 Stable
Operating System: Android 15, Pixel 6, ARM Mali Valhall GPU, Vulkan backend
Result:
Positive with --enable-dawn-features=use_blit_for_t2b
Negative without the Dawn T2B feature on this device
--enable-unsafe-webgpu not required
Chrome Version: 148.0.7778.168 Stable
Operating System: Windows 10 Version 22H2, Build 19045.6466,
NVIDIA GeForce RTX 3070 Ti, driver 32.0.15.7602
Result:
No flags: negative on this host. chrome://gpu shows the default usable WebGPU
adapter is D3D12, and the D3D11 WebGPU adapter is blocklisted.
With --enable-dawn-features=use_blit_for_t2b: positive stale GPU buffer
disclosure.
Chrome Version: 149.0.7827.14 Beta
Operating System: Windows 10 Version 22H2, Build 19045.6466,
NVIDIA GeForce RTX 3070 Ti, driver 32.0.15.7602
Result:
No flags: negative on this host for the same D3D12-default / D3D11-blocklisted
reason.
With --enable-dawn-features=use_blit_for_t2b: positive stale GPU buffer
disclosure.
REPRODUCTION CASE
Android PoC verification steps
Use these steps for Android Chrome. The tested Pixel 6 path required the
non-rooted Chrome command-line mechanism plus use_blit_for_t2b.
- In Chrome, open:
chrome://flags/#enable-command-line-on-non-rooted-devices
- Set it to
Enabled. - Relaunch Chrome.
- With USB debugging enabled, install the command line. From this folder on the computer, either push the provided template:
adb push chrome-command-line.txt /data/local/tmp/chrome-command-line
Then restart Chrome. 5. Set up the http server.
python3 -m http.server 18099 --bind 127.0.0.1
adb reverse tcp:18099 tcp:18099
adb shell am force-stop com.android.chrome
adb shell am start -n com.android.chrome/com.google.android.apps.chrome.Main \
-d http://127.0.0.1:18099/poc.html
Windows PoC verification steps
The server setup procedure is the same as Android. The command line to start Chrome with certain command lines can be:
$Chrome = "$env:LOCALAPPDATA\Google\Chrome\Application\chrome.exe"
if (!(Test-Path $Chrome)) { $Chrome = "$env:ProgramFiles\Google\Chrome\Application\chrome.exe" }
& $Chrome `
--user-data-dir="$env:TEMP\webgpu-t2b-repro-stable" `
--no-first-run `
--no-default-browser-check `
--enable-dawn-features=use_blit_for_t2b `
http://127.0.0.1:18099/poc.html
The poc.html is attached below.
The PoC performs the following sequence:
1. Victim: Create one GPUDevice.
2. Victim: Create a prior WebGPU resource containing a per-trial positional nonce.
3. Victim: Destroy/drop that prior resource.
4. Victim: Submit an empty command buffer and await queue.onSubmittedWorkDone() so
Dawn can recycle the prior allocation.
5. Attacker: Allocate an attacker buffer of the same size class.
6. Attacker: Encode a full-buffer copyTextureToBuffer() into the attacker buffer.
7. Attacker: Call encoder.finish() but do not submit that command buffer.
8. Attacker: Submit a separate copyBufferToBuffer(attacker -> MAP_READ buffer).
9. Attacker: Map the readback buffer and check for current or historical nonce bytes.
The critical bug is step 7: copyTextureToBuffer() marks the attacker buffer
initialized during encoding, but the command buffer is never submitted and the
attacker buffer is never actually written by the T2B blit.
How to Read poc.html
The page highlights the no-submit attack rows and keeps the full JSON under “Raw CHROVUS_LINE output”.
Important fields:
didSubmit=false
This is the vulnerable no-submit path. The T2B command buffer was finished
and dropped instead of being submitted.
nonZero / allZero
A safe no-submit read should return all zeroes because the destination buffer
should still require Dawn lazy initialization. nonZero > 0 in a no-submit
attack trial means stale bytes were exposed.
linearMatches
Number of texels matching the current trial pattern
[x_low_byte, y_low_byte, nonce_byte_0, nonce_byte_1] at the expected row-major
position. This is the strongest current-trial proof.
nonceOnly
Number of texels containing the current nonce in bytes 2 and 3 but not at the
expected row-major position. This still proves recovery of current-trial data,
and usually reflects driver tiling/swizzling.
historicalNonceHits
Matches for nonces from earlier trials. Hits in T3/T4 are useful because those
trials do not create a current primer allocation before the no-submit read.
Trial meanings:
T1_L2_positional_4M
Primes and destroys a 4MB texture, then performs a no-submit T2B read into a
same-size attacker buffer. Current nonce hits are a positive leak.
T2_L2_positional_4M_spray
Same size class as T1, with allocator spray. Current or historical nonce hits
show stale allocation reuse.
T3_no_prime_null_4M
No current primer is created. Historical nonce hits show residual bytes from
an earlier trial, not from the current trial's own write.
T4_no_prime_null_4M_spray
Same as T3, with allocator spray to exercise reuse behavior.
T5_L2_positional_256K
Repeats the current nonce leak test in a smaller 256KB size class.
The expected positive pattern is:
Any no-submit attack row with:
didSubmit=false
allZero=0
linearMatches + nonceOnly > 0
or:
didSubmit=false
allZero=0
historicalNonceHits[*].hits > 0
T3 and T4 are especially useful for explaining impact because they
demonstrate historical residual data without a current same-trial primer.
CREDIT INFORMATION Externally reported security bugs may appear in Chrome release notes. If this bug is included, how would you like to be credited? Reporter credit: Chrovus