make(1) aborts on malformed input containing nested archive
specs with variable references.

A 36-byte input reproduces the crash on all architectures
with the stock system binary, no special flags needed:

  printf 'h:)C)($$\017*)))(($$$$\t))))()\n' > crash.mk
  /usr/bin/make -nf crash.mk

  Abort trap (core dumped)

Confirmed on OpenBSD 7.9/amd64, 7.9/i386, and 7.8/arm64.

Root cause: Arch_ParseArchive() in arch.c uses a static
buffer shared across recursive calls.  When an archive
member contains $-variables, parse_archive() recurses
into Arch_ParseArchive() (line 313), which calls
Buf_Reinit() on the same static buffer, corrupting the
outer call's state.  malloc detects the corruption and
calls abort().

Introduced in arch.c r1.91 (2020-01-13).

Fix: revert the buffer to a local variable, restoring
the Buf_Init/Buf_Destroy pair that r1.91 removed.

All 48 regression tests pass on amd64, i386, and arm64.
Fuzzed for 5 minutes with AFL++ on amd64: 0 crashes.

Found by AFL++ fuzzing.

Index: usr.bin/make/arch.c
===================================================================
RCS file: /cvs/src/usr.bin/make/arch.c,v
retrieving revision 1.95
diff -u -p -r1.95 arch.c
--- usr.bin/make/arch.c 26 Jan 2025 13:06:30 -0000      1.95
+++ usr.bin/make/arch.c
@@ -193,10 +193,11 @@ bool
 Arch_ParseArchive(const char **line, Lst nodes, SymTable *ctxt)
 {
        bool result;
-       static BUFFER expand;
+       BUFFER expand;

-       Buf_Reinit(&expand, MAKE_BSIZE);
+       Buf_Init(&expand, MAKE_BSIZE);
        result = parse_archive(&expand, line, nodes, ctxt);
+       Buf_Destroy(&expand);
        return result;
 }

Reply via email to