Hello GNU tar maintainers,

While reviewing the incremental dumpdir handling in tar, I found a
heap out-of-bounds read caused by missing NUL termination of the
dumpdir buffer. A fix and a test generator are attached.

Description

In get_gnu_dumpdir() (src/incremen.c), the dumpdir data from the
archive is copied into a buffer allocated with xmalloc(size) and no
NUL terminator is appended afterwards:

  archive_dir = xmalloc (size); /* line 1506 */
  ...
  memcpy (to, charptr (data_block), copied); /* line 1521 */
  mv_end (); /* line 1526 */
  /* no NUL appended here */
  stat_info->dumpdir = archive_dir; /* line 1528 */

The same pattern exists in dumpdir_decoder() (src/xheader.c):

  st->dumpdir = ximalloc (size); /* line 1486 */
  memcpy (st->dumpdir, arg, size); /* line 1487 */

Several consumer functions then traverse this buffer assuming
NUL-terminated strings:

  dumpdir_size() (incremen.c:243): while (*p) { strlen(p); ... }
  dumpdir_ok() (incremen.c:1551): for (p=dumpdir; *p; p+=strlen(p)+1)
  dumpdir_create() (incremen.c:153): for (p=contents; *p; p+=strlen(p)+1)

When a crafted archive provides dumpdir data without a trailing NUL,
these functions read past the allocated buffer (CWE-125).

Affected version

tar (GNU tar) 1.35.90 (master as of 2026-07-16 08c3fc2e9337094aff01a511170fd35fdb8f1ee3)

Also confirmed in the 1.35 release.

Reproduction

The attached craft_tar.py generates an OLDGNU incremental archive
containing a GNUTYPE_DUMPDIR ('D') member whose payload is made
entirely of 'A' bytes with no trailing NUL:

  crafted.tar: 16-byte payload — triggers a small heap over-read
that leaks adjacent heap bytes into the tar listing output.

Step 1. Generate the test archive:

  $ python3 craft_tar.py .
  wrote ./crafted.tar (2048 bytes); dumpdir st_size=16, has_NUL=False
  done

Step 2. List the crafted archive with incremental mode enabled:

  $ tar -G -tvvvf crafted.tar | cat -v
  drwxr-xr-x 0/0 16 1970-01-01 08:00 ./testdir/
  AAAAAAAAAAAAAAAA<heap-garbage-bytes-here>

The bytes after the 16 'A's are adjacent heap memory that
dumpdir_size() reads via strlen() past the buffer boundary.

