cmark

My personal build of CMark ✏️

Commit
f8737b1c82981624b3263224dbf92fa6627f7205
Parent
09d96cd0b6f352227f741c4fc9b0d82cbefcc012
Author
John MacFarlane <jgm@berkeley.edu>
Date

latex writer: fix memory overflow.

We got an array overflow in enumerated lists nested more than 10 deep with start number =/= 1.

Found by google/oss-fuzz. https://oss-fuzz.com/v2/testcase-detail/5546760854306816

This commit also ensures that we don't try to set `enum_` counters that aren't defined by LaTeX (generally up to enumv).

Closes #210.

Diffstat

1 file changed, 19 insertions, 9 deletions

Status File Name N° Changes Insertions Deletions
Modified src/latex.c 28 19 9
diff --git a/src/latex.c b/src/latex.c
@@ -220,11 +220,10 @@ static int S_get_enumlevel(cmark_node *node) {
 static int S_render_node(cmark_renderer *renderer, cmark_node *node,
                          cmark_event_type ev_type, int options) {
   int list_number;
+  int enumlevel;
   char list_number_string[LIST_NUMBER_STRING_SIZE];
   bool entering = (ev_type == CMARK_EVENT_ENTER);
   cmark_list_type list_type;
-  const char *roman_numerals[] = {"",   "i",   "ii",   "iii", "iv", "v",
-                                  "vi", "vii", "viii", "ix",  "x"};
   bool allow_wrap = renderer->width > 0 && !(CMARK_OPT_NOBREAKS & options);
 
   // avoid warning about unused parameter:
@@ -253,13 +252,24 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
       CR();
       list_number = cmark_node_get_list_start(node);
       if (list_number > 1) {
-        snprintf(list_number_string, LIST_NUMBER_STRING_SIZE, "%d",
-                 list_number);
-        LIT("\\setcounter{enum");
-        LIT((char *)roman_numerals[S_get_enumlevel(node)]);
-        LIT("}{");
-        OUT(list_number_string, false, NORMAL);
-        LIT("}");
+	enumlevel = S_get_enumlevel(node);
+	// latex normally supports only five levels
+	if (enumlevel >= 1 && enumlevel <= 5) {
+          snprintf(list_number_string, LIST_NUMBER_STRING_SIZE, "%d",
+                   list_number);
+          LIT("\\setcounter{enum");
+          switch(enumlevel) {
+	  case 1: LIT("i"); break;
+	  case 2: LIT("ii"); break;
+	  case 3: LIT("iii"); break;
+	  case 4: LIT("iv"); break;
+	  case 5: LIT("v"); break;
+	  default: LIT("i"); break;
+	  }
+          LIT("}{");
+          OUT(list_number_string, false, NORMAL);
+          LIT("}");
+	}
         CR();
       }
     } else {