High chrome Integer Overflow 📄 Reporter bug report 🔧 Commit mapped

Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInteger overflow in Media
DescriptionInteger overflow in Media
ComponentMedia
Bug ClassInteger Overflow
Tracker513396305
Fix commit136bb7f450da (chromium/src) +31/-2
CISA KEVNot listed
CreditedGoogle
Disclosed2026-06-08

Changed Functions

FunctionChangeNotes
if
media/audio/apple/audio_auhal.cc
modified
if
media/audio/mac/avfoundation_output_stream.mm
modified
if
media/filters/mac/audio_toolbox_audio_decoder.cc
modified

Files Changed

  • media/audio/apple/audio_auhal.cc
  • media/audio/mac/avfoundation_output_stream.mm
  • media/base/mac/channel_layout_util_mac.cc
  • media/filters/mac/audio_toolbox_audio_decoder.cc
From 136bb7f450dae7225bb90c721f1616d4e57d1e78 Mon Sep 17 00:00:00 2001
From: Thomas Guilbert <tguilbert@chromium.org>
Date: Thu, 28 May 2026 20:03:07 -0700
Subject: [PATCH] Use checked math before allocating ScopedAudioChannelLayout

This CL fixes a potential issue when trying to allocate a
`ScopedAudioChannelLayout` with a huge number of channels.

The CL fixes the issue by using checked math, and preventing integer
truncation when converting from `size_t` to `int`.

We prefer this approach over adding CHECKs to guard against a channel
count higher than `media::limits::kMaxChannels`, since `kMaxChannels`
(32 channels as of this commit) is lower than some high-end audio
interfaces (e.g. 40 channels), and this could introduce crashes in
otherwise valid scenarios.

Fixed: 513396305
Change-Id: I65f3f41bcffef5ce193f623eeac5d5178cdf6502
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7876673
Reviewed-by: Dale Curtis <dalecurtis@chromium.org>
Auto-Submit: Thomas Guilbert <tguilbert@chromium.org>
Commit-Queue: Thomas Guilbert <tguilbert@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1638201}
---

diff --git a/media/audio/apple/audio_auhal.cc b/media/audio/apple/audio_auhal.cc
index a1c0f34b..819b082 100644
--- a/media/audio/apple/audio_auhal.cc
+++ b/media/audio/apple/audio_auhal.cc
@@ -174,6 +174,10 @@
 
   auto coreaudio_layout =
       ChannelLayoutToAudioChannelLayout(channel_layout, channels);
+  if (!coreaudio_layout) {
+    DLOG(ERROR) << "Failed to create audio channel layout.";
+    return;
+  }
 
   MaybeMapRearSurroundChannelToSurroundChannel(audio_unit,
                                                coreaudio_layout->layout());
