From 8915bd22570ee608907f1b88a68e587d17813812 Mon Sep 17 00:00:00 2001 From: Micah Snyder Date: Tue, 16 Jul 2024 11:22:05 -0400 Subject: [PATCH] Fix possible out of bounds read in PDF parser The `find_length()` function in the PDF parser incorrectly assumes that objects found are located in the main PDF file map, and fails to take into account whether the objects were in fact found in extracted PDF object streams. The resulting pointer is then invalid and may be an out of bounds read. This issue was found by OSS-Fuzz. This fix checks if the object is from an object stream, and then calculates the pointer based on the start of the object stream instead of based on the start of the PDF. I've also added extra checks to verify the calculated pointer and object size are within the stream (or PDF file map). I'm not entirely sure this is necessary, but better safe than sorry. Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=69617 --- libclamav/pdf.c | 45 +++++++++++++++++++++++++++++++++++++++------ libclamav/pdfng.c | 5 +++++ 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/libclamav/pdf.c b/libclamav/pdf.c index a5dd159e8a..6b2c7d2ff8 100644 --- a/libclamav/pdf.c +++ b/libclamav/pdf.c @@ -1003,8 +1003,26 @@ static size_t find_length(struct pdf_struct *pdf, struct pdf_obj *obj, const cha return 0; } - indirect_obj_start = pdf->map + obj->start; - bytes_remaining = pdf->size - obj->start; + if (NULL == obj->objstm) { + indirect_obj_start = (const char *)(obj->start + pdf->map); + + if (!CLI_ISCONTAINED(pdf->map, pdf->size, indirect_obj_start, obj->size)) { + cli_dbgmsg("find_length: indirect object found, but not contained in PDF\n"); + return 0; + } + + bytes_remaining = pdf->size - obj->start; + + } else { + indirect_obj_start = (const char *)(obj->start + obj->objstm->streambuf); + + if (!CLI_ISCONTAINED(obj->objstm->streambuf, obj->objstm->streambuf_len, indirect_obj_start, obj->size)) { + cli_dbgmsg("find_length: indirect object found, but not contained in PDF streambuf\n"); + return 0; + } + + bytes_remaining = obj->objstm->streambuf_len - obj->start; + } /* Ok so we found the indirect object, lets read the value. */ index = pdf_nextobject(indirect_obj_start, bytes_remaining); @@ -3260,15 +3278,30 @@ void pdf_handle_enc(struct pdf_struct *pdf) obj = find_obj(pdf, pdf->objs[0], pdf->enc_objid); if (!obj) { - cli_dbgmsg("pdf_handle_enc: can't find encrypted object %d %d\n", pdf->enc_objid >> 8, pdf->enc_objid & 0xff); - noisy_warnmsg("pdf_handle_enc: can't find encrypted object %d %d\n", pdf->enc_objid >> 8, pdf->enc_objid & 0xff); + cli_dbgmsg("pdf_handle_enc: can't find encryption object %d %d\n", pdf->enc_objid >> 8, pdf->enc_objid & 0xff); + noisy_warnmsg("pdf_handle_enc: can't find encryption object %d %d\n", pdf->enc_objid >> 8, pdf->enc_objid & 0xff); return; } len = obj->size; - q = (obj->objstm) ? (const char *)(obj->start + obj->objstm->streambuf) - : (const char *)(obj->start + pdf->map); + if (NULL == obj->objstm) { + q = (const char *)(obj->start + pdf->map); + + if (!CLI_ISCONTAINED(pdf->map, pdf->size, q, len)) { + cli_dbgmsg("pdf_handle_enc: encryption object found, but not contained in PDF\n"); + noisy_warnmsg("pdf_handle_enc: encryption object found, but not contained in PDF\n"); + return; + } + } else { + q = (const char *)(obj->start + obj->objstm->streambuf); + + if (!CLI_ISCONTAINED(obj->objstm->streambuf, obj->objstm->streambuf_len, q, len)) { + cli_dbgmsg("pdf_handle_enc: encryption object found, but not contained in PDF streambuf\n"); + noisy_warnmsg("pdf_handle_enc: encryption object found, but not contained in PDF streambuf\n"); + return; + } + } O = U = UE = StmF = StrF = EFF = NULL; diff --git a/libclamav/pdfng.c b/libclamav/pdfng.c index 575cece831..5c3b9a116f 100644 --- a/libclamav/pdfng.c +++ b/libclamav/pdfng.c @@ -518,6 +518,11 @@ char *pdf_parse_string(struct pdf_struct *pdf, struct pdf_obj *obj, const char * if (!(newobj)) return NULL; + if (!CLI_ISCONTAINED(pdf->map, pdf->size, newobj->start, newobj->size)) { + cli_dbgmsg("pdf_parse_string: object not contained in PDF\n"); + return NULL; + } + if (newobj == obj) return NULL;