Skip to content

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

@sxsxno

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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions