1*4882a593SmuzhiyunFrom fdf78a4877afa987ba646a8779b513f258e6d04c Mon Sep 17 00:00:00 2001 2*4882a593SmuzhiyunFrom: Michael Catanzaro <mcatanzaro@gnome.org> 3*4882a593SmuzhiyunDate: Fri, 31 Jul 2020 15:21:53 -0500 4*4882a593SmuzhiyunSubject: [PATCH] libcroco: Limit recursion in block and any productions 5*4882a593Smuzhiyun 6*4882a593Smuzhiyun (CVE-2020-12825) 7*4882a593Smuzhiyun 8*4882a593SmuzhiyunIf we don't have any limits, we can recurse forever and overflow the 9*4882a593Smuzhiyunstack. 10*4882a593Smuzhiyun 11*4882a593SmuzhiyunFixes #8 12*4882a593SmuzhiyunThis is per https://gitlab.gnome.org/Archive/libcroco/-/issues/8 13*4882a593Smuzhiyun 14*4882a593Smuzhiyunhttps://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1404 15*4882a593Smuzhiyun 16*4882a593SmuzhiyunCVE: CVE-2020-12825 17*4882a593SmuzhiyunUpstream-Status: Backport [https://gitlab.gnome.org/Archive/libcroco/-/commit/6eb257e5c731c691eb137fca94e916ca73941a5a] 18*4882a593SmuzhiyunComment: No refreshing changes done. 19*4882a593SmuzhiyunSigned-off-by: Saloni Jain <Saloni.Jain@kpit.com> 20*4882a593Smuzhiyun 21*4882a593Smuzhiyun--- 22*4882a593Smuzhiyun src/cr-parser.c | 44 +++++++++++++++++++++++++++++--------------- 23*4882a593Smuzhiyun 1 file changed, 29 insertions(+), 15 deletions(-) 24*4882a593Smuzhiyun 25*4882a593Smuzhiyundiff --git a/src/cr-parser.c b/src/cr-parser.c 26*4882a593Smuzhiyunindex 18c9a01..f4a62e3 100644 27*4882a593Smuzhiyun--- a/src/cr-parser.c 28*4882a593Smuzhiyun+++ b/src/cr-parser.c 29*4882a593Smuzhiyun@@ -136,6 +136,8 @@ struct _CRParserPriv { 30*4882a593Smuzhiyun 31*4882a593Smuzhiyun #define CHARS_TAB_SIZE 12 32*4882a593Smuzhiyun 33*4882a593Smuzhiyun+#define RECURSIVE_CALLERS_LIMIT 100 34*4882a593Smuzhiyun+ 35*4882a593Smuzhiyun /** 36*4882a593Smuzhiyun * IS_NUM: 37*4882a593Smuzhiyun *@a_char: the char to test. 38*4882a593Smuzhiyun@@ -344,9 +346,11 @@ static enum CRStatus cr_parser_parse_selector_core (CRParser * a_this); 39*4882a593Smuzhiyun 40*4882a593Smuzhiyun static enum CRStatus cr_parser_parse_declaration_core (CRParser * a_this); 41*4882a593Smuzhiyun 42*4882a593Smuzhiyun-static enum CRStatus cr_parser_parse_any_core (CRParser * a_this); 43*4882a593Smuzhiyun+static enum CRStatus cr_parser_parse_any_core (CRParser * a_this, 44*4882a593Smuzhiyun+ guint n_calls); 45*4882a593Smuzhiyun 46*4882a593Smuzhiyun-static enum CRStatus cr_parser_parse_block_core (CRParser * a_this); 47*4882a593Smuzhiyun+static enum CRStatus cr_parser_parse_block_core (CRParser * a_this, 48*4882a593Smuzhiyun+ guint n_calls); 49*4882a593Smuzhiyun 50*4882a593Smuzhiyun static enum CRStatus cr_parser_parse_value_core (CRParser * a_this); 51*4882a593Smuzhiyun 52*4882a593Smuzhiyun@@ -784,7 +788,7 @@ cr_parser_parse_atrule_core (CRParser * a_this) 53*4882a593Smuzhiyun cr_parser_try_to_skip_spaces_and_comments (a_this); 54*4882a593Smuzhiyun 55*4882a593Smuzhiyun do { 56*4882a593Smuzhiyun- status = cr_parser_parse_any_core (a_this); 57*4882a593Smuzhiyun+ status = cr_parser_parse_any_core (a_this, 0); 58*4882a593Smuzhiyun } while (status == CR_OK); 59*4882a593Smuzhiyun 60*4882a593Smuzhiyun status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, 61*4882a593Smuzhiyun@@ -795,7 +799,7 @@ cr_parser_parse_atrule_core (CRParser * a_this) 62*4882a593Smuzhiyun cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, 63*4882a593Smuzhiyun token); 64*4882a593Smuzhiyun token = NULL; 65*4882a593Smuzhiyun- status = cr_parser_parse_block_core (a_this); 66*4882a593Smuzhiyun+ status = cr_parser_parse_block_core (a_this, 0); 67*4882a593Smuzhiyun CHECK_PARSING_STATUS (status, 68*4882a593Smuzhiyun FALSE); 69*4882a593Smuzhiyun goto done; 70*4882a593Smuzhiyun@@ -930,11 +934,11 @@ cr_parser_parse_selector_core (CRParser * a_this) 71*4882a593Smuzhiyun 72*4882a593Smuzhiyun RECORD_INITIAL_POS (a_this, &init_pos); 73*4882a593Smuzhiyun 74*4882a593Smuzhiyun- status = cr_parser_parse_any_core (a_this); 75*4882a593Smuzhiyun+ status = cr_parser_parse_any_core (a_this, 0); 76*4882a593Smuzhiyun CHECK_PARSING_STATUS (status, FALSE); 77*4882a593Smuzhiyun 78*4882a593Smuzhiyun do { 79*4882a593Smuzhiyun- status = cr_parser_parse_any_core (a_this); 80*4882a593Smuzhiyun+ status = cr_parser_parse_any_core (a_this, 0); 81*4882a593Smuzhiyun 82*4882a593Smuzhiyun } while (status == CR_OK); 83*4882a593Smuzhiyun 84*4882a593Smuzhiyun@@ -956,10 +960,12 @@ cr_parser_parse_selector_core (CRParser * a_this) 85*4882a593Smuzhiyun *in chapter 4.1 of the css2 spec. 86*4882a593Smuzhiyun *block ::= '{' S* [ any | block | ATKEYWORD S* | ';' ]* '}' S*; 87*4882a593Smuzhiyun *@param a_this the current instance of #CRParser. 88*4882a593Smuzhiyun+ *@param n_calls used to limit recursion depth 89*4882a593Smuzhiyun *FIXME: code this function. 90*4882a593Smuzhiyun */ 91*4882a593Smuzhiyun static enum CRStatus 92*4882a593Smuzhiyun-cr_parser_parse_block_core (CRParser * a_this) 93*4882a593Smuzhiyun+cr_parser_parse_block_core (CRParser * a_this, 94*4882a593Smuzhiyun+ guint n_calls) 95*4882a593Smuzhiyun { 96*4882a593Smuzhiyun CRToken *token = NULL; 97*4882a593Smuzhiyun CRInputPos init_pos; 98*4882a593Smuzhiyun@@ -967,6 +973,9 @@ cr_parser_parse_block_core (CRParser * a_this) 99*4882a593Smuzhiyun 100*4882a593Smuzhiyun g_return_val_if_fail (a_this && PRIVATE (a_this), CR_BAD_PARAM_ERROR); 101*4882a593Smuzhiyun 102*4882a593Smuzhiyun+ if (n_calls > RECURSIVE_CALLERS_LIMIT) 103*4882a593Smuzhiyun+ return CR_ERROR; 104*4882a593Smuzhiyun+ 105*4882a593Smuzhiyun RECORD_INITIAL_POS (a_this, &init_pos); 106*4882a593Smuzhiyun 107*4882a593Smuzhiyun status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token); 108*4882a593Smuzhiyun@@ -996,13 +1005,13 @@ cr_parser_parse_block_core (CRParser * a_this) 109*4882a593Smuzhiyun } else if (token->type == CBO_TK) { 110*4882a593Smuzhiyun cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); 111*4882a593Smuzhiyun token = NULL; 112*4882a593Smuzhiyun- status = cr_parser_parse_block_core (a_this); 113*4882a593Smuzhiyun+ status = cr_parser_parse_block_core (a_this, n_calls + 1); 114*4882a593Smuzhiyun CHECK_PARSING_STATUS (status, FALSE); 115*4882a593Smuzhiyun goto parse_block_content; 116*4882a593Smuzhiyun } else { 117*4882a593Smuzhiyun cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, token); 118*4882a593Smuzhiyun token = NULL; 119*4882a593Smuzhiyun- status = cr_parser_parse_any_core (a_this); 120*4882a593Smuzhiyun+ status = cr_parser_parse_any_core (a_this, n_calls + 1); 121*4882a593Smuzhiyun CHECK_PARSING_STATUS (status, FALSE); 122*4882a593Smuzhiyun goto parse_block_content; 123*4882a593Smuzhiyun } 124*4882a593Smuzhiyun@@ -1109,7 +1118,7 @@ cr_parser_parse_value_core (CRParser * a_this) 125*4882a593Smuzhiyun status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, 126*4882a593Smuzhiyun token); 127*4882a593Smuzhiyun token = NULL; 128*4882a593Smuzhiyun- status = cr_parser_parse_block_core (a_this); 129*4882a593Smuzhiyun+ status = cr_parser_parse_block_core (a_this, 0); 130*4882a593Smuzhiyun CHECK_PARSING_STATUS (status, FALSE); 131*4882a593Smuzhiyun ref++; 132*4882a593Smuzhiyun goto continue_parsing; 133*4882a593Smuzhiyun@@ -1123,7 +1132,7 @@ cr_parser_parse_value_core (CRParser * a_this) 134*4882a593Smuzhiyun status = cr_tknzr_unget_token (PRIVATE (a_this)->tknzr, 135*4882a593Smuzhiyun token); 136*4882a593Smuzhiyun token = NULL; 137*4882a593Smuzhiyun- status = cr_parser_parse_any_core (a_this); 138*4882a593Smuzhiyun+ status = cr_parser_parse_any_core (a_this, 0); 139*4882a593Smuzhiyun if (status == CR_OK) { 140*4882a593Smuzhiyun ref++; 141*4882a593Smuzhiyun goto continue_parsing; 142*4882a593Smuzhiyun@@ -1162,10 +1171,12 @@ cr_parser_parse_value_core (CRParser * a_this) 143*4882a593Smuzhiyun * | FUNCTION | DASHMATCH | '(' any* ')' | '[' any* ']' ] S*; 144*4882a593Smuzhiyun * 145*4882a593Smuzhiyun *@param a_this the current instance of #CRParser. 146*4882a593Smuzhiyun+ *@param n_calls used to limit recursion depth 147*4882a593Smuzhiyun *@return CR_OK upon successfull completion, an error code otherwise. 148*4882a593Smuzhiyun */ 149*4882a593Smuzhiyun static enum CRStatus 150*4882a593Smuzhiyun-cr_parser_parse_any_core (CRParser * a_this) 151*4882a593Smuzhiyun+cr_parser_parse_any_core (CRParser * a_this, 152*4882a593Smuzhiyun+ guint n_calls) 153*4882a593Smuzhiyun { 154*4882a593Smuzhiyun CRToken *token1 = NULL, 155*4882a593Smuzhiyun *token2 = NULL; 156*4882a593Smuzhiyun@@ -1174,6 +1185,9 @@ cr_parser_parse_any_core (CRParser * a_this) 157*4882a593Smuzhiyun 158*4882a593Smuzhiyun g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR); 159*4882a593Smuzhiyun 160*4882a593Smuzhiyun+ if (n_calls > RECURSIVE_CALLERS_LIMIT) 161*4882a593Smuzhiyun+ return CR_ERROR; 162*4882a593Smuzhiyun+ 163*4882a593Smuzhiyun RECORD_INITIAL_POS (a_this, &init_pos); 164*4882a593Smuzhiyun 165*4882a593Smuzhiyun status = cr_tknzr_get_next_token (PRIVATE (a_this)->tknzr, &token1); 166*4882a593Smuzhiyun@@ -1212,7 +1226,7 @@ cr_parser_parse_any_core (CRParser * a_this) 167*4882a593Smuzhiyun *We consider parameter as being an "any*" production. 168*4882a593Smuzhiyun */ 169*4882a593Smuzhiyun do { 170*4882a593Smuzhiyun- status = cr_parser_parse_any_core (a_this); 171*4882a593Smuzhiyun+ status = cr_parser_parse_any_core (a_this, n_calls + 1); 172*4882a593Smuzhiyun } while (status == CR_OK); 173*4882a593Smuzhiyun 174*4882a593Smuzhiyun ENSURE_PARSING_COND (status == CR_PARSING_ERROR); 175*4882a593Smuzhiyun@@ -1237,7 +1251,7 @@ cr_parser_parse_any_core (CRParser * a_this) 176*4882a593Smuzhiyun } 177*4882a593Smuzhiyun 178*4882a593Smuzhiyun do { 179*4882a593Smuzhiyun- status = cr_parser_parse_any_core (a_this); 180*4882a593Smuzhiyun+ status = cr_parser_parse_any_core (a_this, n_calls + 1); 181*4882a593Smuzhiyun } while (status == CR_OK); 182*4882a593Smuzhiyun 183*4882a593Smuzhiyun ENSURE_PARSING_COND (status == CR_PARSING_ERROR); 184*4882a593Smuzhiyun@@ -1265,7 +1279,7 @@ cr_parser_parse_any_core (CRParser * a_this) 185*4882a593Smuzhiyun } 186*4882a593Smuzhiyun 187*4882a593Smuzhiyun do { 188*4882a593Smuzhiyun- status = cr_parser_parse_any_core (a_this); 189*4882a593Smuzhiyun+ status = cr_parser_parse_any_core (a_this, n_calls + 1); 190*4882a593Smuzhiyun } while (status == CR_OK); 191*4882a593Smuzhiyun 192*4882a593Smuzhiyun ENSURE_PARSING_COND (status == CR_PARSING_ERROR); 193