Skip to content

Commit

Permalink
Merge pull request from GHSA-mc3g-88wq-6f4x
Browse files Browse the repository at this point in the history
0.28.3.gfm.21 patch
  • Loading branch information
phillmv authored Mar 3, 2022
2 parents 3785191 + 6cad5de commit 6fc5672
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 4 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ set(PROJECT_NAME "cmark-gfm")
set(PROJECT_VERSION_MAJOR 0)
set(PROJECT_VERSION_MINOR 28)
set(PROJECT_VERSION_PATCH 3)
set(PROJECT_VERSION_GFM 20)
set(PROJECT_VERSION_GFM 21)
set(PROJECT_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}.gfm.${PROJECT_VERSION_GFM} )

option(CMARK_TESTS "Build cmark-gfm tests and enable testing" ON)
Expand Down
3 changes: 3 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[0.28.3.gfm.21]
* Fixed heap memory corruption vulnerabiliy via integer overflow per https://github.com/github/cmark-gfm/security/advisories/GHSA-mc3g-88wq-6f4x

[0.28.3.gfm.20]

* Add tasklist extension implementation (Watson1978, #94).
Expand Down
31 changes: 28 additions & 3 deletions extensions/table.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ static table_row *row_from_string(cmark_syntax_extension *self,
int len) {
table_row *row = NULL;
bufsize_t cell_matched = 1, pipe_matched = 1, offset;
int int_overflow_abort = 0;

row = (table_row *)parser->mem->calloc(1, sizeof(table_row));
row->n_columns = 0;
Expand All @@ -141,6 +142,12 @@ static table_row *row_from_string(cmark_syntax_extension *self,
--cell->start_offset;
++cell->internal_offset;
}
// make sure we never wrap row->n_columns
// offset will != len and our exit will clean up as intended
if (row->n_columns == UINT16_MAX) {
int_overflow_abort = 1;
break;
}
row->n_columns += 1;
row->cells = cmark_llist_append(parser->mem, row->cells, cell);
}
Expand All @@ -153,7 +160,7 @@ static table_row *row_from_string(cmark_syntax_extension *self,
}
}

if (offset != len || !row->n_columns) {
if (offset != len || !row->n_columns || int_overflow_abort) {
free_table_row(parser->mem, row);
row = NULL;
}
Expand Down Expand Up @@ -194,6 +201,15 @@ static cmark_node *try_opening_table_header(cmark_syntax_extension *self,
input + cmark_parser_get_first_nonspace(parser),
len - cmark_parser_get_first_nonspace(parser));

if (!marker_row) {
// these calls are essentially moot
// but matching error handling style of project
free_table_row(parser->mem, marker_row);
cmark_arena_pop();
return parent_container;
}

// assert may be optimized out, don't rely on it for security boundaries
assert(marker_row);

if (header_row->n_columns != marker_row->n_columns) {
Expand All @@ -211,7 +227,8 @@ static cmark_node *try_opening_table_header(cmark_syntax_extension *self,
len - cmark_parser_get_first_nonspace(parser));
}

if (!cmark_node_set_type(parent_container, CMARK_NODE_TABLE)) {
// row_from_string can return NULL, add additional check to ensure n_columns match
if (!marker_row || !header_row || header_row->n_columns != marker_row->n_columns || !cmark_node_set_type(parent_container, CMARK_NODE_TABLE)) {
free_table_row(parser->mem, header_row);
free_table_row(parser->mem, marker_row);
return parent_container;
Expand All @@ -223,8 +240,10 @@ static cmark_node *try_opening_table_header(cmark_syntax_extension *self,

set_n_table_columns(parent_container, header_row->n_columns);

// allocate alignments based on marker_row->n_columns
// since we populate the alignments array based on marker_row->cells
uint8_t *alignments =
(uint8_t *)parser->mem->calloc(header_row->n_columns, sizeof(uint8_t));
(uint8_t *)parser->mem->calloc(marker_row->n_columns, sizeof(uint8_t));
cmark_llist *it = marker_row->cells;
for (i = 0; it; it = it->next, ++i) {
node_cell *node = (node_cell *)it->data;
Expand Down Expand Up @@ -293,6 +312,12 @@ static cmark_node *try_opening_table_row(cmark_syntax_extension *self,
row = row_from_string(self, parser, input + cmark_parser_get_first_nonspace(parser),
len - cmark_parser_get_first_nonspace(parser));

if (!row) {
// clean up the dangling node
cmark_node_free(table_row_block);
return NULL;
}

{
cmark_llist *tmp;
int i, table_columns = get_n_table_columns(parent_container);
Expand Down

0 comments on commit 6fc5672

Please sign in to comment.