CVE-2021-23206: Out-of-bounds Write (CWE-787)
value: A flaw was found in htmldoc in v1.9.12 and prior. A stack buffer overflow in parse_table() in ps-pdf.cxx may lead to execute arbitrary code and denial of service.
CWE description: The product writes data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 7.8
Published: 2022-03-02T23:15Z
Repository: https://github.com/michaelrsweet/htmldoc
Language: Markdown
Files changed: CHANGES.md, htmldoc/ps-pdf.cxx
Commit date: 2021-04-01 08:21:57 -0400
Commit message: Fix crash bugs with bogus table attributes (Issue #416)

Diff: diff --git a/CHANGES.md b/CHANGES.md
index 866b0a53..faeff3b4 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,9 +1,9 @@
 # Changes in HTMLDOC v1.9.12
 
 - Fixed a crash bug with "data:" URIs and EPUB output (Issue #410)
-- Fixed a crach bug with bogus table attributes (Issue #417)
+- Fixed crash bugs with bogus table attributes (Issue #416, Issue #417)
 - Fixed a crash bug with malformed URIs (Issue #418)
 - Fixed a crash bug with malformed GIF files (Issue #423)
 - Fixed some issues reported by Coverity.
 
 
diff --git a/htmldoc/ps-pdf.cxx b/htmldoc/ps-pdf.cxx
index b8aeb08b..85257e5f 100644
--- a/htmldoc/ps-pdf.cxx
+++ b/htmldoc/ps-pdf.cxx
@@ -5733,11 +5733,11 @@ render_table_row(hdtable_t &table,
     if (table.row_spans[col] == 0)
     {
       if ((var = htmlGetVariable(cells[row][col], (uchar *)"ROWSPAN")) != NULL)
         table.row_spans[col] = atoi((char *)var);
 
-      if (table.row_spans[col] == 1)
+      if (table.row_spans[col] <= 1)
         table.row_spans[col] = 0;
 
       if (table.row_spans[col] > (table.num_rows - row))
         table.row_spans[col] = table.num_rows - row;
 
@@ -6568,19 +6568,24 @@ parse_table(tree_t *t,			// I - Tree to parse
 
         if (tempcol->markup == MARKUP_TD || tempcol->markup == MARKUP_TH)
         {
 	  // Handle colspan and rowspan stuff...
           if ((var = htmlGetVariable(tempcol, (uchar *)"COLSPAN")) != NULL)
-            colspan = atoi((char *)var);
+          {
+            if ((colspan = atoi((char *)var)) < 1)
+              colspan = 1;
+            else if (colspan > (MAX_COLUMNS - col))
+              colspan = MAX_COLUMNS - col;
+          }
           else
             colspan = 1;
 
           if ((var = htmlGetVariable(tempcol, (uchar *)"ROWSPAN")) != NULL)
 	  {
             table.row_spans[col] = atoi((char *)var);
 
-	    if (table.row_spans[col] == 1)
+	    if (table.row_spans[col] <= 1)
 	      table.row_spans[col] = 0;
 
 	    for (tcol = 1; tcol < colspan; tcol ++)
               table.row_spans[col + tcol] = table.row_spans[col];
           }
@@ -6598,10 +6603,15 @@ parse_table(tree_t *t,			// I - Tree to parse
 	    }
 	    else
 	    {
               col_width -= 2.0 * table.cellpadding;
 	    }
+
+	    if (col_width <= 0.0f)
+	      col_width = 0.0f;
+	    else if (col_width > PageWidth)
+	      col_width = PageWidth;
 	  }
 	  else
 	    col_width = 0.0f;
 
           tempcol->height = col_height;

Vulnerable code: - Fixed a crach bug with bogus table attributes (Issue #417)
      if (table.row_spans[col] == 1)
            colspan = atoi((char *)var);
	    if (table.row_spans[col] == 1)
Fixed code: - Fixed crash bugs with bogus table attributes (Issue #416, Issue #417)
      if (table.row_spans[col] <= 1)
          {
            if ((colspan = atoi((char *)var)) < 1)
              colspan = 1;
            else if (colspan > (MAX_COLUMNS - col))
              colspan = MAX_COLUMNS - col;
          }
	    if (table.row_spans[col] <= 1)

	    if (col_width <= 0.0f)
	      col_width = 0.0f;
	    else if (col_width > PageWidth)
	      col_width = PageWidth;