@@ -459,6 +459,8 @@ expr_print(const struct expr *e)
/* Parsing. */
+#define MAX_PAREN_DEPTH 100
+
/* Context maintained during expr_parse(). */
struct expr_context {
struct lexer *lexer; /* Lexer for pulling more tokens. */
@@ -466,6 +468,7 @@ struct expr_context {
const struct shash *addr_sets; /* Address set table. */
const struct shash *port_groups; /* Port group table. */
bool not; /* True inside odd number of NOT operators. */
+ unsigned int paren_depth; /* Depth of nested parentheses. */
};
struct expr *expr_parse__(struct expr_context *);
@@ -1068,6 +1071,7 @@ parse_chassis_resident(struct expr_context *ctx)
expr_destroy(e);
return NULL;
}
+ --ctx->paren_depth;
return e;
}
@@ -1077,11 +1081,18 @@ expr_parse_primary(struct expr_context *ctx, bool *atomic)
{
*atomic = false;
if (lexer_match(ctx->lexer, LEX_T_LPAREN)) {
+ if (++ctx->paren_depth > MAX_PAREN_DEPTH) {
+ lexer_syntax_error(ctx->lexer,
+ "parenthesis nested too deeply");
+ return NULL;
+ }
+
struct expr *e = expr_parse__(ctx);
if (!lexer_force_match(ctx->lexer, LEX_T_RPAREN)) {
expr_destroy(e);
return NULL;
}
+ --ctx->paren_depth;
*atomic = true;
return e;
}
@@ -1093,6 +1104,12 @@ expr_parse_primary(struct expr_context *ctx, bool *atomic)
if (lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) {
if (lexer_match_id(ctx->lexer, "is_chassis_resident")) {
+ if (++ctx->paren_depth > MAX_PAREN_DEPTH) {
+ lexer_syntax_error(ctx->lexer,
+ "parenthesis nested too deeply");
+ return NULL;
+ }
+
lexer_get(ctx->lexer); /* Skip "(". */
*atomic = true;
return parse_chassis_resident(ctx);
@@ -285,6 +285,8 @@ ip6.src == ::1 => ip6.src == 0x1
inport == "eth0"
!(inport != "eth0") => inport == "eth0"
+(((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((is_chassis_resident("eth0")))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) => is_chassis_resident("eth0")
+
ip4.src == "eth0" => Integer field ip4.src is not compatible with string constant.
inport == 1 => String field inport is not compatible with integer constant.
ip4.src = 1.2.3.4 => Syntax error at `=' expecting relational operator.
@@ -351,6 +353,9 @@ eth.dst[40] x => Syntax error at `x' expecting end of input.
ip4.src == {1.2.3.4, $set1, $unknownset} => Syntax error at `$unknownset' expecting address set name.
eth.src == {$set3, badmac, 00:00:00:00:00:01} => Syntax error at `badmac' expecting constant.
+
+((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((( => Syntax error at end of input parenthesis nested too deeply.
+((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((is_chassis_resident("eth1") => Syntax error at `(' parenthesis nested too deeply.
]])
sed 's/ =>.*//' test-cases.txt > input.txt
sed 's/.* => //' test-cases.txt > expout
This patch checks the depth of nested parentheses to prevent stack overflow. Reported-at: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=10714 Signed-off-by: Yifeng Sun <pkusunyifeng@gmail.com> Suggested-by: Ben Pfaff <blp@ovn.org> --- v1->v2: Handle parse_chassis_resident and add new test, thanks Ben! ovn/lib/expr.c | 17 +++++++++++++++++ tests/ovn.at | 5 +++++ 2 files changed, 22 insertions(+)