Skip to content

fix(SgpdAtom): guard bytes_available against underflow to stop giant SetDataSize - #1097

Open
AetherAI3 wants to merge 1 commit into
axiomatic-systems:masterfrom
AetherAI3:fix/1042-sgpd-bytes-available-underflow
Open

AetherAI3 wants to merge 1 commit into
axiomatic-systems:masterfrom
AetherAI3:fix/1042-sgpd-bytes-available-underflow

Conversation

@AetherAI3

Copy link
Copy Markdown

Closes #1042.

AP4_SgpdAtom's constructor tracks the atom's remaining bytes in an unsigned AP4_Size counter and pattern-matches every read as ReadUI32(field); bytes_available -= 4; — no check that four bytes were actually left before the decrement.

On a truncated sgpd (crafted PoC has size close to AP4_FULL_ATOM_HEADER_SIZE), the first -=4 wraps bytes_available to 0xFFFFFFFC. The entry loop below computes description_length as either bytes_available (version 0) or compares a crafted value against it (version 1); either way the description_length <= bytes_available check passes anything up to 0xFFFFFFFC, and AP4_DataBuffer::SetDataSize forwards that same value to operator new[] as a ~4 GiB allocation. ASan aborts:

ERROR: AddressSanitizer: out of memory: allocator is trying to allocate 0xfffffffc bytes
#0 operator new[]
#1 AP4_DataBuffer::ReallocateBuffer Ap4DataBuffer.cpp:210
#2 AP4_DataBuffer::SetDataSize Ap4DataBuffer.cpp:151
#3 AP4_SgpdAtom::AP4_SgpdAtom Ap4SgpdAtom.cpp:108

Guard each read-and-decrement in the constructor prologue with if (bytes_available < 4) return;. Well-formed inputs have plenty of room so nothing observable changes; a malformed atom exits the constructor early with m_GroupingType/m_DefaultLength still at their default-initialised values and an empty m_Entries — the same shape the code already produces when one of the reads fails silently.

Local build (Ubuntu 24.04, gcc 13.3.0, cmake -DCMAKE_CXX_FLAGS="-fsanitize=address,undefined -g -O0") reproduces the ASan OOM on master b8c50a0 and comes back clean after this patch:

$ ./mp4info ~/bento4-poc/poc4 # master b8c50a0
==*==ERROR: AddressSanitizer: out of memory: allocator is trying to allocate 0xfffffffc bytes
exit=1

$ ./mp4info ~/bento4-poc/poc4 # fix 8743f43
Movie:
duration: 1181314149 (movie timescale units)
...
Found 2 Tracks
exit=0

Reported-by: @sigdevel — thanks for the report and reproducer, also referenced by GHSA-v7gf-c3mw-55gx.

…SetDataSize

AP4_SgpdAtom's constructor tracks the atom's remaining bytes with an
unsigned AP4_Size counter and pattern-matches every read as
'ReadUI32(field); bytes_available -= 4;' - never checking that the four
bytes were actually available before decrementing.

On a truncated sgpd atom (size close to AP4_FULL_ATOM_HEADER_SIZE), the
first '-= 4' wraps bytes_available to 0xFFFFFFFC. The entry loop below
then computes description_length as either bytes_available (version 0)
or as a value it compares against bytes_available (version 1). Either
way the comparison 'description_length <= bytes_available' passes any
value up to 0xFFFFFFFC, and AP4_DataBuffer::SetDataSize is handed the
same, which is then forwarded to operator new[] as a ~4 GiB allocation
request - AddressSanitizer aborts with 'out of memory: allocator is
trying to allocate 0xfffffffc bytes'. See @sigdevel's PoC linked from
gh#1042 (also referenced by GHSA-v7gf-c3mw-55gx).

Guard each read-and-decrement with 'if (bytes_available < 4) return;'.
Well-formed inputs have plenty of room so nothing changes on the happy
path; malformed atoms exit the constructor early with the previously-read
fields (m_GroupingType and optionally m_DefaultLength) at their default
values and an empty m_Entries list.

Reported-by: Alexander Shvedov <sigdevel>
Closes axiomatic-systems#1042

Signed-off-by: Brandon Barrante <aetherai@aethersystems.net>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant