CVE-2019-14934 (published 2019-08-11T22:15Z)

An issue was discovered in PDFResurrect before 0.18. pdf_load_pages_kids in pdf.c doesn't validate a certain size value, which leads to a malloc failure and out-of-bounds write.

Severity: MEDIUM
CVSS v2 base score: 6.8 (AV:N/AC:M/Au:N/C:P/I:P/A:P)
CVSS v3 base score: 7.8, HIGH (CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-787
cwe_name: Out-of-bounds Write
description: The product writes data past the end, or before the beginning, of the intended buffer.
extended_description: 
            
            
             
			 
         
         

Fix information:
repo_url: https://github.com/enferex/pdfresurrect
commit_details: repo_url: https://github.com/enferex/pdfresurrect
author: Matt Davis
author_date: 2019-08-10 07:47:09-07:00
msg: Zero and sanity check all dynamic allocs.

This addresses the memory issues in Issue #6 expressed in
calloc_some.pdf and malloc_some.pdf
repository: repo_url: https://github.com/enferex/pdfresurrect
repo_name: enferex/pdfresurrect
description: Analyze and help extract older "hidden" versions of a pdf from the current pdf.
repo_language: C
owner: enferex
file_changes: filename: main.c
change_type: ModificationType.MODIFY
diff: @@ -72,7 +72,7 @@ static void write_version(
     /* Create file */
     if ((c = strstr(fname, ".pdf")))
       *c = '\0';
-    new_fname = malloc(strlen(fname) + strlen(dirname) + 16);
+    new_fname = safe_calloc(strlen(fname) + strlen(dirname) + 16);
     snprintf(new_fname, strlen(fname) + strlen(dirname) + 16,
              "%s/%s-version-%d.pdf", dirname, fname, xref->version);
 
@@ -213,6 +213,23 @@ static pdf_t *init_pdf(FILE *fp, const char *name)
 }
 
 
+void *safe_calloc(size_t size) {
+  void *addr;
+
+  if (!size)
+  {
+    ERR("Invalid allocation size.\n");
+    exit(EXIT_FAILURE);
+  }
+  if (!(addr = calloc(1, size)))
+  {
+      ERR("Failed to allocate requested number of bytes, out of memory?\n");
+      exit(EXIT_FAILURE);
+  }
+  return addr;
+}
+
+
 int main(int argc, char **argv)
 {
     int         i, n_valid, do_write, do_scrub;
@@ -295,7 +312,7 @@ int main(int argc, char **argv)
         if ((c = strrchr(name, '.')))
           *c = '\0';
 
-        dname = malloc(strlen(name) + 16);
+        dname = safe_calloc(strlen(name) + 16);
         sprintf(dname, "%s-versions", name);
         if (!(dir = opendir(dname)))
           mkdir(dname, S_IRWXU);

programming_language: C
filename: main.h
change_type: ModificationType.MODIFY
diff: @@ -40,5 +40,7 @@
 #define TAG "[pdfresurrect]"
 #define ERR(...) {fprintf(stderr, TAG" -- Error -- " __VA_ARGS__);}
 
+/* Returns a zero'd buffer of 'size' bytes or exits in failure. */
+extern void *safe_calloc(size_t bytes);
 
 #endif /* MAIN_H_INCLUDE */

programming_language: C
filename: pdf.c
change_type: ModificationType.MODIFY
diff: @@ -122,7 +122,7 @@ pdf_t *pdf_new(const char *name)
     const char *n;
     pdf_t      *pdf;
    
-    pdf = calloc(1, sizeof(pdf_t));
+    pdf = safe_calloc(sizeof(pdf_t));
 
     if (name)
     {
@@ -132,12 +132,12 @@ pdf_t *pdf_new(const char *name)
         else
           n = name;
 
-        pdf->name = malloc(strlen(n) + 1);
+        pdf->name = safe_calloc(strlen(n) + 1);
         strcpy(pdf->name, n);
     }
     else /* !name */
     {
-        pdf->name = malloc(strlen("Unknown") + 1);
+        pdf->name = safe_calloc(strlen("Unknown") + 1);
         strcpy(pdf->name, "Unknown");
     }
 
@@ -216,7 +216,7 @@ int pdf_load_xrefs(FILE *fp, pdf_t *pdf)
 
     /* Load in the start/end positions */
     fseek(fp, 0, SEEK_SET);
-    pdf->xrefs = calloc(1, sizeof(xref_t) * pdf->n_xrefs);
+    pdf->xrefs = safe_calloc(sizeof(xref_t) * pdf->n_xrefs);
     ver = 1;
     for (i=0; i<pdf->n_xrefs; i++)
     {
@@ -314,7 +314,7 @@ void pdf_load_pages_kids(FILE *fp, pdf_t *pdf)
 
             /* Get root catalog */
             sz = pdf->xrefs[i].end - ftell(fp);
-            buf = malloc(sz + 1);
+            buf = safe_calloc(sz + 1);
             SAFE_E(fread(buf, 1, sz, fp), sz, "Failed to load /Root.\n");
             buf[sz] = '\0';
             if (!(c = strstr(buf, "/Root")))
@@ -444,7 +444,7 @@ void pdf_summarize(
 
     if (name)
     {
-        dst_name = malloc(strlen(name) * 2 + 16);
+        dst_name = safe_calloc(strlen(name) * 2 + 16);
         sprintf(dst_name, "%s/%s", name, name);
 
         if ((c = strrchr(dst_name, '.')) && (strncmp(c, ".pdf", 4) == 0))
@@ -643,7 +643,7 @@ static void load_xref_from_plaintext(FILE *fp, xref_t *xref)
 
     SAFE_E(fread(buf, 1, 21, fp), 21, "Failed to load entry Size string.\n");
     xref->n_entries = atoi(buf + strlen("ize "));
-    xref->entries = calloc(1, xref->n_entries * sizeof(struct _xref_entry));
+    xref->entries = safe_calloc(xref->n_entries * sizeof(struct _xref_entry));
 
     /* Load entry data */
     obj_id = 0;
@@ -810,7 +810,7 @@ static pdf_creator_t *new_creator(int *n_elements)
         {"Trapped",      ""},
     };
 
-    daddy = malloc(sizeof(creator_template));
+    daddy = safe_calloc(sizeof(creator_template));
     memcpy(daddy, creator_template, sizeof(creator_template));
 
     if (n_elements)
@@ -1099,8 +1099,7 @@ static char *get_object(
     obj_sz = 0;    /* Bytes in object */
     total_sz = 0;  /* Bytes read in   */
     n_blks = 1;
-    data = malloc(blk_sz * n_blks);
-    memset(data, 0, blk_sz * n_blks);
+    data = safe_calloc(blk_sz * n_blks);
 
     /* Suck in data */
     stream = 0;
@@ -1266,18 +1265,12 @@ static int get_page(int obj_id, const xref_t *xref)
 
 static char *get_header(FILE *fp)
 {
-    long start;
-
     /* First 1024 bytes of doc must be header (1.7 spec pg 1102) */
-    char *header;
-
-    header = calloc(1, 1024);
-    
-    start = ftell(fp);
+    char *header = safe_calloc(1024);
+    long start = ftell(fp);
     fseek(fp, 0, SEEK_SET);
     SAFE_E(fread(header, 1, 1023, fp), 1023, "Failed to load PDF header.\n");
     fseek(fp, start, SEEK_SET);
-    
     return header;
 }
 
@@ -1292,7 +1285,7 @@ static char *decode_text_string(const char *str, size_t str_len)
     /* Regular encoding */
     if (str[0] == '(')
     {
-        ascii = malloc(strlen(str) + 1);
+        ascii = safe_calloc(strlen(str) + 1);
         strncpy(ascii, str, strlen(str) + 1);
         return ascii;
     }
@@ -1314,7 +1307,7 @@ static char *decode_text_string(const char *str, size_t str_len)
       return NULL;
 
     /* Now decode as hex */
-    ascii = malloc(str_len);
+    ascii = safe_calloc(str_len);
     for ( ; idx<str_len; ++idx)
     {
         hex_buf[0] = str[idx++];

programming_language: C