Fix denial-of-service attack when reading corrupt PDF files.

This commit is contained in:
Michael R Sweet 2023-02-03 20:39:04 -05:00
parent 57d5894f33
commit 4f10021e7e
No known key found for this signature in database
GPG Key ID: 999559A027815955
9 changed files with 43 additions and 18 deletions

View File

@ -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 `pdfioFileCreateTemporary` function (Issue #29)
- Added `pdfioDictIterateKeys` function (Issue #31) - Added `pdfioDictIterateKeys` function (Issue #31)
- Added `pdfioContentPathEnd` function. - Added `pdfioContentPathEnd` function.

View File

@ -1,7 +1,7 @@
# #
# Makefile for PDFio. # 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 # Licensed under Apache License v2.0. See the file "LICENSE" for more
# information. # information.
@ -29,7 +29,7 @@ DSONAME =
LDFLAGS = LDFLAGS =
LIBS = -lm -lz LIBS = -lm -lz
RANLIB = ranlib RANLIB = ranlib
VERSION = 1.1 VERSION = 1.1.0
prefix = /usr/local prefix = /usr/local

2
NOTICE
View File

@ -1,6 +1,6 @@
PDFio - PDF Read/Write Library 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: (Optional) Exceptions to the Apache 2.0 License:
================================================ ================================================

View File

@ -1,7 +1,7 @@
// //
// Common support functions for pdfio. // 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 // Licensed under Apache License v2.0. See the file "LICENSE" for more
// information. // information.
@ -38,6 +38,8 @@ _pdfioFileConsume(pdfio_file_t *pdf, // I - PDF file
else if (_pdfioFileSeek(pdf, (off_t)bytes, SEEK_CUR) < 0) else if (_pdfioFileSeek(pdf, (off_t)bytes, SEEK_CUR) < 0)
return (false); return (false);
PDFIO_DEBUG("_pdfioFileConsume: pos=%ld\n", (long)(pdf->bufpos + pdf->bufptr - pdf->buffer));
return (true); return (true);
} }

View File

@ -1,7 +1,7 @@
// //
// PDF dictionary functions for PDFio. // 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 // Licensed under Apache License v2.0. See the file "LICENSE" for more
// information. // information.
@ -541,8 +541,15 @@ _pdfioDictRead(pdfio_file_t *pdf, // I - PDF file
_pdfioFileError(pdf, "Invalid dictionary contents."); _pdfioFileError(pdf, "Invalid dictionary contents.");
break; break;
} }
else if (_pdfioDictGetValue(dict, key + 1))
{
_pdfioFileError(pdf, "Duplicate dictionary key '%s'.", key + 1);
return (NULL);
}
// Then get the next value... // Then get the next value...
PDFIO_DEBUG("_pdfioDictRead: Reading value for '%s'.\n", key + 1);
if (!_pdfioValueRead(pdf, obj, tb, &value, depth)) if (!_pdfioValueRead(pdf, obj, tb, &value, depth))
{ {
_pdfioFileError(pdf, "Missing value for dictionary key."); _pdfioFileError(pdf, "Missing value for dictionary key.");
@ -932,9 +939,9 @@ _pdfioDictSetValue(
#ifdef DEBUG #ifdef DEBUG
PDFIO_DEBUG("_pdfioDictSetValue(%p): %lu pairs\n", (void *)dict, (unsigned long)dict->num_pairs); PDFIO_DEBUG("_pdfioDictSetValue(%p): %lu pairs\n", (void *)dict, (unsigned long)dict->num_pairs);
PDFIO_DEBUG("_pdfioDictSetValue(%p): ", (void *)dict); // PDFIO_DEBUG("_pdfioDictSetValue(%p): ", (void *)dict);
PDFIO_DEBUG_DICT(dict); // PDFIO_DEBUG_DICT(dict);
PDFIO_DEBUG("\n"); // PDFIO_DEBUG("\n");
#endif // DEBUG #endif // DEBUG
return (true); return (true);

View File

@ -1,7 +1,7 @@
// //
// PDF file functions for PDFio. // 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 // Licensed under Apache License v2.0. See the file "LICENSE" for more
// information. // information.
@ -1984,6 +1984,8 @@ load_xref(
return (false); return (false);
} }
PDFIO_DEBUG("load_xref: Got trailer dict.\n");
_pdfioTokenFlush(&tb); _pdfioTokenFlush(&tb);
if (!pdf->trailer_dict) if (!pdf->trailer_dict)

View File

@ -1,7 +1,7 @@
// //
// PDF object functions for PDFio. // 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 // Licensed under Apache License v2.0. See the file "LICENSE" for more
// information. // information.

View File

@ -1,7 +1,7 @@
// //
// PDF token parsing functions for PDFio. // 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 // Licensed under Apache License v2.0. See the file "LICENSE" for more
// information. // information.
@ -129,9 +129,20 @@ _pdfioTokenGet(_pdfio_token_t *tb, // I - Token buffer/stack
if (tb->num_tokens > 0) if (tb->num_tokens > 0)
{ {
// Yes, return it... // Yes, return it...
size_t len; // Length of token
tb->num_tokens --; 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); 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'; *bufptr = '\0';
PDFIO_DEBUG("_pdfioTokenRead: Read '%s'.\n", buffer); // PDFIO_DEBUG("_pdfioTokenRead: Read '%s'.\n", buffer);
return (bufptr > buffer); return (bufptr > buffer);
} }
@ -573,6 +584,7 @@ get_char(_pdfio_token_t *tb) // I - Token buffer
tb->bufptr = tb->buffer; tb->bufptr = tb->buffer;
tb->bufend = tb->buffer + bytes; tb->bufend = tb->buffer + bytes;
#if 0
#ifdef DEBUG #ifdef DEBUG
unsigned char *ptr; // Pointer into buffer unsigned char *ptr; // Pointer into buffer
@ -586,6 +598,7 @@ get_char(_pdfio_token_t *tb) // I - Token buffer
} }
PDFIO_DEBUG("'\n"); PDFIO_DEBUG("'\n");
#endif // DEBUG #endif // DEBUG
#endif // 0
} }
// Return the next character... // Return the next character...

View File

@ -1,7 +1,7 @@
// //
// PDF value functions for PDFio. // 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 // Licensed under Apache License v2.0. See the file "LICENSE" for more
// information. // information.