Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInsufficient validation of untrusted input in UI
DescriptionInsufficient validation of untrusted input in UI
ComponentUI
Bug ClassLogic Error
Tracker513702971
Fix commit826fa2041c73 (chromium/src) +19/-4
CISA KEVNot listed
CreditedGoogle
Disclosed2026-06-08

Changed Functions

FunctionChangeNotes
if
ui/base/x/x11_display_util.cc
modified

Files Changed

  • ui/base/x/x11_display_util.cc
From 826fa2041c73cca8dbe5ed6fa2d9870ce7459489 Mon Sep 17 00:00:00 2001
From: Tom Anderson <thomasanderson@chromium.org>
Date: Mon, 18 May 2026 16:19:26 -0700
Subject: [PATCH] [X11][gfx] Validate ICC profiles from X11 root window

Limit the size and complexity of ICC profiles fetched from X11 to
prevent potential memory exhaustion and integer overflows in the color
management pipeline.

- Limit long_length in X11 GetProperty request to 4MB and reject truncated data.
- Use base::CheckedNumeric for size calculation to prevent wrap-around.
- Rely on hardened skcms parser for CLUT complexity validation.

R=thestig

Change-Id: Id5f36245cf0430f0764e233d4a83529649bfa708
Bug: 513702971
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7855799
Commit-Queue: Lei Zhang <thestig@chromium.org>
Auto-Submit: Thomas Anderson <thomasanderson@chromium.org>
Commit-Queue: Thomas Anderson <thomasanderson@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1632463}
---

diff --git a/ui/base/x/x11_display_util.cc b/ui/base/x/x11_display_util.cc
index 9af47cd..3c1b275 100644
--- a/ui/base/x/x11_display_util.cc
+++ b/ui/base/x/x11_display_util.cc
@@ -19,6 +19,7 @@
 #include "base/containers/flat_map.h"
 #include "base/logging.h"
 #include "base/notimplemented.h"
