-
Notifications
You must be signed in to change notification settings - Fork 97
Description
Summary
A stack exhaust vulnerability exists in Elk's parser where deeply nested parentheses in JavaScript source code cause excessive recursion on the C stack during the parsing phase. This leads to a process crash (Segmentation Fault).
Root Cause
The parser handles grouped expressions using recursive function calls. Specifically, js_group() calls js_expr(), which eventually calls back into js_group() through the expression hierarchy. While Elk has a js->css and js->maxcss check in js_literal(), the recursion depth is not checked during the parsing of parentheses, allowing the C stack to grow beyond its limits.
// elk.c line 970
static jsval_t js_group(struct js *js) {
if (next(js) == TOK_LPAREN) {
js->consumed = 1;
jsval_t v = js_expr(js); // Recursive call without immediate depth check
// ...
}
}
static jsval_t js_literal(struct js *js) {
next(js);
setlwm(js);
// printf("css : %u\n", js->css);
if (js->maxcss > 0 && js->css > js->maxcss) return js_mkerr(js, "C stack");
// it wouldn't execute before stack exhausted
// ...
}
}Proof of Concept
The vulnerability is triggered by a script with deeply nested structural parentheses:
// Generated script: (((((...1...)))))
((((((((((((((((((((((((((((((((((((((((1))))))))))))))))))))))))))))))))))))))))To trigger a crash, execute script like : "(" * 12000 + "1" + ")" * 12000
POC file in attachment
it would produce : "Segmentation fault (core dumped)"
(Reproduction requires ~10,000 levels of nesting depending on system stack size limits.)
Analysis
Each level of ( consumed by the lexer triggers a chain of function calls: js_group -> js_expr -> js_equality -> ... -> js_group.
Since these calls happen before any leaf node (like a number) is reached, the js->css and js->maxcss check in js_literal is never executed.
Impact
Reliable Denial of Service (DoS) against any application embedding the Elk engine.
Suggested Fix
Implement a recursion depth check at the entry of the grouping parser:
static jsval_t js_group(struct js *js) {
if (js->css > js->maxcss) return js_mkerr(js, "C stack");
if (next(js) == TOK_LPAREN) {
// ...
}
}