Use C comments, define variables at start of block, keep 80 chars per
line. While at it, turn a few variables const to clarify that they do
not change.
SanjayR [Fri, 22 May 2026 05:03:56 +0000 (10:33 +0530)]
warc writer: free hdr on _popul_ehdr overflow in _warc_header
_warc_header() initialises a local archive_string hdr, fills it via
_popul_ehdr(), and frees it on the success path at the bottom. The
intermediate error return on r < 0 (the populated header exceeds
MAX_HDR_SIZE=512, reachable with a long enough pathname carried by
WARC-Target-URI) returns ARCHIVE_WARN without freeing hdr.
By the time _popul_ehdr returns -1 hdr already holds the WARC version
line, WARC-Type, WARC-Target-URI (long path), WARC-Date, Last-Modified,
WARC-Record-ID, and Content-Length headers --- ~1 KB+ per entry in
practice.
Reproduces with the bundled bsdtar against a regular file with a
~400+ char pathname:
ASAN_OPTIONS=detect_leaks=1 bsdtar --format=warc -cf out.warc <long_path>
=> LeakSanitizer: ~1 KB direct leak; stack pierces _popul_ehdr ->
_warc_header (archive_write_set_format_warc.c:245) ->
_archive_write_header -> ... -> main.
Code unchanged since the file's introduction in 2014; no existing test
exercises the long-pathname path. The warcinfo branch above (line ~217)
handles this correctly already (frees hdr unconditionally outside the
"if (r >= 0)" block); only the WT_RSRC branch was missed.
Identified by Neurolog, a code-analysis tool the reporter is developing
that combines Souffle Datalog with LLM-assisted fact extraction. The
reproducer was hand-validated under LeakSanitizer against current master.
SanjayR [Fri, 22 May 2026 05:36:50 +0000 (11:06 +0530)]
7zip writer: free file->utf16name on symlink UTF-8 conversion failure
file_new() at archive_write_set_format_7zip.c:1688 calls free(file)
on the symlink-UTF8-failure branch, leaving file->utf16name
(allocated at line 1666) leaked. The two earlier free(file) calls
in this function (lines 1656, 1668) are correct because they happen
BEFORE utf16name is allocated, but the third one happens after.
The rest of the function uses file_free() on every other
post-utf16name error path; file_free() does free(file->utf16name)
followed by free(file), which is the cleanup convention. Replacing
free(file) with file_free(file) makes the symlink-error branch
consistent with everything else.
Reproduces with bsdtar in a non-UTF-8 locale with a non-UTF-8
symlink target:
ln -s "$(printf 'broken_\\xff\\xfe_link')" sym
LC_ALL=C ASAN_OPTIONS=detect_leaks=1 \
bsdtar --format=7zip -cf out.7z sym
=> LeakSanitizer: 30-48 byte direct leak; allocation site is
file_new (archive_write_set_format_7zip.c:1666).
Equivalent trigger: any libarchive caller that sets AE_IFLNK
filetype on an entry without ever calling
archive_entry_set_symlink() (then archive_entry_symlink_utf8()
returns NULL and the error branch fires).
Code unchanged since the 7zip writer's introduction; no existing
test exercises this error path.
Identified by Neurolog, a code-analysis tool the reporter is
developing that combines Souffle Datalog with LLM-assisted fact
extraction. The reproducer was separately validated under LeakSanitizer
against current master.
Sanjay Rawat [Thu, 21 May 2026 21:51:09 +0000 (23:51 +0200)]
xar: fix fflags_text leak in file_free
file_free() releases pathname, symlink, uname, gname, and hardlink but
omits fflags_text. When a XAR archive describes a file with <flags> or
<ext2> children (e.g. <SystemNoUnlink/>, <Compress/>), xml_parse_file_flags
/ xml_parse_file_ext2 populate xar_file->fflags_text via archive_strcat,
which heap-allocates. The buffer leaks on every file_free().
Reproduces with ASan+LSan via the bundled bsdtar:
bsdtar -tvf <xar-with-flags>
=> Direct leak of N bytes ... archive_strcat ... xml_parse_file_flags
Same shape as commit 6767cbe3 ("Free XAR xattr fstype metadata"), which
fixed the analogous miss in xattr_free().
Existing release of fflags_text in archive_string_free is a no-op when
the field was never populated (.s == NULL, free(NULL) is safe), so the
patch is harmless on the non-flags path.
datauwu [Thu, 21 May 2026 02:55:26 +0000 (10:55 +0800)]
iso9660: avoid negative duplicate suffix offsets
Avoid passing negative suffix offsets to the duplicate identifier
resolver. Clamp them where ISO9660 and Joliet identifiers decide
where the duplicate suffix should be written.
Mark Johnston [Wed, 20 May 2026 16:39:40 +0000 (16:39 +0000)]
libarchive: Force GNU iconv compatibility on FreeBSD
When libarchive is compiled with FreeBSD's native iconv instead of
libiconv, as happens with libarchive in the base system, we need to
configure iconv(3) to handle invalid sequences by returning -1, as
iconv_strncat_in_locale() assumes GNU iconv semantics.
i1011 [Wed, 20 May 2026 13:18:35 +0000 (21:18 +0800)]
filter: Fix mismatched add_filter table entry
The integer-code dispatch table in archive_write_add_filter() maps
ARCHIVE_FILTER_LZOP to the function pointer archive_write_add_filter_lzip
(the lzip filter setter) instead of archive_write_add_filter_lzop.
datauwu [Wed, 20 May 2026 01:36:20 +0000 (09:36 +0800)]
iso9660: test duplicate Joliet identifier truncation
Add a test for ISO9660 entries whose Joliet identifiers collide
after default identifier truncation. The writer should resolve
the duplicate identifiers successfully when the archive is closed.
The debug_buff array is populated but never read. If multiple threads
process compress streams, they access the same index variable, which
could lead to out of boundary writes.
Currently, the code calls GetTempPathW to figure out required size for a
buffer larger enough to contain the temporary directory path, allocates
the memory, and then calls GetTempPathW again to populate the memory.
Since libarchive is designed with multi-threading in mind, the worst
situation would be that another thread modifies the environment variable
between these two calls.
Use a buffer of MAX_PATH + 1 (261) to basically cover all regular
situations. If long paths are enabled, reallocate until enough bytes
were available (32 kb is maximum) without another thread intefering.
Realistically, this will happen only once.
datauwu [Sun, 17 May 2026 07:34:15 +0000 (15:34 +0800)]
cpio: reject oversized pathnames before read-ahead
Reject malformed CPIO entries whose pathname field exceeds 1 MiB before asking the read-ahead layer to satisfy the padded pathname length.
This prevents newc archives with attacker-controlled c_namesize values from forcing large metadata read-ahead and pathname allocation during archive listing. Add a regression test that fails on the unpatched reader and passes once the cap is enforced.
Tim Kientzle [Sat, 16 May 2026 17:04:24 +0000 (10:04 -0700)]
Fix unchecked calloc results in init_unpack (rar5)
window_buf and filtered_buf were allocated via calloc without checking
for NULL. Change init_unpack to return int and propagate ARCHIVE_FATAL
on allocation failure to the caller.
The strcpy and sprintf functions are generally hard to reason about.
While they are safe in this context, I think, it's easy to refactor the
code to avoid them completely.
The code can be simplified to avoid strcpy usage. While not exactly a
much safer approach by manually adjusting characters in a string, this
attempt reduces size of libarchive and avoids unneeded copy operations.
cmdline: Use free+strdup instead of realloc+strcpy
The cmdline_set_path function contains logic to reallocate memory of
command path and copy a new value into it.
Inline a simpler free+strdup alternative into __archive_cmdline_parse.
Since the function is always called with empty data, free could be
removed as well. I've kept it that way just to make sure that it's 100 %
compatible with previous code.
read: Fix memory corruption in client_switch_proxy
Switching a multi-volume archive file with another active filter, e.g.
decompression, can lead to memory corruption due to modifying the wrong
private data (self->data).
Use highest upstream filter to replace the correct private data.
Parsing a string into an integer also means that boundary checks have to
be performed. Check within atou64 as well as outside by verifying that
subsequent casts won't truncate numbers.
br0nzu [Wed, 13 May 2026 07:24:44 +0000 (16:24 +0900)]
Free XAR xattr fstype metadata
The XAR xattr cleanup helper released the xattr name string but not the parallel fstype archive_string. Release fstype from the same xattr_free() ownership boundary.
br0nzu [Wed, 13 May 2026 07:24:44 +0000 (16:24 +0900)]
Add XAR xattr fstype cleanup coverage
Add a focused XAR sample with xattr fstype metadata and exercise it through the public read/free path. This gives leak-checking builds coverage for the xattr cleanup ownership boundary.
Avoid requesting NEWSUB extended data through read-ahead while parsing the header. The full NEWSUB block size is still validated and consumed, but the extended data is not required to be present in memory during header parsing.
Add a test for a malformed NEWSUB header with a large packed size.
Allocate enough memory for possible addition of 3 characters within the
range of 0-Z. Since UTF-16 is in use, allocate 6 bytes + 2 bytes for the
terminating NUL character.
Also keep in mind that "l" is already size in bytes, which means that a
multiplication of 2 is not needed (and prevented overflow issues with
longer filenames).
It is possible to trigger an out of boundary write with short filenames
which contain illegal ISO9660 characters. For these files, Joliet IDs
are generated. If multiple files lead to the same ID (which can happen
because illegal characters are replaced with an underscore), 3
characters/digits in the range of 0-Z are added.