diff options
author | Ken Sharp <ken.sharp@artifex.com> | 2022-08-11 19:16:59 +0100 |
---|---|---|
committer | Ken Sharp <ken.sharp@artifex.com> | 2022-08-11 19:32:11 +0100 |
commit | 30360aca75851e6877765a7b11963cb5c8f5b0d1 (patch) | |
tree | db03cabcd1204c45cd9a372e68ead69c5a47718a | |
parent | 9c7e1ec6a88a53873fd44de672f8bade0bf539d1 (diff) | |
download | ghostpdl-30360aca75851e6877765a7b11963cb5c8f5b0d1.tar.gz |
GhostPDF - Don't follow Parent key in Pages dictionary for Resources
When finding a named resource we check the current dictionary (which
may be a Pattern, Xobject, Page etc) and if we fail to find the resource
we look to see if the dictionary has a Parent entry (for Resource
inheritance) and look in that.
If the current dictionary is of /Type /Page, don't do that, because the
Parent will be the Pages tree and we can end up creating a cyclic
reference between the Pages tree and the page dictionary.
Showed up as a memory leak (because we failed to free the page
dictionary) with a few OSS-fuzz files.
-rw-r--r-- | pdf/pdf_doc.c | 49 |
1 files changed, 31 insertions, 18 deletions
diff --git a/pdf/pdf_doc.c b/pdf/pdf_doc.c index 8c4f64d3f..fb5d4f491 100644 --- a/pdf/pdf_doc.c +++ b/pdf/pdf_doc.c @@ -823,12 +823,15 @@ int pdfi_find_resource(pdf_context *ctx, unsigned char *Type, pdf_name *name, { pdf_dict *typedict = NULL; pdf_dict *Parent = NULL; + pdf_name *n = NULL; int code; *o = NULL; /* Check the provided dict, stream_dict can be NULL if we are trying to find a Default* ColorSpace */ if (dict != NULL) { + bool deref_parent = true; + code = pdfi_resource_knownget_typedict(ctx, Type, dict, &typedict); if (code < 0) goto exit; @@ -839,30 +842,40 @@ int pdfi_find_resource(pdf_context *ctx, unsigned char *Type, pdf_name *name, } /* Check the Parents, if any */ - code = pdfi_dict_knownget_type(ctx, dict, "Parent", PDF_DICT, (pdf_obj **)&Parent); - if (code < 0) - goto exit; - if (code > 0) { - if (ctx->page.CurrentPageDict != NULL && Parent->object_num != ctx->page.CurrentPageDict->object_num) { - if (pdfi_loop_detector_check_object(ctx, Parent->object_num) == true) - return_error(gs_error_circular_reference); + /* If the current dictionary is a Page dictionary, do NOT dereference it's Parent, as that + * will be the Pages tree, and we will end up with circular references, causing a memory leak. + */ + if (pdfi_dict_knownget_type(ctx, dict, "Type", PDF_NAME, (pdf_obj **)&n)) { + if (pdfi_name_is(n, "Page")) + deref_parent = false; + pdfi_countdown(n); + } - code = pdfi_loop_detector_mark(ctx); - if (code < 0) - return code; + if (deref_parent) { + code = pdfi_dict_knownget_type(ctx, dict, "Parent", PDF_DICT, (pdf_obj **)&Parent); + if (code < 0) + goto exit; + if (code > 0) { + if (ctx->page.CurrentPageDict != NULL && Parent->object_num != ctx->page.CurrentPageDict->object_num) { + if (pdfi_loop_detector_check_object(ctx, Parent->object_num) == true) + return_error(gs_error_circular_reference); + + code = pdfi_loop_detector_mark(ctx); + if (code < 0) + return code; - code = pdfi_loop_detector_add_object(ctx, dict->object_num); - if (code < 0) { + code = pdfi_loop_detector_add_object(ctx, dict->object_num); + if (code < 0) { + (void)pdfi_loop_detector_cleartomark(ctx); + return code; + } + code = pdfi_find_resource(ctx, Type, name, Parent, page_dict, o); (void)pdfi_loop_detector_cleartomark(ctx); - return code; + if (code != gs_error_undefined) + goto exit; } - code = pdfi_find_resource(ctx, Type, name, Parent, page_dict, o); - (void)pdfi_loop_detector_cleartomark(ctx); - if (code != gs_error_undefined) - goto exit; } } - pdfi_countdown(typedict); typedict = NULL; } |