diff --git a/media/audio/mac/avfoundation_output_stream.mm b/media/audio/mac/avfoundation_output_stream.mm
index e4a2052c..1487221 100644
--- a/media/audio/mac/avfoundation_output_stream.mm
+++ b/media/audio/mac/avfoundation_output_stream.mm
@@ -95,6 +95,7 @@
       callback_(nullptr),
       objc_storage_(std::make_unique<ObjCStorage>()),
       audio_bus_(AudioBus::Create(params)) {
+  CHECK(params_.IsValid());
   DVLOG(1)
       << __func__
       << ": Initializing AVFoundationOutputStream with these AudioParameters:: "
@@ -147,6 +148,10 @@
 
   auto scoped_layout = ChannelLayoutToAudioChannelLayout(
       params_.channel_layout(), params_.channels());
+  if (!scoped_layout) {
+    LOG(ERROR) << "Failed to create audio channel layout.";
+    return false;
+  }
 
   OSStatus status = CMAudioFormatDescriptionCreate(
       /*allocator=*/kCFAllocatorDefault,
diff --git a/media/base/mac/channel_layout_util_mac.cc b/media/base/mac/channel_layout_util_mac.cc
index 5c9d3c6..10c341f 100644
--- a/media/base/mac/channel_layout_util_mac.cc
+++ b/media/base/mac/channel_layout_util_mac.cc
@@ -10,6 +10,8 @@
 #include "base/check_op.h"
 #include "base/compiler_specific.h"
 #include "base/containers/span.h"
+#include "base/logging.h"
+#include "base/numerics/safe_math.h"
 #include "media/base/channel_layout.h"
 
 namespace media {
@@ -116,8 +118,21 @@
   //
   // Code modeled after example from Apple documentation here:
   // https://developer.apple.com/library/content/qa/qa1627/_index.html
-  int output_layout_size =
-      offsetof(AudioChannelLayout, mChannelDescriptions[input_channels]);
+  // Modified to use `size_t` and `base::CheckedNumeric` to prevent integer
+  // truncation and overflow.
+  // `AudioChannelLayout` already includes one `AudioChannelDescription` in its
+  // definition, so we allocate space for `input_channels - 1` additional
+  // descriptions.
+  base::CheckedNumeric<size_t> checked_layout_size =
+      sizeof(AudioChannelLayout) +
+      base::CheckedNumeric<size_t>(input_channels - 1) *
+          sizeof(AudioChannelDescription);
+  size_t output_layout_size = 0;
+  if (!checked_layout_size.AssignIfValid(&output_layout_size)) {
+    DLOG(ERROR) << "Invalid AudioChannelLayout size.";
+    return nullptr;
+  }
+
   auto new_layout =
       std::make_unique<ScopedAudioChannelLayout>(output_layout_size);
 
diff --git a/media/filters/mac/audio_toolbox_audio_decoder.cc b/media/filters/mac/audio_toolbox_audio_decoder.cc
index dabd6f0..620b24c 100644
--- a/media/filters/mac/audio_toolbox_audio_decoder.cc
+++ b/media/filters/mac/audio_toolbox_audio_decoder.cc
@@ -376,6 +376,11 @@
   // channel order description. This let decoder output correct orders.
   auto ordered_layout = ChannelLayoutToAudioChannelLayout(
       channel_layout, input_format.mChannelsPerFrame);
+  if (!ordered_layout) {
+    MEDIA_LOG(ERROR, media_log_) << "Failed to create audio channel layout.";
+    return false;
+  }
+
   auto result = AudioConverterSetProperty(
       decoder_.get(), kAudioConverterOutputChannelLayout,
       ordered_layout->layout_size(), ordered_layout->layout());
Loading diff…

Original Bug Report

reported by vm...@google.com

Potential linear heap OOB write in macOS GPU process via integer truncation in AudioChannelLayout

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: An integer truncation vulnerability in the macOS-specific audio utility code allows for an undersized heap allocation when processing high channel counts. A compromised renderer can potentially exploit this to trigger a massive linear heap out-of-bounds write in the GPU process. The issue stems from a 64-bit to 32-bit truncation during a buffer size calculation.

Affected files:

  • media/base/mac/channel_layout_util_mac.cc
  • media/filters/mac/audio_toolbox_audio_decoder.cc
  • media/base/mac/channel_layout_util_mac.h

Estimated timestamp from git blame: 2023-04-27

Summary

A potential linear heap out-of-bounds (OOB) write vulnerability exists in the macOS GPU process due to an integer truncation in media::ChannelLayoutToAudioChannelLayout. When calculating the required size for an AudioChannelLayout structure, a 64-bit size_t value is truncated into a 32-bit int, leading to an undersized heap allocation. Subsequent initialization of the structure’s members results in a linear OOB write.

Root Cause Analysis

The vulnerability is located in media/base/mac/channel_layout_util_mac.cc within the ChannelLayoutToAudioChannelLayout function:

std::unique_ptr<ScopedAudioChannelLayout> ChannelLayoutToAudioChannelLayout(
    ChannelLayout input_layout, int input_channels) {
  // ...
  int output_layout_size =  // [1] Truncation occurs here
      offsetof(AudioChannelLayout, mChannelDescriptions[input_channels]);
  auto new_layout =
      std::make_unique<ScopedAudioChannelLayout>(output_layout_size); // [2] Undersized allocation
  new_layout->layout()->mNumberChannelDescriptions = input_channels; // [3] Large count stored
  // ...
  auto descriptions = GetDescriptions(*new_layout->layout());
  if (input_layout == CHANNEL_LAYOUT_DISCRETE) {
    for (int ch = 0; ch < input_channels; ++ch) {
      descriptions[ch].mChannelLabel = kAudioChannelLabel_Unknown; // [4] OOB write
      descriptions[ch].mChannelFlags = kAudioChannelFlags_AllOff;
    }
  }
  1. Truncation: In [1], offsetof returns a 64-bit size_t. For a sufficiently large input_channels (e.g., 214,748,365), the result 12 + (214,748,365 * 20) = 4,294,967,312 (0x100000010) is truncated when assigned to the 32-bit signed int output_layout_size, resulting in a value of 16.
  2. Allocation: In [2], a base::HeapArray of only 16 bytes is allocated.
  3. Inconsistent State: In [3], the structure’s member count is set to the original large value. The GetDescriptions helper subsequently creates a base::span whose length is based on this large value, bypassing span safety checks for the underlying small allocation.
  4. OOB Write: In [4], the loop iterates input_channels times, performing writes starting at offset 12 and continuing linearly well beyond the 16-byte buffer.

Potential Attack Vector

Note: These are potential steps as a functional PoC has not yet been executed.

  1. A compromised renderer binds the media.mojom.AudioDecoder interface in the GPU process (on macOS, this often instantiates AudioToolboxAudioDecoder).
  2. The renderer calls Initialize() with an AudioDecoderConfig where codec is kAAC and profile is kXHE_AAC (xHE-AAC/USAC).
  3. The extra_data field is crafted to contain a USAC configuration that specifies an extremely large channel count (e.g., via ISO/IEC 23003-3 escapedValue syntax).
  4. AudioToolboxAudioDecoder::CreateDecoder uses macOS AudioFormatGetProperty to parse the configuration. If the system API returns the large channel count in mChannelsPerFrame, it triggers the calls to ChannelLayoutToAudioChannelLayout with the malicious count.

Impact

This flaw could allow a compromised renderer to achieve Remote Code Execution (RCE) in the GPU process by corrupting the PartitionAlloc heap. On macOS, the GPU process is sandboxed but maintains access to system audio/graphics frameworks.

Suggested Fix

  1. Use base::CheckedNumeric<size_t> to perform the size calculation in ChannelLayoutToAudioChannelLayout and ensure the result fits in a size_t and is within sane bounds before allocation.
  2. Change the type of output_layout_size from int to size_t to avoid truncation.
  3. Implement explicit validation of the channel count in AudioToolboxAudioDecoder before passing it to utility functions, enforcing limits such as media::limits::kMaxChannels.

Evaluated with Chrome root at commit: b3153093eb3c78c3e88ccf562bcbc20437a04b0e


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