Invalid memory read access in aom_sse_avx2
Categories
(Core :: Audio/Video: Web Codecs, defect, P2)
Tracking
()
People
(Reporter: attekett, Assigned: chunmin)
References
(Regression)
Details
(4 keywords, Whiteboard: [adv-main149+][adv-ESR140.9+])
Attachments
(7 files, 1 external file, 6 obsolete files)
|
892 bytes,
text/html
|
Details | |
|
6.87 KB,
patch
|
Details | Diff | Splinter Review | |
|
5.02 KB,
patch
|
Details | Diff | Splinter Review | |
|
12.13 KB,
patch
|
Details | Diff | Splinter Review | |
|
3.46 KB,
text/x-log
|
Details | |
|
3.47 KB,
text/x-log
|
Details | |
|
50.44 KB,
application/zip
|
Details |
Tested on:
OS: Ubuntu 25.10
Firefox: fuzzfetch fetched AddressSanitizer build
Version=150.0a1
BuildID=20260227090653
SourceStamp=69326b7edf8166a75eba45b4f156f7a9727be83a
ID={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
ASAN-trace(with repro-file as it is):
=================================================================
==85175==ERROR: AddressSanitizer: SEGV on unknown address 0x7bff2cb94880 (pc 0x7bfff31a9b5d bp 0x7bffa91e1730 sp 0x7bffa91e1610 T30)
==85175==The signal is caused by a READ memory access.
SCARINESS: 20 (wild-addr-read)
#0 0x7bfff31a9b5d in aom_sse_avx2 /builds/worker/checkouts/gecko/third_party/aom/aom_dsp/x86/sse_avx2.c:0:0
#1 0x7bfff38591dc in get_filt_error /builds/worker/checkouts/gecko/third_party/aom/av1/encoder/pickcdef.c:428:13
#2 0x7bfff38591dc in av1_cdef_mse_calc_block /builds/worker/checkouts/gecko/third_party/aom/av1/encoder/pickcdef.c:601:33
#3 0x7bfff37442c2 in cdef_filter_block_worker_hook /builds/worker/checkouts/gecko/third_party/aom/av1/encoder/ethread.c:3332:5
#4 0x7bfff3204bf5 in execute /builds/worker/checkouts/gecko/third_party/aom/aom_util/aom_thread.c:197:27
#5 0x7bfff3743657 in launch_workers /builds/worker/checkouts/gecko/third_party/aom/av1/encoder/ethread.c:1481:7
#6 0x7bfff3743657 in av1_cdef_mse_calc_frame_mt /builds/worker/checkouts/gecko/third_party/aom/av1/encoder/ethread.c:3362:3
#7 0x7bfff385cd20 in av1_cdef_search /builds/worker/checkouts/gecko/third_party/aom/av1/encoder/pickcdef.c:880:5
#8 0x7bfff3703233 in cdef_restoration_frame /builds/worker/checkouts/gecko/third_party/aom/av1/encoder/encoder.c:2770:5
#9 0x7bfff3703233 in loopfilter_frame /builds/worker/checkouts/gecko/third_party/aom/av1/encoder/encoder.c:2898:3
#10 0x7bfff3703233 in encode_with_recode_loop_and_filter /builds/worker/checkouts/gecko/third_party/aom/av1/encoder/encoder.c:3724:5
#11 0x7bfff36dbce0 in encode_frame_to_data_rate /builds/worker/checkouts/gecko/third_party/aom/av1/encoder/encoder.c:4370:9
.
.
.
If you modify the repro-file dimensions array from:
const dimensions = [
{ width: 16384, height: 17 },
{ width: 64, height: 55572 }
];
to
const dimensions = [
//{ width: 16384, height: 17 },
{ width: 64, height: 55572 }
];
You get a different ASAN-trace:
=================================================================
==3761615==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7bff241c5c80 at pc 0x7bfff35aa89a bp 0x7bff975e15e0 sp 0x7bff975e15d8
READ of size 32 at 0x7bff241c5c80 thread T36
#0 0x7bfff35aa899 in yy_loadu_256 /builds/worker/checkouts/gecko/third_party/aom/aom_dsp/x86/synonyms_avx2.h:35:10
#1 0x7bfff35aa899 in sse_w32_avx2 /builds/worker/checkouts/gecko/third_party/aom/aom_dsp/x86/sse_avx2.c:25:24
#2 0x7bfff35aa899 in aom_sse_avx2 /builds/worker/checkouts/gecko/third_party/aom/aom_dsp/x86/sse_avx2.c:165:9
#3 0x7bfff3c591dc in get_filt_error /builds/worker/checkouts/gecko/third_party/aom/av1/encoder/pickcdef.c:428:13
#4 0x7bfff3c591dc in av1_cdef_mse_calc_block /builds/worker/checkouts/gecko/third_party/aom/av1/encoder/pickcdef.c:601:33
#5 0x7bfff3b442c2 in cdef_filter_block_worker_hook /builds/worker/checkouts/gecko/third_party/aom/av1/encoder/ethread.c:3332:5
...
0x7bff241c5c80 is located 89 bytes after 21414951-byte region [0x7bff22d59800,0x7bff241c5c27)
allocated by thread T36 here:
#0 0x5555556c3484 in malloc /builds/worker/fetches/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:67:3
#1 0x7bfff35fdd66 in aom_memalign /builds/worker/checkouts/gecko/third_party/aom/aom_mem/aom_mem.c:59:22
#2 0x7bfff35fe4b1 in realloc_frame_buffer_aligned /builds/worker/checkouts/gecko/third_party/aom/aom_scale/generic/yv12config.c:132:38
#3 0x7bfff35fe4b1 in aom_realloc_frame_buffer /builds/worker/checkouts/gecko/third_party/aom/aom_scale/generic/yv12config.c:259:12
#4 0x7bfff3c60dcf in av1_pick_filter_level /builds/worker/checkouts/gecko/third_party/aom/av1/encoder/picklpf.c:348:9
#5 0x7bfff3b0304c in loopfilter_frame /builds/worker/checkouts/gecko/third_party/aom/av1/encoder/encoder.c:2874:5
...
I have also seen this stack-trace on my fuzzing cluster, I suspect it to be from the same root cause, but haven't been able to get that reproduced, by modifying this repro-file:
==796764==ERROR: AddressSanitizer: stack-use-after-return on address 0x7bff5eed9c80 at pc 0x7bfff31aa767 bp 0x7bffad3e1600 sp 0x7bffad3e15f8
READ of size 16 at 0x7bff5eed9c80 thread T32
SCARINESS: 64 (multi-byte-read-stack-use-after-return)
#0 0x7bfff31aa766 in xx_loadu_128 /builds/worker/checkouts/gecko/third_party/aom/aom_dsp/x86/synonyms.h:46:10
#1 0x7bfff31aa766 in aom_sse_avx2 /builds/worker/checkouts/gecko/third_party/aom/aom_dsp/x86/sse_avx2.c:132:30
#2 0x7bfff385944a in get_filt_error /builds/worker/checkouts/gecko/third_party/aom/av1/encoder/pickcdef.c:461:23
#3 0x7bfff385944a in av1_cdef_mse_calc_block /builds/worker/checkouts/gecko/third_party/aom/av1/encoder/pickcdef.c:601:33
#4 0x7bfff37442c2 in cdef_filter_block_worker_hook /builds/worker/checkouts/gecko/third_party/aom/av1/encoder/ethread.c:3332:5
#5 0x7bfff3204bf5 in execute /builds/worker/checkouts/gecko/third_party/aom/aom_util/aom_thread.c:197:27
...
Address 0x7bff5eed9c80 is located in stack of thread T60 at offset 128 in frame
#0 0x7bffd181750f in mozilla::CycleCollectedJSRuntime::DescribeGCThing(bool, JS::GCCellPtr, nsCycleCollectionTraversalCallback&) const /builds/worker/checkouts/gecko/xpcom/base/CycleCollectedJSRuntime.cpp:961:0
This frame has 4 object(s):
[32, 40) 'aThing'
[64, 136) 'name' (line 967) <== Memory access at offset 128 partially overflows this variable
[176, 328) 'chars' (line 982)
[400, 488) 'fname' (line 984)
Updated•8 months ago
|
Updated•8 months ago
|
Tagging Paul on this since I think he'd be the one to ask here.
Updated•8 months ago
|
Comment 2•8 months ago
|
||
Chatted with Ashley, bouncing this over to ChunMin since it's in WebCodecs.
| Assignee | ||
Comment 3•8 months ago
•
|
||
Updating libaom doesn't fix the issue. We need to patch somewhere.
| Assignee | ||
Comment 4•8 months ago
|
||
Here is a standalone libaom test reproducing the issue demonstrated in the test page.
| Assignee | ||
Comment 5•8 months ago
•
|
||
This is a proposed fix by Claude AI.
My knowledge AV1 encoding is limited and insufficient to judge if this is the right fix right now. Need more investigation to verify this. In the in the meanwhile, maybe it's better to check this issue with someone familiar with libaom's internal mechanism?
TODO
- The fix bypass the
get_offset_from_fullmvusage to avoid usingFULLPEL_MV, butFULLPEL_MVis fairly common structure used widely in the libaom codebase. Doesn't that imply all call sites s to be revamped? unlessget_offset_from_fullmvis misued?- Perhaps the calculation here is not for motion vectors so it's okay to skip using
get_offset_from_fullmv - or replacing it with something with the
inttypes?
- Perhaps the calculation here is not for motion vectors so it's okay to skip using
get_offset_from_fullmvwas introduced to pickcdef.c in commit332b730d1e(Oct 2022) by Ranjit Kumar Tulabandu — "Speed-up error calculation in av1_cdef_search()". Need to check the behavior before the changes.- key question: Were
rowandcolinintbefore the commit332b730d1e? (updated: YES)
- key question: Were
| Assignee | ||
Comment 6•8 months ago
|
||
This is a patch adding tracing log on top of attachment #9549579 [details] [diff] [review].
Tracing logs added to the libaom encode pipeline to demonstrate the
int16_t overflow in get_filt_error() for frames with dimensions
exceeding 32768 pixels.
Traced code path
| # | File | Function | Trace tag |
|---|---|---|---|
| 1 | aom/src/aom_encoder.c |
aom_codec_encode() |
TRACE-1 |
| 2 | av1/av1_cx_iface.c |
encoder_encode() |
TRACE-2 |
| 3 | av1/encoder/encoder.c |
av1_get_compressed_data() |
TRACE-3 |
| 4 | av1/encoder/encode_strategy.c |
av1_encode_strategy() |
TRACE-4 |
| 5 | av1/encoder/encoder.c |
av1_encode() |
TRACE-5 |
| 6 | av1/encoder/encoder.c |
encode_frame_to_data_rate() |
TRACE-6 |
| 7 | av1/encoder/encoder.c |
encode_with_recode_loop_and_filter() |
TRACE-7 |
| 8 | av1/encoder/encoder.c |
loopfilter_frame() |
TRACE-8 |
| 9 | av1/encoder/encoder.c |
cdef_restoration_frame() |
TRACE-9 |
| 10 | av1/encoder/pickcdef.c |
av1_cdef_search() |
TRACE-10 |
| 11 | av1/encoder/pickcdef.c |
cdef_mse_calc_frame() |
TRACE-11 |
| 12 | av1/encoder/pickcdef.c |
av1_cdef_mse_calc_block() |
TRACE-12 |
| 13 | av1/encoder/pickcdef.c |
get_filt_error() |
TRACE-13 |
At location 13, the BUG-SITE-1 through BUG-SITE-4 logs detect the
actual FULLPEL_MV int16_t truncation and print both the correct and
truncated values.
Prerequisites
- CMake >= 3.16
- Clang with
-fsanitize=implicit-signed-integer-truncation(Clang 7+) - nasm or yasm
- Perl
Build
mkdir aom-build && cd aom-build
cmake /path/to/aom \
-DCMAKE_BUILD_TYPE=Release \
-DENABLE_TESTS=1 \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_C_FLAGS="-fsanitize=implicit-signed-integer-truncation -fsanitize-recover=implicit-signed-integer-truncation" \
-DCMAKE_CXX_FLAGS="-fsanitize=implicit-signed-integer-truncation -fsanitize-recover=implicit-signed-integer-truncation" \
-DCMAKE_EXE_LINKER_FLAGS="-fsanitize=implicit-signed-integer-truncation"
make -j$(nproc) test_libaom
Run tests and capture logs
cd aom-build
# TallFrame (height > 32768): overflow in row
UBSAN_OPTIONS="halt_on_error=0:print_stacktrace=0" \
./test_libaom --gtest_filter="EncodeLargeHeight.TallFrame" \
> cdef-overflow-trace-tall.log 2>&1
# WideFrame (width > 32768): overflow in col
UBSAN_OPTIONS="halt_on_error=0:print_stacktrace=0" \
./test_libaom --gtest_filter="EncodeLargeHeight.WideFrame" \
> cdef-overflow-trace-wide.log 2>&1
halt_on_error=0 allows execution to continue past the UBSan diagnostic
so all trace points and truncation detections are captured in a single
run.
Reading the logs
The trace lines show the 64x32832 (or 32832x64) frame dimensions
propagating through the entire encode pipeline, ending at the overflow:
[TRACE-1] aom_codec_encode img=64x32832
[TRACE-2] encoder_encode width=64 height=32832
...
[TRACE-11] cdef_mse_calc_frame nvfb=513 nhfb=1
[TRACE-12] av1_cdef_mse_calc_block fbr=512 fbc=0 -> row=32768 col=0
[TRACE-13] get_filt_error row=32768 col=0 ref_stride=256
[BUG-SITE-1] FULLPEL_MV truncation: row=32768 -> int16_t=-32768
correct buf_offset=8388608, truncated buf_offset=-8388608
The key values:
nvfb=513: 513 superblock rows (32832 / 64)fbr=512: last superblock row indexrow=32768: pixel position = 512 * 64 = 32768 (exceeds int16_t max 32767)int16_t=-32768: truncated value wraps negativebuf_offset=-8388608: OOB read 8 MB before the source buffer
| Assignee | ||
Comment 7•8 months ago
|
||
| Assignee | ||
Comment 8•8 months ago
|
||
Comment 9•8 months ago
|
||
I've reported this to the libaom maintainers. Should have some updates here shortly.
Updated•8 months ago
|
| Assignee | ||
Comment 10•8 months ago
•
|
||
I don't have access to the link 🙁
Comment 11•8 months ago
|
||
(In reply to C.M.Chang[:chunmin] from comment #10)
I don't have access to the link 🙁
Sorry, I don't have access controls to open that up. Suffice to say Google is looking at this currently. I sent you some feedback on Matrix.
| Assignee | ||
Comment 12•8 months ago
•
|
||
Chrome avoid the overflow by checking the framesize in advance: https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/modules/webcodecs/video_encoder.cc;l=443-454;drc=3e781fb193605c0dae407c09766c4436d268ef2c
While the max frame size in AV1 spec is 65536 x 65536, their internal check rejects any frame size larger than 32767 x 32767, which is the reason triggering the overflow issue here.
Before we have a fix in libaom, we could probably do the same check in Firefox.
Another workaround is to set enable-cdef=0 on libaom via FFmpeg's av_opt_set in FFmpegVideoEncoder::InitEncoderInternal(). This disables the CDEF filter entirely, so av1_cdef_search() is never called and get_filt_error() is never reached. However, this leads to quality degradation.
| Assignee | ||
Comment 13•8 months ago
|
||
| Assignee | ||
Comment 14•8 months ago
|
||
| Assignee | ||
Comment 15•8 months ago
|
||
This is my WIP analysis docs. Will travel back to Taiwan next week so I won't be able to have access on my daily working machine. The docs are temporarily uploaded here so I can pick it up from my laptop when needed.
Comment 16•7 months ago
|
||
There is a sec fix coming out in the library as well.
get_filt_error() used FULLPEL_MV (int16_t row/col) to store pixel
positions within the frame and compute buffer offsets via
get_offset_from_fullmv(). For frames with height or width exceeding
32768 pixels, the pixel coordinate overflows int16_t, wrapping to a
negative value. This causes get_offset_from_fullmv() to compute a
negative buffer offset, resulting in an out-of-bounds read.
FULLPEL_MV was designed for motion vectors (bounded by search range),
not for absolute pixel coordinates in large frames. The AV1 spec
allows frames up to 65536x65536, so these dimensions are within valid
encoder input range.
Replace FULLPEL_MV + get_offset_from_fullmv() / get_buf_from_fullmv()
with direct int arithmetic at all four usage sites in get_filt_error().
Remove the now-unused mcomp.h include.
Based on original set of patches from Chun-Min Chang.
Bug: 489473886
Change-Id: I01fb3c981a5a7750fc029b6c98fc73f60614849c
| Assignee | ||
Comment 17•7 months ago
•
|
||
The upstream fix is in commit e8b13a0: https://aomedia.googlesource.com/aom/+/e8b13a0936be81657c466f6a99f9a86e0365ef99, which fixes the issue in av1/encoder/pickcdef.c, similar to what attachment 9549585 [details] [diff] [review] suggested (Thanks Claude!).
I'll vendor the fix in bug 1994052 (secretly).
As for uplift, we can try if cherry pick e8b13a0 works. If it doesn't, according to https://aomedia.googlesource.com/aom/+log/e8b13a0936be81657c466f6a99f9a86e0365ef99/av1/encoder/pickcdef.c, we may need to cherry pick all or part of the following commits without updating the whole libaom library:
e8b13a0Fix int16_t overflow in CDEF search for frames > 32768 pixels by James Zern · 3 days ago40f676aImprove sf 'fast_intra_tx_type_search' by Anusuya · 7 weeks ago8b67dd8Adaptive CDEF: do not apply to chroma in CDEF_PICK_FROM_Q mode by Julio Barba · 3 months ago027a236Adaptive CDEF: code review feedback follow-up by Julio Barba · 3 months ago9a1181fAdaptive CDEF: make decoder-friendly at middle quality levels by Julio Barba · 4 months ago
Updated•7 months ago
|
| Assignee | ||
Comment 18•7 months ago
|
||
| Assignee | ||
Comment 19•7 months ago
|
||
Original Revision: https://phabricator.services.mozilla.com/D287089
Updated•7 months ago
|
| Assignee | ||
Comment 20•7 months ago
|
||
Original Revision: https://phabricator.services.mozilla.com/D287089
Updated•7 months ago
|
| Assignee | ||
Comment 21•7 months ago
|
||
Original Revision: https://phabricator.services.mozilla.com/D287089
Updated•7 months ago
|
| Assignee | ||
Comment 22•7 months ago
|
||
Original Revision: https://phabricator.services.mozilla.com/D287089
Updated•7 months ago
|
Updated•7 months ago
|
Updated•7 months ago
|
Updated•7 months ago
|
Updated•7 months ago
|
| Assignee | ||
Comment 23•7 months ago
|
||
Comment on attachment 9551787 [details]
Bug 2020030
Beta/Release Uplift Approval Request
- User impact if declined/Reason for urgency: malicious webpage can a read out-of-bound memory, accessing the data they shouldn't touch
- Is this code covered by automated tests?: No
- Has the fix been verified in Nightly?: Yes
- Needs manual test from QE?: Yes
- If yes, steps to reproduce: 1. Ensure the test page here https://bugzilla.mozilla.org/attachment.cgi?id=9548741 cause a crash, or has ASAN or other memory error logs in the console
- Apply the fix, and make sure no crash ans no unexpected memory error
- List of other uplifts needed: None
- Risk to taking this patch: Low
- Why is the change risky/not risky? (and alternatives if risky): This patch is cherry-picked from libaom update, which correct the calculation of the offset for the memory address reading, and should not any behavior other than this.
- String changes made/needed: None
- Is Android affected?: No
ESR Uplift Approval Request
- If this is not a sec:{high,crit} bug, please state case for ESR consideration:
- User impact if declined: malicious webpage can a read out-of-bound memory, accessing the data they shouldn't touch
- Fix Landed on Version: 150
- Risk to taking this patch: Low
- Why is the change risky/not risky? (and alternatives if risky): This patch is cherry-picked from libaom update, which correct the calculation of the offset for the memory address reading, and should not any behavior other than this.
| Assignee | ||
Updated•7 months ago
|
Comment 24•7 months ago
|
||
Comment on attachment 9551787 [details]
Bug 2020030
Rejecting release uplift request. This is not suitable for inclusion in a dot release since ESR is affected.
Comment 25•7 months ago
|
||
This was fixed on Nightly by bug 1994052.
Comment 26•7 months ago
|
||
Comment on attachment 9551787 [details]
Bug 2020030
Approved for 149.0b9 and 140.9esr.
Updated•7 months ago
|
Comment 27•7 months ago
|
||
| uplift | ||
Comment 28•7 months ago
|
||
| uplift | ||
Updated•7 months ago
|
Updated•7 months ago
|
Comment 29•7 months ago
|
||
Reproduced the issue on Firefox 150.0a1 (2026-02-27) on Ubuntu 24.0.4 by following the informations provided in Comment 0.
The issue is fixed on Firefox ESR 140.9.0, Firefox 149.0b9 and Firefox 150.0a1 (2026-03-15). Tests were performed on Ubuntu 24.04, Windows 11 and macOS 26.3.1.
Updated•7 months ago
|
Updated•7 months ago
|
Updated•7 months ago
|
Updated•3 months ago
|
Updated•2 months ago
|
Comment 30•2 months ago
|
||
Comment 31•2 months ago
|
||
| bugherder | ||
Updated•2 months ago
|
Updated•2 months ago
|
Description
•