diff --git a/CMakeLists.txt b/CMakeLists.txt index 42fefcee6..135932666 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ project(cmark-gfm) set(PROJECT_VERSION_MAJOR 0) set(PROJECT_VERSION_MINOR 29) set(PROJECT_VERSION_PATCH 0) -set(PROJECT_VERSION_GFM 5) +set(PROJECT_VERSION_GFM 6) set(PROJECT_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}.gfm.${PROJECT_VERSION_GFM}) include("FindAsan.cmake") diff --git a/changelog.txt b/changelog.txt index 3ecf949bc..05cab2ac0 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,6 @@ +[0.29.0.gfm.6] + * Fixed polynomial time complexity DoS vulnerability in autolink extension + [0.29.0.gfm.5] * Added xmpp: and mailto: support to the autolink extension diff --git a/src/inlines.c b/src/inlines.c index 4a118a636..3cd3bc3d0 100644 --- a/src/inlines.c +++ b/src/inlines.c @@ -41,6 +41,8 @@ typedef struct bracket { bool image; bool active; bool bracket_after; + bool in_bracket_image0; + bool in_bracket_image1; } bracket; typedef struct subject{ @@ -516,6 +518,8 @@ static void push_bracket(subject *subj, bool image, cmark_node *inl_text) { bracket *b = (bracket *)subj->mem->calloc(1, sizeof(bracket)); if (subj->last_bracket != NULL) { subj->last_bracket->bracket_after = true; + b->in_bracket_image0 = subj->last_bracket->in_bracket_image0; + b->in_bracket_image1 = subj->last_bracket->in_bracket_image1; } b->image = image; b->active = true; @@ -524,6 +528,11 @@ static void push_bracket(subject *subj, bool image, cmark_node *inl_text) { b->previous_delimiter = subj->last_delim; b->position = subj->pos; b->bracket_after = false; + if (image) { + b->in_bracket_image1 = true; + } else { + b->in_bracket_image0 = true; + } subj->last_bracket = b; } @@ -1254,6 +1263,17 @@ static cmark_node *handle_close_bracket(cmark_parser *parser, subject *subj) { } opener = opener->previous; } + bool in_bracket_image1 = false; + if (opener) { + in_bracket_image1 = opener->in_bracket_image1; + } + bracket *opener2 = subj->last_bracket; + while (opener2 != opener) { + if (opener2->image) { + opener2->in_bracket_image1 = in_bracket_image1; + } + opener2 = opener2->previous; + } } return NULL; @@ -1662,10 +1682,15 @@ cmark_chunk *cmark_inline_parser_get_chunk(cmark_inline_parser *parser) { } int cmark_inline_parser_in_bracket(cmark_inline_parser *parser, int image) { - for (bracket *b = parser->last_bracket; b; b = b->previous) - if (b->active && b->image == (image != 0)) - return 1; - return 0; + bracket *b = parser->last_bracket; + if (!b) { + return 0; + } + if (image != 0) { + return b->in_bracket_image1; + } else { + return b->in_bracket_image0; + } } void cmark_node_unput(cmark_node *node, int n) {