CVE-2020-20740: Out-of-bounds Write (CWE-787)
value: PDFResurrect before 0.20 lack of header validation checks causes heap-buffer-overflow in pdf_get_version().
CWE description: The product writes data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 7.8
Published: 2020-11-20T19:15Z
Repository: https://github.com/enferex/pdfresurrect
Language: Other
Files changed: AUTHORS, pdf.c
Commit date: 2020-07-23 21:02:42 -0700
Commit message: Update header validation checks.

Thanks to yifengchen-cc for identifying this.

Diff: diff --git a/AUTHORS b/AUTHORS
index 72924d8..1433c91 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -22,5 +22,7 @@ rwhitworth: Reported and helped isolate bugs. Created initial .gitignore.
 carter-yagemann: Reported and helped isolate a memory issue.
 
 rootup: Reporting and helped isolate a memory issue.
 
 ZanderChang: Reported and identified bad code in kid page loading.
+
+yifengchen-cc: Reported a header parsing bug.
diff --git a/pdf.c b/pdf.c
index 03c674e..c4ed49b 100644
--- a/pdf.c
+++ b/pdf.c
@@ -174,34 +174,34 @@ void pdf_delete(pdf_t *pdf)
 }
 
 
 int pdf_is_pdf(FILE *fp)
 {
-    int   is_pdf;
     char *header;
+    if (!(header = get_header(fp)))
+      return 0;
 
-    header = get_header(fp);
-
-    if (header && strstr(header, "%PDF-"))
-      is_pdf = 1;
-    else 
-      is_pdf = 0;
-
+    /* First 1024 bytes of doc must be header (1.7 spec pg 1102) */
+    const char *c = strstr(header, "%PDF-");
+    const int is_pdf = c && ((c - header+strlen("%PDF-M.m")) < 1024);
     free(header);
     return is_pdf;
 }
 
 
 void pdf_get_version(FILE *fp, pdf_t *pdf)
 {
-    char *header, *c;
-
-    header = get_header(fp);
+    char *header = get_header(fp);
 
-    /* Locate version string start and make sure we dont go past header */
+    /* Locate version string start and make sure we dont go past header
+     * The format is %PDF-M.m, where 'M' is the major number and 'm' minor.
+     */
+    const char *c;
     if ((c = strstr(header, "%PDF-")) && 
-        (c + strlen("%PDF-M.m") + 2))
+        ((c + 6)[0] == '.') && // Separator
+        isdigit((c + 5)[0]) && // Major number
+        isdigit((c + 7)[0]))   // Minor number
     {
         pdf->pdf_major_version = atoi(c + strlen("%PDF-"));
         pdf->pdf_minor_version = atoi(c + strlen("%PDF-M."));
     }
 

Vulnerable code:     int   is_pdf;
    header = get_header(fp);

    if (header && strstr(header, "%PDF-"))
      is_pdf = 1;
    else 
      is_pdf = 0;

    char *header, *c;

    header = get_header(fp);
    /* Locate version string start and make sure we dont go past header */
        (c + strlen("%PDF-M.m") + 2))
Fixed code: 
yifengchen-cc: Reported a header parsing bug.
    if (!(header = get_header(fp)))
      return 0;
    /* First 1024 bytes of doc must be header (1.7 spec pg 1102) */
    const char *c = strstr(header, "%PDF-");
    const int is_pdf = c && ((c - header+strlen("%PDF-M.m")) < 1024);
    char *header = get_header(fp);
    /* Locate version string start and make sure we dont go past header
     * The format is %PDF-M.m, where 'M' is the major number and 'm' minor.
     */
    const char *c;
        ((c + 6)[0] == '.') && // Separator
        isdigit((c + 5)[0]) && // Major number
        isdigit((c + 7)[0]))   // Minor number