From 4f10021e7ee527c1aa24853e2947e38e154d9ccb Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Fri, 3 Feb 2023 20:39:04 -0500 Subject: [PATCH] Fix denial-of-service attack when reading corrupt PDF files. --- CHANGES.md | 5 +++-- Makefile | 4 ++-- NOTICE | 2 +- pdfio-common.c | 6 ++++-- pdfio-dict.c | 15 +++++++++++---- pdfio-file.c | 4 +++- pdfio-object.c | 2 +- pdfio-token.c | 21 +++++++++++++++++---- pdfio-value.c | 2 +- 9 files changed, 43 insertions(+), 18 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 8254505..b38141b 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,9 +2,10 @@ Changes in PDFio ================ -v1.1.0 (Month DD, YYYY) ------------------------ +v1.1.0 (February 3, 2023) +------------------------- +- CVE-2023-nnnn: Fixed a potential denial-of-service with corrupt PDF files. - Added `pdfioFileCreateTemporary` function (Issue #29) - Added `pdfioDictIterateKeys` function (Issue #31) - Added `pdfioContentPathEnd` function. diff --git a/Makefile b/Makefile index 4fbf69c..ac576c9 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # # Makefile for PDFio. # -# Copyright © 2021-2022 by Michael R Sweet. +# Copyright © 2021-2023 by Michael R Sweet. # # Licensed under Apache License v2.0. See the file "LICENSE" for more # information. @@ -29,7 +29,7 @@ DSONAME = LDFLAGS = LIBS = -lm -lz RANLIB = ranlib -VERSION = 1.1 +VERSION = 1.1.0 prefix = /usr/local diff --git a/NOTICE b/NOTICE index fb3ab29..37ef3c8 100644 --- a/NOTICE +++ b/NOTICE @@ -1,6 +1,6 @@ PDFio - PDF Read/Write Library -Copyright © 2021-2022 by Michael R Sweet. +Copyright © 2021-2023 by Michael R Sweet. (Optional) Exceptions to the Apache 2.0 License: ================================================ diff --git a/pdfio-common.c b/pdfio-common.c index 00da8e6..bc23fd0 100644 --- a/pdfio-common.c +++ b/pdfio-common.c @@ -1,7 +1,7 @@ // // Common support functions for pdfio. // -// Copyright © 2021 by Michael R Sweet. +// Copyright © 2021-2023 by Michael R Sweet. // // Licensed under Apache License v2.0. See the file "LICENSE" for more // information. @@ -38,6 +38,8 @@ _pdfioFileConsume(pdfio_file_t *pdf, // I - PDF file else if (_pdfioFileSeek(pdf, (off_t)bytes, SEEK_CUR) < 0) return (false); + PDFIO_DEBUG("_pdfioFileConsume: pos=%ld\n", (long)(pdf->bufpos + pdf->bufptr - pdf->buffer)); + return (true); } @@ -525,7 +527,7 @@ read_buffer(pdfio_file_t *pdf, // I - PDF file return (rbytes); } - + // // 'write_buffer()' - Write a buffer to a PDF file. // diff --git a/pdfio-dict.c b/pdfio-dict.c index eaf6268..4196adf 100644 --- a/pdfio-dict.c +++ b/pdfio-dict.c @@ -1,7 +1,7 @@ // // PDF dictionary functions for PDFio. // -// Copyright © 2021-2022 by Michael R Sweet. +// Copyright © 2021-2023 by Michael R Sweet. // // Licensed under Apache License v2.0. See the file "LICENSE" for more // information. @@ -541,8 +541,15 @@ _pdfioDictRead(pdfio_file_t *pdf, // I - PDF file _pdfioFileError(pdf, "Invalid dictionary contents."); break; } + else if (_pdfioDictGetValue(dict, key + 1)) + { + _pdfioFileError(pdf, "Duplicate dictionary key '%s'.", key + 1); + return (NULL); + } // Then get the next value... + PDFIO_DEBUG("_pdfioDictRead: Reading value for '%s'.\n", key + 1); + if (!_pdfioValueRead(pdf, obj, tb, &value, depth)) { _pdfioFileError(pdf, "Missing value for dictionary key."); @@ -932,9 +939,9 @@ _pdfioDictSetValue( #ifdef DEBUG PDFIO_DEBUG("_pdfioDictSetValue(%p): %lu pairs\n", (void *)dict, (unsigned long)dict->num_pairs); - PDFIO_DEBUG("_pdfioDictSetValue(%p): ", (void *)dict); - PDFIO_DEBUG_DICT(dict); - PDFIO_DEBUG("\n"); +// PDFIO_DEBUG("_pdfioDictSetValue(%p): ", (void *)dict); +// PDFIO_DEBUG_DICT(dict); +// PDFIO_DEBUG("\n"); #endif // DEBUG return (true); diff --git a/pdfio-file.c b/pdfio-file.c index 90986d9..a95378c 100644 --- a/pdfio-file.c +++ b/pdfio-file.c @@ -1,7 +1,7 @@ // // PDF file functions for PDFio. // -// Copyright © 2021-2022 by Michael R Sweet. +// Copyright © 2021-2023 by Michael R Sweet. // // Licensed under Apache License v2.0. See the file "LICENSE" for more // information. @@ -1984,6 +1984,8 @@ load_xref( return (false); } + PDFIO_DEBUG("load_xref: Got trailer dict.\n"); + _pdfioTokenFlush(&tb); if (!pdf->trailer_dict) diff --git a/pdfio-object.c b/pdfio-object.c index 6053518..88ab25f 100644 --- a/pdfio-object.c +++ b/pdfio-object.c @@ -1,7 +1,7 @@ // // PDF object functions for PDFio. // -// Copyright © 2021-2022 by Michael R Sweet. +// Copyright © 2021-2023 by Michael R Sweet. // // Licensed under Apache License v2.0. See the file "LICENSE" for more // information. diff --git a/pdfio-token.c b/pdfio-token.c index 1331bb9..559a7ff 100644 --- a/pdfio-token.c +++ b/pdfio-token.c @@ -1,7 +1,7 @@ // // PDF token parsing functions for PDFio. // -// Copyright © 2021 by Michael R Sweet. +// Copyright © 2021-2023 by Michael R Sweet. // // Licensed under Apache License v2.0. See the file "LICENSE" for more // information. @@ -129,9 +129,20 @@ _pdfioTokenGet(_pdfio_token_t *tb, // I - Token buffer/stack if (tb->num_tokens > 0) { // Yes, return it... + size_t len; // Length of token + tb->num_tokens --; - strncpy(buffer, tb->tokens[tb->num_tokens], bufsize - 1); - buffer[bufsize - 1] = '\0'; + + if ((len = strlen(tb->tokens[tb->num_tokens])) > (bufsize - 1)) + { + // Value too large... + PDFIO_DEBUG("_pdfioTokenGet(tb=%p, buffer=%p, bufsize=%u): Token '%s' from stack too large.\n", tb, buffer, (unsigned)bufsize, tb->tokens[tb->num_tokens]); + *buffer = '\0'; + return (false); + } + + memcpy(buffer, tb->tokens[tb->num_tokens], len); + buffer[len] = '\0'; PDFIO_DEBUG("_pdfioTokenGet(tb=%p, buffer=%p, bufsize=%u): Popping '%s' from stack.\n", tb, buffer, (unsigned)bufsize, buffer); @@ -536,7 +547,7 @@ _pdfioTokenRead(_pdfio_token_t *tb, // I - Token buffer/stack *bufptr = '\0'; - PDFIO_DEBUG("_pdfioTokenRead: Read '%s'.\n", buffer); +// PDFIO_DEBUG("_pdfioTokenRead: Read '%s'.\n", buffer); return (bufptr > buffer); } @@ -573,6 +584,7 @@ get_char(_pdfio_token_t *tb) // I - Token buffer tb->bufptr = tb->buffer; tb->bufend = tb->buffer + bytes; +#if 0 #ifdef DEBUG unsigned char *ptr; // Pointer into buffer @@ -586,6 +598,7 @@ get_char(_pdfio_token_t *tb) // I - Token buffer } PDFIO_DEBUG("'\n"); #endif // DEBUG +#endif // 0 } // Return the next character... diff --git a/pdfio-value.c b/pdfio-value.c index 7f114e6..1007465 100644 --- a/pdfio-value.c +++ b/pdfio-value.c @@ -1,7 +1,7 @@ // // PDF value functions for PDFio. // -// Copyright © 2021 by Michael R Sweet. +// Copyright © 2021-2023 by Michael R Sweet. // // Licensed under Apache License v2.0. See the file "LICENSE" for more // information.