CVE-2026-10020
Overview
Files Changed
gpu/ipc/common/vulkan_ycbcr_info_mojom_traits.h
Patch
From 2540f0d8870b855bd58a696ccfd9c213a2e95c88 Mon Sep 17 00:00:00 2001
From: Vasiliy Telezhnikov <vasilyt@chromium.org>
Date: Thu, 07 May 2026 13:33:56 -0700
Subject: [PATCH] Validate YCbCr info enum values
Due to dependency issues, we passed uint32_t values instead of enum
historically, until we can resolve this we should validate against known
values.
Bug: 496282591,496565479
Change-Id: I36e3429b19cd71c32e4317cad24dfb1299c3406f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7823022
Reviewed-by: Joe Mason <joenotcharles@google.com>
Commit-Queue: Vasiliy Telezhnikov <vasilyt@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1627197}
---
diff --git a/gpu/ipc/common/vulkan_ycbcr_info_mojom_traits.h b/gpu/ipc/common/vulkan_ycbcr_info_mojom_traits.h
index e349c8bd..0048aef 100644
--- a/gpu/ipc/common/vulkan_ycbcr_info_mojom_traits.h
+++ b/gpu/ipc/common/vulkan_ycbcr_info_mojom_traits.h
@@ -51,6 +51,22 @@
out->suggested_xchroma_offset = data.suggested_xchroma_offset();
out->suggested_ychroma_offset = data.suggested_ychroma_offset();
out->format_features = data.format_features();
+
+ // Values from Vulkan definitions, because we can't easy depend on vulkan
+ // here.
+ // https://source.chromium.org/chromium/chromium/src/+/main:third_party/vulkan-headers/src/include/vulkan/vulkan_core.h;drc=f6a6f7ab165cedbfa2a7d0c93fe27a2d01ce09c8;l=5438
+ const uint32_t VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020 = 4;
+ const uint32_t VK_CHROMA_LOCATION_MIDPOINT = 1;
+ const uint32_t VK_SAMPLER_YCBCR_RANGE_ITU_NARROW = 1;
+
+ if (out->suggested_ycbcr_model >
+ VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020 ||
+ out->suggested_ycbcr_range > VK_SAMPLER_YCBCR_RANGE_ITU_NARROW ||
+ out->suggested_xchroma_offset > VK_CHROMA_LOCATION_MIDPOINT ||
+ out->suggested_ychroma_offset > VK_CHROMA_LOCATION_MIDPOINT) {
+ return false;
+ }
+
return true;
}
};
Original Bug Report
Potential Sandbox Escape via Bit-Packing Overflow in Skia Graphite Dawn YCbCr Descriptor
Project Fortify, an experimental security project, has identified the following potential security issue.
Overview: A compromised renderer can send an out-of-bounds VulkanYCbCrInfo.suggested_ycbcr_model value to the GPU process. This value overflows during bit-packing in Skia’s Dawn backend, corrupting the vkChromaFilter field and bypassing Dawn’s validation. This results in undefined behavior when constructing a Vulkan sampler, potentially leading to a sandbox escape in the graphics driver.
Affected files:
third_party/skia/src/gpu/graphite/dawn/DawnGraphiteUtils.cppthird_party/dawn/src/dawn/native/vulkan/UtilsVulkan.cppthird_party/dawn/src/dawn/native/Sampler.cppthird_party/skia/src/gpu/graphite/dawn/DawnSampler.cppgpu/command_buffer/service/shared_image/shared_image_format_service_utils.cc
Estimated timestamp from git blame: 2026-02-25
Summary
A bit-packing overflow vulnerability exists in Skia’s Graphite Dawn backend when processing YCbCr descriptors. A compromised renderer process can send a malicious VulkanYCbCrInfo struct via IPC to the GPU process, containing an out-of-bounds suggested_ycbcr_model value. This value is assigned to a Dawn descriptor and passed to Skia without proper validation. During serialization, Skia shifts this value into a bitfield, overflowing its intended bits and corrupting an adjacent field (vkChromaFilter). This invalid filter mode bypasses Dawn’s validation logic, leading to compiler-level undefined behavior when Dawn attempts to convert it to a Vulkan enum. The resulting out-of-bounds Vulkan enum is passed to the highly privileged Vulkan driver, potentially triggering an out-of-bounds array access and arbitrary memory corruption within the driver, constituting a sandbox escape.
Note: These are potential steps as the AI agent doesn’t yet have the ability to run a working proof of concept to verify the full exploit chain.
Root Cause Analysis
- Missing IPC Validation: The
VulkanYCbCrInfostruct is deserialized in the GPU process viagpu/ipc/common/vulkan_ycbcr_info_mojom_traits.h. TheReadmethod copies the fields, includingsuggested_ycbcr_model, without any bounds checking. - Unvalidated Conversion: This malicious value (e.g.,
0xFF) is stored in aviz::TransferableResourceand later copied directly into thevkYCbCrModelfield of awgpu::YCbCrVkDescriptorinsidegpu/command_buffer/service/shared_image/shared_image_format_service_utils.cc:740(ToDawnYCbCrVkDescriptor). - SkASSERT Bypass: Skia receives this descriptor and attempts to validate the input in
third_party/skia/src/gpu/graphite/dawn/DawnGraphiteUtils.cpp:301:SkASSERT(desc.vkYCbCrModel < (1u << kYcbcrModelBits));. However,SkASSERTcompiles to a no-op in release builds, so the oversized0xFFvalue passes through. - Bit-Packing Overflow: The function
DawnDescriptorToImmutableSamplerInfopacks the descriptor fields into auint32_t. It shifts the oversized model value:((uint32_t)(desc.vkYCbCrModel) << kYcbcrModelShift).kYcbcrModelShiftis 1, andvkYCbCrModelis only supposed to occupy 3 bits. Shifting0xFFleft by 1 produces0x1FE, which overwrites bits 1 through 8. - Adjacent Field Corruption: The
vkChromaFilterfield occupies bits 7-8. The overflow from the model shift writes11into these bits, completely corrupting the filter mode and setting it to the invalid value3(valid values are0to2).
Exploit Path
- Reconstruction: Skia later unpacks the corrupted value from the bitfield using
DawnDescriptorFromImmutableSamplerInfo, extracting the invalidwgpu::FilterModeof3. - Validation Bypass: This invalid descriptor is passed back to Dawn to create a sampler. In
third_party/dawn/src/dawn/native/Sampler.cpp:74, Dawn validates the descriptor but crucially fails to check theycbcr->vkChromaFilterfield. - Undefined Behavior Sink: When Dawn prepares to call the Vulkan driver, it converts the
wgpu::FilterModeto aVkFilterusingToVulkanSamplerFilter(third_party/dawn/src/dawn/native/vulkan/UtilsVulkan.cpp:90). This switch statement does not have a case for3and falls through toDAWN_UNREACHABLE(), which expands to__builtin_unreachable()in release builds. - Driver Exploitation: Hitting
__builtin_unreachable()invokes compiler-level undefined behavior. The compiler will optimize the code assuming this path is never taken, typically resulting in an invalidVkFiltervalue (like2or3) being returned and assigned tovulkanYCbCrCreateInfo.chromaFilter. At line 447, Dawn passes this invalid struct to the Vulkan graphics driver viavkCreateSamplerYcbcrConversion. The driver will attempt to use this out-of-bounds enum, likely triggering an out-of-bounds array access within the highly privileged Vulkan driver, leading to a sandbox escape.
Suggested Fix
- IPC Validation: Add proper bounds checking to the
VulkanYCbCrInfodeserializer ingpu/ipc/common/vulkan_ycbcr_info_mojom_traits.h. Ensure all enum-like fields, includingsuggested_ycbcr_model, are within their expected valid ranges. - Bit-Packing Masking: In
third_party/skia/src/gpu/graphite/dawn/DawnGraphiteUtils.cpp, updateDawnDescriptorToImmutableSamplerInfoto explicitly mask all input values before bitwise shifting them into the packed integer, preventing any out-of-bounds value from clobbering adjacent fields (e.g.,(desc.vkYCbCrModel & ((1u << kYcbcrModelBits) - 1)) << kYcbcrModelShift). - Dawn Validation: Add validation for the
ycbcr->vkChromaFilterfield within Dawn’sValidateSamplerDescriptorfunction.
Evaluated with Chrome root at commit: 0eb4855bda702feaaa8b899336664f97e3df88b8
Results so far have been promising, but there can be wrong deductions. If this proves to be a false positive, please close as WAI; data from false positives will be used to improve accuracy over time. Please feel free to reach out to me if you have concerns or feedback.