Step 3. (Optional) Confirm with an ASan build:

  $ ./tar -G -tvvvf crafted.tar | cat -v
  =================================================================
  drwxr-xr-x 0/0 16 1970-01-01 08:00 ./testdir/
  ==1603745==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6020000002c0 at pc 0x7f68d824cf7a bp 0x7ffcc4a47540 sp 0x7ffcc4a46ce8
  READ of size 17 at 0x6020000002c0 thread T0
  #0 0x7f68d824cf79 (/usr/lib64/libasan.so.8+0x4cf79)
  #1 0x42e36d in dumpdir_size .../src/incremen.c:202
  #2 0x4385f0 in list_archive .../src/list.c:341
  #3 0x437f86 in read_and .../src/list.c:229
  #4 0x456a2f in main .../src/tar.c:2845
  #5 0x7f68d804aa4f (/usr/lib64/libc.so.6+0x23a4f)
  #6 0x7f68d804ab08 in __libc_start_main (/usr/lib64/libc.so.6+0x23b08)
  #7 0x405ef4 in _start (.../src/tar+0x405ef4)

  0x6020000002c0 is located 0 bytes to the right of 16-byte region [0x6020000002b0,0x6020000002c0)
  allocated by thread T0 here:
  #0 0x7f68d82c067f in __interceptor_malloc (/usr/lib64/libasan.so.8+0xc067f)
  #1 0x49ac19 in xmalloc .../gnu/xmalloc.c:45
  #2 0x432179 in get_gnu_dumpdir .../src/incremen.c:1500
  #3 0x432179 in is_dumpdir .../src/incremen.c:1535
  #4 0x4385ca in list_archive .../src/list.c:340
  #5 0x437f86 in read_and .../src/list.c:229
  #6 0x456a2f in main .../src/tar.c:2845
  #7 0x7f68d804aa4f (/usr/lib64/libc.so.6+0x23a4f)

  SUMMARY: AddressSanitizer: heap-buffer-overflow (/usr/lib64/libasan.so.8+0x4cf79)
  Shadow bytes around the buggy address:
  0x0c047fff8000: fa fa fd fa fa fa 00 04 fa fa 00 04 fa fa 00 04
  0x0c047fff8010: fa fa 00 04 fa fa 00 04 fa fa 00 04 fa fa 00 04
  0x0c047fff8020: fa fa 00 04 fa fa 00 04 fa fa 00 04 fa fa 00 04
  0x0c047fff8030: fa fa 00 04 fa fa 00 04 fa fa 00 04 fa fa 00 00
  0x0c047fff8040: fa fa 00 03 fa fa fd fd fa fa 01 fa fa fa 00 02
  =>0x0c047fff8050: fa fa 00 07 fa fa 00 00[fa]fa fa fa fa fa fa fa
  0x0c047fff8060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8070: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8090: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff80a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable: 00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone: fa
  Freed heap region: fd
  Stack left redzone: f1
  Stack mid redzone: f2
  Stack right redzone: f3
  Stack after return: f5
  Stack use after scope: f8
  Global redzone: f9
  Global init order: f6
  Poisoned by user: f7
  Container overflow: fc
  Array cookie: ac
  Intra object redzone: bb
  ASan internal: fe
  Left alloca redzone: ca
  Right alloca redzone: cb
  ==1603745==ABORTING

  ==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000300
  READ of size 17 at 0x602000000300 thread T0
  #0 in dumpdir_size src/incremen.c:245
  #1 in list_archive src/list.c:332
  #2 in read_and src/list.c:229
  #3 in main src/tar.c:2845
  0x602000000300 is located 0 bytes to the right of 16-byte region
  [0x6020000002f0,0x602000000300)
  allocated by:
  #0 in xmalloc src/incremen.c:1506

Security impact

CWE-125 (Out-of-bounds Read)
CVSS 3.1: CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H (5.5 Medium)

A malicious archive can cause heap memory disclosure (adjacent heap
data appears in tar output) or denial of service (SIGSEGV when the
OOB read crosses an unmapped page).

Proposed fix

Allocate size+2 bytes and append two NUL terminators after the
memcpy, in both get_gnu_dumpdir (incremen.c) and dumpdir_decoder
(xheader.c). Two NUL bytes are needed because dumpdir_size() reads
one byte past the data to detect the end sentinel (it returns
totsize+1).

The complete patch is attached to this email as a clean mbox
attachment (0001-Fix-heap-over-read-in-get_gnu_dumpdir-and-dumpdir_decoder.patch).

  src/incremen.c | 5 ++++-
  src/xheader.c | 4 +++-
  2 files changed, 7 insertions(+), 2 deletions(-)

CVE assignment

Would this issue qualify for a CVE ID? If so, could one be assigned?

Tested with the archives produced by craft_tar.py: before the
patch, tar -G -tvvvf crafted.tar shows extra heap bytes in the
output and ASan reports heap-buffer-overflow in dumpdir_size; after
the patch the output is clean and ASan reports no errors.

Output after fix (confirmed with an ASan build)

  $ tar -G -tvvvf crafted.tar | cat -v
  drwxr-xr-x 0/0 16 1970-01-01 08:00 ./testdir/
  AAAAAAAAAAAAAAAA

Attachments

1. craft_tar.py
Generator for the test archive (crafted.tar).
2. 0001-Fix-heap-over-read-in-get_gnu_dumpdir-and-dumpdir_decoder.patch
Fix adding NUL termination to both code paths.

 

Kind regards,

Shuo Wang

---

 

Attachment: "0001-Fix-heap-over-read-in-get_gnu_dumpdir-and-dumpdir_decoder.patch
Description: Binary data

Attachment: "craft_tar.py
Description: Binary data

Reply via email to