The cgetnext() function in lib/libc/gen/getcap.c has a stack
buffer overflow.  At line 782-783:

  char nbuf[BSIZE];        /* BSIZE = 1024 */
  ...
  len = strcspn(record, "|:");
  memcpy(nbuf, record, len);

The record buffer grows dynamically via realloc (line 757), but
nbuf is a fixed 1024-byte stack buffer.  A capability record
with no '|' or ':' character longer than 1024 bytes overflows
nbuf, overwriting the return address and saved registers.

Confirmed on OpenBSD 7.8/arm64 via cap_mkdb(1) with a corrupted
termcap file.  GDB shows the stack is overwritten with data from
the record:

  #0 _libc_cgetnext at getcap.c:803
      buf = <Cannot access memory at address 0x5e5e5e5e5e5e5a56>
  #1 0x5e5e5e5e5e5e5e5e in ?? ()
  Backtrace stopped: corrupt stack

Registers x19-x30 (including frame pointer and return address)
are all 0x5e5e5e5e5e5e5e5e ('^' characters from the input).

Fix: truncate the name to fit nbuf before the memcpy.

Found by AFL++ fuzzing of cap_mkdb(1).

Index: lib/libc/gen/getcap.c
===================================================================
RCS file: /cvs/src/lib/libc/gen/getcap.c,v
retrieving revision 1.38
diff -u -p -r1.38 getcap.c
--- lib/libc/gen/getcap.c       9 Mar 2026 12:22:44 -0000       1.38
+++ lib/libc/gen/getcap.c
@@ -780,6 +780,8 @@ cgetnext(char **cap, char **db_array)
 lookup:
        /* extract name from record */
        len = strcspn(record, "|:");
+       if (len >= sizeof(nbuf))
+               len = sizeof(nbuf) - 1;
        memcpy(nbuf, record, len);
        nbuf[len] = '\0';

Reply via email to