CVE-2026-9939
Overview
Files Changed
DEPSthird_party/libaom/README.chromiumthird_party/libaom/source/config/config/aom_version.hthird_party/libaom/source/libaom
Patch
From c3cf0a691164420931daf3d2d47c5809749b5733 Mon Sep 17 00:00:00 2001
From: Marco Paniconi <marpan@google.com>
Date: Thu, 21 May 2026 20:46:53 -0700
Subject: [PATCH] Cherry-pick libaom 343cee0 to m148
Bug: 502735235
Fixed: 514923880
Change-Id: I86ee1a1f4bb4956ba5aede4f255bf97ce9351053
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7869715
Commit-Queue: James Zern <jzern@google.com>
Reviewed-by: Wan-Teh Chang <wtc@google.com>
Reviewed-by: James Zern <jzern@google.com>
Cr-Commit-Position: refs/branch-heads/7778@{#3460}
Cr-Branched-From: 77f495ee216d4c3cc784d33658bad4778c0680ee-refs/heads/main@{#1610480}
---
diff --git a/DEPS b/DEPS
index 9006c031..53db0a7 100644
--- a/DEPS
+++ b/DEPS
@@ -2371,7 +2371,7 @@
Var('chromium_git') + '/external/libaddressinput.git' + '@' + 'e20690c8d5178bb282641d5eb06ef0298ff4cbc5',
'src/third_party/libaom/source/libaom':
- Var('aomedia_git') + '/aom.git' + '@' + 'b63f30b6d30028a3d7d9c5223def8f3ad97dcc4c',
+ Var('aomedia_git') + '/aom.git' + '@' + '343cee0a952f8c7d329e59ff3ac2c8bdbe70ec6a',
'src/third_party/crabbyavif/src':
Var('chromium_git') + '/external/github.com/webmproject/CrabbyAvif.git' + '@' + Var('crabbyavif_revision'),
diff --git a/third_party/libaom/README.chromium b/third_party/libaom/README.chromium
index b05ec0a1..8227b0c 100644
--- a/third_party/libaom/README.chromium
+++ b/third_party/libaom/README.chromium
@@ -2,10 +2,10 @@
Short Name: libaom
URL: https://aomedia.googlesource.com/aom/
Version: N/A
-Revision: b63f30b6d30028a3d7d9c5223def8f3ad97dcc4c
+Revision: 343cee0a952f8c7d329e59ff3ac2c8bdbe70ec6a
Update Mechanism: Manual
CPEPrefix: cpe:/a:aomedia:aomedia:3.13.3
-License: BSD-2-Clause, Patent
+License: Alliance-for-Open-Media-Patent, BSD-2-Clause
License Android Compatible: yes
License File: source/libaom/LICENSE, source/libaom/PATENTS
Security Critical: yes
diff --git a/third_party/libaom/source/config/config/aom_version.h b/third_party/libaom/source/config/config/aom_version.h
index d7033d7..b6014308 100644
--- a/third_party/libaom/source/config/config/aom_version.h
+++ b/third_party/libaom/source/config/config/aom_version.h
@@ -14,9 +14,9 @@
#define VERSION_MAJOR 3
#define VERSION_MINOR 13
#define VERSION_PATCH 3
-#define VERSION_EXTRA "371-gb63f30b6d3"
+#define VERSION_EXTRA "372-g343cee0a95"
#define VERSION_PACKED \
((VERSION_MAJOR << 16) | (VERSION_MINOR << 8) | (VERSION_PATCH))
-#define VERSION_STRING_NOSP "3.13.3-371-gb63f30b6d3"
-#define VERSION_STRING " 3.13.3-371-gb63f30b6d3"
+#define VERSION_STRING_NOSP "3.13.3-372-g343cee0a95"
+#define VERSION_STRING " 3.13.3-372-g343cee0a95"
#endif // AOM_VERSION_H_
diff --git a/third_party/libaom/source/libaom b/third_party/libaom/source/libaom
index b63f30b..343cee0a 160000
--- a/third_party/libaom/source/libaom
+++ b/third_party/libaom/source/libaom
@@ -1 +1 @@
-Subproject commit b63f30b6d30028a3d7d9c5223def8f3ad97dcc4c
+Subproject commit 343cee0a952f8c7d329e59ff3ac2c8bdbe70ec6a
Original Bug Report
Potential Heap-buffer-overflow in libaom av1_rc_scene_detection_onepass_rt via WebCodecs
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 without the Chrome Security team. Please see go/chrome-ai-generated-security-bugs-faq for more information.
Overview: A potential heap-buffer-overflow WRITE exists in libaom’s scene detection logic when using SVC temporal layers via the WebCodecs API. By dynamically shrinking and then growing the encoder resolution, an attacker can desynchronize libaom’s internal state, causing it to reuse a small buffer for a large frame’s data. This bypasses size checks and leads to an out-of-bounds write of SAD (Sum of Absolute Differences) values in the renderer process.
Affected files:
third_party/libaom/source/libaom/av1/encoder/ratectrl.cthird_party/libaom/source/libaom/av1/encoder/svc_layercontext.cthird_party/libaom/source/libaom/av1/encoder/encoder.cmedia/video/av1_video_encoder.cc
Estimated timestamp from git blame: 2025-05-06
Summary
A potential linear heap-buffer-overflow WRITE exists in libaom’s scene detection logic when using Scalable Video Coding (SVC) temporal layers (e.g., scalabilityMode: 'L1T2') via the WebCodecs API. A specific sequence of resolution reconfigurations (shrink-then-grow) causes the encoder to erroneously reuse a stale, smaller buffer (cpi->src_sad_blk_64x64) for a larger frame’s data, bypassing dimension-mismatch safety checks. This allows an attacker to write partially controlled values beyond the buffer’s bounds in the renderer process.
Root Cause Analysis
The buffer cpi->src_sad_blk_64x64 is used to store block-wise Sum of Absolute Differences (SAD) during one-pass real-time rate control. It is allocated in av1_rc_scene_detection_onepass_rt based on the superblock grid size of the current frame.
To ensure the buffer matches the current frame dimensions, a check compares the current frame (frame_input->source) against the previous reference frame (frame_input->last_source). If they differ, the buffer is safely freed and nulled so it can be reallocated correctly.
// ratectrl.c:3309
if (src_width != last_src_width || src_height != last_src_height) {
aom_free(cpi->src_sad_blk_64x64);
cpi->src_sad_blk_64x64 = NULL;
return;
}
When SVC temporal layers are enabled, if the encoder believes a base layer (TL0) frame was dropped, it redirects frame_input->last_source to cpi->svc.source_last_TL0. This specific fallback buffer is allocated once at the start of encoding (frame_number == 0) and is never resized during subsequent dynamic resolution reconfigurations (aom_codec_enc_config_set).
Potential Trigger Sequence:
- Initial Configuration (Large): WebCodecs is configured with a large resolution (e.g., 256x512) and
scalabilityMode: 'L1T2'.source_last_TL0is allocated at 256x512. - Reconfigure Down (Small): The resolution is reconfigured to a smaller size (e.g., 256x64). The next frame (TL1) encounters a dimension mismatch, causing
src_sad_blk_64x64to be safely freed and reallocated for the smaller size (e.g., 4 elements). Because it’s a TL1 frame, it does not update the time index for the TL0 reference buffer. - Reconfigure Up (Large): The resolution is restored to the large size (256x512). The next frame is encoded as a TL0 frame.
- State Desync: Because the previous TL1 frame did not update the TL0 reference time index,
av1_svc_set_last_sourceincorrectly concludes that the previous base layer frame was dropped. It forcesframe_input->last_sourceto point to the fallbacksource_last_TL0buffer. - Bypass & Overflow: In
av1_rc_scene_detection_onepass_rt, the code compares the current frame (256x512) againstsource_last_TL0(which is still 256x512 from step 1). The safety check passes, failing to free the smallsrc_sad_blk_64x64buffer allocated in step 2. The subsequent loop iterates over the large frame’s grid, writing out of bounds into the small buffer.
Impact
- Type: Heap-buffer-overflow WRITE.
- Process: Renderer process.
- Controllability: The attacker can control the size of the initial small allocation to place the victim buffer in a specific PartitionAlloc bucket. By providing crafted
VideoFrameluma data, an attacker controls the low 20 bits of the writtenuint64_tSAD values, which can be used to corrupt adjacent heap object metadata (e.g., length or capacity fields), potentially leading to arbitrary read/write and remote code execution. - Note: This is a spatial overflow on a raw C pointer, so it is not mitigated by MiraclePtr.
Suggested Fix
The primary issue is that cpi->svc.source_last_TL0 holds stale dimensions across reconfigurations. The fix should involve either:
- Reallocating or invalidating
cpi->svc.source_last_TL0insideav1_change_config(or related configuration change handlers) when the frame dimensions change. - In
av1_rc_scene_detection_onepass_rt, validating the dimensions ofcpi->src_sad_blk_64x64directly against the current frame dimensions instead of relying solely on the comparison betweenframe_input->sourceandframe_input->last_source.
Evaluated with Chrome root at commit: c0eb5541aebfa4ea08806eaf6e94bcc69f87ab2f
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. And please feel free to reach out to me directly if you have concerns or feedback on the project.