3 분 소요

Summary

CVE-2026-38752 tracks uncontrolled recursion in BusyBox awk. A user-defined AWK function can call itself directly or indirectly without a depth check. Each call enters another native evaluate() frame until the process stack is exhausted, terminating the applet. The demonstrated impact is denial of service in a process that executes an attacker-controlled AWK program.

The bug is scored as CVSS 7.5 (High) by CISA-ADP.

Affected versions

BusyBox builds containing the awk applet are affected from version 1.00 through 1.38.0, inclusive. The latest tested development commit after the 1.38.0 release, ec0c5cc142f1, is also affected. No fixed release is available.

Root cause

evaluate() allocates temporary AWK variables when it enters. In the OC_FUNC case it prepares the function arguments and then evaluates the function body by calling evaluate() again:

tmpvars = nvalloc(2);

/* ... */

case XC(OC_FUNC): {
        /* prepare argvars and save interpreter state */
        fnargs = argvars;
        res = evaluate(op->r.f->body.first, res);
        nvfree(argvars, nargs);
        /* restore interpreter state */
        break;
}

There is no pre-call depth check in the vulnerable source. For a program such as f() { return f() }, the inner call reaches the same OC_FUNC path repeatedly.

nvalloc() returns heap storage. It contributes per-call heap activity, but it is not the stack overflow itself. The overflow comes from the accumulating native C call frames and their local state. The crash can happen while a deep frame is asking malloc() for more temporary variables, which explains why the top frame in one trace is inside the allocator.

Evidence

The minimal reproducer is:

busybox awk 'function f(n){return f(n)} BEGIN{f(1)}' /dev/null

AddressSanitizer builds of Git tag 1_37_0 (be7d1b7b1701), the official 1.38.0 source tarball, and development commit ec0c5cc142f1 all terminated with AddressSanitizer: stack-overflow. The tarball’s editors/awk.c is byte-for-byte identical to the file at the 1.38.0 release commit, fc71374dfccd. The relevant frames from the ec0c5cc142f1 run were:

#3  nvalloc   editors/awk.c:1915
#4  evaluate  editors/awk.c:3141
#5  evaluate  editors/awk.c:3171
#6  evaluate  editors/awk.c:3472
#7  evaluate  editors/awk.c:3171
#8  evaluate  editors/awk.c:3472

GDB stopped on SIGSEGV and showed the same alternating evaluate() frames at the function-body call. That rules out a parser-only failure: execution had already entered the evaluator’s user-function path.

I also ran the reproducer on a non-sanitized build at commit 244c0a01eece. It exited with status 139 (SIGSEGV). This confirms that the denial of service is not merely an AddressSanitizer abort.

Fix

I submitted a patch that tracks active AWK function calls and raises a normal interpreter error at a fixed limit:

if (func_depth >= MAX_AWK_FUNC_DEPTH)
        syntax_error(EMSG_RECURSION);

func_depth++;
res = evaluate(op->r.f->body.first, res);
func_depth--;

With the submitted patch and the default 8 MiB stack, the same sanitizer build exits cleanly with:

awk: cmd. line:1: Recursion limit exceeded

The patch was public on 2026-06-16 but was not present in BusyBox official/master as of 2026-07-16.

The submitted limit is 1000. That value is not independent of the target’s stack size or build instrumentation: my -O0 sanitizer build still exhausted reduced stacks before reaching the guard. Sanitizers substantially enlarge frames, so those reduced-stack thresholds are not production sizing data, but they do show why a constrained BusyBox target should validate the chosen limit rather than assume that 1000 is universally safe.

Exploit

The input capability is the ability to make a BusyBox awk process execute a crafted AWK program.

The reproduced primitive is deterministic process-stack exhaustion. I did not obtain an out-of-bounds heap access, controlled memory write, code execution, privilege change, or cross-process effect from this bug. The evidence supports process denial of service, rather than RCE.

Mitigation

As of 2026-07-16 there is no merged upstream fix to point to. Please do not execute untrusted AWK programs with an affected BusyBox awk. Integrators that backport the submitted depth guard should choose and test a conservative limit for their smallest supported process stack.

References