+#include "base/numerics/checked_math.h"
 #include "base/numerics/clamped_math.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -82,13 +83,21 @@
 x11::Future<x11::GetPropertyReply> GetIccProfileFuture(
     x11::Connection* connection,
     size_t monitor) {
+  // Limit the size of the ICC profile to 4MB. Most monitor profiles are
+  // much smaller than this (typically < 1MB). This prevents potential
+  // memory exhaustion and serves as a first-line defense against malicious
+  // profiles with massive CLUTs.
+  constexpr size_t kMaxIccProfileSize = 4 * 1024 * 1024;
+  // GetProperty takes the length in 4-byte multiples.
+  constexpr uint32_t kMaxIccProfileLongLength = kMaxIccProfileSize / 4;
+
   std::string atom_name = monitor == 0
                               ? "_ICC_PROFILE"
                               : base::StringPrintf("_ICC_PROFILE_%zu", monitor);
   auto future = connection->GetProperty({
       .window = connection->default_root(),
       .property = x11::GetAtom(atom_name.c_str()),
-      .long_length = std::numeric_limits<uint32_t>::max(),
+      .long_length = kMaxIccProfileLongLength,
   });
   future.IgnoreError();
   return future;
@@ -96,11 +105,17 @@
 
 gfx::ICCProfile GetIccProfileSync(x11::Future<x11::GetPropertyReply> future) {
   auto response = future.Sync();
-  if (!response || !response->value_len) {
+  if (!response || !response->value_len || response->bytes_after > 0) {
     return gfx::ICCProfile();
   }
-  return gfx::ICCProfile::FromData(response->value->bytes(),
-                                   response->value_len * response->format / 8u);
+
+  base::CheckedNumeric<size_t> size = response->value_len;
+  size *= (response->format / 8u);
+  if (!size.IsValid()) {
+    return gfx::ICCProfile();
+  }
+
+  return gfx::ICCProfile::FromData(response->value->bytes(), size.ValueOrDie());
 }
 
 x11::Future<x11::RandR::GetOutputPropertyReply> GetEdidFuture(
Loading diff…

Original Bug Report

reported by vm...@google.com

Sandbox Escape from GPU to Browser via X11 Root Window _ICC_PROFILE

Project Fortify, an experimental security project, has identified the following potential security issue. If you’re a feature owner CC-ed on this bug, please do your best to review these reports. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.

Overview: A compromised GPU process on Linux/X11 can potentially escape its sandbox by manipulating X11 root window properties that are trusted by the unsandboxed browser process. By writing malicious ICC profile data and triggering a display update, the attacker forces the browser to parse and transform the data on the UI thread. This triggers a signed integer overflow in the skcms library, leading to a heap out-of-bounds read in the browser process context.

Affected files:

  • ui/base/x/x11_display_util.cc
  • ui/base/x/x11_display_manager.cc
  • third_party/skia/modules/skcms/src/Transform_inl.h
  • ui/ozone/platform/x11/ozone_platform_x11.cc
  • ui/ozone/platform/x11/x11_screen_ozone.cc
  • ui/gfx/icc_profile.cc

Estimated timestamp from git blame: Unknown (Google3 checkout)

Summary

A potential vulnerability exists on Linux/X11 systems where a compromised GPU process can escape its sandbox and attack the browser process. By manipulating properties on the X11 root window, an attacker can force the unsandboxed browser process to parse and transform malicious ICC profile data, leading to a heap out-of-bounds read or potential memory corruption in the browser process context.

Root Cause Analysis

On Linux, the GPU process is sandboxed using seccomp-bpf but retains an active X11 socket connection initialized before sandbox engagement (see ui/ozone/platform/x11/ozone_platform_x11.cc). This allows a compromised GPU process to issue X11 requests, such as ChangeProperty, on the root window.

The browser process monitors the X11 root window for changes to properties like _NET_WORKAREA to trigger display list updates. This logic is handled in ui/base/x/x11_display_manager.cc. When a change is detected, the browser calls FetchDisplayList(), which reads display-calibration data from the _ICC_PROFILE properties on the root window via ui/base/x/x11_display_util.cc.

Because any X11 client can write to root window properties, a sandboxed GPU process can deliver an arbitrary ICC profile directly into the browser process’s color-management pipeline. The browser process treats this data as trusted, parsing it on the UI thread without additional sandboxing.

Technical Details

A latent signed integer overflow exists in the Color Lookup Table (CLUT) indexing logic within Skia’s skcms library (third_party/skia/modules/skcms/src/Transform_inl.h). Specifically, index calculations such as 3 * ix or 6 * ix in SIMD gather functions can overflow a 32-bit signed integer when the CLUT grid size is large.

For a 4D CLUT with ~1.33e9 entries (fitting within the 4GB ICC tag limit), the calculated index ix can reach values that, when multiplied by 3 or 6, wrap to a negative value in 32-bit signed arithmetic. This results in an out-of-bounds read at a negative offset relative to the CLUT grid buffer in the browser process.

Potential Exploitation Steps

  1. From a compromised GPU process, use the existing X11 connection to write a crafted ICC profile to the _ICC_PROFILE property on the root window. The profile should contain a large A2B0 CLUT designed to trigger the 3 * ix overflow.
  2. Update the _NET_WORKAREA property on the root window to trigger a property notification.
  3. The browser process receives the notification, fetches the malicious profile, and executes the transformation pipeline during profile comparison or display initialization.
  4. The resulting out-of-bounds read may allow the attacker to leak browser process memory or cause a crash on the UI thread.

Suggested Fix

  1. Validation: The browser process should validate the size and complexity (e.g., total grid points) of ICC profiles fetched from the X11 root window before passing them to the transformation pipeline.
  2. skcms Hardening: Update skcms to use size_t or 64-bit integers for offset calculations in Transform_inl.h, or implement explicit overflow checks using safe math primitives to ensure indices remain within buffer bounds.

Evaluated with Chrome root at commit: 1a8d40fc44df2088d5945c0bf53584038aa1614a


Results so far have been promising, but there can be wrong deductions. Feel free to adjust as follows:

  • If you are familiar with the severity guidelines, you may adjust the severity.
  • If this is a false positive, and there’s no work to be done, please close as WAI.
  • If there is work to do here but not a vulnerability, please change the issue type to Task/Bug/FR.

Data from false positives will be used to improve accuracy over time. And please feel free to reach out to me directly if you have concerns or feedback on the project.

View on issue tracker