pax: add "align" write option for reflink-friendly archives
Add a per-format "align" option to the pax writer that pads each
regular file's pax extended header (creating one if necessary) so the
file data that follows begins on a multiple of the requested number of
bytes within the uncompressed archive stream. The value must be a
power of two and a multiple of the 512-byte tar block.
The alignment is applied to the stream feeding into any compression
filter, so the decompressed archive is aligned regardless of whether
the archive is compressed. This lets tools share file contents out of
an (uncompressed copy of an) archive using reflinks / copy_file_range(2)
instead of doing a full data copy on extraction.
The padding is carried in an ignorable "LIBARCHIVE.pad" pax record, so
existing readers extract the archive unchanged. Files shorter than the
alignment are left unpadded since they cannot share a whole block.
Add a test covering uncompressed and gzip-compressed archives and
document the option.
cpio: add regression test for symlink-trailer end-of-archive check
A symlink entry named TRAILER!!! with a body large enough to grow the
read filter's copy buffer used to leave the cached name pointer stale
before the end-of-archive comparison. Read a static newc archive in
small blocks and assert the trailer is still detected (ARCHIVE_EOF).
The fix landed in 23b54da; this only adds coverage.
The uu filter can keep a partial encoded line in its internal input
buffer, then reach upstream EOF with no new bytes available. In that
case, d is NULL and avail_in is zero, but the buffered-input path still
passes d to memcpy() before processing the saved bytes.
Skip the append copy when avail_in is zero so the saved input is handled
without passing a null source pointer to memcpy().
Cache the CPIO trailer-name check before consuming the pathname
buffer.
The reader kept a pointer returned by __archive_read_ahead() and used
it after __archive_read_consume(), and after possible symlink body
processing. Read-ahead pointers are views into libarchive input buffers
and should not be relied on after the associated bytes are consumed.
Store the TRAILER!!! decision while the pathname buffer is still valid,
then use the saved boolean after the remaining header handling.
Parse Content-Length only up to the located end-of-line instead of
passing a bounded header field to strtol(). Use int64_t for the parsed
entry size, ASCII digit checks, and checked arithmetic while accumulating
the value.
test_sparse_basic: avoid out-of-bounds pointer arithmetic in verify
When a sparse map entry began before the current data block
(expected_offset < offset), verify_sparse_file() formed the intermediate
pointer "buff + (expected_offset - offset)" before adding the entry
size. That intermediate points before buff, which is undefined behavior;
with file4's large hole it trapped the test under UBSan
(-fsanitize=pointer-overflow). Fold the size into the displacement so the
whole byte offset is computed as one integer and added to buff in a
single, in-bounds step.
Some lzx functions reverse the generic logic of 0 being success and
anything else being an error. It's debatable from a boolean point of
view but use the regular ARCHIVE_OK in case of success, which is 0.
Unifies with other lzx functions and general idea of libarchive
functions.
Most if not all compilers today understand inline, but it's also just a
hint. Static functions will be inlined if it's worth it from compiler
perspective and inline functions will be still functions, too.
Remove it and let compilers decide. Increases portability for very old
compilers which cannot handle it.
archive_string: bound best_effort_strncat_in_locale to length
remaining was set to length but never decremented, so the loop only stopped at a NUL and read past fields passed without a trailing NUL (a read_ahead window sized by mbsnbytes). Decrement per byte and check the count before dereferencing *itp.
archive_string: add test for best-effort converter over-read
Drives the best-effort converter (charset iconv cannot open) through
archive_strncpy_l with a length-delimited buffer: once with trailing
non-NUL bytes after the declared length and once with an exact-length
heap allocation with no trailing NUL. Fails under ASan before the fix.
iso9660_options() checks the second byte of the iso-level option value
before checking that the first byte contains a valid ISO level.
For an empty option value such as iso9660:iso-level=,
archive_write_set_options() passes a value pointer to the terminating NUL
byte of the duplicated options string. Reading value[1] then reads one byte
past that heap allocation.
Check value[0] before reading value[1]. This keeps the same accepted values
while rejecting the empty value without reading past the option buffer.
The GNU sparse name builder trims trailing slash and /. components before
building the synthetic ustar entry name. If the sparse pathname is fully
pruned, the effective source length becomes zero and build_ustar_entry_name()
reads one byte before the pathname buffer.
Handle the all-pruned pathname case before calling the ustar name builder.
The synthetic name then preserves the root-directory case.
tar: add test for SUN.holesdata sparse map ending on a digit
Read a Solaris pax entry whose SUN.holesdata value ends right after its
final decimal offset (no trailing space), which is the shape of every
valid map. The 1536-byte file has data at [0,512) and [1024,1536) with a
hole between them, so archive_entry_sparse must report exactly those two
data blocks. This pins the parser's loop-termination behavior for the
common case where the run consumes all value_length bytes.
bsdtar: fix 1-byte OOB read in substitution handling
The -s replacement scanner consumes a backslash and then reads the
escaped byte. If the replacement ends in one literal backslash, the loop
can advance past the terminating NUL and read one byte past the
allocated replacement buffer.
Stop scanning when a backslash is followed by the terminating NUL. The
final literal append then preserves the trailing backslash.
The seekable ZIP reader checks whether __MACOSX/ entries are resource
fork entries by testing the basename prefix.
The existing guard used r - name, which is the basename offset from the
start of the filename, not the basename length. For a short basename such
as "__MACOSX/.", this could read one byte past the filename.
Check the remaining basename length before reading the resource fork prefix.
pax: handle all-slash pathnames in USTAR name splitting
When build_ustar_entry_name() trims trailing '/' characters and '/.'
path elements from a pathname made entirely of separators, filename_end
can be reduced all the way back to src.
Handle this root-like pathname case before attempting to locate the
filename component, and emit a root-like ustar name instead.
Add a regression test that writes and reads back a long all-slash pax
pathname.
Consume pending data before EOF and skip handling.
Then skip only the unread body bytes plus the WARC record separator.
This keeps the reader at the correct input position after an entry has
been partially or fully read.
tar_atol_base_n() read the next byte before checking whether any bytes
remained. If a numeric field ended at the caller-provided boundary, this
caused a 1-byte OOB read while preparing the next digit range check.
header_pax_extension() passes PAX attribute values without the trailing
newline to pax_attribute(). The SUN.holesdata parser read one byte past
the supplied value when the last numeric field ended at the value
boundary.
data [Mon, 6 Jul 2026 10:34:52 +0000 (18:34 +0800)]
tar: avoid redundant Solaris ACL size parsing
read_body_to_string() already consumes the extension body according to
the header size. Use the resulting string length instead of decoding the
size field again in header_Solaris_ACL().