Skip to content

C-Stack Exhaustion via Deeply Nested Expressions Leading to crash(DOS) #73

Description

@sxsxno

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

poc.js

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) {
    // ...
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions