Fix CVE-2016-8674 (use-after-free in pdf_to_num()). https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-8674 https://security-tracker.debian.org/tracker/CVE-2016-8674 Patch copied from upstream source repository: http://git.ghostscript.com/?p=mupdf.git;h=1e03c06456d997435019fb3526fa2d4be7dbc6ec diff --git a/include/mupdf/pdf/document.h b/include/mupdf/pdf/document.h index aabf05f..0078c4a 100644 --- a/include/mupdf/pdf/document.h +++ b/include/mupdf/pdf/document.h @@ -269,6 +269,10 @@ struct pdf_document_s fz_hash_table *images; fz_hash_table *fonts; } resources; + + int orphans_max; + int orphans_count; + pdf_obj **orphans; }; /* diff --git a/include/mupdf/pdf/object.h b/include/mupdf/pdf/object.h index 5bc3dca..bf57455 100644 --- a/include/mupdf/pdf/object.h +++ b/include/mupdf/pdf/object.h @@ -110,6 +110,7 @@ pdf_obj *pdf_dict_gets(fz_context *ctx, pdf_obj *dict, const char *key); pdf_obj *pdf_dict_getsa(fz_context *ctx, pdf_obj *dict, const char *key, const char *abbrev); void pdf_dict_put(fz_context *ctx, pdf_obj *dict, pdf_obj *key, pdf_obj *val); void pdf_dict_put_drop(fz_context *ctx, pdf_obj *dict, pdf_obj *key, pdf_obj *val); +void pdf_dict_get_put_drop(fz_context *ctx, pdf_obj *dict, pdf_obj *key, pdf_obj *val, pdf_obj **old_val); void pdf_dict_puts(fz_context *ctx, pdf_obj *dict, const char *key, pdf_obj *val); void pdf_dict_puts_drop(fz_context *ctx, pdf_obj *dict, const char *key, pdf_obj *val); void pdf_dict_putp(fz_context *ctx, pdf_obj *dict, const char *path, pdf_obj *val); diff --git a/source/pdf/pdf-object.c b/source/pdf/pdf-object.c index b4e33f3..1c19ba4 100644 --- a/source/pdf/pdf-object.c +++ b/source/pdf/pdf-object.c @@ -1265,11 +1265,14 @@ pdf_dict_geta(fz_context *ctx, pdf_obj *obj, pdf_obj *key, pdf_obj *abbrev) return pdf_dict_get(ctx, obj, abbrev); } -void -pdf_dict_put(fz_context *ctx, pdf_obj *obj, pdf_obj *key, pdf_obj *val) +static void +pdf_dict_get_put(fz_context *ctx, pdf_obj *obj, pdf_obj *key, pdf_obj *val, pdf_obj **old_val) { int i; + if (old_val) + *old_val = NULL; + RESOLVE(obj); if (!OBJ_IS_DICT(obj)) fz_throw(ctx, FZ_ERROR_GENERIC, "not a dict (%s)", pdf_objkindstr(obj)); @@ -1295,7 +1298,10 @@ pdf_dict_put(fz_context *ctx, pdf_obj *obj, pdf_obj *key, pdf_obj *val) { pdf_obj *d = DICT(obj)->items[i].v; DICT(obj)->items[i].v = pdf_keep_obj(ctx, val); - pdf_drop_obj(ctx, d); + if (old_val) + *old_val = d; + else + pdf_drop_obj(ctx, d); } } else @@ -1316,10 +1322,27 @@ pdf_dict_put(fz_context *ctx, pdf_obj *obj, pdf_obj *key, pdf_obj *val) } void +pdf_dict_put(fz_context *ctx, pdf_obj *obj, pdf_obj *key, pdf_obj *val) +{ + pdf_dict_get_put(ctx, obj, key, val, NULL); +} + +void pdf_dict_put_drop(fz_context *ctx, pdf_obj *obj, pdf_obj *key, pdf_obj *val) { fz_try(ctx) - pdf_dict_put(ctx, obj, key, val); + pdf_dict_get_put(ctx, obj, key, val, NULL); + fz_always(ctx) + pdf_drop_obj(ctx, val); + fz_catch(ctx) + fz_rethrow(ctx); +} + +void +pdf_dict_get_put_drop(fz_context *ctx, pdf_obj *obj, pdf_obj *key, pdf_obj *val, pdf_obj **old_val) +{ + fz_try(ctx) + pdf_dict_get_put(ctx, obj, key, val, old_val); fz_always(ctx) pdf_drop_obj(ctx, val); fz_catch(ctx) diff --git a/source/pdf/pdf-repair.c b/source/pdf/pdf-repair.c index 690bf15..167f609 100644 --- a/source/pdf/pdf-repair.c +++ b/source/pdf/pdf-repair.c @@ -260,6 +260,27 @@ pdf_repair_obj_stm(fz_context *ctx, pdf_document *doc, int stm_num) } } +static void +orphan_object(fz_context *ctx, pdf_document *doc, pdf_obj *obj) +{ + if (doc->orphans_count == doc->orphans_max) + { + int new_max = (doc->orphans_max ? doc->orphans_max*2 : 32); + + fz_try(ctx) + { + doc->orphans = fz_resize_array(ctx, doc->orphans, new_max, sizeof(*doc->orphans)); + doc->orphans_max = new_max; + } + fz_catch(ctx) + { + pdf_drop_obj(ctx, obj); + fz_rethrow(ctx); + } + } + doc->orphans[doc->orphans_count++] = obj; +} + void pdf_repair_xref(fz_context *ctx, pdf_document *doc) { @@ -528,12 +549,13 @@ pdf_repair_xref(fz_context *ctx, pdf_document *doc) /* correct stream length for unencrypted documents */ if (!encrypt && list[i].stm_len >= 0) { + pdf_obj *old_obj = NULL; dict = pdf_load_object(ctx, doc, list[i].num); length = pdf_new_int(ctx, doc, list[i].stm_len); - pdf_dict_put(ctx, dict, PDF_NAME_Length, length); - pdf_drop_obj(ctx, length); - + pdf_dict_get_put_drop(ctx, dict, PDF_NAME_Length, length, &old_obj); + if (old_obj) + orphan_object(ctx, doc, old_obj); pdf_drop_obj(ctx, dict); } } diff --git a/source/pdf/pdf-xref.c b/source/pdf/pdf-xref.c index 7d21775..0cf20d4 100644 --- a/source/pdf/pdf-xref.c +++ b/source/pdf/pdf-xref.c @@ -1620,6 +1620,12 @@ pdf_drop_document_imp(fz_context *ctx, pdf_document *doc) pdf_drop_resource_tables(ctx, doc); + for (i = 0; i < doc->orphans_count; i++) + { + pdf_drop_obj(ctx, doc->orphans[i]); + } + fz_free(ctx, doc->orphans); + fz_free(ctx, doc); } fz_always(ctx) -- 2.9.1