Skip to content

Promise.withResolvers(): OOM cleanup use-after-free on current master #1660

Description

@mschwarzl

Affected code: quickjs.c, js_promise_withResolvers() at current master 954dc53.

A single ordinary JavaScript expression can trigger a native heap use-after-free when a property definition fails under the runtime memory limit:

ASAN_OPTIONS=abort_on_error=1:detect_leaks=0:halt_on_error=1 \
  ./qjs --memory-limit 119434b -e "Promise.withResolvers()"

The exact limit is build-dependent. On the tested Linux x86_64 ASan build, 119434b through 119438b reproduce consistently. ASan reports a READ of size 4 in JS_FreeValueRT, called by js_promise_withResolvers at quickjs.c:56061. The object was freed by JS_DefinePropertyValue at quickjs.c:11538, called from the reject-property definition at quickjs.c:56054.

Expected: Promise.withResolvers() returns or throws OOM cleanly.

Actual: the host process performs a UAF read and aborts under ASan.

Root cause: JS_DefinePropertyValue() consumes and releases val even when it returns an error. js_promise_withResolvers() clears result_promise and resolving_funcs[0] only after successful calls, and never clears resolving_funcs[1]. On failure, exception cleanup releases the stale local again. The promise, resolve, and reject property paths are all statically affected; the command above directly reproduces the reject path.

This was introduced by b0eb4fe (#1173) and is distinct from #1613 / GHSA-crgj-9jv8-xfhq, which fixed stale output from js_create_resolving_functions() before v0.16.0. This reproduces on v0.16.1.

The ownership fix is to set each local to JS_UNDEFINED immediately after the consuming JS_DefinePropertyValue call, before checking its return value. I tested that change in a separate ASan build: no ASan findings across 119400b..119460b or sampled handled-OOM limits, git diff --check passed, and the project suite reported 0/89 errors (9 excluded). A deterministic allocation-failure regression harness does not appear to exist in the current suite.

Reported publicly per SECURITY.md guidance for AI-assisted source findings; the root cause, reproducer, ASan trace, affected history, and fix were independently verified.

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