summaryrefslogtreecommitdiff
path: root/source/pdf/pdf-write.c
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2017-11-07 19:21:58 +0000
committerRobin Watts <robin.watts@artifex.com>2017-11-08 09:36:23 +0000
commit520cc26d18c9ee245b56e9e91f9d4fcae02be5f0 (patch)
treecbc92b8a9c99bf20360b39c1a30fd17218523275 /source/pdf/pdf-write.c
parentd18bc728e46c5a5708f14d27c2b6c44e1d0c3232 (diff)
downloadmupdf-520cc26d18c9ee245b56e9e91f9d4fcae02be5f0.tar.xz
Bug 689699: Avoid buffer overrun.
When cleaning a pdf file, various lists (of pdf_xref_len length) are defined early on. If we trigger a repair during the clean, this can cause pdf_xref_len to increase causing an overrun. Fix this by watching for changes in the length, and checking accesses to the list for validity. This also appears to fix bugs 698700-698703.
Diffstat (limited to 'source/pdf/pdf-write.c')
-rw-r--r--source/pdf/pdf-write.c56
1 files changed, 43 insertions, 13 deletions
diff --git a/source/pdf/pdf-write.c b/source/pdf/pdf-write.c
index c9f70b0a..b3d59db6 100644
--- a/source/pdf/pdf-write.c
+++ b/source/pdf/pdf-write.c
@@ -66,6 +66,7 @@ struct pdf_write_state_s
int do_linear;
int do_clean;
+ int list_len;
int *use_list;
int64_t *ofs_list;
int *gen_list;
@@ -627,13 +628,35 @@ static int markobj(fz_context *ctx, pdf_document *doc, pdf_write_state *opts, pd
return 0;
}
+static void
+expand_lists(fz_context *ctx, pdf_write_state *opts, int num)
+{
+ int i;
+
+ num++;
+ opts->use_list = fz_resize_array(ctx, opts->use_list, num, sizeof(*opts->use_list));
+ opts->ofs_list = fz_resize_array(ctx, opts->ofs_list, num, sizeof(*opts->ofs_list));
+ opts->gen_list = fz_resize_array(ctx, opts->gen_list, num, sizeof(*opts->gen_list));
+ opts->renumber_map = fz_resize_array(ctx, opts->renumber_map, num, sizeof(*opts->renumber_map));
+ opts->rev_renumber_map = fz_resize_array(ctx, opts->rev_renumber_map, num, sizeof(*opts->rev_renumber_map));
+
+ for (i = opts->list_len; i < num; i++)
+ {
+ opts->use_list[i] = 0;
+ opts->ofs_list[i] = 0;
+ opts->renumber_map[i] = i;
+ opts->rev_renumber_map[i] = i;
+ }
+ opts->list_len = num;
+}
+
/*
* Scan for and remove duplicate objects (slow)
*/
static void removeduplicateobjs(fz_context *ctx, pdf_document *doc, pdf_write_state *opts)
{
- int num, other;
+ int num, other, max_num;
int xref_len = pdf_xref_len(ctx, doc);
for (num = 1; num < xref_len; num++)
@@ -713,6 +736,9 @@ static void removeduplicateobjs(fz_context *ctx, pdf_document *doc, pdf_write_st
/* Keep the lowest numbered object */
newnum = fz_mini(num, other);
+ max_num = fz_maxi(num, other);
+ if (max_num >= opts->list_len)
+ expand_lists(ctx, opts, max_num);
opts->renumber_map[num] = newnum;
opts->renumber_map[other] = newnum;
opts->rev_renumber_map[newnum] = num; /* Either will do */
@@ -742,6 +768,9 @@ static void compactxref(fz_context *ctx, pdf_document *doc, pdf_write_state *opt
* object ids be updated to reflect the compaction.
*/
+ if (xref_len > opts->list_len)
+ expand_lists(ctx, opts, xref_len-1);
+
newnum = 1;
for (num = 1; num < xref_len; num++)
{
@@ -2719,21 +2748,16 @@ static void initialise_write_state(fz_context *ctx, pdf_document *doc, const pdf
/* We deliberately make these arrays long enough to cope with
* 1 to n access rather than 0..n-1, and add space for 2 new
* extra entries that may be required for linearization. */
- opts->use_list = fz_malloc_array(ctx, xref_len + 3, sizeof(int));
- opts->ofs_list = fz_malloc_array(ctx, xref_len + 3, sizeof(int64_t));
- opts->gen_list = fz_calloc(ctx, xref_len + 3, sizeof(int));
- opts->renumber_map = fz_malloc_array(ctx, xref_len + 3, sizeof(int));
- opts->rev_renumber_map = fz_malloc_array(ctx, xref_len + 3, sizeof(int));
+ opts->list_len = 0;
+ opts->use_list = NULL;
+ opts->ofs_list = NULL;
+ opts->gen_list = NULL;
+ opts->renumber_map = NULL;
+ opts->rev_renumber_map = NULL;
opts->continue_on_error = in_opts->continue_on_error;
opts->errors = in_opts->errors;
- for (num = 0; num < xref_len; num++)
- {
- opts->use_list[num] = 0;
- opts->ofs_list[num] = 0;
- opts->renumber_map[num] = num;
- opts->rev_renumber_map[num] = num;
- }
+ expand_lists(ctx, opts, xref_len + 3);
}
/* Free the resources held by the dynamic write options */
@@ -2871,8 +2895,11 @@ do_pdf_save_document(fz_context *ctx, pdf_document *doc, pdf_write_state *opts,
if (opts->do_garbage >= 1 || opts->do_linear)
(void)markobj(ctx, doc, opts, pdf_trailer(ctx, doc));
else
+ {
+ xref_len = pdf_xref_len(ctx, doc); /* May have changed due to repair */
for (num = 0; num < xref_len; num++)
opts->use_list[num] = 1;
+ }
/* Coalesce and renumber duplicate objects */
if (opts->do_garbage >= 3)
@@ -2888,8 +2915,11 @@ do_pdf_save_document(fz_context *ctx, pdf_document *doc, pdf_write_state *opts,
/* Truncate the xref after compacting and renumbering */
if ((opts->do_garbage >= 2 || opts->do_linear) && !opts->do_incremental)
+ {
+ xref_len = pdf_xref_len(ctx, doc); /* May have changed due to repair */
while (xref_len > 0 && !opts->use_list[xref_len-1])
xref_len--;
+ }
if (opts->do_linear)
linearize(ctx, doc, opts);