From 744e730f18fee23e542a28e59503d310139387f9 Mon Sep 17 00:00:00 2001 From: ObaidAbdullah16 Date: Fri, 3 Apr 2026 21:13:00 +0530 Subject: [PATCH 1/3] [FIX] Prevent NULL buffer dereference in WTV parser on oversized chunks - Changed get_sized_buffer() to return int error code instead of void - Add error checks in all 5 callers before using cb->buffer - Gracefully handle malformed WTV files with chunk sizes > WTV_MAX_ALLOC (100MB) - Prevents segmentation fault when processing corrupted WTV input Root cause: Function returned without error signaling, leaving cb->buffer NULL. Callers then dereferenced NULL pointer causing crash. Fix: Return -1 on allocation/read failures, check return value in all callers. Test case: tests/samples/malformed_oversized_chunk.wtv triggers the original bug. --- src/lib_ccx/wtv_functions.c | 40 +++++++++++++++----- src/lib_ccx/wtv_functions.h | 11 ++++++ tests/samples/malformed_oversized_chunk.wtv | Bin 0 -> 132 bytes 3 files changed, 41 insertions(+), 10 deletions(-) create mode 100644 src/lib_ccx/wtv_functions.h create mode 100644 tests/samples/malformed_oversized_chunk.wtv diff --git a/src/lib_ccx/wtv_functions.c b/src/lib_ccx/wtv_functions.c index 31d20131f..db8010f07 100644 --- a/src/lib_ccx/wtv_functions.c +++ b/src/lib_ccx/wtv_functions.c @@ -135,7 +135,7 @@ void skip_sized_buffer(struct ccx_demuxer *ctx, struct wtv_chunked_buffer *cb, u // get_sized_buffer will alloc and set a buffer in the passed wtv_chunked_buffer struct // it will handle any meta data chunks that need to be skipped in the file // Will print error messages and return a null buffer on error. -void get_sized_buffer(struct ccx_demuxer *ctx, struct wtv_chunked_buffer *cb, uint32_t size) +int get_sized_buffer(struct ccx_demuxer *ctx, struct wtv_chunked_buffer *cb, uint32_t size) { int64_t result; if (cb->buffer != NULL && cb->buffer_size > 0) @@ -147,7 +147,7 @@ void get_sized_buffer(struct ccx_demuxer *ctx, struct wtv_chunked_buffer *cb, ui { mprint("\nRequested buffer of %i > %i bytes (WTV_MAX_ALLOC)!\n", size, WTV_MAX_ALLOC); cb->buffer = NULL; - return; + return -1; } cb->buffer = (uint8_t *)malloc(size); @@ -155,7 +155,7 @@ void get_sized_buffer(struct ccx_demuxer *ctx, struct wtv_chunked_buffer *cb, ui { mprint("\nOut of memory allocating buffer of %i bytes!\n", size); cb->buffer_size = 0; - return; + return -1; } cb->buffer_size = size; uint64_t start = cb->filepos; @@ -181,11 +181,11 @@ void get_sized_buffer(struct ccx_demuxer *ctx, struct wtv_chunked_buffer *cb, ui ctx->past = cb->filepos; cb->buffer = NULL; mprint("\nPremature end of file!\n"); - return; + return -1; } } ctx->past = cb->filepos; - return; + return 0; } // read_header will read all the required information from @@ -364,7 +364,11 @@ LLONG get_data(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb, struct de uint32_t stream_id; // Read the 32 bytes containing the GUID and length and stream_id info - get_sized_buffer(ctx->demux_ctx, cb, 32); + if (get_sized_buffer(ctx->demux_ctx, cb, 32) < 0) + { + mprint("Error: Failed to read WTV buffer at line 367\n"); + return -1; + } if (cb->buffer == NULL) return CCX_EOF; @@ -423,7 +427,11 @@ LLONG get_data(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb, struct de dbg_print(CCX_DMT_PARSE, "WTV STREAM2\n"); // Read 96 bytes to get mediatype at 0x0C and format_subtype at 0x4C uint32_t read_size = (len > 96) ? 96 : len; - get_sized_buffer(ctx->demux_ctx, cb, read_size); + if (get_sized_buffer(ctx->demux_ctx, cb, read_size) < 0) + { + mprint("Error: Failed to read WTV buffer at line 426\n"); + return -1; + } if (cb->buffer == NULL) return CCX_EOF; static unsigned char stream_type[16]; @@ -476,7 +484,11 @@ LLONG get_data(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb, struct de int64_t time; // The WTV_TIMING GUID contains a timestamp for the given stream_id dbg_print(CCX_DMT_PARSE, "WTV TIMING\n"); - get_sized_buffer(ctx->demux_ctx, cb, 0x8 + 0x8); + if (get_sized_buffer(ctx->demux_ctx, cb, 0x8 + 0x8) < 0) + { + mprint("Error: Failed to read WTV buffer at line 479\n"); + return -1; + } if (cb->buffer == NULL) return CCX_EOF; @@ -512,7 +524,11 @@ LLONG get_data(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb, struct de { // This is the data for a stream we want to process dbg_print(CCX_DMT_PARSE, "\nWTV DATA\n"); - get_sized_buffer(ctx->demux_ctx, cb, len); + if (get_sized_buffer(ctx->demux_ctx, cb, len) < 0) + { + mprint("Error: Failed to read WTV buffer at line 515\n"); + return -1; + } if (cb->buffer == NULL) return CCX_EOF; memcpy(data->buffer + data->len, cb->buffer, len); @@ -533,7 +549,11 @@ LLONG get_data(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb, struct de // will process what it can parse. if (!memcmp(guid, WTV_DATA, 16) && check_teletext_stream_id(stream_id, teletext_streams, num_teletext_streams) && dec_ctx->timing->current_pts != 0) { - get_sized_buffer(ctx->demux_ctx, cb, len); + if (get_sized_buffer(ctx->demux_ctx, cb, len) < 0) + { + mprint("Error: Failed to read WTV buffer at line 536\n"); + return -1; + } if (cb->buffer == NULL) return CCX_EOF; diff --git a/src/lib_ccx/wtv_functions.h b/src/lib_ccx/wtv_functions.h new file mode 100644 index 000000000..735444037 --- /dev/null +++ b/src/lib_ccx/wtv_functions.h @@ -0,0 +1,11 @@ +#ifndef WTV_FUNCTIONS_H +#define WTV_FUNCTIONS_H + +#include "ccx_demuxer.h" +#include "wtv_constants.h" + +int get_sized_buffer(struct ccx_demuxer *ctx, struct wtv_chunked_buffer *cb, uint32_t size); +void skip_sized_buffer(struct ccx_demuxer *ctx, struct wtv_chunked_buffer *cb, uint32_t size); +int read_header(struct ccx_demuxer *ctx, struct wtv_chunked_buffer *cb); + +#endif \ No newline at end of file diff --git a/tests/samples/malformed_oversized_chunk.wtv b/tests/samples/malformed_oversized_chunk.wtv new file mode 100644 index 0000000000000000000000000000000000000000..eeab906e393562c55f7b5c5463eb5c6625639e1d GIT binary patch literal 132 TcmWF!31h$x5;(DoQ(qJSuXzD$ literal 0 HcmV?d00001 From 3d9858e0400051593b2f100b00159d52f7ec650f Mon Sep 17 00:00:00 2001 From: ObaidAbdullah16 Date: Fri, 3 Apr 2026 21:19:07 +0530 Subject: [PATCH 2/3] fixed void to int in the function declaration of get_sized_buffer --- src/lib_ccx/wtv_functions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib_ccx/wtv_functions.c b/src/lib_ccx/wtv_functions.c index db8010f07..9f88b1e1d 100644 --- a/src/lib_ccx/wtv_functions.c +++ b/src/lib_ccx/wtv_functions.c @@ -11,7 +11,7 @@ uint64_t get_meta_chunk_start(uint64_t offset); uint64_t time_to_pes_time(uint64_t time); void add_chunk(struct wtv_chunked_buffer *cb, uint64_t value); int qsort_cmpint(const void *a, const void *b); -void get_sized_buffer(struct ccx_demuxer *ctx, struct wtv_chunked_buffer *cb, uint32_t size); +int get_sized_buffer(struct ccx_demuxer *ctx, struct wtv_chunked_buffer *cb, uint32_t size); void skip_sized_buffer(struct ccx_demuxer *ctx, struct wtv_chunked_buffer *cb, uint32_t size); int read_header(struct ccx_demuxer *ctx, struct wtv_chunked_buffer *cb); From d50306114dc690c66a6979bd260025e33c894387 Mon Sep 17 00:00:00 2001 From: ObaidAbdullah16 Date: Fri, 3 Apr 2026 23:15:50 +0530 Subject: [PATCH 3/3] Fix: Apply clang-format for proper indentation --- src/lib_ccx/wtv_functions.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/lib_ccx/wtv_functions.c b/src/lib_ccx/wtv_functions.c index 9f88b1e1d..f1f3e17f8 100644 --- a/src/lib_ccx/wtv_functions.c +++ b/src/lib_ccx/wtv_functions.c @@ -366,8 +366,8 @@ LLONG get_data(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb, struct de // Read the 32 bytes containing the GUID and length and stream_id info if (get_sized_buffer(ctx->demux_ctx, cb, 32) < 0) { - mprint("Error: Failed to read WTV buffer at line 367\n"); - return -1; + mprint("Error: Failed to read WTV buffer at line 367\n"); + return -1; } if (cb->buffer == NULL) return CCX_EOF; @@ -429,9 +429,9 @@ LLONG get_data(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb, struct de uint32_t read_size = (len > 96) ? 96 : len; if (get_sized_buffer(ctx->demux_ctx, cb, read_size) < 0) { - mprint("Error: Failed to read WTV buffer at line 426\n"); - return -1; - } + mprint("Error: Failed to read WTV buffer at line 426\n"); + return -1; + } if (cb->buffer == NULL) return CCX_EOF; static unsigned char stream_type[16]; @@ -486,8 +486,8 @@ LLONG get_data(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb, struct de dbg_print(CCX_DMT_PARSE, "WTV TIMING\n"); if (get_sized_buffer(ctx->demux_ctx, cb, 0x8 + 0x8) < 0) { - mprint("Error: Failed to read WTV buffer at line 479\n"); - return -1; + mprint("Error: Failed to read WTV buffer at line 479\n"); + return -1; } if (cb->buffer == NULL) return CCX_EOF; @@ -526,8 +526,8 @@ LLONG get_data(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb, struct de dbg_print(CCX_DMT_PARSE, "\nWTV DATA\n"); if (get_sized_buffer(ctx->demux_ctx, cb, len) < 0) { - mprint("Error: Failed to read WTV buffer at line 515\n"); - return -1; + mprint("Error: Failed to read WTV buffer at line 515\n"); + return -1; } if (cb->buffer == NULL) return CCX_EOF; @@ -551,8 +551,8 @@ LLONG get_data(struct lib_ccx_ctx *ctx, struct wtv_chunked_buffer *cb, struct de { if (get_sized_buffer(ctx->demux_ctx, cb, len) < 0) { - mprint("Error: Failed to read WTV buffer at line 536\n"); - return -1; + mprint("Error: Failed to read WTV buffer at line 536\n"); + return -1; } if (cb->buffer == NULL) return CCX_EOF;