Compare commits

...
1412 Commits
Author SHA1 Message Date
Dustin L. Howett b738b9d38c Merge pull request #3377 from stoeckmann/7zip_max_bid
CI / FreeBSD (autotools) (push) Failing after 7s
CI / FreeBSD (cmake) (push) Failing after 1s
CI / MacOS (autotools) (push) Canceled after 0s
CI / MacOS (cmake) (push) Canceled after 0s
CI / Ubuntu (autotools, mbedtls) (push) Canceled after 0s
CI / Ubuntu (autotools, nettle) (push) Canceled after 0s
CI / Ubuntu (autotools, openssl) (push) Canceled after 0s
CI / Ubuntu (cmake, mbedtls) (push) Canceled after 0s
CI / Ubuntu (cmake, nettle) (push) Canceled after 0s
CI / Ubuntu (cmake, openssl) (push) Canceled after 0s
CI / Ubuntu-distcheck (push) Canceled after 0s
CI / Windows (cygwin-gcc) (push) Canceled after 0s
CI / Windows (mingw-gcc) (push) Canceled after 0s
CI / Windows (msvc) (push) Canceled after 0s
Lint / Lint (push) Canceled after 0s
7zip: Fix max bidding check
2026-08-12 18:30:34 -05:00
Tobias Stoeckmann daf210f18a 7zip: Fix max bidding check
The 7zip bidder can return 48, so maximum check of 32 is too small.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-08-12 20:42:29 +02:00
Tim Kientzle a16834cfc6 Merge pull request #3373 from stoeckmann/mem_seek
memory: Adjust seek logic
2026-08-11 19:38:17 -07:00
Tobias Stoeckmann 1cd388fc60 memory: Adjust seek logic
The seek implementations for files return ARCHIVE_FATAL if seek fails to
adjust the position. ARCHIVE_FAILED is used in case of pipes etc.

Also, if a file seek fails, the position is not adjusted.

Adjust the memory implementations to do the same.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-08-11 21:34:28 +02:00
Dustin L. Howett d304bbcc50 Merge pull request #3371 from stoeckmann/open_err_leak
Fix memory leaks on open error paths
2026-08-10 13:36:12 -05:00
Dustin L. Howett ce01d3d86c Merge pull request #3370 from stoeckmann/lrzip_bits
lrzip: Return matching bits in bidding
2026-08-10 13:35:40 -05:00
Tobias Stoeckmann 73412046b7 lrzip: Return matching bits in bidding
Actually follow the bidder comment and return amount of bits. Has the
nice advantage of removing the int/ssize_t handling, even though it was
safe anyway.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-08-10 19:52:30 +02:00
Tobias Stoeckmann 98546092b9 Fix memory leaks on open error paths
If open functions fail to store client data, free internally allocated
memory before returning an error code.

Writer open functions must check magic themselves.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-08-10 19:48:26 +02:00
Dustin L. Howett ec398c5a4a Merge pull request #3369 from libarchive/dependabot/github_actions/all-actions-6c7da2231a
CI: Bump the all-actions group with 4 updates
2026-08-10 11:26:44 -05:00
dependabot[bot] 9d0dedbe3b CI: Bump the all-actions group with 4 updates
Bumps the all-actions group with 4 updates: [github/codeql-action/init](https://github.com/github/codeql-action), [github/codeql-action/autobuild](https://github.com/github/codeql-action), [github/codeql-action/analyze](https://github.com/github/codeql-action) and [github/codeql-action/upload-sarif](https://github.com/github/codeql-action).


Updates `github/codeql-action/init` from 4.37.4 to 4.37.6
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/f205ea1c3313d32999d8d6a48b4f6530d4437b38...5595ccaf912efad79be6eef63a5619ff05969be3)

Updates `github/codeql-action/autobuild` from 4.37.4 to 4.37.6
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/f205ea1c3313d32999d8d6a48b4f6530d4437b38...5595ccaf912efad79be6eef63a5619ff05969be3)

Updates `github/codeql-action/analyze` from 4.37.4 to 4.37.6
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/f205ea1c3313d32999d8d6a48b4f6530d4437b38...5595ccaf912efad79be6eef63a5619ff05969be3)

Updates `github/codeql-action/upload-sarif` from 4.37.4 to 4.37.6
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/f205ea1c3313d32999d8d6a48b4f6530d4437b38...5595ccaf912efad79be6eef63a5619ff05969be3)

---
updated-dependencies:
- dependency-name: github/codeql-action/init
  dependency-version: 4.37.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-actions
- dependency-name: github/codeql-action/autobuild
  dependency-version: 4.37.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-actions
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.37.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-actions
- dependency-name: github/codeql-action/upload-sarif
  dependency-version: 4.37.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-10 16:17:40 +00:00
Tim Kientzle 6ea9e10bc5 Merge pull request #3321 from carrerasdarren-cell/fix/cpio-newc-inode-synthesis
cpio: synthesize newc inode values
2026-08-10 06:58:16 -07:00
Darren Carreras 1803922e49 cpio: synthesize newc inode values
The newc format stores only 32-bit inode values. Assign unique
synthetic values from each full device and inode identity. This avoids
collisions after truncation while preserving hardlink groups.

Fixes #3314.
2026-08-10 09:40:05 -04:00
Dustin L. Howett b100df7e65 Merge pull request #3362 from stoeckmann/filter_bits 2026-08-10 00:53:31 -05:00
Darren Carreras 48fc018080 cpio: test synthetic newc inode values
Exercise large inode values that collide after 32-bit truncation,
hardlink identity, and distinct device IDs. Update bsdcpio expectations
so successful synthesis produces no truncation warnings.
2026-08-08 17:50:29 -04:00
Dustin L. Howett 682a87b111 Merge pull request #3365 from moodyastra/codex/libarchive-lzx-history-guard
cab: reject LZX matches before initialized history
2026-08-08 14:38:09 -05:00
Malachi Moody 9a76681531 cab: reject LZX matches before initialized history 2026-08-08 13:59:18 -05:00
Malachi Moody 88f49e2623 tests: reproduce invalid CAB LZX history reference 2026-08-08 13:59:18 -05:00
Dustin L. Howett 6b89e4f9d6 Merge pull request #3340 from subotac/fix/7zip-ppmd-small-read-buffer
7zip: Track PPMd input across read blocks
2026-08-08 13:10:12 -05:00
Dustin L. Howett eff72295a6 Merge pull request #3354 from subotac/fix/write-close-fatal-state
Return fatal when closing a failed writer
2026-08-08 13:08:07 -05:00
Tobias Stoeckmann 0b42deee05 Merge pull request #3348 from stoeckmann/signature_len
program: Avoid signature length overflow
2026-08-08 17:54:31 +02:00
subotac a6306a2197 7zip: Track PPMd input across read blocks
PPMd pulls input through its byte callback, so the regular input buffer does not track bytes consumed after crossing a read-block boundary. Advance the packed stream using the callback count and reject reads beyond the remaining packed data.

Resolves #3337
2026-08-08 14:48:15 +03:00
subotac f514e28373 7zip: Add PPMd small read block regression test
The fixture and reproducer are based on the archive and report provided by @004helix in #3337.
2026-08-08 14:31:35 +03:00
subotac 2af20746e6 Return fatal when closing a failed writer
Once an archive writer enters the fatal state, close should report that failure instead of proceeding as though it were usable.

Resolves #3353
2026-08-08 14:31:04 +03:00
subotac 0c4749950a tests: Cover closing a failed writer 2026-08-08 14:31:04 +03:00
Dustin L. Howett f7b8423a0a Merge pull request #3363 from dnelson-1901/zero-tm 2026-08-07 22:39:45 -05:00
Dan Nelson 5a813c0282 rar: zero out stack-allocated struct tm before calling mktime()
Caught by valgrind
2026-08-07 21:35:38 -05:00
Dustin L. Howett c63a9d33de Merge pull request #3357 from dnelson-1901/remove-cat
tar: manually combine test files instead of calling cat
2026-08-07 17:58:10 -05:00
Dustin L. Howett 01f717faea Merge pull request #3298 from DHowett/iso9660-nm-loop
iso9660: rewrite the "NM" extension generator for clarity
2026-08-07 17:57:32 -05:00
Dustin L. Howett 2b0e515913 iso9660: rewrite the "NM" extension generator for clarity
There are other such generators in this code, but this one was the
subject of a recent bug. It was unclear how it worked, since it broke
writing the header, continuation and final entries into three different
places.

I feel this version is more intuitive.
2026-08-07 17:01:14 -05:00
Dustin L. Howett 11fe99baf1 Merge pull request #3360 from subotac/fix/windows-empty-wcs-conversion 2026-08-07 16:51:03 -05:00
Tobias Stoeckmann f815fc44e6 lz4/zstd: Count bits in bidder, not bytes
All other filters count bits as bidding result. Do so here as well.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-08-07 22:40:33 +02:00
Tobias Stoeckmann 978a9184ec lz4/zstd: Always check upper bid byte limit
If upstream filter provides huge amount of bytes, e.g. if archive is
fully stored in memory, bidding accesses too many bytes. This could in
turn overflow int return value, possibly leading to signed integer
overflows.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-08-07 22:27:58 +02:00
Tobias Stoeckmann c2c5fffe1c zstd: Remove redundant errno.h include
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-08-07 22:27:33 +02:00
subotac ea6bff4f92 Fix empty wide string conversion on Windows 2026-08-06 21:29:20 +03:00
Dustin L. Howett b3b2f54e10 Merge pull request #3356 from dunhor/windows-clang-fixes
Fix a number of Windows/clang(-cl) issues
2026-08-06 11:38:16 -05:00
Dan Nelson 93fc73f6dc tar: manually combine test files instead of calling cat
Lets the --ignore-zeros tests run on Windows
2026-08-05 21:20:37 -05:00
Dustin L. Howett d07177dcc3 Merge pull request #3341 from subotac/fix/root-absolute-path-test 2026-08-05 20:26:26 -05:00
Duncan Horn f75ed3a205 Fix a number of Windows/clang(-cl) issues 2026-08-05 16:44:08 -07:00
Tim Kientzle ca8b5cdfe3 Merge pull request #3345 from PeiweiHu/peiwei_fix
Fix bsdtar’s `@archive` handling by freeing input readers after open failures and applying passphrases to the correct reader object.
2026-08-03 22:16:19 -07:00
Dustin L. Howett e5a65a5644 Merge pull request #3351 from stoeckmann/support_format
format: Improve format registration error handling
2026-08-03 17:26:03 -05:00
Tobias Stoeckmann af46e0e7b2 format: Unify support_format styles
Use same style across all formats for easier audits.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-08-03 19:57:25 +02:00
Tobias Stoeckmann cb3cd6f09c format: Unify support_format error handling
Always return r to unify style for easier audits.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-08-03 19:57:25 +02:00
Tobias Stoeckmann d42b4c1999 format: Forward errors/warnings in support_format
If registering a format parser bidder fails or triggers a warning,
forward the information instead of silently turning it into ARCHIVE_OK.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-08-03 19:57:25 +02:00
Tobias Stoeckmann a2b7dea95f format: Test error handling in support_format
Make sure that all formats return a warning if registered multiple
times.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-08-03 19:57:25 +02:00
Dustin L. Howett ada220177a Merge pull request #3347 from datauwu/archive-write-share-hdrcharset
archive_write: share hdrcharset option handling
2026-08-03 12:51:31 -05:00
Dustin L. Howett d83294359b Merge pull request #3346 from stoeckmann/append_filter_desync
Always attach filter to correct bidder
2026-08-03 12:48:35 -05:00
Dustin L. Howett 2d91e3a051 Merge pull request #3350 from libarchive/dependabot/github_actions/all-actions-4f142db38a
CI: Bump the all-actions group with 4 updates
2026-08-03 12:07:32 -05:00
dependabot[bot] b3d621f4c3 CI: Bump the all-actions group with 4 updates
Bumps the all-actions group with 4 updates: [github/codeql-action/init](https://github.com/github/codeql-action), [github/codeql-action/autobuild](https://github.com/github/codeql-action), [github/codeql-action/analyze](https://github.com/github/codeql-action) and [github/codeql-action/upload-sarif](https://github.com/github/codeql-action).


Updates `github/codeql-action/init` from 4.37.3 to 4.37.4
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81...f205ea1c3313d32999d8d6a48b4f6530d4437b38)

Updates `github/codeql-action/autobuild` from 4.37.3 to 4.37.4
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81...f205ea1c3313d32999d8d6a48b4f6530d4437b38)

Updates `github/codeql-action/analyze` from 4.37.3 to 4.37.4
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81...f205ea1c3313d32999d8d6a48b4f6530d4437b38)

Updates `github/codeql-action/upload-sarif` from 4.37.3 to 4.37.4
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81...f205ea1c3313d32999d8d6a48b4f6530d4437b38)

---
updated-dependencies:
- dependency-name: github/codeql-action/init
  dependency-version: 4.37.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-actions
- dependency-name: github/codeql-action/autobuild
  dependency-version: 4.37.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-actions
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.37.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-actions
- dependency-name: github/codeql-action/upload-sarif
  dependency-version: 4.37.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-03 16:18:20 +00:00
datauwu 86a88b9edf archive_write: share hdrcharset option handling
Several archive writers duplicate identical hdrcharset option handling.
Share the validation and conversion logic across the affected cpio, tar,
and zip writers.

This reduces duplication without changing behavior.
2026-08-03 16:53:58 +08:00
Dustin L. Howett c706ac4b56 Merge pull request #3312 from datauwu/formats-use-strrchr 2026-08-02 23:53:08 -05:00
Peiwei Hu 337e5fcd0c bsdtar: apply passphrase to appended archive reader
When creating an archive from an @archive argument, configure the
input reader rather than passing the output writer to
archive_read_add_passphrase(). Use the reader for error reporting as
well.
2026-08-03 08:49:58 +08:00
Peiwei Hu 7bd12a903f bsdtar: test passphrase for appended archives
Exercise --passphrase while copying entries from an encrypted
@archive into a new archive, then extract the result and verify the
copied file contents.
2026-08-03 08:49:51 +08:00
Tobias Stoeckmann daac5d8de0 program: Avoid signature length overflow
If a signature is too large, the bid value could overflow INT_MAX. With
its current implementation, it could even lead to a signed integer
overflow, which is undefined behavior.

Disallow huge signatures, which most likely won't impact anyone.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-08-02 22:12:56 +02:00
Peiwei Hu 0d71fa2ad7 bsdtar: free reader after failed archive open
append_archive_filename() returns after reporting an input archive open
failure so archive creation can continue. Release the input archive
reader before returning to avoid accumulating one reader for every
failed @archive argument.
2026-08-02 23:02:10 +08:00
Tim Kientzle 0c353e1a8f Merge pull request #3343 from dnelson-1901/tar-mode
tar: add --mode option for GNU tar compatibility
2026-08-02 07:34:39 -07:00
Tobias Stoeckmann 7c7d41c13c Remove bidder name
The name was only needed to find the appropriate bidder for a filter.
Since this has been resolved by accessing the last bidder, since in these
situations the bidder is added first, then the filter, the name is not
needed anymore.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-08-02 15:13:35 +02:00
Tobias Stoeckmann 50b585bb55 append_filter: Use last bidder for filter
Appending a filter implies appending a bidder. Always use the last added
bidder, since it was just added. This avoids desync situations where
previously added bidders could erroneously match.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-08-02 15:13:33 +02:00
Tobias Stoeckmann bf1f5ba79e append_filter: Verify that bidder and filter match
Make sure that appending a filter always matches its supposed bidder.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-08-02 15:12:59 +02:00
Dan Nelson c26faff361 tar: handle --mode when extracting archives also 2026-08-01 15:11:08 -05:00
Dan Nelson e8154e0bfc tar: add --mode option (compatible with gnutar) 2026-08-01 15:11:08 -05:00
Tim Kientzle e893064acf Merge pull request #3344 from datauwu/warc-fix-ub
warc: fix UB signed overflow in time conversion
2026-08-01 12:58:35 -07:00
datauwu c84de7963c warc: fix UB signed overflow in time conversion
Use checked 64-bit math when timegm() is not available.
Reject values outside time_t instead of overflowing signed integers.
2026-08-02 03:04:20 +08:00
datauwu 535360bfeb warc: test future date conversion
Add a WARC date after 2038 to cover the fallback time conversion.
On 64-bit time_t, it must parse as the expected Unix timestamp.
2026-08-02 02:57:01 +08:00
Tim Kientzle ea476d962f Merge pull request #3342 from datauwu/bsdcpio-fix-ub
bsdcpio: fix UB signed overflow in time formatting
2026-08-01 08:54:01 -07:00
datauwu 0da2e229b1 bsdtar: fix UB signed overflow in time formatting
Use difftime() instead of changing time_t values by the half-year
range. This avoids signed overflow near the time_t limits without
changing normal output.
2026-08-01 19:48:39 +08:00
datauwu efa19ce699 bsdcpio: fix UB signed overflow in time formatting
Use difftime() instead of subtracting time_t values when choosing the
date format. This avoids signed overflow for far past or future
timestamps without changing normal output.
2026-08-01 19:48:38 +08:00
subotac abba713e8e Clarify absolute path test extraction roots 2026-07-31 20:26:23 +03:00
Dustin L. Howett 8c4acda5e7 Merge pull request #3335 from jaipaulcheernam/fix/skip-ppmd8-aes256-test-without-crypto 2026-07-31 09:22:42 -05:00
Dustin L. Howett 280402b7f1 Merge pull request #3339 from datauwu/archive-string-fix-build 2026-07-30 18:21:32 -05:00
subotac 83a023ee30 Fix absolute path test when run as root 2026-07-30 18:40:17 +03:00
datauwu fcf3d40b3b archive_string: require localcharset.h for locale_charset
Only call locale_charset() when localcharset.h provides its declaration.
2026-07-30 16:20:51 +08:00
Jaipaul Cheernam c2b00a5fff test: skip ppmd8 aes256 streaming test when no crypto library is present
test_read_format_zip_ppmd8_aes256_streaming fails with 6 assertion
failures on systems without a crypto library (openssl/nettle/mbedtls)
because it tries to decrypt a pre-built encrypted zipx file without
checking crypto availability first.

Add the same guard used by the other encrypted zip tests in this file.

Signed-off-by: Jaipaul Cheernam <jaipaul.cheernam@est.tech>
2026-07-29 13:37:21 +00:00
Dustin L. Howett 19ff56da4f Merge pull request #3320 from carrerasdarren-cell/fix/iso9660-boot-image-size-overflow
iso9660: avoid boot image block count overflow
2026-07-28 14:32:46 -05:00
carrerasdarren-cell f648978feb iso9660: avoid boot image block count overflow
Use overflow-free ceiling division before narrowing the boot image block count to int.

Fixes #3269
2026-07-28 14:53:36 -04:00
Dustin L. Howett 40da2cdc52 Merge pull request #3315 from datauwu/iso9660-remove-per-reader-comp-buf
iso9660: remove per-reader zero comparison buffer
2026-07-27 17:12:53 -05:00
Dustin L. Howett 10ea0e7499 Merge pull request #3302 from datauwu/program-read-fix-uaf
program: fix dangling pointer after close
2026-07-27 17:12:20 -05:00
Dustin L. Howett e207c4b357 Merge pull request #3317 from stoeckmann/rar5_varint
rar5: Improve varint handling
2026-07-27 16:08:31 -05:00
Tim Kientzle 4c5854ed69 Merge pull request #3329 from dag-erling/des/xar-unsup-digest
xar: Fix for unsupported digests
2026-07-27 12:36:40 -07:00
Dustin L. Howett ca6e125867 Merge pull request #3325 from tbontb-iaq/fix/seek-data-null-not-fatal
archive_read: don't poison archive when format lacks seek_data (fixes #3323)
2026-07-27 14:24:12 -05:00
Dag-Erling Smørgrav 4acbc50d7d xar: Fix for unsupported digests
* In _checksum_init() and _checksum_final(), fail if the requested digest
  is not supported (e.g. archive uses SHA256 but libarchive was compiled
  without SHA256 support)

* In checksum_init(), fail with a meaningful error message if either
  _checksum_init() call fails.

* In checksum_final(), simplify the logic and improve the error message.

* Make the various digest tests conditional on support for the digest
  being tested.

Fixes:		6f10adcd59 ("xar: Add support for SHA256 and SHA512")
2026-07-27 21:02:23 +02:00
Dustin L. Howett 3e6d656c80 Merge pull request #3322 from datauwu/warc-writer-unify
warc: match other writer styles
2026-07-27 13:43:51 -05:00
Tim Kientzle b722e2cccc Merge pull request #3328 from dag-erling/des/xar-sha2
xar: Add support for SHA256 and SHA512
2026-07-27 11:20:21 -07:00
Dag-Erling Smørgrav 6f10adcd59 xar: Add support for SHA256 and SHA512
Extend the xar reader and writer to understand the SHA256 (header
cksum_alg 3, 32 bytes, style "sha256") and SHA512 (cksum_alg 4, 64
bytes, style "sha512") checksum algorithms in addition to the existing
SHA1 and MD5.  These are the algorithm codes defined by the canonical
xar format, so archives written with them interoperate with Apple's xar,
pkgutil, and PackageKit.

Both the TOC ("toc-checksum") and per-file ("checksum") algorithms are
supported for writing.  New algorithm handling is guarded by
ARCHIVE_HAS_SHA256 / ARCHIVE_HAS_SHA512 so builds without those digests
are unaffected.  MAX_SUM_SIZE grows from 20 to 64 to hold a SHA512
digest.
2026-07-27 19:28:21 +02:00
Dustin L. Howett 4d3bfca239 Merge pull request #3327 from libarchive/dependabot/github_actions/all-actions-413c1c7ad7
CI: Bump the all-actions group with 6 updates
2026-07-27 12:01:12 -05:00
Jin 79b06edf6e archive_read: don't poison archive when seek is unsupported (fixes #3323)
3.8.8 ("make ARCHIVE_FATAL sticky in data-reading entry points",
commit e1f890dc) made archive_seek_data() set
a->archive.state = ARCHIVE_STATE_FATAL whenever the call returned
ARCHIVE_FATAL.  That is correct for genuine I/O / parse failures
returned by a format's seek_data() implementation, but it also
poisoned the archive in two cases where seeking is simply
unsupported for the current format:

  1. The seek_data == NULL branch in archive_seek_data() itself
     (no format_seek_data_block registered: ustar/tar, the
     streaming ZIP reader, ...).

  2. rar5_seek_data() in archive_read_support_format_rar5.c, which
     unconditionally returns ARCHIVE_FATAL because RAR5 is a
     streaming unpacker.  This was latent before 3.8.8 because
     the read core did not make FATAL sticky; the stickiness
     change exposed it.

Both are capability gaps, not stream corruption.  ARCHIVE_FATAL
must always be sticky (it means the archive is irrecoverably
damaged), so both sites now return ARCHIVE_FAILED with an error
string instead.  ARCHIVE_FAILED is recoverable: capability probes
such as

    if (archive_seek_data(a, 0, SEEK_CUR) >= 0) ...

learn that seeking is unavailable while the archive remains
usable for subsequent reads.  The sticky-on-genuine-FATAL part of
the original 3.8.8 change is preserved for actual ARCHIVE_FATAL
returns from a format's seek_data() implementation.

The seek_data == NULL branch also reports the condition better: a
format that never registers a seek hook is not illegal use of the
library, so the error is now ARCHIVE_ERRNO_MISC / "Cannot seek
data with this format" instead of ARCHIVE_ERRNO_PROGRAMMER /
"Internal error: No format_seek_data_block function registered".

The rar5 change also matches how the RAR4 reader already reports
the same situation (archive_read_support_format_rar.c:1339
returns ARCHIVE_FAILED for compressed RAR files).

This restores 3.8.7 behaviour for clients that probe seekability
before reading.  VLC's skins2 stream extractor
(modules/stream_extractor/archive.c, archive_seek_subentry())
probes with archive_seek_data(a, 0, SEEK_CUR); on a non-seekable
format the poisoned state killed all later archive_read_data()
calls, breaking ZIP-packed .vlt skins on distributions shipping
libarchive 3.8.8.

Tests:
  - test_archive_seek_data_unsupported: covers the seek_data==NULL
    branch using a ustar archive.
  - test_read_format_rar5_seek_data_unsupported: covers the
    rar5_seek_data() branch using an existing RAR5 fixture, and
    verifies the entry content with verify_data() after the probe.
  Both fail on master and pass with this change.
2026-07-28 00:30:34 +08:00
dependabot[bot] a8de0156d4 CI: Bump the all-actions group with 6 updates
Bumps the all-actions group with 6 updates:

| Package | From | To |
| --- | --- | --- |
| [acj/freebsd-firecracker-action](https://github.com/acj/freebsd-firecracker-action) | `0.10.4` | `0.11.0` |
| [github/codeql-action/init](https://github.com/github/codeql-action) | `4.37.1` | `4.37.3` |
| [github/codeql-action/autobuild](https://github.com/github/codeql-action) | `4.37.1` | `4.37.3` |
| [github/codeql-action/analyze](https://github.com/github/codeql-action) | `4.37.1` | `4.37.3` |
| [ossf/scorecard-action](https://github.com/ossf/scorecard-action) | `2.4.3` | `2.4.4` |
| [github/codeql-action/upload-sarif](https://github.com/github/codeql-action) | `4.37.1` | `4.37.3` |


Updates `acj/freebsd-firecracker-action` from 0.10.4 to 0.11.0
- [Release notes](https://github.com/acj/freebsd-firecracker-action/releases)
- [Commits](https://github.com/acj/freebsd-firecracker-action/compare/0fe13161c7d388eed0570eac668e1ba8fc1f1e4e...e04896d2dd91f7ec7381e5f363c6fbe83ee445c3)

Updates `github/codeql-action/init` from 4.37.1 to 4.37.3
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/7188fc363630916deb702c7fdcf4e481b751f97a...e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81)

Updates `github/codeql-action/autobuild` from 4.37.1 to 4.37.3
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/7188fc363630916deb702c7fdcf4e481b751f97a...e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81)

Updates `github/codeql-action/analyze` from 4.37.1 to 4.37.3
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/7188fc363630916deb702c7fdcf4e481b751f97a...e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81)

Updates `ossf/scorecard-action` from 2.4.3 to 2.4.4
- [Release notes](https://github.com/ossf/scorecard-action/releases)
- [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md)
- [Commits](https://github.com/ossf/scorecard-action/compare/4eaacf0543bb3f2c246792bd56e8cdeffafb205a...2d1146689b8cda280b9bc96326124645441f03bc)

Updates `github/codeql-action/upload-sarif` from 4.37.1 to 4.37.3
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/7188fc363630916deb702c7fdcf4e481b751f97a...e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81)

---
updated-dependencies:
- dependency-name: acj/freebsd-firecracker-action
  dependency-version: 0.11.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-actions
- dependency-name: github/codeql-action/init
  dependency-version: 4.37.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-actions
- dependency-name: github/codeql-action/autobuild
  dependency-version: 4.37.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-actions
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.37.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-actions
- dependency-name: ossf/scorecard-action
  dependency-version: 2.4.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-actions
- dependency-name: github/codeql-action/upload-sarif
  dependency-version: 4.37.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-27 16:13:38 +00:00
datauwu a96851a161 warc: name local variables
Replace short local names with clear names.

Match the common writer layout and return style.
2026-07-27 17:30:52 +08:00
carrerasdarren-cell 6ccaddb831 iso9660: test large no-emulation boot image 2026-07-23 11:20:41 -04:00
datauwu a1f1de994e warc: name helper functions
Give private helpers clear WARC names.

Make the UUID helper return void.
2026-07-23 22:07:11 +08:00
datauwu d4aa000ea5 warc: name internal types and fields
Replace short names with clear WARC names.

Move the header size limit to file scope.
2026-07-23 22:07:11 +08:00
datauwu 2a672716cc warc: use writer callback names
Use the same callback form as other format writers.

Clean the prototypes and remove old section marks.
2026-07-23 22:07:11 +08:00
datauwu 454168772b program: fix dangling pointer after close
Store the program filter description in the bidder state instead of the
active filter state.

The active state is freed by archive_read_close(), while the bidder state
remains valid until archive_read_free(). This keeps archive_filter_name()
from returning a dangling pointer.
2026-07-22 03:12:04 +08:00
datauwu 6cab05dbd5 program: test filter name after close
Verify that the external program filter name remains available after
archive_read_close().
2026-07-22 03:12:04 +08:00
Dustin L. Howett f5509ae993 Merge pull request #3299 from datauwu/tar-read-fix-uaf
tar: fix UAF when reading GNU sparse headers
2026-07-21 13:13:03 -05:00
Dustin L. Howett 0b71b606dd Merge commit from fork
Fix RAR seek_data cursor underflow
2026-07-21 12:55:13 -05:00
Dustin L. Howett 8dec814f98 Merge pull request #3318 from carrerasdarren-cell/fix/mac-metadata-self-copy-uaf
archive_entry: handle aliased Mac metadata copies
2026-07-21 12:48:06 -05:00
carrerasdarren-cell a8bff73641 archive_entry: handle aliased Mac metadata copies 2026-07-21 11:54:13 -04:00
carrerasdarren-cell 925a3a385f archive_entry: test aliased Mac metadata copies 2026-07-21 11:54:05 -04:00
datauwu b76db24481 xar: use strrchr to find parent directories
Replace the manual pathname scan with strrchr when locating the
parent directory.
2026-07-21 17:43:15 +08:00
datauwu 2a8a284212 mtree: use strrchr to find parent directories
Replace the manual pathname scan with strrchr when locating the
parent directory.
2026-07-21 17:43:15 +08:00
datauwu 4a448d488c mtree: use archive_string_dirname to roll back paths
Replace the manual reverse scan with archive_string_dirname while
preserving the empty path representation.
2026-07-21 17:43:14 +08:00
datauwu b15a0a0bb5 iso9660: remove per-reader zero comparison buffer
Check reserved fields by comparing adjacent bytes after confirming the
first byte is zero. This preserves the memcmp fast path and removes
2 KiB from each ISO9660 reader state.
2026-07-21 17:07:05 +08:00
Dustin L. Howett 33da30bd9c Merge pull request #3316 from libarchive/dependabot/github_actions/all-actions-3c55da1aaa
CI: Bump the all-actions group with 6 updates
2026-07-20 19:36:20 -05:00
Tobias Stoeckmann 38fbee2e21 rar5: Improve varint handling
A varint field can actually have up to 10 bytes to resemble whole 64 bit
of a value. Use checked arithmetic to detect integer overflows.

Also, treat a varint which never has a byte without continuation bit as
faulty.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-20 19:03:22 +02:00
dependabot[bot] c52c7ed6fc CI: Bump the all-actions group with 6 updates
Bumps the all-actions group with 6 updates:

| Package | From | To |
| --- | --- | --- |
| [acj/freebsd-firecracker-action](https://github.com/acj/freebsd-firecracker-action) | `0.10.3` | `0.10.4` |
| [actions/checkout](https://github.com/actions/checkout) | `7.0.0` | `7.0.1` |
| [github/codeql-action/init](https://github.com/github/codeql-action) | `4.37.0` | `4.37.1` |
| [github/codeql-action/autobuild](https://github.com/github/codeql-action) | `4.37.0` | `4.37.1` |
| [github/codeql-action/analyze](https://github.com/github/codeql-action) | `4.37.0` | `4.37.1` |
| [github/codeql-action/upload-sarif](https://github.com/github/codeql-action) | `4.37.0` | `4.37.1` |


Updates `acj/freebsd-firecracker-action` from 0.10.3 to 0.10.4
- [Release notes](https://github.com/acj/freebsd-firecracker-action/releases)
- [Commits](https://github.com/acj/freebsd-firecracker-action/compare/53cfec625fd81cfb34160e6d9ec19c9d9baa8adf...0fe13161c7d388eed0570eac668e1ba8fc1f1e4e)

Updates `actions/checkout` from 7.0.0 to 7.0.1
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0...3d3c42e5aac5ba805825da76410c181273ba90b1)

Updates `github/codeql-action/init` from 4.37.0 to 4.37.1
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/99df26d4f13ea111d4ec1a7dddef6063f76b97e9...7188fc363630916deb702c7fdcf4e481b751f97a)

Updates `github/codeql-action/autobuild` from 4.37.0 to 4.37.1
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/99df26d4f13ea111d4ec1a7dddef6063f76b97e9...7188fc363630916deb702c7fdcf4e481b751f97a)

Updates `github/codeql-action/analyze` from 4.37.0 to 4.37.1
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/99df26d4f13ea111d4ec1a7dddef6063f76b97e9...7188fc363630916deb702c7fdcf4e481b751f97a)

Updates `github/codeql-action/upload-sarif` from 4.37.0 to 4.37.1
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/99df26d4f13ea111d4ec1a7dddef6063f76b97e9...7188fc363630916deb702c7fdcf4e481b751f97a)

---
updated-dependencies:
- dependency-name: acj/freebsd-firecracker-action
  dependency-version: 0.10.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-actions
- dependency-name: actions/checkout
  dependency-version: 7.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-actions
- dependency-name: github/codeql-action/init
  dependency-version: 4.37.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-actions
- dependency-name: github/codeql-action/autobuild
  dependency-version: 4.37.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-actions
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.37.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-actions
- dependency-name: github/codeql-action/upload-sarif
  dependency-version: 4.37.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-20 16:13:42 +00:00
Dustin L. Howett 3a8f29903f Merge pull request #3306 from stoeckmann/data 2026-07-20 10:25:52 -05:00
Tobias Stoeckmann 5a2330788e Generally use f for filter
If there is no good reason to deviate from the rule, always use "f" for
filter just as we use "a" for archive.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-20 08:55:51 +02:00
Tobias Stoeckmann 88df4c92f7 filter: Use f as filter variable name
- If filter is meant, use "f" instead of "self" or "filter".
- If bidder is meant, use "b" instead of "self".

Matches writer filter style.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-20 08:55:51 +02:00
Tobias Stoeckmann 12ba7fdf05 Unify filter data access names
Use "struct filter *filter" pattern, with filter being the name of the
filter. This matches the format parser pattern.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-20 08:55:51 +02:00
Tobias Stoeckmann 11b87598ce shar: Merge format setters
Clarify where the differences between the format setters are.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-20 08:55:51 +02:00
Tobias Stoeckmann 9f62f96798 Unify filter data handling
- Declare access variable at the beginning
- Remove unneeded cast

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-20 08:55:51 +02:00
Tobias Stoeckmann 6c3bab2480 Unify format data access names
It's generally the pattern "struct format *format". Unify for easier
readability.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-20 08:55:50 +02:00
Tobias Stoeckmann a631287e4c Unify format data handling
- Declare access variable at the beginning
- Remove unneeded cast (see warc parser, which never did it)
- Remove inline cast function
- Avoid unneeded brackets to unify style

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-20 08:55:25 +02:00
Tim Kientzle 4840347569 Merge pull request #616 from chenxiaolong/android-utf8
Force UTF-8 as the default charset on Android
2026-07-19 15:46:59 -07:00
Tim Kientzle 097119fc0f Merge pull request #3308 from datauwu/warc-reject-truncated-file-data
warc: reject truncated file data
2026-07-19 15:33:19 -07:00
Tim Kientzle e26d91cef1 Merge pull request #3309 from stoeckmann/write_huge
write: Correctly handle huge write requests
2026-07-19 15:28:53 -07:00
Tobias Stoeckmann 29dd9c909b write: Use uint64_t for __archive_write_nulls
Even though int64_t would be the correct data type because no more data
than INT64_MAX can be written, use the easier solution for format
writers for now.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-19 23:08:26 +02:00
Tobias Stoeckmann 0543fc1320 write: Do not write more than INT64_MAX bytes
Never try to write more than INT64_MAX bytes to avoid integer overflows.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-19 23:08:26 +02:00
Tobias Stoeckmann 91fa66073e tar: Verify that huge files are not written
Files which cannot fit into a stream should never return success, which
can happen due to truncation on 32 bit systems.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-19 23:07:44 +02:00
datauwu 402d829d2f warc: reject truncated file data
Return ARCHIVE_FATAL when EOF is reached before Content-Length.
2026-07-20 01:35:04 +08:00
datauwu 9fa66d8fe0 warc: test truncated file data
Verify that a body shorter than Content-Length is rejected.
2026-07-20 01:25:10 +08:00
Tim Kientzle e70bf490b8 Merge pull request #3301 from datauwu/zip-remove-redundant-helper
zip: remove redundant helper
2026-07-19 08:47:07 -07:00
Tim Kientzle cb550d2791 Merge pull request #3303 from datauwu/xar-write-fix-null-deref
xar: fix NULL dereference on allocation failure
2026-07-19 08:41:27 -07:00
Tim Kientzle ae8f0ccceb Merge pull request #3305 from datauwu/formats-various-cleanup
formats: simplify string handling
2026-07-19 08:39:55 -07:00
Tim Kientzle 30708c06c8 Merge pull request #3307 from stoeckmann/warc_digit
warc: Avoid `isdigit` in version number check
2026-07-19 08:03:20 -07:00
0xmrniko e548c99423 Guard RAR seek cursor before previous block lookup 2026-07-19 19:30:23 +05:30
0xmrniko f3d21565cb Add RAR seek_data cursor regression test 2026-07-19 19:30:18 +05:30
Tobias Stoeckmann 8827bc3016 warc: Avoid isdigit in version number check
The isdigit function is locale-dependent, which means that characters
outside of 0-9 range can return true here, e.g. "power of 2" for a few
locales on Windows.

Test for ASCII character range from '0' to '9' instead.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-19 13:46:06 +02:00
datauwu 888d25b754 pax: use memcpy for known-length path components
Use memcpy() for path components whose lengths are already known and
write the terminating null byte explicitly.

Cache the inserted component length instead of calculating it multiple
times while constructing the ustar pathname.
2026-07-19 18:01:44 +08:00
datauwu 70a04a84cc ar: use strrchr for member filenames
Replace the single-use basename helper with strrchr() and preserve the
existing rejection of pathnames ending in a slash.

Cache the member filename length to avoid repeated strlen() calls while
building and writing the archive header.
2026-07-19 18:01:44 +08:00
datauwu e9fcf44e02 rar: avoid rescanning converted path separators
Continue searching after each replaced backslash instead of restarting
from the beginning of the filename.

This avoids repeatedly scanning the already converted prefix.
2026-07-19 12:15:48 +08:00
datauwu 3cc1738058 lha: use memchr to validate filenames
Replace the bytewise filename scan with memchr() when checking for the
invalid 0xff byte.

The search remains bounded by the filename length.
2026-07-19 03:07:34 +08:00
datauwu 5cb553dbcb xar: fix NULL dereference on allocation failure
Check the allocation used to initialize cur_dirstr before accessing the
buffer.

Release the partially initialized strings, root entry, file registry,
and hardlink registry before returning ARCHIVE_FATAL.
2026-07-19 00:28:32 +08:00
datauwu 5a822798ff tar: fix UAF when reading GNU sparse headers
Copy the old GNU tar header before reading sparse extension blocks.

Those reads may replace or free the callback buffer backing the original
header. Use the copy when parsing the common header fields.
2026-07-18 23:31:40 +08:00
datauwu ee5715fc82 zip: remove redundant helper
Calculate the pathname length directly after validating the path.

The helper only wrapped strlen() and adjusted the length for directory
entries. Removing it keeps the calculation beside the validation and
reuses the existing file type value.
2026-07-18 19:19:45 +08:00
datauwu dc81f68c6f tar: add GNU sparse header buffer reuse test
Add a test archive that reuses one read buffer for every 512-byte block.

Reading the sparse extension overwrites the main GNU header. Check that
mode, uid, gid, and mtime still come from the original header.
2026-07-18 15:48:44 +08:00
Dustin L. Howett 84fbafad32 Merge pull request #3292 from datauwu/xar-fix-mem-leaks
xar: fix several memory leaks
2026-07-17 17:51:23 -05:00
Dustin L. Howett d141f661da Merge pull request #3297 from datauwu/archive-write-fix-uaf
archive_write: fix UAF when switching formats
2026-07-17 15:17:29 -05:00
Dustin L. Howett 10a7247810 Merge pull request #3294 from datauwu/bsdtar-fix-signed-overflow 2026-07-17 14:06:56 -05:00
Dustin L. Howett b85488c37a Merge pull request #3296 from stoeckmann/filter_writer 2026-07-17 14:04:59 -05:00
datauwu 17fc2be73a bsdtar: remove tar_i64toa()
Format integer values directly at each call site and remove the custom
integer formatter.

This handles the full signed integer range and preserves unsigned byte
counters.
2026-07-18 02:09:50 +08:00
datauwu 975ea4dbd9 archive_write: fix UAF when switching formats
Clear format state and callbacks after running the previous format
destructor so a failed replacement setup cannot leave stale pointers.

Also unregister previous GNU tar state and require ARCHIVE_STATE_NEW
before switching to GNU tar.
2026-07-18 01:27:25 +08:00
Dustin L. Howett 47d94d1f92 Merge pull request #3295 from stoeckmann/typos_2
Fix typos
2026-07-17 12:03:55 -05:00
Tobias Stoeckmann 66e5b3e5d7 uuencode: Fix typo
Add missing "encode" to magic error message.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-17 19:02:35 +02:00
Tobias Stoeckmann 727da55204 filter: Unify add_filter style
This makes it easier to spot differences, which might require more
attention.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-17 19:02:35 +02:00
Tobias Stoeckmann 421b6c267d filter: Check __archive_write_allocate_filter result
If allocation of filter fails, gracefully handle it instead of
eventually triggering a NULL pointer dereference.

Allocate the filter in last step, because it's rather difficult to
cleanly revert in case of error.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-17 19:02:35 +02:00
Tobias Stoeckmann b2a38b8845 xz: Merge more common code into common_setup
Reduces complexity of individual functions.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-17 19:02:35 +02:00
Tobias Stoeckmann dfc4357a74 filter: Simplify archive handling
Use archive for magic check and logging directly.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-17 19:02:35 +02:00
Tobias Stoeckmann 42584eb62f compress: Allocate data while adding filter
This syncs compress write filter with other write filters.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-17 19:02:27 +02:00
datauwu 9c805a24ea archive_write: test format switch UAF cleanup
Test that unregistering 7-Zip and XAR clears format state and is safe
to repeat.

Also test switching from 7-Zip to GNU tar and selecting GNU tar again.
2026-07-18 00:05:01 +08:00
Tobias Stoeckmann c2ebb602e9 filter: Set function pointers in add_filter
Set function pointers in add filter functions, not in open.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-17 17:43:15 +02:00
Tobias Stoeckmann 860365a3f0 filter: Free data in its own function
Create free_data function for later reusing.
Also make sure that f->data is always set to NULL.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-17 17:43:15 +02:00
Tobias Stoeckmann 48e77da188 filter: Do not set filter data redundantly
There is no need to assign fields again if they do not change.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-17 17:43:15 +02:00
Tobias Stoeckmann c74bb50661 Fix typos
Typos found with codespell.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-17 08:49:17 +02:00
Tobias Stoeckmann 8992885932 Fix typos
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-17 08:49:12 +02:00
Dustin L. Howett 0362c77f9f Merge pull request #3293 from DHowett/iso9660-nmlen 2026-07-16 11:10:07 -05:00
Dustin L. Howett fd36d37a6c iso9660: always recalculate remaining extra space writing multi-part NM
Writing an iso archive with a series of long names in it would eventually
cause an out-of-bounds write off the end of the rockridge extra data.

This happened when we allocated a net-new block for a file with a name
longer than would fit in two records spanning multiple blocks. We would:

- Fill up the extra_space in the last block
- Allocate a new block
- Write 250 + 5 (header) bytes of the name into it
- Try to copy 250 _more_ bytes out of the name, even if we did not have
  space left.
2026-07-15 15:07:29 -05:00
Dustin L. Howett 1a9e48f6b8 iso9660: add a test for repeated long-named files blowing up RR blocks 2026-07-15 15:07:29 -05:00
datauwu 9b1746f63a xar: clean xattr checksum on encoder setup failure
Finalize the remaining xattr checksum context if encoder setup fails.
2026-07-15 22:34:03 +08:00
datauwu c318e8fac6 xar: clean xattr checksums on heap allocation failure
Finalize xattr checksum contexts if the xattr heap allocation fails.
2026-07-15 22:34:02 +08:00
datauwu 8abb31c630 xar: free virtual files on tree insert failure
Free both unlinked files when virtual-parent name generation fails.
2026-07-15 22:34:02 +08:00
datauwu 2c0d2c259e xar: clean checksums on encoder setup failure
Finalize both file checksum contexts if encoder setup fails after init.
2026-07-15 22:34:02 +08:00
datauwu 2fc84234cf xar: free write file on utility-name failure
Free the pending write file when utility name generation fails early.
2026-07-15 22:34:01 +08:00
datauwu d8040bff17 xar: free new read file when heap insertion fails
Restore the parent and free the unqueued file after heap insertion fails.
2026-07-15 22:34:01 +08:00
datauwu 2baeb07843 xar: free current read file on entry string ENOMEM
Free the popped xar_file before returning on metadata-copy ENOMEM.
2026-07-15 22:34:01 +08:00
Dustin L. Howett 87f72b5e6a Merge pull request #3243 from datauwu/tar-prefer-native-appledouble
tar: prefer multibyte pathname for AppleDouble checks
2026-07-14 14:58:23 -05:00
Dustin L. Howett bd57e425f1 Merge pull request #3290 from stoeckmann/cab_skip
cab: Check `__archive_read_consume` result
2026-07-14 14:55:29 -05:00
Tobias Stoeckmann d1c8cca883 cab: Check __archive_read_consume result
The bytes were not previously read, so check result of
__archive_read_consume.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-14 20:29:55 +02:00
Dustin L. Howett 8d66ccf261 Merge pull request #3289 from uchiha-bug-hunter/pax-base64-checked-size 2026-07-14 10:44:07 -05:00
Dustin L. Howett 9e0bae9458 Merge pull request #3284 from datauwu/warc-propagate-generated-header-errors
warc: propagate generated header errors
2026-07-14 08:38:29 -05:00
Kaif Khan 992cf1fc0b pax: use checked size arithmetic in base64_encode 2026-07-14 18:46:00 +05:30
datauwu c9e90b0ba7 tar: prefer multibyte pathname for AppleDouble checks
AppleDouble detection only needs to inspect the final path component for
the "._" prefix.

Check the multibyte pathname first on all platforms and only fall back to
WCS when the multibyte pathname is unavailable. This avoids unnecessary
wide-character pathname conversion for ordinary tar entries when mac-ext
handling is enabled.

Entries without an available pathname now return no match instead of
ARCHIVE_FAILED from the boolean check.
2026-07-14 16:59:06 +08:00
Dustin L. Howett d5a15c706c Merge pull request #3264 from stoeckmann/options_const
options: Use const char pointer where possible
2026-07-13 19:22:46 -05:00
Dustin L. Howett ed6475a64c Merge pull request #3247 from stoeckmann/strnlen
Use strnlen if available
2026-07-13 19:15:34 -05:00
Dustin L. Howett a6a899d655 Merge pull request #3278 from uchiha-bug-hunter/cpio-trailer-uaf
cpio: add regression test for symlink-trailer end-of-archive check
2026-07-13 12:03:30 -05:00
Dustin L. Howett 03b665040a Merge pull request #3287 from libarchive/dependabot/github_actions/all-actions-bfcd148bc6
CI: Bump the all-actions group across 1 directory with 5 updates
2026-07-13 11:42:11 -05:00
dependabot[bot] 9fe5719d4d CI: Bump the all-actions group across 1 directory with 5 updates
Bumps the all-actions group with 5 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [acj/freebsd-firecracker-action](https://github.com/acj/freebsd-firecracker-action) | `0.10.1` | `0.10.3` |
| [github/codeql-action/init](https://github.com/github/codeql-action) | `4.36.2` | `4.37.0` |
| [github/codeql-action/autobuild](https://github.com/github/codeql-action) | `4.36.2` | `4.37.0` |
| [github/codeql-action/analyze](https://github.com/github/codeql-action) | `4.36.2` | `4.37.0` |
| [github/codeql-action/upload-sarif](https://github.com/github/codeql-action) | `4.36.2` | `4.37.0` |



Updates `acj/freebsd-firecracker-action` from 0.10.1 to 0.10.3
- [Release notes](https://github.com/acj/freebsd-firecracker-action/releases)
- [Commits](https://github.com/acj/freebsd-firecracker-action/compare/da029f050a7a2535fce96385727cf3d5768bd8bf...53cfec625fd81cfb34160e6d9ec19c9d9baa8adf)

Updates `github/codeql-action/init` from 4.36.2 to 4.37.0
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/8aad20d150bbac5944a9f9d289da16a4b0d87c1e...99df26d4f13ea111d4ec1a7dddef6063f76b97e9)

Updates `github/codeql-action/autobuild` from 4.36.2 to 4.37.0
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/8aad20d150bbac5944a9f9d289da16a4b0d87c1e...99df26d4f13ea111d4ec1a7dddef6063f76b97e9)

Updates `github/codeql-action/analyze` from 4.36.2 to 4.37.0
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/8aad20d150bbac5944a9f9d289da16a4b0d87c1e...99df26d4f13ea111d4ec1a7dddef6063f76b97e9)

Updates `github/codeql-action/upload-sarif` from 4.36.2 to 4.37.0
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/8aad20d150bbac5944a9f9d289da16a4b0d87c1e...99df26d4f13ea111d4ec1a7dddef6063f76b97e9)

---
updated-dependencies:
- dependency-name: acj/freebsd-firecracker-action
  dependency-version: 0.10.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-actions
- dependency-name: github/codeql-action/init
  dependency-version: 4.37.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-actions
- dependency-name: github/codeql-action/autobuild
  dependency-version: 4.37.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-actions
- dependency-name: github/codeql-action/analyze
  dependency-version: 4.37.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-actions
- dependency-name: github/codeql-action/upload-sarif
  dependency-version: 4.37.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-13 16:13:35 +00:00
Tim Kientzle 46e9236e4e Merge pull request #3272 from daandemeyer/push-kysumqozmsuq
pax: add "align" write option for reflink-friendly archives
2026-07-13 07:53:21 -07:00
Tim Kientzle 6bbaf0ad41 Merge pull request #3286 from uchiha-bug-hunter/xar-parse-time-overread
xar: fix one-byte over-read in parse_time date parser
2026-07-13 07:36:17 -07:00
Kaif Khan 54b7f1f679 xar: fix one-byte over-read in parse_time date parser 2026-07-13 19:31:09 +05:30
datauwu 4291ca15b1 warc: clarify resource header size error
Use a more specific error when resource header generation fails.

The old message said `cannot archive file`, but this path fails when
the generated WARC resource header exceeds the internal limit.
2026-07-13 16:52:33 +08:00
datauwu aeee33085d warc: propagate generated header errors
Check generated WARC header creation and writes.

Fail when the generated warcinfo header cannot be built. Treat a
resource header build failure as fatal because output may already exist.

Propagate write errors instead of marking the record as written.
2026-07-13 16:52:31 +08:00
datauwu aefecf2fc2 warc: test generated header write errors
Add memory-writer tests for generated WARC header write failures.

Cover both the warcinfo header and a resource header with warcinfo
disabled. These tests show that header write failures are hidden.
2026-07-13 16:52:25 +08:00
Daan De Meyer 7d53dd2b49 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.

Signed-off-by: Daan De Meyer <daan@amutable.com>
2026-07-13 09:47:24 +02:00
Kaif Khan b76abee5b1 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.
2026-07-13 11:44:09 +05:30
Dustin L. Howett d888c11d18 Merge pull request #3270 from daandemeyer/push-qnzponoyonzo
test_sparse_basic: avoid out-of-bounds pointer arithmetic in verify
2026-07-12 23:05:02 -05:00
Dustin L. Howett d030af0ab7 Merge pull request #3282 from datauwu/warc-reject-incomplete-resource-records
warc: reject incomplete resource records
2026-07-12 22:51:31 -05:00
Dustin L. Howett ffc377a02f Merge pull request #3285 from datauwu/uu-fix-null-memcpy-ub
uu: fix null pointer UB in EOF buffering
2026-07-12 22:20:46 -05:00
datauwu 43bb153a65 uu: fix null pointer UB in EOF buffering
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().
2026-07-12 22:04:12 +08:00
Dustin L. Howett 5d25dac1a7 Merge pull request #3277 from datauwu/cpio-fix-pointer-lifetime 2026-07-11 07:23:18 -05:00
Dustin L. Howett 4436696356 Merge pull request #3280 from stoeckmann/warc_cleanup 2026-07-11 07:17:58 -05:00
datauwu e87311a9a7 warc: reject incomplete resource records
Reject resource records when less data was written than Content-Length.

Do not append the WARC end marker after a short entry. Return fatal
because the record body has already been started.

This avoids writing a record whose length does not match its body.
2026-07-11 20:16:39 +08:00
datauwu 2e35365462 warc: test incomplete resource records
Add a writer test for a resource entry shorter than Content-Length.

The test closes after a short write and checks for a fatal error. It
documents that the end marker must not hide a short body.
2026-07-11 20:16:24 +08:00
Dustin L. Howett ade8de6f77 Merge pull request #3281 from stoeckmann/warc_bid_check 2026-07-11 07:14:05 -05:00
Tobias Stoeckmann 8e750da087 warc: Sort include headers
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-11 13:22:58 +02:00
Tobias Stoeckmann 7d8c565377 warc: Unify private function names
Use same style as in other format parsers.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-11 13:22:58 +02:00
Tobias Stoeckmann 38a4047782 warc: Use common function names
Apply same style used in other format parsers.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-11 13:22:58 +02:00
Tobias Stoeckmann d646e22bd8 warc: Use proper data type for unconsumed
Match other parsers and use int64_t to avoid casts and switching between
signed and unsigned.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-11 13:22:56 +02:00
Tobias Stoeckmann d78fea3815 warc: Simplify __archive_read_ahead check
A short read would lead to a NULL return value, thus the second check
will never be true.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-11 13:20:06 +02:00
Tobias Stoeckmann da33bf2d71 Merge pull request #3279 from datauwu/warc-modernize-comments
warc: modernize comments
2026-07-11 12:01:19 +02:00
datauwu ca8044d3c4 warc: modernize writer comments
Rewrite WARC writer comments to use clearer wording and consistent
terminology.

Keep the change comment-only while preserving existing behavior.
2026-07-11 16:47:24 +08:00
datauwu eb6fc941b8 warc: modernize reader comments
Rewrite WARC reader comments to use clearer wording and match the
style used by other libarchive format readers.

Keep the change comment-only while preserving existing behavior.
2026-07-11 16:47:23 +08:00
datauwu 23b54da0ba cpio: fix read-ahead pointer lifetime issue
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.
2026-07-11 12:11:53 +08:00
Tim Kientzle 2139626099 Merge pull request #3276 from DHowett/dh/fix-archive-literals
tidy: prefer ARCHIVE_OK over 0 when appropriate
2026-07-10 20:40:54 -07:00
Dustin L. Howett bf4c5688d8 write: prefer ARCHIVE_OK over literal in set_bytes_per_block 2026-07-10 20:26:37 -05:00
Dustin L. Howett abfcfabbe7 iso9660: prefer ARCHIVE_OK over literal in gen*identifier 2026-07-10 20:26:31 -05:00
Dustin L. Howett a94475b11a shar: prefer ARCHIVE_OK over literal in finish_entry 2026-07-10 20:26:25 -05:00
Dustin L. Howett 8149e6bd92 xz: prefer ARCHIVE_OK over literal in filter_open 2026-07-10 20:26:17 -05:00
Dustin L. Howett 3e8e0cb32d uuencode: prefer ARCHIVE_OK over literal in filter_open 2026-07-10 20:26:08 -05:00
Dustin L. Howett 56bed7f2bd compress: prefer ARCHIVE_OK over literal in filter_open 2026-07-10 20:25:58 -05:00
Dustin L. Howett 65ddb3d0f4 b64: prefer ARCHIVE_OK over literal in filter_open 2026-07-10 20:25:34 -05:00
Dustin L. Howett 98d1ceeca6 Merge pull request #3274 from datauwu/warc-fix-oob-read
warc: parse Content-Length as a bounded field
2026-07-10 16:39:15 -05:00
datauwu 9fcb4048fa warc: parse Content-Length as a bounded field
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.
2026-07-11 02:08:05 +08:00
Tim Kientzle 2ff2b423e7 Merge pull request #3275 from datauwu/fix-several-left-shift-ub
libarchive: fix left-shift UB in several places
2026-07-10 10:29:24 -07:00
datauwu 2854735c80 tests: fix signed left-shift UB in fuzz consumer
Fix i64 construction by using a uint64_t accumulator.
2026-07-10 21:35:35 +08:00
datauwu 27c56a53d5 pax: fix signed-char left-shift UB in base64 encoder
Fix base64 shifts by casting input bytes to unsigned.
2026-07-10 21:35:35 +08:00
datauwu 342d2728d3 rar: fix signed left-shift UB in audio filter
Fix signed audio delta scaling by using multiplication.
2026-07-10 21:35:35 +08:00
datauwu 801b9707c3 7zip: fix negative shift count in x86 BCJ filter
Fix the previous-position shift count before updating the mask.
2026-07-10 21:35:35 +08:00
Dustin L. Howett 8d62a0512a Merge pull request #3257 from R4mbb/fix-pax-all-slash-pathname
pax: handle all-slash pathnames in USTAR name splitting
2026-07-09 10:53:22 -05:00
Daan De Meyer ce008c72af 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.
2026-07-09 17:17:29 +02:00
Dustin L. Howett cb2c1207f0 Merge pull request #3256 from stoeckmann/cab_integers
cab: Refactor data types + extend huffman tables to 16 bit if needed
2026-07-09 10:03:45 -05:00
Tobias Stoeckmann d3d8481e7f cab: Grow pre-tree Huffman table if needed
The standard has no fixed 10 bit limit. Instead, a pre-tree could
contain up to 16 bit codes, although this is very unlikely.

Grow the table if needed.

While at it, clarify now that max_bits are actually lookup_bits.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-09 08:37:34 +02:00
Tobias Stoeckmann e04051cb4b cab: Add large LZX pre-tree test
If a pre-tree is larger than 10 bit, libarchive fails to read the data.
According to spec, up to 16 bit are valid.

Example file provided by Duncan Horn. Thanks a lot!

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-09 08:37:34 +02:00
Tobias Stoeckmann a791094bdf cab: Clarify LZX/Huffman bit handling
- Huffman operations are up to 16 bit, thus uint16_t
- LZX itself can handle up to 32 bit, thus uint32_t
- Memory sizes are size_t

Otherwise:

- Use uint8_t to show where bit lengths are stored
- Use int to clarify that a status is stored

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-09 08:37:34 +02:00
Tobias Stoeckmann e155b516a0 cab: Remove check in lzx_make_huffman_table
The check against table size is redundant since Kraft's inequality
already verified that this operation cannot exceed table size anymore.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-09 08:37:34 +02:00
Tobias Stoeckmann 8d22629c9e cab: Use correct limit in lzx_make_huffman_table
The table size is in bytes, but bitlen must be checked against maximum
bit length allowed.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-09 08:37:34 +02:00
Tobias Stoeckmann dcf31bea79 cab: Clarify lzx_decode_huffman signature
No more than 16 bits shall ever be supplied for a table lookup.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-09 08:37:34 +02:00
Tobias Stoeckmann 8beccd23e2 cab: Adjust lzx_read_bitlen API
Use 0 as marker for maximum symbol count to be able to eventually switch
to another data type.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-09 08:37:34 +02:00
Tobias Stoeckmann 4fa9fc1f37 cab: Clear lookup table in lzx_huffman_init
This step is not actually needed, but will prevent static analysis
warnings that values might exist which have never been initialized.

"Invalid" values only exist outside of the addressable area, which can
happen if maximum code bit length is smaller than table bit length.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-09 08:37:34 +02:00
Tobias Stoeckmann 5bcaf207c1 cab: Clarify what "len_size" is
It's actually the amount of symbols/codes in Huffman tree. Clarify it by
using the field name symbol_count instead.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-09 08:37:34 +02:00
Tobias Stoeckmann 4d8e56fd19 cab: Use ARCHIVE_* values with lzx functions
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.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-09 08:37:34 +02:00
Tobias Stoeckmann 898b63c19b cab: Fix Kraft's inequality check
We really have to check if Kraft's inequality is 1 (in our case it's
0x10000) or 0 for an empty tree. Anything else is an error.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-09 08:37:34 +02:00
Tobias Stoeckmann eed685b4d6 cab: Simplify lzx_decode_huffman
As long as the given index is in range of the table, the previous
creation of the lookup table takes care that all elements are valid.

This is a left over of actual tree removal done in commit
c253f0aae9.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-09 08:37:34 +02:00
Tobias Stoeckmann 06765dbea5 cab: Remove inline keyword
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.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-09 08:37:34 +02:00
Tobias Stoeckmann ba202cdafc Merge pull request #3259 from uchiha-bug-hunter/7zip-bound-header-counts
7zip: bound folder and stream counts before allocating
2026-07-09 08:34:32 +02:00
Dustin L. Howett 1e48c53e9e Merge pull request #3266 from datauwu/pax-fix-oob-read
pax: fix 1-byte OOB read in sparse name building
2026-07-08 22:26:06 -05:00
Dustin L. Howett cfb3eb5497 Merge pull request #3267 from datauwu/iso9660-fix-oob
iso9660: fix 1-byte OOB read in iso-level option
2026-07-08 22:20:50 -05:00
Dustin L. Howett 1d7b49b8d9 Merge pull request #3268 from uchiha-bug-hunter/best-effort-strncat-overread
archive_string: bound best_effort_strncat_in_locale to length
2026-07-08 22:19:43 -05:00
Kaif Khan 9b5dae145f 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.
2026-07-08 22:10:27 +05:30
Kaif Khan 18449a3f8d 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.
2026-07-08 22:10:19 +05:30
datauwu 0046f16644 iso9660: fix 1-byte OOB read in iso-level option
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.
2026-07-08 20:24:33 +08:00
datauwu 51287cecd6 pax: fix 1-byte OOB read in sparse name building
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.
2026-07-08 18:10:27 +08:00
Kaif Khan e5d72383a6 7zip: bound NumFolders before allocating folders array 2026-07-08 01:13:52 +05:30
Dustin L. Howett 40a71c8382 Merge pull request #3265 from stoeckmann/ckd_alloc
Check size arithmetic before memory allocations
2026-07-07 13:49:14 -05:00
Dustin L. Howett 6752ed2c27 Merge pull request #3214 from uchiha-bug-hunter/tar-sun-holesdata-overread
tar: add regression test for SUN.holesdata sparse map ending on a digit
2026-07-07 13:45:47 -05:00
Kaif Khan 91648e29bd 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.
2026-07-07 23:44:50 +05:30
Tobias Stoeckmann 761652401f Merge pull request #3220 from DHowett/fix-assertions-lstat
test: make Windows file assertions act like lstat
2026-07-07 19:28:21 +02:00
Tobias Stoeckmann 1bcc833a5d Check size arithmetic before memory allocations
Make sure that multiplications do not overflow (or if they overflow,
handle them properly).

This also means that proper data type size_t instead of int is used.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-07 17:57:33 +02:00
Dustin L. Howett 8324372849 Merge pull request #3249 from datauwu/warc-fix-pending-data
warc: fix pending data when skipping entries
2026-07-07 10:47:10 -05:00
Dustin L. Howett 617d422c86 test: make Windows file assertions act like lstat
I've removed our lstat shim and replaced all uses with my_GetFileInformationByName.
2026-07-07 10:24:00 -05:00
Dustin L. Howett 4c7066dd98 Merge pull request #3227 from DHowett/windows-bsdtar-fix-upper-h-mode
win32: fix symlink mode 'H' (hybrid) in wildcard search
2026-07-07 10:23:19 -05:00
Tobias Stoeckmann 68ccc129a8 options: Use const char pointer where possible
If referenced strings are not modified, use const char pointer.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-07 17:16:01 +02:00
Dustin L. Howett f0af7530a1 Merge pull request #3258 from uchiha-bug-hunter/mtree-global-set-overread
mtree: fix out-of-bounds read in process_global_set
2026-07-07 09:26:38 -05:00
Dustin L. Howett 512675e432 Merge pull request #3262 from datauwu/zip-fix-oob-read
zip: fix 1-byte OOB read in Mac extension check
2026-07-07 09:25:11 -05:00
Dustin L. Howett 108381c805 Merge pull request #3263 from datauwu/bsdtar-fix-oob-read
bsdtar: fix 1-byte OOB read in substitution handling
2026-07-07 09:24:58 -05:00
Dustin L. Howett a6b6c50c3b Merge pull request #3260 from mmatuska/constify-fix
7-zip and rar5: add constifications missing in e150c2f41 (#3113)
2026-07-07 09:24:15 -05:00
Dustin L. Howett bcdda15a40 Merge pull request #3223 from DHowett/win32-o-excl
win32: prevent writing through a broken symlink in insecure mode
2026-07-07 09:17:28 -05:00
datauwu 0053ea743f 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.
2026-07-07 21:58:54 +08:00
datauwu c81bc7eee8 zip: fix 1-byte OOB read in Mac extension check
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.
2026-07-07 20:36:24 +08:00
Martin Matuska 2610a79fd5 7-zip and rar5: add constifications missing in e150c2f41 (#3113) 2026-07-07 13:53:19 +02:00
Kaif Khan 5c61644fdb mtree: fix out-of-bounds read in process_global_set 2026-07-07 14:19:03 +05:30
R4mbb 82d44c4042 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.

Signed-off-by: R4mbb <yong010301@gmail.com>
2026-07-07 14:38:07 +09:00
Dustin L. Howett c16162083a Merge pull request #3253 from datauwu/tar-fix-oob 2026-07-06 21:00:05 -05:00
Dustin L. Howett dbb4e7f28d Merge pull request #3255 from datauwu/iso9660-fix-oob-read 2026-07-06 20:57:53 -05:00
datauwu 2f0e327d12 warc: fix pending data when skipping entries
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.
2026-07-07 08:14:38 +08:00
datauwu bd0cae0be7 iso9660: fix 1-byte OOB read in directory scanning
read_children() checked the directory record length byte before ensuring
that the record pointer was still inside the current logical block.

If directory records exactly filled the final block, the next loop
condition could read one byte past the image buffer.

Check the remaining block length before reading the record length byte.
2026-07-07 08:07:59 +08:00
datauwu f93abd161e tar: fix 1-byte OOB read in number parsing
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.

Read each digit only while bytes remain.
2026-07-06 22:51:18 +08:00
Dustin L. Howett 51060e492b Merge pull request #3236 from uchiha-bug-hunter/acl-from-text-nl-overread
acl: fix over-read on empty field in archive_acl_from_text_nl
2026-07-06 09:29:59 -05:00
Tim Kientzle f4786afb10 Merge pull request #3250 from datauwu/tar-avoid-redundant-size
tar: avoid redundant Solaris ACL size parsing
2026-07-06 07:11:54 -07:00
Tim Kientzle d81b9f5582 Merge pull request #3252 from datauwu/tar-fix-oob-read
tar: fix 1-byte OOB read in SUN.holesdata parsing
2026-07-06 07:06:58 -07:00
datauwu 40b92de1de tar: fix 1-byte OOB read in SUN.holesdata parsing
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.

Handle length == 0 before checking *e.
2026-07-06 21:51:15 +08:00
data 70bae9b796 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().
2026-07-06 18:34:52 +08:00
datauwu 172e463c41 warc: add test for skipping after extraction
Add a test that extracts data from the first WARC resource record, then
moves to the second header.

This checks the bug where already-read entry data was not handled correctly
before skip handling.
2026-07-06 16:15:05 +08:00
Dustin L. Howett f0b9700384 Merge pull request #3246 from stoeckmann/cab_style
cab: Extend Huffman documentation
2026-07-06 00:04:31 -05:00
Dustin L. Howett 7b635176c5 Merge pull request #3244 from datauwu/warc-fix-write-past 2026-07-05 16:15:03 -05:00
Tobias Stoeckmann 59826c033e cab: Use strnlen if possible
Adjust cab_strnlen to match strnlen API and use system's strnlen if
available.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-05 21:46:12 +02:00
Tobias Stoeckmann 405cf62736 mtree: Fix custom strnlen API
If strnlen is not available, custom code is used. Make sure that the
custom code keeps premise of strnlen API for maximum compatibility.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-05 21:35:14 +02:00
Tim Kientzle f2f3eb9f50 Merge pull request #3245 from kientzle/kientzle-archive-read-failed-header-recovery
[Read core] Allow format handlers to FAIL a header read
2026-07-05 10:36:10 -07:00
Tobias Stoeckmann 07aca47167 cab: Extend Huffman documentation
Explain the algorithm and data structure involved in Huffman tree
handling as array. Hopefully simplifies upcoming code change
verifications.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-05 19:35:45 +02:00
Tim Kientzle 16d8156deb [Read core] Allow format readers to FAIL a header read
While investigating improvements to Zip's header reading,
I found	an overlooked case in the read core:  When a format
returned FAILED	for a header read (indicating that the entry
could not be read but that the archive as a whole is still valid),
the core silently converted that to FATAL, ending the archive
at that	point.

The change to the read core adds a new internal state "DATA_RECOVERY"
indicating that we're post-header (like the existing DATA state) but
that client requests to actually obtain data are not valid.
2026-07-05 10:12:33 -07:00
Tim Kientzle 0409837cb9 [Read core] Test handling of FAILED header reads
While investigating improvements to Zip's header reading,
I found	an overlooked case in the read core:  When a format
returned FAILED	for a header read (indicating that the entry
could not be read but that the archive as a whole is still valid),
the core silently converted that to FATAL, ending the archive
at that	point.

Two formats already returned FAILED for	certain	header issues:
Zip and	LHA both indicated unreadable symlink entries in this way,
which should allow the rest of the archive to continue being read.
New tests here verify that we can now continue reading past
such entries, and that clients who ignore the FAILED result
get the	same FATAL handling as other API misuse.
2026-07-05 10:11:50 -07:00
data 80cda1e17e warc: track remaining entry bytes when writing data
The WARC writer capped each data write against the full declared entry
size, but never reduced that value after accepting data. As a result,
repeated write calls could emit more bytes than the WARC Content-Length.

Track the remaining byte count for the current regular-file entry and
decrement it after each successful write. Further writes are then
clamped to the remaining length and return zero once the entry is full.
2026-07-06 00:31:53 +08:00
data ab1de8f3bc warc: test repeated writes past Content-Length
Verify that a WARC entry does not accept bytes after its declared
Content-Length has already been written.
2026-07-06 00:28:38 +08:00
Tim Kientzle f7965ac947 Merge pull request #3242 from datauwu/zip-basic-support-0x000d
zip: read PKWARE Unix extra field metadata
2026-07-05 08:38:11 -07:00
Tobias Stoeckmann 3ad6bb89a9 cab: Do not nest struct definitions
This complies with other C source files of format parsers.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-05 17:27:14 +02:00
Kaif Khan 70e4b8c511 acl: fix over-read on empty field in archive_acl_from_text_nl
archive_acl_from_text_nl() parses ACL text from a pointer and a length
and does not require a NUL terminator; the tar reader passes a
__archive_read_ahead() window of exactly value_length bytes for
SCHILY.acl.access/.default/.ace.  When an entry is empty (a
whitespace-only value, or trailing whitespace after a valid entry)
next_field() consumes the rest of the buffer as whitespace and leaves
field[0].start one past the end, which the '#'-comment probe then
dereferences.  Capture the buffer end and skip the entry when its first
field starts there.  The wide archive_acl_from_text_w is NUL terminated
and unaffected.
2026-07-05 13:39:58 +05:30
Kaif Khan 18f5209e48 acl: add test_acl_from_text_overread regression test
Drives archive_acl_from_text_nl() with exact-length, non-NUL-terminated
buffers whose first field is only whitespace, covering the empty-entry
and trailing-whitespace cases.  Allow the test to include
archive_acl_private.h via __LIBARCHIVE_TEST.
2026-07-05 13:39:52 +05:30
datauwu 467d31b0cf zip: read PKWARE Unix extra field metadata
Read the fixed metadata prefix of the PKWARE Unix extra field 0x000d.

The fixed portion contains atime, mtime, uid, and gid values. Require
the full 12-byte prefix before reading it, and leave the variable-length
data field unsupported for now.
2026-07-05 13:27:29 +08:00
datauwu 9a2087f9d7 zip: test PKWARE Unix extra field
Add a test for the PKWARE Unix extra field 0x000d.

The fixture stores a regular file with the 12-byte fixed metadata
prefix in both the local header and central directory. The test checks
that the ZIP reader exposes mtime, atime, uid, and gid metadata for
seekable and streaming reads.
2026-07-05 13:22:03 +08:00
Tim Kientzle d21fdc9f84 Merge pull request #3240 from kientzle/kientzle-zip-uncompressed-size-exact-check
[Zip] Reject archives if the 32-bit size field is not correct
2026-07-04 22:06:35 -07:00
Dustin L. Howett 3c3ec69d44 Merge pull request #3232 from kientzle/kientzle-read-data-into-fd-size-boundary
[Write] Truncate write-to-fd at the declared entry size
2026-07-04 15:08:23 -05:00
Dustin L. Howett afc33dfeb4 Merge pull request #3219 from DHowett/custom-clang-in-ci
ci: add a new Lint step that uses a custom-built linter
2026-07-04 14:57:14 -05:00
Dustin L. Howett 3151a76b1e Merge pull request #3237 from datauwu/tar-avoid-redundant-mode
tar: avoid redundant mode parsing
2026-07-04 14:56:02 -05:00
Dustin L. Howett cebab49b99 Merge pull request #3233 from stoeckmann/archive_entry_new2
Check `archive_entry_new2` return value
2026-07-04 14:51:49 -05:00
Dustin L. Howett 0cb18445d3 Merge pull request #3234 from stoeckmann/raw_oflow
raw: Properly treat huge inputs
2026-07-04 14:51:31 -05:00
Dustin L. Howett e19d93fe22 lint: compile la-lint and use in place of clang-tidy 2026-07-04 14:42:27 -05:00
Dustin L. Howett 942984fd7d Merge commit '25ef914386252adbf67d07d6c5bf018dfcbe34a9' as 'build/la-lint' 2026-07-04 14:42:27 -05:00
Dustin L. Howett 25ef914386 Squashed 'build/la-lint/' content from commit 66dbe023
git-subtree-dir: build/la-lint
git-subtree-split: 66dbe023892df333ae794f6004553ff0a3d32275
2026-07-04 14:42:27 -05:00
Dustin L. Howett c0f58c7b34 build: add a new "lint" workflow that runs clang-tidy 2026-07-04 14:42:26 -05:00
Dustin L. Howett 89efbd80de build: add ENABLE_CLANG_TIDY and CLANG_TIDY_PATH 2026-07-04 14:42:26 -05:00
Dustin L. Howett 4767d73519 Merge pull request #3239 from datauwu/warc-require-size 2026-07-04 14:24:22 -05:00
datauwu 3a2538bca3 warc: require file size before writing header
WARC records require a known Content-Length. Reject regular file
entries without a valid size instead of treating them as zero.
Avoid casting archive_entry_size() through size_t before storing it in
the uint64_t WARC Content-Length field, since that can truncate large
sizes on 32-bit platforms.
2026-07-05 03:11:15 +08:00
Tim Kientzle f66b4c7f8f Merge pull request #3238 from stoeckmann/cpio_ioflow
cpio: Prevent signed integer overflow
2026-07-04 10:43:37 -07:00
datauwu 366baca718 warc: test missing file size handling
Add coverage for WARC entries without a known size. The writer
must reject these entries because WARC requires Content-Length.
2026-07-05 01:26:57 +08:00
Tobias Stoeckmann c1ce208f8e cpio: Prevent signed integer overflow
If enough bytes have to be skipped, a signed integer overflow could
occur (most realistically on 32 bit systems). Use an unsigned type,
which could still overflow but has only negative impact on diagnostic
warning message.

Follow up of 02fa05675f but this time for
function find_newc_header.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-04 19:06:52 +02:00
Tim KientzleandTobias Stoeckmann 1ff24fb981 Update libarchive/archive_read_data_into_fd.c
Co-authored-by: Tobias Stoeckmann <stoeckmann@users.noreply.github.com>
2026-07-04 09:48:31 -07:00
Tobias Stoeckmann 41a72e5553 Merge pull request #3231 from datauwu/7zip-skip-archiveproperties
7zip: skip ArchiveProperties payload data
2026-07-04 09:56:23 +02:00
datauwu 9c5210e8a5 pax: remove redundant hardlink size assignment
archive_write_pax_header() set hardlink entries to size zero for the
restricted pax format, then immediately set all hardlink entries to size
zero again.

Remove the narrower check because it is fully subsumed by the following
hardlink check.

No functional change intended.
2026-07-04 13:57:33 +08:00
datauwu 426f2aef86 tar: avoid parsing mode field twice
header_common() parsed the tar mode field once when setting the file
type and again when setting permissions. Cache the parsed value and reuse
it for both setters.

archive_entry_set_filetype() and archive_entry_set_perm() already mask
the relevant bits, so passing the full header mode preserves behavior.
The permission-set guard is unchanged.

No functional change intended.
2026-07-04 13:57:32 +08:00
Tim Kientzle d2a224f443 Fix the test failure
This was originally developed without the Zip fix from #3230.
Since that's been merged, we need to adjust the expectations here
a bit.
2026-07-03 21:52:27 -07:00
Tim Kientzle ec36bf4179 Rework size-overrun check to avoid arithmetic errors 2026-07-03 21:41:08 -07:00
Tim Kientzle aba955e416 [Write] Truncate write-to-fd at the declared entry size
This is	the fix for....

Update the common archive_read_data_into_fd() to truncate
output to the actual entry size	from the most recent
archive_read_header result.

This addresses a hole in handling of certain subtly-malformed archives
that can have more data than declared in the header.  Before this,
bsdtar explicitly truncates the entry data to the actual declared size
when extracting to a file, but did not do so when extracting to
stdout.
2026-07-03 21:41:08 -07:00
Tim Kientzle e7e408a1a9 [Write] Truncate write-to-fd at the declared entry size
This is the test for....

Update the common archive_read_data_into_fd() to truncate
output to the actual entry size from the most recent
archive_read_header result.

This addresses a hole in handling of certain subtly-malformed archives
that can have more data than declared in the header.  Before this,
bsdtar explicitly truncates the entry data to the actual declared size
when extracting to a file, but did not do so when extracting to
stdout.
2026-07-03 21:41:08 -07:00
Tim Kientzle ba542208a3 [Zip] Reject archives if the 32-bit size field is not correct
Reverse an old experiment: When the 32-bit size field is provided, it
now must match the actual size exactly.  We no longer permit it to
only match the least-significant 32 bits of the actual size.

--begin-history--
When developing the earliest versions of libarchive's Zip support, I
experimented with the idea of supporting greater-than-4GiB entries in
32-bit Zip archives.  This proved to be technically feasible as long
as the _compressed_ data was small enough to keep the resulting
archive under 4GiB.  But this also required us to interpret
the 32-bit uncompressed size field as representing only the
least-significant 32 bits of the size.
--end-history--
2026-07-03 21:25:54 -07:00
Tim Kientzle 1559ae86da [Zip] Be strict about the 32-bit uncompressed size
Test:  If the uncompressed size stored in the archive differs
from the actual uncompressed size by a multiple of 2^32,
we should report some kind of error.

This currently goes undiagnosed because of an old attempt
to support larger-than-4GiB entries in plain 32-bit Zip
archives without necessarily requiring Zip64 extensions.
While this is technically feasible, it requires treating
the 32-bit size field ambiguously, which can lead to size
confusion from readers.
2026-07-03 21:22:48 -07:00
datauwu fbad49b708 7zip: skip ArchiveProperties payload data
ArchiveProperties entries have a property ID, a size, and payload.

The reader parsed the ID and size, but did not consume the payload.
Payload bytes could then be read as the next property ID, which
misaligned the rest of header parsing.

Skip the payload in chunks so parsing stays aligned with 7-Zip/7zz.
2026-07-04 12:00:07 +08:00
Tobias Stoeckmann f4493cea76 raw: Properly treat huge inputs
If the raw parser ever treats a basically endless stream which
eventually overflows INT64_MAX, fail instead of overflowing
offset + size calculation, leading to subsequent issues in callers.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-03 23:26:28 +02:00
Tobias Stoeckmann 47964b3533 Check archive_entry_new2 return value
The memory allocation might fail. Check return value and properly handle
error cases.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-03 22:45:11 +02:00
Tim Kientzle 5a2ec45b9c Merge pull request #3230 from kientzle/kientzle-zip-reject-overlong-bodies
[Zip] Reject entries with overlong bodies
2026-07-03 13:26:30 -07:00
Tim Kientzle c11df428d1 [Zip] Reject entries with overlong bodies
If an entry declares an uncompressed size, we should not return any
data beyond that point.  This doesn't impact bsdtar and friends since
they independently truncate to the declared entry size, but other
clients may not be so careful.

Apparently discovered (but not reported) by @bikini
Reported by @dkgkdfg65
2026-07-03 13:14:27 -07:00
Tim Kientzle 5f29836190 [Zip] Reject entries with overlong bodies
Tests for...

If an entry declares an uncompressed size, we should not return any
data beyond that point.  This doesn't impact bsdtar and friends since
they independently truncate to the declared entry size, but other
clients may not be so careful.

Apparently discovered (but not reported) by @bikini
Reported by @dkgkdfg65
2026-07-03 13:13:31 -07:00
Dustin L. Howett 5933c80ae5 Merge pull request #3229 from stoeckmann/cab_e8 2026-07-03 13:38:20 -05:00
datauwu 49a273e314 7zip: add ArchiveProperties payload test
Add a 7z test archive with a non-empty ArchiveProperties payload.

The archive has one empty file and an ArchiveProperties entry with a
1-byte payload. It is accepted by 7-Zip/7zz.

This covers parsing when ArchiveProperties has payload bytes.
2026-07-04 01:44:58 +08:00
Tim Kientzle 47999c275f Merge pull request #3228 from datauwu/zip-encrypted-int-overflow
zip: avoid signed overflow in encrypted size checks
2026-07-03 09:36:45 -07:00
datauwu 1c6e7b491f zip: avoid signed overflow in encrypted size checks
Avoid adding the encryption overhead directly to entry sizes when deciding
whether Zip64 is needed or when updating the stored compressed size.

For the Zip64 decision, compare against ZIP_4GB_MAX - additional_size. For
stored encrypted entries, use archive_ckd_add_i64() so the size update and
overflow check happen together.
2026-07-03 23:48:50 +08:00
Tobias Stoeckmann 53d1c0bc65 cab: Add E8 translation test
Covers basic E8 translations, yet it lacks the handling of negative
values because this would require large archives.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-03 17:37:37 +02:00
Tobias Stoeckmann 220eefe346 cab: Translate E8 calls only in first 1 GB of data
The cab specification states that E8 translation shall be performed only
within the first 1 GB range of an uncompressed file, i.e. for the first
0x8000 CFDATA entries in a folder.

Take this limit properly into account.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-03 17:37:34 +02:00
Dustin L. Howett 42b2444920 Merge pull request #3208 from datauwu/7zip-skip-defined-bitmaps 2026-07-02 20:22:52 -05:00
datauwu a32e870da4 7zip: skip fully-defined metadata bitmaps
Avoid allocating and filling metadata bitmaps when the 7z header says
that every file has the corresponding value.

Sparse metadata still uses the existing bitmap path.
2026-07-03 08:24:15 +08:00
Dustin L. Howett 1162aaeccb Merge pull request #3224 from datauwu/formats-remove-unused-state
formats: remove unused states from 7 formats
2026-07-02 17:27:28 -05:00
Dustin L. Howett 6c97b0ae54 Merge pull request #3226 from uchiha-bug-hunter/pathmatch-wide-bracket-overread
pathmatch: fix wide-char bracket over-read in pm_w
2026-07-02 14:40:59 -05:00
Dustin L. Howett e3f9ed95b7 win32: repair symlink mode 'H' (hybrid) in wildcard search
The Windows disk reader supports wildcards by converting a path like
"foo/*" into a single tree rooted at "foo/". This does not play nicely
with symlink mode `H`, which treats the first item in each tree as a
dereferenced link (L) and all subsequent items as physical links (P). On
Windows, we take the first _match_ in L mode and all subsequent
descendants and matches in P mode.

This creates a behavioral difference between `bsdtar -c -H *` and
`bsdtar -c -H one two three`.

This commit changes how we handle H->L/P transitions when doing wildcard
matches. The transition from H to P is now done when we descend into our
first directory, and we switch back to H mode when we ascend out of
it[^1].

Closes #3222

[^1]: This does not matter in practice because tree is breadth-first
rather than depth-first, but I've done it in the interest of
completeness and not leaving ourselves caltrops to step on later.
2026-07-02 14:26:40 -05:00
Kaif Khan 262461917e pathmatch: guard end-of-string before wide bracket class match 2026-07-02 22:36:44 +05:30
Kaif Khan 10ca288a48 test: cover wide bracket over-read in pm_w 2026-07-02 22:36:44 +05:30
datauwu e42a14d5e7 write: remove unused zip and warc fields
Remove writer fields that are initialized but never read.
2026-07-02 21:44:48 +08:00
datauwu 1a98844466 rar5: remove unused filter_info fields
Remove filter_info fields that are never assigned or read.
2026-07-02 21:44:48 +08:00
datauwu c5f1dba4e3 rar: remove unused globalbackup fields
Remove RAR filter backup fields that are never used.
2026-07-02 21:44:48 +08:00
datauwu f12b3fe00c cab: remove unused LZX tree_used state
Remove LZX Huffman state that is reset but never read.
2026-07-02 21:44:48 +08:00
datauwu ebe53f5fcd cab: remove unused header and entry fields
Remove CAB fields that are parsed or reset but never read.
2026-07-02 21:44:48 +08:00
datauwu 4f9f341f16 zip: remove unused central directory counters
Remove counters that are initialized or incremented but never read.
2026-07-02 21:40:07 +08:00
Dustin L. Howett 0c856d3a8f Merge pull request #3206 from DHowett/win32-symlink-bypass 2026-07-02 07:25:37 -05:00
Dustin L. Howett e707414ed8 win32: prevent writing through a broken symlink in insecure mode
The comments document that we were expecting O_EXCL behavior, and
archive_write_disk_posix uses O_EXCL as well. Let's use O_EXCL's nearest
equivalent.
2026-07-01 21:43:09 -05:00
Dustin L. Howett 52bf591c1a Merge pull request #3221 from stoeckmann/callback_data_check 2026-07-01 16:04:34 -05:00
Tobias Stoeckmann dfcc108ebd Check result of archive_read_set_callback_data
The memory allocation in archive_read_set_callback_data2, which is
called by archive_read_set_callback_data, could fail.

Check result and properly handle failure.

Resolves #3210.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-07-01 22:38:58 +02:00
Dustin L. Howett 983f8da4be Merge pull request #3216 from setarcos/loongarch
test: fix incorrect hole count reporting on loongarch64
2026-07-01 12:03:18 -05:00
Dustin L. Howett 0b661a91be Merge pull request #3217 from datauwu/7zip-simplify-bool-handling
7zip: simplify bool handling
2026-07-01 12:02:12 -05:00
Dustin L. Howett d586479a72 Merge pull request #3218 from datauwu/7zip-redundant-bcj-assign
7zip: drop redundant BCJ2 assignments
2026-07-01 12:01:06 -05:00
datauwu 5cd808a44b 7zip: simplify metadata bool handling
Flatten nested allAreDefined checks for attribute and timestamp bools.

Also initialize empty-stream entries as directories by default before
applying the optional EmptyFile bitmap.

No archive behavior change is intended.
2026-07-01 23:10:46 +08:00
datauwu 86fd6c20c0 7zip: drop redundant BCJ2 assignments
Both supported BCJ2 layout branches store the chosen unpack size in
remaining.

main_stream_bytes_remaining is set from remaining immediately after
the branch, so the earlier assignments are redundant.
2026-07-01 22:56:30 +08:00
Pluto Yang 22af22edb8 test: fix incorrect hole count reporting on loongarch64
On LoongArch64 with 16KB pages, Linux tmpfs often uses Transparent
Huge Pages (THP) sized at 32MiB. When a test writes data followed
by a 32MiB hole, the kernel may allocate a single huge page folio
to back the entire range in RAM. Because the range is physically
backed by memory, SEEK_HOLE correctly (from the kernel's perspective)
identifies the range as DATA, failing the test's assertion. Increasing
MIN_HOLE to 64MiB ensures the hole exceeds the huge page size on
loongarch64, preserving the sparse nature of the file for the test.

Signed-off-by: Pluto Yang <yangyj.ee@gmail.com>
2026-07-01 22:17:08 +08:00
Dustin L. Howett 769b628019 Merge pull request #3213 from datauwu/7zip-remove-unused-state 2026-07-01 08:13:55 -05:00
datauwu 5782aa72cd 7zip: remove unused writer byte counters
The 7z writer kept compressed and uncompressed byte counters that were
updated after each entry but never read.

Remove the counters and their updates.
2026-07-01 17:38:25 +08:00
Dustin L. Howett 4191fecb3a Merge pull request #3212 from stoeckmann/cab_doc_types
cab: Improve LZX translation readability
2026-06-30 18:25:42 -05:00
Tobias Stoeckmann 1afe5ba2cd cab: Improve lzx_translation data types
Use correct data types to reduce amount of casts. This should further
improve readability.

While at it, also improve white space usage.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-30 22:42:06 +02:00
Tobias Stoeckmann ee07a5486a cab: Improve lzx_translation variable names
It's quite rare that "p" is not the iteration pointer but the base
pointer, while "b" is not the base pointer but the iteration pointer.

Use more descriptive variable names to assist auditors to figure out how
E8 call translation reversal works. It's already hard by itself.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-30 22:40:17 +02:00
Tobias Stoeckmann 4e6c97e66c cab: Turn translation size into int32_t
It's a file size and used for signed integer comparison. Since it's
literally a file size, its maximum value should be properly checked as
well.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-30 22:38:52 +02:00
Tobias Stoeckmann b4f9d327c6 cab: Document some magic numbers
Use more macro definitions instead of magic numbers to improve code
readability. Hopefully this explains a bit more where these values come
from.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-30 22:36:29 +02:00
Tobias Stoeckmann ed8d866f77 cab: Improve decoding status value description
Move the macro definitions up to the field where they are used, which is
done for other such fields as well.

This in turn allows to avoid the magic value 0 in initial assignment.
Use ST_RD_TRANSLATION instead for better documentation where the finite
state machine starts (and that this state cannot be reached again).

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-30 22:33:32 +02:00
Dustin L. Howett f59675ccff Merge pull request #3207 from datauwu/tests-merge-fix-typo
tests: merge tests and fix misleading labels
2026-06-30 11:33:06 -05:00
Dustin L. Howett d05e842435 Merge pull request #3209 from datauwu/7zip-fix-sfx-boundary
7zip: fix SFX boundary checks
2026-06-30 11:26:17 -05:00
datauwu aabed78710 7zip: fix SFX boundary checks
The SFX scanner missed a valid 7-Zip header when exactly 32 bytes
remained in the lookahead buffer.

The ELF SFX path also missed ".data" when it was at the last valid
position in the section string table. It also allowed e_shstrndx to be
equal to e_shnum, even though that is one past the section table.

Tighten these checks so valid edge cases are handled correctly.
2026-06-30 21:46:55 +08:00
datauwu 6333be32b8 7zip: add SFX boundary tests
Add PE and ELF SFX fixtures for the SFX scanner boundary cases.

The PE fixture places an empty 7z archive at the final exact
32-byte scan window. The ELF fixture places ".data\0" at the final
valid section string-table position.

Register the fixtures for autotools distcheck.
2026-06-30 21:46:54 +08:00
datauwu 00bafe21f1 fuzz: fix iteration comment
The fuzz test comment says each file is tested 100 times, but the
loop runs 1000 iterations. Update the comment to match the code.
2026-06-30 17:12:12 +08:00
datauwu 5e1afc9b42 zip: fix lzma/xz compression test name
The ZIP compression test name used lzmaxz even though the test covers
the LZMA and XZ compression paths. Rename it to lzma_xz.
2026-06-30 17:12:11 +08:00
datauwu e519625cf5 iso9660: fix compress test names
Several ISO tests used a bz2 suffix even though they read .Z files
and verify ARCHIVE_FILTER_COMPRESS. Rename them to use a compress
suffix so the test names match the filter.
2026-06-30 17:12:11 +08:00
datauwu ae78682a02 archive_write: group option setter tests
The write option setter checks used several tiny source files with the
same basic shape.

Keep the same DEFINE_TEST cases. Put the write-side option setter
checks in test_archive_write_set_options.c. Remove the extra source
files from the build lists.
2026-06-30 17:12:10 +08:00
datauwu 25533dd722 archive_read: group option setter tests
The read option setter checks used several tiny source files with the
same basic shape.

Keep the same DEFINE_TEST cases. Put the read-side option setter
checks in test_archive_read_set_options.c. Remove the extra source
files from the build lists.
2026-06-30 17:12:10 +08:00
datauwu d6e1e7bc3d archive_read: group close-twice tests
The close-twice read checks used three tiny source files.

Keep the same DEFINE_TEST cases. Put the fresh-object, fd-backed,
and filename-backed checks in one source file. Remove the two extra
files from the build lists.
2026-06-30 17:12:09 +08:00
Dustin L. Howett 1e8d061bf2 test: enable most of the remaining disk_secure tests on Windows
This rather required porting them to assertIs{Reg,Dir,Symlink} and away
from lstat.

This is possible now that 9046e753ca fixed
a number of other symlink issues on Windows.
2026-06-29 15:43:44 -05:00
Dustin L. Howett 9046e753ca Merge commit from fork
windows: fix a number of symlink handling issues and enable tests
2026-06-29 15:30:34 -05:00
Tobias Stoeckmann ab4f2a57e9 Merge pull request #3205 from DHowett/assert-mem-obo
Fix two more off-by-ones calling assertEqualMem
2026-06-29 22:11:18 +02:00
Dustin L. Howett e0c4bccd8e Merge pull request #3204 from stoeckmann/cab_oob_handling 2026-06-29 14:13:07 -05:00
Dustin L. Howett 83b55fc446 zip: compare entire file contents (assert_mem off by one) 2026-06-29 14:01:00 -05:00
Dustin L. Howett 219ef4caf2 ustar: fix length of ustar header needle 2026-06-29 14:00:42 -05:00
Tobias Stoeckmann 33e0dd575e cab: Remove obsolete safety checks
Commit e1f890dc62 fixed the underlying
root cause of these OOB checks: If a header is invalid and ARCHIVE_FATAL
is returned, do not allow data reads anymore.

The checks while reading CFDATA already looked rather off, since the
check exists in header parser and the value is never updated, but
prevent worst case scenario.

Keep the tests as regression tests if archive_read.c is modified again.

This makes the code easier to read and audit.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-29 19:55:08 +02:00
Dustin L. Howett 4e6e6619eb Merge pull request #3200 from datauwu/zip-fix-compare-full-contents
zip: compare full file3 contents in tests
2026-06-29 12:04:44 -05:00
Dustin L. Howett 573de88e1c Merge pull request #3199 from datauwu/7zip-redundant-header-checks
7zip: remove redundant read header checks
2026-06-29 12:04:01 -05:00
Dustin L. Howett 1e1d478486 Merge pull request #3201 from datauwu/tests-fix-charset-labels
tests: fix incorrect charset labels
2026-06-29 11:31:52 -05:00
Dustin L. Howett aa1dbe602a Merge pull request #3203 from libarchive/dependabot/github_actions/all-actions-fc272564ab
CI: Bump acj/freebsd-firecracker-action from 0.10.0 to 0.10.1 in the all-actions group
2026-06-29 11:31:09 -05:00
Dustin L. Howett 588363eb4e Merge pull request #3187 from nvmb3r/rar5-unpacked-size-limit
rar5: reject streams that exceed the declared unpacked size
2026-06-29 11:30:15 -05:00
Dustin L. Howett 354a3535ed Merge pull request #3194 from uchiha-bug-hunter/iso9660-zf-oob-read
iso9660: fix OOB read in parse_rockridge_ZF1 on short ZF entry
2026-06-29 11:29:28 -05:00
dependabot[bot] 9639fbd466 CI: Bump acj/freebsd-firecracker-action in the all-actions group
Bumps the all-actions group with 1 update: [acj/freebsd-firecracker-action](https://github.com/acj/freebsd-firecracker-action).


Updates `acj/freebsd-firecracker-action` from 0.10.0 to 0.10.1
- [Release notes](https://github.com/acj/freebsd-firecracker-action/releases)
- [Commits](https://github.com/acj/freebsd-firecracker-action/compare/ff79eb955fd19c697a708a02834995e47a6e58ed...da029f050a7a2535fce96385727cf3d5768bd8bf)

---
updated-dependencies:
- dependency-name: acj/freebsd-firecracker-action
  dependency-version: 0.10.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-29 16:13:00 +00:00
Dustin L. Howett 401a1915cf Merge pull request #3192 from stoeckmann/ar_integers 2026-06-29 10:36:22 -05:00
Tobias Stoeckmann 17af9d6ea6 ar: Adjust style and fix comment grammar
Use style most often seen in other format parsers.
While at it, fix grammar in comment.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-29 17:12:37 +02:00
Tobias Stoeckmann 7054bec543 ar: Simplify error handling in _ar_read_header
The comment states that a warning should be returned, but
97f964e3e0 explicitly changed that to
fatal. Adjust the comment and remove unneeded function call.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-29 17:12:37 +02:00
Tobias Stoeckmann 80cf6d2199 ar: Simplify _ar_read_header cases
Symbol tables are not treated specially. Clarify that by merely
mentioning them in a comment.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-29 17:12:37 +02:00
Tobias Stoeckmann c3e27cc135 ar: Set filetype only once
All entries in ar are regular files. Set this information only once to
simplify code audits.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-29 17:12:37 +02:00
Tobias Stoeckmann e235bb06a4 ar: Simplify ar_parse_common_header usage
The function ar_parse_common_header can be called at exactly one
position in _ar_read_header, since it parses common information.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-29 17:12:37 +02:00
Tobias Stoeckmann 2876f4912b ar: Simplify __archive_read_consume usage
The __archive_read_consume function is binary: Either all bytes are
consumed or a failure occurred. No partial consumption can occur.

Simplify its calls to clarify this.

While at it, adjust style of callers as well.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-29 17:12:30 +02:00
datauwu 98b6197033 tests: fix incorrect charset labels
Several filename encoding tests were copied from KOI8-R or EUC-JP
cases, but now use CP1251 or CP932/SJIS instead.

Update skip messages, conversion messages, and comments to match the
locales and byte sequences used by the tests.

Also fix a typo in an EUC-JP ZIP filename skip message.
2026-06-29 17:59:34 +08:00
data 8e3d979e58 zip: compare full file3 contents in tests
The file3_deflate payload is written and read as 5 bytes, but the test
only compared the first 4 bytes. Compare the full payload.
2026-06-29 17:41:22 +08:00
data 437cdf542f 7zip: remove redundant read header checks
archive_read_format_7zip_read_header() already returns before this
point if zip_entry is NULL. The folder pointer is also assigned from an
in-bounds folder array entry, so the extra NULL checks are redundant.

The later DONT_KNOW reset is redundant as well, since the same state is
handled earlier in the function. Remove the dead checks without changing
the encryption detection logic.
2026-06-29 17:22:30 +08:00
Kaif Khan a9a73c0e63 iso9660: check ZF entry length before reading data bytes 2026-06-29 11:28:39 +05:30
Kaif Khan 86e5498285 iso9660: add regression test for short ZF entry over-read 2026-06-29 11:28:38 +05:30
nvmb3r 3c231ffe01 rar5: reject streams exceeding unpacked size 2026-06-28 19:04:16 -07:00
nvmb3r b41a768d61 rar5: add unpacked-size regression test 2026-06-28 17:35:16 -07:00
Dustin L. Howett b5aceb5887 Merge pull request #3197 from stoeckmann/mtree_cast
mtree: Fix integer overflow on 32 bit systems
2026-06-28 15:41:48 -05:00
Tobias Stoeckmann b3ad4f20c7 mtree: Fix integer overflow on 32 bit systems
If a file close to SSIZE_MAX in size is mapped into memory and checked
for mtree, a signed integer overflow could occur.

While this this generally harmless and the scenario very unlikely, fix
the issue with a proper cast.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-28 22:16:42 +02:00
Dustin L. Howett a1b0e83464 Merge pull request #3196 from datauwu/7zip-redundant-per-entry-setup 2026-06-28 09:14:48 -05:00
Dustin L. Howett dbc3b336a5 Merge pull request #3193 from datauwu/zip-harden-test-cleanup-assertion 2026-06-28 08:30:25 -05:00
Dustin L. Howett 25ea451941 Merge pull request #3191 from stoeckmann/xattr_malloc 2026-06-28 08:29:11 -05:00
data 73286ad57f 7zip: remove redundant per-entry setup
`archive_read_format_7zip_read_header()` initialized `entry_crc32` with
`crc32(0, NULL, 0)`, which is equivalent to zero for this accumulator.

The same function also formatted the constant string `"7-Zip"` into an
internal buffer for every entry, then assigned it as the archive format name.
The format name can be set directly to the constant string, so the extra
buffer and per-entry `snprintf()` are unnecessary.

Remove the unused buffer and redundant per-entry work.
2026-06-28 21:28:15 +08:00
data a04a44a716 zip: harden test cleanup assertion
assertEqualIntA() uses the archive pointer to print archive error details
when the assertion fails. Passing `a` while the asserted expression is
`archive_free(a)` can make the failure path inspect the archive after it has
already been freed.
2026-06-28 18:43:13 +08:00
Tobias Stoeckmann ce962f1425 ar: Use correct data types
Use int64_t for entry/file sizes.
Use size_t for sizes in heap.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-28 12:11:02 +02:00
Tobias Stoeckmann 4bb750c789 xattr: Treat memory allocation failure as error
Do not silently truncate values if allocation fails.

Reported by ysf.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-28 10:43:31 +02:00
Dustin L. Howett d796465006 disk (win32): do not promote ENOENT to EPERM in CreateSymbolicLinkW 2026-06-27 13:44:08 -05:00
Dustin L. Howett 9195cd510c disk (win32): disallow hard links to symlinks 2026-06-27 13:44:08 -05:00
Dustin L. Howett adde805055 disk (win32): invalidate the safe path cache when we write a symlink 2026-06-27 13:44:08 -05:00
Dustin L. Howett a572920479 disk (win32): when caching a path as symlink-safe, only cache the parent
We used to cache the entire target path, which presented a problem when
we used that target path to write a symlink. Future archive entries
could write "through" that symlink because we cached it as safe.
2026-06-27 13:44:07 -05:00
Dustin L. Howett 0e1f3f1c74 disk (win32): lift check_symlinks' logic into ...by_path 2026-06-27 13:44:07 -05:00
Dustin L. Howett 74a7989176 disk (win32): remove 'a' parameter from file_information 2026-06-27 13:44:07 -05:00
Dustin L. Howett 852ffdfd9b disk (win32): use the provided path for CreateFile 2026-06-27 13:44:07 -05:00
Dustin L. Howett f1915cc0b4 test: light up the secure746 (hardlink + symlink) tests on Windows 2026-06-27 13:44:07 -05:00
Dustin L. Howett 2ecc8f5d9b test: add a clarifying comment to secure745 2026-06-27 13:44:07 -05:00
Dustin L. Howett 88084472eb test: light up the secure744 (deep nested symlinks) tests on Windows 2026-06-27 13:44:07 -05:00
Dustin L. Howett 56546a0a4e test: add a variant of the secure tests for windows 2026-06-27 13:44:07 -05:00
Tim Kientzle 82c0149234 Merge pull request #3188 from cyphercodes/fix-3151-empty-pax-headers
Reject empty pax extended headers
2026-06-27 09:03:47 -07:00
cyphercodes 80f126c97d Reject empty pax extended headers 2026-06-27 18:13:07 +03:00
Tobias Stoeckmann b1677ddb92 Merge pull request #3185 from stoeckmann/7zip_integers
7zip: Improve integer handling
2026-06-27 16:57:10 +02:00
Tobias Stoeckmann 4558c310de Merge pull request #3167 from stoeckmann/unzip_windows
unzip: Add Windows port
2026-06-27 16:56:53 +02:00
Tobias Stoeckmann f58645fb60 7zip: Fix style and typos
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-26 19:23:40 +02:00
Tobias Stoeckmann 9a92fb1d92 7zip: Move files_info_numfiles_is_sane body
Declare and define files_info_numfiles_is_sane like all other static
functions in this file.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-26 19:23:40 +02:00
Tobias Stoeckmann 532b6a8d9e 7zip: Do not store unused values
If values are only parsed and verified but not used later on, skip field
assignments. This reduces amount of fields to audit.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-26 19:23:40 +02:00
Tobias Stoeckmann e9e9b2ebcc 7zip: Check skip in setup_decode_folder
Make sure that all bytes are actually skipped. Normally, the result can
be ignored because the bytes were read previously. Here, more bytes than
previously read will be skipped.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-26 19:23:40 +02:00
Tobias Stoeckmann 20e12ad019 7zip: Fix BZ2/DEFLATE with huge input files
If more than UINT_MAX byte are available, e.g. if a very large archive
is mapped into memory, the BZ2/DEFLATE avail_in/avail_out values are
truncated.

Set to maximum allowed value in such cases.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-26 19:23:40 +02:00
Tobias Stoeckmann cd938e2815 7zip: Simplify decode_encoded_header_info
With correct data types in place, simplify the overflow check by using
checked arithmetic and simple comparison.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-26 19:23:40 +02:00
Tobias Stoeckmann aca55d476b 7zip: Use correct data types
Follow idea of internal libarchive APIs:

- File offsets and sizes are int64_t
- Memory offsets and sizes are size_t

Also use correct data types for iterator variables.

This refactoring also makes parse_7zip_uint64 obsolete by turning it
into parse_7zip_int64.

Resolves GHSA-m4vx-w6j3-jp82.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-26 19:23:40 +02:00
Tobias Stoeckmann 5a7ae702e4 7zip: Unify unpack_streams check
Use checked arithmetic and unify unpack_streams check to cover all
cases. This should be a purely defensive measure.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-26 19:23:40 +02:00
Tobias Stoeckmann c1bcd9ca9e 7zip: Unify UMAX_ENTRY check
Introduce parse_7zip_size, which performs the UMAX_ENTRY check.
Generally, use this function whenever memory allocation sizes or indices
into memory allocations are used, i.e. when size_t is meant.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-26 19:23:40 +02:00
Tobias Stoeckmann c1ddb31c07 7zip: Use checked arithmetic more often
Use checked arithmetic to avoid overflows. Use it also where checks are
already in place for better readability.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-26 19:23:40 +02:00
Tobias Stoeckmann a6e72ee36a 7zip: Simplify decode_codec_id
Since we have checked integer arithmetic now, use it.
Clarify that INT64_MAX is the maximum according to standard.

With that, switch to int64_t to avoid (unsigned long)-1 casts.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-26 19:23:40 +02:00
Tobias Stoeckmann b7e902b471 7zip: Check numDigests in read_SubStreamsInfo
Verify that sum of numUnpackStreams will never overflow numDigests. For
this, also set numDigests to size_t because that's how the variable is
used later on.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-26 19:23:40 +02:00
Tobias Stoeckmann 48657cc38f 7zip: Handle large requests in extract_pack_stream
If the minimum amount of bytes could overflow size_t after alignment,
allocate exact minimum amount instead.

This avoids integer overflow and will most likely lead to regular OOM
error handling instead.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-26 19:23:36 +02:00
Tobias Stoeckmann bc3e9af734 7zip: Skip bytes in read_stream in chunks
Avoid huge requests while skipping bytes to avoid integer truncation and
memory allocation issues.
2026-06-26 18:36:04 +02:00
Tobias Stoeckmann a42f5d1322 7zip: Improve integer handling in skip_stream
The skip_stream function is supposed to skip a specified amount of bytes
from input stream. Since streams could be larger than 4 GB even on 32
bit systems, do not cast to size_t. Instead, read the data in small
chunks until all bytes are skipped.

This also helps to avoid large allocations on 64 bit systems.

Also verify that skipped_bytes tracking cannot overflow.

While at it, change return value to int because it's only needed for
status information, i.e. if operation was successful or not. This avoids
another cast issue with uint64_t values larger than INT64_MAX.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-26 18:36:04 +02:00
Dustin L. Howett 1a778f9c10 Merge pull request #3181 from uchiha-bug-hunter/xar-atou64-overread 2026-06-26 07:56:20 -05:00
Kaif Khan 62be4ffdc4 xar: stop atou64 reading one byte past the numeric field 2026-06-26 13:57:18 +05:30
Kaif Khan 0352fe5033 xar: add regression test for atou64 numeric field over-read
Exercise atou64() through a TOC numeric element (<inode>) read via the
expat backend, which hands the parser its raw, non-NUL-terminated
character-data buffer. Mirrors test_read_format_xar_base64_oob; build
with ASan for the out-of-bounds coverage.
2026-06-26 13:57:11 +05:30
Dustin L. Howett 414e4e05ca Merge pull request #3183 from uchiha-bug-hunter/gnutar-gname-overflow 2026-06-25 18:31:30 -05:00
Dustin L. Howett 42d9794ec5 Merge pull request #3182 from bluca/seek_issue
read_data_into_fd: Fix spurious "Seek error" for trailing holes
2026-06-25 14:01:53 -05:00
Luca Boccassi 91c146e87d read_data_into_fd: Fix spurious "Seek error" for trailing holes
The final seek check never advanced actual_offset for the trailing
hole created by the EOF pad_to(), so extracting any sparse file whose
last region is a hole failed with ARCHIVE_FATAL "Seek error".

This affects the systemd CI which does such an operation, and now
fails since PR https://github.com/libarchive/libarchive/pull/3128
was merged and appeared in Archlinux:

 [  269.636946] TEST-13-NSPAWN.sh[5439]: + run0 --pipe -u testuser importctl -m --user import-tar - inodetest2
 [  270.132545] TEST-13-NSPAWN.sh[5440]: Enqueued transfer job 7. Press C-c to continue download in background.
 [  270.137660] TEST-13-NSPAWN.sh[5440]: Exporting '/home/testuser/.local/state/machines/inodetest', saving to 'pipe:[79515]' with compression 'uncompressed'.
 [  270.148434] TEST-13-NSPAWN.sh[5441]: Enqueued transfer job 8. Press C-c to continue download in background.
 [  270.173410] TEST-13-NSPAWN.sh[5441]: Importing 'pipe:[79515]', saving as 'inodetest2'.
 [  270.178790] TEST-13-NSPAWN.sh[5441]: Operating on image directory '/home/testuser/.local/state/machines'.
 [  270.386155] TEST-13-NSPAWN.sh[5440]: Operation completed successfully.
 [  270.389171] TEST-13-NSPAWN.sh[5440]: Exiting.
 [  270.689994] TEST-13-NSPAWN.sh[5441]: Failed to unpack regular file 'testfile': Seek error

https://github.com/systemd/systemd/actions/runs/28159904022/job/83436896561?pr=42736

A local and small regression test is added that replicates that test's
behaviour.
2026-06-25 17:57:32 +01:00
Kaif Khan 1be2aea27e gnutar: fix stack overflow writing oversized gname field 2026-06-25 22:22:56 +05:30
Kaif Khan f2e80fff9c gnutar: add regression test for oversized gname field 2026-06-25 22:22:56 +05:30
Dustin L. Howett bad51bcc8d Merge pull request #3180 from dag-erling/des/3.8.8-fixes
Miscellaneous fixes for 3.8.8

* configure.ac: Remove unused checks
* libarchive: Fix `TIME_MAX` and `TIME_MIN`
* test: Fix off-by-one in bounds check
  Fixes:                0e4fa9ff0d ("test: promote the win32-repairing systemf wrapper to all systemf calls")
* bsdunzip_test: Set umask before asserting permissions
  Fixes:                34b3da0013 ("unzip: Add symlink tests")
* archive_write_disk_posix: Fix type issues
  Fix type issues in the HFS+ (de)compression code, primarily to avoid
  arithmetic overflow when calculating the block count during compression.
* archive_write_disk_posix: Miscellaneous cleanup
  Use `S_IS*()` macros consistently and clean up some `#ifdef`s.
* archive_write_disk_posix: Symlinks can have AppleDouble data
* libarchive: Fix format string issues
2026-06-24 13:51:42 -05:00
Dustin L. Howett 7633fd475e Merge pull request #3177 from DHowett/zisofs-creation-size 2026-06-24 13:13:40 -05:00
Dag-Erling Smørgrav db1bb73b86 libarchive: Fix format string issues 2026-06-24 18:25:01 +02:00
Dag-Erling Smørgrav 04f2cbc98c archive_write_disk_posix: Symlinks can have AppleDouble data 2026-06-24 18:25:01 +02:00
Dag-Erling Smørgrav bf0057ee7d archive_write_disk_posix: Miscellaneous cleanup
Use S_IS*() macros consistently and clean up some #ifdefs.
2026-06-24 18:25:01 +02:00
Dag-Erling Smørgrav a008f61155 archive_write_disk_posix: Fix type issues
Fix type issues in the HFS+ (de)compression code, primarily to avoid
arithmetic overflow when calculating the block count during compression.
2026-06-24 18:25:00 +02:00
Dag-Erling Smørgrav 355f7cb849 bsdunzip_test: Set umask before asserting permissions
Fixes:		34b3da0013 ("unzip: Add symlink tests")
2026-06-24 18:25:00 +02:00
Dag-Erling Smørgrav d4fa1de0ad test: Fix off-by-one in bounds check
Fixes:		0e4fa9ff0d ("test: promote the win32-repairing systemf wrapper to all systemf calls")
2026-06-24 18:25:00 +02:00
Dag-Erling Smørgrav fc6bca4b06 libarchive: Fix TIME_MAX and TIME_MIN 2026-06-24 18:25:00 +02:00
Reyad Attiyat bf0ce94fec unzip: mark bsdunzip as long-path aware on Windows
Signed-off-by: God-damnit-all <53661808+God-damnit-all@users.noreply.github.com>
2026-06-24 18:02:20 +02:00
Tobias Stoeckmann 37b0b5a502 unzip: Add Windows port
Copy missing functionality from libarchive and cpio.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-24 18:02:15 +02:00
Dustin L. Howett 1502f42ba2 iso9660: do not overflow zisofs block pointer count when a file is ~4GiB
(applies to 32-bit builds of libarchive)

Files within one ZF_BLOCK_SIZE of 4 GiB (which is, incidentally, the max
zisofs-compressible file size) would trigger an overflow in the
calculation of the number of block _pointers_ they would require. We
could have rejected those files, but the truth is that they just require
exactly 131073 block pointers (131072 for the file itself and one for
the trailer.)
2026-06-24 10:52:06 -05:00
Dustin L. Howett 02447e94d0 iso9660: add a test for the 32-bit zisofs overflow case
Writing a file near 4 GiB causes an overflow when we calculate the
number of block pointers we need to store, which leads to us allocating
the wrong amount of memory to store them.

This is visible with ASan:

Exercising: libarchive 3.9.0dev zlib/1.3.1 liblzma/5.4.4 bz2lib/1.0.8 libzstd/1.5.6 cng/2.0 libb2/bundled
706: test_write_format_iso9660_zisofs_overflow
=================================================================
==40444==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x08c004b4 at pc 0x006acb3b bp 0x002edb44 sp 0x002edb38
WRITE of size 1 at 0x08c004b4 thread T0
    #0 0x006acb3a in archive_le32enc libarchive\archive_endian.h:219
    #1 0x006c81d0 in zisofs_write_to_temp libarchive\archive_write_set_format_iso9660.c:7760
    #2 0x006ca1bd in write_iso9660_data libarchive\archive_write_set_format_iso9660.c:1785
2026-06-24 10:51:48 -05:00
Tobias Stoeckmann 61b7147289 unzip: Improve portability
- Use contrib/untar's system_mkdir for extended portability
- Compile warning function only if it's actually used
- Use %H:%M instead of %R in strftime for extended portability
- Introduce system_unlink to add special directory symlink handling

Copy missing functionality from libarchive and cpio.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-24 17:45:23 +02:00
Dag-Erling Smørgrav 2a251501b0 configure.ac: Remove unused checks 2026-06-24 17:41:19 +02:00
Dustin L. Howett 6b468d68d1 Merge pull request #3160 from GeorgH93/fix_zipx_streaming_non_seekable
Fix zipx reading with ZIP_LENGTH_AT_END flag from non-seekable source
2026-06-24 08:42:37 -05:00
Tim Kientzle 6f85565e42 Merge pull request #3175 from uchiha-bug-hunter/xar-base64-oob-read
xar: fix OOB read decoding odd-length base64 in strappend_base64
2026-06-24 06:10:15 -07:00
Tim Kientzle 94daafd6fb Merge pull request #3178 from uchiha-bug-hunter/unzip-pathname-dotdot
unzip: reject bare '..' and trailing '/..' in pathname_is_insecure
2026-06-24 06:08:25 -07:00
Kaif Khan e1730385ee unzip: reject bare '..' and trailing '/..' in pathname_is_insecure 2026-06-24 12:00:05 +05:30
Kaif Khan 79fe496410 unzip: add regression test for insecure '..' symlink targets 2026-06-24 12:00:05 +05:30
Kaif Khan d78dda0304 xar: fix OOB read decoding odd-length base64 in strappend_base64 2026-06-24 10:56:44 +05:30
Kaif Khan 98c25d8b5c xar: add regression test for odd-length base64 name decoding
Crafted TOC with a base64-encoded <name> of odd length, which used to
make strappend_base64() read past the character-data buffer. The trailing
incomplete base64 character is dropped; the rest still decodes.
2026-06-24 10:56:44 +05:30
Dustin L. Howett c0e779b73c Merge pull request #3162 from soda0289/add-windows-long-path-manifest
tar: mark bsdtar as long-path aware on Windows

tar -C/--directory option calls SetCurrentDirectoryW(), which is limited to MAX_PATH (260) characters unless the process opts in to longpath support via an application manifest and enables a registry setting or sets an option in developer settings.
2026-06-23 23:33:12 -05:00
Tobias Stoeckmann df13c97c45 Merge pull request #3176 from stoeckmann/unzip_tests
unzip: Extend test suite
2026-06-23 20:29:22 +02:00
Tobias Stoeckmann 34b3da0013 unzip: Add symlink tests
Verify that symlink creations and overwriting works, i.e. that dangling
symlinks are properly overwritten.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-23 20:12:26 +02:00
Tobias Stoeckmann a3d38d0272 unzip: Add -u test
Verify that -u does not override files which have a newer timestamp.

This also verifies that creation of timestamps properly works.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-23 20:12:26 +02:00
Tobias Stoeckmann 4f70bf0e7b unzip: Add -f test
Verify that -f does not create new files and also does not override
files which have a newer timestamp.

This also verifies that creation of timestamps properly works.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-23 20:12:23 +02:00
Martin Matuška 2b9cacf6e8 Merge pull request #3171 from libarchive/dependabot/github_actions/all-actions-2217aebe03
CI: Bump actions/checkout from 6.0.3 to 7.0.0 in the all-actions group
2026-06-23 09:56:06 +02:00
Martin Matuška 9819bc9370 Merge pull request #3172 from stoeckmann/lafe_fnmatch
libarchive_fe: Import FreeBSD's fnmatch
2026-06-23 09:42:50 +02:00
Reyad Attiyat 6ef83d7a41 tar: mark bsdtar as long-path aware on Windows
bsdtar's -C/--directory option calls SetCurrentDirectoryW(), which is
 limited to MAX_PATH (260) characters unless the process opts in to long
 path support via an application manifest declaring longPathAware.
 Extracting into (or changing into) a directory whose path exceeds 260
 characters fails with "could not chdir".

 Embed a longPathAware application manifest into bsdtar.exe so these
 operations work for long destination paths. Both Windows build systems
 (CMake and the autotools/Makefile.am build) embed it, using different
 mechanisms per toolchain:

   - MinGW/Clang (GNU ld) do not generate an application manifest, so it
     is compiled from a resource script (bsdtar.rc) via windres. This
     manifest replaces the toolchain default, so it also declares the
     asInvoker execution level explicitly.
   - MSVC's linker already embeds a manifest (resource id 1); a duplicate
     RT_MANIFEST resource fails to link (CVT1100). Instead the manifest is
     merged into the linker's default manifest (asInvoker) by adding it to
     the target sources.
2026-06-22 22:37:05 -05:00
Dustin L. Howett ca1e27dd6a Merge pull request #3173 from stoeckmann/cpio_endian
cpio: Avoid naming conflict with endian functions
2026-06-22 14:39:56 -05:00
Tobias Stoeckmann 266b9136f2 cpio: Avoid naming conflict with endian functions
The local functions be32dec and le32dec lead to conflicts on NetBSD. Use
a proper prefix as suggested by Dustin L. Howett.

Resolves #3170.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-22 21:24:04 +02:00
Dustin L. Howett c55c66b507 Merge pull request #3168 from uchiha-bug-hunter/cpio-write-pathlength-oob
cpio: fix OOB read from int pathlength truncation in newc/binary writers
2026-06-22 13:42:54 -05:00
Tobias Stoeckmann 2615ba5cd5 libarchive_fe: Import FreeBSD's fnmatch
If system lacks fnmatch(3), use FreeBSD's fnmatch. It's adjusted for
increased compatibility, i.e. it uses strcoll instead of FreeBSD's
library internals and const char pointers where needed with latest
GNU/Linux toolchains.

FreeBSD source can be obtained here:

https://github.com/freebsd/freebsd-src/blob/dc36d6f9bb1753f3808552f3afd30eda9a7b206a/lib/libc/gen/fnmatch.c

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-22 20:32:23 +02:00
dependabot[bot] cddc2dea9e CI: Bump actions/checkout from 6.0.3 to 7.0.0 in the all-actions group
Bumps the all-actions group with 1 update: [actions/checkout](https://github.com/actions/checkout).


Updates `actions/checkout` from 6.0.3 to 7.0.0
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/df4cb1c069e1874edd31b4311f1884172cec0e10...9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: all-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-22 16:12:57 +00:00
uchiha-bug-hunter 849eeab664 cpio: fix OOB read from int pathlength truncation in newc/binary writers 2026-06-22 15:11:13 +05:30
Tobias Stoeckmann c56456886d Merge pull request #3166 from stoeckmann/unzip_p_enc_test
unzip: Skip another test if zlib unavailable
2026-06-22 07:44:58 +02:00
Tobias Stoeckmann ed9f5ad7d2 unzip: Skip another test if zlib unavailable
The input file in test_P_encryption uses deflate, which is only
available if zlib is available. Skip the test if built without zlib.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-21 21:07:43 +02:00
Dustin L. Howett 29657bc0c3 Merge pull request #3164 from stoeckmann/iso9660_realloc 2026-06-20 11:34:51 -05:00
Tobias Stoeckmann 427d423021 iso9660: Remove realloc from idr_extend_identifier
Allocate enough memory with initial malloc for possible additions, which
removes any kind of error handling required in idr_extend_identifier.

The additional memory allocated was already large enough. Clarify
exactly where the required amount comes from by using named constants.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-20 11:16:02 +02:00
Dustin L. Howett cafc7f7156 Merge pull request #3165 from stoeckmann/error_zero
Do not set 0 as error code, since this will be printed as success. Use proper error codes in various places for better error messages.
2026-06-19 17:19:18 -05:00
Tobias Stoeckmann 3f1a6882ac Avoid 0 as error code
Do not set 0 as error code, since this will be printed as success. Use
proper error codes in various places for better error messages.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-19 17:45:42 +02:00
Martin Matuška ba387256e0 Merge pull request #2918 from aale24/fix-test-format-newc-race
Fix test_format_newc timestamp race condition
2026-06-19 09:48:25 +02:00
Tobias Stoeckmann 042501f89c Merge pull request #3158 from stoeckmann/cpio_write
cpio: Fix writer OOB read with very long filenames
2026-06-18 22:51:43 +02:00
Dustin L. Howett 7ab1a6538e Merge commit from fork
xattr/sparse: Fix UAF by nullifying pointer
2026-06-18 11:41:47 -05:00
Martin Matuška 2498165482 Merge pull request #3159 from stoeckmann/ckd_size
Use checked size_t arithmetic
2026-06-18 16:37:15 +02:00
Tobias Stoeckmann 1ff898d4a0 Use checked size_t arithmetic
Add archive_ckd_add_size and archive_ckd_mul_size. Use them for checked
arithmetic throughout the source code where explicit SIZE_MAX checks
were performed.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-18 07:48:45 +02:00
Dustin L. Howett 22e1240357 Merge pull request #3135 from stoeckmann/read_ahead_format
formats: Simplify `__archive_read_ahead` use
2026-06-17 21:20:51 -05:00
GeorgH93 22d16a04e4 Fix reading ppmd8 zipx with ZIP_LENGTH_AT_END flag from non-seekable stream 2026-06-17 22:42:50 +02:00
GeorgH93andMarco ea7b2da999 zip: fix OOB read in streaming WinZip-AES xz decryption
entry_bytes_remaining goes negative for a streaming entry after the AES
header is subtracted; zip_read_data_zipx_xz passed it to zip_read_decrypt
as a size_t, causing an out-of-bounds read.

Co-Authored-By: Marco <marco@mpreimann.de>
2026-06-17 22:42:13 +02:00
GeorgH93 f63a943a32 Fix reading lzma zipx with ZIP_LENGTH_AT_END flag from non-seekable stream 2026-06-17 22:35:59 +02:00
GeorgH93 501d6341d7 Fix reading xz zipx with ZIP_LENGTH_AT_END flag from non-seekable stream 2026-06-17 22:35:13 +02:00
GeorgH93 369084a4f7 Fix reading bzip2 zipx with ZIP_LENGTH_AT_END flag from non-seekable stream 2026-06-17 22:33:49 +02:00
GeorgH93 11a8ab6c10 Fix reading zstd zipx with ZIP_LENGTH_AT_END flag from non-seekable stream 2026-06-17 22:31:59 +02:00
GeorgH93 298d95faa0 Expand testing for encrypted zipx to also test streaming headers and non seekable data sources 2026-06-17 22:30:58 +02:00
Tobias Stoeckmann e8e3cdf184 formats: Simplify __archive_read_ahead use
Set the third argument to NULL if the amount of actually read bytes is
not needed. This simplifies code audits.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-17 22:22:46 +02:00
Tobias Stoeckmann 26980ccecd cpio: Fix OOB read with very long filenames
If a filename is larger than INT_MAX, eventual size_t/int/size_t
conversions lead to huge size_t values and subsequent OOB reads.

Use correct values. Before this would lead to unnecessary writes, the
filename length field check already aborts the operation.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-17 19:43:18 +02:00
Tobias Stoeckmann 7a1ec48f19 cpio: Verify that filename length fits into field
If the filename length cannot be represented as octal in its field,
return an error instead of silently truncating the value.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-17 19:36:42 +02:00
Martin Matuška ead081b704 Merge pull request #3157 from libarchive/dependabot/github_actions/all-actions-0a5d8bb8fa
CI: Bump the all-actions group across 1 directory with 5 updates
2026-06-17 11:30:05 +02:00
Martin Matuška fc0530d502 Merge pull request #3150 from DHowett/ci/windows-package-dependencies
build: windows: get all CI dependencies from a package manager
2026-06-17 09:29:46 +02:00
dependabot[bot] 13f4760ddd CI: Bump the all-actions group across 1 directory with 5 updates
Bumps the all-actions group with 5 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [acj/freebsd-firecracker-action](https://github.com/acj/freebsd-firecracker-action) | `0.9.1` | `0.10.0` |
| [actions/checkout](https://github.com/actions/checkout) | `6.0.1` | `6.0.3` |
| [actions/upload-artifact](https://github.com/actions/upload-artifact) | `6.0.0` | `7.0.1` |
| [cygwin/cygwin-install-action](https://github.com/cygwin/cygwin-install-action) | `6.0.1` | `6.0.2` |
| [github/codeql-action](https://github.com/github/codeql-action) | `4.31.9` | `4.36.2` |



Updates `acj/freebsd-firecracker-action` from 0.9.1 to 0.10.0
- [Release notes](https://github.com/acj/freebsd-firecracker-action/releases)
- [Commits](https://github.com/acj/freebsd-firecracker-action/compare/bab3e77871573c7943b80816f1641b6c1ce36896...ff79eb955fd19c697a708a02834995e47a6e58ed)

Updates `actions/checkout` from 6.0.1 to 6.0.3
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/8e8c483db84b4bee98b60c0593521ed34d9990e8...df4cb1c069e1874edd31b4311f1884172cec0e10)

Updates `actions/upload-artifact` from 6.0.0 to 7.0.1
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/b7c566a772e6b6bfb58ed0dc250532a479d7789f...043fb46d1a93c77aae656e7c1c64a875d1fc6a0a)

Updates `cygwin/cygwin-install-action` from 6.0.1 to 6.0.2
- [Release notes](https://github.com/cygwin/cygwin-install-action/releases)
- [Commits](https://github.com/cygwin/cygwin-install-action/compare/711d29f3da23c9f4a1798e369a6f01198c13b11a...3f0a3f9f988f7e96b8c18098ae05eaec175f5b52)

Updates `github/codeql-action` from 4.31.9 to 4.36.2
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/5d4e8d1aca955e8d8589aabd499c5cae939e33c7...8aad20d150bbac5944a9f9d289da16a4b0d87c1e)

---
updated-dependencies:
- dependency-name: acj/freebsd-firecracker-action
  dependency-version: 0.10.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-actions
- dependency-name: actions/checkout
  dependency-version: 6.0.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-actions
- dependency-name: actions/upload-artifact
  dependency-version: 7.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: all-actions
- dependency-name: cygwin/cygwin-install-action
  dependency-version: 6.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-actions
- dependency-name: github/codeql-action
  dependency-version: 4.36.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-17 07:25:32 +00:00
Martin Matuška 26f68fcc6d Merge pull request #3144 from stoeckmann/cab_truncation
cab: Improve truncation detection
2026-06-17 08:49:31 +02:00
Martin Matuška f6dea9e94b Merge pull request #3134 from stoeckmann/archive_integer
Introduce `archive_integer.h` for checked arithmetic
2026-06-17 08:48:55 +02:00
Tobias Stoeckmann 8510878d38 Merge pull request #3145 from stoeckmann/cab_max_namelen
cab: Properly limit maximum name length
2026-06-17 08:32:03 +02:00
Dustin L. Howett 5e566cf0c6 Merge pull request #3153 from stoeckmann/cab_multi
cab: Fix multi volume parser
2026-06-16 21:57:14 -05:00
Tobias Stoeckmann 5e605fd8b0 cab: Fix name reading
Archives are not necessarily 256 bytes long, e.g. the last part of a
multi volume archive. Only try to read up to 256 bytes when looking for
an archive or disk name, not necessarily exactly 256 bytes. This matches
the behavior of regular entry name lookups.

Also, disk names can be empty. Handle this as well.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-16 22:59:17 +02:00
Tobias Stoeckmann 551623e6ed cab: Add test for multi volume archives
The cab reader does not support multi volume archives, but it should be
able to read the files to print information about content.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-16 21:37:55 +02:00
Dustin L. Howett d3d511ca9e Merge pull request #3142 from datauwu/tar-avoid-wcs-slash-check
tar: avoid wide pathname conversion for trailing slash check
2026-06-15 20:00:23 -05:00
Dustin L. Howett 374f901a4d build: use vcpkg for Windows-MSVC's dependencies 2026-06-15 15:27:37 -05:00
Dustin L. Howett 3087dc0cc8 build: move library dependencies into mingw install 2026-06-15 15:27:37 -05:00
Dustin L. Howett 18a8a6d1fc build: use the setup-msys2 action rather than chocolatey
This will give us some ability in the future to vary `MSYSTEM` and
produce different MSYS builds.
2026-06-15 15:27:37 -05:00
Dustin L. Howett d5a1026aea Merge pull request #3148 from XananasX7/ci/pin-actions
ci: pin acj/freebsd-firecracker-action to full commit SHA
2026-06-15 15:25:35 -05:00
Dustin L. Howett 1bf2b2ac3f Merge pull request #3149 from DHowett/fix-mingw-tests 2026-06-15 15:24:06 -05:00
Dustin L. Howett 3ccaf85c7c tar: use filesystem-neutral replacement characters in the -s test 2026-06-15 15:08:02 -05:00
Dustin L. Howett 0e4fa9ff0d test: promote the win32-repairing systemf wrapper to all systemf calls 2026-06-15 15:08:02 -05:00
XananasX7 126299f2dd ci: pin acj/freebsd-firecracker-action to full commit SHA
acj/freebsd-firecracker-action: @v0.9.1 -> @bab3e77871573c7943b80816f1641b6c1ce36896
2026-06-14 18:38:24 +00:00
Dustin L. Howett 7a35e71786 Merge pull request #3143 from stoeckmann/7zip_size_int64
7zip: Avoid unnecessary int64_t size_t casts
2026-06-14 10:01:50 -05:00
Dustin L. Howett 99d695c0d3 Merge pull request #3146 from stoeckmann/size_t_off
read_disk: Check if off_t can overflow size_t
2026-06-14 09:59:01 -05:00
Tobias Stoeckmann a8f3aebd3a read_disk: Check if off_t can overflow size_t
Make sure that the content of the link can fit into a size_t. This
should be always true, but be cautious with 32 bit systems and very
weird filesystems (possibly through fuse).

I took SSIZE_MAX as upper limit due to signedness and eventual readlink
calls which would fail with larger values anyway.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-14 11:14:03 +02:00
Tobias Stoeckmann 06d6ea17dd 7zip: Avoid unnecessary int64_t size_t casts
Use size_t for avail_in, avail_out and stream_in for ppmd streams.

The fields avail_in and avail_out values are set in function decompress
based on size_t variables (t_avail_in/t_avail_out) and eventually
written back. The stream_in field is only incremented.

The actual use case happens within ppmd_read to support situations in
which not enough bytes are available. In such cases, more bytes are read
on demand but not written into next_in.

In such cases, avail_in can turn negative and next_in can point outside
of its allocated memory area.

Since stream_in is always incremented by one, it won't overflow on real
hardware, given that size_t would address the whole available heap
space.

Make sure that avail_in never turns negative (which allows the size_t
usage) and also guarantee that t_avail_in will never wrap around,
leading to a huge "used" value.

As a bonus, __archive_read_ahead can be reliably called with a NULL
argument now, since no more casting occurs for second argument, which
was missing in the test.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-13 16:17:25 +02:00
Tobias Stoeckmann e0f04e1d1a cab: Properly limit maximum name length
The cab_read_ahead_remaining function might return more bytes through
avail than initially asked for. The given limit is 255+1, i.e. the
maximum file name length.

While it's not a big deal for libarchive to handle file names longer
than that, the CAB format does not allow longer names.

Limit the amount of available bytes to the given argument for proper
checking.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-13 16:08:10 +02:00
Tobias Stoeckmann 8ed86bf17b cab: Improve truncation detection
If not enough bytes are available, __archive_read_ahead will return the
amount of bytes still available, which can be larger than 0. Only in
error cases, a negative value is returned.

Check the return pointer instead. It simplifies the error handling,
allows a NULL argument, and covers more truncation issues.

Right now, a NULL pointer with a non-zero size could be further
processed, which just asks for more technical or logical issues to
arise.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-13 16:02:38 +02:00
data 83ca7801f2 tar: avoid wide pathname conversion for trailing slash check
Avoid requesting the wide-character pathname when the tar reader only
needs to check whether a regular entry name ends in '/'.

archive_entry_pathname_w() can lazily convert the pathname to WCS. In the
common tar read path, the multibyte pathname is already available, so
checking it first avoids unnecessary per-entry conversion. The WCS fallback
is kept for cases where the multibyte pathname is unavailable.
2026-06-13 08:12:52 +08:00
Tobias Stoeckmann 710503d83c time: Use archive_integer.h
Use archive_integer's checked integer arithmetic.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-12 23:32:41 +02:00
Tobias Stoeckmann 7df4dee12d time: Sort header includes
While at it, add header checks.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-12 23:32:41 +02:00
Tobias Stoeckmann 8df82c3154 Use archive_integer.h for number parsers
Use checked integer arithmetic to detect integer overflows.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-12 23:32:41 +02:00
Tobias Stoeckmann 16be338523 Add archive_integer.h
The archive_integer.h header offers various integer operations to
libarchive, utilizing system functionality where possible.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-12 23:32:36 +02:00
Dustin L. Howett fdd53e2c23 Merge pull request #3138 from datauwu/tar-ustar-pathname-fastpath 2026-06-12 13:17:58 -05:00
Tobias Stoeckmann 42c656a3f9 Merge pull request #3140 from DHowett/dh/write-free-1
test: remove one new instance of assertEqualIntA(...free...)
2026-06-12 18:05:13 +02:00
Dustin L. Howett b9f9d0e3f6 test: remove one new instance of assertEqualIntA(...free...) 2026-06-12 10:32:27 -05:00
Dustin L. Howett b66d136b70 Merge pull request #2865 from GeorgH93/read_zipx_encryption
Add support for reading encrypted zipx formats (bzip2, lzma, ppmd, xz, zstd)
2026-06-12 10:28:45 -05:00
GeorgH93 b266da129a Introduce zipx encryption handling for zstd compressed zip files 2026-06-12 12:02:41 +02:00
GeorgH93 43682f0e7a Introduce zipx encryption handling for bzip2 compressed zip files 2026-06-12 12:02:41 +02:00
GeorgH93 26256df5ab Introduce zipx encryption handling for lzma compressed zip files 2026-06-12 12:02:33 +02:00
GeorgH93 91ffcda239 Introduce zipx encryption handling for xz compressed zip files 2026-06-12 12:01:15 +02:00
GeorgH93 02411983a5 Introduce zipx encryption handling for ppmd compressed zip files 2026-06-12 12:01:09 +02:00
GeorgH93 67a848c947 Add test for creating encrypted zip file with libarchive and reading it again with libarchive 2026-06-12 11:54:14 +02:00
GeorgH93 4a7bcbbeeb Refactor zip archive reader, by moving decryption related code blocks into their own functions to make them reusable for compression formats other than deflate 2026-06-12 11:49:24 +02:00
data ec9d2fb992 tar reader: avoid temporary buffer for empty-prefix ustar names
For empty-prefix ustar entries, copy the fixed-width name field
directly into the archive entry instead of first building a temporary
archive_string.

This avoids a temporary buffer allocation and intermediate copy in the
common case. It also fixes a small fatal-error leak by freeing the
temporary prefix/name buffer before returning on pathname conversion
failure.
2026-06-12 15:36:28 +08:00
Tobias Stoeckmann 10bd4da47b Merge pull request #2923 from bililateral/pr-7zip-numfiles-oom
7zip: sanity-check FilesInfo NumFiles before allocating entries
2026-06-12 08:27:25 +02:00
Dustin L. Howett c09f7b044b Merge pull request #3105 from i1011/rar-unbounded-staticdata-fix
rar: Add missing bound check for staticdata
2026-06-11 23:09:19 -05:00
Dustin L. Howett 727be2f1a5 Merge pull request #3137 from stoeckmann/typos_style
Fix minor non-functional issues
2026-06-11 23:05:03 -05:00
Dustin L. Howett 5a7d75f3e6 Merge pull request #3136 from stoeckmann/counters
Remove unneeded counters
2026-06-11 15:41:05 -05:00
Tobias Stoeckmann 527e30107e cpio: Remove unneeded cast
The variable l is uint64_t, the return type is uint64_t. Do not cast to
int64_t.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-11 20:36:44 +02:00
Tobias Stoeckmann 1e81181175 Fix whitespace issues
No functional change

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-11 20:36:40 +02:00
Tobias Stoeckmann 6a714b66f0 Fix typos in comments and documentation
No functional change

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-11 20:36:27 +02:00
Tobias Stoeckmann b3d3bed74b filters: Remove unneeded counters
These counters are written to, but they are never read. Remove them for
easier code audits.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-11 18:57:36 +02:00
Tobias Stoeckmann 349bc34c5f formats: Remove unneeded counters
These counters are written to, but they are never read. Remove them for
easier code audits.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-11 18:56:59 +02:00
i1011 59c659048f rar: Reject staticdatalen larger than VM memory 2026-06-12 00:51:16 +08:00
Tobias Stoeckmann 9bd1a06adb Merge commit from fork
unzip: reject absolute or traversing symlink targets
2026-06-11 17:41:31 +02:00
GeorgH93 8ac716260d Refactor the zip_winzip_aes_large test to support parameterized file ordering, file mode and compression type 2026-06-10 21:14:02 +02:00
bililateral 57389860f5 7zip: sanity-check FilesInfo NumFiles before allocating entries 2026-06-10 10:07:01 +08:00
Dustin L. Howett bede9a3692 Merge pull request #3048 from legnaleurc/fix/rar-reset-lz-table
rar: reset low-distance state for new LZ tables
2026-06-09 20:30:47 -05:00
Dustin L. Howett 82404ac239 Merge pull request #3047 from legnaleurc/fix/rar-recovery-record
rar: skip NEWSUB payloads without size cap
2026-06-09 20:26:31 -05:00
Dustin L. Howett 1b2af5a7a8 Merge pull request #3132 from stoeckmann/lz4_double_free
lz4: Fix double-free on reallocation failure
Alternative version of https://github.com/libarchive/libarchive/pull/2945 which removes the test (which requires a modified malloc to actually fail the 4 MB allocation).
2026-06-09 20:14:28 -05:00
Dustin L. Howett ea5c8fff0b Merge pull request #3034 from datauwu/master 2026-06-09 17:00:55 -05:00
isomorph-cyber a49a85002b Fix double-free in LZ4 filter on reallocation failure (CWE-415)
lz4_allocate_out_block() frees state->out_block without NULLing
the pointer. If the subsequent malloc fails, the function returns
ARCHIVE_FATAL with a dangling pointer. lz4_filter_close() later
calls free(state->out_block) again, triggering a double-free.

Also, state->out_block_size was updated before checking if malloc
succeeded, leaving inconsistent metadata on failure.

Fix both lz4_allocate_out_block() and lz4_allocate_out_block_for_legacy():
- NULL the pointer immediately after free
- Move size update to after malloc succeeds
- Reset size to 0 on allocation failure
2026-06-09 22:48:33 +02:00
datauwu f729237321 7zip: reject malformed SubStreamsInfo metadata
Validate the accumulated unpack stream count before allocating
per-substream metadata.

Reject folders that declare multiple substreams without kSize metadata,
since the parser needs those sizes to describe the stream layout.

Drop the explicit digest zeroing loop. The arrays are allocated with
calloc(), so the entries are already initialized.
2026-06-10 04:39:31 +08:00
datauwu 1960646fe8 7zip: add malformed SubStreamsInfo test
Add a 7z regression test for malformed SubStreamsInfo metadata that
declares more than one unpack stream without the kSize data needed to
describe those streams.

Store the archive as a .7z.uu file, matching the existing malformed
7z tests.
2026-06-10 03:10:27 +08:00
Dustin L. Howett ac92d07bf2 unzip: reject absolute or traversing symlink targets
This is overly broad, and will reject some well-formed archives which
contain symlinks to trees which exist in the archive; however, this is
the best we can do without some rudimentary path parsing.

Fixes GHSA-q4gj-vh8c-67p8
2026-06-09 11:16:02 -05:00
Dustin L. Howett 81385b8864 Merge pull request #2954 from ShelpAm/master
fix: zstd not found on Windows
2026-06-09 09:55:46 -05:00
Martin Matuška 983e1edcdd Merge pull request #2967 from bgilbert/deflate
Fix `test_write_filter_gzip` on Ubuntu s390x
2026-06-09 08:40:07 +02:00
Martin Matuška 65eaff4835 Merge pull request #3131 from stoeckmann/rpm_fsm
rpm: Refactor filter
2026-06-09 08:35:23 +02:00
Martin Matuška 5f8f651fae Merge pull request #3128 from stoeckmann/into_fd
Improve `archive_read_data_into_fd` with sparse files
2026-06-09 08:31:24 +02:00
Martin Matuška d9279e464c Merge pull request #3121 from stoeckmann/rar5_bytes_remaining
rar5: fix signed integer underflow in bytes_remaining
2026-06-09 08:30:03 +02:00
Martin Matuška b3da16bbf2 Merge pull request #3120 from stoeckmann/archive_endian
Extend `archive_endian.h` usage
2026-06-09 08:29:23 +02:00
Martin Matuška a116558eb4 Merge pull request #3098 from stoeckmann/filter_read_ahead
filters: Simplify `__archive_read_filter_ahead` use
2026-06-09 08:28:38 +02:00
Martin Matuška f7ec3a2505 Merge pull request #3119 from stoeckmann/7zip_u32_oflow
7zip: Fix range check in get_pe_sfx_offset
2026-06-09 08:27:58 +02:00
Martin Matuška 792c87d5bd Merge pull request #3115 from stoeckmann/gzip_writer_mem
gzip: Fix OOB in writer with huge filename
2026-06-09 08:26:54 +02:00
Martin Matuška 7957d6d3b0 Merge pull request #3114 from stoeckmann/open_oob
Fix OOB in `archive_read_open_filenames_w` on some systems
2026-06-09 08:25:51 +02:00
Martin Matuška 5ce5112087 Merge pull request #3113 from stoeckmann/fflags_strcpy
7zip/rar5: Simplify file attribute handling
2026-06-09 08:25:10 +02:00
Martin Matuška 5c516433ee Merge pull request #3108 from stoeckmann/windows_legacy
Reduce Windows legacy support
2026-06-09 08:24:24 +02:00
Dustin L. Howett 06e296c729 Merge pull request #3116 from stoeckmann/hardening
This PR does not fix any reachable issue, but fixes the code in question nonetheless to prevent regressions in the future:

- Do not call `archive_copy_error` after `archive_read_free` to prevent a user after free bug
- Reset `vtable` to `NULL` to prevent `close` from being called after filter initialization error, since `data` is already freed and set to `NULL`, preventing a `NULL` pointer dereference
2026-06-08 19:29:04 -05:00
Dustin L. Howett e501d52c74 Merge pull request #3021 from chnzzh/fix/iso9660-ce-loop
iso9660: fix infinite loop on self-referencing CE entry
2026-06-08 19:06:43 -05:00
Dustin L. Howett e78c98d896 Merge pull request #3127 from shxz9u/fix-callback-data-realloc
Avoid updating allocation state before realloc succeeds
2026-06-08 15:39:07 -05:00
Dustin L. Howett a9a9039866 Merge pull request #3126 from stoeckmann/shar
shar: Check `archive_entry_clone` result
2026-06-08 15:30:26 -05:00
Dustin L. Howett 2b21f5a6cc Merge pull request #3125 from stoeckmann/disk_clone
Check allocation in `_archive_write_disk_header`
2026-06-08 15:29:48 -05:00
Dustin L. Howett 5335a4ed97 Merge pull request #3124 from stoeckmann/entry_mem
entry_link_resolver: Improve memory handling
2026-06-08 15:28:01 -05:00
Dustin L. Howett 1a248e3a36 Merge pull request #3123 from stoeckmann/cab_remaining
cab: Simplify `cab_read_ahead_remaining`
2026-06-08 15:27:04 -05:00
Dustin L. Howett 53f2275bf0 Merge pull request #3122 from stoeckmann/into_buffer
Remove `archive_read_data_into_buffer` comment
2026-06-08 15:26:25 -05:00
Dustin L. Howett aff2e9d8d9 Merge pull request #3117 from i1011/iso9660-null-deref-fix
iso9660: Fix null dereference in set_directory_record_rr
2026-06-08 15:25:59 -05:00
Tobias Stoeckmann bf312cf279 open: Fix OOB in archive_read_open_filenames_w
If a system with sizeof(wchar_t)=2 (e.g. Cygwin) tries to convert a wide
character string into a multi byte string representation, it
precalculates the required length with sizeof(wchar_t) instead of
MB_LEN_MAX. This can lead to short memory allocation for filenames which
have a shorter representation in wchar_t than in UTF-8.

Resolves GHSA-crm5-q56g-xw29.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-08 21:28:35 +02:00
Tobias Stoeckmann 3666767271 open: Check OOB in archive_read_open_filenames_w
A system with sizeof(wchar_t)=2 (Cygwin on Windows) can trigger an out
of boundary write in archive_read_open_filenames_w when converting the
wide character string into a multi byte string.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-08 21:28:29 +02:00
Tobias Stoeckmann 966ca887f2 rpm: Refactor filter
The current finite state machine carefully handles short reads, i.e. the
loop can enter as often as needed until enough bytes arrive for the
current state to perform its actions.

This can be simplified by relying on __archive_filter_read_ahead to
return the amount of bytes actually needed. I assume that this did not
happen in the original code due to its age (2009) and evolution of
libarchive's internals over time.

Also, headers are only skipped at the beginning. As soon as the reader
starts returning data (ST_ARCHIVE reached), the filter pretty much
becomes a pass-through filter.

Split the initial lead and header skipping into its own function and
only keep track if the initial skipping was performed or not. This
greatly simplifies the reader function.

Also, it avoids book keeping of internal states and "total_in" tracking,
which I don't have to properly audit for edge cases anymore.

Last but not least, this refactoring properly reports truncated streams
now.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-08 21:12:28 +02:00
magnolia 67c2c6364d Avoid updating allocation state before realloc succeeds 2026-06-08 15:58:02 +09:00
Tobias Stoeckmann 7e246b08aa read_data_into_fd: Allocate nulls on demand
Allocate nulls only when needed, i.e. when sparse files are encountered.
This removes another malloc call from regular use cases.

While at it, call archive_set_error in case of allocation failure for
better error messages.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-07 18:29:11 +02:00
Tobias Stoeckmann 67ffa82497 read_data_into_fd: Perform final seek check
Try to detect if writing data to correct position failed due to being
in append mode.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-07 18:28:37 +02:00
Tobias Stoeckmann 5ffbc3a0a1 read_data_into_fd: Print correct error code
If lseek fails to seek to correct position, e.g. because the descriptor
is in append mode, do not use errno because it's not set.

In such a case, fall back to ARCHIVE_ERRNO_MISC.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-07 17:14:33 +02:00
Tobias Stoeckmann cd431688e0 shar: Check archive_entry_clone result
Properly handle allocation failures.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-07 15:52:45 +02:00
Tobias Stoeckmann 3cbf1f01a1 Check allocation in _archive_write_disk_header
The POSIX and Windows code did not check the result of
archive_entry_clone. Handle this error condition properly.

While at it, unify POSIX and Windows code a bit.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-07 15:49:46 +02:00
Tobias Stoeckmann 6d489c2787 entry: Use size_t for element count
LLP64 could theoretically overflow the 32 bit counter. It still needs a
lot memory to achieve this, but let's better be safe than sorry.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-07 15:46:12 +02:00
Tobias Stoeckmann 50758b7532 entry: Check allocation in insert_entry
Check if allocation succeded. If not, properly handle the error instead
of eventually performing a NULL pointer dereference.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-07 15:46:12 +02:00
Tobias Stoeckmann 727e411429 cab: Simplify cab_read_ahead_remaining
We do not have to guess the amount of remaining bytes, since
archive_read_ahead returns the information.

Simplify the function.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-07 15:21:21 +02:00
Tobias Stoeckmann 7d8e546d8c Remove archive_read_data_into_buffer comment
The function has been removed in 2011 with commit
fe9b86254d. Remove the comment as well.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-07 15:15:33 +02:00
00redbeer 6782b7c337 rar5: fix integer underflow in bytes_remaining
A malformed RAR5 archive with data_size=1 forces bytes_remaining
(ssize_t) to wrap to -2 when a compressed block header consumes
to_skip=3 bytes (CWE-191). That negative value is then implicitly
cast to size_t ~0 inside malloc(), requesting a ~16-exabyte
allocation — confirmed heap buffer overflow via ASAN/UBSan on a
48-byte crafted archive requiring no authentication.

Three guards added to archive_read_support_format_rar5.c:

1. Reject data_size > SSIZE_MAX before assigning to bytes_remaining
   (CWE-195, unsafe unsigned-to-signed conversion)

2. Reject to_skip > bytes_remaining in process_block() before the
   subtraction — this is the primary fix for the underflow (CWE-191)

3. Change cur_block_size == 0 to cur_block_size <= 0 in merge_block()
   as defense-in-depth so that any negative bytes_remaining reaching
   read_ahead() is caught before it becomes a malloc size (CWE-122)
2026-06-07 15:07:05 +02:00
00redbeer 7e056baa5c rar5: check integer overflow in bytes_remaining
A malformed RAR5 archive with data_size=1 forces bytes_remaining
(ssize_t) to wrap to -2 when a compressed block header consumes
to_skip=3 bytes (CWE-191). That negative value is then implicitly
cast to size_t ~0 inside malloc(), requesting a ~16-exabyte
allocation — confirmed heap buffer overflow via ASAN/UBSan on a
48-byte crafted archive requiring no authentication.

Reproducer: 48-byte crafted RAR5 archive; ASAN confirms
"allocation-size-too-big 0xfffffffffffffffe".

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-07 15:06:59 +02:00
i1011 e8d1caf9e6 iso9660: Reserve more space in record to avoid null deref 2026-06-07 20:50:42 +08:00
i1011 9cbb26c09b iso9660: Add symlink name length enumeration test 2026-06-07 20:50:31 +08:00
Tobias Stoeckmann ee915849b7 shar: Use archive_endian.h function
Make it easier to verify code by re-using already existing function.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-07 10:42:56 +02:00
Tobias Stoeckmann 3cfaf4b34d rar5: Use archive_endian.h functions
Make it easier to verify code by re-using already existing functions.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-07 10:42:56 +02:00
Tobias Stoeckmann 9a92513ecb 7zip: Use archive_endian.h functions
Make it easier to verify code by re-using already existing functions.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-07 10:42:56 +02:00
Tobias Stoeckmann 2b756d7820 iso9660: Use archive_endian.h functions
Make it easier to verify code by re-using already existing functions.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-07 10:42:56 +02:00
Tobias Stoeckmann b69fd7706c gzip: Use archive_endian.h functions
Make it easier to verify code by re-using already existing functions.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-07 10:42:42 +02:00
Tobias Stoeckmann d6dafddeeb cpio: Use archive_endian.h functions
Make it easier to verify code be re-using already existing functions.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-07 10:03:32 +02:00
Tobias Stoeckmann 0f4bceee19 endian: Add new 24 bit functions
Sometimes, 24 bit operations are needed. Enough users exist that moving
this into archive_endian.h is worth it.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-07 10:03:32 +02:00
Tobias Stoeckmann 2eab7be10a 7zip: Fix range check in get_pe_sfx_offset
Fix an unsigned integer overflow in get_pe_sfx_offset to properly
address the correct section.

Reported by shxz9u.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-06 22:47:00 +02:00
Tobias Stoeckmann 3de41df401 xz: Properly clean up resources on error path
If vtable is not set to NULL, close function would be called during
shutdown. Since data is already freed and set to NULL, this would lead
to a NULL pointer dereference later on.

The called library functions should never fail though, so this is a
purely defensive measure against future lzma changes.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-06 11:40:19 +02:00
Tobias Stoeckmann a85cdd1216 match: Prevent currently unreachable UAF
If archive_read_next_header in add_pattern_from_file would ever return
anything but ARCHIVE_OK or ARCHIVE_EOF, a use after free would occur
when copying error information.

Since this is impossible with current setup (format raw without any
further filter, thus only open_filename code), this change is a purely
defensive measure against future changes.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-06 11:39:55 +02:00
Tobias Stoeckmann bc2ccf30a7 gzip: Fix OOB with huge filenames
If a filename is larger than INT_MAX, an out of boundary write could
occur on 64 bit systems. Fix data types and ignore such huge file names.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-04 22:33:43 +02:00
Tobias Stoeckmann a21dc3f3b0 gzip: Properly handle option strdup failure
If the original name cannot be duplicated, return ARCHIVE_FAILED instead
of ARCHIVE_WARN. The latter implies that the option is unknown, which is
not the case.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-04 22:33:42 +02:00
Tobias Stoeckmann d267d6beed gzip: Turn total_in unsigned
All arithmetical operations are unsigned, and it makes sense to keep it
unsigned: The total_in value is written at the end of the stream and if
the value overflows, it's pretty much expected to be % UINT32_MAX.

Very unlikely that int64_t will ever overflow, but the fix is cheap.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-04 22:33:40 +02:00
Tobias Stoeckmann 6338754d6a cpio: Simplify WINAPI_FAMILIY_PARTITION check
The macro is defined in archive_windows.h if missing.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-03 20:51:04 +02:00
Tobias Stoeckmann a5dc237e55 windows: Simplify la_CreateSymbolicLinkW
The CreateSymbolicLinkW function is available since 0x0600 and is also
part of the Nano Server APIs. On earlier systems, don't even try.
Otherwise use it directly to simplify code.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-03 20:50:51 +02:00
Tobias Stoeckmann 5554bdf816 7zip/rar5: Simplify file attribute handling
- Use a stack array for 22 bytes
- Entering the if-branch already implies that we will add data
- Use snprintf instead of strcpy

Even though snprintf is slower than strcpy, it's easier to verify and
since nobody complained so far about the malloc overhead, this should be
okay (for now).

As a bonus, this code cannot fail anymore, which previously meant that
file attributes were silently ignored.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-03 20:47:22 +02:00
Tobias Stoeckmann bbddb0c9dd windows: Remove pre Windows XP support code
The oldest version we support is 0x0502, while _WIN32_WINNT_XP is
0x0500. Drop support code for even older versions.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-03 20:30:20 +02:00
Dustin L. Howett cda40b999b Merge pull request #3039 from dnelson-1901/manpage-fixes 2026-06-02 22:35:22 -07:00
Dustin L. Howett 5c920c88f4 Merge pull request #3109 from stoeckmann/windows_concurrency 2026-06-02 22:33:10 -07:00
Dustin L. Howett cc85a2cdf0 Merge pull request #3112 from stoeckmann/windows_partition 2026-06-02 21:58:40 -07:00
Tim Kientzle bf268f086d Merge pull request #3106 from stoeckmann/precompute_tables
Precompute static tables
2026-06-02 21:10:22 -07:00
Tim Kientzle e48b9c4cf4 Merge pull request #3107 from stoeckmann/dynamic
Turn static state variables dynamic
2026-06-02 21:09:33 -07:00
Tim Kientzle b660b6965c Merge pull request #3110 from stoeckmann/static_style
Turn two static tables `static const`
2026-06-02 21:08:35 -07:00
Tim Kientzle 6895434b64 Merge pull request #3111 from stoeckmann/tests_assert_a
tests: Use assertEqualInt for archive_write_free
2026-06-02 21:07:42 -07:00
Tobias Stoeckmann db75ddc996 windows: Extend CreateSymbolicLinkW guard
Add WINDOWS_PARTITION_SYSTEM to guard for extended supported.
Reported by Duncan Horn.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-02 22:28:33 +02:00
Tobias Stoeckmann c45c2a07bf windows: Define WINAPI_FAMILY_PARTITION if missing
Define the macro WINAPI_FAMILY_PARTITION if it's missing, which can
happen on old Windows versions like Windows XP. Also add other missing
definitions to support compilation.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-02 22:26:17 +02:00
Tobias Stoeckmann b7dfae4a5a tests: Use assertEqualInt for archive_write_free
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-02 21:34:35 +02:00
Tobias Stoeckmann 88a1082517 windows: Fix concurrency in __archive_create_child
Use proper memory barrier while checking for availability of function
WaitForInputIdle.

Since Vista, InitOnceExecuteOnce is a very simple idiom to handle such a
singleton setup. For earlier setups, accept a possible data race and
recover gracefully if two concurrent threads performed the initial
setup.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-02 21:33:07 +02:00
Tobias Stoeckmann cb62ef5d99 lz4: Adjust style
Having const right after static makes it easier to grep for array which
are not static const.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-02 21:25:38 +02:00
Tobias Stoeckmann c33aab4ec0 rar5: Turn rar5_signature_xor const
The content is never modified, so move it into read-only section.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-02 21:25:36 +02:00
Tobias Stoeckmann 5b997acdf4 posix: Move static var into archive_write_disk
Move a static variable into struct archive_write_disk, which is a safe
location from a thread perspective.

Only create and use it if it's really needed, i.e. for systems which
lack support for extended attributes.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-02 20:50:12 +02:00
Tobias Stoeckmann f78894b87e tar: Move static variables into struct tar
Move these variables into struct tar, which is populated for every
individual tar archive.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-02 20:50:10 +02:00
Tobias Stoeckmann 3c2ffb0116 lha: Precalculate CRC16 tables
This avoids all possible concurrency issues.

As a bonus, turn the whole array const to move it into read-only
section.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-02 20:45:18 +02:00
Tobias Stoeckmann 95154465d9 crc32: Precalculate table
This avoids all possible concurrency issues.

As a bonus, turn the whole array const to move it into read-only
section.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-02 20:45:17 +02:00
Tobias Stoeckmann 235165e3e5 tar: Precalculate decode_table of base64_decode
This avoids all possible concurrency issues.

As a bonus, turn the whole array const to move it into read-only
section.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-02 20:45:16 +02:00
i1011 cc5b027ee5 rar: Add test of large staticdatalen in header 2026-06-03 01:29:49 +08:00
Martin Matuška 1b080e9c2a Merge pull request #3045 from datauwu/iso9660-joliet-patch
iso9660: bound duplicate identifier extension placement
2026-06-02 15:06:34 +02:00
Martin Matuška 6ac02f9521 Merge pull request #3073 from stoeckmann/lz4_zstd_32
lz4/zstd: Fix 32 bit platform endless loop and OOB access during bidding
2026-06-02 15:05:42 +02:00
Martin Matuška 9b5c25087e Merge pull request #3091 from yPin9/fix/rar5-consume-remaining
rar5: skip unconsumed block bytes before ARCHIVE_RETRY
2026-06-02 15:04:44 +02:00
Martin Matuška 85ea76b373 Merge pull request #3103 from stoeckmann/uu_32_oob
uu: Extend range checks to avoid 32 bit OOB
2026-06-02 15:04:00 +02:00
Martin Matuška 93065aac92 Merge pull request #2837 from mmatuska/ci-firecracker
CI: add FreeBSD 15 build via firecracker VM to GitHub Actions
2026-06-02 15:03:35 +02:00
Tobias Stoeckmann f1b6650c67 Merge pull request #3081 from stoeckmann/tests_i686_asan
tests: Skip checks on low memory systems
2026-06-02 08:12:43 +02:00
Tobias Stoeckmann 1e0736a92e Merge pull request #3104 from stoeckmann/uu_cleanup
uu: Minor code cleanups
2026-06-02 08:12:22 +02:00
Tobias Stoeckmann 0fdc1d4d94 uu: Fix grammar in comments
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-01 23:05:36 +02:00
Tobias Stoeckmann 6f9724fdc5 uu: Extend range checks to avoid 32 bit OOB
It is possible to trigger an out of boundary write on 32 bit systems
with around 1 GB of data (with a line consuming most of that data) when
opened with archive_read_open_memory.

Cap the amount of data read at once at 2 * UUENCODE_BID_MAX_READ to
allow range checks to take place before a possible SSIZE_MAX overflow
can occur through avail_in. Also, discard any line longer than
UUENCODE_BID_MAX_READ since this should definitely be more than
enough, especially since in_cnt check already takes care of that.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-01 23:03:58 +02:00
Tobias Stoeckmann 1430b203fe uu: Fix formatting
No functional change, but clarify where this if-block belongs to.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-01 22:54:13 +02:00
Tobias Stoeckmann f4ad19bc39 uu: Remove unneeded code
We know that ptr is NULL, so no need to call free on it.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-01 22:52:56 +02:00
Dustin L. Howett 17b4395a15 Merge pull request #3082 from stoeckmann/bzip2_dead
The check for end of file (`avail == 0`) happens after the check for a `NULL` return value of `__archive_read_filter_ahead`.

Remove it, because at this stage, it's definitely truncated, not just end of file.
2026-06-01 15:15:06 -05:00
Dustin L. HowettandTobias Stoeckmann 49b9383800 Merge pull request #3102 from DHowett/bug/7z-build
7zip: fix a number of issues in zstd detection

- -Wunused-function when ZSTD_compressStream is unavailable
- Incorrect automatic selection of 7Z_ZSTD when ZSTD_compressStream is unavailable
- Other instances of HAVE_ZSTD_H not matching HAVE_LIBZSTD

Co-authored-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-01 14:02:14 -05:00
Tobias Stoeckmann d503ab38be 7zip: Support old zstd versions as well
Use ZSTD_DStream only if it's available, which should always be the
case.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-06-01 14:29:06 -04:00
Dustin L. Howett 4a18b9a4b5 Merge pull request #3090 from DHowett/ci/cygwin
ci: migrate Windows Cygwin to GitHub Actions
2026-06-01 12:54:56 -05:00
Dustin L. Howett 49f67a344e 7zip: only fall back to 7Z_ZSTD if we can actually use zstd
Without this fix, the 7zip writer will fall back to zstd (when it is the
last available option) even if it could not be linked, then fail at
runtime with an unexpected error message.
2026-06-01 13:39:57 -04:00
Dustin L. Howett d65aa58b19 7zip: fix -Wunused-function if zstd.h exists but zstd can't be linked 2026-06-01 13:39:17 -04:00
Dustin L. Howett 5ddb5efce1 Merge pull request #3094 from i1011/xar-redundant-dec-fix 2026-06-01 06:50:50 -05:00
Dustin L. Howett af1e69c8e7 ci: add the new cygwin-gcc backend to the GitHub CI workflow 2026-06-01 05:37:43 -05:00
Dustin L. Howett ffeb1395ce ci: add support for cygwin-gcc to the github CI script 2026-06-01 05:37:43 -05:00
Martin Matuska f1c6aa7b07 CI: add FreeBSD-15-amd64 build via firecracker 2026-06-01 10:37:21 +02:00
Martin Matuška ebfa344055 Merge pull request #3089 from mostynb/remove_cirrus_ci
Remove Cirrus CI setup, it is shutting down in a few days
2026-06-01 09:58:42 +02:00
Martin Matuška 66026841b2 Merge pull request #3093 from stoeckmann/lz4_skip
lz4: Improve truncated input stream detection
2026-06-01 09:55:02 +02:00
Martin Matuška 36d69b3ec8 Merge pull request #3095 from stoeckmann/afio_header
cpio: Improve afio header detection
2026-06-01 09:54:26 +02:00
Martin Matuška fcbbce329c Merge pull request #3096 from stoeckmann/filters_comments
filters: Update comments
2026-06-01 09:53:36 +02:00
Martin Matuška 05eff7d2da Merge pull request #3097 from stoeckmann/typos
Fix typos in comments and error message
2026-06-01 09:53:20 +02:00
Martin Matuška 0ebc440d8e Merge pull request #3099 from stoeckmann/7zip_seek
7zip: Extend support for filtered input
2026-06-01 09:51:32 +02:00
Martin Matuška bb0d9dfd39 Merge pull request #3100 from stoeckmann/lz4_xxh32
lz4: Check `XXH32_init` result
2026-06-01 09:50:34 +02:00
Tobias Stoeckmann e7fb63bc86 lz4: Check XXH32_init result
The XXH32_init function allocates memory. Check if the allocation was
successful and return ARCHIVE_FATAL on error.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-31 17:41:41 +02:00
Tobias Stoeckmann 7f9e3f7448 filters: Update comments
Some filter comments were not updated when the execution of external
filter programs was introduced.

Sync them with reality, including the actually performed commands.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-31 17:40:53 +02:00
Tobias Stoeckmann ac4a21d8ef Fix typo in manual page
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-31 17:40:23 +02:00
Tobias Stoeckmann abee43553e read: Fix typo in error message
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-31 17:40:23 +02:00
Tobias Stoeckmann 10b0193372 Fix typos in comments
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-31 17:40:16 +02:00
Tobias Stoeckmann dc6f400bb7 7zip: Extend support for filtered input
The 7-ZIP archives written by libarchive can be streamed. Support such
archives by using a fallback if seek is not supported: As long as the
target position is somewhere ahead in stream, consume bytes until the
position is reached.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-31 15:40:23 +02:00
Tobias Stoeckmann d29b527037 filters: Simplify __archive_read_filter_ahead use
The third argument (available bytes) is not always evaluated. It is
perfectly fine to pass a NULL argument if it's not needed.

Also, some checks of the third argument can be removed, because in case
of an error (< 0) or in case of end of stream (0) the return value is
NULL anyway. If a NULL check is already in place, just use it.

Simplifies code audits because it's obvious that the available bytes are
not needed within the function if they are never stored.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-31 11:39:12 +02:00
Tobias Stoeckmann 46a1f02675 cpio: Improve afio header detection
Do not assume that enough bytes will be provided by filter if not
explicitly requested. The requested size is 76, but some checks expect
116 bytes. If these were not supplied by filter, th afio header
detection erroneously skips headers which otherwise could be found.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-31 11:07:43 +02:00
Tobias Stoeckmann 02fa05675f cpio: Prevent signed integer overflow
If enough bytes have to be skipped, a signed integer overflow could
occur (most realistically on 32 bit systems). Use an unsigned type,
which could still overflow but has only negative impact on diagnostic
warning message.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-30 22:00:30 +02:00
Tobias Stoeckmann 298facb31e cpio: Add afio header split test
Verify that afio headers are detected even on unfortunate filter read
splits, i.e. when magic is found but rest of header has yet to be
retrieved.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-30 21:58:51 +02:00
i1011 50adbb55c3 xar: Remove redundant decrement in xar_finish_entry 2026-05-31 01:23:39 +08:00
i1011 0263a260ae xar: Add test for redundant decrement in xar_finish_entry 2026-05-31 01:22:32 +08:00
yPin9andClaude Opus 4.8 3b466c2456 rar5: consume unconsumed block bytes before ARCHIVE_RETRY
process_base_block() returned ARCHIVE_RETRY for HEAD_MAIN (and
HFL_SKIP_IF_UNKNOWN) blocks without consuming the body bytes the
sub-parser did not read. rar5_read_header() then re-parsed the same
region, turning an O(1) skip into O(N) and letting a crafted RAR5 file
stall the reader (GHSA-9h2c-464f-j3hj).

Record the block body start and skip any unconsumed bytes through a
small helper rar5_skip_remaining_block() before returning ARCHIVE_RETRY.

Add two regression tests derived from test_read_format_rar5_stored, each
with extra unread bytes appended to a no-data block's body (HEAD_MAIN and
an unknown HFL_SKIP_IF_UNKNOWN block); both fail on master and pass with
the fix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 20:19:25 +08:00
Dustin L. Howett 6a8af66e64 Merge pull request #3088 from mostynb/improve_bsdtar_subst_error_messages
tar: Improve -s Invalid replacement string error messages
2026-05-29 13:48:14 -05:00
Tobias Stoeckmann f7602bd955 lz4: Detect truncation in lz4_filter_read
If __archive_read_filter_consume fails, report information about
detected truncation.

In many cases, the return value can be ignored since
__archive_read_ahead already performed the check. In this case, we never
read the data before, so add the check here.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-29 18:02:09 +02:00
Tobias Stoeckmann bc379862f9 lz4: Avoid integer overflow in lz4_filter_read
Integer promotion stops at unsigned int, thus addition of 4 to a
uint32_t can lead to an integer overflow.

Use int64_t to support all values.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-29 18:02:09 +02:00
Tobias Stoeckmann 303482693a lz4: Add check for proper byte skipping
Check if truncated input is detected while skipping data.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-29 18:02:04 +02:00
Tobias Stoeckmann 3b6b10e7e2 Merge pull request #3085 from stoeckmann/gzip_check
gzip: Support more large in-memory archives
2026-05-29 18:00:49 +02:00
Tim Kientzle a70de97aab Merge pull request #3092 from vmihalis/https-config-fetch
build: fetch config.guess/config.sub over HTTPS
2026-05-29 09:00:39 -07:00
Michalis Vasileiadis 2f3bb0f291 build: fetch config.guess/config.sub over HTTPS in release Dockerfile
Switch the config.guess/config.sub ADD fetches from http:// to https://
(CWE-494).
2026-05-29 21:30:38 +08:00
Michalis Vasileiadis c38b2decf8 build: fetch config.guess/config.sub over HTTPS in makerelease.sh
Switch the release-time config.guess/config.sub fetches from http:// to
https:// and add -fsSL so a failed fetch errors out instead of writing an
error page into the helper script (CWE-494).
2026-05-29 21:30:34 +08:00
Mostyn Bramley-Moore b437415f73 Remove Cirrus CI setup, it is shutting down in a few days
https://circleci.com/blog/cirrus-ci-alternative/
> On April 7, the Cirrus Labs team announced they are joining OpenAI.
> As a result, Cirrus CI will stop running jobs on June 1, 2026.
2026-05-29 00:49:16 +02:00
Mostyn Bramley-Moore 490907dd3f tar: Improve -s Invalid replacement string error messages
We can add a bit more context here, to make the error easier to understand.
2026-05-29 00:28:13 +02:00
Dustin L. Howett 2ef07fe0d1 Merge pull request #3079 from i1011/win-ci-missing-errcheck-fix
CI: Add missing exit on error in windows CI
2026-05-28 16:56:46 -05:00
Dustin L. Howett 7858c8cbf5 Merge pull request #3087 from stoeckmann/cygwin_rar
rar: Simplify FILE_ATTRIBUTE_DIRECTORY check
2026-05-28 16:56:36 -05:00
Tobias Stoeckmann 2fd1dc5397 rar: Simplify FILE_ATTRIBUTE_DIRECTORY check
Just check if the definition exists. If not, create it.
Fixes Cygwin build.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-28 22:54:41 +02:00
Tobias Stoeckmann d5053c3512 Merge pull request #3083 from stoeckmann/read_int_overflow
Fix integer overflow in __archive_read_filter_ahead
2026-05-28 22:46:43 +02:00
Tobias Stoeckmann e1efb9a7eb Merge pull request #3084 from stoeckmann/filters_total_out
Drop total_out tracking from read filters
2026-05-28 22:46:23 +02:00
Tobias Stoeckmann 8a1750fda7 gzip: Support more large in-memory archives
Apply same logic of gzip_filter_read from commit
256c71ad4e
to consumer_header, which contains the identical issue.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-27 22:41:32 +02:00
Tobias Stoeckmann e803f19c73 Drop total_out tracking from read filters
The variable is never read and it only allows a very unlikely integer
overflow if more than INT64_MAX bytes are read.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-27 22:37:24 +02:00
Tobias Stoeckmann d6654b4e01 Merge pull request #3080 from stoeckmann/tests_skip
tests: Fix memory leaks when skipping
2026-05-27 22:01:10 +02:00
Tobias Stoeckmannandypp 5fa691b872 Fix integer overflow in __archive_read_filter_ahead
The pointer arithmetic could overflow with a large min value. Prevent
this by using subtraction instead of addition.

Resolves #3025.

Co-authored-by: ypp <alen0421@gmail.com>
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-27 21:54:42 +02:00
Tobias Stoeckmann a54de78b87 bzip2: Remove dead code
The check for end of file (avail == 0) happens after the check for a
NULL return value of __archive_read_filter_ahead.

Remove it, because at this stage, it's definitely truncated, not just
end of file.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-27 21:19:09 +02:00
Tobias Stoeckmann e624f04ce5 tests: Skip checks on low memory systems
If not enough memory is available, skip tests. This can happen on 32 bit
systems with ASAN enabled. While these tests run perfectly fine if run
directly with libarchive_test, the test harness fails with eventual NULL
pointer dereferences, since these assert-checks do not stop processing.

Happens with lzma and xz and compression level 9.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-27 21:17:44 +02:00
Tobias Stoeckmann 684cc957d3 tests: Fix memory leaks when skipping
Release all resources when skipping to avoid ASAN memory leak warnings.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-27 21:12:46 +02:00
i1011 dd08dc9751 CI: Add missing exit on error in windows CI 2026-05-28 01:32:04 +08:00
Tim Kientzle c15997d4f3 Merge pull request #3061 from tosanjay/warc-header-popul-ehdr-leak
warc writer: free hdr on _popul_ehdr overflow in _warc_header
2026-05-26 21:02:28 -07:00
Tim Kientzle 43a5035657 Merge pull request #3078 from vlmarek/solaris-skip-string-conversion-fail-tests
Skip tests where Solaris iconv substitutes invalid chars
2026-05-26 20:29:44 -07:00
Dustin L. Howett b4d8c89bfa Merge pull request #3067 from fdegros/fix-7z-seek-null-error
7-Zip: Set error message in case of error
2026-05-26 17:35:41 -05:00
François Degros 04f6b80e18 7-Zip: Set error message when reading ahead fails
Nice to have more explicit error messages.
2026-05-26 17:15:47 -05:00
François Degros 15515822b1 7-Zip: Set error message when seeking fails
Avoid (null) error message when seeking fails (e.g. on filtered
streams).

Fixes #2956
2026-05-26 17:15:45 -05:00
Tobias Stoeckmann cd61f4cc59 Merge pull request #3077 from stoeckmann/32build
32 bit: Fix compile warnings and test failure
2026-05-26 22:06:54 +02:00
Vladimír Marek 57be90c509 Skip tests where Solaris iconv substitutes invalid chars
Solaris iconv may perform an implementation-defined conversion for
non-identical characters instead of failing. In the tested conversions it
substitutes question marks and reports success, so these negative tests do
not match Solaris behavior.
2026-05-26 21:52:03 +02:00
Dustin L. Howett 7235ae8714 Merge pull request #3049 from KongQBin/master
build: fix global state leakage in crypto/library checks
2026-05-26 14:38:40 -05:00
Dustin L. Howett d59e51f97b Merge pull request #3075 from stoeckmann/tests_close
tests: Use assertEqualIntA for archive_*_close
2026-05-26 14:24:46 -05:00
Tobias Stoeckmann b1d1173082 tests: Fix 32 bit time_t check
On systems with a 32 bit time_t, archive_parse_date covers less values
than with a 64 bit time_t.

Adjust the expected return value for an overly large value.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-26 21:17:01 +02:00
Tobias Stoeckmann daa19b9c60 7zip: Fix format modifier in init_decompression
The codec field is of type uint64_t, which is an unsigned long on many
64 bit platforms (LP64), but 32 bit platforms and LLP64 platforms cannot
use the l modifier for correct output.

Cast to uintmax_t for portable j support.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-26 21:16:28 +02:00
Tobias Stoeckmann a662e108f2 Merge pull request #2972 from stoeckmann/rr_moved
iso9660: Add test for #2978
2026-05-26 21:14:32 +02:00
Tobias Stoeckmann f105880eb0 iso9660: Add Rock Ridge regression test
The Rock Ridge rr_move functionality for paths with a depth larger than 8
has a few bugs in it. For one, it might loop over the same entries over
and over. And second, rr_move/ directory entries are not verified to be
unique. Both issues can lead to NULL pointer dereferences.

Add a test case which highlights the NULL pointer dereference.

Based on issue #2936.
2026-05-26 21:01:38 +02:00
Dustin L. Howett c03931678b Merge pull request #3055 from stoeckmann/cpio_uaf
cpio: Fix UAF in error path
Add entry only after its full initialization into list. Otherwise the error handling of a failing strdup would have to unlink the entry again.

Fixes: 16ad931073 ("cpio reader: Validate pathname in record_hardlink")

Resolves #3053.
2026-05-26 14:00:53 -05:00
Tobias Stoeckmann 1ee75cadcc tests: Use assertEqualIntA for archive_*_close
In case of errors, assertEqualIntA offers more information by accessing
archive's errno and error message.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-26 20:57:08 +02:00
Tobias Stoeckmann 8b56378deb Merge pull request #3050 from stoeckmann/bzip2_large
bzip2: Support large in-memory archives
2026-05-26 20:00:19 +02:00
Tobias Stoeckmann 5c8a084f9d Merge pull request #3072 from stoeckmann/tests_free
tests: Avoid assertEqualIntA with archive_*_free
2026-05-26 19:59:56 +02:00
Tobias Stoeckmann 531d70f88c Merge pull request #3074 from stoeckmann/7zip_stream
7zip: Support streamable reading again
2026-05-26 19:59:38 +02:00
KongQBin 9938302f67 build: fix global state leakage in crypto/library checks
The CMake build script was modifying global CMake variables (CMAKE_REQUIRED_LIBRARIES
and CMAKE_REQUIRED_INCLUDES) during crypto library checks (OpenSSL, MbedTLS, Nettle)
and Haiku libbsd checks without saving/restoring them using
CMAKE_PUSH_CHECK_STATE() and CMAKE_POP_CHECK_STATE().

This caused side effects where subsequent system-level checks (like
CHECK_TYPE_SIZE or CHECK_FUNCTION_EXISTS) inherited these library dependencies,
leading to incorrect feature detection in cross-compilation environments
(e.g., reporting that basic types like 'pid_t' are missing).

This patch ensures all such checks are properly scoped, improving build
robustness across different architectures (x86_64, AArch64, MIPS64, LoongArch64, etc.)
and cross-toolchain environments.
2026-05-26 09:24:31 +08:00
Tobias Stoeckmann 8646199c47 7zip: Support streamable reading again
The slurp_central_directory function has been changed to always use
seek, which is not needed and also breaks streamable 7-Zip archives.

Resolves an issue observed in #3068.

Fixes: 71ef1c3852 ("7zip: Merge skip_sfx into get_data_offset")

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-25 23:45:34 +02:00
Tobias Stoeckmann d014896fe8 lz4/zstd: Fix integer overflows while bidding
The C standard dictates that integer promotion increases data types up
to int or the largest argument in arithmetic.

This becomes problematic in `offset_in_buffer += 4 + frame_data_size`
which effectively is `size_t += int + uint32_t`.

If frame_data_size is UINT32_MAX, adding 4 overflows before the
overflown value is added to size_t.

On 32 bit systems, this can easily lead to an endless loop or out of
boundary access.

Fix this by properly checking if integer overflows would occur.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-25 22:11:16 +02:00
Tobias Stoeckmann f948099a0d zstd: Check for endless loop on 32 bit systems
It is possible to trigger an endless loop on 32 bit systems due to
a triggerable integer overflow.

Add a regression test for this.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-25 22:11:12 +02:00
Tobias Stoeckmann bfe3dda34c lz4/zstd: Use correct data types while bidding
Use size_t where size_t arguments are expected (and cast avail to size_t
because we know at this point that it cannot be negative).

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-25 21:13:10 +02:00
Tobias Stoeckmann 922c97d681 lz4/zstd: Apply style guide in bidding function
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.

No functional change.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-25 21:13:04 +02:00
Tobias Stoeckmann 622bda49db tests: Avoid assertEqualIntA with archive_*_free
In case of errors, assertEqualIntA accesses the given archive and prints
diagnostic information about errno and error string.

Since archive_read_free and archive_write_free free the memory of the
archive, this would just lead to memory issues in case of errors.

Use assertEqualInt instead.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-25 20:36:39 +02:00
SanjayR cbb74d2822 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.
2026-05-25 11:37:20 +05:30
Dustin L. Howett 4db7955782 Merge pull request #2790 from LumioseSil/SetFilePointerEx_perso
Replace SetFilePointerEx_perso (local reimplementation) with SetFilePointerEx,
as we no longer need to support Windows XP
2026-05-24 14:59:52 -05:00
Dustin L. Howett d86214bfbb Merge pull request #3062 from tosanjay/7zip-file-new-utf16name-leak
7zip writer: free file->utf16name on symlink UTF-8 conversion failure
2026-05-24 12:43:52 -05:00
Dustin L. Howett ea7084a735 Merge pull request #3057 from i1011/mtree-null-deref-fix
mtree: Fix null dereference for some corner cases:

- a symlink whose target is never set
- emitting a root directory entry that is actually a file
2026-05-24 12:43:25 -05:00
Dustin L. Howett 42453cf162 Merge pull request #3071 from stoeckmann/rar5_doublefree
rar5: Avoid dangling pointers in init_unpack
2026-05-24 12:43:00 -05:00
Dustin L. Howett b8a7b027f8 Merge pull request #3064 from i1011/version-details-fix
Fix libattr version returned in archive_version_details, as well as a leak.
2026-05-24 12:39:08 -05:00
Tobias Stoeckmann 1c914cdfef rar5: Avoid dangling pointers in init_unpack
If init_unpack fails to allocate memory for given window size, a
dangling pointer can lead to an eventual double free.

Resolves #3069.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-24 15:06:06 +02:00
i1011 0379e80a38 mtree: Root entry '.' must be directory 2026-05-24 19:41:16 +08:00
i1011 3cd7319e47 mtree: Assign empty path to symlink if undefined 2026-05-24 19:41:16 +08:00
i1011 ec74abc206 Add two testcases for mtree null deref 2026-05-24 19:41:16 +08:00
Tobias Stoeckmann e20a0b2136 Merge pull request #3051 from stoeckmann/compress_debug
compress: Remove harmful "dead" code
2026-05-24 10:15:35 +02:00
Tobias Stoeckmann 51e9cd6dc7 Merge pull request #3052 from stoeckmann/tar_wempty
tar: Fix OOB with empty wide character directory names
2026-05-24 10:14:50 +02:00
Tobias Stoeckmann 97595197b2 Merge pull request #3035 from stoeckmann/acl_string
acl: Simplify string creation
2026-05-24 10:14:11 +02:00
Tobias Stoeckmann e681e45b31 Merge pull request #3041 from stoeckmann/xar_fflags
xar: Fix writer OOB accesses with fflags
2026-05-24 10:13:34 +02:00
i1011 5ef91448b1 util: Fix libattr version returned in archive_version_details
Also, add missing init=1 so that the version string
initialization/allocation only runs on the first call.
2026-05-24 15:22:26 +08:00
Dustin L. Howett 6f95523f45 Merge pull request #3060 from stoeckmann/xar_free
xar: fix fflags_text leak in file_free
2026-05-24 01:19:12 -05:00
SanjayR eb4153fbc4 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.
2026-05-22 11:06:50 +05:30
Sanjay Rawat 1aeaa4d104 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.

Resolves #3058.
2026-05-21 23:56:11 +02:00
datauwu 68c78d5dbd 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.
2026-05-21 10:55:26 +08:00
Tim Kientzle c97baadd86 Merge pull request #3056 from markjdb/master
libarchive: Force GNU iconv compatibility on FreeBSD
2026-05-20 15:57:07 -07:00
Tim Kientzle 2e183f664c Merge pull request #3054 from i1011/add-filter-mismatch-fix
filter: Fix mismatched filter function dispatch table entry in archive_write_add_filter.c
2026-05-20 15:55:18 -07:00
Mark Johnston 0e3d312174 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.
2026-05-20 17:04:17 +00:00
Sanjay Rawat d53db9de36 cpio: Fix UAF in error path
Add entry only after its full initialization into list. Otherwise the
error handling of a failing strdup would have to unlink the entry again.

Fixes: 16ad931073 ("cpio reader: Validate pathname in record_hardlink")

Resolves #3053.
2026-05-20 18:13:50 +02:00
i1011 5a24c9c69f 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.
2026-05-20 21:18:35 +08:00
i1011 e21749afe3 Add test for filter dispatch in archive_write_add_filter.c
Modified from test_archive_write_add_filter_by_name.c
2026-05-20 20:56:40 +08:00
datauwu 9cc1878a13 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.
2026-05-20 09:36:20 +08:00
Tobias Stoeckmann 843b3baea1 tar: Fix empty wide character string handling
Apply the same fix as done in commit
c246ec5d05 for non-wide character
strings.

Without this, empty strings lead to out of boundary read accesses.

Resolves #3046.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-19 21:19:31 +02:00
Tobias Stoeckmann e04cc903e0 tar: Check empty dir name handling
Make sure that empty wide character names do not lead to out of boundary
accesses.

Reported by shura-turtle.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-19 21:18:22 +02:00
Tobias Stoeckmann df999b41c9 compress: Remove harmful "dead" code
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.

Delete the debug code to fix this issue.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-19 17:32:26 +02:00
Tobias Stoeckmann 7f9f27cea3 bzip2: Support large in-memory archives
If an archive has more than UINT_MAX (4 GB) bytes available, the bzip2
filter will enter an endless loop.

Apply same logic of gzip filter from commit
256c71ad4e.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-19 17:24:01 +02:00
Tobias Stoeckmann fd182c5ba5 Merge pull request #3027 from stoeckmann/xar_debug
xar: Do not modify variables in DEBUG block
2026-05-19 17:19:06 +02:00
Tobias Stoeckmann 0637bc4221 Merge pull request #3033 from stoeckmann/filter_strcpy
filter: Remove unneeded strcpy calls
2026-05-19 17:18:05 +02:00
Tobias Stoeckmann 14c07f64ae Merge pull request #3036 from stoeckmann/cmdline_strdup
cmdline: Use free+strdup instead of realloc+strcpy
2026-05-19 17:17:42 +02:00
Tobias Stoeckmann ccd2dfbdb2 Merge pull request #3037 from stoeckmann/strmode_strcpy
strmode: Remove strcpy usage
2026-05-19 17:17:24 +02:00
Tobias Stoeckmann b9eea3e51a Merge pull request #3044 from stoeckmann/util_windows_toctou
util: Fix GetTempPathW TOCTOU race condition
2026-05-19 17:16:28 +02:00
Wei-Cheng Pan b1a5aa97a3 rar: reset low-distance state for new LZ tables
Low-distance repeat state is scoped to the current RAR3 LZ table. Reusing it after a new table starts can make the next match use the wrong offset, producing incorrect output and a file CRC error.

Reset lastlowoffset and numlowoffsetrepeats when parsing a new LZ table. Add a small handcrafted RAR3 fixture that leaves a low-distance repeat pending, switches tables, and verifies the decoded bytes after the boundary.
2026-05-19 17:16:53 +09:00
Wei-Cheng Pan e09d88eaa3 rar: skip NEWSUB payloads without size cap
RAR3 recovery records can be stored as NEWSUB RR blocks with payloads larger than the old 1 MiB extended-header limit. These records are metadata-only for this reader, so after validating the header and guarding against header-size plus payload-size overflow, consume the remaining header bytes and payload instead of rejecting the archive.

Add a reference archive with a NEWSUB RR payload just over 1 MiB, and keep the malformed huge-size case covering the overflow/truncation path.
2026-05-19 17:14:12 +09:00
Dustin L. Howett a651b4fcd8 Merge pull request #3043 from datauwu/cpio-patch 2026-05-17 13:24:24 -07:00
Tobias Stoeckmann a932ffa30a util: Fix GetTempPathW TOCTOU race condition
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.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-17 15:49:57 +02:00
datauwu 1f2da75fb3 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.

Signed-off-by: datauwu <datauwu@users.noreply.github.com>
2026-05-17 17:34:06 +08:00
Tobias Stoeckmann 68b69249de Merge commit from fork
read: Fix memory corruption on filtered multi-volume archives
2026-05-17 10:21:08 +02:00
Tim Kientzle c18a5c7e5f Merge pull request #3040 from kientzle/fix/unchecked-alloc
Fix a number of unchecked memory allocations
2026-05-16 15:04:07 -07:00
Tobias Stoeckmann 583b5e4d2f xar: Fix OOB accesses with fflags
If multiple fflags are added to archive, a stack out of boundary is
triggered due to insufficient array allocation.

Also, if flags with long names are supplied, an out of boundary read can
occur.

Resolves GHSA-wfvr-54j8-47r9.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-16 21:50:01 +02:00
Tobias Stoeckmann b55059597b xar: Add fflag regression test
It is possible to trigger an out of boundary stack write and out of
boundary reads with fflags.

Based on proof of concept reported by Cris Jacob Maamor.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-16 21:49:53 +02:00
Tobias Stoeckmann 7eeaced525 Merge pull request #3038 from stoeckmann/tar_util_string
tar: Improve string safety in list_item_verbose
2026-05-16 21:40:12 +02:00
Tobias Stoeckmann 959fd04b65 acl: Do not count entries during string creation
It is only relevant to know if a separator has to be inserted. This can
be simplified by only checking if string already contains characters.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-16 21:36:04 +02:00
Tobias Stoeckmann d8dbf2f156 acl: Use archive_string/archive_wstring
Since libarchive already contains infrastructure to safely work with
strings, use it instead of manually constructing strings.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-16 21:35:58 +02:00
Tim Kientzle 7ef136b750 Fix unchecked malloc result in XXH32_init
If XXH_malloc fails, state would be NULL and passed directly to
XXH32_resetState, causing a NULL dereference.
2026-05-16 10:04:51 -07:00
Tim Kientzle cb231e2b39 Fix unchecked strdup result in __archive_write_program_allocate
If strdup fails, program_name would be NULL and later use could crash.
Free data and return NULL on allocation failure.
2026-05-16 10:04:38 -07:00
Tim Kientzle 620bdafa26 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.
2026-05-16 10:04:24 -07:00
Tim Kientzle 059dff39be Fix unchecked calloc result in make_table (rar)
If calloc fails, code->table would be NULL and passed directly to
make_table_recurse, causing a NULL dereference.
2026-05-16 10:03:31 -07:00
Tim Kientzle 42151837dc Fix unchecked calloc result in tree_open
If calloc fails, t would be NULL and immediately dereferenced.
Return NULL on allocation failure.
2026-05-16 10:03:11 -07:00
Tim Kientzle f5bb79a62e Fix unchecked calloc result in tree_push
If calloc fails, te would be NULL and immediately dereferenced.
Return early on allocation failure.
2026-05-16 10:02:57 -07:00
Tim Kientzle 589004793a Fix unchecked malloc result in read_reparse_data
If malloc fails, indata would be NULL and passed directly to
DeviceIoControl, causing undefined behavior.
2026-05-16 10:02:30 -07:00
Tim Kientzle 89a6d760c1 Merge pull request #3032 from stoeckmann/dotdot
Port iso9660 fix for `..` (dot dot) path normalization to mtree and xar
2026-05-16 09:39:31 -07:00
Dan Nelson b9ea385403 Minor manpage fixes
Add documentation for
 archive_free
 archive_position_compressed
 archive_position_uncompressed
 archive_read_open_filenames
 archive_write_add_filter_by_name
 archive_write_set_format_filter_by_ext_def

Note that archive_write_add_filter.* can return ARCHIVE_WARN, and
archive_read_support_filter.* can return ARCHIVE_FATAL

Chase rename of archive_position to archive_filter_bytes
2026-05-16 11:25:00 -05:00
Tobias Stoeckmann 6f18dd94cd tar: Improve string safety in list_item_verbose
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.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-16 15:40:13 +02:00
Tobias Stoeckmann 0d08bc6db9 strmode: Remove strcpy usage
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.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-16 15:33:23 +02:00
Tobias Stoeckmann a4df51287e 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.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-16 15:25:53 +02:00
Tobias Stoeckmann effba1c8cb 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.

Resolves GHSA-qf8j-cq3h-8m2m.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-15 18:43:09 +02:00
Tobias Stoeckmann 515380e7e5 read: Add multi-volume regression test
Check that no memory corruption occurs when switching files which are
decompressed through filters.

Test case supplied by Stuart Wallace.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-15 18:18:26 +02:00
Tobias Stoeckmann f0d6f76cfa read: Simplify client_switch_proxy
Use a dedicated variable for archive instead of referencing
self->archive again and again. Also, inline client_open_proxy.

While at it, fix space intendation.

No functional change.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-15 18:17:16 +02:00
i1011 15996e83bb sparse: Nullify sparse_p in archive_entry_sparse_clear() 2026-05-15 17:14:43 +08:00
i1011 037b0d5248 sparse: Add archive_entry_sparse_clear test 2026-05-15 17:14:43 +08:00
i1011 b25b9d1e03 xattr: Nullify xattr_p in archive_entry_xattr_clear() 2026-05-15 17:14:43 +08:00
i1011 561b8a6237 xattr: Add archive_entry_xattr_clear test 2026-05-15 17:14:42 +08:00
Tobias Stoeckmann e8023fc6bc filter: Remove unneeded strcpy calls
No need to copy these values on stack. Just use them on heap directly.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-14 20:42:13 +02:00
Tobias Stoeckmann 864e735094 mtree: Fix dot dot handling
Port iso9660 dot dot handling over to mtree.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-14 20:23:08 +02:00
Tobias Stoeckmann 88f881cdd2 xar: Fix dot dot handling
Port iso9660 dot dot handling over to xar.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-14 20:22:48 +02:00
Tobias Stoeckmann 6b5a4fd535 mtree: Add dot dot regression test
Check if resolving dot dot does work as expected.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-14 20:22:10 +02:00
Tobias Stoeckmann f860929d25 xar: Add dot dot regression test
Check if resolving dot dot does work as expected.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-14 20:20:57 +02:00
Tim Kientzle 27b08f61da Merge pull request #3028 from br0nzu/xar-fstype-cleanup
Free XAR xattr fstype metadata during cleanup
2026-05-13 19:24:27 -07:00
Tim Kientzle 6d15675331 Merge pull request #3030 from stoeckmann/xar_atol
xar: Avoid integer overflows in number parsers
2026-05-13 18:51:45 -07:00
Tim Kientzle d0ee2d32ef Merge pull request #3029 from stoeckmann/iso_memleak
iso9660: Fix memory leaks on error paths
2026-05-13 18:51:29 -07:00
Tobias Stoeckmann 4f2d783292 xar: Handle integer overflows in atou64
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.

Use error handling available by callers.

Reported by Muhammed Hussein.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-13 20:42:49 +02:00
Tobias Stoeckmann f0d631b479 xar: Merge atol8 and atol10 into atou64
Both functions are similar enough that they can be merged.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-13 20:42:49 +02:00
Tobias Stoeckmann 7e2228b7fe xar: Return uint64_T from atol8
The result of atol8 is cast to mode_t, which is also unsigned.
This brings atol8 closer to atol10.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-13 20:42:49 +02:00
Tobias Stoeckmann 5c58478270 xar: Prepare error pass through for xml_data
The xml_data function is void, but some functions called in there might
fail. Prepare an error propagation for upcoming changes.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-13 20:42:49 +02:00
Tobias Stoeckmann 2f79b7dca0 xar: Remove unneeded cast
The variable is size_t and argument expects a size_t. Do not cast to
int, which could only lead to trouble (in theory).

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-13 20:42:49 +02:00
Tobias Stoeckmann 5bad56b901 xar: Test overly large mode value
Add a test which contains a mode which does not fit into mode_t and
check if such an entry is properly rejected.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-13 20:42:44 +02:00
Tobias Stoeckmann 35befb8c2b iso9660: Fix memory leaks on error paths
- Release memory in case of allocation failure.
- Treat failure to add an entry to rr_moved as fatal error

Fixes ASAN test run with test_write_format_iso9660_null_deref

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-13 20:14:21 +02:00
br0nzu 6767cbe319 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.
2026-05-13 16:24:44 +09:00
br0nzu 601e7d6087 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.
2026-05-13 16:24:44 +09:00
Tobias Stoeckmann fbb63ab3f1 xar: Do not modify variables in DEBUG block
The len variable is used later on. Introduce a new one (debug length) to
limit the amount of characters written to stderr.

Could be further improved with %.*s but let's keep it as simple as
possible, since DEBUG is not default and has to be manually set in
line 89.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-12 21:56:11 +02:00
Zhihan Zheng 7b4343ca83 iso9660: add test_read_format_isorr_ce_loop testcase 2026-05-11 15:01:57 +08:00
Zhihan Zheng ee6252553e iso9660: reject overlapping Rock Ridge CE continuations
A malformed Rock Ridge CE entry can point back into a continuation
area that has already been processed for the same file. This causes
the ISO9660 reader to parse the same SUSP records repeatedly.

Track the end offset of the CE data already processed for each
file_info and reject later CE entries whose start offset is before
that point. This keeps forward nested continuations valid, including
same-block continuations, while rejecting backward or overlapping CE
chains.

This check is done in read_CE(), where continuation data is actually
processed.
2026-05-11 10:09:21 +08:00
Tim Kientzle 1546fbffe8 Merge pull request #3020 from stoeckmann/sparse_uaf_test
sparse: Add archive_entry_sparse_reset test
2026-05-10 08:45:58 -07:00
Tobias Stoeckmann e23e868c3a sparse: Add archive_entry_sparse_reset test
Check that archive_entry_sparse_reset resets all internal variables.

Test case created and issue reported by Linke Li.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-10 14:41:41 +02:00
Tim Kientzle dca1bcd27d Merge pull request #3016 from ZX41R/oss-fuzz-write-disk-secure-coverage
Improve write-disk fuzzer coverage
2026-05-09 14:12:56 -07:00
Tim Kientzle 6246a35326 Merge pull request #3015 from datauwu/master
rar: avoid reading NEWSUB extended data during header parsing
2026-05-09 14:10:02 -07:00
Tim Kientzle 0ec85e45e4 Merge pull request #2978 from stoeckmann/joliet_id_loop
iso9660: Fix infinite loop in Joliet ID generation
2026-05-09 13:50:41 -07:00
Tim Kientzle 5ed0b5ea88 Merge pull request #2928 from stoeckmann/anchor_no_flags
pathmatch: Treat anchors not special without flags
2026-05-09 13:49:25 -07:00
Tim Kientzle 5aa477220e Merge pull request #2927 from stoeckmann/pathmatch_recursion
archive_match: Prevent call stack overflow
2026-05-09 13:48:20 -07:00
Cris Jacob Maamor d3337b58b7 rar: limit and skip NEWSUB extended data
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.
2026-05-10 03:31:37 +08:00
Tim Kientzle dda246a62e Merge pull request #2930 from stoeckmann/mtree_option
mtree: Fix time value parser truncation
2026-05-09 09:15:26 -07:00
Tim Kientzle abed05f954 Merge pull request #2929 from stoeckmann/7zip_codec_id
7zip: Verify that Codec ID fits into 63 bit
2026-05-09 09:14:11 -07:00
Tim Kientzle c25415ade4 Merge pull request #2982 from stoeckmann/mtree_hex
mtree: Fix hex parser
2026-05-09 09:11:14 -07:00
Tim Kientzle a330921e49 Merge pull request #2974 from stoeckmann/joliet_id
iso9660: Fix OOB during Joliet ID generation
2026-05-09 09:10:07 -07:00
Tim Kientzle 3f7a004055 Merge pull request #2969 from stoeckmann/glibc234
Fix build with glibc 2.43
2026-05-09 08:58:28 -07:00
Tobias Stoeckmann a9d2cc5e07 iso9660: Fix OOB in Joliet ID generation
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).

Resolves #2935.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-09 12:31:34 +02:00
Tobias Stoeckmann 77c991bde9 iso9660: Add Joliet ID regression test
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.

The addition could overflow the memory.

Based on PoC in #2935.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-09 12:31:28 +02:00
Tobias Stoeckmann b2ce282da0 mtree: Fix hex parser
Digits a-f/A-F need an offset of 10.

Resolves #2975.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-09 12:22:12 +02:00
Tobias Stoeckmann 2b0ab5bda9 iso9660: Fix infinite loop in Joliet ID generation
3 characters/digits base 36 means that 46656 combinations are possible.
If a directory with even more conflicting identifiers is encountered, the
code would trigger an endless loop.

Fail with an error in such a case instead.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-09 12:22:01 +02:00
Tobias Stoeckmann 6175f49315 Remove const qualifier from modified strings
Strings pointed to by these variables are actually modified. They point
to modifiable data areas (own stack arrays or argv arguments), so the
code does not erroneously modify them. Instead, clarify that they are
modifiable by removing the qualifier.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-09 12:21:27 +02:00
Tobias Stoeckmann ea95e6d53b Fix more handling of missing const type qualifiers
Add missing const qualifier which otherwise triggers build errors
beginning with glibc 2.43.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-09 12:21:27 +02:00
Rudi Heitbaum 2ec5fbe450 fix handling of missing const type qualifier
Since glibc-2.43:

For ISO C23, the functions bsearch, memchr, strchr, strpbrk, strrchr,
strstr, wcschr, wcspbrk, wcsrchr, wcsstr and wmemchr that return pointers
into their input arrays now have definitions as macros that return a
pointer to a const-qualified type when the input argument is a pointer
to a const-qualified type.

Signed-off-by: Rudi Heitbaum <rudi@heitbaum.com>
2026-05-09 12:21:27 +02:00
Rudi Heitbaum 33b0eba662 Do not call parse_options with const
The data variable passed in to parse_option is modified and is passed
in as a strdup.

Signed-off-by: Rudi Heitbaum <rudi@heitbaum.com>
2026-05-09 12:21:27 +02:00
Tobias Stoeckmann 0a6f7f1ca0 mtree: Fix time value parser truncation
The supplied nanoseconds of time keyword could be truncated due to
casting from int64_t to long (relevant for Windows and x86), resulting
in an incorrect value.

Since the implementation already caps the value at specific limits for
bug compatibility, just use the correct data type for parsing to not
make things worse.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-09 12:21:12 +02:00
Tobias Stoeckmann e3b3a20263 7zip: Verify that Codec ID fits into 63 bit
According to 7zip standard, up to 15 bytes can be used for the Codec ID,
but not more than 63 bit shall be used (by today):

- Switch to uint64_t to avoid 32 bit unsigned long on Windows
- Verify that Codec ID parser does not overflow the integer

If the Codec ID does not fit, treat it as a file format error.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-09 12:20:22 +02:00
Tobias Stoeckmann 2794503b1d archive_pathmatch: Anchors without flags regular
If no flags are supplied, anchor flags are supposed to be not special.
This means that ^ at the beginning of a pattern should be treated as a
regular character.

This breaks current behavior, but complies with comments in code, i.e.
archive_pathmatch.h line 41/42.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-09 12:19:11 +02:00
Tobias Stoeckmann fc73571502 archive_pathmatch: Extend unit tests
Add some tests to clarify what happens in these cases. Also, this
increases test coverage.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-09 12:19:11 +02:00
Tobias Stoeckmann 6ef8b42aa9 read_disk: Set correct match error codes
The errno value is not correct here. If the error string of a failed
match is printed, use also its error code.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-09 12:18:38 +02:00
Tobias Stoeckmann 470379a9ef archive_match: Prevent call stack overflow
Patterns with a lot of asterisks may overflow the call stack, crashing
the application. Check the recursion depth. If it is too deep, fail
with an error.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-09 12:18:38 +02:00
Tobias Stoeckmann 2a62d049ea tools: Handle archive_match errors
These functions can return negative values, in which case operation
itself failed. While internal libarchive libraries handle these cases,
the tools don't. Check for negative values in them as well.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-09 12:18:38 +02:00
Tobias Stoeckmann b478882371 libarchive: Fix typos in comments
"something error" -> "some error"

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-09 12:18:38 +02:00
Tim Kientzle f5166ca923 Merge pull request #3019 from kientzle/kientzle-sparse-uaf-012
[sparse] UAF in sparse_reset
2026-05-08 19:04:25 -07:00
Tim Kientzle bcb158d409 Merge pull request #3018 from tbkka/tbkka-mtree-null-deref-014
[MTREE] NULL pointer deref during archive close
2026-05-08 19:03:11 -07:00
Tim Kientzle b1622a8e55 [sparse] UAF in sparse_reset 2026-05-08 18:48:45 -07:00
Tim Kientzle 266e3d5f6c [MTREE] NULL pointer deref during archive close 2026-05-08 16:35:52 -07:00
Tim Kientzle 98f3579020 Merge pull request #3017 from tbkka/tbkka-iso9660-015-019
[ISO9660] Fix NULL deref and Joliet ID overflow
2026-05-08 16:27:48 -07:00
Tim Kientzle cf9b5f7790 Allow functions to be unused here 2026-05-08 16:10:50 -07:00
Tim Kientzle a403da942d [ISO9660] Fix NULL deref and Joliet ID overflow 2026-05-08 15:42:20 -07:00
Tim Kientzle cb9f77e6e5 Merge pull request #3013 from tbkka/tbkka-xar-undefined-011-018
[XAR] Fix two UB
2026-05-08 15:40:05 -07:00
Tim Kientzle e77b37e59b Generalize code to run on Windows 2026-05-08 15:23:06 -07:00
Tim Kientzle 411a4479b9 Merge pull request #2984 from tyler-yankee/cpio-hardlink-pathname-null
cpio reader: Validate pathname in record_hardlink
2026-05-08 10:16:29 -07:00
ZX41R 88b5efe09a Improve write-disk fuzzer coverage 2026-05-08 13:52:58 +00:00
Tyler Yankee 16ad931073 cpio reader: Validate pathname in record_hardlink
Prevent null pointer dereference and heap-use-after-free when
processing CPIO archives with hardlink entries that lack pathname
information.
2026-05-08 07:09:01 -04:00
Tim Kientzle 1fcae10bf7 Merge pull request #3014 from kientzle/kientzle-test_utils-ub
[test_utils] Fix a minor UB
2026-05-07 22:20:19 -07:00
Tim Kientzle 7c9ad86cf4 [7zip] Another shift UB caused by integer promotion 2026-05-07 22:04:20 -07:00
Tim Kientzle e46e2c389a [test_utils] Fix a minor UB
(UBSan occasionally finds something interesting and
often reports whacky non-bugs like this one. "Fixing"
it will make the real UB bugs easier to identify, so...)

According to C's integer promotion rules, `unsigned short` gets
promoted to _signed_ `int`, and shifting into the sign bit of an `int`
is technically UB.  Explicit cast to `unsigned` quiets UBSan.
2026-05-07 21:50:50 -07:00
Tim Kientzle b3b546d008 Merge pull request #3012 from tbkka/tbkka-pathmatch-buffer-overread-003
[pathmatch] Heap buffer over-read
2026-05-07 21:40:10 -07:00
Tim Kientzle be40e17d8e Include missing file 2026-05-07 21:37:08 -07:00
Tim Kientzle 58810c2fae Merge pull request #3011 from tbkka/tbkka-tar-acl-oob-002
[ACL] Parser out-of-bounds read
2026-05-07 21:31:14 -07:00
Tim Kientzle e35b629f20 [XAR] Fix two UB
1. The XAR writer's path normalization code uses strcpy() to move
   parts of a path string within the same buffer. The source and
   destination ranges overlap, which is undefined behavior for strcpy().

2. Failure to check string length before accessing the last character
   of a path component. For empty components (e.g., //), the length is 0,
   and length-1 underflows to SIZE_MAX.
2026-05-07 21:11:54 -07:00
Tim Kientzle 4cbf958253 [pathmatch] Heap buffer over-read
The bracket expression matching [ in the pathmatch engine fails to
handle malformed patterns, specifically when a closing ] is missing or
when high-byte characters are used. The scanner advances the pattern
pointer beyond the allocated buffer.
2026-05-07 20:15:37 -07:00
Tim Kientzle 46290f89c7 Merge pull request #3008 from jlduran/fix-root-mtree
mtree: Do not append '/' when basename is '.'
2026-05-07 19:52:41 -07:00
Tim Kientzle 8308b61c7e [ACL] Parser out-of-bounds read
The ACL parser fails to validate buffer length when processing PAX
attributes (SCHILY.acl.access/default). The next_field() function
attempts to read a separator character from a pointer even when the
remaining length is zero.

Reported-by: Kamil Frankowicz
2026-05-07 19:41:04 -07:00
Tim Kientzle c6322495f1 Merge pull request #3010 from kientzle/kientzle-overlarge-dates
Date parsing: reject dates with numbers of more than 4 digits
2026-05-07 18:21:00 -07:00
Tim Kientzle 692e88b287 Fix build error 2026-05-07 17:50:07 -07:00
Jose Luis Duran dc88807502 mtree: Do not append '/' when basename is '.'
If the basename is '.', it means it is the root directory ('/').  Do not
append '/' to '.', as this will produce a path '/.', resulting in an
invalid mtree entry.

For example, using base.txz from FreeBSD:

    tar -c -f - --format=mtree @base.txz | mtree -C
2026-05-08 00:39:01 +00:00
Tim Kientzle 422aae80ae Date parsing: reject date components with numbers of more than 4 digits
Only the Unix epoch format `@<timestamp>` can have a number with
more than 4 digits.  So let's break out the numeric parsing into
a standalone uint64 parser and use it separately to parse epoch
timestamps (which are only limited by the range of time_t) and
other date components.

It also avoids a time-consuming leap-year correction for
nonsensically large year values.
2026-05-07 17:36:13 -07:00
Tim Kientzle 73c4f1c03f Merge pull request #3009 from kientzle/archive-read-sticky-fatal
Minor cleanups from #2298
2026-05-07 12:41:30 -07:00
Tim Kientzle 9a61f7baa5 Cleanup a new test, fill in some missing assertions 2026-05-07 12:25:58 -07:00
Tim Kientzle e01eeb274d Merge pull request #2998 from kientzle/archive-read-sticky-fatal
archive_read: FATAL should be sticky for all API calls
2026-05-07 12:19:02 -07:00
Tim Kientzle 74107b8110 TODO seems to have been addressed; remove 2026-05-07 09:45:17 -07:00
Tim Kientzle 4b65c3866b Merge pull request #3007 from jlduran/escape-vis-glob-chars
mtree: Escape standard pathname matching characters
2026-05-07 08:34:11 -07:00
Jose Luis Duran db567e1405 mtree: Escape standard pathname matching characters
Escape all strsvis(3) VIS_GLOB matching characters ('*', '?', '[', or
'#').
2026-05-07 10:36:18 +00:00
Tim Kientzle bdf827634b Restore verbosity 2026-05-06 23:25:10 -07:00
Tim Kientzle a1b525e654 Fix CMake style 2026-05-06 23:24:53 -07:00
Tim Kientzle 2040158905 Restore switch_multivolume as needed 2026-05-06 23:16:57 -07:00
Tim Kientzle d5d9e1fd36 Adjust tests 2026-05-06 22:15:11 -07:00
Tim Kientzle f833d13e6d Fix CMake-based testing 2026-05-06 22:02:15 -07:00
Tim Kientzle 6f40ee4f1d Make default test output verbose, for better CI info 2026-05-06 18:56:13 -07:00
Tim Kientzle 4fde023514 Merge pull request #3006 from stoeckmann/7zip_32
7zip: Fix 32 bit heap overflow
2026-05-06 11:52:11 -07:00
Tobias Stoeckmann f52a211f80 7zip: Fix more 32 bit truncations
Check for truncations before casting uint64_t to size_t for 32 bit
system safety.

Reported by Asaf Meizner.
Resolves additional notes in GHSA-rf5v-vf7c-6wvg.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-05-06 20:11:18 +02:00
Asaf Meizner a4b3f6929c 7zip: Fix 32 bit heap overflow
Prevent an unsufficient memory allocation on 32 bit systems by checking
if a uint64_t value actually fits into size_t.

Resolves GHSA-rf5v-vf7c-6wvg.
2026-05-06 20:11:16 +02:00
Tim Kientzle 330148b1be Merge branch 'master' into archive-read-sticky-fatal 2026-05-06 09:28:05 -07:00
Tim Kientzle 398b7b6f73 Merge pull request #3005 from kientzle/kientzle-automatic-test-discovery
[CMake] Automatically update `list.h`
2026-05-05 21:23:54 -07:00
Tim Kientzle 2f5ed45e4c [CMake] Automatically update list.h
`list.h` contains a list of all the tests and is generated
by grepping the test source files for `DEFINE_TEST`.
Previously, it was generated at configure time.
This meant that if you added a new test to an existing
source file, you had to manually reconfigure.

This adds the necessary dependencies so that `list.h`
is regenerated whenever any C test source changes.
This ensures that new tests are always discovered automatically.

Note:  If someone wants to update the autoconf-based
build system to do this, please send a PR.
2026-05-05 20:54:12 -07:00
Tim Kientzle c8afaafb5c Merge pull request #3000 from kientzle/kientzle-cab-hardening
[CAB] Harden the handling of invalid headers
2026-05-05 18:35:33 -07:00
Tim Kientzle 60edb22a0b Merge pull request #3004 from kientzle/kientzle-rar5-bad-tables
[RAR5] FAIL if the decode table is > 2^16
2026-05-05 18:34:22 -07:00
Tim Kientzle 9d6738f554 Remove unused var 2026-05-05 18:20:10 -07:00
Tim Kientzle b5fd810f5d Solid archives cannot recover from a failed entry 2026-05-05 18:03:28 -07:00
Tim Kientzle 09d803dec9 [RAR5] FAIL if the decode table is > 2^16 2026-05-05 15:43:48 -07:00
Tim Kientzle 3526803cb4 Merge pull request #3002 from kientzle/7zip-setup-decode-folder-state-order
[7zip] Clean up the failure path in `setup_decode_folder`
2026-05-05 15:21:50 -07:00
Tim Kientzle aa43119e35 Merge pull request #3003 from kientzle/kientzle-test-runner-name-args
Clarify the test harness usage
2026-05-05 15:21:25 -07:00
Tim Kientzle 28b670d1ed Clarify the test harness usage 2026-05-05 14:45:26 -07:00
Tim Kientzle d4801f63f1 [7zip] Clean up the failure path in setup_decode_folder
As noted by @dunhor, the logic here was a little unclear.
Reorganize to do all the checks, then set up the decode
parameters only if the checks pass.

This has no functional change, it's just a legibility improvement.
2026-05-05 14:12:15 -07:00
Tim Kientzle 48410001f1 [RAR5] Correct handling of unknown filter types
The change to return FAILED for entry-specific issues uncovered
flaws in RAR5 handling of filter types:
* Supported filter types are verified in `parse_filter` and
  were being also checked in `run_filter` -- the duplication
  confused the error handling here.
* `do_uncompress_file` was only checking for `FATAL` from
  the upstream filter logic, so failed to properly pass
  `FAILED` errors through
2026-05-05 13:39:27 -07:00
Tim Kientzle 25d9731518 [rar5] Fix infinite loop in header parsing
The change to return `FAILED` instead of `FATAL` for issues that
impact a single entry (but don't necessarily terminate the entire archive)
created a bug in header parsing since `FAILED` wasn't handled in a
header-check loop.

Thank goodness for fuzzing CI!
2026-05-05 13:39:27 -07:00
Tim Kientzle 24c7124407 7zip: propagate skip_stream's actual error code in read_data_skip
archive_read_format_7zip_read_data_skip used to coerce any negative
skip_stream() return into ARCHIVE_FATAL.  That is wrong in principle:
ARCHIVE_FAILED can legitimately propagate up from setup_decode_folder()
through read_stream() and skip_stream(), and the wrapper should not
upgrade it.

In the current encryption-partially test case this is empirically a
no-op because skip_stream() still returns ARCHIVE_FATAL via a second,
deeper code path through extract_pack_stream().  An inline TODO comment
flags that asymmetry for a follow-up audit.
2026-05-05 13:39:27 -07:00
Tim Kientzle 2bb18c0670 rar5: convert remaining per-entry data errors to ARCHIVE_FAILED
Follow-up to 9fa772ab.  An audit of the rar5 reader found many more
ARCHIVE_FATAL returns in data-decode paths that should be ARCHIVE_FAILED
so the caller can move on to the next entry after a corrupt one:

  apply_filters       Unsupported filter type
  parse_tables        Truncated huffman tables, decode failures (8 sites)
  parse_block_header  Unsupported header size, block checksum error
  do_uncompress_block Decode code length / distance slot failures
                      Distance pointer overflow
                      decode_number / decode_code_length failures
  merge_block         Block size == 0 during merge
  do_uncompress_file  Invalid window size declaration
  verify_checksums    CRC32 / BLAKE2 mismatch

Programmer assertions, ENOMEM, true I/O errors, and propagation of
copy_string's window-buf-NULL FATAL return are intentionally kept as
ARCHIVE_FATAL because they are not recoverable per-entry conditions.
2026-05-05 13:39:27 -07:00
Tim Kientzle 6fec0b68cd rar: convert remaining per-entry data errors to ARCHIVE_FAILED
Follow-up to 4f148608.  A code review found additional ARCHIVE_FATAL
returns in RAR4 data-decode paths that should be ARCHIVE_FAILED so the
caller can move on to the next entry:

  read_data_block      Truncated RAR file data
  read_data_compressed PPMd "Invalid symbol" (3 sites)
  parse_codes          Zero window size is invalid
  add_value            Prefix found (second site)
  make_table_recurse   Huffman tree was not created
  make_table_recurse   Invalid location to Huffman tree specified

These are all per-entry parse/decode failures.  As with the earlier
batch, the rar4 input position is tracked by rar_br_fillup so
read_data_skip will correctly advance past the damaged entry, and
RAR4 solid mode is not supported, so subsequent entries are not at
risk from a half-consumed shared decoder state.
2026-05-05 13:39:27 -07:00
Tim Kientzle 47c07e8948 tests: update expected return codes from FATAL to FAILED
Per-entry data errors (encryption, invalid filters, bad bitstream) now
return ARCHIVE_FAILED instead of ARCHIVE_FATAL.  Update tests that were
asserting the old incorrect ARCHIVE_FATAL return codes.

The one exception is test_read_format_7zip_encryption_partially line 71,
which asserts ARCHIVE_FATAL after archive_read_next_header on the entry
following an encrypted entry: 7zip cannot skip an encrypted entry (the
decode-folder setup fails), so the skip legitimately returns ARCHIVE_FATAL
and the archive is done.
2026-05-05 13:39:27 -07:00
Tim Kientzle 1b0ca26137 7zip: return ARCHIVE_FAILED (not ARCHIVE_FATAL) for per-entry data errors
setup_decode_folder() returned ARCHIVE_FATAL for both header-level and
data-level encryption/filter errors.  Header encryption is a true
archive-fatal condition; data encryption is per-entry.

Distinguish the two by returning ARCHIVE_FATAL when decoding archive
headers (header==1) and ARCHIVE_FAILED when decoding file content
(header==0).  Fix the call site in read_stream() to propagate the
actual return value rather than mapping all errors to ARCHIVE_FATAL.
2026-05-05 13:39:27 -07:00
Tim Kientzle a89666728c rar5: return ARCHIVE_FAILED (not ARCHIVE_FATAL) for per-entry data errors
Two per-entry errors in the RAR5 data-reading path were returning
ARCHIVE_FATAL, preventing iteration over subsequent entries:

- "Reading encrypted data is not currently supported": the encryption
  is per-entry; unencrypted entries in the same archive remain readable.

- "Invalid filter encountered": a malformed filter spec in one entry
  does not make the rest of the archive unreadable.

Change both to ARCHIVE_FAILED.
2026-05-05 13:39:27 -07:00
Tim Kientzle 33f0bd86ff rar: return ARCHIVE_FAILED (not ARCHIVE_FATAL) for per-entry data errors
ARCHIVE_FATAL means the entire archive is unreadable and no further
operations are valid.  ARCHIVE_FAILED means the current entry cannot
be processed but iteration over subsequent entries may still succeed.

The RAR4 decompressor was returning ARCHIVE_FATAL from a large number
of data-parsing failures (invalid Huffman prefix, invalid PPMd sequence,
bad CRC, invalid symbol, etc.) that are per-entry errors.  Because each
entry's compressed data region can be skipped using the packed_size
recorded in its file header, a decompressor error does not prevent
reading the next entry's header.

Change all such per-entry errors in the data-reading path
(read_data_stored, read_data_compressed, parse_codes, create_code,
add_value, make_table_recurse, expand, copy_from_lzss_window,
copy_from_lzss_window_to_unp) to return ARCHIVE_FAILED.  OOM errors
and true I/O failures (rar_br_preparation truncated-data) remain
ARCHIVE_FATAL.
2026-05-05 13:39:27 -07:00
Tim Kientzle e1f890dc62 archive_read: make ARCHIVE_FATAL sticky in data-reading entry points
Three entry points in archive_read.c could return ARCHIVE_FATAL from
the format layer without setting a->archive.state = ARCHIVE_STATE_FATAL,
so subsequent API calls would not see the archive as fatally broken:

- archive_read_data_skip() unconditionally reset state to HEADER even
  when the format's skip returned ARCHIVE_FATAL.

- archive_seek_data() and _archive_read_data_block() forwarded FATAL
  from the format layer without recording it in the archive state.

Fix all three so that ARCHIVE_FATAL causes the state to become
ARCHIVE_STATE_FATAL, consistent with the existing behavior of
archive_read_next_header().
2026-05-05 13:39:27 -07:00
Tim Kientzle e9d68b030d Merge pull request #3001 from kientzle/kientzle-7zip-test-more-tolerant
Suppress spurious failures from old liblzma
2026-05-04 17:43:13 -07:00
Tim Kientzle 800f7af66f Suppress spurious failures from old liblzma 2026-05-04 17:14:21 -07:00
Tim Kientzle 0233c3008d [CAB] Harden the handling of invalid headers
Clear invalid data when a header is invalid.
Check for data being larger than the allocated buffer.

Thanks to @ReverseWarrior for pointing out this issue,
and providing the fix.
2026-05-04 17:01:33 -07:00
Tim Kientzle b18956ea60 Merge pull request #2992 from kientzle/kientzle-acl-isint-overflow
Expand ACL testing
2026-05-03 20:04:03 -07:00
Tim Kientzle ca7f0bfa93 Merge pull request #2991 from kientzle/kientzle-tar-timestamp-hardening
[tar] Harden timestamp parsing
2026-05-03 15:23:22 -07:00
Tim Kientzle 752e197900 Use time_t return for a time_t value 2026-05-03 14:43:10 -07:00
Tim Kientzle 4c19c1ed14 Merge pull request #2996 from kientzle/kientzle-zip-empty-pathname
[Zip] Reject empty pathnames in ZIP writer
2026-05-03 14:33:34 -07:00
Tim Kientzle 591b36307a Merge branch 'master' into kientzle-zip-empty-pathname 2026-05-03 09:38:55 -07:00
Tim Kientzle 6fcf9b4589 Merge pull request #2993 from kientzle/kientzle-zip-long-pathnames
[Zip] Don't try to write overlong pathnames
2026-05-03 09:36:26 -07:00
Tim Kientzle 14da31ff23 [Zip] Reject empty pathnames in ZIP writer
An empty pathname caused a one-byte OOB read before the heap buffer in
write_path() due to two compounding bugs:
(1) misuse of bitwise & instead of logical &&, and
(2) missing gaurd for an empty pathname
2026-05-03 09:32:00 -07:00
Tim Kientzle a20f89eb9b [Zip] Reject overlong pathnames in Zip writer 2026-05-02 16:52:35 -07:00
Tim Kientzle 2065e6c417 Test writing overlong Zip pathnames 2026-05-02 16:52:19 -07:00
Tim Kientzle 9d5b4feeba [ACL] Add more tests for POSIX.1e ACLs
This mirrors the tests just added for NFS4 ACLs.  They
didn't uncover any problems.
2026-05-02 16:23:32 -07:00
Tim Kientzle 5ca297b766 [archive_acl] Reject ACL entries with out-of-range numeric IDs
isint() and isint_w() previously clamped values >= INT_MAX to INT_MAX
and returned success, allowing malformed ACL text to silently set IDs
to an arbitrary sentinel value.  Change them to return -1 (a new
"overflow" indication) instead, and update all callers in both the
NFS4 and POSIX parsers (narrow and wide) to treat overflow as
ARCHIVE_WARN and skip the offending entry.

Add test_acl_nfs4_text.c with four test functions covering NFS4 ACL
text round-trips, audit/alarm entry types, numeric-ID handling
including the overflow boundary (INT_MAX - 1 accepted, INT_MAX
rejected), and malformed-entry error paths.
2026-05-02 16:22:47 -07:00
Tim Kientzle d1d37fcbd7 [tar] Harden timestamp parsing
Improves the parsing of timestamps in a couple of ways:

* Saturate when timestamps exceed the range of time_t.
  In particular, this provides more rational behavior on
  systems with 32-bit time_t.

* Validate the format of overlong pax timestamps.
  We previously failed to check that high-resolution
  timestamps had only digits in the fractional part.
  We now notice and ignore those with a warning.
2026-05-02 15:02:28 -07:00
Tim Kientzle 1cc5c21be2 Merge pull request #2990 from kientzle/kientzle-gitignore-AI-files
Ignore local CLAUDE/GEMINI files
2026-05-02 15:05:07 -04:00
Tim Kientzle 5cc13dcaf2 Ignore local CLAUDE/GEMINI files 2026-05-02 12:03:57 -07:00
Tim Kientzle 4b66fc68e4 Merge pull request #2989 from kientzle/kientzle-test-documentation
Minor clarification on test discovery
2026-05-02 15:02:14 -04:00
Tim Kientzle b43f61da90 Minor clarification on test discovery 2026-05-02 12:00:33 -07:00
Martin Matuška 740be68fc0 Merge pull request #2985 from stoeckmann/7zip_sfx
7zip: Harden SFX parser
2026-05-02 20:48:01 +02:00
Martin Matuška cf9bc89194 Merge pull request #2988 from kientzle/kientzle-acl-to-text
[archive_acl] Fix buffer overrun and wrong output for NULL-name ACL entries
2026-05-02 20:43:56 +02:00
Tim Kientzle d45b5b4b52 archive_acl: Fix buffer overrun and wrong output for NULL-name ACL entries
archive_acl_text_len() counted the trailing ":id" digits only when
ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID was set, but archive_acl_to_text_l()
always writes them for USER/GROUP entries whose name is NULL.  With a
7-digit or larger id the allocated buffer was too short, causing
append_id() to write past its end.

Fix the estimator to also count the extra colon and digits when the
name is NULL, matching the serializer's logic.

The wide serializer (archive_acl_to_text_w) had the opposite problem:
it passed id=-1 to append_entry_w() for NULL-name entries regardless
of the id value, causing a garbage character to be written in the name
field and the numeric id to be omitted entirely.  Fix it to mirror the
narrow serializer by setting id = ap->id when wname is NULL.

Add tests for both the narrow and wide paths.
2026-05-02 09:46:06 -07:00
Tim Kientzle 0755b9eba0 Merge pull request #2983 from kientzle/kientzle-iso9660-joliet-pathname
[iso9660] Fix joliet pathname overflow
2026-05-02 12:09:47 -04:00
Tim Kientzle f33f07442a Merge pull request #2973 from dag-erling/des/darwin-crypto
On Darwin, get digests from libsystem
2026-05-02 12:07:28 -04:00
Dag-Erling Smørgrav 7364e380bc configure: On Darwin, get digests from libsystem
Darwin covers a wide range of platforms with similar but not identical
sets of libraries.  MD5, SHA1 and SHA2 are available from libsystem on
all of these, but macOS also has them in libc and libmd.  Restricting
our search to only libsystem means we can run configure on macOS and get
a config.h that also works for other Darwin platforms.
2026-05-02 12:49:02 +02:00
Tobias Stoeckmann 45d493e4d8 7zip: Fix typos in comment
Also clarify that all systems will handle these SFX files, no matter on
which system libarchive is used.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-04-27 20:15:44 +02:00
Tobias Stoeckmann 9082a50780 7zip: Cap maximum allocation for SFX handling
If 7zip header cannot be found within roughly first 8 MB of data, skip
detection and assume that file is not a valid 7zip archive.

This avoids various 32 bit truncation issues as well as out of memory
conditions.

Reported by various individuals:
- Amemoyoi
- b4sh5i
- Jie Zhu
- Tikket
- wooseokdotkim

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-04-27 20:10:06 +02:00
Tobias Stoeckmann 618a9d77d3 7zip: Be precise about SFX data types
Use desired data types: Offsets in files are (u)int64_t, sizes in memory
are (s)size_t. Use signedness when needed or specified by APIs.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-04-27 20:10:05 +02:00
Tobias Stoeckmann a7b8bef392 7zip: Adjust sfx offset function signatures
Return an int for error information and supply offset through a given
argument. This fits other function declarations and makes it much easier
to differentiate between status and "return value".

While at it, merge fallback mechanism of both functions.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-04-27 20:10:04 +02:00
Tobias Stoeckmann 71ef1c3852 7zip: Merge skip_sfx into get_data_offset
This removes the function skip_sfx which makes slurp_central_directory
and archive_read_format_7zip_bid use the same code now.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-04-27 20:10:03 +02:00
Tobias Stoeckmann 7f13163608 7zip: Introduce get_data_offset
Its functionality is split off from archive_read_format_7zip_bid
and returns offset to actual data, i.e. it handles self extracting
(SFX) files if offset 0 is not already a 7zip magic.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-04-27 20:10:02 +02:00
Tobias Stoeckmann 73db9854ad 7zip: Reduce archive_read_format_7zip_bid depth
Prepare content of archive_read_format_7zip_bid to be split into its own
function which eventually can be reused by slurp_central_directory.

No real functional change (split if-blocks).

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-04-27 20:10:01 +02:00
Tobias Stoeckmann eb6954c850 7zip: Remove casts in check_7zip_header_in_sfx
Directly request an unsigned char pointer. This removes casts within the
function check_7zip_header_in_sfx and its surrounding caller code.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-04-27 20:10:00 +02:00
Alejandro Perez 23de58817c Fix test_format_newc timestamp race condition
Add 1-second tolerance to timestamp assertion to account
for timing variations in containerized build environments.

Fixes #2917
2026-04-27 06:18:19 +00:00
Tim Kientzle 750e8d7b25 Fix joliet pathname buffer overflow 2026-04-26 18:22:10 -04:00
Tim Kientzle 571345791c [ISO9660] Test for buffer overflows with Joliet pathname building
Credit: Anthropic
2026-04-26 18:20:57 -04:00
Tim Kientzle 4f3cf235e3 Merge pull request #2526 from fdegros/compress_support
Fix SIGSEGV in compress filter when appended before open
2026-04-25 16:51:46 -04:00
Tim Kientzle f18c7cb45c Merge pull request #2980 from kientzle/kientzle-7zip-numfiles
[7zip] Sanity-check the number of files
2026-04-25 16:42:06 -04:00
Tim Kientzle 51cfd61544 [7zip] Sanity-check the number of files
We allocate space early on to support the advertised number of
files. A malicious archive can set a nonsensical value here to exhaust
memory. This adds a check comparing the number of files to the number
of streams and the size of the total header.

Note that the just-added test does not actually fail without this.
The existing code recovers if the allocation fails, which it typically
will.  The new check tightens the limit so that we reject nonsensical
file counts and avoid problems from large memory allocations.
2026-04-25 14:58:17 -04:00
Tim Kientzle a2de48dd0f Merge pull request #2981 from kientzle/kientzle-zip-lzma-memory
[Zip] Limit the LZMA initialization to 64MiB memory
2026-04-25 14:57:19 -04:00
Tim Kientzle df55563f0e Merge pull request #2964 from kientzle/kientzle-test-documentation
Document how to write new tests and how to build and run test suites
2026-04-25 14:51:42 -04:00
Tim Kientzle 033dd7f2a5 [7zip] Test extracting an archive with a malicious file count
This currently results in an oversized allocation that can
exhaust available memory.
2026-04-25 14:48:34 -04:00
Tim Kientzle 28a174f2ca Limit LZMA memory allocation to 576MiB
Reject Zip entries that declare an LZMA dictionary size
greater than the maximum possible with Level 9 compression.
2026-04-25 14:42:58 -04:00
Tim Kientzle d8f4a26011 Test extracting Zip Lzma entry with a malicious dictionary size 2026-04-25 14:32:32 -04:00
Tim Kientzle e7afd7730f Additional adjustments 2026-04-24 21:50:42 -04:00
Tim Kientzle 7439210634 Merge pull request #2979 from tyler-yankee/cab-huffman-memcheck
cab reader: Fix use of uninitialized values from Huffman table
2026-04-24 19:44:26 -04:00
François Degros ccf4cd06d2 Add tests for appending various filters before archive open
Extend test coverage to ensure all supported filters can be appended
to an archive reader before it is opened, matching the behavior
required to fix #2514.

Added tests for: BZIP2, LRZIP, LZ4, LZIP, LZMA, ZSTD, RPM, UU, and NONE.
2026-04-24 17:35:27 +10:00
François Degros 3d4871e4d2 Fix SIGSEGV in compress filter when appended before open
Calling archive_read_append_filter(a, ARCHIVE_FILTER_COMPRESS) would
previously trigger a crash because compress_bidder_init() attempted to
read header bits from the upstream filter immediately. If the archive
was not yet opened (common when setting up filters), the upstream filter
state was not ready for reading.

This commit defers the header reading and decompressor initialization
until the first read operation (lazy initialization), consistent with
other filter implementations in libarchive.

Added test_read_append_compress_filter.

Bug: https://github.com/libarchive/libarchive/issues/2514
Test: ./libarchive_test test_read_append_compress_filter
2026-04-24 17:24:02 +10:00
Tyler Yankee 1f5454575f cab reader: Fix use of uninitialized values from Huffman table
Initialize the Huffman table to invalid values, which doesn't otherwise
affect the computation but avoids use of uninitialized values upon
extraction of some archives (as reported by `valgrind`).
2026-04-23 08:02:52 -04:00
Tim Kientzle d8ca779e4d Merge pull request #2966 from solbjorn/win-crypt-unforce
libarchive: fix Windows compilation with `ENABLE_CNG=OFF`
2026-04-21 18:09:17 -07:00
Alexander Lobakin 15b133b372 libarchive: fix Windows compilation with ENABLE_CNG=OFF
Currently, libarchive_{random,util}.c use a couple bcrypt functions
regardless of whether HAVE_BCRYPT_H is defined as there are no other
implementations for Windows, but the actual <bcrypt.h> header is
included only under this macro.

To be able to build libarchive with ENABLE_CNG=OFF (for example, to
prefer a different crypto/digest engine) on Windows, don't guard
the include in these two files. In that case, bcrypt will still be
used, but only as an RNG.
This won't break anything because, as mentioned above, bcrypt is
used unconditionally here and if it's not present in the system,
the library won't build either way, with or without the change.
At least until we implement an RNG for Windows based on something
else.

Signed-off-by: Alexander Lobakin <alobakin@mailbox.org>
2026-04-21 22:50:18 +02:00
Tim Kientzle cb779c5d26 Merge pull request #2971 from stoeckmann/asan_memleak
Fix mem leaks found with ASAN-enabled test suites
2026-04-20 18:56:35 -07:00
Tim Kientzle 92c430d484 Merge pull request #2970 from stoeckmann/gitignore
build: Add more entries to .gitignore
2026-04-20 18:54:43 -07:00
Tobias Stoeckmann bf7cd8c284 Fix memory leaks in test suites
Release memory so ASAN becomes a viable option for test suites.
2026-04-20 20:12:18 +02:00
Tobias Stoeckmann 2f22c57422 mtree: Always release digest memory
If a checksum has been provided through archive_entry and no data is
written, then digest internal memory is not released.

Fix this by always calling final functions, even if result is not
needed.
2026-04-20 20:12:15 +02:00
Tobias Stoeckmann 330bda678e tar: Release memory on error path
Release attr_name memory on error paths.

Fixes: 101646e34e ("tar: Keep block alignment after pax error")
Fixes: 36a530973a ("Fix an infinite loop when parsing `V` headers")
2026-04-20 20:12:13 +02:00
Tobias Stoeckmann 2ba0dc20cd build: Add more entries to .gitignore
Using cmake within VSCode leads to creation of files which are not covered
by .gitignore so far. Covers Linux and Windows builds.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-04-20 20:10:15 +02:00
Tim Kientzle 45d9c12632 Merge pull request #2968 from stoeckmann/isofile_gen_utility_names_dotdot
iso9660: Fix `..` (dot dot) path normalization
2026-04-19 13:42:53 -07:00
Tobias Stoeckmann 941e32fd6e iso9660: Fix ../../ path normalization
The function isofile_gen_utility_names could resolve .. directory
entries in a way that dirname will start with "../". If this happens,
the while-loop is unable to detect this because it forwards until the
cursor detects a slash again.

Fix this by also taking "../" at the beginning into account. Such an
entry can happen if "../../" points before the top directory.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-04-19 22:17:13 +02:00
Tobias Stoeckmann 8903139075 iso9660: Add adjacent dot dot issue to test suite
If dot dot directory entries point before top directory, it can happen
that "../" will stay at the start of the path.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-04-19 22:16:40 +02:00
Tobias Stoeckmann 29bc107209 iso9660: Handle multiple slashes after dot dot
The isofile_gen_utility_names function normalizes directories, including
dot dot directory entries. If such an entry has multiple slahes and leads
to the top directory, then the new path erroneously becomes absolute.

Skip multiple slashes.

If rp is not NULL, then it points to a slash already. Takes this into
account to unify the rp and dirname cases a bit more.

Resolves #2937.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-04-19 22:16:16 +02:00
Tobias Stoeckmann 8a1d019c0f iso9660: Extend test suite for OOB access
Normalizing dot dot directory entries with multiple slashes leads to
memory issues further down the call stack.

Reported in #2937.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-04-19 22:15:48 +02:00
Tobias Stoeckmann 8ba3972efe iso9660: Use memmove with overlapping memory
Resolving paths like "dir/../filename" to "filename" can lead
to a strcpy call with overlapping memory. Use memmove instead,
which already happens at times in isofile_gen_utility_names.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-04-19 21:40:19 +02:00
Benjamin Gilbert 430e63eccb Fix test_write_filter_gzip on Ubuntu s390x
Ubuntu patches zlib to use DFLTCC hardware DEFLATE acceleration on s390x
on compression levels 1-6, causing levels 1 and 6 to produce output with
the same lengths.  Avoid the resulting test failure by comparing the
output lengths of levels 1 and 9 instead.

Tested on Ubuntu 24.04 on s390x hardware.

Fixes: https://github.com/libarchive/libarchive/issues/1515
2026-04-19 17:19:54 +00:00
Tim Kientzle 6411fc8500 Merge pull request #2965 from bgilbert/distcheck
Have `make distcheck` verify CMake build succeeds
2026-04-18 21:18:33 -07:00
Benjamin Gilbert 0edf315faa Have make distcheck verify CMake build succeeds
There have been multiple instances of test cases being added to the CMake
build but not the Autotools one, thus omitting them from the released dist
tarball.  Prevent this by testing the CMake build during `make distcheck`.
2026-04-18 23:05:58 -05:00
Tim Kientzle 0b0b888f86 Merge pull request #2905 from Patsakas/Patsakas-fix-acl-bug
Fix NULL pointer increment in archive_acl_from_text_nl

(Not a security issue, and arguably not really even a bug, but easy to fix regardless.)
2026-04-18 21:04:59 -07:00
Tim Kientzle 4fd2e893c1 Fix indentation in examples to match project style 2026-04-18 19:58:46 -07:00
Tim Kientzle dbaf6794c4 Document how to write new tests and how to build and run test suites
I consider this an experiment to see if we can improve the
quality of incoming PRs.
2026-04-18 19:51:27 -07:00
Martin Matuška 2860b2a792 Merge pull request #2961 from bgilbert/malformed
Add malformed CAB test to Autotools
2026-04-18 01:33:00 +02:00
Martin Matuška fc76727081 Merge pull request #2962 from dag-erling/des/optreset
unzip: Remove dead code
test_main: Staticize some variables
2026-04-18 01:27:42 +02:00
Dag-Erling Smørgrav bfa16c05a2 test_main: Staticize some variables
These variables are not used outside test_main, so they should be static.

Fixes:		a252c60308 ("test_main: Run tests as unprivileged user")
2026-04-17 18:46:59 +02:00
Dag-Erling Smørgrav b92f14a220 unzip: Remove dead code
Remove an #include controlled by a preprocessor symbol that nothing
defines.  I'm not sure if this has ever been needed, or what for, but
it serves no purpose today.
2026-04-17 18:45:55 +02:00
Tim Kientzle aca8b0d3d2 Merge pull request #2942 from benoit-pierre/pr/fix___LA_MODE_T_handling
fix `archive_entry_set_mode` & `archive_entry_set_perm`
2026-04-17 05:04:53 -07:00
Benoit Pierre f30d7fe833 fix archive_entry_set_mode & archive_entry_set_perm
Match the prototypes in `archive_entry.h`: use `__LA_MODE_T` (which is not always an alias for `mode_t`).
2026-04-16 20:15:27 +02:00
Benjamin Gilbert 08e39deca2 Add malformed CAB test to Autotools
It wasn't being included in the dist tarball.

Fixes: 32b62cf785 ("Fix NULL pointer dereference in CAB parser during skip")
2026-04-16 10:36:03 -05:00
Tim Kientzle 6d9dddbab1 Merge pull request #2957 from kientzle/kientzle-linkresolver
Fix a double-free in the link resolver
2026-04-13 20:14:58 -07:00
Tim Kientzle 66d0d11742 Remove unused variable 2026-04-13 20:00:24 -07:00
Tim Kientzle d99cd8340f Minor code improvements 2026-04-13 19:58:12 -07:00
Tim Kientzle 23edf56960 Fix a double-free in the link resolver
The link resolver is a helper utility that tracks linked
entries so they can be correctly restored.  Clients add link information
to the link resolver and incrementally query it to correctly
link entries as they are restored to disk.  The link resolver
incrementally releases entries as they are consumed in order
to minimize memory usage.

The `archive_entry_linkresolver_free()` method cleans up
by repeatedly querying the cache and freeing each entry.
But this conflicted with the incremental clean up,
leading to double-frees of leftover items.

The easy fix here is to have `archive_entry_linkresolver_free()`
just repeatedly query the list without trying to free, relying
on the incremental clean up mechanism.

Credit: tianshuo han reported the issue and suggested the fix.
2026-04-13 19:38:07 -07:00
Tim Kientzle f78019b41c Merge pull request #2952 from solbjorn/ppmd-symbols
libarchive/ppmd8: mark the remaining functions static
2026-04-12 16:12:07 -07:00
Tim Kientzle 762b30011a Merge pull request #2898 from ElhananHaenel/fix/rar3-lzss-window-realloc
rar: fix LZSS window size mismatch after PPMd block
2026-04-12 15:16:57 -07:00
Tim Kientzle f76218f309 Merge pull request #2934 from ElhananHaenel/fix/zisofs-validate-log2bs
FIX - iso9660: validate pz_log2_bs, add test for 32-bit heap overflow
2026-04-12 15:13:18 -07:00
Tim Kientzle 34f7d8c73e Merge pull request #2924 from stoeckmann/pathmatch_pm
pathmatch: Anchors within pattern not special
2026-04-12 15:03:02 -07:00
Tim Kientzle aaf154f627 Merge pull request #2922 from stoeckmann/err_style_followup
Improve style of more error messages
2026-04-12 15:02:13 -07:00
Tim Kientzle c8f6c3fb05 Merge branch 'master' into fix/zisofs-validate-log2bs 2026-04-12 14:57:23 -07:00
Tim Kientzle 071e2e1c59 Merge pull request #2897 from ElhananHaenel/fix/iso_zisofs_undefined_behavior
iso9660: validate pz_log2_bs in parse_rockridge_ZF1()
2026-04-12 14:51:56 -07:00
elhananhaenel a2a73a8f14 Add regression test for zisofs 32-bit heap overflow
A crafted ISO with pz_log2_bs=2 and pz_uncompressed_size=0xFFFFFFF9
causes an integer overflow in the block pointer allocation in
zisofs_read_data(). On 32-bit, (ceil+1)*4 wraps size_t to 0, malloc(0)
returns a tiny buffer, and the code writes ~4GB past it.

The pz_log2_bs validation fix prevents this. Add a regression test with
a crafted 48KB ISO that triggers the overflow on unfixed 32-bit builds.
2026-04-09 19:09:12 +03:00
ShelpAm e8d363a09d fix: zstd not found
On Windows, zstd is sometimes named `zstd_static`.
2026-04-09 15:26:12 +08:00
Alexander Lobakin dc58c10ac4 libarchive/ppmd8: mark the remaining functions static
Those 9 are not used anywhere outside the file (the actual
functionality is exported as a callback structure).
Make them static for a bit better compiler optimization
opportunities and, more important, to avoid symbol conflict
when static linking libarchive and any library which uses
the original Ppmd*.c from the LZMA SDK (like minizip-ng).

Also remove a couple declarations and macros not used
anywhere at all while we're here.

Signed-off-by: Alexander Lobakin <alobakin@mailbox.org>
2026-04-08 22:12:32 +02:00
Tim Kientzle 2bb6f3461c Merge pull request #2947 from fdegros/lzop_support
LZOP and GRZIP support
2026-03-29 16:34:20 -07:00
François Degros 1bdc3c1df8 Add tests
test_read_append_lzop_filter
test_read_append_grzip_filter

Bug: https://github.com/libarchive/libarchive/issues/2513
Test: ./libarchive_test test_read_append_lzop_filter test_read_append_grzip_filter
2026-03-27 21:49:16 +11:00
Tim Kientzle ea3b510322 Fix archive_read_append_filter() for lzop and grzip
These two filters failed to correctly set a name when
being registered, which prevented them from working
correctly with archive_read_append_filter()

Thanks to @fdegros for the test case demonstrating the lrzip failure
2026-03-27 14:04:24 +11:00
Tim Kientzle 30335f92d9 Merge pull request #2943 from bgilbert/test
Add v7 tar filename encoding test to Autotools
2026-03-22 10:34:40 -07:00
Benjamin Gilbert 56ee1eca57 Add v7 tar filename encoding test to Autotools
It wasn't being included in the dist tarball.

Fixes: d4cf95cdac ("archive_write: Fix crash on failure to convert WCS/UTF-8 pathname to MBS")
2026-03-21 20:49:38 -07:00
Tim Kientzle 8f6614c378 Merge pull request #2919 from LoboQ1ng/fix-cab-lzx-oob
Fix Heap OOB Write in CAB LZX decoder
2026-03-20 19:11:15 -07:00
LoboQ1ng 6f0d94ea23 build: add test files to Makefile.am for autotools compatibility 2026-03-21 00:27:12 +00:00
LoboQ1ng 32c6572023 test: resolve SonarQube code smell by removing redundant conditional 2026-03-20 21:57:18 +00:00
Tim Kientzle 24f4626777 Merge pull request #2939 from stoeckmann/cpio_mem_leak
cpio: Fix `-R` memory leak
2026-03-20 08:44:15 -07:00
Tim Kientzle 7229570c84 Merge pull request #2940 from wrp/wrp/doc
Provide more details on autotool meta-files
2026-03-20 08:43:08 -07:00
William Pursell db7aa7530f Provide more details on autotool meta-files
Given the amount of confusion surrounding the autotools, it is
better to have accurate descriptions of these files in the
README.
2026-03-20 09:07:45 -06:00
Tobias Stoeckmann 393d686854 cpio: Fix -R memory leak
If the -R command line argument is supplied with user/group names
multiple times, memory leaks occur.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-03-20 13:40:19 +01:00
Tobias Stoeckmann adf7edd191 pathmatch: Anchors within pattern not special
The anchor characters ^ and $ have only special meanings if they are
located at the beginning (^) or at the end ($) of the pattern. And even
then they are supposed to be only special if flags are set.

If they are located within the pattern itself, they are regular
characters regardless of flags.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-03-18 14:31:03 +01:00
Tobias Stoeckmann b468e242d8 zip: Unify error code formatting in error messages
This unifies the way error codes are shown in error messages.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-03-18 14:30:44 +01:00
Tobias Stoeckmann 7632c6fcf4 rar5: Remove "Error: " prefix from error message
Unifies style with other error messages.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-03-18 14:30:44 +01:00
Tobias Stoeckmann abfac2ca3b Fix whitespace style in error messages
- Keep a whitespace between text and brackets
- No whitespace between text and colon
- No newline at end of error message

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-03-18 14:30:44 +01:00
Tobias Stoeckmann 74055248b7 7zip: Fix typo in error message
Failed should be written without capital letter here.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-03-18 14:30:44 +01:00
Tobias Stoeckmann 53755dc951 Remove periods from error messages
Some error messages previously slipped through. Remove periods from
these messages as well.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-03-18 14:30:44 +01:00
Tim Kientzle 4613cc9d79 Merge pull request #2921 from stoeckmann/err_style_regression
Fix Windows test regression
2026-03-18 05:58:45 -07:00
Tobias Stoeckmann cf7c78228f Fix Windows test regression
By only removing periods from error messages in Windows specific code,
but not adjusting its POSIX counterpart, the test fails on Windows but
not on POSIX systems.

Fix this by removing the period in test and in POSIX error messages.

Fixes: 3e0819b59e ("libarchive: Remove period from error messages")

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-03-18 09:09:30 +01:00
Tim Kientzle 54436854a4 Merge pull request #2912 from stoeckmann/pax_ugid
pax: Remove uid/gid cast in value range check
2026-03-17 20:11:29 -07:00
Tim Kientzle 7a5ec15781 Merge pull request #2913 from stoeckmann/cpio_buff
cpio: Reduce visibility of variable buff
2026-03-17 20:09:54 -07:00
Tim Kientzle be30e16fea Merge pull request #2915 from stoeckmann/err_style
libarchive: Improve error message style
2026-03-17 20:07:55 -07:00
LoboQ1ng 79a0787b47 Fix Heap OOB Write in CAB LZX decoder 2026-03-18 00:24:40 +00:00
Tobias Stoeckmann 2038741077 libarchive: Fix error message style
Remove space in front of colon to match rest of messages.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-03-17 10:47:52 +01:00
Tobias Stoeckmann 90433e6eb7 libarchive: Remove "Failed : " error prefixes
Calling archive_set_error with a message and errno already indicates
that a failure occurred. Only a minority of functions did that: Unify
with the rest.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-03-17 10:46:25 +01:00
Tobias Stoeckmann 3e0819b59e libarchive: Remove period from error messages
The error messages are mostly written without a period. This makes
sense, because they can be accompanied with a strerror(errno) call,
giving more information: most likely a colon is appended.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-03-17 10:41:25 +01:00
Tobias Stoeckmann df9ce5cd6c cpio: Reduce visibility of variable buff
The buff variable is only used in entry_to_archive. Moving it into the
specific code block where it is actually used reduces its visibility and
thus makes it easier to read the code:

Since Windows indeed uses unsigned for read, this makes it much easier
to verify that buff never grows and cannot be too large.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-03-17 10:11:58 +01:00
Tobias Stoeckmann 91652bb2db pax: Remove uid/gid cast in value range check
The API allows to set int64_t uid/gid values. When writing pax archives,
such large values are properly set in the USTAR header of actual data in
base256, i.e. everything works.

The pax header entries might be missing though because the check
truncates these values to unsigned int. Larger values could be truncated
in a way that they seem smaller than (1 << 18).

The check in line 1427 which sets the uid/gid values into the PAX header
block is correct, truncating the actual value to max. octal
representation.

This is a purely defensive change to support parsers which actually
allow such large uid/gid values but do not understand base256 encoding.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-03-17 09:42:56 +01:00
Tim Kientzle f084dfae97 Merge pull request #2911 from stoeckmann/libarchive_opt_vals
libarchive: Check number ranges of supplied option values
2026-03-16 14:01:33 -07:00
Tobias Stoeckmann 7ea0c52519 libarchive/{b64,uu}: Improve atol8 checks
Make sure that supplied values cannot overflow int64_t, which would be
an undefined behavior. Also do not accept empty strings as numbers.

Last but not least, check values before casting them to target data
types to avoid truncations.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-03-16 16:53:29 +01:00
Tobias Stoeckmann 339e3fe76f libarchive: Check strto(u)l results before casts
Make sure that supplied option values fit into data types. If not,
return an error instead of silently truncating values.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-03-16 16:52:49 +01:00
Tobias Stoeckmann 182993dca1 libarchive/7zip: Properly check strto* errno value
Set errno to 0 before calling strtoimax/strtol and check its value
afterwards.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-03-16 15:57:17 +01:00
Tobias Stoeckmann b736f640a6 libarchive/gzip: Check strdup return value
Handle strdup error instead of silently ignoring the option.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-03-16 15:54:16 +01:00
Tim Kientzle 284a0a103f Merge pull request #2910 from stoeckmann/cpio_num
cpio: Check number arguments before casts
2026-03-16 06:56:31 -07:00
Tim Kientzle 9d1631752b Merge pull request #2909 from stoeckmann/lafe_error
tools: Remove `Error : ` prefix in lafe_errc calls
2026-03-16 06:47:14 -07:00
Tim Kientzle 339b0e7003 Merge pull request #2908 from stoeckmann/cpio_mode
cpio: Improve mode option handling
2026-03-16 06:46:38 -07:00
Tobias Stoeckmann 2f6e6b03ba cpio: Set lafe_warnc code to 0
Otherwise an unknown error is printed, which does not help the user
(especially since a custom message is printed in this case already).

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-03-16 14:34:32 +01:00
Tim Kientzle 568bfc7c50 Merge pull request #2872 from stoeckmann/filter_options_failed
filter options: Use ARCHIVE_FAILED on errors
2026-03-16 06:30:07 -07:00
Tim Kientzle 9cfee00d70 Merge pull request #2899 from stoeckmann/cpio_rename
cpio: Allow long paths with -r option
2026-03-16 06:28:55 -07:00
Tobias Stoeckmann 71d8195f2e cpio: Check number arguments before casts
Make sure that supplied arguments actually fit into target data types.
Print an error if numbers are too large instead of silently truncating
them.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-03-16 14:19:30 +01:00
Tobias Stoeckmann c24fa12410 tools: Remove 'Error : ' prefix in lafe_errc calls
Only a minority of calls to lafe_errc state explicitly that an error
occurred. Remove these few cases for a more unified argument handling.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-03-16 14:01:56 +01:00
Tobias Stoeckmann 40e00705e5 cpio: Clarify that onyl one mode is acceptable
Do not print that at least one mode has to be supplied. Exactly one mode
has to be supplied instead.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-03-16 13:50:42 +01:00
Tobias Stoeckmann 72ebae391a cpio: Improve mode argument checks
Complain only if contradicting mode options are supplied. Passing the
same argument multiple times should not lead to errors.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-03-16 10:16:19 +01:00
Tobias Stoeckmann ed2b40e43d filter options: Use ARCHIVE_FAILED on errors
If a filter option is recognized but its value is invalid, return
ARCHIVE_FAILED instead of ARCHIVE_WARN. The latter is used for unknown
options, e.g. at the end of the option setter functions.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-03-16 09:47:27 +01:00
Tobias Stoeckmann ef1744a352 cpio: Use getline in cpio_rename
The buffer has a fixed 1024 limit, which can be smaller than the maximum
allowed path length. Increasing the limit to 4096 would partially help,
but since leading spaces are stripped, input lines could be valid and
longer.

Use getline instead.
2026-03-16 09:43:54 +01:00
Tobias Stoeckmann 1ea5604e3e cpio: Refactor cpio_rename
Let cpio_rename work with the entry directly. In this initial step, it
moves buff into the stack.

The comment suggests that this was done in the past already.
2026-03-16 09:43:54 +01:00
Tobias Stoeckmann ab956a274e Move la_getline into libarchive_fe
This allows easier reuse of the getline implementation in other tools
like cpio (in upcoming commit).
2026-03-16 09:43:45 +01:00
Tobias Stoeckmann d99f5ebadf Add missing HAVE_STDIO_H cmake check
The check is performed by configure, but not with cmake. The
bsdunzip/la_getline.c file checks for presence of this definition.
2026-03-16 09:42:19 +01:00
Tim Kientzle f59ed04545 Merge pull request #2871 from stoeckmann/archive_options_either
libarchive: Correctly handle option failures
2026-03-15 19:21:37 -07:00
Tim Kientzle aab503881d Merge pull request #2900 from LoboQ1ng/fix-cab-null-deref
Fix NULL pointer dereference in CAB parser during skip
2026-03-15 18:41:04 -07:00
Tim Kientzle 33dab8959d Merge pull request #2903 from ZUENS2020/codex/fix-untar-parseoct-bounds-check
Fix OOB read in contrib/untar.c parseoct()
2026-03-15 18:39:32 -07:00
Tim Kientzle b5f1272333 Merge pull request #2901 from stoeckmann/cpio_llp64
tools: Cast int64_t to long long in printf
2026-03-15 18:39:10 -07:00
Georgios Patsakas 4b3ba035ed Fix NULL pointer dereference in archive_acl_from_text_nl
### Summary
This PR fixes a NULL pointer dereference in `archive_acl_from_text_nl()` (located in `archive_acl.c`) that occurs when parsing malformed PAX tar archives containing a short "default" ACL prefix.

### Technical Details
This is a variant of the bug previously fixed in the wide-character version `archive_acl_from_text_w()` via commit 7a6549a6 (Issue #2744). 

The vulnerability exists because `st = field[n].start + 1` is calculated before verifying if the field length is zero. In cases of malformed entries, `field[n].start` can be NULL, leading to Undefined Behavior/SIGILL. This patch applies the same logic from the wide-char fix: moving the pointer increment after the length guard.

### Validation
- **Environment:** Ubuntu 24.04, compiled with AddressSanitizer (ASan) and UndefinedBehaviorSanitizer (UBSan).
- **Reproduction:** Verified that the minimized PAX tar archive provided in issue #2904 no longer triggers the crash.
- **Regression:** All existing library tests pass.

Closes #2904
2026-03-12 22:24:13 +02:00
ZUENS2020 0064032972 Fix OOB read in contrib/untar.c parseoct()
Reported-by: ZUENS2020
2026-03-11 21:36:49 +08:00
Tobias Stoeckmann 89c5831750 tar: print int64_t uid/gid as long long
On LLP64 systems like Windows 11, overly large uid/gid values would be
truncated.

Same is true on Linux 32 bit.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-03-10 20:10:24 +01:00
Tobias Stoeckmann 31b48a1326 cpio: Cast int64_t to long long in printf
LLP64 systems like Windows 11 have a 32 bit long. Cast int64_t to
long long for better output.

Same is true for 32 bit systems.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-03-10 18:22:17 +01:00
LoboQ1ng 32b62cf785 Fix NULL pointer dereference in CAB parser during skip
When parsing a malformed CAB file, the skip routine (cab_checksum_finish) blindly calculated the checksum on an uninitialized cfdata->memimage. This patch adds a NULL check before the checksum calculation and includes a standalone test case with a minimized malformed payload to prevent regressions.
2026-03-10 17:04:43 +00:00
Tim Kientzle 78b632c336 Merge pull request #2877 from kientzle/kientzle-rar5-loop-bug
Infinite loop in Rar5 decompression
2026-03-09 19:52:31 -07:00
Tim Kientzle 7273d04803 Reject filters when the block length is nonsensical
Credit: Grzegorz Antoniak @antekone
2026-03-09 19:26:51 -07:00
Tim Kientzle ef53e2023d Infinite loop in Rar5 decompression
Found by: Elhanan Haenel
2026-03-09 19:26:51 -07:00
elhananhaenel e9bd2e8e85 Add TODO comment for future error propagation 2026-03-08 15:33:50 +02:00
elhananhaenel e1907c5832 Fix -Wsign-compare: cast mask+1 to unsigned int 2026-03-08 15:29:46 +02:00
elhananhaenel d379dc0b29 rar: fix LZSS window size mismatch after PPMd block
When a PPMd-compressed block updates dictionary_size, the LZSS window
from a prior block is not reallocated. The allocation guard only checks
if dictionary_size is zero or the window pointer is NULL, not whether
the existing window is large enough. This allows copy_from_lzss_window()
to read past the allocated buffer.

Fix the guard to also check whether the current window is undersized.
Add bounds checks in copy_from_lzss_window() and parse_filter() as
defense in depth.
2026-03-07 22:32:09 +02:00
elhananhaenel c3cb1c568e iso9660: validate pz_log2_bs in parse_rockridge_ZF1()
The zisofs block size exponent (pz_log2_bs) read from the Rock Ridge ZF
extension entry is used directly in shift expressions without validation.
The zisofs specification only permits values 15, 16, or 17 (corresponding
to 32K, 64K, and 128K block sizes).

When pz_log2_bs >= 64 on 64-bit systems (or >= 32 on 32-bit), the
expression (size_t)1UL << pz_log2_bs is undefined behavior per C11
6.5.7. On 32-bit systems, a large exponent also causes the block pointer
allocation size computation (ceil + 1) * 4 to overflow to zero, leading
to a heap buffer overflow write after malloc(0).

Fix: reject any pz_log2_bs outside the range [15, 17] by disabling
zisofs for the entry (file->pz = 0), which prevents the zisofs
decompression path from executing.

Found by fuzzing with ASAN/UBSAN.
2026-03-07 22:14:23 +02:00
Tim Kientzle e480b80eb4 Merge pull request #2896 from kientzle/kientzle-fix-omitted-uu
Add UU file from #2864 to Makefile.am
2026-03-07 10:53:05 -08:00
Tim Kientzle 9fddc89ac7 Add UU file from #2864 to Makefile.am 2026-03-07 10:46:43 -08:00
Tim Kientzle a549c5eb8b Merge pull request #2889 from OwenSanzas/fix/linkify-fuzzer-double-free
Fix double-free in libarchive_linkify_fuzzer
2026-03-07 10:29:36 -08:00
Tim Kientzle 219639c764 Merge pull request #2864 from vdsilva/patch
7zip: Fix SEGV in check_7zip_header_in_sfx via ELF offset validation
2026-03-07 10:15:44 -08:00
Tim Kientzle 6fa79fb56e Merge pull request #2892 from antekone/feature/8192-filters-memleak/1
RAR5 reader: fix potential memory leak
2026-03-07 10:09:26 -08:00
Tim Kientzle 5a1f39d8f3 Merge pull request #2893 from antekone/feature/github/1963/init-twice/1
RAR5 reader: fix SIGSEGV when archive_read_support_format_rar5 is called twice
2026-03-07 10:08:49 -08:00
Tim Kientzle 639412f636 Merge pull request #2895 from antekone/feature/github-1980/memleak-in-cab/1
CAB reader: fix memory leak on repeated calls to archive_read_support_format_cab
2026-03-07 10:07:49 -08:00
Grzegorz Antoniak e19ef42daf CAB reader: fix memory leak on repeated calls to archive_read_support_format_cab
`archive_read_support_format_cab` allocates a fresh context structure on
each call before registering the CAB format with libarchive. On the
second call, however, the registration step reports the format is
already registered, so the function frees the newly allocated context
structure — it is not needed, since the one from the first call is
already in use.

The context structure contains a `ws` field of type `archive_wstring`.
During initialization, `archive_wstring_ensure` is called on that field,
which performs its own heap allocation.

The cleanup path described above frees the context structure without
also releasing the memory owned by the `ws` field, causing a leak.

Fixed by calling `archive_wstring_free` on the `ws` field before freeing
the context structure.

Fixes #1980.
2026-03-07 11:40:06 +01:00
Tim Kientzle ebf23148a8 Merge pull request #2888 from seb128/archive-read-valgrind
archive_read: optimize string copy, avoid redundant strlen
2026-03-06 17:33:15 -08:00
Grzegorz Antoniak 35877523fc RAR5 reader: fix SIGSEGV when archive_read_support_format_rar5 is called twice
When the same archive_read object registers rar5 format more than once,
__archive_read_register_format returns ARCHIVE_WARN (duplicate bid).
The error path then called rar5_cleanup(ar), which dereferences
a->format to get the rar5 context — but a->format is NULL until
archive_read_open() is called, causing a SIGSEGV. The newly allocated
rar struct was also leaked.

Fix by introducing rar5_deinit() (the inverse of rar5_init) and using
it in both rar5_cleanup() and the registration error path. On failure,
the locally allocated rar is freed directly without going through
a->format. The function now always returns ARCHIVE_OK, consistent with
all other format handlers.

Fixes #1963.
2026-03-06 19:53:36 +01:00
Grzegorz Antoniak f8fea386f0 RAR5 reader: fix potential memory leak
If a file declares more than 8192 filters at once, without consuming
them, then the filter allocation function leaks memory.

The backing array used for storing filter pointers can hold up to 8192
pointers. After that it won't accept any new entries. The problem was
that the caller code didn't check if the backing array has accepted the
pointer; it silently assumed the pointer was registered, disposing the
only variable that was holding the pointer to allocated memory.

The fix is to fail the creation of a new filter structure if the backing
array is full. This will result in failure to unpack, but having more
than 8192 filters in one file at the same time seems unlikely.

Fixes issue #2891
2026-03-06 19:03:38 +01:00
OwenSanzas 070062a166 Fix double-free in libarchive_linkify_fuzzer
The fuzzer fails to update entries[i] after archive_entry_linkify()
modifies the pointer (caching or swapping entries). This causes the
cleanup loop to free entries that were already freed via spare or
the drain loop, resulting in heap-use-after-free.

Fix: add entries[i] = entry after the linkify call to track ownership.
2026-03-05 19:03:46 +00:00
Sebastien Bacher cf889cdb00 archive_read: optimize string copy, avoid redundant strlen
Calculate the filename length only once during read_file_data
initialization and replace strcpy with memcpy.

As a side effect it also helps silencing valgrind warnings due to strcpy
word-based optimization
https://github.com/libarchive/libarchive/issues/2887
2026-03-05 13:24:30 +01:00
Tim Kientzle 7f34e20817 Merge pull request #2885 from kpatsakis/signature-malloc-null-check
Unchecked malloc result in archive_read_support_filter_program_signature()
2026-03-03 20:38:33 -08:00
Constantinos Patsakis 45ec1a24d9 If malloc() returns NULL (e.g., under memory pressure, container memory limits, or constrained embedded environments), the subsequent memcpy(NULL, ...) produces a SIGSEGV. 2026-03-02 21:40:53 +02:00
Tim Kientzle 0a35627ec8 Merge pull request #2855 from dag-erling/des/mkdir-errno
archive_write_disk_posix: Report correct error
2026-03-02 10:17:48 -08:00
Dag-Erling Smørgrav 8ee661c8e7 Unbreak CMake build 2026-03-02 18:19:07 +01:00
Tim Kientzle 180d602353 Merge pull request #2856 from bradking/pathname-encoding
archive_write: Fix crash on failure to convert WCS/UTF-8 pathname to MBS
2026-03-02 07:20:23 -08:00
Dag-Erling Smørgrav a252c60308 test_main: Run tests as unprivileged user
If run as root (as is the case in CI), switch to an unprivileged user
(default: nobody) before running each test, and switch back after.
This makes it possible to write tests that rely on file permissions.

Note that tests that use the UID or GID must now check the EUID / EGID
instead as they will be different while the test is running.  The only
way to avoid that is to run each test case in a child process, which
would hugely increase the complexity of test_run().
2026-03-02 12:42:05 +01:00
Dag-Erling Smørgrav 0de2f8ee8d test_main: Add assertChown 2026-03-02 12:42:05 +01:00
Dag-Erling Smørgrav d4d61f1694 Add test case for failing to create directory 2026-03-02 09:27:00 +01:00
Dag-Erling Smørgrav 8ae9e937b7 archive_write_disk_posix: Report correct error
When create_dir() fails to create a directory, it immediately checks to
see if the directory already exists, which can happen if it's been given
something like foo/../foo.  Unfortunately, this clobbers errno, which
means that create_dir() always reports ENOENT, regardless of the actual
error.  Fix this by only performing this extra check if errno is EEXIST,
then reset errno to either EEXIST or ENOTDIR depending on the outcome.
2026-03-02 09:27:00 +01:00
Tim Kientzle d31126d0bc Merge pull request #2880 from kientzle/kientzle-lha-oversize-header
Reject LHA archives with ridiculously large headers
2026-03-01 15:27:25 -08:00
Tim Kientzle fc2635f670 Remove unused var 2026-03-01 13:52:57 -08:00
Tim Kientzle 7b7aecec34 Reject LHA archives with ridiculously large headers
The header is a series of blocks, most of which contain
values of just a few bytes (sizes, times, etc).  The only
exceptions are the filename and directory name attributes,
which will be limited by the MSDOS/Windows maximum file length
limit.  So it seems unlikely that this will ever exceed 64k.
(If we find counter-examples, we can easily extend this limit.)
2026-03-01 13:45:50 -08:00
Tim Kientzle d7598c04d3 Merge pull request #2878 from LoboQ1ng/fix-mtree-fd-leak
Fix file descriptor leak in mtree parser cleanup (CWE-775)
2026-03-01 12:46:39 -08:00
Tim Kientzle 21d60cb6af Merge pull request #2879 from kientzle/kientzle-prune-freebsd-ci
Prune FreeBSD CI from 10 variations down to 3
2026-03-01 12:45:55 -08:00
Tim Kientzle 513100d1af Non-snap images are RELEASE, not STABLE 2026-03-01 12:31:48 -08:00
Tim Kientzle 8960ea37a0 Don't use snap image here 2026-03-01 12:30:09 -08:00
Tim Kientzle 116c3d97ef Prune FreeBSD CI from 10 variations down to 3
Previously, we tested many combinations of FreeBSD version, build system, and filesystem.
In practice, that's redundant, and we've started seeing these excessive requests get throttled by Cirrus.
Cutting back to just 3 combinations should suffice and reduce the risk of throttling.
2026-03-01 12:17:05 -08:00
LoboQ1ng dc72e6157e mtree: fix file descriptor leak in cleanup
Close any dangling file descriptor in the mtree cleanup function to prevent FD exhaustion (CWE-775) when a read loop is aborted early.
2026-03-01 19:53:47 +00:00
Tim Kientzle 67830f7b9c Merge pull request #2875 from bradking/7z-elf64
7zip: Fix out-of-bounds access on ELF 64-bit header
2026-02-27 20:15:39 -08:00
Brad King b5fce10e32 7zip: Fix out-of-bounds access on ELF 64-bit header
The ELF specification's `Elf64_Ehdr` type is 64 bytes [1].
`find_elf_data_sec` accesses the last field, `e_shstrndx`.
Make sure we read enough data to populate it.

[1] https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.eheader.html
2026-02-27 16:31:52 -05:00
Tobias Stoeckmann 34e1515456 libarchive: Correctly handle option failures
If an incorrect option value has been passed to a filter, it is possible
that library operations continue without even printing a warning.

This can happen because the special value "ARCHIVE_WARN - 1" is only
checked for filter issues, not format issues. Since this special value
is larger than ARCHIVE_FAILED, such failures are silently discarded.

Fix this by checking for this magic value for formats as well.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2026-02-22 15:20:48 +01:00
Vijay D'SilvaandCodeMender 24cb0b588f 7zip: Fix SEGV in check_7zip_header_in_sfx via ELF offset validation
The crash reported in this issue is caused by a segmentation fault
that happens when a pointer `p` passed to `check_7zip_header_in_sfx`
is dereferenced. That argument `p` is defined as `p = buff + offset` in
`archive_read_format_7zip_bid` with `offset` determined by a call
to `find_elf_data_sec`.

Within `find_elf_data_sec`, a 64-bit ELF section offset is cast
to `ssize_t`. For a sufficiently large offset, such as an unsigned
64-bit value exceeding `SSIZE_MAX`, the `ssize_t` will be negative,
which leads to `p` to point before the start of the buffer.

This patch eliminates the problem by:
1. Reading the ELF section offset into a `uint64_t`.
2. Validating that the offset does not exceed `SSIZE_MAX`.
3. If the offset is invalid, breaking the loop to retain the safe
   default `SFX_MIN_ADDR`.

These checks ensure that `min_addr` is always within the bounds of the buffer.
This PR includes a regression test `test_malformed3` in
`test_read_format_7zip_malformed.c` using a crafted reproducer file.

CodeMender verified with AddressSanitizer that the crash is resolved and the
test suite passes.

Co-authored-by: CodeMender <codemender-patching@google.com>
Fixes: https://issues.oss-fuzz.com/issues/470963352
2026-02-12 04:46:19 +00:00
Tim Kientzle a255a84250 Merge pull request #2858 from FooIbar/nettle-4.x
Fix incompatibility with Nettle 4.x
2026-02-10 20:00:27 -08:00
Tim Kientzle f75b6b6e2c Merge pull request #2860 from xTibor/fix-iso-year
bsdunzip: Fix ISO week year and Gregorian year confusion
2026-02-10 19:43:31 -08:00
Tim Kientzle a4d325b2ef Merge pull request #2859 from zhangjy1014/fix-issue-2744
Fix NULL pointer dereference in archive_acl_from_text_w()
2026-02-09 07:20:41 -08:00
Nagy Tibor 1a7ce43864 bsdunzip: Fix ISO week year and Gregorian year confusion 2026-02-09 06:39:22 +01:00
zhangjy1014 396b9a9735 Add test for malformed "default" ACL prefix (issue #2744)
Verify that archive_entry_acl_from_text() and
archive_entry_acl_from_text_w() return ARCHIVE_WARN instead of
crashing when given a bare "d" or "default" string with no
subsequent tag field.

Without the accompanying fix in archive_acl.c this test triggers
a NULL-pointer dereference (SEGV) in archive_acl_from_text_w().
2026-02-09 11:20:18 +08:00
zhangjy1014 7a6549a6bf Fix NULL pointer dereference in archive_acl_from_text_w()
When parsing a short "default" ACL prefix (e.g. L"d") with no
subsequent tag field, field[n] is left as {NULL, NULL} and the
code dereferences it unconditionally in the switch statement,
causing a SEGV.

Add a zero-length check after computing the field length so that
malformed entries are skipped with ARCHIVE_WARN, matching the
documented contract. Also move the st pointer computation after
the guard to avoid dereferencing a NULL start pointer.

Fixes libarchive/libarchive#2744
2026-02-08 17:18:43 +08:00
FooIbar 6a3d059507 Fix incompatibility with Nettle 4.x 2026-02-06 22:26:19 +08:00
Brad King d4cf95cdac archive_write: Fix crash on failure to convert WCS/UTF-8 pathname to MBS
If an entry pathname is set only by WCS or UTF-8, it may not have any
MBS representation in the archive's hdrcharset.  Do not crash or create
an archive with an empty pathname.  Furthermore, the entry pathname may
not have any MBS representation in the current locale.  Do not report a
`(null)` pathname in the error message.
2026-02-05 20:40:23 -05:00
Brad King 84bda647d2 archive_string_append_from_wcs: Fix silently lossy conversions on Windows
On Windows, since commit ae54394104 (Implement a string conversion
interface..., 2011-05-09, v3.0.0a~398), `archive_string_append_from_wcs`
no longer returns an error on use of replacement characters in non-C
locales.  Restore the error to avoid silent use of replacement
characters, and for consistency across platforms.
2026-02-05 19:26:43 -05:00
Brad King 3aabd7ad8d archive_string_conversion_charset_name: Fix calls for current locale
Some code paths may call `archive_string_conversion_charset_name(sconv)`
with `sconv == NULL` when converting to/from the current locale.
2026-02-05 19:26:43 -05:00
Brad King 00690bbf99 archive_mstring_get_mbs_l: Restore error on failure to convert from WCS/UTF-8
Prior to commit c30f279475 (Complete support for UTF8 encoding
conversion, 2020-05-31, v3.5.0~32^2), `archive_mstring_get_mbs_l` returned
an error on failure to convert WCS to MBS.  Restore the error so callers
can distinguish conversion failure from having no string in any form.

On Windows, `archive_mstring_get_mbs_l` from WCS with `sconv != NULL`
internally calls `archive_string_append_from_wcs_in_codepage` more than
once, with both `sconv != NULL` and `sconv == NULL`.  Due to another bug
in the `sconv == NULL` case, we cannot enable all test combinations yet.
2026-02-05 19:26:43 -05:00
Brad King eacdc8d99c archive_string_append_from_wcs: add test case for conversion failure 2026-02-05 18:53:28 -05:00
Martin Matuška 8d1c9b95f1 Merge pull request #2838 from DHowett/revert-2826-waitpid
Revert "Wait for the process instead of busy wait loop"
2026-01-07 23:38:30 +01:00
Dustin L. Howett dea03d6e00 Revert "Wait for the process instead of busy wait loop" 2026-01-07 13:42:41 -08:00
Martin Matuška 3cd503b75a Merge pull request #2781 from AZero13/ints
Remove unneeded int cast
2026-01-05 10:35:59 +01:00
Martin Matuška 86851e3092 Merge pull request #2826 from AZero13/waitpid
Wait for the process instead of busy wait loop
2026-01-05 10:33:33 +01:00
Martin Matuška 02eba33825 Merge pull request #2836 from ngie-eign/add-freebsd-15-cirrus-ci
Expand the test matrix to include 15.x images/ZFS
2026-01-05 10:32:49 +01:00
Enji Cooper 0bb2058bd5 Expand the test matrix to include 15.x images/ZFS
This change adds support for the following test scenarios:

- 15.0-RELEASE - ZFS
- 15.0-STABLE - UFS
- 15.0-STABLE - ZFS

This additional testing aims to catch issues with 15.x, as well as
ensure libarchive use doesn't regress when run on ZFS-based hosts.

Signed-off-by: Enji Cooper <yaneurabeya@gmail.com>
2026-01-04 17:55:34 -08:00
Tim Kientzle e663efb430 Merge pull request #2835 from jmcarp/build-illumos
Skip unsupported linker options on illumos.
2025-12-31 15:31:55 -08:00
Josh Carp 3ff73fdfce Skip unsupported linker options on illumos.
Building on illumos currently fails with:

```
ld: fatal: unrecognized option '--gc-sections'
```

This happens because `--gc-sections` isn't supported on illumos `ld`.
This patch updates CMakeLists.txt to skip unsupported linker options on
illumos. The flags used on other operating systems are optimizations
that don't affect correctness, so this change is safe.
2025-12-31 22:37:01 +00:00
Tim Kientzle e91171c9a0 Merge pull request #2825 from AZero13/patch-2
Error check ret before calling copy_seek_stat
2025-12-27 10:52:17 -08:00
Tim Kientzle 7f27446a51 Merge pull request #2824 from AZero13/qosflags
Remove bitmask typo in dwSecurityQosFlags
2025-12-27 10:48:03 -08:00
Tim Kientzle 090fbc3655 Merge pull request #2827 from AZero13/free
Simplify file free
2025-12-27 10:31:27 -08:00
Tim Kientzle 8c2241a7e4 Merge pull request #2829 from AZero13/leak-shar
archive_write_shar_header: free shar->last_dir before replacement
2025-12-27 10:30:22 -08:00
Tim Kientzle d54b2241b9 Merge pull request #2830 from AZero13/return
return early if archive_write_set_format_shar fails
2025-12-27 10:28:27 -08:00
Tim Kientzle 782cdd88b6 Merge pull request #2831 from AZero13/check-copy-length
Use copy_length as upper-bound, not strlen(p)
2025-12-27 10:27:12 -08:00
Tim Kientzle d1b87af584 Merge pull request #2834 from AZero13/patch-5
Use #warning, not #warn
2025-12-27 10:21:44 -08:00
AZero13 9a089dc44a archive_write_shar_header: free shar->last_dir before replacement 2025-12-26 18:05:03 -05:00
AZero13 a55b8e8aec Use #warning, not #warn
#warn is a GNU extension
2025-12-26 15:28:12 -05:00
AZero13 76558692a4 Use copy_length as upper-bound, not strlen(p) 2025-12-26 15:09:10 -05:00
AZero13 4a32d9ff7f return early if archive_write_set_format_shar fails 2025-12-26 15:05:46 -05:00
AZero13 998c0b4080 Simplify file free
free is fine if NULL
2025-12-26 14:45:42 -05:00
AZero13 030a93817c Wait for the process instead of busy wait loop 2025-12-26 13:54:21 -05:00
AZero13 9298dc503a Error check ret before calling copy_seek_stat 2025-12-26 13:29:14 -05:00
AZero13 e54c735586 Remove bitmask typo in dwSecurityQosFlags
We seemed to have been isolating the wrong flags.
2025-12-26 13:19:56 -05:00
Martin Matuška b2d68e2f1a Merge pull request #2813 from AZero13/memcpy
We copy from p, not p + module_len
2025-12-26 10:22:13 +01:00
Martin Matuška 1cd0b9179c Merge pull request #2796 from vcoxvco/fix_unninit
libarchive/archive_util.c: Uninitialized variable
2025-12-25 10:16:46 +01:00
Martin Matuška 095609e89b Merge pull request #2816 from AZero13/strdup
Error check strdup for path name
2025-12-25 10:14:23 +01:00
Martin Matuška 5c84afd664 Merge pull request #2814 from AZero13/gname
uname_override checks gname_override when it should check uname_override
2025-12-25 10:04:44 +01:00
Martin Matuška f366e98107 Merge pull request #2789 from libarchive/dependabot/github_actions/all-actions-50b857948b
CI: Bump the all-actions group across 1 directory with 3 updates
2025-12-25 10:03:34 +01:00
Martin Matuška c4597a73f3 Merge pull request #2815 from AZero13/=
Use >=, not =>
2025-12-25 10:00:35 +01:00
dependabot[bot] 79fac84eb2 CI: Bump the all-actions group across 1 directory with 3 updates
Bumps the all-actions group with 3 updates in the / directory: [actions/checkout](https://github.com/actions/checkout), [actions/upload-artifact](https://github.com/actions/upload-artifact) and [github/codeql-action](https://github.com/github/codeql-action).


Updates `actions/checkout` from 5.0.0 to 5.0.1
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/08c6903cd8c0fde910a37f88322edcfb5dd907a8...93cb6efe18208431cddfb8368fd83d5badbf9bfd)

Updates `actions/upload-artifact` from 4.6.2 to 5.0.0
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/ea165f8d65b6e75b540449e92b4886f43607fa02...330a01c490aca151604b8cf639adc76d48f6c5d4)

Updates `github/codeql-action` from 3.30.6 to 4.31.3
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/64d10c13136e1c5bce3e5fbde8d4906eeaafc885...014f16e7ab1402f30e7c3329d33797e7948572db)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 5.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-actions
- dependency-name: actions/upload-artifact
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: all-actions
- dependency-name: github/codeql-action
  dependency-version: 4.31.3
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: all-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-25 08:53:17 +00:00
Martin Matuška 8042630d4f Merge pull request #2819 from GabrielBarrantes/work/typos
Improve wording
2025-12-25 09:48:17 +01:00
Martin Matuška 214ee3edc7 Merge pull request #2820 from skypher/oss-fuzz-expansion
Expand OSS-Fuzz integration: 1 → 25 fuzz targets
2025-12-25 09:47:17 +01:00
Leslie P. Polzer eb6f992ba1 Refactor all fuzzers to use shared fuzz_helpers.h
Complete the refactoring of all 25 fuzzers:
- Remove duplicate Buffer struct definitions from 15 format fuzzers
- Remove duplicate DataConsumer class from 7 API fuzzers
- Update consume_bytes() calls to match new signature
- All fuzzers now use shared helpers from fuzz_helpers.h

This eliminates ~1000 lines of duplicated code.
2025-12-22 04:53:06 +00:00
Leslie P. Polzer 544b07541b Refactor fuzzers: add shared header, remove system() call
- Add fuzz_helpers.h with shared Buffer, reader_callback, DataConsumer
- Replace system("rm -rf") with nftw-based remove_directory_tree()
- Refactor entry, tar, write_disk fuzzers to use shared helpers
- Reduces code duplication and improves maintainability
2025-12-22 04:26:57 +00:00
Leslie P. Polzer 5e88593708 Expand OSS-Fuzz integration: 1 → 25 fuzz targets
Add comprehensive fuzzing coverage for libarchive:

Format-specific fuzzers (13):
- tar, zip, 7zip, rar, rar5, xar, cab, lha, iso9660, cpio, warc, mtree, ar

Security-critical fuzzers (4):
- encryption: encrypted archive handling
- write_disk: extraction path traversal
- read_disk: filesystem traversal, symlinks
- entry: ACL functions (previously 0% coverage)

API fuzzers (7):
- write: archive creation
- linkify: hardlink detection (complexity 775, was 0%)
- match: inclusion/exclusion patterns
- string: encoding conversions (UTF-8, wide chars)
- seek: seekable archive operations
- roundtrip: write-then-read consistency
- filter: compression/decompression

Supporting files:
- 14 dictionaries with format-specific magic bytes
- 9 options files for complex fuzzers
- Updated build script with seed corpora generation

Targets previously uncovered functions:
- archive_entry_linkify (complexity 775)
- ACL functions (complexity 705-713)
- xar_read_header (was 10.11% coverage)

Expected coverage improvement: 74% → 85-95%
2025-12-22 04:08:26 +00:00
Gabriel Barrantes 8f3fcf9ecd Improve wording 2025-12-21 17:30:42 -06:00
Tim Kientzle 6e77f521fa Merge pull request #2812 from AZero13/w
Fix p == null copy paste error
2025-12-18 07:52:10 -08:00
AZero13 50a67c9223 Error check strdup for path name 2025-12-16 21:50:06 -05:00
AZero13 b39f91e5da Use >=, not => 2025-12-16 21:48:45 -05:00
AZero13 55fbf225c8 uname_override checks gname_override when it should check uname_override 2025-12-16 21:44:31 -05:00
AZero13 e75e5892fd We copy from p, not p + module_len 2025-12-16 21:41:05 -05:00
AZero13 784b778f3b Fix p == null copy paste error 2025-12-16 21:37:16 -05:00
Tim Kientzle b51e59bcfb Merge pull request #2807 from KlaraSystems/des/list-tests
Add option to list tests
2025-12-12 17:19:37 -08:00
Martin Matuška a7f3b56af6 Merge pull request #2809 from mmatuska/fix/2787
tar: fix off-bounds read resulting from #2787 (3150539ed)
2025-12-12 12:04:09 +01:00
Martin Matuska cfb02de558 tar: fix off-bounds read resulting from #2787 (3150539ed) 2025-12-09 22:40:42 +01:00
Dag-Erling Smørgrav 8295366f94 test_main: Add option to list tests
The test runner already lists available tests if it fails to parse the
command line, but add a -l option to explicitly do this without also
printing an error message and a summary of options.
2025-12-06 14:45:40 +01:00
Tim Kientzle 8c86c46d1b Merge pull request #2805 from fredldotme/android-recovery
libarchive & contrib: Build as static binary for the Android recovery
2025-12-04 04:17:34 -08:00
Alfred Neumayer 752df6abb7 libarchive & contrib: Build as static binary for the Android recovery
Adds a 'bsdtar-recovery' Android build target for use in Android recoveries
as a static binary, and fixes some build failures on the get-go.

Tested on halium-7.1, halium-9.0 & halium-13.0.

Change-Id: I9b656e7016d4bf21517e2edb18f2a7733edc6982
2025-12-04 06:34:21 +01:00
Martin Matuška 728b43c0c1 Merge pull request #2800 from mmatuska/fix/freebsdci
CI: use gmake in Cirrus FreeBSD build
2025-12-01 13:31:22 +01:00
Martin Matuska 0a594ab77d CI: use gmake in Cirrus FreeBSD build 2025-11-28 22:31:25 +01:00
Martin Matuška a819cc2829 Merge pull request #2797 from mmatuska/fix/treefuncs
Partially revert "Merge pull request #2679 from AZero13/error"
2025-11-28 00:57:09 +01:00
Tim Kientzle 1b9b42720f Merge pull request #2799 from AZero13/idk
Prevent unneeded truncation
2025-11-26 21:08:01 -08:00
AZero13 827905c93f Prevent unneeded truncation
There is no reason we need to cast when every data type involved is size_t
2025-11-26 15:35:54 -05:00
Martin Matuska aac59c1bd5 Partially revert "Merge pull request #2679 from AZero13/error"
This reverts commit d8aaf88c9f, reversing
changes made to ee49ac8106.

tree_reopen() and tree_dup() return NULL only of they
are unable to allocate memory. Otherwise libarchive enters
ARCHIVE_FATAL if trying to walk an enterable but unreadable
directory.

__archive_ensure_cloexec_flag() operates only on fd >= 0
so there is no need to skip it

I have reimplemented the check around fdopendir()

Reported by:	Christian Weisgerber from OpenBSD
2025-11-24 14:16:53 +01:00
vcoxvco f49372e945 libarchive/archive_util.c:__archive_issetugid: Fix uninitialized variable rgid 2025-11-23 19:27:42 +01:00
Tim Kientzle 8ef2084104 Merge pull request #2791 from KlaraSystems/des/383-fixes
Fix issues encountered while importing 3.8.3 downstream
2025-11-20 22:24:38 -08:00
Tim Kientzle e17f169356 Merge pull request #2792 from KlaraSystems/des/generate-list
Generate test lists reliably and deterministically
2025-11-20 22:22:32 -08:00
Tim Kientzle 47809f10bf Merge pull request #2793 from bgilbert/rar
Add missing rar5 test case to dist
2025-11-20 22:19:23 -08:00
Tim Kientzle 81bc00a549 Merge pull request #2787 from ljdarj/aar
Fix bsdtar zero-length pattern issue.
2025-11-20 21:40:17 -08:00
ARJANEN Loïc Jean David 3150539edb Fix bsdtar zero-length pattern issue.
Uses the sed-like way (and Java-like, and .Net-like, and Javascript-like…) to fix this issue of advancing the string to be processed by one if the match is zero-length.

Fixes libarchive/libarchive#2725 and solves libarchive/libarchive#2438.
2025-11-21 00:44:38 +01:00
Benjamin Gilbert 8f7d334646 Add missing rar5 test case to dist
Fixes: aafb078b7c ("Update 'archive_mstring_update_utf8' to attempt UTF8->WCS conversion on Windows if MBS conversion fails (#1978)")
2025-11-19 00:12:36 -08:00
Dag-Erling Smørgrav 12522911fa Fix low-hanging type issues 2025-11-19 01:18:18 +01:00
Dag-Erling Smørgrav 1890755ab2 Fix lseek argument order 2025-11-19 01:16:29 +01:00
Dag-Erling Smørgrav 35aac8a925 Fix the condition for using LIBXML_DOTTED_VERSION 2025-11-19 01:15:48 +01:00
Dag-Erling Smørgrav fdec8c2f24 Improve test list generation
Update the lists of tests reliably and deterministically when the test sources change.
2025-11-19 01:12:50 +01:00
Dag-Erling Smørgrav 2df76f52c2 Clean up the top-level Makefile
Most of this is just moving headers out from *_SOURCES.
2025-11-19 01:05:41 +01:00
Martin Matuška ce7b3f1c15 Merge pull request #2771 from mostynb/lz4_with_leading_skippable_frames
Support both lz4 and zstd data with leading skippable frames
2025-11-17 20:30:16 +01:00
Martin Matuška dbacda991c Merge pull request #2751 from KlaraSystems/des/zip_magic_numbers
Avoid magic numbers in zip support code
2025-11-17 20:27:46 +01:00
Martin Matuška 2caee6a37e Merge pull request #2752 from KlaraSystems/des/safe-writes-umask
Set umask before testing safe writes
2025-11-17 20:26:35 +01:00
Martin Matuška d5bd2dfafe Merge pull request #2755 from mmatuska/fix/cirrusci
CI: update FreeBSD 14 build environment
2025-11-17 20:24:53 +01:00
AZero13 d1f36bd6ab Replace SetFilePointerEx_perso with NT kernel's SetFilePointerEx
We do not support Windows XP anymore, we can go back to the NT kernel version instead of maintaining our own
2025-11-17 12:39:43 -05:00
Tim Kientzle e1c3061b12 Merge pull request #2783 from YoshiRulz/docs-fix-typo
Fix typo in archive_entry_stat(3) man page
2025-11-16 16:18:03 -08:00
Tim Kientzle c2333a511d Merge pull request #2738 from cmcgee1024/add_clang_module_map
Add a clang module map for libarchive
2025-11-16 16:17:54 -08:00
YoshiRulz d8fba4df3a Fix typo in archive_entry_stat(3) man page 2025-11-13 12:46:23 +10:00
Chris McGee f75b5ddab0 Provide a detailed description of the libarchive module map file 2025-11-12 08:42:03 -05:00
AZero13 02a76f2dc9 Remove unneeded int cast 2025-11-11 11:47:26 -05:00
Tim Kientzle c5cc510145 Merge pull request #2778 from AZero13/result-0
Set *result to 0 when the tar flush fails.
2025-11-06 20:17:19 -08:00
Tim Kientzle ab09af7304 Merge pull request #2654 from AZero13/swapping-2
s is a signed int, so make it signed int
2025-11-06 20:15:08 -08:00
Tim Kientzle e929454ec8 Merge pull request #2779 from AZero13/descriptor
file_open should close if fstat fails
2025-11-06 20:13:10 -08:00
AZero13 3aa9c22ddf file_open should close if fstat fails 2025-11-06 11:14:45 -05:00
AZero13 daf5abf802 Add error handling 2025-11-06 10:46:27 -05:00
Rose f18a754d02 s is a signed int, so make it signed int 2025-11-06 10:44:16 -05:00
AZero13 3396ba84d7 Set *result to 0 when the tar flush fails.
We should not uninitialize 0 when an error happens. Because t is then checked.
2025-11-06 10:02:41 -05:00
Tim Kientzle 26c769ecdc Merge pull request #2775 from AZero13/off-by-one
[tar] Bounds check newdir_len
2025-11-04 19:30:01 -08:00
AZero13 45a873e998 Bounds check newdir_len
Honestly, this is of little consequence; if old_len is too big the program will crash anyway. However, an error exists just in case.
2025-11-04 19:02:08 -05:00
Tim Kientzle fa5f70627c Merge pull request #2769 from kientzle/kientzle-issue2765
Fix a buffer overrun when reading truncated 7zip headers
2025-11-02 14:17:48 -08:00
Tim Kientzle c45a07854d Merge pull request #2772 from moubctez/forget_name_max
Remove name_max leftover
2025-11-02 09:08:31 -08:00
Adam Ciarciński f80b1ae294 Remove name_max leftover 2025-11-02 09:49:02 +01:00
Mostyn Bramley-Moore 1435c4b20c Skip over LZ4/zstd skippable frames when detecting data format
Since LZ4 and zstd share the same format for skippable frames, we need
to skip over these frames when trying to detect the format of compressed
data. Let's read up to something like 64kb of data when performing this
scanning.

Note that the LZ4 specification advises against starting with a skippable
frame, but doesn't forbid it:
> For the purpose of facilitating identification, it is discouraged to
> start a flow of concatenated frames with a skippable frame. If there
> is a need to start such a flow with some user data encapsulated into
> a skippable frame, it's recommended to start with a zero-byte LZ4
> frame followed by a skippable frame. This will make it easier for
> file type identifiers.

Resolves #2692.
2025-11-01 22:43:38 +01:00
Mostyn Bramley-Moore 989a303793 Test that we can read lz4 data with leading skippable frames
This is expected to fail until a followup commit, because lz4 and zstd
skippable frames are the same format and we don't skip over those when
performing format detection (yet).

Relates to #2692.
2025-11-01 22:23:21 +01:00
Tim Kientzle f02961f402 Correct the new test expectations 2025-10-31 22:37:33 -07:00
Tim Kientzle dc6c0c5f35 Fix a buffer overrun when reading truncated 7zip headers
This adjusts the request size for reading data from a 7zip SFX header
to ensure we get enough bytes to cover the following checks.

Resolves #2765
2025-10-31 22:31:45 -07:00
Tim Kientzle ce614c6524 Merge pull request #2768 from Commandoss/master
Fix for an out-of-bounds buffer overrun when using p[H_LEVEL_OFFSET]
2025-10-31 22:07:19 -07:00
Tim Kientzle 8855146220 Merge pull request #2767 from KlaraSystems/des/posix_spawn
Replace system() with posix_spawn() if available
2025-10-31 07:27:15 -07:00
Tim Kientzle edbada88c0 Merge pull request #2766 from mostynb/fix_mac_signed_unsigned_comparison
Fix signed-unsigned comparison in add_trivial_nfs4_acl
2025-10-31 07:23:44 -07:00
Илья 212426e751 heap-use-after-free(read) at src/libarchive/archive_read_support_format_lha.c:692:6 2025-10-31 15:23:55 +03:00
Mostyn Bramley-Moore 83c30ee813 Fix signed-unsigned comparison in add_trivial_nfs4_acl
Resolves #2760
2025-10-30 11:29:55 +01:00
Tim Kientzle d2e861769c Merge pull request #2753 from KlaraSystems/des/temp-files
Create temporary files in the target directory
2025-10-28 17:13:18 -07:00
Martin Matuska 89cbfe1028 CI: update FreeBSD 14 build environment 2025-10-15 23:41:46 +02:00
Dag-Erling Smørgrav 1c08abc60d Create temporary files in the target directory
Whenever we need to create a temporary file while writing to disk on a
POSIX system, try to create it in the same directory as the final file
instead of the current working directory.  The target directory can
reasonably be expected to be writable (and if it isn't, creating the
file will fail anyway), but the current working directory may not be.

While here, consistently use __archive_mkstemp(), and increase the
template from six to eight random characters.

Fixes:		2e73ea3a7d ("Fix max path-length metadata writing (#2243)")
Fixes:		e12c955dca ("Unify temporary directory handling")
2025-10-15 09:41:06 +02:00
Dag-Erling Smørgrav 8fff509f1a Replace system() with posix_spawn() if available
Some platforms disallow system() due to its perceived insecurity.
Luckily, we can be just as insecure using the more palatable
posix_spawn() instead!
2025-10-14 19:17:53 +02:00
Dag-Erling Smørgrav d0f69b355d Add archive_string_dirname()
This function performs the equivalent of POSIX dirname(3) on a
struct archive_string.
2025-10-14 02:08:44 +02:00
Dag-Erling Smørgrav 7976476c9f Set umask before testing safe writes
Fixes:		27588eba50 ("Fix replacing a regular file with a dir for ARCHIVE_EXTRACT_SAFE_WRITES")
2025-10-13 21:49:29 +02:00
Dag-Erling Smørgrav 51b3e14257 zip: Increase max size of Mac metadata
Raise the maximum size of Mac metadata from 4 MiB to 10 MiB, as that is
the value used by Apple themselves in the version of libarchive included
in Darwin.
2025-10-13 21:39:13 +02:00
Dag-Erling Smørgrav 33ac104169 zip: Avoid magic numbers
Provide preprocessor macros for two recurring magic numbers in the zip
support code: the length of the local file header (30 bytes) and the
maximum allowable size for Mac metadata (4 MiB).
2025-10-13 21:39:00 +02:00
Tim Kientzle de73860cda Merge pull request #2737 from kientzle/kientzle-volume-header-overflow
Fix an infinite loop when parsing `V` headers
2025-10-13 10:58:26 -07:00
Tim Kientzle d207d816d0 Merge pull request #2749 from KlaraSystems/des/tempdir
Unify temporary directory handling
2025-10-13 10:57:18 -07:00
Dag-Erling Smørgrav 12cdd35f31 Drop unused variable.
Fixes:		a335429c5e ("Drop support for readdir_r()")
2025-10-13 16:58:44 +02:00
Dag-Erling Smørgrav e12c955dca Unify temporary directory handling
In archive_util.c, we have a private function named get_tempdir() which
is used by __archive_mktemp() to get the temporary directory if the
caller did not pass one.

In archive_read_disk_entry_from_file.c, we use the same logic with a
slight twist (don't trust the environment if setugid) to create a
temporary file for metadata.

Merge the two by renaming get_tempdir() to __archive_get_tempdir() and
unstaticizing it (with a prototype in archive_private.h).
2025-10-13 16:58:44 +02:00
Martin Matuška 46fe318edd Merge pull request #2722 from dependabot
CI: Bump the all-actions group across 1 directory with 3 updates
2025-10-11 22:12:11 +02:00
Tim Kientzle 582799ee57 Merge pull request #2746 from pbrisbin/patch-1
Fix invalid quoting in archive_entry_paths.3
2025-10-07 06:09:01 -07:00
dependabot[bot] b12d1c14d1 CI: Bump the all-actions group across 1 directory with 3 updates
Bumps the all-actions group with 3 updates in the / directory: [actions/checkout](https://github.com/actions/checkout), [github/codeql-action](https://github.com/github/codeql-action) and [ossf/scorecard-action](https://github.com/ossf/scorecard-action).


Updates `actions/checkout` from 4.2.2 to 5.0.0
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/11bd71901bbe5b1630ceea73d27597364c9af683...08c6903cd8c0fde910a37f88322edcfb5dd907a8)

Updates `github/codeql-action` from 3.28.18 to 3.29.8
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/ff0a06e83cb2de871e5a09832bc6a81e7276941f...76621b61decf072c1cee8dd1ce2d2a82d33c17ed)

Updates `ossf/scorecard-action` from 2.4.1 to 2.4.2
- [Release notes](https://github.com/ossf/scorecard-action/releases)
- [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md)
- [Commits](https://github.com/ossf/scorecard-action/compare/f49aabe0b5af0936a0987cfb85d86b75731b0186...05b42c624433fc40578a4040d5cf5e36ddca8cde)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: all-actions
- dependency-name: github/codeql-action
  dependency-version: 3.29.8
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-actions
- dependency-name: ossf/scorecard-action
  dependency-version: 2.4.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: all-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-06 16:07:23 +00:00
Pat Brisbin 6d8e1a883c Fix invalid quoting in archive_entry_paths.3 2025-10-06 08:23:26 -04:00
Tim Kientzle eb54a4d869 Add test case 2025-10-04 10:03:08 -07:00
Tim Kientzle fda50c79ba Merge pull request #2740 from dunhor/gnutar_longpath_unicode
Check WCS pathname in header_gnutar before overwriting
2025-10-03 20:43:21 -07:00
Tim Kientzle 372e709c1a Merge pull request #2729 from KlaraSystems/des/leak-on-fatal
Don't leak memory on fatal error
2025-09-27 10:25:03 -07:00
Tim Kientzle 4ecf62fbd7 Merge pull request #2742 from bradking/parse-date-2038
parse_date: handle dates in 2038 and beyond if time_t is big enough
2025-09-26 19:52:20 -07:00
Tim Kientzle c34ff01c02 Merge pull request #2741 from e-kwsm/extra-semi
fix: remove extra ';' outside of functions
2025-09-26 19:50:52 -07:00
Brad King 2d987e725f parse_date: handle dates in 2038 and beyond if time_t is big enough 2025-09-26 17:48:56 -04:00
Eisuke Kawashima 7fdf32b6b2 fix: remove extra ';' outside of functions 2025-09-26 19:41:30 +09:00
Duncan Horn 98731ad500 Check WCS pathname in header_gnutar 2025-09-25 16:03:18 -07:00
Tim Kientzle be31ad37f3 Merge pull request #2739 from DHowett/remove-wincrypt
windows: remove support for WinCrypt
2025-09-24 06:21:23 -07:00
Dustin L. Howett 619e22cae7 WIP: remove WinCrypt support
I am debating whether to remove the checks for bcrypt as well (it is
supported on all versions of Windows currently targeted.)

fixes https://github.com/libarchive/libarchive/issues/2595
2025-09-22 16:05:17 -05:00
Chris McGee 52bf0d7de0 Add a clang module map for libarchive
When compiling libarchive using clang in module mode a special
module.modulemap file describes the structure of the header files
so that they can be imported modularly. Having this file makes
it easier for modular uses of the library out of the box so that
clients don't need to write their own, potentially making errors
in doing so.

Add a module.modulemap in the public header file location so that
clang and related tools can find it easily.
2025-09-22 11:11:02 -04:00
Tim Kientzle 36a530973a Fix an infinite loop when parsing V headers
Our tar header parsing tracks a count of bytes that need to be
consumed from the input.  After each header, we skip this many bytes,
discard them, and reset the count to zero.  The `V` header parsing
added the size of the `V` entry body to this count, but failed to
check whether that size was negative.  A negative size (from
overflowing the 64-bit signed number parsing) would decrement this
count, potentially leading us to consume zero bytes and leading to an
infinite loop parsing the same header over and over.

There are two fixes here:
* Check for a negative size for the `V` body
* Check for errors when skipping the bytes that
  need to be consumed

Thanks to Zhang Tianyi from Wuhan University for finding
and reporting this issue.
2025-09-16 08:25:57 -07:00
Tim Kientzle 39dc43b3e0 Merge pull request #2734 from kientzle/kientzle-ignore-too-long-gzip-filename
Ignore over-long gzip filename
2025-09-13 19:34:03 -07:00
Tim Kientzle 638464b477 Fix the reference to the archive object 2025-09-13 13:07:33 -07:00
Martin Matuška ab5cb61f49 Merge pull request #2735 from kientzle/kientzle-err.h-conflict
Rename err.h to avoid conflict with system header
2025-09-13 22:01:52 +02:00
Martin Matuška 38debf6be1 Merge pull request #2731 from mmatuska/fix/macosci
CI: add workaround for cmake installed from local/pinned tab on GH/MacOS
2025-09-13 21:36:29 +02:00
Martin Matuška e1dea559c7 Merge pull request #2732 from mmatuska/fix/safe-dir-over-reg-win
win: add complementary safe writes fix for Windows to 27588eba5 (#2477)
2025-09-13 21:36:13 +02:00
Tim Kientzle 96f76577d3 Rename err.h to avoid conflict with system header
Depending on header search path ordering, we can easily
confuse libarchive_fe/err.h with the system header.
Rename ours to lafe_err.h to avoid the confusion.
Rename libarchive_fe/err.c to match.
2025-09-13 12:30:03 -07:00
Tim Kientzle e5c2eb783b Only set the filename-present bit if we actually write the filename 2025-09-13 11:17:38 -07:00
Tim Kientzle a3787a34a8 Fix some nearby formatting 2025-09-12 09:03:01 -07:00
Tim Kientzle a2933fbefd Ignore overlong gzip original_filename
We reuse the compression buffer to format the gzip header,
but didn't check for an overlong gzip original_filename.
This adds that check.  If the original_filename is
over 32k (or bigger than the buffer in case someone shrinks
the buffer someday), we WARN and ignore the filename.
2025-09-12 09:01:13 -07:00
Martin Matuska 123d92bc3a win: add complementary safe writes fix for Windows to 27588eba5 (#2477) 2025-09-10 10:59:40 +02:00
Martin Matuska ff3a0c37aa CI: add workaround for cmake installed from local/pinned tab on GH/MacOS 2025-09-10 10:50:46 +02:00
Martin Matuška 589659ed7f Merge pull request #2670 from benoit-pierre/pr/fix_zip_writing_with_zstd_compression_method
zip: fix writing with ZSTD compression
2025-09-10 10:41:33 +02:00
Martin Matuška 52db141ece Merge pull request #2477 from jrtc27/safe-dir-over-reg
Fix replacing a regular file with a dir for ARCHIVE_EXTRACT_SAFE_WRITES
2025-09-10 10:40:44 +02:00
Martin Matuška 3b1100f9a9 Merge pull request #2686 from stoeckmann/lseek_win_regression
Fix Windows off_t handling
2025-09-10 10:24:34 +02:00
Martin Matuška 6bd863f612 Merge pull request #2710 from meecash/CVE-2025-25724-check_strftime_result
Fix CVE-2025-25724 by checking the result of the strftime
2025-09-10 10:22:58 +02:00
Dag-Erling Smørgrav 4768f38535 archive_write: Set archive state to fatal if format or filters fail
In archive_write_header(), if the format method or a filter flush method
fails, we set the archive state to fatal, but we did not do this in
archive_write_data() or archive_write_finish_entry().  There is no good
reason for this discrepancy.  Not setting the archive state to fatal
means a subsequent archive_write_free() will invoke archive_write_close()
which may retry the operation and cause archive_write_free() to return
an unexpected ARCHIVE_FATAL.
2025-09-08 23:33:32 +02:00
Dag-Erling Smørgrav 3a072e0bb0 write_add_filter_bzip2: End compression in the freer
If a fatal error occurs, the closer will not be called, so neither will
BZ2_bzCompressEnd(), and we will leak memory.  Fix this by calling it a
second time from the freer.  This is harmless in the non-error case as
it will see that the compression state has already been cleared and
immediately return BZ_PARAM_ERROR, which we simply ignore.
2025-09-08 23:33:32 +02:00
Dag-Erling Smørgrav 06191cd287 archive_write_client: Free state in freer, not in closer
The closer will not be called if a fatal error occurs, so the current
arrangement results in a memory leak.  The downside is that the freer
may be called even if we were not fully constructed, so it needs to
perform additional checks.  On the other hand, knowing that the freer
always gets called and will free the client state simplifies error
handling in the opener.
2025-09-08 23:15:57 +02:00
Tim Kientzle 53135ca48e Merge pull request #2717 from peakschris/cb_windows
bsdtar: Allow @filename to have CRLF endings
2025-08-22 08:13:40 -07:00
Chris Brown 37ab51c2d3 address review comment 2025-08-22 04:00:44 -04:00
Tim Kientzle ab4d21e4cb Merge pull request #2707 from fdegros/close_range_support
Avoid leaking file descriptors into subprocesses
2025-08-20 11:18:45 -07:00
François Degros f12d80442c Use sysconf(_SC_OPEN_MAX) on systems without close_range or closefrom
Close all the file descriptors in the range [3 ..
sysconf(_SC_OPEN_MAX)-1] before executing a filter program to avoid
leaking file descriptors into subprocesses.

Bug: https://github.com/libarchive/libarchive/issues/2520
2025-08-20 15:47:18 +10:00
Tim Kientzle 892f331450 Merge pull request #2696 from al3xtjames/mkstemp
Fix mkstemp path in setup_mac_metadata
2025-08-16 10:27:11 -06:00
Martin Matuška bf50fe0538 Merge pull request #2723 from KlaraSystems/des/couldnt-visit
archive_read_disk_posix: Don't pass -1 to a function expecting errno
2025-08-14 23:22:30 +02:00
Martin Matuška 2db13f7422 Merge pull request #2716 from antekone/bug/GH-2714/infinite-loop/1
RAR5 reader: early fail when file declares data for a dir entry
2025-08-14 23:20:55 +02:00
Martin Matuška 93f9e93d73 Merge pull request #2713 from antekone/bug/GH-2711/crash-when-rr/1
RAR5 reader: fix multiple issues in extra field parsing function
2025-08-14 23:20:01 +02:00
Martin Matuška 12ffcef28c Merge pull request #2700 from mostynb/avoid_libxml2_deprecation_warnings
xar: avoid libxml2 deprecation warnings
2025-08-14 23:17:39 +02:00
Dag-Erling Smørgrav 02ebfb5a48 archive_read_disk_posix: Don't pass -1 to a function expecting errno
This fixes an unhelpful "Couldn't visit directory: Unknown error: -1" message.

Fixes:		3311bb52cb ("Bring the code supporting directory traversals from bsdtar/tree.[ch] into archive_read_disk.c and modify it. Introduce new APIs archive_read_disk_open and archive_read_disk_descend.")
2025-08-14 15:29:34 +02:00
Chris Brown e099b418e3 revert test verbosity change 2025-08-09 16:43:55 -04:00
Chris Brown 6a008e524e revert ci fix which didn't help 2025-08-09 16:13:26 -04:00
Chris Brown 835fe1133f disable tests on windows; they don't work 2025-08-09 15:51:48 -04:00
Chris Brown 466a2b5c7b fix test 2025-08-09 15:50:45 -04:00
Chris Brown 640c9feced fix mingw windows build issue 2025-08-09 15:32:55 -04:00
Chris Brown 9e7af6f21c increase test verbosity 2025-08-09 15:28:34 -04:00
Chris Brown 652a0c107b enable tests on windows 2025-08-09 15:08:49 -04:00
Chris Brown 980b541632 update autotools 2025-08-08 20:53:33 -04:00
Chris Brown 8b3d3ee99b update test 2025-08-08 20:40:14 -04:00
Chris Brown fb859e6d3f add test 2025-08-08 20:15:35 -04:00
Chris Brown da65b39c06 suggested changes by kientzle 2025-08-08 19:41:51 -04:00
Chris Brown e47c315f51 debug non-printing characters and handle CRLF 2025-08-08 11:56:39 -04:00
Grzegorz Antoniak cb403667d7 RAR5 reader: early fail when file declares data for a dir entry
RAR5 reader had inconsistent sanity checks for directory entries that
declare data. On one hand such declaration was accepted during the
header parsing process, but at the same time this was disallowed during
the data reading process. Disallow logic was returning the
ARCHIVE_FAILED error code that allowed the client to retry, while in
reality, the error was non-retryable.

This commit adds another sanity check during the header parsing logic
that disallows the directory entries to declare any data. This will make
clients fail early when such entry is detected.

Also, the commit changes the ARCHIVE_FAILED error code to ARCHIVE_FATAL
when trying to read data for the directory entry that declares data.
This makes sure that tools like bsdtar won't attempt to retry unpacking
such data.

Fixes issue #2714.
2025-08-04 19:52:53 +02:00
Grzegorz Antoniak 0ff100c8d3 RAR5 reader: fix multiple issues in extra field parsing function
This commit fixes multiple issues found in the function that parses
extra fields found in the "file"/"service" blocks.

1. In case the file declares just one extra field, which is an
   unsupported field, the function returns ARCHIVE_FATAL.

   The commit fixes this so this case is allowed, and the unsupported
   extra field is skipped. The commit also introduces a test for this
   case.

2. Current parsing method of extra fields can report parsing errors in
   case the file is malformed. The problem is that next iteration of
   parsing, which is meant to process the next extra field (if any),
   overwrites the result of the previous iteration, even if previous
   iteration has reported parsing error. A successful parse can be
   returned in this case, leading to undefined behavior.

   This commit changes the behavior to fail the parsing function early.
   Also a test file is introduced for this case.

3. In case the file declares only the EX_CRYPT extra field, current
   function simply returns ARCHIVE_FATAL, preventing the caller from
   setting the proper error string. This results in libarchive returning
   an ARCHIVE_FATAL without any error messages set. The PR #2096 (commit
   adee36b00) was specifically created to provide error strings in case
   EX_CRYPT attribute was encountered, but current behavior contradicts
   this case.

   The commit changes the behavior so that ARCHIVE_OK is returned by the
   extra field parsing function in only EX_CRYPT is encountered, so that
   the caller header reading function can properly return ARCHIVE_FATAL
   to the caller, at the same time setting a proper error string. A test
   file is also provided for this case.

This PR should fix issue #2711.
2025-08-03 15:28:58 +02:00
Tim Kientzle 3bf1035e67 Merge pull request #2712 from KlaraSystems/des/readdir_r
Drop support for readdir_r()
2025-08-02 16:33:01 -07:00
Dag-Erling Smørgrav a335429c5e Drop support for readdir_r()
There has never been a good reason to prefer it over readdir(), and it
has now been marked obsolete in POSIX-1.2024.
2025-08-01 17:07:17 +02:00
François Degros 23ee781520 Use POSIX_SPAWN_CLOEXEC_DEFAULT when possible
Use posix_spawn() with POSIX_SPAWN_CLOEXEC_DEFAULT on systems that
define this constant, in order to avoid leaking file descriptors into
subprocesses.

Bug: https://github.com/libarchive/libarchive/issues/2520
2025-07-31 15:56:31 +10:00
François Degros 64bcf69ef8 Use closefrom() or close_range() when possible
To avoid leaking file descriptors into subprocesses.

Fixes: https://github.com/libarchive/libarchive/issues/2520
2025-07-31 15:03:22 +10:00
Marcin Mikula ecce46744f Fix CVE-2025-25724 by checking the result of the strftime
to avoid use of undefined content of buf, in case when custom
locale makes the result string longer than buf length.

Signed-off-by: Marcin Mikula <marcin@helix.pl>
2025-07-30 10:33:51 +02:00
Tim Kientzle 6062470cbc Merge pull request #2704 from kientzle/kientzle-harden-append-acl
Guard against invalid type arguments
2025-07-26 12:24:43 -07:00
Tim Kientzle aa1fc90ae5 Guard against invalid type arguments
Some experiments showed strange things happen if you
provide an invalid type value when appending a new ACL entry.
Guard against that, and while we're here be a little more
paranoid elsewhere against bad types in case there is another
way to get them in.
2025-07-26 11:10:24 -07:00
Benoit Pierre d1418af239 zip: fix writing with ZSTD compression
When testing the feature with `bsdtar -acf test.zip --options
zip:compression=zstd …` on a tree of ~100MB, the execution would
appear to "hang" while writing a multi-gigabytes ZIP file.
2025-07-21 11:35:27 +02:00
Tim Kientzle cc97338239 Merge pull request #2699 from mostynb/7z_eopm_reference
7z: add liblzma EOPM reference
2025-07-17 19:18:53 -07:00
Mostyn Bramley-Moore ed2ada78a6 7z: add liblzma EOPM reference
This is useful for developers trying to understand the 7z read support code.
2025-07-15 22:13:10 +02:00
Mostyn Bramley-Moore 4dfaf2d359 xar: avoid libxml2 deprecation warnings 2025-07-15 13:18:14 +02:00
Tim Kientzle cb6b9e9a28 Merge pull request #2697 from Kraust/topic/cmake_build_fixes
Allow Compiling Against Static CRT.
2025-07-14 10:05:56 -07:00
Kraust d2d72ac78a Allow Compiling Against Static CRT. 2025-07-13 22:57:25 -04:00
Alex James b57d14f9c9 Fix mkstemp path in setup_mac_metadata
setup_mac_metadata currently concates the template after TMPDIR without
adding a path separator, which causes mkstemp to create a temporary file
next to TMPDIR instead of in TMPDIR. Add a path separator to the
template to ensure that the temporary file is created under TMPDIR.

I hit this while rebuilding libarchive in nixpkgs. Lix recently started
using a dedicated build directory (under /nix/var/nix/builds) instead of
using a directory under /tmp [1]. nixpkgs & Lix support (optional)
on macOS sandboxing. The default sandbox profile allows builds to access
paths under the build directory and any path under /tmp. Because the
build directory is no longer under /tmp, some of libarchive's tests
started to fail as they accessed paths next to (but not under) the build
directory:

cpio/test/test_basic.c:65: Contents don't match
   Description: Expected: 2 blocks
, options=
  file="pack.err"
0000_62_73_64_63_70_69_6f_3a_20_43_6f_75_6c_64_20_6e_bsdcpio: Could n
0010_6f_74_20_6f_70_65_6e_20_65_78_74_65_6e_64_65_64_ot open extended
0020_20_61_74_74_72_69_62_75_74_65_20_66_69_6c_65_0a_ attribute file.

Sandbox: bsdcpio(11215) deny(1) file-write-create /nix/var/nix/builds/nix-build-libarchive-3.8.0.drv-7tar.md.5EUrQu

[1]: https://lix.systems/blog/2025-06-24-lix-cves/
2025-07-12 15:44:55 -05:00
Tim Kientzle 267042ebc7 Merge pull request #2694 from stoeckmann/cleanups
Perform various cleanups
2025-07-11 21:06:20 -07:00
Tobias Stoeckmann a3d261a29a rar: Fix typos in comments
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-07-09 23:13:51 +02:00
Tobias Stoeckmann 3c646995db archive_read: Fix formatting
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-07-09 23:13:51 +02:00
Tobias Stoeckmann 7b59a6b693 SECURITY.md: Turn singular into plural
Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-07-09 23:13:51 +02:00
Tobias Stoeckmann e559754d6d mtree: Fix grammar and typos
Fix grammar and typos in comments and error messages.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-07-09 23:13:48 +02:00
Tobias Stoeckmann 82e247fe7c archive_string: Use correct data types
If it's already known that we use variables for calculations with
size_t, use size_t for them directly instead of int, even if values
fit.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-07-09 23:06:09 +02:00
Tobias Stoeckmann eff524fa4e Fix formatting in archive_string_sprintf.c
Do not mix tabs and spaces if not needed.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-07-09 22:58:38 +02:00
Tobias Stoeckmann 84e8f3c98e tar: Remove unneeded casts
The variable size is already of type size_t. No need to cast it again
to size_t.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-07-09 22:57:40 +02:00
Tobias Stoeckmann 4035fca93a Define ARCHIVE_CRYPTOR_USE_Apple_CommonCrypto to 1
All other define statements set a value. Set one here as well for
maximum compatibility.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-07-09 22:55:12 +02:00
Andrew Gunnerson 86e65103d8 Force UTF-8 as the default charset on Android
bionic libc does not support nl_langinfo and the locale defaults to
C.UTF-8.

Signed-off-by: Andrew Gunnerson <accounts+github@chiller3.com>
2025-07-04 13:07:20 -04:00
Tobias Stoeckmann 3997a5f28a Do not truncate seek requests
If a seek cannot be fulfilled, fail directly with EOVERFLOW to match
regular lseek behavior.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-29 21:35:44 +02:00
Tobias Stoeckmann d01dc496d3 Fix Windows off_t handling
The off_t datatype in Windows is 32 bit, which leads to issues when
handling files larger than 2 GB.

Add a wrapper around fstat/stat calls to return a struct which has a
properly sized st_size variable. On systems with an off_t representing
the actual system limits, use the native system calls.

This also fixes mtree's checkfs option with large files on Windows.

Fixes https://github.com/libarchive/libarchive/issues/2685
Fixes 89b8c35ff4

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-29 21:35:39 +02:00
Tim Kientzle d06700a098 Merge pull request #2691 from kientzle/kientzle-issue2681
Add missing test file
2025-06-29 12:03:51 -07:00
Tim Kientzle 2db02ae6ae Add missing test file 2025-06-28 20:45:14 -07:00
Tim Kientzle 595fb29e4c Merge pull request #2664 from fedegiova/fix_leak_for_cb_error
Fix a memory leak if write callback error early
2025-06-28 19:15:32 -07:00
Tim Kientzle 609d8122f1 Merge pull request #2658 from stoeckmann/skip_tests
Skip tests if respective support is missing
2025-06-28 19:14:17 -07:00
Tim Kientzle 31cff981e4 Merge pull request #2673 from 004helix/master
archive_cryptor_private.h: check message digest functions are enabled for windows
2025-06-28 19:10:27 -07:00
Tim Kientzle d8aaf88c9f Merge pull request #2679 from AZero13/error
Handle possible errors from system calls
2025-06-28 19:09:12 -07:00
Tim Kientzle ee49ac8106 Merge pull request #2687 from hemant-jadhav-emerson/master
Supress restrict keyword for msc_ver older than 1927
2025-06-28 19:04:30 -07:00
Tim Kientzle 9fe18ba0a6 Merge pull request #2689 from ElvishJerricco/linux-fs-flags
clear_nochange_fflags: Use linux FS flags
2025-06-28 14:23:02 -07:00
Tim Kientzle cd020d1ccb Merge pull request #2684 from DHowett/dev/duhowett/shim_open
win32: shim wopen, and make both open/wopen use _s "secure" variant
2025-06-28 14:22:26 -07:00
Tim Kientzle a474bab7e3 Merge pull request #2688 from stoeckmann/entry_off32
Ignore sizes which do not fit into off_t
2025-06-28 14:11:17 -07:00
Will Fancher 489d0b8e2f clear_nochange_fflags: Use linux FS flags 2025-06-27 19:24:34 -04:00
Tobias Stoeckmann 1e4b84ed30 Ignore sizes which do not fit into off_t
It is possible to handle entries and files with sizes which do not fit
into off_t of the current system (Windows always has 32 bit off_t and
32 bit systems without large file support also have 32 bit off_t).

Set sizes to 0 in such cases. The fstat system call would return -1 and
set errno to EOVERFLOW, but that's not how archive_entry_set_size acts.
It would simply ignore negative values and set the size to 0.

Actual callers of archive_entry_stat from foreign projects seem to not
even check for NULL return values, so let's try to handle such cases as
nice as possible.

Affects mtree's checkfs option as well (Windows only, 32 bit systems
would simply fail in fstat/stat).

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-27 17:06:14 +02:00
Dustin Howett 50d44b4202 win32: shim wopen, and make both open/wopen use _s "secure" variant
The new `__la_wopen` wrapper is a copy of `__la_open` that
expects--rather than converts--a wcs parameter.

The `sopen` variants are offered as "more secure" variants of `open` and
`wopen`; I cannot vouch for their security, but some build systems are
strict about the use of "banned insecure APIs".

I've confirmed that `_wsopen_s` and `_open_s` are present in the Windows
Vista SDK.

I did not confirm that they are available in the Windows XP Platform
SDK, in part because in e61afbd463 (2016!) Tim says:

> I'd like to completely remove support for WinXP and earlier.
2025-06-26 10:56:33 -07:00
Rose b1b3709cae Handle possible errors from system calls
dup, open, etc, can fail and we should not assume they do not.
2025-06-20 17:35:54 -04:00
Tim Kientzle ffde04f272 Merge pull request #2672 from AZero13/ferror
Fix error checking in writing files
2025-06-20 14:33:45 -07:00
Rose fd4ecc0146 Fix error checking in writing files
For write, 0 may not mean an error at all. We need to instead check for the length not being the same.

With fwrite, because 0 could mean an error, but not always. We must check that we wrote the entire file!

Note that unlike write, fwrite's description according to POSIX does not mention returning a negative type at all. Nor does it say you can retry unlike write.

Finally, with write, we need to check less than 0, not 0, as 0 is a valid return and does not mean an error.
2025-06-20 13:55:57 -04:00
Tim Kientzle a218a52dbb Merge pull request #2678 from mostynb/zstd_filter_checksum
Enable Zstandard's checksum feature in the zstd write filter
2025-06-20 09:32:51 -07:00
Mostyn Bramley-Moore 0de62cbda8 Enable Zstandard's checksum feature in the zstd write filter
Note that this is not enabled when writing .zip or .7z archive formats,
because they already use their own checksums.

Implements #2675.
2025-06-20 14:42:40 +02:00
Tim Kientzle e4978e2edd Merge pull request #2677 from AZero13/fwrite
Change error message from "fwrite function failed" to "write function failed"
2025-06-19 16:12:26 -07:00
Rose 40a89c7379 Change error message from "fwrite function failed" to "write function failed"
We are checking the return value from write, not fwrite, so this message is wrong.
2025-06-19 14:44:43 -04:00
Tim Kientzle 6a252c84a2 Merge pull request #2676 from danyeaw/fix-pkgconf-path
Fix .pc location when CMAKE_INSTALL_LIBDIR not set
2025-06-19 08:20:43 -07:00
Dan Yeaw 4984c652db Fix .pc location when CMAKE_INSTALL_LIBDIR not set 2025-06-18 21:27:04 -04:00
Hemant 664a20b6c7 Error related to restrict keyword supressed for older vs compiler 2025-06-18 14:05:23 -05:00
Hemant b7066d4a6b Error related to restrict keyword supressed for older vs compiler 2025-06-18 13:51:00 -05:00
Martin Matuška 6effe2ec6b Merge pull request #2659 from stoeckmann/chld
Improve filter process handling
2025-06-12 10:59:43 +02:00
Martin Matuška 251f7e839c Merge pull request #2669 from benoit-pierre/pr/minor_test_related_tweaks
minor test related tweaks
2025-06-12 10:57:17 +02:00
Martin Matuška 47bdf82489 Merge pull request #2663 from stoeckmann/filename_errpath
open_filename: Free memory on error paths
2025-06-12 10:56:32 +02:00
Martin Matuška c3be70e071 Merge pull request #2665 from stoeckmann/read_data_sparse
archive_read_data: Handle sparse holes at end of file correctly
2025-06-12 10:54:08 +02:00
Martin Matuška 9bdc5b82f7 Merge pull request #2668 from stoeckmann/7z_oob
7zip: Fix out of boundary access
2025-06-12 10:51:45 +02:00
Raman Shyshniou 475423a154 archive_cryptor_private.h: check message digest functions are enabled for windows 2025-06-12 00:22:47 +00:00
Benoit Pierre 864c904442 test_utils: factorize canProg implementations 2025-06-08 00:05:58 +02:00
Benoit Pierre dcf5475661 test_utils: fix canRunCommand implementation
Do not unconditionally cache the result of the first call (and
reused it for subsequent calls). Thankfully, the function is
only called once.
2025-06-08 00:05:34 +02:00
Tobias Stoeckmann 90c1e32a0d open_filename: Free memory on error paths
If opening a filename fails, make sure that allocated memory which is
not inserted into any remaining structure is freed.

Fixes https://github.com/libarchive/libarchive/issues/1949

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-05 22:17:56 +02:00
Tobias Stoeckmann c0691458a0 7zip: Fix out ouf boundary read in ELF detection
Make sure that the string table size is not smaller than 6 (and also
not larger than SIZE_MAX for better 32 bit support).

Such small values would lead to a large loop limit which either leads to
a crash or wrong detection of a ".data" string in possibly uninitialized
memory.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-05 21:38:43 +02:00
Tobias Stoeckmann 75ef803092 7zip: Increase minimum ELF header length
The 64 bit format requires at least 63 bytes, so increase this limit.
Such small binaries most likely don't contain 7zip data anyway.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-05 21:36:23 +02:00
Tim Kientzle 0931c12b7e Merge pull request #2662 from stoeckmann/set_format_strcpy
archive_read_set_format: Remove strcpy calls
2025-06-04 05:58:32 -07:00
Tobias Stoeckmann b1839a20e5 archive_read: Handle sparse holes at end of file
If a sparse hole is located at the end of an entry, then the tar
parser returns ARCHIVE_EOF while updating the offset where 0 bytes of
data will follow.

If archive_read_data encounters such an ARCHIVE_EOF return value, it
has to recheck if the offsets (data offset and output offset) still
match. If they do not match, it has to keep filling 0 bytes.

This changes assumes that it's okay to call archive_read_data_block
again after an EOF. As far as I understood the parsers so far, this
should be okay, since it's always ARCHIVE_EOF afterwards.

Fixes https://github.com/libarchive/libarchive/issues/1194

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-03 22:01:15 +02:00
Tobias Stoeckmann f3949062ed rar: Do not forcefully set offset to unpacked size
If an entry reaches its end of file, the offset is not necessarily
the same as unp_size. This is especially true for links which have
a "0 size body" even though the unpacked size is not 0.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-03 21:59:05 +02:00
Tobias Stoeckmann cdb45d71b2 warc: Ignore separator when reaching end of entry
When _warc_read encounters end of entry, it adds 4 bytes to the last
offset for \r\n\r\n separator, which is never written. Ignore these
bytes since they are not part of the returned entry.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-03 21:57:42 +02:00
Tobias Stoeckmann fa85c7eaae xar: End with entry offset, not archive offset
If xar_read_data has no further data, set offset to end of entry,
not to total size of parsed archive so far.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-03 21:57:05 +02:00
Federico Giovanardi aa69d34311 Fix a memory leak if write callback error early 2025-06-03 18:24:35 +02:00
Tobias Stoeckmann 5a60d8cda4 archive_read_set_format: Remove strcpy calls
The string constants can be used directly for comparison, which makes
this code robust against future changes which could lead to names being
longer than str could hold on stack.

Also removes around 100 bytes from compiled library (with gcc 15).

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-03 17:43:27 +02:00
Tobias Stoeckmann ac66e0bc42 Skip zlib tests if support is missing
If zlib is not supported, do not run tests to avoid false positives.

Also adjust tests to support latest gzip versions (1.10+) which store
less information for improved reproducibility. The gzip binary is
used as a fallback if zlib is not available.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-03 17:27:48 +02:00
Tobias Stoeckmann f2c3c790ff Skip lzma test if support is missing
If lzma is not supported, do not run tests to avoid false positives.

Fixes https://github.com/libarchive/libarchive/issues/2647

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-03 17:27:48 +02:00
Tobias Stoeckmann b7e1c617cb Skip KOI8 conversion test if support is missing
If a unix system has no iconv support, the best effort function will
be unable to convert KOI8 to UTF-8. Skip the test if such support is
missing.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-03 17:27:48 +02:00
Tobias Stoeckmann c40a3887ab unzip: Pass test if encryption support is missing
If no encryption support exists, the -P option will always fail.
"Skip" the test by making sure that there really is no encryption
support according to libarchive functions.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-03 17:27:48 +02:00
Tobias Stoeckmann 9836e7e2fe zip: Better detect no encryption support
Some functions might return -1 in case of library error. Use an
own return value if a stub function was used for better error
messages.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-03 17:27:48 +02:00
Tim Kientzle a8f93f2480 Merge pull request #2660 from kevans91/ke/fix-fortify
libarchive/test: fix build when memcpy() is a macro
2025-06-03 06:02:09 -07:00
Kyle Evans b76c4042ae libarchive/test: fix build when memcpy() is a macro
After importing the latest libarchive into FreeBSD, Shawn Webb @
HardenedBSD noted that the test build is broken when FORTIFY_SOURCE=2
while building the base system.  Braced initializer lists are a special
case that need some extra fun parentheses when we're dealing with the
preprocessor.

While it's not a particularly common setup, the extra parentheses don't
really hurt readability all that much so it's worth fixing for wider
compatibility.

Fixes: libarchive/libarchive#2657
2025-06-02 21:46:28 -05:00
Tobias Stoeckmann 36bac92cd2 tools: Enforce default handling of SIGCHLD
Ignoring SIGCHLD gets passed to child processes. Doing that has
influence on waitpid, namely that zombie processes won't be
created. This means that a status can never be read.

We can't enforce this in library, but libarchive's tools can be
protected against this by enforcing default handling.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-02 23:29:49 +02:00
Tobias Stoeckmann 2764062e65 Unify reader and writer filter process handling
Use pid_t since waitpid returns a pid_t. Also check for a negative
return value in writer as well to avoid reading the possibly
unitialized status value.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-02 23:28:26 +02:00
Tobias Stoeckmann 13700e1fb8 windows: close child process handle only once
Calling CloseHandle multiple times for the same handle can lead to
exceptions while debugging according to documentation.

Mimic the waitpid handling for success cases to behave more like the
Unix version which would "reap the zombie".

Doing this for an unsuccessful call is off, but the loop is never
entered again, so I guess it's okay and worth it to reduce the amount
of Windows specific definitions in source files.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-02 23:23:05 +02:00
Tobias Stoeckmann d7d1d19bb6 windows: Preserve GetExitCodeProcess error
If the waitpid version for Windows fails, preserve the error code and
avoid overwriting it with a possible CloseHandle error.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-06-02 23:21:26 +02:00
Tim Kientzle 0f9a06d6ab Merge pull request #2655 from mmatuska/fix/setclocale
test_utils/test_main.c: satisfy -Wstrict-prototypes
2025-06-01 16:04:49 -07:00
Martin Matuska 1311a438a3 test_utils/test_main.c: satisfy -Wstrict-prototypes 2025-06-01 23:35:05 +02:00
Martin Matuška 70978468e9 Merge pull request #2627 from heirecka/do-not-hard-code-pkg-config
Use PKG_CONFIG instead of hard-coded pkg-config
2025-05-31 21:40:04 +02:00
Martin Matuška c7b7bd7c0e Merge pull request #2643 from stoeckmann/tar_pax_sparse
tar: Handle extra bytes after sparse entries
2025-05-31 21:31:14 +02:00
Tim Kientzle 8d074302ac Merge pull request #2652 from stoeckmann/wstring_ensure
Check archive_wstring_ensure return value
2025-05-31 07:16:07 -07:00
Tobias Stoeckmann e1ca935c00 Always check archive_wstring_ensure return value
Memory allocation might fail, so check if it was successful.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-31 11:37:02 +02:00
Tobias Stoeckmann e1c0f9a660 write disk windows: Release memory on error paths
Free wsp in case of out of memory condition.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-31 11:31:50 +02:00
Tobias Stoeckmann 20b4a4cb7c iso9660: Check another archive_string_ensure result
Missed one unchecked archive_string_ensure in the previous commit.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-31 09:46:17 +02:00
Tim Kientzle 101230094c Merge pull request #2651 from stoeckmann/string_ensure_check
Always check archive_string_ensure return value
2025-05-30 19:50:25 -07:00
Tim Kientzle 8540cb7cfb Merge pull request #2648 from stoeckmann/test_en_us
test_utils: Enforce C locale for all tests
2025-05-30 19:35:44 -07:00
Tim Kientzle e2eda9e68b Merge pull request #2650 from stoeckmann/string_sort
archive_utility_string_sort: Use qsort directly
2025-05-30 19:33:34 -07:00
Tobias Stoeckmann 9ac39a0168 Always check archive_string_ensure return value
Memory allocation might fail, so check if it was successful.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-30 23:42:40 +02:00
Tobias Stoeckmann 0a320b6a37 Remove archive_utility_string_sort with 4.0.0
The archive_utility_string_sort function won't be part of the 4.0.0 API
anymore. No users were found and such a task should be done outside of
the library.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-30 17:41:26 +02:00
Tobias Stoeckmann f90d036057 archive_utility_string_sort: Use qsort directly
The utility function "archive_utility_string_sort" is a custom qsort
implementation. Since qsort is specified in C11 and POSIX.1-2008
which libarchive is based on, use system's qsort directly.

The function is not used directly in libarchive, so this is a good
way to save around 500 bytes in resulting library without breaking
compatibility for any user of this function (none found).

Also allows more than UINT_MAX entries which previously were limited
by data type and (way earlier) due to recursion.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-30 17:41:12 +02:00
Tobias Stoeckmann 65d0393f24 test_list_item: Do not modify LC_TIME
Test cases already get a C locale, which is sufficient for this test.
IF LC_TIME was not previously set, the used en_US.UTF-8 would stay
as an environment variable, possibly affecting other test cases.
Since en_US.UTF-8 is not guaranteed to be available, C is a better
choice.

Fixes https://github.com/libarchive/libarchive/issues/2560

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-30 17:33:19 +02:00
Tobias Stoeckmann e70e24a738 test_utils: Reset all locale related entries
Reset current locale settings through setlocale and also all
environment variables which might affect test cases which
spawn children through systemf which in turn would call setlocale
on their own, e.g. bsdtar.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-30 17:32:02 +02:00
Tim Kientzle 9b07a143ee Merge pull request #2634 from stoeckmann/tar_neg_time
tar: Support negative time values with pax
2025-05-29 17:31:28 -07:00
Tim Kientzle cd5c44c5d0 Merge pull request #2649 from stoeckmann/compress_recursion
compress: Prevent call stack overflow
2025-05-29 16:37:44 -07:00
Tobias Stoeckmann 2ed2db55e8 compress: Prevent call stack overflow
Explicitly use goto to turn a recursive call into an iterative one.
Most compilers do this on their own with default settings, but MSVC
with default settings would create a binary which actually performs
recursive calls.

Fixes call stack overflow in binaries compiled with low optimization.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-29 15:07:02 +02:00
Tim Kientzle 59b09796c3 Merge pull request #2642 from stoeckmann/seek_regress
Fix FILE_skip regression
2025-05-27 20:55:15 -07:00
Tim Kientzle d261f46ae5 Merge pull request #2644 from stoeckmann/tar_neg_size
tar: Always treat negative sizes as error
2025-05-27 20:52:36 -07:00
Tim Kientzle dcdd7338d6 Merge pull request #2645 from stoeckmann/tar_formatter
tar: Fix archive_set_error formatters
2025-05-27 20:43:46 -07:00
Tim Kientzle 702f31a01c Merge pull request #2646 from stoeckmann/sparse32
tar: Handle many sparse comments on 32 bit systems
2025-05-27 20:41:19 -07:00
Tobias Stoeckmann ebca997192 tar: Handle many sparse comments on 32 bit systems
The sparse 1.0 parser skips lines with comments. The amount of skipped
bytes is stored in a ssize_t variable, although common 32 bit systems
allow files larger than 4 GB.

Gracefully handle files with more than 2 GB bytes full of comments to
prevent integer truncations.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-27 21:30:19 +02:00
Tobias Stoeckmann 9d07162b08 tar: Fix archive_set_error formatters
Use correct formatters and casts with newly introduced ll
length modifier.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-27 20:50:53 +02:00
Tobias Stoeckmann 33d3528723 tar: Always treat negative sizes as error
If a pax global header specifies a negative size, it is possible to
reduce variable `unconsumed` by 512 bytes, leading to a re-reading
of the pax global header. Fortunately the loop verifies that only one
global header per entry is allowed, leading to a later ARCHIVE_FATAL.

Avoid any form of negative size handling and fail early.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-27 20:46:51 +02:00
Tobias Stoeckmann 715f7eac02 tar: Handle extra bytes after sparse entries
Skip all entry bytes after sparse entries were encountered. This matches
GNU tar behavior.

I have adjusted (and fixed) the existing test case for this. The test
case test_read_format_gtar_sparse_skip_entry did not work with GNU tar.

In #2558 it was explained that the pax size always overrides the header
size (correct). Since the pax size in the test case was way larger than
the actual entry bytes in archive, GNU tar choke on the test file.

The libarchive parser did not skip any bytes not already read due to
references by sparse entries, so the huge pax size was not detected.

By adjusting the test case to have a leftover byte (only 3 bytes are
referenced through sparse entry now, leaving one extra byte) with a
correct pax size and an invalid header size (after all it is overridden
by pax size), GNU tar works and libarchive gets off its 512 byte
alignment, not being able to read the next entry.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-27 19:57:05 +02:00
Tobias Stoeckmann 51b4c35bb3 Fix FILE_skip regression
The fseek* family of functions return 0 on success, not the new offset.
This is only true for lseek.

Fixes https://github.com/libarchive/libarchive/issues/2641
Fixes dcbf1e0ede

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-27 17:09:12 +02:00
Tim Kientzle 6389d172ed Merge pull request #2640 from robUx4/xml-uuid
[cmake] add uuid library when using xmllite
2025-05-26 09:06:47 -07:00
Steve Lhomme ac96967e36 [cmake] add uuid library when using xmllite
Consecutive to 16fd043f51
IID_ISequentialStream is required by the code.
This GUID is defined in uuid.lib or libuuid.a in mingw-w64. It is required
to link with that library to get the definition of the GUID. Some toolchains
add it by default but not all.
2025-05-26 10:44:49 +02:00
Tim Kientzle 341dd5d1d4 Merge pull request #2637 from stoeckmann/pax_nl
tar: Keep block alignment after pax error
2025-05-25 16:22:59 -07:00
Tim Kientzle 18d456377e Merge pull request #2639 from stoeckmann/sprintf_ll
Add ll length modifier to archive_string_vsprintf
2025-05-25 16:19:38 -07:00
Tobias Stoeckmann bc5f0884e3 Add ll length modifier to archive_string_vsprintf
Some error messages already use the ll length modifier, which results
in raw formatter output, i.e. "%lld" instead of a number.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-25 14:27:46 +02:00
Tobias Stoeckmann 101646e34e tar: Keep block alignment after pax error
If a pax attribute has a 0 length value and no newline, the tar reader
gets out of sync with block alignment.

This happens because the pax parser assumes that variable value_length
(which includes the terminating newline) is at least 1. To get the
real value length, 1 is subtracted. This result is subtracted from
extsize, which in this case would lead to `extsize -= -1`, i.e.
the remaining byte count is increased.

Such an unexpected calculation leads to an off-by-one when skipping
to the next block. In supplied test case, bsdtar complains that the
checksum of the next block is wrong. Since the tar parser was not
properly 512 bytes aligned, this is no surprise.

Gracefully handle such a case like GNU tar does and warn the user that
an invalid attribute has been encountered.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-25 12:03:55 +02:00
Tim Kientzle b6e1f06457 Merge pull request #2636 from zhaofengli/reset-header-state-after-mac-metadata
tar: Reset accumulated header state after reading macOS metadata blob
2025-05-24 17:18:00 -07:00
Zhaofeng Li 0685c77e83 Add test for macOS metadata reading in tar archives
Signed-off-by: Zhaofeng Li <hello@zhaofeng.li>
2025-05-24 16:42:26 -06:00
Zhaofeng Li 5bb36db5e1 tar: Reset accumulated header state after reading macOS metadata blob
AppleDouble extension entries are present as separate files immediately
preceding the corresponding real files. In libarchive, we process the
entire metadata file (headers + data) as if it were a header in the real
file. However, the code forgets to reset the accumulated header state
before parsing the real file's headers. In one code path, this causes
the metadata file's name to be used as the real file's name.

Specifically, this can be triggered with a tar containing two files:

1. A file named `._badname` with pax header containing the `path` attribute
2. A file named `goodname` _with_ a pax header but _without_ the `path` attribute

libarchive will list one file, `._badname` containing the data of `goodname`.

This code is pretty brittle and we really should let the client deal with
it :(

Fixes #2510.

Signed-off-by: Zhaofeng Li <hello@zhaofeng.li>
2025-05-24 14:33:08 -06:00
Tim Kientzle 42c2f84649 Merge pull request #2630 from stoeckmann/wincrypt_casts
Fix archive_wincrypt_version
2025-05-24 10:45:57 -07:00
Tim Kientzle 6dbea2df3b Merge pull request #2633 from stoeckmann/match_cleanup
archive_match: Simplify and clean up code
2025-05-24 10:37:02 -07:00
Tobias Stoeckmann a5d9c9a7cd tar: Support negative time values with pax
Pax extended headers may specify negative time values for files older
than the epoch.

Adjust the code to clear values to 0.0 more often and set ps to
INT64_MIN to have a proper error specifier, because the parser does
not allow anything below -INT64_MAX.

Fixes https://github.com/libarchive/libarchive/issues/2562

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-24 19:28:22 +02:00
Tim Kientzle cdc185e917 Merge pull request #2632 from stoeckmann/cygwin_definition
Prefer __CYGWIN__ over CYGWIN definition
2025-05-24 10:23:28 -07:00
Tobias Stoeckmann 8b978a0368 archive_match: Fix whitespaces, style
Adjust whitespaces to match file layout and add a full stop to
a comment to match others.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-24 12:37:44 +02:00
Tobias Stoeckmann bef52da622 archive_match: Use correct data type for iterator
Iterating over a size_t with unsigned could lead to an endless loop
while adding uid/gid to a list which already counts 4 billion
entries.

I doubt that this can ever happen, given that the routines become
very slow with insertions, but better be safe than sorry.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-24 12:35:32 +02:00
Tobias Stoeckmann 8b763d872c archive_match: Allow arbitrarily long match lists
Turn unmatched_count into a size_t to support as many entries as
possible on the machine.

If more than INT_MAX entries are not matched, truncate the result
of archive_match_path_unmatched_inclusions for external callers.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-24 12:28:08 +02:00
Tobias Stoeckmann 51e66d32c6 archive_match: Remove unneeded count fields
The count fields are merely used to check if a list is empty or not.
A check for first being not NULL is sufficient and is already in
place while iterating over the linked elements (count is not used).

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-24 12:24:49 +02:00
Tobias Stoeckmann 4223b4c548 archive_match: Set red/black tree operations once
The operations for key and node comparison depend on the platform
libarchive is compiled for. Since these values do not change
during runtime, set them only once during initialisation.

Further simplify the code by declaring only one "rb_ops" with
required functions based on platform.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-24 12:10:49 +02:00
Tobias Stoeckmann 612223356e Prefer __CYGWIN__ over CYGWIN definition
The cygwin FAQ states that __CYGWIN__ is defined when building for a
Cygwin environment. Only a few test files check (inconsistently) for
CYGWIN, so adjust them to the recommended __CYGWIN__ definition.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-24 11:37:26 +02:00
Tim Kientzle 0ed4435209 Merge pull request #2631 from stoeckmann/configure_windows
configure.ac: Improve Windows version detection
2025-05-23 19:58:02 -07:00
Tim Kientzle 992734d6cc Merge pull request #2509 from tesap/install-lib-dir
Make installation lib dir depend on CMAKE_INSTALL_LIBDIR variable
2025-05-23 19:57:14 -07:00
Tim Kientzle 627ba5bbbf Merge pull request #2629 from mmatuska/fix/versiontest
tests: accept underscore in arbitrary third-party version strings
2025-05-23 19:39:00 -07:00
Tobias Stoeckmann 2cdf47f332 Set ARCHIVE_CRYPTOR_USE_WINCRYPT for WinCrypt
If WinCrypt is used, actually set ARCHIVE_CRYPTOR_USE_WINCRYPT
for version details output.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-23 19:43:26 +02:00
Tobias Stoeckmann d8ff8dd62c archive_version_details.c: Drop ARCHIVE_DIGEST_*
These definitions are never available and are supposedly a leftover of
a work in progress.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-23 19:43:24 +02:00
Tobias Stoeckmann d6f6fdf979 configure.ac: Improve Windows version detection
Include windows.h for better windows version detection.

Fixes https://github.com/libarchive/libarchive/issues/2628

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-23 19:22:41 +02:00
Tobias Stoeckmann 38ac49553d Fix archive_wincrypt_version compilation
Cast address of "version" to BYTE pointer for CryptGetProvParam.
Fix "major" variable assignment for picky compilers like MSVC.

The "length" variable is an in/out variable. It must be set to the size
of available memory within "version". Right now it is undefined behavior
and 0 would crash during runtime.

Fixes https://github.com/libarchive/libarchive/issues/2628

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
2025-05-23 19:05:21 +02:00
Martin Matuska 9eacf09a86 tests: accept underscore in arbitrary third-party version strings
Fixes #2626
2025-05-23 13:20:25 +02:00
Heiko Becker 0ddaa5f71c Use PKG_CONFIG instead of hard-coded pkg-config 2025-05-21 00:44:50 +02:00
Tim Kientzle 2961b132d0 Merge pull request #2624 from mmatuska/feat/390dev
Libarchive 3.9.0dev
2025-05-20 07:55:26 -07:00
Martin Matuska 182726d16a Libarchive 3.9.0dev 2025-05-20 10:29:10 +02:00
Stepan Tsepa 447201758e Make installation lib dir depend on CMAKE_INSTALL_LIBDIR variable 2025-02-14 11:34:56 +03:00
Jessica Clarke 27588eba50 Fix replacing a regular file with a dir for ARCHIVE_EXTRACT_SAFE_WRITES
The outer if checks !S_ISDIR(a->st.st_mode), so we know that the file
being overwritten is not a directory, and thus we can rename(2) over it
if we want to, but whether we can use a temporary regular file is a
property of the file being extracted. Otherwise, when replacing a
regular file with a directory, we end up in this case and create a
temporary regular file for the new directory, but with the permissions
of the directory (which likely includes x), and rename it over the top
at the end. Depending on where the archive_entry came from, it may have
a non-zero size that also isn't ovewritten with 0 (e.g. if it came from
stat(2)) and so the API user may then try to copy data (thus failing if
read(2) of directories isn't permitted, or writing the raw directory
contents if it is), but if the size is zero as is the case for this tar
test then it will end up not writing any data and "successfully"
overwrite the file with an empty file, not a directory.
2025-01-07 20:59:09 +00:00
646 changed files with 76789 additions and 11177 deletions

No files matched your search

-44
View File
@@ -1,44 +0,0 @@
env:
CIRRUS_CLONE_DEPTH: 1
ARCH: amd64
FreeBSD_task:
matrix:
env:
BS: autotools
env:
BS: cmake
matrix:
freebsd_instance:
image_family: freebsd-14-2
freebsd_instance:
image_family: freebsd-13-5
prepare_script:
- ./build/ci/cirrus_ci/ci.sh prepare
configure_script:
- env CFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib ./build/ci/build.sh -a autogen
- env CFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib ./build/ci/build.sh -a configure
build_script:
- env MAKE_ARGS="-j 2" ./build/ci/build.sh -a build
test_script:
- env SKIP_TEST_RESTORE_ATIME=1 MAKE_ARGS="-j 2" ./build/ci/build.sh -a test
- ./build/ci/cirrus_ci/ci.sh test
install_script:
- env MAKE_ARGS="-j 2" ./build/ci/build.sh -a install
Windows_Cygwin_task:
windows_container:
image: cirrusci/windowsservercore:2019
os_version: 2019
env:
BE: cygwin-gcc
prepare_script:
- build\ci\cirrus_ci\ci.cmd prepare
configure_script:
- build\ci\cirrus_ci\ci.cmd configure
build_script:
- build\ci\cirrus_ci\ci.cmd build
test_script:
- build\ci\cirrus_ci\ci.cmd test
install_script:
- build\ci\cirrus_ci\ci.cmd install
+57 -18
View File
@@ -6,13 +6,34 @@ permissions:
contents: read
jobs:
FreeBSD:
runs-on: ubuntu-latest
strategy:
matrix:
bs: [autotools, cmake]
steps:
- name: Build and test on a FreeBSD 15 firecracker VM
uses: acj/freebsd-firecracker-action@e04896d2dd91f7ec7381e5f363c6fbe83ee445c3 # v0.11.0
with:
run-in-vm: |
chflags -R noschg / && \
fetch -o - https://download.freebsd.org/releases/amd64/15.0-RELEASE/base.txz | bsdtar -x -C / -f - && \
pkg bootstrap -y && \
cd firecracker-freebsd && \
env BS=${{ matrix.bs }} ./build/ci/github_actions/freebsd.sh prepare && \
env BS=${{ matrix.bs }} CFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib ./build/ci/build.sh -a autogen && \
env BS=${{ matrix.bs }} MAKE=gmake CFLAGS=-I/usr/local/include LDFLAGS=-L/usr/local/lib ./build/ci/build.sh -a configure && \
env BS=${{ matrix.bs }} MAKE=gmake MAKE_ARGS="-j 2" ./build/ci/build.sh -a build && \
env BS=${{ matrix.bs }} MAKE=gmake SKIP_TEST_RESTORE_ATIME=1 MAKE_ARGS="-j 2" ./build/ci/build.sh -a test && \
env BS=${{ matrix.bs }} ./build/ci/github_actions/freebsd.sh test && \
env BS=${{ matrix.bs }} MAKE=gmake MAKE_ARGS="-j 2" ./build/ci/build.sh -a install
MacOS:
runs-on: macos-15
strategy:
matrix:
bs: [autotools, cmake]
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Install dependencies
run: ./build/ci/github_actions/install-macos-dependencies.sh
- name: Autogen
@@ -47,7 +68,7 @@ jobs:
run: ./build/ci/build.sh -a artifact
env:
BS: ${{ matrix.bs }}
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: libarchive-macos-${{ matrix.bs }}-${{ github.sha }}
path: libarchive.tar.xz
@@ -59,7 +80,7 @@ jobs:
bs: [autotools, cmake]
crypto: [mbedtls, nettle, openssl]
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Update apt cache
run: sudo apt-get update
- name: Install dependencies
@@ -93,14 +114,14 @@ jobs:
run: ./build/ci/build.sh -a artifact
env:
BS: ${{ matrix.bs }}
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: libarchive-ubuntu-${{ matrix.bs }}-${{ matrix.crypto }}-${{ github.sha }}
path: libarchive.tar.xz
Ubuntu-distcheck:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Update package definitions
run: sudo apt-get update
- name: Install dependencies
@@ -115,7 +136,7 @@ jobs:
SKIP_OPEN_FD_ERR_TEST: 1
- name: Dist-Artifact
run: ./build/ci/build.sh -a dist-artifact
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: libarchive-${{ github.sha }}
path: libarchive-dist.tar
@@ -125,18 +146,36 @@ jobs:
strategy:
fail-fast: false
matrix:
be: [mingw-gcc, msvc]
be: [mingw-gcc, cygwin-gcc, msvc]
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Install mingw
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Install Cygwin
uses: cygwin/cygwin-install-action@3f0a3f9f988f7e96b8c18098ae05eaec175f5b52 # v6
if: ${{ matrix.be=='cygwin-gcc' }}
with:
install-dir: "D:\\cygwin"
packages: |-
make autoconf automake cmake
gcc-core binutils libtool pkg-config
bison zlib-devel libbz2-devel liblzma-devel
liblz4-devel libiconv-devel libxml2-devel
libzstd-devel libssl-devel
- name: Install MinGW (msys2)
uses: msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 # v2.32.0
if: ${{ matrix.be=='mingw-gcc' }}
run: choco install mingw
shell: cmd
- name: Install library dependencies
run: ./build/ci/github_actions/ci.cmd deplibs
shell: cmd
env:
BE: ${{ matrix.be }}
with:
location: "D:\\"
install: |-
mingw-w64-x86_64-gcc
mingw-w64-x86_64-autotools
mingw-w64-x86_64-binutils
mingw-w64-x86_64-pkgconf
mingw-w64-x86_64-cmake
mingw-w64-x86_64-make
mingw-w64-x86_64-zlib
mingw-w64-x86_64-bzip2
mingw-w64-x86_64-xz
mingw-w64-x86_64-zstd
- name: Configure
run: ./build/ci/github_actions/ci.cmd configure
shell: cmd
@@ -163,7 +202,7 @@ jobs:
shell: cmd
env:
BE: ${{ matrix.be }}
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: libarchive-windows-${{ matrix.be }}-${{ github.sha }}
path: libarchive.zip
path: ${{ matrix.be=='cygwin-gcc' && 'libarchive.tar.xz' || 'libarchive.zip' }}
+1 -1
View File
@@ -21,7 +21,7 @@ jobs:
fuzz-seconds: 600
dry-run: false
- name: Upload Crash
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts
+4 -4
View File
@@ -26,18 +26,18 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Initialize CodeQL
uses: github/codeql-action/init@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
uses: github/codeql-action/init@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6
with:
languages: ${{ matrix.language }}
queries: +security-and-quality
- name: Autobuild
uses: github/codeql-action/autobuild@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
uses: github/codeql-action/autobuild@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
uses: github/codeql-action/analyze@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6
with:
category: "/language:${{ matrix.language }}"
+34
View File
@@ -0,0 +1,34 @@
name: Lint
on: [push, pull_request]
permissions:
contents: read
jobs:
Lint:
runs-on: ubuntu-26.04
env:
BS: cmake
CRYPTO: openssl
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Update apt cache
run: sudo apt-get update
- name: Install dependencies
run: sudo apt-get install -y autoconf automake build-essential cmake git libssl-dev nettle-dev libmbedtls-dev libacl1-dev libbz2-dev liblzma-dev liblz4-dev libzstd-dev lzop pkg-config zlib1g-dev libclang-22-dev libclang-cpp22-dev clang-22 ninja-build
- name: Install Lint
run: |-
set -euo pipefail
cmake -S build/la-lint -B /tmp/lint-build -GNinja
cmake --build /tmp/lint-build
cmake --install /tmp/lint-build
- name: Configure
run: ./build/ci/build.sh -a configure
env:
CMAKE_ARGS: -GNinja -DENABLE_CLANG_TIDY=YES -DCLANG_TIDY_PATH=la-lint
- name: Build
run: ./build/ci/build.sh -a build
env:
MAKE: ninja
MAKE_ARGS: --
+4 -4
View File
@@ -29,12 +29,12 @@ jobs:
steps:
- name: "Checkout code"
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1
uses: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc # v2.4.4
with:
results_file: results.sarif
results_format: sarif
@@ -52,7 +52,7 @@ jobs:
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: SARIF file
path: results.sarif
@@ -60,6 +60,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
uses: github/codeql-action/upload-sarif@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6
with:
sarif_file: results.sarif
+10 -3
View File
@@ -9,6 +9,7 @@
*.lo
*.recipe
*.sln
*.slnx
*.tlog
*.cmake
*.vcxproj
@@ -27,6 +28,8 @@ bsdcat
bsdcpio
bsdtar
bsdunzip
build/.ninja_deps
build/.ninja_log
build/autoconf/compile
build/autoconf/config.guess
build/autoconf/config.sub
@@ -39,8 +42,10 @@ build/autoconf/ltsugar.m4
build/autoconf/ltversion.m4
build/autoconf/lt~obsolete.m4
build/autoconf/missing
build/build.ninja
build/build/pkgconfig/libarchive.pc
build/cat/test/list.h
build/compile_commands.json
build/cpio/test/list.h
build/libarchive/test/list.h
build/pkgconfig/libarchive.pc
@@ -59,6 +64,8 @@ libtool
stamp-h1
tar/test/list.h
unzip/test/list.h
CLAUDE.md
GEMINI.md
CMakeCache.txt
CMakeFiles/
DartConfiguration.tcl
@@ -80,9 +87,9 @@ libarchive-*.tar.gz
libarchive-*.zip
Testing/
libarchive/libarchive.a
libarchive/libarchive.so
libarchive/libarchive.so.*
**/libarchive/libarchive.a
**/libarchive/libarchive.so
**/libarchive/libarchive.so.*
.DS_Store
+155 -135
View File
@@ -3,6 +3,9 @@ cmake_minimum_required(VERSION 3.17 FATAL_ERROR)
PROJECT(libarchive C)
#
# Include standard installation directories
include(GNUInstallDirs)
#
SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/build/cmake")
if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${libarchive_BINARY_DIR}/bin)
@@ -136,7 +139,12 @@ IF (CMAKE_C_COMPILER_ID MATCHES "^GNU$" OR
# either of the following two, yet neither is supported as of 3.0.2
# - check_linker_flag - does not exist
# - try_compile - does not support linker flags
IF(NOT CMAKE_SYSTEM_NAME MATCHES "Darwin")
IF(CMAKE_SYSTEM_NAME MATCHES "Darwin")
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-dead_strip")
SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-dead_strip")
ELSEIF(CMAKE_SYSTEM_NAME MATCHES "SunOS")
# SunOS linker doesn't support --gc-sections
ELSE()
# Place the functions and data into separate sections, allowing the linker
# to garbage collect the unused ones.
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffunction-sections -fdata-sections")
@@ -145,10 +153,7 @@ IF (CMAKE_C_COMPILER_ID MATCHES "^GNU$" OR
# Printing the discarded section is "too much", so enable on demand.
#SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -Wl,--print-gc-sections")
#SET(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -Wl,--print-gc-sections")
ELSE()
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-dead_strip")
SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-dead_strip")
ENDIF(NOT CMAKE_SYSTEM_NAME MATCHES "Darwin")
ENDIF()
ENDIF (CMAKE_C_COMPILER_ID MATCHES "^GNU$" OR
CMAKE_C_COMPILER_ID MATCHES "^Clang$" AND NOT MSVC)
IF (CMAKE_C_COMPILER_ID MATCHES "^XL$")
@@ -241,19 +246,19 @@ OPTION(ENABLE_CPIO "Enable cpio building" ON)
OPTION(ENABLE_CPIO_SHARED "Enable dynamic build of cpio" FALSE)
OPTION(ENABLE_CAT "Enable cat building" ON)
OPTION(ENABLE_CAT_SHARED "Enable dynamic build of cat" FALSE)
IF(WIN32 AND NOT CYGWIN)
SET(ENABLE_UNZIP FALSE)
SET(ENABLE_UNZIP_SHARED FALSE)
ELSE()
OPTION(ENABLE_UNZIP "Enable unzip building" ON)
OPTION(ENABLE_UNZIP_SHARED "Enable dynamic build of unzip" FALSE)
ENDIF()
OPTION(ENABLE_UNZIP "Enable unzip building" ON)
OPTION(ENABLE_UNZIP_SHARED "Enable dynamic build of unzip" FALSE)
OPTION(ENABLE_XATTR "Enable extended attribute support" ON)
OPTION(ENABLE_ACL "Enable ACL support" ON)
OPTION(ENABLE_ICONV "Enable iconv support" ON)
OPTION(ENABLE_TEST "Enable unit and regression tests" ON)
OPTION(ENABLE_COVERAGE "Enable code coverage (GCC only, automatically sets ENABLE_TEST to ON)" FALSE)
OPTION(ENABLE_INSTALL "Enable installing of libraries" ON)
OPTION(ENABLE_CLANG_TIDY "Enable custom build-time code health checks" OFF)
IF(WIN32 AND MSVC)
OPTION(MSVC_USE_STATIC_CRT "Use static CRT" OFF)
ENDIF()
SET(POSIX_REGEX_LIB "AUTO" CACHE STRING "Choose what library should provide POSIX regular expression support")
SET(ENABLE_SAFESEH "AUTO" CACHE STRING "Enable use of /SAFESEH linker flag (MSVC only)")
@@ -332,27 +337,69 @@ INCLUDE(CheckTypeSize)
#
# Generate list.h
#
MACRO (GENERATE_LIST_H _listfile _cmlist __list_sources)
MACRO (GENERATE_LIST_H _listfile _cmlist _target __list_sources)
SET(_argv ${ARGV})
# Remove _listfile and _cmlist from _argv
LIST(REMOVE_AT _argv 0 1)
IF (NOT EXISTS "${_listfile}" OR
${_cmlist} IS_NEWER_THAN "${_listfile}")
MESSAGE(STATUS "Generating ${_listfile}")
FILE(WRITE ${_listfile} "")
FOREACH (testfile ${_argv})
IF (testfile MATCHES "^test_[^/]+[.]c$")
FILE(STRINGS ${testfile} testvar REGEX "^DEFINE_TEST")
FOREACH (deftest ${testvar})
FILE(APPEND ${_listfile} "${deftest}\n")
ENDFOREACH (deftest)
ENDIF (testfile MATCHES "^test_[^/]+[.]c$")
ENDFOREACH (testfile)
ENDIF (NOT EXISTS "${_listfile}" OR
${_cmlist} IS_NEWER_THAN "${_listfile}")
# Remove _listfile, _cmlist, and _target from _argv
LIST(REMOVE_AT _argv 0 1 2)
# Convert source paths to absolute so discover_tests.cmake can find them
# regardless of the working directory when cmake -P runs.
SET(_gl_abs_sources "")
FOREACH(_gl_src ${_argv})
IF(IS_ABSOLUTE "${_gl_src}")
LIST(APPEND _gl_abs_sources "${_gl_src}")
ELSE()
LIST(APPEND _gl_abs_sources "${CMAKE_CURRENT_SOURCE_DIR}/${_gl_src}")
ENDIF()
ENDFOREACH()
# Stamp out discover_tests.cmake with source list and output path baked in.
SET(SOURCES "${_gl_abs_sources}")
SET(OUTPUT "${_listfile}")
CONFIGURE_FILE(
${CMAKE_SOURCE_DIR}/build/cmake/discover_tests.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/discover_tests.cmake
@ONLY)
UNSET(SOURCES)
UNSET(OUTPUT)
# list.h is regenerated at build time whenever any test .c file changes.
ADD_CUSTOM_COMMAND(
OUTPUT "${_listfile}"
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/discover_tests.cmake
DEPENDS ${_gl_abs_sources}
COMMENT "Generating ${_listfile}"
VERBATIM)
# Attaching list.h to the target tells CMake to build it before compiling.
TARGET_SOURCES(${_target} PRIVATE "${_listfile}")
ENDMACRO (GENERATE_LIST_H)
#
# Register individual tests with CTest by scanning DEFINE_TEST() declarations.
#
MACRO (DISCOVER_TESTS _component __list_sources)
IF(ENABLE_TEST)
SET(_sources ${ARGV})
LIST(REMOVE_AT _sources 0)
FOREACH (_src ${_sources})
IF (_src MATCHES "test_[^/]+\\.c$")
FILE(STRINGS "${_src}" _lines REGEX "^DEFINE_TEST\(.*\)")
FOREACH (_line ${_lines})
STRING(REGEX MATCH "DEFINE_TEST\((.*)\)" _full_match ${_line})
# CMake REGEX seems to handle ( and \( rather inconsistently...
# So we go through an extra dance to definitively strip the parens
STRING(REPLACE "(" "" _test_name_with_paren "${CMAKE_MATCH_1}")
STRING(REPLACE ")" "" _test_name "${_test_name_with_paren}")
SET(_full_test_name "${_component}_${_test_name}")
ADD_TEST(NAME ${_full_test_name}
COMMAND ${_component}_test -vv
-r ${CMAKE_CURRENT_SOURCE_DIR}
-s
${_test_name})
SET_TESTS_PROPERTIES(${_full_test_name} PROPERTIES SKIP_RETURN_CODE 2)
ENDFOREACH (_line)
ENDIF (_src MATCHES "test_[^/]+\\.c$")
ENDFOREACH (_src)
ENDIF(ENABLE_TEST)
ENDMACRO (DISCOVER_TESTS __list_sources)
#
# Generate installation rules for man pages.
#
@@ -654,7 +701,7 @@ IF(ENABLE_ZSTD)
ENDIF()
FIND_PATH(ZSTD_INCLUDE_DIR zstd.h HINTS ${PC_ZSTD_INCLUDEDIR} ${PC_ZSTD_INCLUDE_DIRS})
FIND_LIBRARY(ZSTD_LIBRARY NAMES zstd libzstd HINTS ${PC_ZSTD_LIBDIR} ${PC_ZSTD_LIBRARY_DIRS})
FIND_LIBRARY(ZSTD_LIBRARY NAMES zstd libzstd zstd_static HINTS ${PC_ZSTD_LIBDIR} ${PC_ZSTD_LIBRARY_DIRS})
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(ZSTD DEFAULT_MSG ZSTD_LIBRARY ZSTD_INCLUDE_DIR)
ELSE(ENABLE_ZSTD)
@@ -723,6 +770,7 @@ CHECK_C_SOURCE_COMPILES("#include <sys/ioctl.h>
#include <linux/fs.h>
int main(void) { return FS_IOC_GETFLAGS; }" HAVE_WORKING_FS_IOC_GETFLAGS)
LA_CHECK_INCLUDE_FILE("intsafe.h" HAVE_INTSAFE_H)
LA_CHECK_INCLUDE_FILE("linux/magic.h" HAVE_LINUX_MAGIC_H)
LA_CHECK_INCLUDE_FILE("locale.h" HAVE_LOCALE_H)
LA_CHECK_INCLUDE_FILE("membership.h" HAVE_MEMBERSHIP_H)
@@ -737,7 +785,9 @@ LA_CHECK_INCLUDE_FILE("regex.h" HAVE_REGEX_H)
LA_CHECK_INCLUDE_FILE("signal.h" HAVE_SIGNAL_H)
LA_CHECK_INCLUDE_FILE("spawn.h" HAVE_SPAWN_H)
LA_CHECK_INCLUDE_FILE("stdarg.h" HAVE_STDARG_H)
LA_CHECK_INCLUDE_FILE("stdckdint.h" HAVE_STDCKDINT_H)
LA_CHECK_INCLUDE_FILE("stdint.h" HAVE_STDINT_H)
LA_CHECK_INCLUDE_FILE("stdio.h" HAVE_STDIO_H)
LA_CHECK_INCLUDE_FILE("stdlib.h" HAVE_STDLIB_H)
LA_CHECK_INCLUDE_FILE("string.h" HAVE_STRING_H)
LA_CHECK_INCLUDE_FILE("strings.h" HAVE_STRINGS_H)
@@ -754,6 +804,7 @@ LA_CHECK_INCLUDE_FILE("sys/select.h" HAVE_SYS_SELECT_H)
LA_CHECK_INCLUDE_FILE("sys/stat.h" HAVE_SYS_STAT_H)
LA_CHECK_INCLUDE_FILE("sys/statfs.h" HAVE_SYS_STATFS_H)
LA_CHECK_INCLUDE_FILE("sys/statvfs.h" HAVE_SYS_STATVFS_H)
LA_CHECK_INCLUDE_FILE("sys/sysctl.h" HAVE_SYS_SYSCTL_H)
LA_CHECK_INCLUDE_FILE("sys/sysmacros.h" HAVE_SYS_SYSMACROS_H)
LA_CHECK_INCLUDE_FILE("sys/time.h" HAVE_SYS_TIME_H)
LA_CHECK_INCLUDE_FILE("sys/utime.h" HAVE_SYS_UTIME_H)
@@ -771,12 +822,22 @@ IF(ENABLE_CNG)
LA_CHECK_INCLUDE_FILE("bcrypt.h" HAVE_BCRYPT_H)
IF(HAVE_BCRYPT_H)
LIST(APPEND ADDITIONAL_LIBS "bcrypt")
# bcrypt supports these algorithms on all available versions
SET(ARCHIVE_CRYPTO_MD5 1)
SET(ARCHIVE_CRYPTO_MD5_WIN 1)
SET(ARCHIVE_CRYPTO_SHA1 1)
SET(ARCHIVE_CRYPTO_SHA1_WIN 1)
SET(ARCHIVE_CRYPTO_SHA256 1)
SET(ARCHIVE_CRYPTO_SHA256_WIN 1)
SET(ARCHIVE_CRYPTO_SHA384 1)
SET(ARCHIVE_CRYPTO_SHA384_WIN 1)
SET(ARCHIVE_CRYPTO_SHA512 1)
SET(ARCHIVE_CRYPTO_SHA512_WIN 1)
ENDIF(HAVE_BCRYPT_H)
ELSE(ENABLE_CNG)
UNSET(HAVE_BCRYPT_H CACHE)
ENDIF(ENABLE_CNG)
# Following files need windows.h, so we should test it after windows.h test.
LA_CHECK_INCLUDE_FILE("wincrypt.h" HAVE_WINCRYPT_H)
LA_CHECK_INCLUDE_FILE("winioctl.h" HAVE_WINIOCTL_H)
#
@@ -804,11 +865,14 @@ IF(ENABLE_MBEDTLS)
LIST(APPEND ADDITIONAL_LIBS ${MBEDCRYPTO_LIBRARY})
INCLUDE_DIRECTORIES(${MBEDTLS_INCLUDE_DIRS})
CMAKE_PUSH_CHECK_STATE()
LIST(APPEND CMAKE_REQUIRED_INCLUDES ${MBEDTLS_INCLUDE_DIRS})
LA_CHECK_INCLUDE_FILE("mbedtls/aes.h" HAVE_MBEDTLS_AES_H)
LA_CHECK_INCLUDE_FILE("mbedtls/md.h" HAVE_MBEDTLS_MD_H)
LA_CHECK_INCLUDE_FILE("mbedtls/pkcs5.h" HAVE_MBEDTLS_PKCS5_H)
LA_CHECK_INCLUDE_FILE("mbedtls/version.h" HAVE_MBEDTLS_VERSION_H)
CMAKE_POP_CHECK_STATE()
ENDIF(MBEDTLS_FOUND)
MARK_AS_ADVANCED(CLEAR MBEDTLS_INCLUDE_DIRS)
MARK_AS_ADVANCED(CLEAR MBEDCRYPTO_LIBRARY)
@@ -824,6 +888,7 @@ IF(ENABLE_NETTLE)
LIST(APPEND ADDITIONAL_LIBS ${NETTLE_LIBRARIES})
INCLUDE_DIRECTORIES(${NETTLE_INCLUDE_DIR})
CMAKE_PUSH_CHECK_STATE()
LIST(APPEND CMAKE_REQUIRED_INCLUDES ${NETTLE_INCLUDE_DIR})
LA_CHECK_INCLUDE_FILE("nettle/aes.h" HAVE_NETTLE_AES_H)
LA_CHECK_INCLUDE_FILE("nettle/hmac.h" HAVE_NETTLE_HMAC_H)
@@ -832,6 +897,8 @@ IF(ENABLE_NETTLE)
LA_CHECK_INCLUDE_FILE("nettle/ripemd160.h" HAVE_NETTLE_RIPEMD160_H)
LA_CHECK_INCLUDE_FILE("nettle/sha.h" HAVE_NETTLE_SHA_H)
LA_CHECK_INCLUDE_FILE("nettle/version.h" HAVE_NETTLE_VERSION_H)
CMAKE_POP_CHECK_STATE()
ENDIF(NETTLE_FOUND)
MARK_AS_ADVANCED(CLEAR NETTLE_INCLUDE_DIR)
MARK_AS_ADVANCED(CLEAR NETTLE_LIBRARIES)
@@ -847,11 +914,15 @@ IF(ENABLE_OPENSSL AND NOT CMAKE_SYSTEM_NAME MATCHES "Darwin")
SET(HAVE_LIBCRYPTO 1)
INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR})
LIST(APPEND ADDITIONAL_LIBS ${OPENSSL_CRYPTO_LIBRARY})
CMAKE_PUSH_CHECK_STATE()
SET(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_CRYPTO_LIBRARY})
SET(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
LA_CHECK_INCLUDE_FILE("openssl/evp.h" HAVE_OPENSSL_EVP_H)
LA_CHECK_INCLUDE_FILE("openssl/opensslv.h" HAVE_OPENSSL_OPENSSLV_H)
CHECK_FUNCTION_EXISTS(PKCS5_PBKDF2_HMAC_SHA1 HAVE_PKCS5_PBKDF2_HMAC_SHA1)
CMAKE_POP_CHECK_STATE()
ENDIF(OPENSSL_FOUND)
ELSE()
SET(OPENSSL_FOUND FALSE) # Override cached value
@@ -872,9 +943,13 @@ ENDIF(NOT OPENSSL_FOUND)
# libbsd for readpassphrase on Haiku
IF("${CMAKE_SYSTEM_NAME}" MATCHES "Haiku")
MESSAGE(STATUS "Adding libbsd for Haiku")
CMAKE_PUSH_CHECK_STATE()
SET(CMAKE_REQUIRED_LIBRARIES "bsd")
FIND_LIBRARY(LIBBSD_LIBRARY NAMES bsd)
LIST(APPEND ADDITIONAL_LIBS ${LIBBSD_LIBRARY})
CMAKE_POP_CHECK_STATE()
ENDIF("${CMAKE_SYSTEM_NAME}" MATCHES "Haiku")
#
@@ -985,85 +1060,6 @@ main(int argc, char **argv)
ENDFOREACH(ALGORITHM ${ALGORITHMS})
ENDMACRO(CHECK_CRYPTO ALGORITHMS IMPLEMENTATION)
#
# CRYPTO functions on Windows is defined at archive_windows.c, thus we do not
# need the test what the functions can be mapped to archive_{crypto name}_init,
# archive_{crypto name}_update and archive_{crypto name}_final.
# The functions on Windows use CALG_{crypto name} macro to create a crypt object
# and then we need to know what CALG_{crypto name} macros is available to show
# ARCHIVE_CRYPTO_{crypto name}_WIN macros because Windows 2000 and earlier version
# of Windows XP do not support SHA256, SHA384 and SHA512.
#
MACRO(CHECK_CRYPTO_WIN CRYPTO_LIST)
IF(WIN32 AND NOT CYGWIN)
FOREACH(CRYPTO ${CRYPTO_LIST})
IF(NOT ARCHIVE_CRYPTO_${CRYPTO})
IF(NOT DEFINED ARCHIVE_CRYPTO_${CRYPTO}_WIN)
STRING(TOUPPER "${CRYPTO}" crypto)
SET(ALGID "")
IF ("${CRYPTO}" MATCHES "^MD5$")
SET(ALGID "CALG_MD5")
ENDIF ("${CRYPTO}" MATCHES "^MD5$")
IF ("${CRYPTO}" MATCHES "^SHA1$")
SET(ALGID "CALG_SHA1")
ENDIF ("${CRYPTO}" MATCHES "^SHA1$")
IF ("${CRYPTO}" MATCHES "^SHA256$")
SET(ALGID "CALG_SHA_256")
ENDIF ("${CRYPTO}" MATCHES "^SHA256$")
IF ("${CRYPTO}" MATCHES "^SHA384$")
SET(ALGID "CALG_SHA_384")
ENDIF ("${CRYPTO}" MATCHES "^SHA384$")
IF ("${CRYPTO}" MATCHES "^SHA512$")
SET(ALGID "CALG_SHA_512")
ENDIF ("${CRYPTO}" MATCHES "^SHA512$")
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/build/cmake/config.h.in
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/confdefs.h)
FILE(READ "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/confdefs.h"
CONFDEFS_H)
SET(SOURCE "${CONFDEFS_H}
#define ${crypto}_COMPILE_TEST
#include <windows.h>
#include <wincrypt.h>
int
main(int argc, char **argv)
{
return ${ALGID};
}
")
SET(SOURCE_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/check_crypto_win.c")
FILE(WRITE "${SOURCE_FILE}" "${SOURCE}")
MESSAGE(STATUS "Checking support for ARCHIVE_CRYPTO_${CRYPTO}_WIN")
TRY_COMPILE(ARCHIVE_CRYPTO_${CRYPTO}_WIN
${CMAKE_BINARY_DIR}
${SOURCE_FILE}
CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_BINARY_DIR};${CMAKE_CURRENT_SOURCE_DIR}/libarchive"
OUTPUT_VARIABLE OUTPUT)
IF (ARCHIVE_CRYPTO_${CRYPTO}_WIN)
MESSAGE(STATUS
"Checking support for ARCHIVE_CRYPTO_${CRYPTO}_WIN -- found")
SET(ARCHIVE_CRYPTO_${CRYPTO} 1)
ELSE (ARCHIVE_CRYPTO_${CRYPTO}_WIN)
MESSAGE(STATUS
"Checking support for ARCHIVE_CRYPTO_${CRYPTO}_WIN -- not found")
FILE(APPEND
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
"Checking support for ARCHIVE_CRYPTO_${CRYPTO}_WIN failed with the following output:\n"
"${OUTPUT}\n"
"Source file was:\n${SOURCE}\n")
ENDIF (ARCHIVE_CRYPTO_${CRYPTO}_WIN)
ENDIF(NOT DEFINED ARCHIVE_CRYPTO_${CRYPTO}_WIN)
ENDIF(NOT ARCHIVE_CRYPTO_${CRYPTO})
ENDFOREACH(CRYPTO)
ENDIF(WIN32 AND NOT CYGWIN)
ENDMACRO(CHECK_CRYPTO_WIN CRYPTO_LIST)
#
# Find iconv
# POSIX defines the second arg as const char **
@@ -1078,8 +1074,8 @@ MACRO(CHECK_ICONV LIB TRY_ICONV_CONST)
CMAKE_C_COMPILER_ID MATCHES "^Clang$")
#
# During checking iconv proto type, we should use -Werror to avoid the
# success of iconv detection with a warning which success is a miss
# detection. So this needs for all build mode(even it's a release mode).
# success of iconv detection with a warning, which would be a false
# positive. So this is needed for all build modes, even in release mode.
#
SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Werror")
ENDIF (CMAKE_C_COMPILER_ID MATCHES "^GNU$" OR
@@ -1257,7 +1253,7 @@ ELSE(LIBXML2_FOUND)
# Check linkage as well; versions of mingw-w64 before v11.0.0
# do not contain an import library for xmllite.
cmake_push_check_state()
SET(CMAKE_REQUIRED_LIBRARIES "xmllite")
SET(CMAKE_REQUIRED_LIBRARIES "xmllite" "uuid")
check_c_source_compiles("
#include <initguid.h>
#include <xmllite.h>
@@ -1268,7 +1264,7 @@ ELSE(LIBXML2_FOUND)
cmake_pop_check_state()
IF(HAVE_XMLLITE_H)
SET(XMLLITE_FOUND TRUE)
LIST(APPEND ADDITIONAL_LIBS "xmllite")
LIST(APPEND ADDITIONAL_LIBS "xmllite" "uuid")
ENDIF()
ENDIF()
ENDIF(EXPAT_FOUND)
@@ -1467,11 +1463,24 @@ IF (CMAKE_C_COMPILER_ID MATCHES "^GNU$" OR
SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-builtin")
ENDIF (CMAKE_C_COMPILER_ID MATCHES "^GNU$" OR
CMAKE_C_COMPILER_ID MATCHES "^Clang$")
IF (MSVC)
#
# The Windows CRT marks a number of standard functions (e.g. wcscpy) as
# deprecated. All source files in this project are compiled with those
# deprecations suppressed, so suppress these warnings for the following
# symbol checks as well. Otherwise, the deprecation warnings get turned into
# errors by ENABLE_WERROR's /WX flag and the check fails even when the
# function exists.
#
LIST(APPEND CMAKE_REQUIRED_DEFINITIONS -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS)
ENDIF (MSVC)
CHECK_SYMBOL_EXISTS(_CrtSetReportMode "crtdbg.h" HAVE__CrtSetReportMode)
CHECK_FUNCTION_EXISTS_GLIBC(arc4random_buf HAVE_ARC4RANDOM_BUF)
CHECK_FUNCTION_EXISTS_GLIBC(chflags HAVE_CHFLAGS)
CHECK_FUNCTION_EXISTS_GLIBC(chown HAVE_CHOWN)
CHECK_FUNCTION_EXISTS_GLIBC(chroot HAVE_CHROOT)
CHECK_FUNCTION_EXISTS_GLIBC(closefrom HAVE_CLOSEFROM)
CHECK_FUNCTION_EXISTS_GLIBC(close_range HAVE_CLOSE_RANGE)
CHECK_FUNCTION_EXISTS_GLIBC(ctime_r HAVE_CTIME_R)
CHECK_FUNCTION_EXISTS_GLIBC(fchdir HAVE_FCHDIR)
CHECK_FUNCTION_EXISTS_GLIBC(fchflags HAVE_FCHFLAGS)
@@ -1489,15 +1498,20 @@ CHECK_FUNCTION_EXISTS_GLIBC(ftruncate HAVE_FTRUNCATE)
CHECK_FUNCTION_EXISTS_GLIBC(futimens HAVE_FUTIMENS)
CHECK_FUNCTION_EXISTS_GLIBC(futimes HAVE_FUTIMES)
CHECK_FUNCTION_EXISTS_GLIBC(futimesat HAVE_FUTIMESAT)
CHECK_FUNCTION_EXISTS_GLIBC(getegid HAVE_GETEGID)
CHECK_FUNCTION_EXISTS_GLIBC(geteuid HAVE_GETEUID)
CHECK_FUNCTION_EXISTS_GLIBC(getgrgid_r HAVE_GETGRGID_R)
CHECK_FUNCTION_EXISTS_GLIBC(getgrnam_r HAVE_GETGRNAM_R)
CHECK_FUNCTION_EXISTS_GLIBC(getline HAVE_GETLINE)
CHECK_FUNCTION_EXISTS_GLIBC(getpid HAVE_GETPID)
CHECK_FUNCTION_EXISTS_GLIBC(getpwnam_r HAVE_GETPWNAM_R)
CHECK_FUNCTION_EXISTS_GLIBC(getpwuid_r HAVE_GETPWUID_R)
CHECK_FUNCTION_EXISTS_GLIBC(getpid HAVE_GETPID)
CHECK_FUNCTION_EXISTS_GLIBC(getresgid HAVE_GETRESGID)
CHECK_FUNCTION_EXISTS_GLIBC(getresuid HAVE_GETRESUID)
CHECK_FUNCTION_EXISTS_GLIBC(gettimeofday HAVE_GETTIMEOFDAY)
CHECK_FUNCTION_EXISTS_GLIBC(getvfsbyname HAVE_GETVFSBYNAME)
CHECK_FUNCTION_EXISTS_GLIBC(gmtime_r HAVE_GMTIME_R)
CHECK_FUNCTION_EXISTS_GLIBC(issetugid HAVE_ISSETUGID)
CHECK_FUNCTION_EXISTS_GLIBC(lchflags HAVE_LCHFLAGS)
CHECK_FUNCTION_EXISTS_GLIBC(lchmod HAVE_LCHMOD)
CHECK_FUNCTION_EXISTS_GLIBC(lchown HAVE_LCHOWN)
@@ -1516,6 +1530,7 @@ CHECK_FUNCTION_EXISTS_GLIBC(nl_langinfo HAVE_NL_LANGINFO)
CHECK_FUNCTION_EXISTS_GLIBC(openat HAVE_OPENAT)
CHECK_FUNCTION_EXISTS_GLIBC(pipe HAVE_PIPE)
CHECK_FUNCTION_EXISTS_GLIBC(poll HAVE_POLL)
CHECK_FUNCTION_EXISTS_GLIBC(posix_spawn HAVE_POSIX_SPAWN)
CHECK_FUNCTION_EXISTS_GLIBC(posix_spawnp HAVE_POSIX_SPAWNP)
CHECK_FUNCTION_EXISTS_GLIBC(readlink HAVE_READLINK)
CHECK_FUNCTION_EXISTS_GLIBC(readpassphrase HAVE_READPASSPHRASE)
@@ -1579,12 +1594,6 @@ CHECK_C_SOURCE_COMPILES(
"#include <sys/types.h>\n#include <sys/mount.h>\nint main(void) { struct statfs s; return sizeof(s);}"
HAVE_STRUCT_STATFS)
# Make sure we have the POSIX version of readdir_r, not the
# older 2-argument version.
CHECK_C_SOURCE_COMPILES(
"#include <dirent.h>\nint main() {DIR *d = opendir(\".\"); struct dirent e,*r; return readdir_r(d,&e,&r);}"
HAVE_READDIR_R)
# dirfd can be either a function or a macro.
CHECK_C_SOURCE_COMPILES(
"#include <dirent.h>\nint main() {DIR *d = opendir(\".\"); return dirfd(d);}"
@@ -2165,18 +2174,19 @@ ENDIF(ENABLE_ACL)
# Check MD5/RMD160/SHA support
# NOTE: Crypto checks must be run last before generating config.h
#
CHECK_CRYPTO("MD5;RMD160;SHA1;SHA256;SHA384;SHA512" LIBC)
CHECK_CRYPTO("SHA256;SHA384;SHA512" LIBC2)
CHECK_CRYPTO("SHA256;SHA384;SHA512" LIBC3)
CHECK_CRYPTO("MD5;SHA1;SHA256;SHA384;SHA512" LIBSYSTEM)
CHECK_CRYPTO("MD5;RMD160;SHA1;SHA256;SHA384;SHA512" MBEDTLS)
CHECK_CRYPTO("MD5;RMD160;SHA1;SHA256;SHA384;SHA512" NETTLE)
CHECK_CRYPTO("MD5;RMD160;SHA1;SHA256;SHA384;SHA512" OPENSSL)
IF(CMAKE_SYSTEM_NAME MATCHES "Darwin")
CHECK_CRYPTO("MD5;SHA1;SHA256;SHA384;SHA512" LIBSYSTEM)
ELSE()
CHECK_CRYPTO("MD5;RMD160;SHA1;SHA256;SHA384;SHA512" LIBC)
CHECK_CRYPTO("SHA256;SHA384;SHA512" LIBC2)
CHECK_CRYPTO("SHA256;SHA384;SHA512" LIBC3)
CHECK_CRYPTO("MD5;RMD160;SHA1;SHA256;SHA384;SHA512" MBEDTLS)
CHECK_CRYPTO("MD5;RMD160;SHA1;SHA256;SHA384;SHA512" NETTLE)
CHECK_CRYPTO("MD5;RMD160;SHA1;SHA256;SHA384;SHA512" OPENSSL)
# Libmd has to be probed after OpenSSL.
CHECK_CRYPTO("MD5;RMD160;SHA1;SHA256;SHA512" LIBMD)
CHECK_CRYPTO_WIN("MD5;SHA1;SHA256;SHA384;SHA512")
# Libmd has to be probed after OpenSSL.
CHECK_CRYPTO("MD5;RMD160;SHA1;SHA256;SHA512" LIBMD)
ENDIF()
# Check visibility annotations
SET(OLD_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
@@ -2220,7 +2230,10 @@ ENDIF(WIN32 AND NOT CYGWIN AND ENABLE_INSTALL)
INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/libarchive)
#
IF(MSVC)
ADD_DEFINITIONS(-D_CRT_SECURE_NO_DEPRECATE)
ADD_DEFINITIONS(
-D_CRT_NONSTDC_NO_WARNINGS
-D_CRT_SECURE_NO_DEPRECATE
)
ENDIF(MSVC)
OPTION(DONT_FAIL_ON_CRC_ERROR "Ignore CRC errors during parsing (For fuzzing)" OFF)
@@ -2232,6 +2245,13 @@ IF(ENABLE_TEST)
ADD_CUSTOM_TARGET(run_all_tests)
ENDIF(ENABLE_TEST)
IF(ENABLE_CLANG_TIDY)
IF(NOT CLANG_TIDY_PATH)
SET(CLANG_TIDY_PATH clang-tidy)
ENDIF(NOT CLANG_TIDY_PATH)
SET(CMAKE_C_CLANG_TIDY ${CLANG_TIDY_PATH})
ENDIF(ENABLE_CLANG_TIDY)
add_subdirectory(libarchive)
add_subdirectory(cat)
add_subdirectory(tar)
+333 -119
View File
File diff suppressed because it is too large. Load diff
+10
View File
@@ -1,3 +1,13 @@
May 20, 2025: libarchive 3.8.0 released
Mar 30, 2025: libarchive 3.7.9 released
Mar 20, 2025: libarchive 3.7.8 released
Oct 13, 2024: libarchive 3.7.7 released
Sep 23, 2024: libarchive 3.7.6 released
Sep 13, 2024: libarchive 3.7.5 released
Apr 26, 2024: libarchive 3.7.4 released
+8 -5
View File
@@ -37,10 +37,13 @@ The top-level directory contains the following information files:
* **CMakeLists.txt** - input for "cmake" build tool, see INSTALL
* **configure** - configuration script, see INSTALL for details. If your copy of the source lacks a `configure` script, you can try to construct it by running the script in `build/autogen.sh` (or use `cmake`).
The following files in the top-level directory are used by the 'configure' script:
The following files in the top-level directory are related to the 'configure' script and are only needed by maintainers:
* `Makefile.am`, `aclocal.m4`, `configure.ac` - used to build this distribution, only needed by maintainers
* `Makefile.in`, `config.h.in` - templates used by configure script
* `configure.ac` - used (by autoconf) to build the configure script and related files
* `Makefile.am` - used (by automake) to generate Makefile.in
* `aclocal.m4` - auto-generated file (created by aclocal) used to build the configure script
* `Makefile.in` - auto-generated template (created by automake) used by the configure script to create Makefile
* `config.h.in` - auto-generated template (created by autoheader) used by the configure script to create config.h
## Documentation
@@ -191,7 +194,7 @@ questions we are asked about libarchive:
libraries. This also reduces the size of statically-linked
binaries in environments where that matters.
* The library is generally _thread safe_ depending on the platform:
* The library is generally _thread-safe_ depending on the platform:
it does not define any global variables of its own. However, some
platforms do not provide fully thread-safe versions of key C library
functions. On those platforms, libarchive will use the non-thread-safe
@@ -214,7 +217,7 @@ questions we are asked about libarchive:
multiple threads. Of course, those modules are completely
optional and you can use the rest of libarchive without them.
* The library is _not_ thread aware, however. It does no locking
* The library is _not_ thread-aware, however. It does no locking
or thread management of any kind. If you create a libarchive
object and need to access it from multiple threads, you will
need to provide your own locking.
+13 -6
View File
@@ -1,9 +1,10 @@
# Security Policy
If you have discovered a security vulnerability in this project, please report it
privately. **Do not disclose it as a public issue.** This gives us time to work with you
to fix the issue before public exposure, reducing the chance that the exploit will be
used before a patch is released.
If you have discovered a security vulnerability in this project,
please report it privately.
**Do not disclose it as a public issue.**
This gives us time to work with you to fix the issue before public exposure,
reducing the chance that the exploit will be used before a patch is released.
You may submit the report in the following ways:
@@ -15,5 +16,11 @@ Please provide the following information in your report:
- A description of the vulnerability and its impact
- How to reproduce the issue
This project is maintained by volunteers on a reasonable-effort basis. As such, we ask
that you give me 90 days to work on a fix before public exposure.
While we welcome all reports, we can act most quickly if the report
includes a complete libarchive test case and a proposed fix.
See [doc/WRITING_TESTS.md](doc/WRITING_TESTS.md) for guidance on creating a reproduction test case.
You can provide the test case and proposed fix as separate patch files
prepared with `git format-patch` or `git diff`.
This project is maintained by volunteers on a reasonable-effort basis.
We ask that you give us 90 days to work on a fix before public exposure.
-4
View File
@@ -1,4 +0,0 @@
FROM cirrusci/windowsservercore:2019
RUN choco install -y --no-progress cygwin
RUN C:\tools\cygwin\cygwinsetup.exe -q -P make,autoconf,automake,cmake,gcc-core,binutils,libtool,pkg-config,bison,zlib-devel,libbz2-devel,liblzma-devel,liblz4-devel,libiconv-devel,libxml2-devel,libzstd-devel,libssl-devel
-3
View File
@@ -1,3 +0,0 @@
FROM fedora:31
RUN dnf -y install make cmake gcc gcc-c++ kernel-devel automake libtool bison pkgconf libacl-devel libasan librichacl-devel bzip2-devel zlib-devel xz-devel lz4-devel libzstd-devel openssl-devel nettle-devel mbedtls-devel
@@ -1,3 +0,0 @@
FROM fedora:31
RUN dnf -y install make cmake gcc gcc-c++ kernel-devel automake libtool bison pkgconf libacl-devel libasan librichacl-devel bzip2-devel zlib-devel xz-devel lz4-devel libzstd-devel openssl-devel groff ghostscript xz zip
-8
View File
@@ -1,8 +0,0 @@
FROM cirrusci/windowsservercore:2019
RUN choco install -y --no-progress --installargs 'ADD_CMAKE_TO_PATH=User' cmake
RUN choco install -y --no-progress mingw
RUN curl -o zlib-1.2.11.tar.gz https://www.zlib.net/zlib-1.2.11.tar.gz
RUN tar -x -f zlib-1.2.11.tar.gz
RUN cd zlib-1.2.11 && cmake -G "MinGW Makefiles" -D CMAKE_BUILD_TYPE="Release" . && mingw32-make && mingw32-make install
RUN del /f /q /s zlib-1.2.11 zlib-1.2.11.tar.gz
-9
View File
@@ -1,9 +0,0 @@
FROM cirrusci/windowsservercore:2019
RUN choco install -y --no-progress --installargs 'ADD_CMAKE_TO_PATH=User' cmake
RUN choco install -y --no-progress visualstudio2017community
RUN choco install -y --no-progress visualstudio2017-workload-vctools
RUN curl -o zlib-1.2.11.tar.gz https://www.zlib.net/zlib-1.2.11.tar.gz
RUN tar -x -f zlib-1.2.11.tar.gz
RUN cd zlib-1.2.11 && cmake -G "Visual Studio 15 2017" . && cmake --build . --target ALL_BUILD --config Release && cmake --build . --target INSTALL --config Release
RUN del /f /q /s zlib-1.2.11 zlib-1.2.11.tar.gz
-12
View File
@@ -1,12 +0,0 @@
FROM cirrusci/windowsservercore:2019
RUN choco install -y --no-progress mingw
RUN choco install -y --no-progress --installargs 'ADD_CMAKE_TO_PATH=User' cmake
RUN choco install -y --no-progress visualstudio2017community
RUN choco install -y --no-progress visualstudio2017-workload-vctools
RUN curl -o zlib-1.2.11.tar.gz https://www.zlib.net/zlib-1.2.11.tar.gz
RUN tar -x -f zlib-1.2.11.tar.gz
RUN cd zlib-1.2.11 && cmake -G "Visual Studio 15 2017" . && cmake --build . --target ALL_BUILD --config Release && cmake --build . --target INSTALL --config Release
RUN del /f /q /s zlib-1.2.11 zlib-1.2.11.tar.gz
RUN choco install -y --no-progress cygwin
RUN C:\tools\cygwin\cygwinsetup.exe -q -P make,autoconf,automake,cmake,gcc-core,binutils,libtool,pkg-config,bison,zlib-devel,libbz2-devel,liblzma-devel,liblz4-devel,libiconv-devel,libxml2-devel,libzstd-devel,libssl-devel
-122
View File
@@ -1,122 +0,0 @@
@ECHO OFF
SET ZLIB_VERSION=1.2.11
IF NOT "%BE%"=="cygwin-gcc" (
IF NOT "%BE%"=="mingw-gcc" (
IF NOT "%BE%"=="msvc" (
ECHO Environment variable BE must be cygwin-gcc, mingw-gcc or msvc
EXIT /b 1
)
)
)
IF "%1%"=="prepare" (
IF "%BE%"=="cygwin-gcc" (
@ECHO ON
choco install -y --no-progress cygwin || EXIT /b 1
C:\tools\cygwin\cygwinsetup.exe -q -P make,autoconf,automake,cmake,gcc-core,binutils,libtool,pkg-config,bison,zlib-devel,libbz2-devel,liblzma-devel,liblz4-devel,libiconv-devel,libxml2-devel,libzstd-devel,libssl-devel || EXIT /b 1
@EXIT /b 0
) ELSE IF "%BE%"=="mingw-gcc" (
@ECHO ON
choco install -y --no-progress mingw || EXIT /b 1
choco install -y --no-progress --installargs 'ADD_CMAKE_TO_PATH=System' cmake || EXIT /b 1
@EXIT /b 0
) ELSE IF "%BE%"=="msvc" (
@ECHO ON
choco install -y --no-progress visualstudio2017community || EXIT /b 1
choco install -y --no-progress visualstudio2017-workload-vctools || EXIT /b 1
choco install -y --no-progress --installargs 'ADD_CMAKE_TO_PATH=System' cmake || EXIT /b 1
)
) ELSE IF "%1"=="deplibs" (
IF "%BE%"=="cygwin-gcc" (
ECHO Skipping on this platform
EXIT /b 0
)
IF NOT EXIST build_ci\libs (
MKDIR build_ci\libs
)
CD build_ci\libs
IF NOT EXIST zlib-%ZLIB_VERSION%.tar.gz (
curl -o zlib-%ZLIB_VERSION%.tar.gz https://www.zlib.net/zlib-%ZLIB_VERSION%.tar.gz
)
IF NOT EXIST zlib-%ZLIB_VERSION% (
tar -x -z -f zlib-%ZLIB_VERSION%.tar.gz
)
SET PATH=%PATH%;C:\Program Files\cmake\bin;C:\ProgramData\chocolatey\lib\mingw\tools\install\mingw64\bin
CD zlib-%ZLIB_VERSION%
IF "%BE%"=="mingw-gcc" (
cmake -G "MinGW Makefiles" -D CMAKE_BUILD_TYPE="Release" . || EXIT /b 1
mingw32-make || EXIT /b 1
mingw32-make test || EXIT /b 1
mingw32-make install || EXIT /b 1
) ELSE IF "%BE%"=="msvc" (
cmake -G "Visual Studio 15 2017" . || EXIT /b 1
cmake --build . --target ALL_BUILD --config Release || EXIT /b 1
cmake --build . --target RUN_TESTS --config Release || EXIT /b 1
cmake --build . --target INSTALL --config Release || EXIT /b 1
)
) ELSE IF "%1%"=="configure" (
IF "%BE%"=="cygwin-gcc" (
SET BS=cmake
SET CONFIGURE_ARGS=-DENABLE_ACL=OFF
C:\tools\cygwin\bin\bash.exe --login -c "cd '%cd%'; ./build/ci/build.sh -a configure" || EXIT /b 1
) ELSE IF "%BE%"=="mingw-gcc" (
SET PATH=%PATH%;C:\Program Files\cmake\bin;C:\ProgramData\chocolatey\lib\mingw\tools\install\mingw64\bin
MKDIR build_ci\cmake
CD build_ci\cmake
cmake -G "MinGW Makefiles" ..\.. || EXIT /b 1
) ELSE IF "%BE%"=="msvc" (
SET PATH=%PATH%;C:\Program Files\cmake\bin;C:\ProgramData\chocolatey\lib\mingw\tools\install\mingw64\bin
MKDIR build_ci\cmake
CD build_ci\cmake
cmake -G "Visual Studio 15 2017" -D CMAKE_BUILD_TYPE="Release" ..\.. || EXIT /b 1
)
) ELSE IF "%1%"=="build" (
IF "%BE%"=="cygwin-gcc" (
SET BS=cmake
C:\tools\cygwin\bin\bash.exe --login -c "cd '%cd%'; ./build/ci/build.sh -a build"
) ELSE IF "%BE%"=="mingw-gcc" (
SET PATH=%PATH%;C:\Program Files\cmake\bin;C:\ProgramData\chocolatey\lib\mingw\tools\install\mingw64\bin
CD build_ci\cmake
mingw32-make || EXIT /b 1
) ELSE IF "%BE%"=="msvc" (
SET PATH=%PATH%;C:\Program Files\cmake\bin;C:\ProgramData\chocolatey\lib\mingw\tools\install\mingw64\bin
CD build_ci\cmake
cmake --build . --target ALL_BUILD --config Release
)
) ELSE IF "%1%"=="test" (
IF "%BE%"=="cygwin-gcc" (
ECHO "Skipping tests on this platform"
EXIT /b 0
REM SET BS=cmake
REM SET SKIP_TEST_SPARSE=1
REM C:\tools\cygwin\bin\bash.exe --login -c "cd '%cd%'; ./build/ci/build.sh -a test"
) ELSE IF "%BE%"=="mingw-gcc" (
SET PATH=%PATH%;C:\Program Files\cmake\bin;C:\ProgramData\chocolatey\lib\mingw\tools\install\mingw64\bin
COPY "C:\Program Files (x86)\zlib\bin\libzlib.dll" build_ci\cmake\bin\
CD build_ci\cmake
SET SKIP_TEST_SPARSE=1
mingw32-make test
) ELSE IF "%BE%"=="msvc" (
SET PATH=%PATH%;C:\Program Files\cmake\bin;C:\ProgramData\chocolatey\lib\mingw\tools\install\mingw64\bin
ECHO "Skipping tests on this platform"
EXIT /b 0
REM CD build_ci\cmake
REM cmake --build . --target RUN_TESTS --config Release
)
) ELSE IF "%1%"=="install" (
IF "%BE%"=="cygwin-gcc" (
SET BS=cmake
C:\tools\cygwin\bin\bash.exe --login -c "cd '%cd%'; ./build/ci/build.sh -a install"
) ELSE IF "%BE%"=="mingw-gcc" (
SET PATH=%PATH%;C:\Program Files\cmake\bin;C:\ProgramData\chocolatey\lib\mingw\tools\install\mingw64\bin
CD build_ci\cmake
mingw32-make install DESTDIR=%cd%\destdir
) ELSE IF "%BE%"=="msvc" (
SET PATH=%PATH%;C:\Program Files\cmake\bin;C:\ProgramData\chocolatey\lib\mingw\tools\install\mingw64\bin
cmake --build . --target INSTALL --config Release
)
) ELSE (
ECHO "Usage: %0% prepare|deplibs|configure|build|test|install"
@EXIT /b 0
)
@EXIT /b 0
-66
View File
@@ -1,66 +0,0 @@
#!/bin/sh
set -eu
if [ $# != 1 ]
then
echo "Usage: $0 prepare | test"
exit 1
fi
UNAME=`uname`
if [ "$1" = "prepare" ]
then
if [ "${UNAME}" = "FreeBSD" ]
then
set -x -e
env ASSUME_ALWAYS_YES=yes pkg bootstrap -f
sed -i.bak -e 's,pkg+http://pkg.FreeBSD.org/\${ABI}/quarterly,pkg+http://pkg.FreeBSD.org/\${ABI}/latest,' /etc/pkg/FreeBSD.conf
pkg update
mount -u -o acls /
mkdir /tmp_acl_nfsv4
MD=`mdconfig -a -t swap -s 128M`
newfs /dev/$MD
tunefs -N enable /dev/$MD
mount /dev/$MD /tmp_acl_nfsv4
chmod 1777 /tmp_acl_nfsv4
pkg install -y autoconf automake cmake libiconv libtool pkgconf expat libxml2 liblz4 zstd
elif [ "${UNAME}" = "Darwin" ]
then
set -x -e
brew update > /dev/null
for pkg in autoconf automake libtool pkg-config cmake xz lz4 zstd
do
brew list $pkg > /dev/null && brew upgrade $pkg || brew install $pkg
done
elif [ "${UNAME}" = "Linux" ]
then
if [ -f "/etc/debian_version" ]
then
apt-get -y update
apt-get -y install build-essential locales automake libtool bison pkgconf libacl1-dev libbz2-dev zlib1g-dev liblzma-dev liblz4-dev libzstd-dev libssl-dev lrzip cmake
elif [ -f "/etc/fedora-release" ]
then
dnf -y install make cmake gcc gcc-c++ kernel-devel automake libtool bison pkgconf libacl-devel librichacl-devel bzip2-devel zlib-devel xz-devel lz4-devel libzstd-devel openssl-devel
fi
fi
elif [ "$1" = "test" ]
then
if [ "${UNAME}" = "FreeBSD" ]
then
set -e
echo "Additional NFSv4 ACL tests"
CURDIR=`pwd`
if [ "${BS}" = "cmake" ]
then
BIN_SUBDIR="bin"
else
BIN_SUBDIR=.
fi
BUILDDIR="${CURDIR}/build_ci/${BS}"
cd "$BUILDDIR"
TMPDIR=/tmp_acl_nfsv4 ${BIN_SUBDIR}/libarchive_test -r "${CURDIR}/libarchive/test" -v test_acl_platform_nfs4
fi
else
echo "Usage: $0 prepare | test"
exit 1
fi
+38 -107
View File
@@ -1,126 +1,32 @@
@ECHO OFF
SET ZLIB_VERSION=1.3
SET BZIP2_VERSION=1ea1ac188ad4b9cb662e3f8314673c63df95a589
SET XZ_VERSION=5.6.3
IF NOT "%BE%"=="mingw-gcc" (
IF NOT "%BE%"=="msvc" (
ECHO Environment variable BE must be mingw-gcc or msvc
EXIT /b 1
IF NOT "%BE%"=="cygwin-gcc" (
ECHO Environment variable BE must be cygwin-gcc, mingw-gcc or msvc
EXIT /b 1
)
)
)
REM v1.5.6 has a bug with the CMake files & MSVC
REM https://github.com/facebook/zstd/issues/3999
REM Fall back to 1.5.5 for MSVC until fixed
IF "%BE%"=="msvc" (
SET ZSTD_VERSION=1.5.5
) ELSE (
SET ZSTD_VERSION=1.5.6
)
SET ORIGPATH=%PATH%
IF "%BE%"=="mingw-gcc" (
SET MINGWPATH=C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\Program Files\cmake\bin;C:\ProgramData\mingw64\mingw64\bin
SET MINGWPATH=C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;D:\msys64\mingw64\bin;C:\Program Files\cmake\bin
)
IF "%1"=="deplibs" (
IF NOT EXIST build_ci\libs (
MKDIR build_ci\libs
)
CD build_ci\libs
IF NOT EXIST zlib-%ZLIB_VERSION%.zip (
ECHO Downloading https://github.com/libarchive/zlib/archive/v%ZLIB_VERSION%.zip
curl -L -o zlib-%ZLIB_VERSION%.zip https://github.com/libarchive/zlib/archive/v%ZLIB_VERSION%.zip || EXIT /b 1
)
IF NOT EXIST zlib-%ZLIB_VERSION% (
ECHO Unpacking zlib-%ZLIB_VERSION%.zip
C:\windows\system32\tar.exe -x -f zlib-%ZLIB_VERSION%.zip || EXIT /b 1
)
IF NOT EXIST bzip2-%BZIP2_VERSION%.zip (
echo Downloading https://github.com/libarchive/bzip2/archive/%BZIP2_VERSION%.zip
curl -L -o bzip2-%BZIP2_VERSION%.zip https://github.com/libarchive/bzip2/archive/%BZIP2_VERSION%.zip || EXIT /b 1
)
IF NOT EXIST bzip2-%BZIP2_VERSION% (
echo Unpacking bzip2-%BZIP2_VERSION%.zip
C:\windows\system32\tar.exe -x -f bzip2-%BZIP2_VERSION%.zip || EXIT /b 1
)
IF NOT EXIST xz-%XZ_VERSION%.zip (
echo Downloading https://github.com/libarchive/xz/archive/%XZ_VERSION%.zip
curl -L -o xz-%XZ_VERSION%.zip https://github.com/libarchive/xz/archive/v%XZ_VERSION%.zip || EXIT /b 1
)
IF NOT EXIST xz-%XZ_VERSION% (
echo Unpacking xz-%XZ_VERSION%.zip
C:\windows\system32\tar.exe -x -f xz-%XZ_VERSION%.zip || EXIT /b 1
)
IF NOT EXIST zstd-%ZSTD_VERSION%.zip (
echo Downloading https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD_VERSION%.zip
curl -L -o zstd-%ZSTD_VERSION%.zip https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD_VERSION%.zip || EXIT /b 1
)
IF NOT EXIST zstd-%ZSTD_VERSION% (
echo Unpacking zstd-%ZSTD_VERSION%.zip
C:\windows\system32\tar.exe -x -f zstd-%ZSTD_VERSION%.zip || EXIT /b 1
)
CD zlib-%ZLIB_VERSION%
IF "%BE%"=="mingw-gcc" (
SET PATH=%MINGWPATH%
cmake -G "MinGW Makefiles" -D CMAKE_BUILD_TYPE="Release" . || EXIT /b 1
mingw32-make -j %NUMBER_OF_PROCESSORS% || EXIT /b 1
mingw32-make test || EXIT /b 1
mingw32-make install || EXIT /b 1
) ELSE IF "%BE%"=="msvc" (
cmake -G "Visual Studio 17 2022" . || EXIT /b 1
cmake --build . --target ALL_BUILD --config Release || EXIT /b 1
cmake --build . --target RUN_TESTS --config Release || EXIT /b 1
cmake --build . --target INSTALL --config Release || EXIT /b 1
)
CD ..
CD bzip2-%BZIP2_VERSION%
IF "%BE%"=="mingw-gcc" (
SET PATH=%MINGWPATH%
cmake -G "MinGW Makefiles" -D CMAKE_BUILD_TYPE="Release" -D ENABLE_LIB_ONLY=ON -D ENABLE_SHARED_LIB=OFF -D ENABLE_STATIC_LIB=ON . || EXIT /b 1
mingw32-make -j %NUMBER_OF_PROCESSORS% || EXIT /b 1
REM mingw32-make test || EXIT /b 1
mingw32-make install || EXIT /b 1
) ELSE IF "%BE%"=="msvc" (
cmake -G "Visual Studio 17 2022" -D CMAKE_BUILD_TYPE="Release" -D ENABLE_LIB_ONLY=ON -D ENABLE_SHARED_LIB=OFF -D ENABLE_STATIC_LIB=ON . || EXIT /b 1
cmake --build . --target ALL_BUILD --config Release || EXIT /b 1
REM cmake --build . --target RUN_TESTS --config Release || EXIT /b 1
cmake --build . --target INSTALL --config Release || EXIT /b 1
)
CD ..
CD xz-%XZ_VERSION%
IF "%BE%"=="mingw-gcc" (
SET PATH=%MINGWPATH%
cmake -G "MinGW Makefiles" -D CMAKE_BUILD_TYPE="Release" . || EXIT /b 1
mingw32-make -j %NUMBER_OF_PROCESSORS% || EXIT /b 1
mingw32-make install || EXIT /b 1
) ELSE IF "%BE%"=="msvc" (
cmake -G "Visual Studio 17 2022" -D CMAKE_BUILD_TYPE="Release" . || EXIT /b 1
cmake --build . --target ALL_BUILD --config Release || EXIT /b 1
cmake --build . --target INSTALL --config Release || EXIT /b 1
)
CD ..
CD zstd-%ZSTD_VERSION%\build\cmake
IF "%BE%"=="mingw-gcc" (
SET PATH=%MINGWPATH%
cmake -G "MinGW Makefiles" -D CMAKE_BUILD_TYPE="Release" . || EXIT /b 1
mingw32-make -j %NUMBER_OF_PROCESSORS% || EXIT /b 1
mingw32-make install || EXIT /b 1
) ELSE IF "%BE%"=="msvc" (
cmake -G "Visual Studio 17 2022" -D CMAKE_BUILD_TYPE="Release" . || EXIT /b 1
cmake --build . --target ALL_BUILD --config Release || EXIT /b 1
cmake --build . --target INSTALL --config Release || EXIT /b 1
)
) ELSE IF "%1%"=="configure" (
IF "%1%"=="configure" (
IF "%BE%"=="mingw-gcc" (
SET PATH=%MINGWPATH%
MKDIR build_ci\cmake
CD build_ci\cmake
cmake -G "MinGW Makefiles" -D ZLIB_LIBRARY="C:/Program Files (x86)/zlib/lib/libzlibstatic.a" -D ZLIB_INCLUDE_DIR="C:/Program Files (x86)/zlib/include" -D BZIP2_LIBRARIES="C:/Program Files (x86)/bzip2/lib/libbz2_static.a" -D BZIP2_INCLUDE_DIR="C:/Program Files (x86)/bzip2/include" -D LIBLZMA_LIBRARY="C:/Program Files (x86)/xz/lib/liblzma.a" -D LIBLZMA_INCLUDE_DIR="C:/Program Files (x86)/xz/include" -D ZSTD_LIBRARY="C:/Program Files (x86)/zstd/lib/libzstd.a" -D ZSTD_INCLUDE_DIR="C:/Program Files (x86)/zstd/include" ..\.. || EXIT /b 1
cmake -G "MinGW Makefiles" ..\.. || EXIT /b 1
) ELSE IF "%BE%"=="msvc" (
MKDIR build_ci\cmake
CD build_ci\cmake
cmake -G "Visual Studio 17 2022" -D CMAKE_BUILD_TYPE="Release" -D ZLIB_LIBRARY="C:/Program Files (x86)/zlib/lib/zlibstatic.lib" -D ZLIB_INCLUDE_DIR="C:/Program Files (x86)/zlib/include" -D BZIP2_LIBRARIES="C:/Program Files (x86)/bzip2/lib/bz2_static.lib" -D BZIP2_INCLUDE_DIR="C:/Program Files (x86)/bzip2/include" -D LIBLZMA_LIBRARY="C:/Program Files (x86)/xz/lib/lzma.lib" -D LIBLZMA_INCLUDE_DIR="C:/Program Files (x86)/xz/include" -D ZSTD_LIBRARY="C:/Program Files (x86)/zstd/lib/zstd_static.lib" -D ZSTD_INCLUDE_DIR="C:/Program Files (x86)/zstd/include" ..\.. || EXIT /b 1
cmake -G "Visual Studio 17 2022" -D CMAKE_BUILD_TYPE="Release" --toolchain "%VCPKG_INSTALLATION_ROOT%\scripts\buildsystems\vcpkg.cmake" -D VCPKG_TARGET_TRIPLET=x64-windows-static -D VCPKG_MANIFEST_DIR=%GITHUB_WORKSPACE%\build\ci\github_actions ..\.. || EXIT /b 1
) ELSE IF "%BE%"=="cygwin-gcc" (
SET BS=cmake
SET CYGWIN_NOWINPATH=1
D:\cygwin\bin\bash.exe --login -c "cd '%cd%'; ./build/ci/build.sh -a configure" || EXIT /b 1
)
) ELSE IF "%1%"=="build" (
IF "%BE%"=="mingw-gcc" (
@@ -130,6 +36,11 @@ IF "%1"=="deplibs" (
) ELSE IF "%BE%"=="msvc" (
CD build_ci\cmake
cmake --build . --target ALL_BUILD --config Release || EXIT /b 1
) ELSE IF "%BE%"=="cygwin-gcc" (
SET BS=cmake
SET MAKE_ARGS=-j
SET CYGWIN_NOWINPATH=1
D:\cygwin\bin\bash.exe --login -c "cd '%cd%'; ./build/ci/build.sh -a build" || EXIT /b 1
)
) ELSE IF "%1%"=="test" (
IF "%BE%"=="mingw-gcc" (
@@ -140,6 +51,13 @@ IF "%1"=="deplibs" (
) ELSE IF "%BE%"=="msvc" (
CD build_ci\cmake
cmake --build . --target RUN_TESTS --config Release || EXIT /b 1
) ELSE IF "%BE%"=="cygwin-gcc" (
REM SET BS=cmake
REM SET CYGWIN_NOWINPATH=1
REM SET SKIP_TEST_SPARSE=1
ECHO "Skipping tests on this platform"
REM D:\cygwin\bin\bash.exe --login -c "cd '%cd%'; ./build/ci/build.sh -a test" || EXIT /b 1
EXIT /b 0
)
) ELSE IF "%1%"=="install" (
IF "%BE%"=="mingw-gcc" (
@@ -149,10 +67,23 @@ IF "%1"=="deplibs" (
) ELSE IF "%BE%"=="msvc" (
CD build_ci\cmake
cmake --build . --target INSTALL --config Release || EXIT /b 1
) ELSE IF "%BE%"=="cygwin-gcc" (
SET BS=cmake
SET CYGWIN_NOWINPATH=1
D:\cygwin\bin\bash.exe --login -c "cd '%cd%'; ./build/ci/build.sh -a install" || EXIT /b 1
REM Exit early here; the build.sh install step for Cygwin prints the version.
EXIT /b 0
)
"C:\Program Files (x86)\libarchive\bin\bsdtar.exe" --version
) ELSE IF "%1"=="artifact" (
C:\windows\system32\tar.exe -c -C "C:\Program Files (x86)" --format=zip -f libarchive.zip libarchive
IF "%BE%"=="cygwin-gcc" (
SET BS=cmake
SET CYGWIN_NOWINPATH=1
D:\cygwin\bin\bash.exe --login -c "cd '%cd%'; ./build/ci/build.sh -a artifact" || EXIT /b 1
EXIT /b 0
)
C:\windows\system32\tar.exe -c -C "C:\Program Files (x86)" --format=zip -f libarchive.zip libarchive
) ELSE (
ECHO "Usage: %0% deplibs|configure|build|test|install|artifact"
@EXIT /b 0
+41
View File
@@ -0,0 +1,41 @@
#!/bin/sh
set -eu
if [ $# != 1 ]
then
echo "Usage: $0 prepare | test"
exit 1
fi
if [ "$1" = "prepare" ]
then
set -x -e
env ASSUME_ALWAYS_YES=yes pkg bootstrap -f
sed -i.bak -e 's,pkg+http://pkg.FreeBSD.org/\${ABI}/quarterly,pkg+http://pkg.FreeBSD.org/\${ABI}/latest,' /etc/pkg/FreeBSD.conf
pkg update
mount -u -o acls /
mkdir /tmp_acl_nfsv4
MD=`mdconfig -a -t swap -s 128M`
newfs /dev/$MD
tunefs -N enable /dev/$MD
mount /dev/$MD /tmp_acl_nfsv4
chmod 1777 /tmp_acl_nfsv4
pkg install -y autoconf automake cmake gmake libiconv libtool pkgconf expat libxml2 liblz4 zstd
elif [ "$1" = "test" ]
then
set -e
echo "Additional NFSv4 ACL tests"
CURDIR=`pwd`
if [ "${BS}" = "cmake" ]
then
BIN_SUBDIR="bin"
else
BIN_SUBDIR=.
fi
BUILDDIR="${CURDIR}/build_ci/${BS}"
cd "$BUILDDIR"
TMPDIR=/tmp_acl_nfsv4 ${BIN_SUBDIR}/libarchive_test -r "${CURDIR}/libarchive/test" -v test_acl_platform_nfs4
else
echo "Usage: $0 prepare | test"
exit 1
fi
@@ -5,6 +5,9 @@ set -eux
#brew update > /dev/null
#brew upgrade > /dev/null
# Workaround for cmake in local/pinned tap issue
brew uninstall cmake
# This does an upgrade if the package is already installed
brew install \
autoconf \
+15
View File
@@ -0,0 +1,15 @@
{
"dependencies": [
"zlib",
"bzip2",
"liblzma",
"zstd"
],
"vcpkg-configuration": {
"default-registry": {
"kind": "git",
"repository": "https://github.com/microsoft/vcpkg",
"baseline": "44819aa2a6c10e56065e2b0330e7d6c89d1d2574"
}
}
}
+1 -1
View File
@@ -29,5 +29,5 @@ CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/build/pkgconfig/libarchive.pc.in
# And install it, of course ;).
IF(ENABLE_INSTALL)
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/build/pkgconfig/libarchive.pc
DESTINATION "lib/pkgconfig")
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
ENDIF()
+21 -3
View File
@@ -405,6 +405,12 @@ typedef uint64_t uintmax_t;
/* Define to 1 if you have the `chroot' function. */
#cmakedefine HAVE_CHROOT 1
/* Define to 1 if you have the `closefrom' function. */
#cmakedefine HAVE_CLOSEFROM 1
/* Define to 1 if you have the `close_range' function. */
#cmakedefine HAVE_CLOSE_RANGE 1
/* Define to 1 if you have the <copyfile.h> header file. */
#cmakedefine HAVE_COPYFILE_H 1
@@ -636,6 +642,9 @@ typedef uint64_t uintmax_t;
/* Define to 1 if you have the `getea' function. */
#cmakedefine HAVE_GETEA 1
/* Define to 1 if you have the `getegid' function. */
#cmakedefine HAVE_GETEGID 1
/* Define to 1 if you have the `geteuid' function. */
#cmakedefine HAVE_GETEUID 1
@@ -657,6 +666,9 @@ typedef uint64_t uintmax_t;
/* Define to 1 if you have the `getpwuid_r' function. */
#cmakedefine HAVE_GETPWUID_R 1
/* Define to 1 if you have the `gettimeofday' function. */
#cmakedefine HAVE_GETTIMEOFDAY 1
/* Define to 1 if you have the `getvfsbyname' function. */
#cmakedefine HAVE_GETVFSBYNAME 1
@@ -675,6 +687,9 @@ typedef uint64_t uintmax_t;
/* Define to 1 if you have the <iconv.h> header file. */
#cmakedefine HAVE_ICONV_H 1
/* Define to 1 if you have the <intsafe.h> header file. */
#cmakedefine HAVE_INTSAFE_H 1
/* Define to 1 if you have the <inttypes.h> header file. */
#cmakedefine HAVE_INTTYPES_H 1
@@ -970,9 +985,6 @@ typedef uint64_t uintmax_t;
/* Define to 1 if you have the <pwd.h> header file. */
#cmakedefine HAVE_PWD_H 1
/* Define to 1 if you have the `readdir_r' function. */
#cmakedefine HAVE_READDIR_R 1
/* Define to 1 if you have the `readlink' function. */
#cmakedefine HAVE_READLINK 1
@@ -1019,9 +1031,15 @@ typedef uint64_t uintmax_t;
/* Define to 1 if you have the <stdarg.h> header file. */
#cmakedefine HAVE_STDARG_H 1
/* Define to 1 if you have the <stdckdint.h> header file. */
#cmakedefine HAVE_STDCKDINT_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#cmakedefine HAVE_STDINT_H 1
/* Define to 1 if you have the <stdio.h> header file. */
#cmakedefine HAVE_STDIO_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#cmakedefine HAVE_STDLIB_H 1
+13
View File
@@ -0,0 +1,13 @@
# Generated by CMake at configure time -- do not edit.
# Scans test source files for DEFINE_TEST() declarations and writes list.h.
set(_sources @SOURCES@)
set(_output "@OUTPUT@")
file(WRITE "${_output}" "")
foreach(_src ${_sources})
if(_src MATCHES "test_[^/]+\\.c$")
file(STRINGS "${_src}" _lines REGEX "^DEFINE_TEST")
foreach(_line ${_lines})
file(APPEND "${_output}" "${_line}\n")
endforeach()
endif()
endforeach()
+46
View File
@@ -0,0 +1,46 @@
---
BasedOnStyle: Google
AlignAfterOpenBracket: DontAlign
AlignArrayOfStructures: Left
AlignConsecutiveAssignments:
AlignFunctionDeclarations: true
AlignConsecutiveMacros:
Enabled: true
AlignOperands: DontAlign
AllowAllArgumentsOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: Empty
AllowShortEnumsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakBeforeMultilineStrings: false
BinPackParameters: OnePerLine
BreakBeforeTemplateCloser: true
BreakConstructorInitializers: AfterColon
BreakInheritanceList: AfterComma
BreakStringLiterals: false
ColumnLimit: 120
ConstructorInitializerIndentWidth: 8
EnumTrailingComma: Insert
IncludeBlocks: Preserve
IndentCaseLabels: false
IndentGotoLabels: false
IndentPPDirectives: AfterHash
IndentWidth: 8
PPIndentWidth: 1
PackConstructorInitializers: BinPack
PointerAlignment: Right
QualifierAlignment: Left
RemoveEmptyLinesInUnwrappedLines: true
SeparateDefinitionBlocks: Always
SortIncludes:
Enabled: false
SpaceBeforeParens: Custom
SpaceBeforeParensOptions:
AfterControlStatements: false
AfterForeachMacros: false
AfterIfMacros: false
SpacesInContainerLiterals: false
UseTab: ForIndentation
+25
View File
@@ -0,0 +1,25 @@
cmake_minimum_required(VERSION 3.12)
set(CMAKE_CXX_STANDARD 23)
project(libarchive-clang-tools)
find_package(zstd REQUIRED)
find_package(Clang REQUIRED)
add_executable(la-lint)
target_sources(la-lint
PRIVATE
main.cpp
)
target_include_directories(la-lint
PRIVATE
${CLANG_INCLUDE_DIRS}
)
target_link_libraries(la-lint
PRIVATE
LLVM LLVMCore LLVMSupport
libclang clang-cpp
)
install(TARGETS la-lint RUNTIME DESTINATION bin)
+190
View File
@@ -0,0 +1,190 @@
/*-
* Copyright (c) 2026 Dustin L. Howett
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer
* in this position and unchanged.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <clang/Frontend/FrontendActions.h>
#include <clang/Frontend/TextDiagnosticPrinter.h>
#include <clang/Frontend/ChainedDiagnosticConsumer.h>
#include <clang/Tooling/CommonOptionsParser.h>
#include <clang/Tooling/Tooling.h>
#include <clang/ASTMatchers/ASTMatchFinder.h>
#include <llvm/Support/CommandLine.h>
#include <print>
using namespace clang::tooling;
using namespace clang::ast_matchers;
using namespace llvm;
static llvm::cl::OptionCategory LaToolCategory("la-clang-tool options");
static llvm::cl::opt<std::string> Prefix("prefix",
llvm::cl::desc("Project path prefix"),
llvm::cl::init(""),
llvm::cl::cat(LaToolCategory));
static bool IsGithubCiBuild{};
struct MemCmpNeedleHandler : public MatchFinder::MatchCallback {
virtual void run(const MatchFinder::MatchResult &result) {
auto needle = result.Nodes.getNodeAs<clang::StringLiteral>("needle");
auto lenExpr = result.Nodes.getNodeAs<clang::IntegerLiteral>("length");
/*
* This check uses [less than] rather than [less equal] because in some formats we want to verify the
* presence of the null terminator and in others we do not.
*/
if(lenExpr->getValue().ult(needle->getLength())) {
auto &diag = result.Context->getDiagnostics();
auto did = diag.getCustomDiagID(clang::DiagnosticsEngine::Level::Error,
"memcmp needle has length `%0', but is checked with length `%1'");
clang::DiagnosticBuilder db = diag.Report(lenExpr->getLocation(), did);
db.AddTaggedVal(needle->getLength(), clang::DiagnosticsEngine::ArgumentKind::ak_uint);
db.AddTaggedVal(lenExpr->getValue().getSExtValue(),
clang::DiagnosticsEngine::ArgumentKind::ak_sint);
db.AddSourceRange(clang::CharSourceRange::getCharRange(needle->getSourceRange()));
}
}
};
struct AssertUAFHandler : public MatchFinder::MatchCallback {
virtual void run(const MatchFinder::MatchResult &result) {
/*
* This code uses getFileLoc to specify locations disregarding macro expansion
* and to avoid Clang printing "macro expanded from here".
*/
auto &SM = *result.SourceManager;
auto uaf = result.Nodes.getNodeAs<clang::DeclRefExpr>("uaf");
auto assertion = result.Nodes.getNodeAs<clang::CallExpr>("assertion");
auto freed = result.Nodes.getNodeAs<clang::CallExpr>("free");
auto &diag = result.Context->getDiagnostics();
{
auto did = diag.getCustomDiagID(clang::DiagnosticsEngine::Level::Error,
"test assertion uses `%0' after free; prefer assertEqualInt");
clang::DiagnosticBuilder db = diag.Report(SM.getFileLoc(uaf->getBeginLoc()), did);
db.AddString(uaf->getNameInfo().getAsString());
db << clang::FixItHint::CreateReplacement(
clang::SourceRange{SM.getFileLoc(assertion->getBeginLoc()),
SM.getFileLoc(uaf->getBeginLoc())},
"assertEqualInt(");
}
{
auto did = diag.getCustomDiagID(clang::DiagnosticsEngine::Level::Note, "`%0' freed here");
clang::DiagnosticBuilder db = diag.Report(freed->getBeginLoc(), did);
db.AddString(uaf->getNameInfo().getAsString());
}
}
};
class GithubActionDiagnosticConsumer : public clang::DiagnosticConsumer {
virtual void HandleDiagnostic(clang::DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &Info) {
static constexpr const char *levels[] = {nullptr, "notice", "notice", "warning", "error", "error"};
const auto level = levels[DiagLevel];
if(!level)
return;
auto &SM = Info.getSourceManager();
auto loc = Info.getLocation();
loc = SM.getFileLoc(loc);
auto file = SM.getFilename(loc);
if(file.empty()) {
return;
}
file.consume_front_insensitive(Prefix);
while(file.consume_front("/")) {}
bool lineInvalid = false;
auto line = SM.getLineNumber(loc, &lineInvalid);
if(lineInvalid) {
return;
}
llvm::SmallVector<char> diagString;
Info.FormatDiagnostic(diagString);
std::print("::{0} file={1},line={2},title=Lint::{3}\n", level, std::string_view{file}, line,
std::string_view{diagString});
}
};
int main(int argc, const char **argv) {
auto exp = CommonOptionsParser::create(argc, argv, LaToolCategory);
auto &optionsParser = exp.get();
ClangTool tool(optionsParser.getCompilations(), optionsParser.getSourcePathList());
if(const char *e = getenv("GITHUB_WORKSPACE")) {
IsGithubCiBuild = true;
if(Prefix.c_str()[0] == '\0') {
Prefix.assign(e);
Prefix.append("/");
}
}
MatchFinder finder;
/*
* Find every assertion_equal_mem that passes a string literal.
* --> assertEqualMem(foo, "literal", 7);
*/
MemCmpNeedleHandler memCmpHandler;
finder.addMatcher(callExpr(callee(functionDecl(hasName("assertion_equal_mem"))),
hasArgument(4, stringLiteral().bind("needle")),
hasArgument(6, integerLiteral(anything()).bind("length"))),
&memCmpHandler);
/*
* Find every assertion_equal_int whose call site contains a `free` function,
* and then passes the freed decl to assertion_equal_int as context.
* --> assertEqualIntA(a, ARCHIVE_OK, archive_write_free(a));
* ^-- must be the same as ----------^
*/
AssertUAFHandler uafHandler;
finder.addMatcher(
callExpr(callee(functionDecl(hasName("assertion_equal_int"))),
hasArgument(4,
callExpr(callee(functionDecl(matchesName("archive.*_free$"))),
hasArgument(0, declRefExpr(to(varDecl(anything()).bind("freed")))))
.bind("free")),
hasArgument(6, declRefExpr(to(varDecl(declaresSameEntityAsBoundNode("freed")))).bind("uaf")))
.bind("assertion"),
&uafHandler);
std::unique_ptr<clang::DiagnosticConsumer> diagnosticConsumer;
if(IsGithubCiBuild) {
/* Emit GitHub-formatted error messages by default when we are building in GitHub Actions */
clang::DiagnosticOptions diagOptions;
diagOptions.ShowColors = true;
clang::TextDiagnosticPrinter defaultDiag(llvm::errs(), diagOptions, false);
diagnosticConsumer = std::make_unique<clang::ChainedDiagnosticConsumer>(&defaultDiag,
std::make_unique<GithubActionDiagnosticConsumer>());
tool.setDiagnosticConsumer(diagnosticConsumer.get());
}
return tool.run(newFrontendActionFactory(&finder).get());
}
+2 -2
View File
@@ -50,8 +50,8 @@ export MAKE_LIBARCHIVE_RELEASE="1"
/bin/sh build/autogen.sh
# Get the newest config.guess/config.sub from savannah.gnu.org
curl 'http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD' > build/autoconf/config.guess
curl 'http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD' > build/autoconf/config.sub
curl -fsSL 'https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD' > build/autoconf/config.guess
curl -fsSL 'https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD' > build/autoconf/config.sub
./configure
make distcheck
+2 -2
View File
@@ -3,8 +3,8 @@ ENV DEBIAN_FRONTEND=noninteractive
RUN ln -sf /usr/share/zoneinfo/Europe/Berlin /etc/localtime
RUN apt-get update && apt-get install -y build-essential autoconf automake libtool pkg-config cmake zlib1g-dev libssl-dev libacl1-dev libbz2-dev liblzma-dev liblz4-dev libzstd-dev lzop groff ghostscript bsdmainutils zip
ADD . $HOME/libarchive/
ADD "http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD" $HOME/libarchive/build/autoconf/config.guess
ADD "http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD" $HOME/libarchive/build/autoconf/config.sub
ADD "https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD" $HOME/libarchive/build/autoconf/config.guess
ADD "https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD" $HOME/libarchive/build/autoconf/config.sub
WORKDIR $HOME/libarchive
RUN /bin/sh build/clean.sh
RUN /bin/sh build/autogen.sh
+1 -1
View File
@@ -1 +1 @@
3008000
3009000
+2 -2
View File
@@ -13,8 +13,8 @@ IF(ENABLE_CAT)
bsdcat.h
bsdcat_platform.h
cmdline.c
../libarchive_fe/err.c
../libarchive_fe/err.h
../libarchive_fe/lafe_err.c
../libarchive_fe/lafe_err.h
../libarchive_fe/lafe_platform.h
)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../libarchive_fe)
+14 -1
View File
@@ -7,6 +7,9 @@
#include "bsdcat_platform.h"
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
@@ -22,7 +25,7 @@
#include <archive_entry.h>
#include "bsdcat.h"
#include "err.h"
#include "lafe_err.h"
#define BYTES_PER_BLOCK (20*512)
@@ -105,6 +108,16 @@ main(int argc, char **argv)
bsdcat = &bsdcat_storage;
memset(bsdcat, 0, sizeof(*bsdcat));
#if defined(HAVE_SIGACTION) && defined(SIGCHLD)
{ /* Do not ignore SIGCHLD. */
struct sigaction sa;
sa.sa_handler = SIG_DFL;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(SIGCHLD, &sa, NULL);
}
#endif
lafe_setprogname(*argv, "bsdcat");
bsdcat->argv = argv;
+1 -1
View File
@@ -22,7 +22,7 @@
#endif
#include "bsdcat.h"
#include "err.h"
#include "lafe_err.h"
/*
* Short options for bsdcat. Please keep this sorted.
+3 -16
View File
@@ -3,7 +3,7 @@
#
############################################
#
# How to build bsdtar_test
# How to build bsdcat_test
#
############################################
IF(ENABLE_CAT AND ENABLE_TEST)
@@ -51,25 +51,12 @@ IF(ENABLE_CAT AND ENABLE_TEST)
# Generate list.h by grepping DEFINE_TEST() lines out of the C sources.
#
GENERATE_LIST_H(${CMAKE_CURRENT_BINARY_DIR}/list.h
${CMAKE_CURRENT_LIST_FILE} ${bsdcat_test_SOURCES})
${CMAKE_CURRENT_LIST_FILE} bsdcat_test ${bsdcat_test_SOURCES})
SET_PROPERTY(DIRECTORY APPEND PROPERTY INCLUDE_DIRECTORIES
${CMAKE_CURRENT_BINARY_DIR})
# list.h has a line DEFINE_TEST(testname) for every
# test. We can use that to define the tests for cmake by
# defining a DEFINE_TEST macro and reading list.h in.
MACRO (DEFINE_TEST _testname)
ADD_TEST(
NAME bsdcat_${_testname}
COMMAND bsdcat_test -vv
-p $<TARGET_FILE:bsdcat>
-r ${CMAKE_CURRENT_SOURCE_DIR}
-s
${_testname})
SET_TESTS_PROPERTIES(bsdcat_${_testname} PROPERTIES SKIP_RETURN_CODE 2)
ENDMACRO (DEFINE_TEST _testname)
DISCOVER_TESTS(bsdcat ${bsdcat_test_SOURCES})
INCLUDE(${CMAKE_CURRENT_BINARY_DIR}/list.h)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/test_utils)
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/cat/test)
+39 -34
View File
@@ -4,8 +4,8 @@ dnl First, define all of the version numbers up front.
dnl In particular, this allows the version macro to be used in AC_INIT
dnl These first two version numbers are updated automatically on each release.
m4_define([LIBARCHIVE_VERSION_S],[3.8.0dev])
m4_define([LIBARCHIVE_VERSION_N],[3008000])
m4_define([LIBARCHIVE_VERSION_S],[3.9.0dev])
m4_define([LIBARCHIVE_VERSION_N],[3009000])
dnl bsdtar and bsdcpio versioning tracks libarchive
m4_define([BSDTAR_VERSION_S],LIBARCHIVE_VERSION_S())
@@ -101,6 +101,9 @@ esac
AM_CONDITIONAL([INC_WINDOWS_FILES], [test $inc_windows_files = yes])
AM_CONDITIONAL([INC_CYGWIN_FILES], [test $inc_cygwin_files = yes])
dnl On native Windows (MinGW), embedding the manifest needs windres
AS_IF([test $inc_windows_files = yes], [AC_CHECK_TOOL([WINDRES], [windres])])
dnl Defines that are required for specific platforms (e.g. -D_POSIX_SOURCE, etc)
PLATFORMCPPFLAGS=
case "$host_os" in
@@ -258,7 +261,8 @@ AM_CONDITIONAL([STATIC_BSDCPIO], [ test "$static_bsdcpio" = yes ])
case $host in
*mingw* | *cygwin* | *msys* )
AC_PREPROC_IFELSE([AC_LANG_PROGRAM(
[[#ifdef _WIN32_WINNT
[[#include <windows.h>
#ifdef _WIN32_WINNT
# error _WIN32_WINNT already defined
#endif
]],[[;]])
@@ -267,7 +271,8 @@ case $host in
AC_DEFINE([NTDDI_VERSION], 0x05020000, [Define to '0x05020000' for Windows Server 2003 APIs.])
])
AC_PREPROC_IFELSE([AC_LANG_PROGRAM(
[[#ifdef WINVER
[[#include <windows.h>
#ifdef WINVER
# error WINVER already defined
#endif
]],[[;]])
@@ -363,19 +368,20 @@ AS_VAR_IF([ac_cv_have_decl_FS_IOC_GETFLAGS], [yes],
[AC_DEFINE_UNQUOTED([HAVE_WORKING_FS_IOC_GETFLAGS], [1],
[Define to 1 if you have a working FS_IOC_GETFLAGS])])
AC_CHECK_HEADERS([locale.h membership.h paths.h poll.h pthread.h pwd.h])
AC_CHECK_HEADERS([readpassphrase.h signal.h spawn.h])
AC_CHECK_HEADERS([stdarg.h stdint.h stdlib.h string.h])
AC_CHECK_HEADERS([intsafe.h locale.h membership.h paths.h poll.h pthread.h])
AC_CHECK_HEADERS([pwd.h readpassphrase.h signal.h spawn.h])
AC_CHECK_HEADERS([stdarg.h stdckdint.h stdint.h stdlib.h string.h])
AC_CHECK_HEADERS([sys/acl.h sys/cdefs.h sys/ea.h sys/extattr.h])
AC_CHECK_HEADERS([sys/ioctl.h sys/mkdev.h sys/mount.h])
AC_CHECK_HEADERS([sys/param.h sys/poll.h sys/richacl.h])
AC_CHECK_HEADERS([sys/select.h sys/statfs.h sys/statvfs.h sys/sysmacros.h])
AC_CHECK_HEADERS([sys/time.h sys/utime.h sys/utsname.h sys/vfs.h sys/xattr.h])
AC_CHECK_HEADERS([time.h unistd.h utime.h wchar.h wctype.h])
AC_CHECK_HEADERS([sys/select.h sys/statfs.h sys/statvfs.h sys/sysctl.h])
AC_CHECK_HEADERS([sys/sysmacros.h sys/time.h sys/utime.h sys/utsname.h])
AC_CHECK_HEADERS([sys/vfs.h sys/xattr.h time.h unistd.h utime.h wchar.h])
AC_CHECK_HEADERS([wctype.h])
AC_CHECK_TYPE([suseconds_t])
AC_CHECK_HEADERS([windows.h])
# check windows.h first; the other headers require it.
AC_CHECK_HEADERS([wincrypt.h winioctl.h],[],[],
AC_CHECK_HEADERS([winioctl.h],[],[],
[[#ifdef HAVE_WINDOWS_H
# include <windows.h>
#endif
@@ -436,13 +442,15 @@ if test "x$with_bz2lib" != "xno"; then
esac
fi
PKG_PROG_PKG_CONFIG
AC_ARG_WITH([libb2],
AS_HELP_STRING([--without-libb2], [Don't build support for BLAKE2 through libb2]))
if test "x$with_libb2" != "xno"; then
AC_CHECK_HEADERS([blake2.h])
AC_CHECK_LIB(b2,blake2sp_init)
BLAKE2_PC_VER=`pkg-config --modversion libb2`
BLAKE2_PC_VER=`$PKG_CONFIG --modversion libb2`
if test "x$BLAKE2_PC_VER" != "x"; then
AC_DEFINE_UNQUOTED([LIBB2_PKGCONFIG_VERSION], ["$BLAKE2_PC_VER"], [Libb2 version coming from pkg-config.])
fi
@@ -817,16 +825,20 @@ AC_FUNC_VPRINTF
# To avoid necessity for including windows.h or special forward declaration
# workarounds, we use 'void *' for 'struct SECURITY_ATTRIBUTES *'
AC_CHECK_STDCALL_FUNC([CreateHardLinkA],[const char *, const char *, void *])
AC_CHECK_FUNCS([arc4random_buf chflags chown chroot ctime_r])
AC_CHECK_FUNCS([arc4random_buf chflags chown chroot])
AC_CHECK_FUNCS([closefrom close_range ctime_r])
AC_CHECK_FUNCS([fchdir fchflags fchmod fchown fcntl fdopendir fnmatch fork])
AC_CHECK_FUNCS([fstat fstatat fstatfs fstatvfs ftruncate])
AC_CHECK_FUNCS([futimens futimes futimesat])
AC_CHECK_FUNCS([geteuid getline getpid getgrgid_r getgrnam_r])
AC_CHECK_FUNCS([getpwnam_r getpwuid_r getvfsbyname gmtime_r])
AC_CHECK_FUNCS([getegid geteuid getline getpid getresgid getresuid])
AC_CHECK_FUNCS([getgrgid_r getgrnam_r getpwnam_r getpwuid_r])
AC_CHECK_FUNCS([gettimeofday getvfsbyname gmtime_r])
AC_CHECK_FUNCS([issetugid])
AC_CHECK_FUNCS([lchflags lchmod lchown link linkat localtime_r lstat lutimes])
AC_CHECK_FUNCS([mbrtowc memmove memset])
AC_CHECK_FUNCS([mkdir mkfifo mknod mkstemp])
AC_CHECK_FUNCS([nl_langinfo openat pipe poll posix_spawnp readlink readlinkat])
AC_CHECK_FUNCS([nl_langinfo openat pipe poll posix_spawn posix_spawnp])
AC_CHECK_FUNCS([readlink readlinkat])
AC_CHECK_FUNCS([readpassphrase])
AC_CHECK_FUNCS([select setenv setlocale sigaction statfs statvfs])
AC_CHECK_FUNCS([strchr strdup strerror strncpy_s strnlen strrchr symlink])
@@ -877,14 +889,6 @@ AC_CHECK_TYPES(struct statfs,,,
#include <sys/mount.h>
])
# There are several variants of readdir_r around; we only
# accept the POSIX-compliant version.
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([[#include <dirent.h>]],
[[DIR *dir; struct dirent e, *r;
return(readdir_r(dir, &e, &r));]])],
[AC_DEFINE(HAVE_READDIR_R,1,[Define to 1 if you have a POSIX compatible readdir_r])]
)
# dirfd can be either a function or a macro.
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([[#include <dirent.h>
@@ -925,7 +929,7 @@ if test "x$enable_xattr" != "xno"; then
])
AC_CHECK_DECLS([XATTR_NOFOLLOW], [], [], [#include <sys/xattr.h>
])
ATTR_PC_VER=`pkg-config --modversion libattr`
ATTR_PC_VER=`$PKG_CONFIG --modversion libattr`
if test "x$ATTR_PC_VER" != "x"; then
AC_DEFINE_UNQUOTED([LIBATTR_PKGCONFIG_VERSION], ["$ATTR_PC_VER"], [Libattr version coming from pkg-config.])
fi
@@ -1024,7 +1028,7 @@ AC_ARG_ENABLE([acl],
if test "x$enable_acl" != "xno"; then
# Libacl
AC_CHECK_LIB([acl], [acl_get_file])
ACL_PC_VER=`pkg-config --modversion libacl`
ACL_PC_VER=`$PKG_CONFIG --modversion libacl`
if test "x$ACL_PC_VER" != "x"; then
AC_DEFINE_UNQUOTED([LIBACL_PKGCONFIG_VERSION], ["$ACL_PC_VER"], [Libacl version coming from pkg-config.])
fi
@@ -1038,7 +1042,7 @@ if test "x$enable_acl" != "xno"; then
])
AC_CHECK_LIB([richacl], [richacl_get_file])
RICHACL_PC_VER=`pkg-config --modversion librichacl`
RICHACL_PC_VER=`$PKG_CONFIG --modversion librichacl`
if test "x$RICHACL_PC_VER" != "x"; then
AC_DEFINE_UNQUOTED([LIBRICHACL_PKGCONFIG_VERSION], ["$RICHACL_PC_VER"], [Librichacl version coming from pkg-config.])
fi
@@ -1291,24 +1295,26 @@ main(int argc, char **argv)
case "$host_os" in
*mingw* | *cygwin* | *msys*)
;;
*darwin*)
CRYPTO_CHECK(MD5, LIBSYSTEM, md5)
CRYPTO_CHECK(SHA1, LIBSYSTEM, sha1)
CRYPTO_CHECK(SHA256, LIBSYSTEM, sha256)
CRYPTO_CHECK(SHA384, LIBSYSTEM, sha384)
CRYPTO_CHECK(SHA512, LIBSYSTEM, sha512)
;;
*)
CRYPTO_CHECK(MD5, LIBC, md5)
CRYPTO_CHECK(MD5, LIBSYSTEM, md5)
CRYPTO_CHECK(RMD160, LIBC, rmd160)
CRYPTO_CHECK(SHA1, LIBC, sha1)
CRYPTO_CHECK(SHA1, LIBSYSTEM, sha1)
CRYPTO_CHECK(SHA256, LIBC, sha256)
CRYPTO_CHECK(SHA256, LIBC2, sha256)
CRYPTO_CHECK(SHA256, LIBC3, sha256)
CRYPTO_CHECK(SHA256, LIBSYSTEM, sha256)
CRYPTO_CHECK(SHA384, LIBC, sha384)
CRYPTO_CHECK(SHA384, LIBC2, sha384)
CRYPTO_CHECK(SHA384, LIBC3, sha384)
CRYPTO_CHECK(SHA384, LIBSYSTEM, sha384)
CRYPTO_CHECK(SHA512, LIBC, sha512)
CRYPTO_CHECK(SHA512, LIBC2, sha512)
CRYPTO_CHECK(SHA512, LIBC3, sha512)
CRYPTO_CHECK(SHA512, LIBSYSTEM, sha512)
;;
esac
@@ -1373,9 +1379,8 @@ AC_SUBST(LIBSREQUIRED)
# Probe libmd AFTER OpenSSL/libcrypto.
# The two are incompatible and OpenSSL is more complete.
AC_CHECK_HEADERS([md5.h ripemd.h sha.h sha256.h sha512.h])
saved_LIBS=$LIBS
AC_CHECK_LIB(md,MD5Init)
AC_CHECK_LIB(md, MD5Init)
CRYPTO_CHECK(MD5, LIBMD, md5)
CRYPTO_CHECK(RMD160, LIBMD, rmd160)
CRYPTO_CHECK(SHA1, LIBMD, sha1)
+23 -1
View File
@@ -26,6 +26,8 @@ LOCAL_PATH := $(subst /contrib/android,,$(call my-dir))
libarchive_target_config := contrib/android/config/android.h
libarchive_src_files := libarchive/archive_acl.c \
libarchive/archive_blake2s_ref.c \
libarchive/archive_blake2sp_ref.c \
libarchive/archive_check_magic.c \
libarchive/archive_cmdline.c \
libarchive/archive_cryptor.c \
@@ -44,6 +46,7 @@ libarchive_src_files := libarchive/archive_acl.c \
libarchive/archive_parse_date.c \
libarchive/archive_pathmatch.c \
libarchive/archive_ppmd7.c \
libarchive/archive_ppmd8.c \
libarchive/archive_random.c \
libarchive/archive_rb.c \
libarchive/archive_read.c \
@@ -86,6 +89,7 @@ libarchive_src_files := libarchive/archive_acl.c \
libarchive/archive_read_support_format_lha.c \
libarchive/archive_read_support_format_mtree.c \
libarchive/archive_read_support_format_rar.c \
libarchive/archive_read_support_format_rar5.c \
libarchive/archive_read_support_format_raw.c \
libarchive/archive_read_support_format_tar.c \
libarchive/archive_read_support_format_warc.c \
@@ -93,6 +97,7 @@ libarchive_src_files := libarchive/archive_acl.c \
libarchive/archive_read_support_format_zip.c \
libarchive/archive_string.c \
libarchive/archive_string_sprintf.c \
libarchive/archive_time.c \
libarchive/archive_util.c \
libarchive/archive_version_details.c \
libarchive/archive_virtual.c \
@@ -123,7 +128,9 @@ libarchive_src_files := libarchive/archive_acl.c \
libarchive/archive_write_set_format_ar.c \
libarchive/archive_write_set_format_by_name.c \
libarchive/archive_write_set_format_cpio.c \
libarchive/archive_write_set_format_cpio_binary.c \
libarchive/archive_write_set_format_cpio_newc.c \
libarchive/archive_write_set_format_cpio_odc.c \
libarchive/archive_write_set_format_iso9660.c \
libarchive/archive_write_set_format_mtree.c \
libarchive/archive_write_set_format_pax.c \
@@ -151,7 +158,9 @@ else
libarchive_host_src_files :=
endif
libarchive_fe_src_files := libarchive_fe/err.c \
libarchive_fe_src_files := libarchive_fe/lafe_err.c \
libarchive_fe/lafe_fnmatch.c \
libarchive_fe/lafe_getline.c \
libarchive_fe/line_reader.c \
libarchive_fe/passphrase.c
@@ -305,4 +314,17 @@ LOCAL_SRC_FILES := $(bsdcat_src_files)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/libarchive $(LOCAL_PATH)/libarchive_fe $(LOCAL_PATH)/contrib/android/include
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_MODULE := bsdtar-recovery
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_STEM := bsdtar
LOCAL_CFLAGS := -DBSDTAR_VERSION_STRING=ARCHIVE_VERSION_ONLY_STRING -DPLATFORM_CONFIG_H=\"$(libarchive_target_config)\"
LOCAL_STATIC_LIBRARIES := libarchive libarchive_fe libz
LOCAL_SRC_FILES := $(bsdtar_src_files)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/libarchive $(LOCAL_PATH)/libarchive_fe $(LOCAL_PATH)/contrib/android/include
LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
LOCAL_FORCE_STATIC_EXECUTABLE := true
include $(BUILD_EXECUTABLE)
endif
+7 -1
View File
@@ -26,6 +26,8 @@
#ifndef ARCHIVE_PLATFORM_H_ANDROID_INCLUDED
#define ARCHIVE_PLATFORM_H_ANDROID_INCLUDED
#define __LIBARCHIVE_CONFIG_H_INCLUDED 1
#include <android/api-level.h>
#ifdef __ANDROID_API__
#if __ANDROID_API__ > 20
@@ -40,6 +42,8 @@
#define HAVE_CHOWN 1
#define HAVE_CHROOT 1
#define HAVE_CLOSEFROM 0
#define HAVE_CLOSE_RANGE 0
#define HAVE_CTIME_R 1
#define HAVE_CTYPE_H 1
#define HAVE_DECL_EXTATTR_NAMESPACE_USER 0
@@ -53,6 +57,8 @@
#define HAVE_DECL_UINTMAX_MAX 1
#define HAVE_DECL_UINT32_MAX 1
#define HAVE_DECL_UINT64_MAX 1
#define HAVE_DECL_INT32_MAX 1
#define HAVE_DECL_INT32_MIN 1
#define HAVE_DIRENT_H 1
#define HAVE_DIRFD 1
#define HAVE_DLFCN_H 1
@@ -135,7 +141,7 @@
#define HAVE_STRING_H 1
#define HAVE_STRRCHR 1
#define HAVE_STRUCT_STAT_ST_BLKSIZE 1
#define HAVE_STRUCT_STAT_ST_MTIME_NSEC 1
#define HAVE_STRUCT_STAT_ST_MTIME_NSEC 0
#define HAVE_STRUCT_TM_TM_GMTOFF 1
#define HAVE_SYMLINK 1
#define HAVE_SYS_CDEFS_H 1
+3 -1
View File
@@ -28,6 +28,8 @@
#define HAVE_CHOWN 1
#define HAVE_CHROOT 1
#define HAVE_CLOSEFROM 1
#define HAVE_CLOSE_RANGE 1
#define HAVE_CTIME_R 1
#define HAVE_CTYPE_H 1
#define HAVE_DECL_EXTATTR_NAMESPACE_USER 0
@@ -180,7 +182,7 @@
#define HAVE_WMEMCMP 1
#define HAVE_WMEMCPY 1
#define HAVE_ZLIB_H 1
#define ICONV_CONST
#define ICONV_CONST
#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1
#define SIZEOF_WCHAR_T 4
#define STDC_HEADERS 1
+6 -6
View File
@@ -175,6 +175,12 @@
/* Define to 1 if you have the `chroot' function. */
/* #undef HAVE_CHROOT */
/* Define to 1 if you have the `closefrom' function. */
/* #undef HAVE_CLOSEFROM */
/* Define to 1 if you have the `close_range' function. */
/* #undef HAVE_CLOSE_RANGE */
/* Define to 1 if you have the <copyfile.h> header file. */
/* #undef HAVE_COPYFILE_H */
@@ -620,9 +626,6 @@
/* Define to 1 if you have the <pwd.h> header file. */
/* #undef HAVE_PWD_H */
/* Define to 1 if you have a POSIX compatible readdir_r */
#define HAVE_READDIR_R 1
/* Define to 1 if you have the `readlink' function. */
/* #undef HAVE_READLINK */
@@ -896,9 +899,6 @@
/* Define to 1 if you have the <wctype.h> header file. */
#define HAVE_WCTYPE_H 1
/* Define to 1 if you have the <wincrypt.h> header file. */
#define HAVE_WINCRYPT_H 1
/* Define to 1 if you have the <windows.h> header file. */
#define HAVE_WINDOWS_H 1
+1 -2
View File
@@ -1,4 +1,4 @@
/*
/*
* Macros for file64 functions
*
* Android does not support the macro _FILE_OFFSET_BITS=64
@@ -19,7 +19,6 @@
#include <sys/vfs.h>
//dirent.h
#define readdir_r readdir64_r
#define readdir readdir64
#define dirent dirent64
//fcntl.h
+156
View File
@@ -0,0 +1,156 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef LIBARCHIVE_FUZZ_HELPERS_H_
#define LIBARCHIVE_FUZZ_HELPERS_H_
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <ftw.h>
#include <unistd.h>
#include "archive.h"
// Default maximum input size for fuzzers
static constexpr size_t kDefaultMaxInputSize = 256 * 1024; // 256KB
// Buffer structure for archive reading callbacks
struct Buffer {
const uint8_t* data;
size_t size;
size_t pos;
};
// Archive read callback function
static la_ssize_t reader_callback(struct archive* a, void* client_data,
const void** buffer) {
(void)a;
Buffer* buf = static_cast<Buffer*>(client_data);
if (buf->pos >= buf->size) {
return 0; // EOF
}
*buffer = buf->data + buf->pos;
size_t remaining = buf->size - buf->pos;
buf->pos = buf->size; // Consume all remaining data
return static_cast<la_ssize_t>(remaining);
}
// Helper class for consuming fuzz data in structured ways
class DataConsumer {
public:
DataConsumer(const uint8_t* data, size_t size)
: data_(data), size_(size), pos_(0) {}
bool empty() const { return pos_ >= size_; }
size_t remaining() const { return size_ - pos_; }
uint8_t consume_byte() {
if (pos_ >= size_) return 0;
return data_[pos_++];
}
uint16_t consume_u16() {
uint16_t val = 0;
if (pos_ + 2 <= size_) {
val = static_cast<uint16_t>(data_[pos_]) |
(static_cast<uint16_t>(data_[pos_ + 1]) << 8);
pos_ += 2;
}
return val;
}
uint32_t consume_u32() {
uint32_t val = 0;
if (pos_ + 4 <= size_) {
val = static_cast<uint32_t>(data_[pos_]) |
(static_cast<uint32_t>(data_[pos_ + 1]) << 8) |
(static_cast<uint32_t>(data_[pos_ + 2]) << 16) |
(static_cast<uint32_t>(data_[pos_ + 3]) << 24);
pos_ += 4;
}
return val;
}
int64_t consume_i64() {
int64_t val = 0;
if (pos_ + 8 <= size_) {
for (int i = 0; i < 8; i++) {
val |= static_cast<int64_t>(data_[pos_ + i]) << (8 * i);
}
pos_ += 8;
}
return val;
}
// Consume a null-terminated string up to max_len characters
// Returns pointer to internal buffer (valid until next consume_string call)
const char* consume_string(size_t max_len) {
if (max_len > sizeof(string_buf_) - 1) {
max_len = sizeof(string_buf_) - 1;
}
size_t avail = size_ - pos_;
size_t len = (avail < max_len) ? avail : max_len;
size_t actual_len = 0;
while (actual_len < len && pos_ < size_) {
char c = static_cast<char>(data_[pos_++]);
if (c == '\0') break;
string_buf_[actual_len++] = c;
}
string_buf_[actual_len] = '\0';
return string_buf_;
}
// Consume raw bytes into a buffer
size_t consume_bytes(void* out, size_t len) {
size_t avail = size_ - pos_;
size_t to_copy = (avail < len) ? avail : len;
if (to_copy > 0) {
memcpy(out, data_ + pos_, to_copy);
pos_ += to_copy;
}
return to_copy;
}
// Get remaining data as a buffer
const uint8_t* remaining_data() const {
return data_ + pos_;
}
private:
const uint8_t* data_;
size_t size_;
size_t pos_;
char string_buf_[512];
};
// Callback for nftw to remove files/directories
static int remove_callback(const char* fpath, const struct stat* sb,
int typeflag, struct FTW* ftwbuf) {
(void)sb;
(void)typeflag;
(void)ftwbuf;
return remove(fpath);
}
// Recursively remove a directory tree (safer than system("rm -rf ..."))
static int remove_directory_tree(const char* path) {
// nftw with FTW_DEPTH processes directory contents before the directory itself
return nftw(path, remove_callback, 64, FTW_DEPTH | FTW_PHYS);
}
#endif // LIBARCHIVE_FUZZ_HELPERS_H_
@@ -0,0 +1,63 @@
/*
* 7-Zip format specific fuzzer for libarchive
* Targets 7-Zip parsing and decompression code paths
*/
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 512 * 1024; // 512KB
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
// Enable 7-Zip format specifically
archive_read_support_format_7zip(a);
// Enable all filters for 7z internal compression
archive_read_support_filter_all(a);
// Set passphrase for encrypted archives
archive_read_add_passphrase(a, "password");
Buffer buffer = {buf, len, 0};
if (archive_read_open(a, &buffer, NULL, reader_callback, NULL) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(4096, 0);
struct archive_entry *entry;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
// Exercise entry metadata access
archive_entry_pathname(entry);
archive_entry_pathname_w(entry);
archive_entry_size(entry);
archive_entry_mtime(entry);
archive_entry_mode(entry);
archive_entry_is_encrypted(entry);
archive_entry_is_data_encrypted(entry);
archive_entry_is_metadata_encrypted(entry);
// Read data
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0)
;
}
archive_read_free(a);
return 0;
}
@@ -0,0 +1,47 @@
# 7-Zip format dictionary
# Magic bytes
"7z\xbc\xaf\x27\x1c"
"\x37\x7a\xbc\xaf\x27\x1c"
# Common property IDs
"\x00"
"\x01"
"\x02"
"\x03"
"\x04"
"\x05"
"\x06"
"\x07"
"\x08"
"\x09"
"\x0a"
"\x0b"
"\x0c"
"\x0d"
"\x0e"
"\x0f"
"\x10"
"\x11"
"\x17"
"\x19"
"\x21"
"\x23"
"\x24"
"\x25"
# Compression method IDs
"\x00\x00"
"\x00\x03"
"\x00\x04"
"\x00\x06"
"\x01\x01"
"\x03\x01\x01"
"\x04\x01\x08"
"\x04\x02\x02"
"\x21\x01"
"\x30\x01\x01"
# Encryption
"\x06\xf1\x07\x01"
"Password"
"password"
@@ -0,0 +1,10 @@
[libfuzzer]
max_len = 524288
timeout = 60
rss_limit_mb = 2048
[honggfuzz]
timeout = 60
[afl]
timeout = 60
+54
View File
@@ -0,0 +1,54 @@
/*
* AR (Unix archive) format fuzzer for libarchive
* Tests BSD and GNU ar formats
*/
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 512 * 1024;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
archive_read_support_format_ar(a);
archive_read_support_filter_all(a);
Buffer buffer = {buf, len, 0};
if (archive_read_open(a, &buffer, NULL, reader_callback, NULL) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(4096, 0);
struct archive_entry *entry;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
archive_entry_pathname(entry);
archive_entry_size(entry);
archive_entry_mtime(entry);
archive_entry_mode(entry);
archive_entry_uid(entry);
archive_entry_gid(entry);
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0)
;
}
archive_read_free(a);
return 0;
}
@@ -0,0 +1,20 @@
# AR format dictionary
# AR magic
"!<arch>\x0a"
# File header terminator
"\x60\x0a"
# Special entries
"/"
"//"
"/SYM64/"
# Common permissions
"100644 "
"100755 "
# UID/GID fields
"0 "
"1000 "
+51
View File
@@ -0,0 +1,51 @@
/*
* CAB (Microsoft Cabinet) format fuzzer for libarchive
*/
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 512 * 1024;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
archive_read_support_format_cab(a);
archive_read_support_filter_all(a);
Buffer buffer = {buf, len, 0};
if (archive_read_open(a, &buffer, NULL, reader_callback, NULL) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(4096, 0);
struct archive_entry *entry;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
archive_entry_pathname(entry);
archive_entry_size(entry);
archive_entry_mtime(entry);
archive_entry_mode(entry);
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0)
;
}
archive_read_free(a);
return 0;
}
@@ -0,0 +1,23 @@
# CAB (Microsoft Cabinet) format dictionary
# CAB signature
"MSCF"
"\x4d\x53\x43\x46"
# Version
"\x03\x01"
# Compression types
"\x00\x00"
"\x01\x00"
"\x02\x00"
"\x03\x00"
# Folder count patterns
"\x01\x00"
"\x02\x00"
# Header flags
"\x00\x00"
"\x01\x00"
"\x04\x00"
@@ -0,0 +1,58 @@
/*
* CPIO format fuzzer for libarchive
* Tests all CPIO variants: binary, odc, newc, crc
*/
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 512 * 1024;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
archive_read_support_format_cpio(a);
archive_read_support_filter_all(a);
Buffer buffer = {buf, len, 0};
if (archive_read_open(a, &buffer, NULL, reader_callback, NULL) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(4096, 0);
struct archive_entry *entry;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
archive_entry_pathname(entry);
archive_entry_size(entry);
archive_entry_mtime(entry);
archive_entry_mode(entry);
archive_entry_uid(entry);
archive_entry_gid(entry);
archive_entry_ino(entry);
archive_entry_nlink(entry);
archive_entry_rdev(entry);
archive_entry_hardlink(entry);
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0)
;
}
archive_read_free(a);
return 0;
}
@@ -0,0 +1,25 @@
# CPIO format dictionary
# Binary magic (little endian)
"\xc7\x71"
# Binary magic (big endian)
"\x71\xc7"
# ASCII odc magic
"070707"
# ASCII newc magic
"070701"
# ASCII crc magic
"070702"
# Common trailer
"TRAILER!!!"
# Common field patterns
"00000000"
"00000001"
"000001ed"
"000003e8"
@@ -0,0 +1,101 @@
/*
* Encrypted archive fuzzer for libarchive
* Tests password/passphrase handling across formats
*/
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 512 * 1024;
// Passphrase callback for testing
static const char *test_passphrases[] = {
"password",
"test",
"123456",
"",
"secret",
NULL
};
static int passphrase_idx = 0;
static const char* passphrase_callback(struct archive *a, void *client_data) {
(void)a;
(void)client_data;
const char *pass = test_passphrases[passphrase_idx];
if (pass != NULL) {
passphrase_idx++;
}
return pass;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
// Reset passphrase index
passphrase_idx = 0;
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
// Enable all formats that support encryption
archive_read_support_format_zip(a);
archive_read_support_format_7zip(a);
archive_read_support_format_rar(a);
archive_read_support_format_rar5(a);
archive_read_support_filter_all(a);
// Set up passphrase callback
archive_read_set_passphrase_callback(a, NULL, passphrase_callback);
// Also add some static passphrases
archive_read_add_passphrase(a, "password");
archive_read_add_passphrase(a, "test123");
Buffer buffer = {buf, len, 0};
if (archive_read_open(a, &buffer, NULL, reader_callback, NULL) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(4096, 0);
struct archive_entry *entry;
int entry_count = 0;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK && entry_count < 100) {
archive_entry_pathname(entry);
// Check encryption status
int is_encrypted = archive_entry_is_encrypted(entry);
int is_data_encrypted = archive_entry_is_data_encrypted(entry);
int is_meta_encrypted = archive_entry_is_metadata_encrypted(entry);
(void)is_encrypted;
(void)is_data_encrypted;
(void)is_meta_encrypted;
// Check if archive has encrypted entries
archive_read_has_encrypted_entries(a);
// Try to read data (may fail due to wrong password)
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0)
;
entry_count++;
}
archive_read_free(a);
return 0;
}
@@ -0,0 +1,10 @@
[libfuzzer]
max_len = 524288
timeout = 60
rss_limit_mb = 2048
[honggfuzz]
timeout = 60
[afl]
timeout = 60
+105
View File
@@ -0,0 +1,105 @@
/*
* Archive entry fuzzer for libarchive
* Targets archive_entry_* functions including ACL, linkify, and metadata
*/
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 64 * 1024; // 64KB
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
DataConsumer consumer(buf, len);
struct archive_entry *entry = archive_entry_new();
if (entry == NULL) {
return 0;
}
// Set basic entry properties
archive_entry_set_pathname(entry, consumer.consume_string(256));
archive_entry_set_size(entry, consumer.consume_i64());
archive_entry_set_mode(entry, consumer.consume_u32());
archive_entry_set_uid(entry, consumer.consume_u32());
archive_entry_set_gid(entry, consumer.consume_u32());
archive_entry_set_mtime(entry, consumer.consume_i64(), 0);
archive_entry_set_atime(entry, consumer.consume_i64(), 0);
archive_entry_set_ctime(entry, consumer.consume_i64(), 0);
archive_entry_set_birthtime(entry, consumer.consume_i64(), 0);
// Set various string fields
archive_entry_set_uname(entry, consumer.consume_string(64));
archive_entry_set_gname(entry, consumer.consume_string(64));
archive_entry_set_symlink(entry, consumer.consume_string(256));
archive_entry_set_hardlink(entry, consumer.consume_string(256));
// Exercise ACL functions (low coverage targets)
int acl_type = consumer.consume_byte() & 0x0F;
int acl_permset = consumer.consume_u32();
int acl_tag = consumer.consume_byte() & 0x0F;
int acl_qual = consumer.consume_u32();
const char *acl_name = consumer.consume_string(64);
archive_entry_acl_add_entry(entry, acl_type, acl_permset, acl_tag, acl_qual, acl_name);
// Add more ACL entries based on remaining data
while (!consumer.empty() && consumer.remaining() > 10) {
acl_type = consumer.consume_byte() & 0x0F;
acl_permset = consumer.consume_u32();
acl_tag = consumer.consume_byte() & 0x0F;
acl_qual = consumer.consume_u32();
acl_name = consumer.consume_string(32);
archive_entry_acl_add_entry(entry, acl_type, acl_permset, acl_tag, acl_qual, acl_name);
}
// Exercise ACL text conversion functions (archive_acl_to_text_* are uncovered)
ssize_t text_len;
char *acl_text = archive_entry_acl_to_text(entry, &text_len, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
if (acl_text) {
// Parse the text back
archive_entry_acl_from_text(entry, acl_text, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
free(acl_text);
}
acl_text = archive_entry_acl_to_text(entry, &text_len, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
if (acl_text) {
free(acl_text);
}
acl_text = archive_entry_acl_to_text(entry, &text_len, ARCHIVE_ENTRY_ACL_TYPE_NFS4);
if (acl_text) {
free(acl_text);
}
// Exercise wide character versions
wchar_t *acl_text_w = archive_entry_acl_to_text_w(entry, &text_len, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
if (acl_text_w) {
free(acl_text_w);
}
// Get pathname variants
archive_entry_pathname(entry);
archive_entry_pathname_w(entry);
archive_entry_pathname_utf8(entry);
// Clone the entry
struct archive_entry *entry2 = archive_entry_clone(entry);
if (entry2) {
archive_entry_free(entry2);
}
// Clear and reuse
archive_entry_clear(entry);
archive_entry_free(entry);
return 0;
}
@@ -0,0 +1,65 @@
/*
* Compression filter fuzzer for libarchive
* Tests decompression of gzip, bzip2, xz, lzma, zstd, lz4, etc.
*/
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 256 * 1024;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
// Enable raw format (just decompress, no archive format)
archive_read_support_format_raw(a);
// Enable all compression filters
archive_read_support_filter_all(a);
Buffer buffer = {buf, len, 0};
if (archive_read_open(a, &buffer, NULL, reader_callback, NULL) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(8192, 0);
struct archive_entry *entry;
if (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
// Get filter info
int filter_count = archive_filter_count(a);
for (int i = 0; i < filter_count; i++) {
archive_filter_name(a, i);
archive_filter_code(a, i);
archive_filter_bytes(a, i);
}
// Read all decompressed data
ssize_t total = 0;
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0) {
total += r;
// Limit total decompressed size to prevent zip bombs
if (total > 10 * 1024 * 1024) {
break;
}
}
}
archive_read_free(a);
return 0;
}
@@ -0,0 +1,33 @@
# Compression filter dictionary
# GZIP magic
"\x1f\x8b"
"\x1f\x8b\x08"
# BZIP2 magic
"BZh"
"BZ0"
# XZ magic
"\xfd7zXZ\x00"
# LZMA magic
"\x5d\x00\x00"
# ZSTD magic
"\x28\xb5\x2f\xfd"
# LZ4 magic
"\x04\x22\x4d\x18"
# Compress (.Z) magic
"\x1f\x9d"
# LZIP magic
"LZIP"
# LRZIP magic
"LRZI"
# LZO magic
"\x89LZO\x00\x0d\x0a\x1a\x0a"
@@ -0,0 +1,10 @@
[libfuzzer]
max_len = 262144
timeout = 30
rss_limit_mb = 2048
[honggfuzz]
timeout = 30
[afl]
timeout = 30
+2 -15
View File
@@ -3,20 +3,7 @@
#include <vector>
#include "archive.h"
struct Buffer {
const uint8_t *buf;
size_t len;
};
ssize_t reader_callback(struct archive *a, void *client_data,
const void **block) {
Buffer *buffer = reinterpret_cast<Buffer *>(client_data);
*block = buffer->buf;
ssize_t len = buffer->len;
buffer->len = 0;
return len;
}
#include "fuzz_helpers.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
int ret;
@@ -26,7 +13,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
archive_read_support_filter_all(a);
archive_read_support_format_all(a);
Buffer buffer = {buf, len};
Buffer buffer = {buf, len, 0};
archive_read_open(a, &buffer, NULL, reader_callback, NULL);
std::vector<uint8_t> data_buffer(getpagesize(), 0);
+76
View File
@@ -0,0 +1,76 @@
# General libarchive dictionary covering multiple formats
# TAR magic
"ustar"
"ustar\x00"
"ustar \x00"
"\x00\x00"
# ZIP magic
"PK\x03\x04"
"PK\x05\x06"
"PK\x01\x02"
"PK\x07\x08"
# 7z magic
"7z\xbc\xaf\x27\x1c"
# RAR magic
"Rar!\x1a\x07\x00"
"Rar!\x1a\x07\x01\x00"
# XAR magic
"xar!"
# CPIO magic
"\xc7\x71"
"070701"
"070702"
"070707"
# CAB magic
"MSCF"
# LHA magic
"-lh"
"-lz"
# AR magic
"!<arch>\x0a"
# ISO9660 magic
"CD001"
# GZIP magic
"\x1f\x8b"
# BZIP2 magic
"BZ"
"BZh"
# XZ magic
"\xfd7zXZ\x00"
# LZMA magic
"\x5d\x00\x00"
# ZSTD magic
"\x28\xb5\x2f\xfd"
# LZ4 magic
"\x04\x22\x4d\x18"
# Common paths
"/"
"./"
"../"
"./test"
"test.txt"
"test/"
# Common attributes
"\x00\x00\x00\x00"
"\xff\xff\xff\xff"
# Passphrase
"password"
@@ -0,0 +1,9 @@
[libfuzzer]
max_len = 524288
timeout = 30
[honggfuzz]
timeout = 30
[afl]
timeout = 30
@@ -0,0 +1,58 @@
/*
* ISO9660 format fuzzer for libarchive
* Tests ISO, Joliet, and Rock Ridge extensions
*/
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 1024 * 1024; // 1MB for ISO images
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
archive_read_support_format_iso9660(a);
archive_read_support_filter_all(a);
// Set options to test various ISO extensions
archive_read_set_options(a, "iso9660:joliet,iso9660:rockridge");
Buffer buffer = {buf, len, 0};
if (archive_read_open(a, &buffer, NULL, reader_callback, NULL) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(4096, 0);
struct archive_entry *entry;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
archive_entry_pathname(entry);
archive_entry_pathname_w(entry);
archive_entry_size(entry);
archive_entry_mtime(entry);
archive_entry_mode(entry);
archive_entry_symlink(entry);
archive_entry_hardlink(entry);
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0)
;
}
archive_read_free(a);
return 0;
}
@@ -0,0 +1,36 @@
# ISO9660 format dictionary
# Volume descriptor type
"\x00"
"\x01"
"\x02"
"\xff"
# Standard identifier
"CD001"
# Volume descriptor version
"\x01"
# Joliet escape sequences
"%/@"
"%/C"
"%/E"
# Rock Ridge signatures
"SP"
"RR"
"CE"
"PX"
"PN"
"SL"
"NM"
"CL"
"PL"
"RE"
"TF"
"SF"
# System use
"ER"
"ES"
@@ -0,0 +1,10 @@
[libfuzzer]
max_len = 1048576
timeout = 60
rss_limit_mb = 2048
[honggfuzz]
timeout = 60
[afl]
timeout = 60
+54
View File
@@ -0,0 +1,54 @@
/*
* LHA/LZH format fuzzer for libarchive
*/
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 512 * 1024;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
archive_read_support_format_lha(a);
archive_read_support_filter_all(a);
Buffer buffer = {buf, len, 0};
if (archive_read_open(a, &buffer, NULL, reader_callback, NULL) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(4096, 0);
struct archive_entry *entry;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
archive_entry_pathname(entry);
archive_entry_pathname_w(entry);
archive_entry_size(entry);
archive_entry_mtime(entry);
archive_entry_mode(entry);
archive_entry_uid(entry);
archive_entry_gid(entry);
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0)
;
}
archive_read_free(a);
return 0;
}
@@ -0,0 +1,26 @@
# LHA/LZH format dictionary
# Compression methods
"-lh0-"
"-lh1-"
"-lh2-"
"-lh3-"
"-lh4-"
"-lh5-"
"-lh6-"
"-lh7-"
"-lhd-"
"-lzs-"
"-lz4-"
"-lz5-"
# OS type
"\x00"
"\x4d"
"\x55"
# Header levels
"\x00"
"\x01"
"\x02"
"\x03"
@@ -0,0 +1,115 @@
/*
* Archive entry link resolver fuzzer for libarchive
* Targets archive_entry_linkify (complexity: 775, zero coverage)
*/
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 64 * 1024; // 64KB
// Simple data consumer
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
DataConsumer consumer(buf, len);
// Create a link resolver
struct archive_entry_linkresolver *resolver = archive_entry_linkresolver_new();
if (resolver == NULL) {
return 0;
}
// Set the format strategy based on input
uint8_t strategy = consumer.consume_byte() % 5;
int format;
switch (strategy) {
case 0: format = ARCHIVE_FORMAT_TAR_GNUTAR; break;
case 1: format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE; break;
case 2: format = ARCHIVE_FORMAT_CPIO_POSIX; break;
case 3: format = ARCHIVE_FORMAT_CPIO_SVR4_NOCRC; break;
default: format = ARCHIVE_FORMAT_TAR_USTAR; break;
}
archive_entry_linkresolver_set_strategy(resolver, format);
// Create multiple entries to test linkify with hardlinks
struct archive_entry *entries[32];
int num_entries = 0;
while (!consumer.empty() && num_entries < 32 && consumer.remaining() > 20) {
struct archive_entry *entry = archive_entry_new();
if (entry == NULL) break;
// Set pathname
archive_entry_set_pathname(entry, consumer.consume_string(64));
// Set inode and device for hardlink detection
archive_entry_set_ino(entry, consumer.consume_i64());
archive_entry_set_dev(entry, consumer.consume_u32());
archive_entry_set_nlink(entry, (consumer.consume_byte() % 5) + 1);
// Set mode (regular file or directory)
uint8_t ftype = consumer.consume_byte() % 2;
mode_t mode = ftype ? (S_IFDIR | 0755) : (S_IFREG | 0644);
archive_entry_set_mode(entry, mode);
archive_entry_set_size(entry, consumer.consume_i64() & 0xFFFF);
archive_entry_set_uid(entry, consumer.consume_u32() & 0xFFFF);
archive_entry_set_gid(entry, consumer.consume_u32() & 0xFFFF);
entries[num_entries++] = entry;
}
// Now run all entries through the linkresolver
for (int i = 0; i < num_entries; i++) {
struct archive_entry *entry = entries[i];
struct archive_entry *spare = NULL;
// This is the main function we want to fuzz (zero coverage)
archive_entry_linkify(resolver, &entry, &spare);
// Update entries[i] to reflect ownership changes from linkify.
// If linkify cached the entry internally, entry is now NULL and the
// resolver owns the object. If linkify swapped it with a previously
// cached entry, entry points to that other object.
entries[i] = entry;
// Free any entry returned via spare (complete hardlink pair)
if (spare != NULL) {
archive_entry_free(spare);
}
}
// Free remaining entries from the resolver (drain loop)
struct archive_entry *entry = NULL;
struct archive_entry *spare = NULL;
while (1) {
archive_entry_linkify(resolver, &entry, &spare);
if (entry == NULL)
break;
archive_entry_free(entry);
entry = NULL;
if (spare != NULL) {
archive_entry_free(spare);
spare = NULL;
}
}
// Free all our created entries that were NOT consumed by the resolver
for (int i = 0; i < num_entries; i++) {
if (entries[i] != NULL) {
archive_entry_free(entries[i]);
}
}
archive_entry_linkresolver_free(resolver);
return 0;
}
@@ -0,0 +1,96 @@
/*
* Archive match fuzzer for libarchive
* Tests pattern matching, time matching, and owner matching
*/
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 32 * 1024;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
DataConsumer consumer(buf, len);
struct archive *match = archive_match_new();
if (match == NULL) {
return 0;
}
// Add various match patterns
while (!consumer.empty() && consumer.remaining() > 5) {
uint8_t match_type = consumer.consume_byte() % 6;
switch (match_type) {
case 0: {
// Pattern exclusion
const char *pattern = consumer.consume_string(64);
archive_match_exclude_pattern(match, pattern);
break;
}
case 1: {
// Pattern inclusion
const char *pattern = consumer.consume_string(64);
archive_match_include_pattern(match, pattern);
break;
}
case 2: {
// Time comparison (newer than)
int64_t sec = consumer.consume_i64();
int64_t nsec = consumer.consume_i64() % 1000000000;
archive_match_include_time(match, ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_NEWER,
sec, nsec);
break;
}
case 3: {
// Time comparison (older than)
int64_t sec = consumer.consume_i64();
int64_t nsec = consumer.consume_i64() % 1000000000;
archive_match_include_time(match, ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_OLDER,
sec, nsec);
break;
}
case 4: {
// UID inclusion
int64_t uid = consumer.consume_i64() & 0xFFFF;
archive_match_include_uid(match, uid);
break;
}
case 5: {
// GID inclusion
int64_t gid = consumer.consume_i64() & 0xFFFF;
archive_match_include_gid(match, gid);
break;
}
}
}
// Create a test entry and check if it matches
struct archive_entry *entry = archive_entry_new();
if (entry) {
archive_entry_set_pathname(entry, "test/file.txt");
archive_entry_set_mtime(entry, 1234567890, 0);
archive_entry_set_uid(entry, 1000);
archive_entry_set_gid(entry, 1000);
archive_entry_set_mode(entry, 0644 | 0100000); // Regular file
// Test matching
archive_match_path_excluded(match, entry);
archive_match_time_excluded(match, entry);
archive_match_owner_excluded(match, entry);
archive_match_excluded(match, entry);
archive_entry_free(entry);
}
archive_match_free(match);
return 0;
}
@@ -0,0 +1,61 @@
/*
* MTREE format fuzzer for libarchive
* Tests mtree manifest parsing
*/
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 256 * 1024;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
archive_read_support_format_mtree(a);
archive_read_support_filter_all(a);
// Enable checkfs option to test more code paths
archive_read_set_options(a, "mtree:checkfs");
Buffer buffer = {buf, len, 0};
if (archive_read_open(a, &buffer, NULL, reader_callback, NULL) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(4096, 0);
struct archive_entry *entry;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
archive_entry_pathname(entry);
archive_entry_size(entry);
archive_entry_mtime(entry);
archive_entry_mode(entry);
archive_entry_uid(entry);
archive_entry_gid(entry);
archive_entry_uname(entry);
archive_entry_gname(entry);
archive_entry_symlink(entry);
archive_entry_fflags_text(entry);
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0)
;
}
archive_read_free(a);
return 0;
}
@@ -0,0 +1,47 @@
# MTREE format dictionary
# Keywords
"/set"
"/unset"
".."
# File types
"type=file"
"type=dir"
"type=link"
"type=block"
"type=char"
"type=fifo"
"type=socket"
# Attributes
"mode="
"uid="
"gid="
"uname="
"gname="
"size="
"time="
"link="
"cksum="
"md5="
"md5digest="
"sha1="
"sha1digest="
"sha256="
"sha256digest="
"sha384="
"sha384digest="
"sha512="
"sha512digest="
"rmd160="
"rmd160digest="
"flags="
"nlink="
"inode="
"device="
"resdevice="
"contents="
"optional"
"ignore"
"nochange"
@@ -0,0 +1,61 @@
/*
* RAR5 format specific fuzzer for libarchive
* Targets RAR5 parsing code paths
*/
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 512 * 1024; // 512KB
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
// Enable RAR5 format specifically
archive_read_support_format_rar5(a);
// Enable common filters
archive_read_support_filter_all(a);
// Set passphrase for encrypted archives
archive_read_add_passphrase(a, "password");
Buffer buffer = {buf, len, 0};
if (archive_read_open(a, &buffer, NULL, reader_callback, NULL) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(4096, 0);
struct archive_entry *entry;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
// Exercise entry metadata access
archive_entry_pathname(entry);
archive_entry_pathname_w(entry);
archive_entry_size(entry);
archive_entry_mtime(entry);
archive_entry_mode(entry);
archive_entry_is_encrypted(entry);
// Read data
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0)
;
}
archive_read_free(a);
return 0;
}
@@ -0,0 +1,37 @@
# RAR5 format dictionary
# Magic bytes (RAR5 signature)
"Rar!\x1a\x07\x01\x00"
"\x52\x61\x72\x21\x1a\x07\x01\x00"
# Common header types
"\x01"
"\x02"
"\x03"
"\x04"
"\x05"
# Common flags
"\x00\x00"
"\x01\x00"
"\x02\x00"
"\x04\x00"
# Compression methods
"\x00"
"\x01"
"\x02"
"\x03"
"\x04"
"\x05"
# File attributes
"\x20\x00\x00\x00"
"\x10\x00\x00\x00"
# Encryption marker
"\x80"
"password"
"Password"
# End of archive
"\x1d\x77\x56\x51\x03\x05\x04\x00"
+56
View File
@@ -0,0 +1,56 @@
/*
* RAR v4 format fuzzer for libarchive
*/
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 512 * 1024;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
archive_read_support_format_rar(a);
archive_read_support_filter_all(a);
// Add passphrase for encrypted RARs
archive_read_add_passphrase(a, "password");
Buffer buffer = {buf, len, 0};
if (archive_read_open(a, &buffer, NULL, reader_callback, NULL) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(4096, 0);
struct archive_entry *entry;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
archive_entry_pathname(entry);
archive_entry_pathname_w(entry);
archive_entry_size(entry);
archive_entry_mtime(entry);
archive_entry_mode(entry);
archive_entry_is_encrypted(entry);
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0)
;
}
archive_read_free(a);
return 0;
}
@@ -0,0 +1,76 @@
/*
* Archive read disk fuzzer for libarchive
* Tests filesystem traversal and entry creation from paths
* Security-critical: path traversal, symlink handling
*/
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 16 * 1024;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
DataConsumer consumer(buf, len);
struct archive *a = archive_read_disk_new();
if (a == NULL) {
return 0;
}
// Configure disk reader behavior
uint8_t flags = consumer.consume_byte();
if (flags & 0x01) {
archive_read_disk_set_symlink_logical(a);
} else if (flags & 0x02) {
archive_read_disk_set_symlink_physical(a);
} else {
archive_read_disk_set_symlink_hybrid(a);
}
archive_read_disk_set_standard_lookup(a);
// Set behavior flags
int behavior = 0;
if (flags & 0x04) behavior |= ARCHIVE_READDISK_RESTORE_ATIME;
if (flags & 0x08) behavior |= ARCHIVE_READDISK_HONOR_NODUMP;
if (flags & 0x10) behavior |= ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS;
archive_read_disk_set_behavior(a, behavior);
// Create an entry and test entry_from_file with various paths
struct archive_entry *entry = archive_entry_new();
if (entry) {
// Test with /tmp (safe, always exists)
archive_entry_copy_pathname(entry, "/tmp");
archive_read_disk_entry_from_file(a, entry, -1, NULL);
// Get entry info
archive_entry_pathname(entry);
archive_entry_size(entry);
archive_entry_mode(entry);
archive_entry_uid(entry);
archive_entry_gid(entry);
// Test name lookups
archive_read_disk_gname(a, 0);
archive_read_disk_uname(a, 0);
archive_read_disk_gname(a, 1000);
archive_read_disk_uname(a, 1000);
archive_entry_free(entry);
}
archive_read_free(a);
return 0;
}
@@ -0,0 +1,110 @@
/*
* Archive roundtrip fuzzer for libarchive
* Writes an archive then reads it back - tests write/read consistency
*/
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 64 * 1024;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len < 10 || len > kMaxInputSize) {
return 0;
}
DataConsumer consumer(buf, len);
std::vector<uint8_t> archive_data;
archive_data.reserve(len * 2);
// Phase 1: Write an archive
struct archive *writer = archive_write_new();
if (writer == NULL) {
return 0;
}
// Select format
uint8_t format = consumer.consume_byte() % 5;
switch (format) {
case 0: archive_write_set_format_pax_restricted(writer); break;
case 1: archive_write_set_format_ustar(writer); break;
case 2: archive_write_set_format_cpio_newc(writer); break;
case 3: archive_write_set_format_zip(writer); break;
default: archive_write_set_format_gnutar(writer); break;
}
archive_write_add_filter_none(writer);
// Open to memory
size_t used = 0;
archive_data.resize(len * 4);
if (archive_write_open_memory(writer, archive_data.data(), archive_data.size(), &used) != ARCHIVE_OK) {
archive_write_free(writer);
return 0;
}
// Write entries
int entry_count = 0;
while (!consumer.empty() && entry_count < 5 && consumer.remaining() > 10) {
struct archive_entry *entry = archive_entry_new();
if (entry == NULL) break;
archive_entry_set_pathname(entry, consumer.consume_string(32));
archive_entry_set_mode(entry, S_IFREG | 0644);
archive_entry_set_uid(entry, consumer.consume_u32() & 0xFFFF);
archive_entry_set_gid(entry, consumer.consume_u32() & 0xFFFF);
uint8_t data_buf[256];
size_t data_len = consumer.consume_bytes(data_buf, 256);
archive_entry_set_size(entry, data_len);
if (archive_write_header(writer, entry) == ARCHIVE_OK && data_len > 0) {
archive_write_data(writer, data_buf, data_len);
}
archive_entry_free(entry);
entry_count++;
}
archive_write_close(writer);
archive_write_free(writer);
if (used == 0) {
return 0;
}
// Phase 2: Read the archive back
struct archive *reader = archive_read_new();
if (reader == NULL) {
return 0;
}
archive_read_support_format_all(reader);
archive_read_support_filter_all(reader);
if (archive_read_open_memory(reader, archive_data.data(), used) != ARCHIVE_OK) {
archive_read_free(reader);
return 0;
}
std::vector<uint8_t> read_buffer(4096, 0);
struct archive_entry *entry;
while (archive_read_next_header(reader, &entry) == ARCHIVE_OK) {
archive_entry_pathname(entry);
archive_entry_size(entry);
ssize_t r;
while ((r = archive_read_data(reader, read_buffer.data(), read_buffer.size())) > 0)
;
}
archive_read_free(reader);
return 0;
}
@@ -0,0 +1,3 @@
[libfuzzer]
max_len = 65536
timeout = 30
+125
View File
@@ -0,0 +1,125 @@
/*
* Archive seek/read fuzzer for libarchive
* Tests seeking within archives and reading at random positions
*/
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 256 * 1024;
struct SeekableBuffer {
const uint8_t *buf;
size_t len;
size_t pos;
};
static ssize_t seek_read_callback(struct archive *a, void *client_data,
const void **block) {
(void)a;
SeekableBuffer *buffer = reinterpret_cast<SeekableBuffer *>(client_data);
if (buffer->pos >= buffer->len) {
*block = NULL;
return 0;
}
*block = buffer->buf + buffer->pos;
size_t avail = buffer->len - buffer->pos;
size_t to_read = (avail > 4096) ? 4096 : avail;
buffer->pos += to_read;
return to_read;
}
static la_int64_t seek_callback(struct archive *a, void *client_data,
la_int64_t offset, int whence) {
(void)a;
SeekableBuffer *buffer = reinterpret_cast<SeekableBuffer *>(client_data);
la_int64_t new_pos;
switch (whence) {
case SEEK_SET:
new_pos = offset;
break;
case SEEK_CUR:
new_pos = static_cast<la_int64_t>(buffer->pos) + offset;
break;
case SEEK_END:
new_pos = static_cast<la_int64_t>(buffer->len) + offset;
break;
default:
return ARCHIVE_FATAL;
}
if (new_pos < 0) new_pos = 0;
if (new_pos > static_cast<la_int64_t>(buffer->len))
new_pos = static_cast<la_int64_t>(buffer->len);
buffer->pos = static_cast<size_t>(new_pos);
return new_pos;
}
static la_int64_t skip_callback(struct archive *a, void *client_data,
la_int64_t request) {
(void)a;
SeekableBuffer *buffer = reinterpret_cast<SeekableBuffer *>(client_data);
size_t avail = buffer->len - buffer->pos;
la_int64_t to_skip = (request > static_cast<la_int64_t>(avail))
? static_cast<la_int64_t>(avail)
: request;
buffer->pos += static_cast<size_t>(to_skip);
return to_skip;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
// Enable formats that benefit from seeking
archive_read_support_format_zip_seekable(a);
archive_read_support_format_7zip(a);
archive_read_support_format_rar(a);
archive_read_support_format_rar5(a);
archive_read_support_format_iso9660(a);
archive_read_support_filter_all(a);
SeekableBuffer buffer = {buf, len, 0};
archive_read_set_read_callback(a, seek_read_callback);
archive_read_set_seek_callback(a, seek_callback);
archive_read_set_skip_callback(a, skip_callback);
archive_read_set_callback_data(a, &buffer);
if (archive_read_open1(a) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(4096, 0);
struct archive_entry *entry;
int entry_count = 0;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK && entry_count < 50) {
archive_entry_pathname(entry);
archive_entry_size(entry);
// Read data which may trigger seeks
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0)
;
entry_count++;
}
archive_read_free(a);
return 0;
}
@@ -0,0 +1,3 @@
[libfuzzer]
max_len = 262144
timeout = 30
@@ -0,0 +1,144 @@
/*
* Archive string/encoding conversion fuzzer for libarchive
* Tests character encoding conversions which are often vulnerability sources
*/
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 32 * 1024;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive_entry *entry = archive_entry_new();
if (entry == NULL) {
return 0;
}
// Reserve some bytes for control
if (len < 4) {
archive_entry_free(entry);
return 0;
}
uint8_t test_type = buf[0];
const char *str = reinterpret_cast<const char*>(buf + 1);
size_t str_len = len - 1;
// Ensure null termination for string operations
char *safe_str = static_cast<char*>(malloc(str_len + 1));
if (safe_str == NULL) {
archive_entry_free(entry);
return 0;
}
memcpy(safe_str, str, str_len);
safe_str[str_len] = '\0';
// Test various string functions based on type
switch (test_type % 10) {
case 0:
// Pathname conversions
archive_entry_set_pathname(entry, safe_str);
archive_entry_pathname(entry);
archive_entry_pathname_w(entry);
archive_entry_pathname_utf8(entry);
break;
case 1:
// Symlink conversions
archive_entry_set_symlink(entry, safe_str);
archive_entry_symlink(entry);
archive_entry_symlink_w(entry);
archive_entry_symlink_utf8(entry);
break;
case 2:
// Hardlink conversions
archive_entry_set_hardlink(entry, safe_str);
archive_entry_hardlink(entry);
archive_entry_hardlink_w(entry);
archive_entry_hardlink_utf8(entry);
break;
case 3:
// Username conversions
archive_entry_set_uname(entry, safe_str);
archive_entry_uname(entry);
archive_entry_uname_w(entry);
archive_entry_uname_utf8(entry);
break;
case 4:
// Group name conversions
archive_entry_set_gname(entry, safe_str);
archive_entry_gname(entry);
archive_entry_gname_w(entry);
archive_entry_gname_utf8(entry);
break;
case 5:
// Copy functions
archive_entry_copy_pathname(entry, safe_str);
archive_entry_copy_symlink(entry, safe_str);
archive_entry_copy_hardlink(entry, safe_str);
break;
case 6:
// UTF-8 specific
archive_entry_update_pathname_utf8(entry, safe_str);
archive_entry_update_symlink_utf8(entry, safe_str);
archive_entry_update_hardlink_utf8(entry, safe_str);
break;
case 7:
// Fflags text
archive_entry_copy_fflags_text(entry, safe_str);
archive_entry_fflags_text(entry);
break;
case 8:
// ACL text parsing
archive_entry_acl_from_text(entry, safe_str, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
archive_entry_acl_from_text(entry, safe_str, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
archive_entry_acl_from_text(entry, safe_str, ARCHIVE_ENTRY_ACL_TYPE_NFS4);
break;
case 9: {
// Wide character operations
size_t wlen = str_len;
wchar_t *wstr = static_cast<wchar_t*>(malloc((wlen + 1) * sizeof(wchar_t)));
if (wstr) {
mbstowcs(wstr, safe_str, wlen);
wstr[wlen] = L'\0';
archive_entry_copy_pathname_w(entry, wstr);
archive_entry_pathname_w(entry);
archive_entry_copy_symlink_w(entry, wstr);
archive_entry_symlink_w(entry);
free(wstr);
}
break;
}
}
// Clone and compare
struct archive_entry *entry2 = archive_entry_clone(entry);
if (entry2) {
archive_entry_free(entry2);
}
free(safe_str);
archive_entry_free(entry);
return 0;
}
+86
View File
@@ -0,0 +1,86 @@
/*
* TAR format fuzzer for libarchive
* Tests all TAR variants: ustar, pax, gnutar, v7, oldgnu
*/
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 512 * 1024;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
archive_read_support_format_tar(a);
archive_read_support_format_gnutar(a);
archive_read_support_filter_all(a);
// Enable various TAR options
archive_read_set_options(a, "tar:read_concatenated_archives,tar:mac-ext");
Buffer buffer = {buf, len, 0};
if (archive_read_open(a, &buffer, NULL, reader_callback, NULL) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(4096, 0);
struct archive_entry *entry;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
// Exercise all metadata accessors
archive_entry_pathname(entry);
archive_entry_pathname_w(entry);
archive_entry_size(entry);
archive_entry_mtime(entry);
archive_entry_atime(entry);
archive_entry_ctime(entry);
archive_entry_mode(entry);
archive_entry_uid(entry);
archive_entry_gid(entry);
archive_entry_uname(entry);
archive_entry_gname(entry);
archive_entry_symlink(entry);
archive_entry_hardlink(entry);
archive_entry_rdev(entry);
archive_entry_devmajor(entry);
archive_entry_devminor(entry);
// Test sparse file handling
archive_entry_sparse_reset(entry);
int64_t offset, length;
while (archive_entry_sparse_next(entry, &offset, &length) == ARCHIVE_OK) {
(void)offset;
(void)length;
}
// Test xattr handling
archive_entry_xattr_reset(entry);
const char *name;
const void *value;
size_t size;
while (archive_entry_xattr_next(entry, &name, &value, &size) == ARCHIVE_OK) {
(void)name;
(void)value;
(void)size;
}
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0)
;
}
archive_read_free(a);
return 0;
}
@@ -0,0 +1,51 @@
# TAR format dictionary
# USTAR magic
"ustar"
"ustar\x00"
"ustar \x00"
# GNU tar magic
"GNUtar "
"GNUtar\x00"
# Common header field values
"00000000000"
"0000644"
"0000755"
"0000777"
# Type flags
"0"
"1"
"2"
"3"
"4"
"5"
"6"
"7"
"g"
"x"
"L"
"K"
# PAX keywords
"path="
"linkpath="
"uname="
"gname="
"uid="
"gid="
"size="
"mtime="
"atime="
"ctime="
"SCHILY.xattr."
"LIBARCHIVE.xattr."
# Sparse headers
"GNU.sparse.major="
"GNU.sparse.minor="
"GNU.sparse.name="
"GNU.sparse.realsize="
"GNU.sparse.map="
@@ -0,0 +1,50 @@
/*
* WARC (Web Archive) format fuzzer for libarchive
*/
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 512 * 1024;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
archive_read_support_format_warc(a);
archive_read_support_filter_all(a);
Buffer buffer = {buf, len, 0};
if (archive_read_open(a, &buffer, NULL, reader_callback, NULL) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(4096, 0);
struct archive_entry *entry;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
archive_entry_pathname(entry);
archive_entry_size(entry);
archive_entry_mtime(entry);
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0)
;
}
archive_read_free(a);
return 0;
}
@@ -0,0 +1,34 @@
# WARC format dictionary
# Version
"WARC/1.0"
"WARC/1.1"
"WARC/0.17"
"WARC/0.18"
# Record types
"warcinfo"
"response"
"resource"
"request"
"metadata"
"revisit"
"conversion"
"continuation"
# Headers
"WARC-Type:"
"WARC-Record-ID:"
"WARC-Date:"
"WARC-Target-URI:"
"Content-Length:"
"Content-Type:"
"WARC-Block-Digest:"
"WARC-Payload-Digest:"
"WARC-Concurrent-To:"
"WARC-Refers-To:"
# Content types
"application/warc-fields"
"application/http;msgtype=request"
"application/http;msgtype=response"
@@ -0,0 +1,273 @@
/*
* Archive write disk fuzzer for libarchive
* Tests extraction to filesystem
* Security-critical: path traversal, permission handling, symlink attacks
*/
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 64 * 1024;
static char g_temp_dir[256] = {0};
static char g_start_dir[512] = {0};
static char g_extract_dir[512] = {0};
static char g_outside_dir[512] = {0};
static char g_sentinel_path[512] = {0};
static int write_file(const char* path, const char* data) {
FILE* f = fopen(path, "wb");
size_t len = strlen(data);
size_t written;
if (f == NULL) {
return -1;
}
written = fwrite(data, 1, len, f);
if (fclose(f) != 0) {
return -1;
}
return written == len ? 0 : -1;
}
static int sentinel_is_unchanged() {
char buf[32];
FILE* f = fopen(g_sentinel_path, "rb");
if (f == NULL) {
return 0;
}
size_t n = fread(buf, 1, sizeof(buf) - 1, f);
fclose(f);
buf[n] = '\0';
return strcmp(buf, "outside-original") == 0;
}
static int reset_temp_tree() {
if (g_start_dir[0] != '\0') {
if (chdir(g_start_dir) != 0) {
return -1;
}
}
remove_directory_tree(g_temp_dir);
if (mkdir(g_temp_dir, 0700) != 0) {
return -1;
}
snprintf(g_extract_dir, sizeof(g_extract_dir), "%s/extract", g_temp_dir);
snprintf(g_outside_dir, sizeof(g_outside_dir), "%s/outside", g_temp_dir);
snprintf(g_sentinel_path, sizeof(g_sentinel_path), "%s/outside/sentinel",
g_temp_dir);
if (mkdir(g_extract_dir, 0700) != 0 || mkdir(g_outside_dir, 0700) != 0) {
return -1;
}
char existing[512];
char existing_dir[512];
char nested_existing[512];
snprintf(existing, sizeof(existing), "%s/extract/existing", g_temp_dir);
snprintf(existing_dir, sizeof(existing_dir), "%s/extract/dir", g_temp_dir);
snprintf(nested_existing, sizeof(nested_existing),
"%s/extract/dir/existing", g_temp_dir);
if (mkdir(existing_dir, 0700) != 0) {
return -1;
}
return write_file(g_sentinel_path, "outside-original") ||
write_file(existing, "inside") ||
write_file(nested_existing, "inside");
}
static void consume_path(DataConsumer* consumer, char* out, size_t out_size) {
static const char* const kPaths[] = {
"file",
"dir/file",
"dir/./file",
"dir//file",
"link",
"link/file",
"link/./file",
"link//file",
"../outside/sentinel",
"../outside/new-file",
"./../outside/sentinel",
"dir/../file",
"hardlink",
"hardlink-with-data",
"symlink",
"existing",
"dir/existing",
};
uint8_t selector = consumer->consume_byte();
if ((selector & 0x80) != 0) {
snprintf(out, out_size, "%s/extract/absolute-%u", g_temp_dir, selector);
} else if ((selector & 0x40) != 0) {
snprintf(out, out_size, "%s/outside/sentinel", g_temp_dir);
} else {
snprintf(out, out_size, "%s",
kPaths[selector % (sizeof(kPaths) / sizeof(kPaths[0]))]);
}
}
static void consume_linkname(DataConsumer* consumer, char* out,
size_t out_size) {
static const char* const kTargets[] = {
"existing",
"dir/existing",
"link/sentinel",
"link/./sentinel",
"link//sentinel",
"../outside/sentinel",
"./../outside/sentinel",
"dir/../existing",
"missing-target",
};
uint8_t selector = consumer->consume_byte();
if ((selector & 0x80) != 0) {
snprintf(out, out_size, "%s/outside/sentinel", g_temp_dir);
} else if ((selector & 0x40) != 0) {
snprintf(out, out_size, "%s/extract/existing", g_temp_dir);
} else {
snprintf(out, out_size, "%s",
kTargets[selector % (sizeof(kTargets) / sizeof(kTargets[0]))]);
}
}
extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) {
(void)argc;
(void)argv;
if (getcwd(g_start_dir, sizeof(g_start_dir)) == NULL) {
g_start_dir[0] = '\0';
}
// Create a temporary directory for extraction
snprintf(g_temp_dir, sizeof(g_temp_dir), "/tmp/fuzz_extract_XXXXXX");
if (mkdtemp(g_temp_dir) == NULL) {
g_temp_dir[0] = '\0';
}
return 0;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
if (g_temp_dir[0] == '\0') {
return 0;
}
if (reset_temp_tree() != 0 || chdir(g_extract_dir) != 0) {
return 0;
}
DataConsumer consumer(buf, len);
struct archive *disk = archive_write_disk_new();
if (disk == NULL) {
if (g_start_dir[0] != '\0') {
if (chdir(g_start_dir) != 0) {
return 0;
}
}
return 0;
}
// Configure write disk options
uint8_t opt_flags = consumer.consume_byte();
int flags = 0;
if (opt_flags & 0x01) flags |= ARCHIVE_EXTRACT_TIME;
if (opt_flags & 0x02) flags |= ARCHIVE_EXTRACT_PERM;
if (opt_flags & 0x04) flags |= ARCHIVE_EXTRACT_ACL;
if (opt_flags & 0x08) flags |= ARCHIVE_EXTRACT_FFLAGS;
if (opt_flags & 0x10) flags |= ARCHIVE_EXTRACT_OWNER;
if (opt_flags & 0x20) flags |= ARCHIVE_EXTRACT_XATTR;
if (opt_flags & 0x40) flags |= ARCHIVE_EXTRACT_UNLINK;
if (opt_flags & 0x80) flags |= ARCHIVE_EXTRACT_SAFE_WRITES;
flags |= ARCHIVE_EXTRACT_SECURE_SYMLINKS |
ARCHIVE_EXTRACT_SECURE_NODOTDOT |
ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS;
archive_write_disk_set_options(disk, flags);
archive_write_disk_set_standard_lookup(disk);
// Create entries to extract
int entry_count = 0;
while (!consumer.empty() && entry_count < 5 && consumer.remaining() > 20) {
struct archive_entry *entry = archive_entry_new();
if (entry == NULL) break;
char pathname[512];
char linkname[512];
consume_path(&consumer, pathname, sizeof(pathname));
archive_entry_set_pathname(entry, pathname);
uint8_t ftype = consumer.consume_byte() % 4;
mode_t mode;
switch (ftype) {
case 0: mode = S_IFREG | 0644; break;
case 1: mode = S_IFDIR | 0755; break;
case 2: mode = S_IFLNK | 0777; break;
default: mode = S_IFREG | 0644; break;
}
archive_entry_set_mode(entry, mode);
if (S_ISLNK(mode)) {
consume_linkname(&consumer, linkname, sizeof(linkname));
archive_entry_set_symlink(entry, linkname);
archive_entry_set_size(entry, 0);
} else if (ftype == 3) {
consume_linkname(&consumer, linkname, sizeof(linkname));
archive_entry_set_hardlink(entry, linkname);
}
archive_entry_set_uid(entry, 1000);
archive_entry_set_gid(entry, 1000);
archive_entry_set_mtime(entry, consumer.consume_i64(), 0);
uint8_t data_buf[256];
size_t data_len = 0;
if (S_ISREG(mode)) {
data_len = consumer.consume_bytes(data_buf, 256);
archive_entry_set_size(entry, data_len);
}
// Write the entry header
if (archive_write_header(disk, entry) == ARCHIVE_OK) {
if (S_ISREG(mode) && data_len > 0) {
archive_write_data(disk, data_buf, data_len);
}
archive_write_finish_entry(disk);
}
archive_entry_free(entry);
entry_count++;
}
archive_write_close(disk);
archive_write_free(disk);
if (!sentinel_is_unchanged()) {
abort();
}
if (g_start_dir[0] != '\0') {
if (chdir(g_start_dir) != 0) {
abort();
}
}
// Clean up extracted files using nftw (safer than system())
remove_directory_tree(g_temp_dir);
// Recreate the temp directory for next iteration
mkdir(g_temp_dir, 0700);
return 0;
}
@@ -0,0 +1,3 @@
[libfuzzer]
max_len = 65536
timeout = 30
+132
View File
@@ -0,0 +1,132 @@
/*
* Archive write fuzzer for libarchive
* Tests archive creation and writing code paths
*/
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 64 * 1024; // 64KB
// Simple data consumer
// Memory write callback
static std::vector<uint8_t> *g_output = nullptr;
static ssize_t write_callback(struct archive *a, void *client_data, const void *buffer, size_t length) {
(void)a;
(void)client_data;
if (g_output && length > 0) {
const uint8_t *buf = static_cast<const uint8_t*>(buffer);
g_output->insert(g_output->end(), buf, buf + length);
}
return length;
}
static int close_callback(struct archive *a, void *client_data) {
(void)a;
(void)client_data;
return ARCHIVE_OK;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
DataConsumer consumer(buf, len);
std::vector<uint8_t> output;
g_output = &output;
struct archive *a = archive_write_new();
if (a == NULL) {
return 0;
}
// Select format based on input
uint8_t format_choice = consumer.consume_byte() % 8;
switch (format_choice) {
case 0: archive_write_set_format_pax_restricted(a); break;
case 1: archive_write_set_format_gnutar(a); break;
case 2: archive_write_set_format_ustar(a); break;
case 3: archive_write_set_format_cpio_newc(a); break;
case 4: archive_write_set_format_zip(a); break;
case 5: archive_write_set_format_7zip(a); break;
case 6: archive_write_set_format_xar(a); break;
default: archive_write_set_format_pax(a); break;
}
// Select compression based on input
uint8_t filter_choice = consumer.consume_byte() % 6;
switch (filter_choice) {
case 0: archive_write_add_filter_gzip(a); break;
case 1: archive_write_add_filter_bzip2(a); break;
case 2: archive_write_add_filter_xz(a); break;
case 3: archive_write_add_filter_zstd(a); break;
case 4: archive_write_add_filter_none(a); break;
default: archive_write_add_filter_none(a); break;
}
// Open for writing to memory
if (archive_write_open(a, NULL, NULL, write_callback, close_callback) != ARCHIVE_OK) {
archive_write_free(a);
g_output = nullptr;
return 0;
}
// Create entries based on remaining input
int entry_count = 0;
while (!consumer.empty() && entry_count < 10 && consumer.remaining() > 20) {
struct archive_entry *entry = archive_entry_new();
if (entry == NULL) break;
// Set entry properties
archive_entry_set_pathname(entry, consumer.consume_string(64));
uint8_t ftype = consumer.consume_byte() % 4;
mode_t mode;
switch (ftype) {
case 0: mode = S_IFREG | 0644; break;
case 1: mode = S_IFDIR | 0755; break;
case 2: mode = S_IFLNK | 0777; break;
default: mode = S_IFREG | 0644; break;
}
archive_entry_set_mode(entry, mode);
archive_entry_set_uid(entry, consumer.consume_u32() & 0xFFFF);
archive_entry_set_gid(entry, consumer.consume_u32() & 0xFFFF);
archive_entry_set_mtime(entry, consumer.consume_i64(), 0);
// For regular files, write some data
if (S_ISREG(mode)) {
uint8_t data_buf[1024];
size_t data_len = consumer.consume_bytes(data_buf, 1024);
archive_entry_set_size(entry, data_len);
if (archive_write_header(a, entry) == ARCHIVE_OK && data_len > 0) {
archive_write_data(a, data_buf, data_len);
}
} else if (S_ISLNK(mode)) {
archive_entry_set_symlink(entry, consumer.consume_string(64));
archive_entry_set_size(entry, 0);
archive_write_header(a, entry);
} else {
archive_entry_set_size(entry, 0);
archive_write_header(a, entry);
}
archive_entry_free(entry);
entry_count++;
}
archive_write_close(a);
archive_write_free(a);
g_output = nullptr;
return 0;
}
+60
View File
@@ -0,0 +1,60 @@
/*
* XAR format specific fuzzer for libarchive
* Targets xar_read_header and XAR parsing code paths
*/
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 512 * 1024; // 512KB
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
// Enable XAR format specifically
archive_read_support_format_xar(a);
// Enable common filters
archive_read_support_filter_all(a);
Buffer buffer = {buf, len, 0};
if (archive_read_open(a, &buffer, NULL, reader_callback, NULL) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(4096, 0);
struct archive_entry *entry;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
// Exercise entry metadata access
archive_entry_pathname(entry);
archive_entry_pathname_w(entry);
archive_entry_size(entry);
archive_entry_mtime(entry);
archive_entry_mode(entry);
archive_entry_filetype(entry);
archive_entry_uid(entry);
archive_entry_gid(entry);
// Read data
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0)
;
}
archive_read_free(a);
return 0;
}
@@ -0,0 +1,44 @@
# XAR format dictionary
# Magic bytes
"xar!"
"\x78\x61\x72\x21"
# XML elements commonly in XAR
"<xar>"
"</xar>"
"<toc>"
"</toc>"
"<file>"
"</file>"
"<name>"
"</name>"
"<data>"
"</data>"
"<encoding>"
"</encoding>"
"<archived-checksum>"
"<extracted-checksum>"
"<offset>"
"<length>"
"<size>"
"<mode>"
"<uid>"
"<gid>"
"<user>"
"<group>"
"<type>"
"<mtime>"
"<atime>"
"<ctime>"
# Compression types
"application/octet-stream"
"application/x-gzip"
"application/x-bzip2"
"application/x-lzma"
# Checksum types
"sha1"
"md5"
"sha256"
"sha512"
@@ -0,0 +1,10 @@
[libfuzzer]
max_len = 524288
timeout = 60
rss_limit_mb = 2048
[honggfuzz]
timeout = 60
[afl]
timeout = 60
+68
View File
@@ -0,0 +1,68 @@
/*
* ZIP format fuzzer for libarchive
* Tests ZIP with various compression methods and encryption
*/
#include <stddef.h>
#include <stdint.h>
#include <vector>
#include "archive.h"
#include "archive_entry.h"
#include "fuzz_helpers.h"
static constexpr size_t kMaxInputSize = 512 * 1024;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
if (len == 0 || len > kMaxInputSize) {
return 0;
}
struct archive *a = archive_read_new();
if (a == NULL) {
return 0;
}
archive_read_support_format_zip(a);
archive_read_support_filter_all(a);
// Add passphrase for encrypted ZIPs
archive_read_add_passphrase(a, "password");
archive_read_add_passphrase(a, "test");
archive_read_add_passphrase(a, "");
// Enable ZIP options
archive_read_set_options(a, "zip:ignorecrc32");
Buffer buffer = {buf, len, 0};
if (archive_read_open(a, &buffer, NULL, reader_callback, NULL) != ARCHIVE_OK) {
archive_read_free(a);
return 0;
}
std::vector<uint8_t> data_buffer(4096, 0);
struct archive_entry *entry;
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
archive_entry_pathname(entry);
archive_entry_pathname_w(entry);
archive_entry_size(entry);
archive_entry_mtime(entry);
archive_entry_mode(entry);
archive_entry_is_encrypted(entry);
archive_entry_is_data_encrypted(entry);
archive_entry_is_metadata_encrypted(entry);
// Check compression name
archive_format_name(a);
archive_filter_name(a, 0);
ssize_t r;
while ((r = archive_read_data(a, data_buffer.data(), data_buffer.size())) > 0)
;
}
archive_read_free(a);
return 0;
}
@@ -0,0 +1,43 @@
# ZIP format dictionary
# Signatures
"PK\x03\x04"
"PK\x01\x02"
"PK\x05\x06"
"PK\x06\x06"
"PK\x06\x07"
"PK\x07\x08"
# Version needed
"\x14\x00"
"\x0a\x00"
"\x2d\x00"
"\x3f\x00"
# Compression methods
"\x00\x00"
"\x08\x00"
"\x09\x00"
"\x0c\x00"
"\x0e\x00"
"\x5f\x00"
# General purpose flags
"\x00\x00"
"\x01\x00"
"\x08\x00"
"\x09\x00"
# Extra field IDs
"\x01\x00"
"\x07\x00"
"\x09\x00"
"\x0a\x00"
"\x15\x00"
"\x17\x00"
"\x55\x54"
"\x75\x78"
# Encryption
"\x01\x99"
"\x02\x99"
+126 -11
View File
@@ -1,16 +1,131 @@
# build the project
#!/bin/bash -eu
# Build the project
./build/autogen.sh
./configure
make -j$(nproc) all
# build seed
cp $SRC/libarchive/contrib/oss-fuzz/corpus.zip\
$OUT/libarchive_fuzzer_seed_corpus.zip
FUZZ_DIR=$SRC/libarchive/contrib/oss-fuzz
TEST_DIR=$SRC/libarchive/libarchive/test
# build fuzzer(s)
$CXX $CXXFLAGS -Ilibarchive \
$SRC/libarchive/contrib/oss-fuzz/libarchive_fuzzer.cc \
-o $OUT/libarchive_fuzzer $LIB_FUZZING_ENGINE \
.libs/libarchive.a -Wl,-Bstatic -lbz2 -llzo2 \
-lxml2 -llzma -lz -lcrypto -llz4 -licuuc \
-licudata -Wl,-Bdynamic
# Common libraries for linking
LIBS=".libs/libarchive.a -Wl,-Bstatic -lbz2 -llzo2 -lxml2 -llzma -lz -lcrypto -llz4 -licuuc -licudata -Wl,-Bdynamic"
# Function to build a fuzzer
build_fuzzer() {
local name=$1
local source=$2
echo "Building fuzzer: $name"
$CXX $CXXFLAGS -Ilibarchive \
"$source" \
-o "$OUT/$name" $LIB_FUZZING_ENGINE $LIBS
}
# Build all format-specific fuzzers
FUZZERS=(
"libarchive_fuzzer"
"libarchive_tar_fuzzer"
"libarchive_zip_fuzzer"
"libarchive_7zip_fuzzer"
"libarchive_rar_fuzzer"
"libarchive_rar5_fuzzer"
"libarchive_xar_fuzzer"
"libarchive_cab_fuzzer"
"libarchive_lha_fuzzer"
"libarchive_iso9660_fuzzer"
"libarchive_cpio_fuzzer"
"libarchive_warc_fuzzer"
"libarchive_mtree_fuzzer"
"libarchive_ar_fuzzer"
"libarchive_filter_fuzzer"
"libarchive_entry_fuzzer"
"libarchive_write_fuzzer"
"libarchive_linkify_fuzzer"
"libarchive_match_fuzzer"
"libarchive_encryption_fuzzer"
"libarchive_read_disk_fuzzer"
"libarchive_write_disk_fuzzer"
"libarchive_seek_fuzzer"
"libarchive_string_fuzzer"
"libarchive_roundtrip_fuzzer"
)
for fuzzer in "${FUZZERS[@]}"; do
if [ -f "$FUZZ_DIR/${fuzzer}.cc" ]; then
build_fuzzer "$fuzzer" "$FUZZ_DIR/${fuzzer}.cc"
fi
done
# Copy dictionaries and options
cp "$FUZZ_DIR"/*.dict "$OUT/" 2>/dev/null || true
cp "$FUZZ_DIR"/*.options "$OUT/" 2>/dev/null || true
# Build seed corpora
echo "Building seed corpora..."
# Main fuzzer corpus (existing)
cp "$FUZZ_DIR/corpus.zip" "$OUT/libarchive_fuzzer_seed_corpus.zip"
# Function to create corpus from test files
create_corpus() {
local name=$1
local pattern=$2
local dir="/tmp/${name}_corpus"
mkdir -p "$dir"
for f in $TEST_DIR/$pattern; do
if [ -f "$f" ]; then
base=$(basename "$f" .uu)
uudecode -o "$dir/$base" "$f" 2>/dev/null || true
fi
done
if [ "$(ls -A $dir 2>/dev/null)" ]; then
zip -j "$OUT/${name}_seed_corpus.zip" "$dir"/* 2>/dev/null || true
echo "Created corpus for $name with $(ls $dir | wc -l) files"
fi
rm -rf "$dir"
}
# Create format-specific corpora
create_corpus "libarchive_tar_fuzzer" "test_compat_*tar*.uu"
create_corpus "libarchive_zip_fuzzer" "test_*zip*.uu"
create_corpus "libarchive_7zip_fuzzer" "test_read_format_7zip*.uu"
create_corpus "libarchive_rar_fuzzer" "test_read_format_rar_*.uu"
create_corpus "libarchive_rar5_fuzzer" "test_read_format_rar5*.uu"
create_corpus "libarchive_xar_fuzzer" "test_read_format_xar*.uu"
create_corpus "libarchive_cab_fuzzer" "test_read_format_cab*.uu"
create_corpus "libarchive_lha_fuzzer" "test_read_format_lha*.uu"
create_corpus "libarchive_iso9660_fuzzer" "test_read_format_iso*.uu"
create_corpus "libarchive_cpio_fuzzer" "test_compat_cpio*.uu"
create_corpus "libarchive_warc_fuzzer" "test_read_format_warc*.uu"
create_corpus "libarchive_mtree_fuzzer" "test_read_format_mtree*.uu"
create_corpus "libarchive_ar_fuzzer" "test_read_format_ar*.uu"
# Filter corpus - use compressed test files
mkdir -p /tmp/filter_corpus
for f in $TEST_DIR/*.gz.uu $TEST_DIR/*.bz2.uu $TEST_DIR/*.xz.uu $TEST_DIR/*.lz4.uu $TEST_DIR/*.zst.uu $TEST_DIR/*.Z.uu; do
if [ -f "$f" ]; then
base=$(basename "$f" .uu)
uudecode -o "/tmp/filter_corpus/$base" "$f" 2>/dev/null || true
fi
done
if [ "$(ls -A /tmp/filter_corpus 2>/dev/null)" ]; then
zip -j "$OUT/libarchive_filter_fuzzer_seed_corpus.zip" /tmp/filter_corpus/* 2>/dev/null || true
fi
rm -rf /tmp/filter_corpus
# Encryption corpus - encrypted archives
mkdir -p /tmp/encryption_corpus
for f in $TEST_DIR/*encrypt*.uu $TEST_DIR/*password*.uu; do
if [ -f "$f" ]; then
base=$(basename "$f" .uu)
uudecode -o "/tmp/encryption_corpus/$base" "$f" 2>/dev/null || true
fi
done
if [ "$(ls -A /tmp/encryption_corpus 2>/dev/null)" ]; then
zip -j "$OUT/libarchive_encryption_fuzzer_seed_corpus.zip" /tmp/encryption_corpus/* 2>/dev/null || true
fi
rm -rf /tmp/encryption_corpus
echo "Build complete! Built ${#FUZZERS[@]} fuzzers."
+2 -2
View File
@@ -60,11 +60,11 @@ parseoct(const char *p, size_t n)
{
unsigned long i = 0;
while ((*p < '0' || *p > '7') && n > 0) {
while (n > 0 && (*p < '0' || *p > '7')) {
++p;
--n;
}
while (*p >= '0' && *p <= '7' && n > 0) {
while (n > 0 && *p >= '0' && *p <= '7') {
i *= 8;
i += *p - '0';
++p;
+4 -2
View File
@@ -13,8 +13,10 @@ IF(ENABLE_CPIO)
cpio.c
cpio.h
cpio_platform.h
../libarchive_fe/err.c
../libarchive_fe/err.h
../libarchive_fe/lafe_err.c
../libarchive_fe/lafe_err.h
../libarchive_fe/lafe_getline.c
../libarchive_fe/lafe_getline.h
../libarchive_fe/lafe_platform.h
../libarchive_fe/line_reader.c
../libarchive_fe/line_reader.h
+12 -5
View File
@@ -11,6 +11,9 @@
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#ifdef HAVE_GRP_H
#include <grp.h>
#endif
@@ -26,7 +29,7 @@
#endif
#include "cpio.h"
#include "err.h"
#include "lafe_err.h"
/*
* Short options for cpio. Please keep this sorted.
@@ -347,9 +350,10 @@ owner_parse(const char *spec, struct cpio_owner *owner, const char **errmsg)
owner->gid = pwent->pw_gid;
} else {
char *end;
unsigned long val;
errno = 0;
owner->uid = (int)strtoul(user, &end, 10);
if (errno || *end != '\0') {
val = strtoul(user, &end, 10);
if (errno || *end != '\0' || val > (unsigned)INT_MAX) {
snprintf(errbuff, sizeof(errbuff),
"Couldn't lookup user ``%s''", user);
errbuff[sizeof(errbuff) - 1] = '\0';
@@ -357,6 +361,7 @@ owner_parse(const char *spec, struct cpio_owner *owner, const char **errmsg)
*errmsg = errbuff;
return (-1);
}
owner->uid = (int)val;
}
free(user);
}
@@ -373,15 +378,17 @@ owner_parse(const char *spec, struct cpio_owner *owner, const char **errmsg)
}
} else {
char *end;
unsigned long val;
errno = 0;
owner->gid = (int)strtoul(g, &end, 10);
if (errno || *end != '\0') {
val = strtoul(g, &end, 10);
if (errno || *end != '\0' || val > (unsigned)INT_MAX) {
snprintf(errbuff, sizeof(errbuff),
"Couldn't lookup group ``%s''", g);
errbuff[sizeof(errbuff) - 1] = '\0';
*errmsg = errbuff;
return (-1);
}
owner->gid = (int)val;
}
}
return (0);
+91 -66
View File
@@ -8,6 +8,8 @@
#include "cpio_platform.h"
#include "lafe_getline.h"
#include <sys/types.h>
#include <archive.h>
#include <archive_entry.h>
@@ -33,6 +35,9 @@
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#ifdef HAVE_PWD_H
#include <pwd.h>
#endif
@@ -60,7 +65,7 @@
#endif
#include "cpio.h"
#include "err.h"
#include "lafe_err.h"
#include "line_reader.h"
#include "passphrase.h"
@@ -83,7 +88,7 @@ struct name_cache {
static int extract_data(struct archive *, struct archive *);
const char * cpio_i64toa(int64_t);
static const char *cpio_rename(const char *name);
static void cpio_rename(struct archive_entry *);
static int entry_to_archive(struct cpio *, struct archive_entry *);
static int file_to_archive(struct cpio *, const char *);
static void free_cache(struct name_cache *cache);
@@ -110,27 +115,32 @@ static void passphrase_free(char *);
int
main(int argc, char *argv[])
{
static char buff[16384];
struct cpio _cpio; /* Allocated on stack. */
struct cpio *cpio;
struct cpio_owner owner;
const char *errmsg;
char *tptr;
int opt, t;
int opt;
long t;
cpio = &_cpio;
memset(cpio, 0, sizeof(*cpio));
cpio->buff = buff;
cpio->buff_size = sizeof(buff);
#if defined(HAVE_SIGACTION) && defined(SIGPIPE)
{ /* Ignore SIGPIPE signals. */
#if defined(HAVE_SIGACTION)
{
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
#ifdef SIGPIPE
/* Ignore SIGPIPE signals. */
sa.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sa, NULL);
#endif
#ifdef SIGCHLD
/* Do not ignore SIGCHLD. */
sa.sa_handler = SIG_DFL;
sigaction(SIGCHLD, &sa, NULL);
#endif
}
#endif
@@ -196,13 +206,13 @@ main(int argc, char *argv[])
case 'C': /* NetBSD/OpenBSD */
errno = 0;
tptr = NULL;
t = (int)strtol(cpio->argument, &tptr, 10);
if (errno || t <= 0 || *(cpio->argument) == '\0' ||
t = strtol(cpio->argument, &tptr, 10);
if (errno || t <= 0 || t > INT_MAX || *(cpio->argument) == '\0' ||
tptr == NULL || *tptr != '\0') {
lafe_errc(1, 0, "Invalid blocksize: %s",
cpio->argument);
}
cpio->bytes_per_block = t;
cpio->bytes_per_block = (int)t;
break;
case 'c': /* POSIX 1997 */
cpio->format = "odc";
@@ -214,7 +224,7 @@ main(int argc, char *argv[])
if (archive_match_include_pattern_from_file(
cpio->matching, cpio->argument,
cpio->option_null) != ARCHIVE_OK)
lafe_errc(1, 0, "Error : %s",
lafe_errc(1, 0, "%s",
archive_error_string(cpio->matching));
break;
case 'F': /* NetBSD/OpenBSD/GNU cpio */
@@ -223,7 +233,7 @@ main(int argc, char *argv[])
case 'f': /* POSIX 1997 */
if (archive_match_exclude_pattern(cpio->matching,
cpio->argument) != ARCHIVE_OK)
lafe_errc(1, 0, "Error : %s",
lafe_errc(1, 0, "%s",
archive_error_string(cpio->matching));
break;
case OPTION_GRZIP:
@@ -239,7 +249,7 @@ main(int argc, char *argv[])
cpio->filename = cpio->argument;
break;
case 'i': /* POSIX 1997 */
if (cpio->mode != '\0')
if (cpio->mode != '\0' && cpio->mode != opt)
lafe_errc(1, 0,
"Cannot use both -i and -%c", cpio->mode);
cpio->mode = opt;
@@ -281,13 +291,13 @@ main(int argc, char *argv[])
cpio->filename = cpio->argument;
break;
case 'o': /* POSIX 1997 */
if (cpio->mode != '\0')
if (cpio->mode != '\0' && cpio->mode != opt)
lafe_errc(1, 0,
"Cannot use both -o and -%c", cpio->mode);
cpio->mode = opt;
break;
case 'p': /* POSIX 1997 */
if (cpio->mode != '\0')
if (cpio->mode != '\0' && cpio->mode != opt)
lafe_errc(1, 0,
"Cannot use both -p and -%c", cpio->mode);
cpio->mode = opt;
@@ -308,17 +318,21 @@ main(int argc, char *argv[])
if (owner_parse(cpio->argument, &owner, &errmsg) != 0) {
if (!errmsg)
errmsg = "Error parsing owner";
lafe_warnc(-1, "%s", errmsg);
lafe_warnc(0, "%s", errmsg);
usage();
}
if (owner.uid != -1)
cpio->uid_override = owner.uid;
if (owner.uname != NULL)
if (owner.uname != NULL) {
free(cpio->uname_override);
cpio->uname_override = owner.uname;
}
if (owner.gid != -1)
cpio->gid_override = owner.gid;
if (owner.gname != NULL)
if (owner.gname != NULL) {
free(cpio->gname_override);
cpio->gname_override = owner.gname;
}
break;
case 'r': /* POSIX 1997 */
cpio->option_rename = 1;
@@ -401,7 +415,7 @@ main(int argc, char *argv[])
while (*cpio->argv != NULL) {
if (archive_match_include_pattern(cpio->matching,
*cpio->argv) != ARCHIVE_OK)
lafe_errc(1, 0, "Error : %s",
lafe_errc(1, 0, "%s",
archive_error_string(cpio->matching));
--cpio->argc;
++cpio->argv;
@@ -419,7 +433,7 @@ main(int argc, char *argv[])
break;
default:
lafe_errc(1, 0,
"Must specify at least one of -i, -o, or -p");
"Must specify one of -i, -o, or -p");
}
archive_match_free(cpio->matching);
@@ -516,7 +530,7 @@ mode_out(struct cpio *cpio)
int r;
if (cpio->option_append)
lafe_errc(1, 0, "Append mode not yet supported.");
lafe_errc(1, 0, "Append mode not yet supported");
cpio->archive_read_disk = archive_read_disk_new();
if (cpio->archive_read_disk == NULL)
@@ -630,7 +644,7 @@ mode_out(struct cpio *cpio)
int64_t blocks =
(archive_filter_bytes(cpio->archive, 0) + 511)
/ 512;
fprintf(stderr, "%lu %s\n", (unsigned long)blocks,
fprintf(stderr, "%lld %s\n", (long long)blocks,
blocks == 1 ? "block" : "blocks");
}
archive_write_free(cpio->archive);
@@ -688,7 +702,6 @@ remove_leading_slash(const char *p)
static int
file_to_archive(struct cpio *cpio, const char *srcpath)
{
const char *destpath;
struct archive_entry *entry, *spare;
size_t len;
int r;
@@ -717,7 +730,7 @@ file_to_archive(struct cpio *cpio, const char *srcpath)
if (cpio->uid_override >= 0)
archive_entry_set_uid(entry, cpio->uid_override);
if (cpio->gname_override != NULL)
if (cpio->uname_override != NULL)
archive_entry_set_uname(entry, cpio->uname_override);
if (cpio->gid_override >= 0)
archive_entry_set_gid(entry, cpio->gid_override);
@@ -730,7 +743,6 @@ file_to_archive(struct cpio *cpio, const char *srcpath)
* pass mode or the name that will go into the archive in
* output mode.
*/
destpath = srcpath;
if (cpio->destdir) {
len = cpio->destdir_len + strlen(srcpath) + 8;
if (len >= cpio->pass_destpath_alloc) {
@@ -746,15 +758,17 @@ file_to_archive(struct cpio *cpio, const char *srcpath)
}
strcpy(cpio->pass_destpath, cpio->destdir);
strcat(cpio->pass_destpath, remove_leading_slash(srcpath));
destpath = cpio->pass_destpath;
archive_entry_set_pathname(entry, cpio->pass_destpath);
} else {
archive_entry_set_pathname(entry, srcpath);
}
if (cpio->option_rename)
destpath = cpio_rename(destpath);
if (destpath == NULL) {
cpio_rename(entry);
if (archive_entry_pathname(entry) == NULL) {
archive_entry_free(entry);
return (0);
}
archive_entry_copy_pathname(entry, destpath);
/*
* If we're trying to preserve hardlinks, match them here.
@@ -783,7 +797,6 @@ entry_to_archive(struct cpio *cpio, struct archive_entry *entry)
const char *destpath = archive_entry_pathname(entry);
const char *srcpath = archive_entry_sourcepath(entry);
int fd = -1;
ssize_t bytes_read;
int r;
/* Print out the destination name to the user. */
@@ -861,21 +874,23 @@ entry_to_archive(struct cpio *cpio, struct archive_entry *entry)
exit(1);
if (r >= ARCHIVE_WARN && archive_entry_size(entry) > 0 && fd >= 0) {
bytes_read = read(fd, cpio->buff, (unsigned)cpio->buff_size);
static char buff[16384];
ssize_t bytes_read;
bytes_read = read(fd, buff, sizeof(buff));
while (bytes_read > 0) {
ssize_t bytes_write;
bytes_write = archive_write_data(cpio->archive,
cpio->buff, bytes_read);
buff, bytes_read);
if (bytes_write < 0)
lafe_errc(1, archive_errno(cpio->archive),
"%s", archive_error_string(cpio->archive));
if (bytes_write < bytes_read) {
lafe_warnc(0,
"Truncated write; file may have "
"grown while being archived.");
"grown while being archived");
}
bytes_read = read(fd, cpio->buff,
(unsigned)cpio->buff_size);
bytes_read = read(fd, buff, sizeof(buff));
}
}
@@ -987,13 +1002,14 @@ mode_in(struct cpio *cpio)
lafe_errc(1, archive_errno(a),
"%s", archive_error_string(a));
}
if (archive_match_path_excluded(cpio->matching, entry))
r = archive_match_path_excluded(cpio->matching, entry);
if (r < 0)
lafe_errc(1, 0, "%s", archive_error_string(cpio->matching));
if (r)
continue;
if (cpio->option_rename) {
destpath = cpio_rename(archive_entry_pathname(entry));
archive_entry_set_pathname(entry, destpath);
} else
destpath = archive_entry_pathname(entry);
if (cpio->option_rename)
cpio_rename(entry);
destpath = archive_entry_pathname(entry);
if (destpath == NULL)
continue;
if (cpio->verbose)
@@ -1032,7 +1048,7 @@ mode_in(struct cpio *cpio)
if (!cpio->quiet) {
int64_t blocks = (archive_filter_bytes(a, 0) + 511)
/ 512;
fprintf(stderr, "%lu %s\n", (unsigned long)blocks,
fprintf(stderr, "%lld %s\n", (long long)blocks,
blocks == 1 ? "block" : "blocks");
}
archive_read_free(a);
@@ -1104,7 +1120,10 @@ mode_list(struct cpio *cpio)
lafe_errc(1, archive_errno(a),
"%s", archive_error_string(a));
}
if (archive_match_path_excluded(cpio->matching, entry))
r = archive_match_path_excluded(cpio->matching, entry);
if (r < 0)
lafe_errc(1, 0, "%s", archive_error_string(cpio->matching));
if (r)
continue;
if (cpio->verbose)
list_item_verbose(cpio, entry);
@@ -1117,7 +1136,7 @@ mode_list(struct cpio *cpio)
if (!cpio->quiet) {
int64_t blocks = (archive_filter_bytes(a, 0) + 511)
/ 512;
fprintf(stderr, "%lu %s\n", (unsigned long)blocks,
fprintf(stderr, "%lld %s\n", (long long)blocks,
blocks == 1 ? "block" : "blocks");
}
archive_read_free(a);
@@ -1141,6 +1160,7 @@ list_item_verbose(struct cpio *cpio, struct archive_entry *entry)
const char *uname, *gname;
FILE *out = stdout;
const char *fmt;
double age;
time_t mtime;
static time_t now;
struct tm *ltime;
@@ -1180,16 +1200,15 @@ list_item_verbose(struct cpio *cpio, struct archive_entry *entry)
/* Format the time using 'ls -l' conventions. */
mtime = archive_entry_mtime(entry);
age = difftime(mtime, now);
#if defined(_WIN32) && !defined(__CYGWIN__)
/* Windows' strftime function does not support %e format. */
if (mtime - now > 365*86400/2
|| mtime - now < -365*86400/2)
if (age > 365.0 * 86400 / 2 || age < -365.0 * 86400 / 2)
fmt = cpio->day_first ? "%d %b %Y" : "%b %d %Y";
else
fmt = cpio->day_first ? "%d %b %H:%M" : "%b %d %H:%M";
#else
if (mtime - now > 365*86400/2
|| mtime - now < -365*86400/2)
if (age > 365.0 * 86400 / 2 || age < -365.0 * 86400 / 2)
fmt = cpio->day_first ? "%e %b %Y" : "%b %e %Y";
else
fmt = cpio->day_first ? "%e %b %H:%M" : "%b %e %H:%M";
@@ -1284,54 +1303,60 @@ mode_pass(struct cpio *cpio, const char *destdir)
* that an input of '.' means the name should be unchanged. GNU cpio
* treats '.' as a literal new name.
*/
static const char *
cpio_rename(const char *name)
void
cpio_rename(struct archive_entry *entry)
{
static char buff[1024];
char *buff = NULL, *p, *ret = NULL;
FILE *t;
char *p, *ret;
size_t n = 0;
ssize_t r;
#if defined(_WIN32) && !defined(__CYGWIN__)
FILE *to;
t = fopen("CONIN$", "r");
if (t == NULL)
return (name);
return;
to = fopen("CONOUT$", "w");
if (to == NULL) {
fclose(t);
return (name);
return;
}
fprintf(to, "%s (Enter/./(new name))? ", name);
fprintf(to, "%s (Enter/./(new name))? ", archive_entry_pathname(entry));
fclose(to);
#else
t = fopen("/dev/tty", "r+");
if (t == NULL)
return (name);
fprintf(t, "%s (Enter/./(new name))? ", name);
return;
fprintf(t, "%s (Enter/./(new name))? ", archive_entry_pathname(entry));
fflush(t);
#endif
p = fgets(buff, sizeof(buff), t);
r = getline(&buff, &n, t);
fclose(t);
if (p == NULL)
if (r < 1)
/* End-of-file is a blank line. */
return (NULL);
goto done;
p = buff;
while (*p == ' ' || *p == '\t')
++p;
if (*p == '\n' || *p == '\0')
/* Empty line. */
return (NULL);
if (*p == '.' && p[1] == '\n')
goto done;
if (*p == '.' && p[1] == '\n') {
/* Single period preserves original name. */
return (name);
free(buff);
return;
}
ret = p;
/* Trim the final newline. */
while (*p != '\0' && *p != '\n')
++p;
/* Overwrite the final \n with a null character. */
*p = '\0';
return (ret);
done:
archive_entry_set_pathname(entry, ret);
free(buff);
}
static void
-2
View File
@@ -71,8 +71,6 @@ struct cpio {
/* Work data. */
struct archive *matching;
char *buff;
size_t buff_size;
char *ppbuff;
};
+2 -2
View File
@@ -24,7 +24,7 @@
#include <sddl.h>
#include "cpio.h"
#include "err.h"
#include "lafe_err.h"
#define EPOC_TIME (116444736000000000ULL)
@@ -140,7 +140,7 @@ cpio_CreateFile(const char *path, DWORD dwDesiredAccess, DWORD dwShareMode,
CREATEFILE2_EXTENDED_PARAMETERS createExParams;
#endif
#if !defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP)
#if WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP)
handle = CreateFileA(path, dwDesiredAccess, dwShareMode,
lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes,
hTemplateFile);
+3 -16
View File
@@ -9,7 +9,7 @@
IF(ENABLE_CPIO AND ENABLE_TEST)
SET(bsdcpio_test_SOURCES
../cmdline.c
../../libarchive_fe/err.c
../../libarchive_fe/lafe_err.c
../../test_utils/test_utils.c
../../test_utils/test_main.c
test.h
@@ -84,25 +84,12 @@ IF(ENABLE_CPIO AND ENABLE_TEST)
# Generate list.h by grepping DEFINE_TEST() lines out of the C sources.
#
GENERATE_LIST_H(${CMAKE_CURRENT_BINARY_DIR}/list.h
${CMAKE_CURRENT_LIST_FILE} ${bsdcpio_test_SOURCES})
${CMAKE_CURRENT_LIST_FILE} bsdcpio_test ${bsdcpio_test_SOURCES})
SET_PROPERTY(DIRECTORY APPEND PROPERTY INCLUDE_DIRECTORIES
${CMAKE_CURRENT_BINARY_DIR})
# list.h has a line DEFINE_TEST(testname) for every
# test. We can use that to define the tests for cmake by
# defining a DEFINE_TEST macro and reading list.h in.
MACRO (DEFINE_TEST _testname)
ADD_TEST(
NAME bsdcpio_${_testname}
COMMAND bsdcpio_test -vv
-p $<TARGET_FILE:bsdcpio>
-r ${CMAKE_CURRENT_SOURCE_DIR}
-s
${_testname})
SET_TESTS_PROPERTIES(bsdcpio_${_testname} PROPERTIES SKIP_RETURN_CODE 2)
ENDMACRO (DEFINE_TEST _testname)
DISCOVER_TESTS(bsdcpio ${bsdcpio_test_SOURCES})
INCLUDE(${CMAKE_CURRENT_BINARY_DIR}/list.h)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/test_utils)
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/cpio/test)
Loaded 100 of 646 files, more files were not shown because too many files have changed in this diff. Show more