Compare commits

...
96 Commits
Author SHA1 Message Date
Mark Johnston 2e6399fe39 Add UPDATING entries and bump version
Approved by:	so
2026-04-30 21:21:13 +00:00
Dag-Erling Smørgrav b362b6b6c8 dhclient: Improve server and filename validation
* Don't iterate over each string three times; once is enough.

* Reject control characters (anything below space) in addition to the
  double quote and backslash.

* If an unsafe character is encountered, discard the string instead of
  rejecting the entire lease.

* If backslashes are encountered in the file name option, convert them
  to forward slashes instead of rejecting the option.

* Tweak the warning messages a bit.  Looking through the rest of the
  code, it seems to me that notes generally end with a period while
  warnings generally don't.

Approved by:	so
Security:	FreeBSD-EN-26:11.dhclient
Fixes:		8008e4b88d ("dhclient: Check for unexpected characters in some DHCP server options")
PR:		294886
MFC after:	1 week
Reviewed by:	brooks, markj
Differential Revision:	https://reviews.freebsd.org/D56740

(cherry picked from commit 873a195ba6)
(cherry picked from commit b1ece85741)
2026-04-30 21:20:57 +00:00
Mark Johnston bf0db64e03 Add UPDATING entries and bump version
Approved by:	so
2026-04-28 20:32:11 +00:00
Mariusz Zaborski f7f48005fb libnv: fix heap overflow in nvlist_recv()
nvlist_check_header() validated nvlh_size for overflow before
performing conversion. An mallicous user can set
NV_FLAG_BIG_ENDIAN in the header and craft nvlh_size so that
the orginall value passes the check, but after the conversion the
sizeof(nvlist_header) + size can overflow.
This can lead to a heap buffer overflow.

Approved by:	so
Security:	FreeBSD-SA-26:17.libnv
Security:	CVE-2026-35547
Fixes:		36fa90dbde
Reviewed by:	markj
Differential Revision:	https://reviews.freebsd.org/D56342
2026-04-28 20:32:11 +00:00
Mariusz Zaborski 32d12677ff libnv: switch fd_wait() from select(2) to poll(2)
The previous implementation used FD_SET() on a stack-allocated fd_set,
which is an out-of-bounds write whenever the socket fd is >= FD_SETSIZE
(1024).

Approved by:	so
Security:	FreeBSD-SA-26:16.libnv
Security:	CVE-2026-39457
Reported by:	Joshua Rogers of AISLE Research Team (https://aisle.com/)
Reviewed by:	markj
Differential Revision:	https://reviews.freebsd.org/D56689
2026-04-28 20:32:11 +00:00
Kristof Provost 0ab05345fb pf: improve SCTP validation
As per RFC5061 "4.2.  New Parameter Types" the add/delete IP address
parameters (0xc001, 0xc002) may not be present in an INIT or INIT-ACK
chunk. They are only allowed to be present in an ASCONF chunk.

This also prevents unbounded recursion while parsing an SCTP packet.

Approved by:	so
Security:	FreeBSD-SA-26:14.pf
Security:	CVE-2026-7164
PR:		294799
Reported by:	Igor Gabriel Sousa e Souza
MFC after:	3 days
Sponsored by:	Orange Business Services
2026-04-28 20:32:11 +00:00
Mark Johnston 5a5e7883a3 dhclient: Fix reallocation of dhclient script environments
When the number of DHCP options exceeds a threshold, script_set_env()
will reallocate the environment, stored as an array of pointers.  The
calculation of the array size failed to multiply by the pointer size,
resulting in a smaller than expected buffer which admits out-of-bounds
writes.

Approved by:	so
Security:	FreeBSD-SA-26:15.dhclient
Security:	CVE-2026-42511
Reported by:	Joshua Rogers of AISLE Research Team (https://aisle.com/)
2026-04-28 20:32:11 +00:00
Mark Johnston a2d45189b9 dhclient: Check for unexpected characters in some DHCP server options
Some options are written directly to the lease file, which may be parsed
by subsequent dhclient invocations.  We must make sure that a malicious
server can't control the "medium" field of a lease definition, otherwise
they can achieve RCE by injecting one into the lease file, whereupon it
will be passed to dhclient-script, which passes it through eval.

Approved by:	so
Security:	FreeBSD-SA-26:12.dhclient
Security:	CVE-2026-42511
Reported by:	Joshua Rogers of AISLE Research Team (https://aisle.com/)
2026-04-28 20:32:11 +00:00
Mark Johnston 7c5c37ac8f execve: Fix an operator precedence bug
The buggy version allowed userspace to overflow the copy into adjacent
execve KVA regions, which enables, among other things, injecting
environment variables into privileged processes.

Approved by:	so
Security:	FreeBSD-SA-26:13.exec
Security:	CVE-2026-7270
Reported by:	Ryan Austin of Calif.io
Reviewed by:	brooks, kib
Fixes:		f373437a01 ("Add helper functions to copy strings into struct image_args.")
Differential Revision:	https://reviews.freebsd.org/D56665
2026-04-28 20:32:11 +00:00
Philip Paeps f7e6b9f128 contrib/tzdata: import tzdata 2025c, 2026a and 2026b
Changes: https://github.com/eggert/tz/blob/2025c/NEWS
Changes: https://github.com/eggert/tz/blob/2026a/NEWS
Changes: https://github.com/eggert/tz/blob/2026b/NEWS

Approved by:	so
Security:	FreeBSD-EN-26:09.tzdata

(cherry picked from commit a86dc94b84)
(cherry picked from commit c7edaaf43f)
(cherry picked from commit 6becc3dff9)
(cherry picked from commit c0b2aff48f)
(cherry picked from commit 9b95cab0a2)
(cherry picked from commit 18787e4ae2)
2026-04-28 20:32:11 +00:00
Mark Johnston 6c36e5dd0c Add UPDATING entries and bump version
Approved by:	so
2026-04-21 15:47:00 +00:00
Mark Johnston a2f6f2d001 pkru: Fix handling of 1GB largepage mappings
pmap_pkru_update_range() did not handle the case where a PDPE has PG_PS
set.  More generally, the SET_PKRU and CLEAR_PKRU sysarch
implementations did not check whether the request covers a "boundary" vm
map entry.  Fix this, add the missing PG_PS test, and add some tests.

Approved by:	so
Security:	FreeBSD-SA-26:11.amd64
Security:	CVE-2026-6386
Reported by:	Nicholas Carlini <[email protected]>
Reviewed by:	kib, alc
Differential Revision:	https://reviews.freebsd.org/D56184
2026-04-21 15:47:00 +00:00
Mark Johnston 2862a33bdd tty: Avoid leaving dangling pointers in tty_drop_ctty()
The TIOCNOTTY handler detaches the calling process from its controlling
terminal.  It clears the link from the session to the tty, but not the
pointers from the tty to the session and process group.  This means that
sess_release() doesn't call tty_rel_sess(), and that pgdelete() doesn't
call tty_rel_pgrp(), so the pointers are left dangling.

Fix this by clearing pointers in tty_drop_ctty().  Add a standalone
regression test.

Approved by:	so
Security:	FreeBSD-SA-26:10.tty
Security:	CVE-2026-5398
Reported by:	Nicholas Carlini <[email protected]>
Reviewed by:	kib, kevans
Fixes:		1b50b999f9 ("tty: implement TIOCNOTTY")
Differential Revision:	https://reviews.freebsd.org/D56046
2026-04-21 15:47:00 +00:00
Mark Johnston 6c9dd75283 vm_fault: Reset m_needs_zeroing properly
- When allocating a page, we should only consider the PG_ZERO flag when
  handling the top-level page.
- Unconditionally reset the flag when restarting the fault handler.
  Previously, vm_fault_busy_sleep() would fail to reset it.

Approved by:	so
Security:	FreeBSD-EN-26:05.vm
PR:		294039
Reviewed by:	kib
Tested by:	Peter Much <[email protected]>
MFC after:	3 days
Fixes:		cff67bc43d ("vm_fault: only rely on PG_ZERO when the page was newly allocated")
Differential Revision:	https://reviews.freebsd.org/D56234

(cherry picked from commit 04132e0100)
(cherry picked from commit 50f7b62f08)
2026-04-21 15:46:57 +00:00
Mark Johnston 5c4e558ab4 Add UPDATING entries and bump version
Approved by:	so
2026-03-26 09:31:01 +08:00
Mark Johnston c4f53a1adb rpcsec_gss: Fix a stack overflow in svc_rpc_gss_validate()
svc_rpc_gss_validate() copies the input message into a stack buffer
without ensuring that the buffer is large enough.  Sure enough,
oa_length may be up to 400 bytes, much larger than the provided space.
This enables an unauthenticated user to trigger an overflow and obtain
remote code execution.

Add a runtime check which verifies that the copy won't overflow.

Approved by:	so
Security:	FreeBSD-SA-26:08.rpcsec_gss
Security:	CVE-2026-4747
Reported by:	Nicholas Carlini <[email protected]>
Reviewed by:	rmacklem
Fixes:		a9148abd9d
2026-03-26 09:30:59 +08:00
Mark Johnston 9d3e842358 Add UPDATING entries and bump version
Approved by:	so
2026-02-24 16:04:27 +00:00
Mark Johnston c2e2bfbd9e rtsock: Fix stack overflow
Approved by:	so
Security:	FreeBSD-SA-26:05.route
Security:	CVE-2026-3038
Fixes:		92be2847e8 ("rtsock: Avoid copying uninitialized padding bytes")

(cherry picked from commit f3be7df50f)
(cherry picked from commit 8b476ffc4e)
2026-02-24 16:03:49 +00:00
Mark Johnston 933abe4a19 amd64/conf: Remove a config committed by accident
Approved by:	so
Reported by:	kib, kp
Fixes:		350ba9672a ("unix: Set O_RESOLVE_BENEATH on fds transferred between jails")

(cherry picked from commit 3ef39f58e5)
(cherry picked from commit 3b0f13ca60)
2026-02-23 01:48:38 +00:00
Mark Johnston ecec541087 unix/tests: Add a regression test for fd transfer across jails
Approved by:	so
MFC after:	3 weeks

(cherry picked from commit 5843b8ee02)
(cherry picked from commit c997713286)
2026-02-23 01:48:38 +00:00
Mark Johnston e6b96891ef unix: Set O_RESOLVE_BENEATH on fds transferred between jails
If a pair of jails with different filesystem roots is able to exchange
SCM_RIGHTS messages (e.g., using a unix socket in a shared nullfs
mount), a process in one jail can open a directory outside of the root
of the second jail and then pass the fd to that second jail, allowing
the receiving process to escape the jail chroot.

Address this using the new FD_RESOLVE_BENEATH flag.  When externalizing
an SCM_RIGHTS message into the receiving process, automatically set this
flag on all new fds where a jail boundary is crossed.  This ensures that
the receiver cannot do more than access files underneath the directory;
in particular, the received fd cannot be used to access vnodes not
accessible by the sender.

Approved by:	so
PR:		262179
Reviewed by:	kib
MFC after:	3 weeks
Differential Revision:	https://reviews.freebsd.org/D50371

(cherry picked from commit 350ba9672a)
(cherry picked from commit 73530e4c2e)
2026-02-23 01:48:38 +00:00
Mark Johnston 82cee749b5 file: Add a fd flag with O_RESOLVE_BENEATH semantics
The O_RESOLVE_BENEATH openat(2) flag restricts name lookups such that
they remain under the directory referenced by the dirfd.  This commit
introduces an implicit version of the flag, FD_RESOLVE_BENEATH, stored
in the file descriptor entry.  When the flag is set, any lookup relative
to that fd automatically has O_RESOLVE_BENEATH semantics.  Furthermore,
the flag is sticky, meaning that it cannot be cleared, and it is copied
by dup() and openat().

File descriptors with FD_RESOLVE_BENEATH set may not be passed to
fchdir(2) or fchroot(2).  Various fd lookup routines are modified to
return fd flags to the caller.

This flag will be used to address a case where jails with different root
directories and the ability to pass SCM_RIGHTS messages across the jail
boundary can transfer directory fds in such as way as to allow a
filesystem escape.

Approved by:	so
PR:		262180
Reviewed by:	kib
MFC after:	3 weeks
Differential Revision:	https://reviews.freebsd.org/D50371

(cherry picked from commit f35525ff20)
(cherry picked from commit f7cbcb19a9)
2026-02-23 01:48:38 +00:00
Mark Johnston 0b18e4842c file: Qualify pointers to capsicum rights as const
File descriptor lookup routines typically take a set of capsicum rights
as input to the lookup, so that the fd's rights can be atomically
checked.  This set should be qualified with const.

No functional change intended.

Approved by:	so
Reviewed by:	olce, oshogbo, brooks, kib
MFC after:	2 weeks
Differential Revision:	https://reviews.freebsd.org/D50419

(cherry picked from commit 5319cb2161)
(cherry picked from commit ecc1e61d31)
2026-02-09 23:11:00 +00:00
Mark Johnston 0e9fc21ec0 Add UPDATING entries and bump patch version
Approved by:	so
2026-01-27 16:55:52 +00:00
Gordon Tetlow 9afc16c4e8 openssl: Fix multiple vulnerabilities
This is a rollup commit from upstream to fix:
  Heap out-of-bounds write in BIO_f_linebuffer on short writes (CVE-2025-68160)
  Unauthenticated/unencrypted trailing bytes with low-level OCB function calls (CVE-2025-69418)
  Out of bounds write in PKCS12_get_friendlyname() UTF-8 conversion (CVE-2025-69419)
  Missing ASN1_TYPE validation in TS_RESP_verify_response() function (CVE-2025-69420)
  NULL Pointer Dereference in PKCS12_item_decrypt_d2i_ex function (CVE-2025-69421)
  Missing ASN1_TYPE validation in PKCS#12 parsing (CVE-2026-22795)
  ASN1_TYPE Type Confusion in the PKCS7_digest_from_attributes() function (CVE-2026-22796)

See https://openssl-library.org/news/secadv/ for additional details.

Approved by:	so
Obtained from:	OpenSSL
Security:	FreeBSD-SA-26:01.openssl
Security:	CVE-2025-68160
Security:	CVE-2025-69418
Security:	CVE-2025-69419
Security:	CVE-2025-69420
Security:	CVE-2025-69421
Security:	CVE-2026-22795
Security:	CVE-2026-22796
2026-01-27 16:55:52 +00:00
Konstantin Belousov e91e8b785b namei: clear internal flags in NDREINIT()
same as it is done for NDRESTART()

Approved by:	so
Fixes:  e05e33041c
Reported and tested by:	pho
Reviewed by:	markj
Sponsored by:	The FreeBSD Foundation

(cherry picked from commit 58b2bd33af)
(cherry picked from commit 53963866f7)
2026-01-27 16:55:52 +00:00
Mark Johnston 15b39c1df3 namei: Fix cn_flags width in various places
This truncation is mostly harmless today, but fix it anyway to avoid
pain later down the road.

Approved by:	so
Reviewed by:	olce, kib
MFC after:	2 weeks
Differential Revision:	https://reviews.freebsd.org/D50417

(cherry picked from commit 0d224af399)
(cherry picked from commit 503ab844ce)
2026-01-27 16:55:52 +00:00
Mark Johnston 4613405fd6 vfs cache: Add NAMEILOOKUP to the whitelist of fastpath lookup flags
Otherwise the lockless name lookup path is inadvertently disabled since
NAMEILOOKUP isn't recognized.

Approved by:	so
Reviewed by:	olce, kib
Fixes:		7587f6d484 ("namei: Make stackable filesystems check harder for jail roots")
Differential Revision:	https://reviews.freebsd.org/D50532

(cherry picked from commit f415895300)
(cherry picked from commit adb8c1a9d0)
2026-01-27 16:55:52 +00:00
Mark Johnston 4586c4f500 namei: Remove a now-unused variable
Approved by:	so
Reported by:	bapt
Fixes:		7587f6d484 ("namei: Make stackable filesystems check harder for jail roots")

(cherry picked from commit 14ec281a09)
(cherry picked from commit 4e31059f80)
2026-01-27 16:55:52 +00:00
Mark Johnston 9f959a9837 tests: Add a regression test for commit 7587f6d484
Approved by:	so
Reviewed by:	kib
MFC after:	2 weeks
Differential Revision:	https://reviews.freebsd.org/D50533

(cherry picked from commit a5dac34f6e)
(cherry picked from commit b55b927296)
2026-01-27 16:55:48 +00:00
Mark Johnston fbb71f3a14 vfs: Don't clobber namei flags in vn_open_cred()
Otherwise NAMEILOOKUP is cleared.  More generally it seems quite
surprising that the flags set by vn_open_cred() callers are not
automatically preserved.  Modify open2nameif() such that it takes
already-set namei flags into account.

Approved by:	so
Reviewed by:	olce, kib
Fixes:		7587f6d484 ("namei: Make stackable filesystems check harder for jail roots")
Differential Revision:	https://reviews.freebsd.org/D50531

(cherry picked from commit e05e33041c)
(cherry picked from commit 8c63056ea8)
2026-01-26 16:46:30 +00:00
Mark Johnston e87a5dd805 namei: Make stackable filesystems check harder for jail roots
Suppose a process has its cwd pointing to a nullfs directory, where the
lower directory is also visible in the jail's filesystem namespace.
Suppose that the lower directory vnode is moved out from under the
nullfs mount.  The nullfs vnode still shadows the lower vnode, and
dotdot lookups relative to that directory will instantiate new nullfs
vnodes outside of the nullfs mountpoint, effectively shadowing the lower
filesystem.

This phenomenon can be abused to escape a chroot, since the nullfs
vnodes instantiated by these dotdot lookups defeat the root vnode check
in vfs_lookup(), which uses vnode pointer equality to test for the
process root.

Fix this by extending nullfs and unionfs to perform the same check,
exploiting the fact that the passed componentname is embedded in a
nameidata structure to avoid changing the VOP_LOOKUP interface.  That
is, add a flag to indicate that containerof can be used to get the full
nameidata structure, and perform the root vnode check on the lower vnode
when performing a dotdot lookup.

Approved by:	so
Security:	FreeBSD-SA-26:02.jail
Security:	CVE-2025-15547
PR:		262180
Reviewed by:	olce, kib
MFC after:	2 weeks
Differential Revision:	https://reviews.freebsd.org/D50418

(cherry picked from commit 7587f6d484)
(cherry picked from commit 592de68e32)
2026-01-26 16:45:56 +00:00
Konstantin Belousov 78b90c34c3 nullfs lookup: cn_flags is 64bit
Approved by:	so
Reviewed by:	olce
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
Differential revision:	https://reviews.freebsd.org/D50390

(cherry picked from commit 89549c2348)
(cherry picked from commit 19b91b1553)
2026-01-26 16:45:53 +00:00
Konstantin Belousov fd02eb5592 vm_fault: only rely on PG_ZERO when the page was newly allocated
Approved by:	so
Security:	FreeBSD-EN-26:03.vm

(cherry picked from commit cff67bc43d)
(cherry picked from commit babac9d7bc)
2026-01-26 15:38:02 +00:00
Konstantin Belousov 4967e14ba2 vm_object_page_remove(): clear pager even if there is no resident pages
Approved by:	so
Security:	FreeBSD-EN-26:03.vm

(cherry picked from commit 72a447d0bc)
(cherry picked from commit 1dc8b622b3)
2026-01-26 15:37:47 +00:00
Mark Johnston eb5a6f5f9f Add UPDATING entries and bump version
Approved by:	so
2025-12-16 23:41:46 +00:00
Mark Johnston 35cee6a901 rtsold: Validate entries in domain search lists
Reported by:	Kevin Day <[email protected]>
Approved by:	so
Security:	FreeBSD-SA-25:12.rtsold
Security:	CVE-2025-14558
2025-12-16 23:41:40 +00:00
Kyle Evans 60026b0636 ipfw: pmod: avoid further rule processing after tcp-mod failures
m_pullup() here will have freed the mbuf chain, but we pass back an
IP_FW_DENY without any signal that the outer loop should finish.  Thus,
rule processing continues without an mbuf and there's a chance that we
conclude that the packet may pass (but there's no mbuf remaining)
depending on the rules that follow it.

PR:		284606
Reviewed by:	ae
Approved by:	so
Security:	FreeBSD-SA-25:11.ipfw
Security:	CVE-2025-14769

(cherry picked from commit c0382512bf)
(cherry picked from commit 9436058454)
2025-12-16 01:55:38 +00:00
Gordon Tetlow 4fc17862cb Add UPDATING entries and bump version.
Approved by:	so
2025-11-26 08:12:10 -08:00
Gordon Tetlow 9b0808259a Add a fix to scrub unsolicited NS RRSets to prevent cache poisoning.
Approved by:	so
Obtained from:	NLnet Labs
Security:	FreeBSD-SA-25:10.unbound
Security:	CVE-2025-11411
2025-11-26 08:09:36 -08:00
Mark Johnston c4530d6e5f Add UPDATING entries and bump version
Approved by:	so
2025-10-22 15:53:22 +00:00
Mark Johnston 8a7adde307 so_reuseport_lb_test: Add a test case for connected UDP sockets
Approved by:	so

(cherry picked from commit 1dd66c6ac2)
(cherry picked from commit 8e999e63c3)
2025-10-22 15:53:11 +00:00
Mark Johnston 90e14aa082 inpcb: Ignore SO_REUSEPORT_LB on connected sockets
While TCP disallows connect()ing a socket with SO_REUSEPORT_LB, UDP does
not.  As a result, a connected UDP socket can be placed in the lbgroup
hash and thus receive datagrams from sources other than the connected
host.

Reported by:	Amit Klein <[email protected]>
Reported by:	Omer Ben Simhon <[email protected]>
Reviewed by:	glebius
Approved by:	so
Security:	FreeBSD-SA-25:09.netinet
Security:	CVE-2025-24934

(cherry picked from commit 320ad3dec5)
(cherry picked from commit df888c8f41)
2025-10-22 15:52:57 +00:00
Gordon Tetlow c106ed3325 Add UPDATING entries and bump version.
Approved by:	so
2025-09-30 08:36:55 -07:00
Gordon Tetlow ae7c74cfa5 Fix issue from OpenSSL.
Out-of-bounds read & write in RFC 3211 KEK Unwrap (CVE-2025-9230)

Obtained from:	OpenSSL
Approved by:	so
Security:	FreeBSD-SA-25:08.openssl
Security:	CVE-2025-9230

(cherry picked from commit c0dbaf2b5d)
2025-09-30 08:32:35 -07:00
Colin Percival ab91dd76ff freebsd-update: Library ordering
Upgrading from 14.x to 15.x with freebsd-update broke because libc
depends on the new libsys library; freebsd-update installed the new
libc before creating libsys, and every step after that failed because
all the tools (including gunzip and install) are dynamically linked
and need a working libc.

Enforce ordering when installing shared objects: First libsys, then
libc, then libthr, and then all the rest of the shared object files.

This is a candidate for an Errata Notice since the issue this fixes
breaks upgrades.

PR:		289769
Reported by:	Graham Perrin
Reviewed by:	kib
MFC after:	3 days
Sponsored by:	https://www.patreon.com/cperciva
Differential Revision:	https://reviews.freebsd.org/D52688
Approved by:	so
Security:	FreeBSD-EN-25:18.freebsd-update

(cherry picked from commit 7ece602e00)
(cherry picked from commit 87eb52f1b0)
2025-09-29 21:58:26 -07:00
Gordon Tetlow e8acfa0be3 Add UPDATING entries and bump version.
Approved by:    so
2025-09-16 09:28:16 -07:00
John-Mark Gurney 751971e554 arm64: prevent panic when using syscall mux + large arg call (mmap)
if the syscall muxes are used, up to two additional arguments
may be required.  This means that the 8 required for mmap increases
up to 10 (for __syscall).

Sponsored by:   Juniper Networks, Inc.
Approved by:	so
Security:	FreeBSD-EN-25:15.arm64

(cherry picked from commit 740b879c6a)
(cherry picked from commit 98ac13c4ba)
2025-09-13 17:22:42 -07:00
Gordon Tetlow 23bc592b8f Add UPDATING entries and bump version.
Approved by:	so
2025-08-07 17:23:24 -07:00
Martin Matuska 798b7b161a libarchive: merge from vendor branch
libarchive 3.8.1

New features:
 #2088 7-zip reader: improve self-extracting archive detection
 #2137 zip writer: added XZ, LZMA, ZSTD and BZIP2 support
 #2403 zip writer: added LZMA + RISCV BCJ filter
 #2601 bsdtar: support --mtime and --clamp-mtime
 #2602 libarchive: mbedtls 3.x compatibility

Security fixes:
 #2422 tar reader: Handle truncation in the middle of a GNU long linkname
       (CVE-2024-57970)
 #2532 tar reader: fix unchecked return value in list_item_verbose()
       (CVE-2025-25724)
 #2532 unzip: fix null pointer dereference (CVE-2025-1632)
 #2568 warc: prevent signed integer overflow (CVE-2025-5916)
 #2584 rar: do not skip past EOF while reading (CVE-2025-5918)
 #2588 tar: fix overflow in build_ustar_entry (CVE-2025-5917)
 #2598 rar: fix double free with over 4 billion nodes (CVE-2025-5914)
 #2599 rar: fix heap-buffer-overflow (CVE-2025-5915)

Important bugfixes:
 #2399 7-zip reader: add SPARC filter support for non-LZMA compressors
 #2405 tar reader: ignore ustar size when pax size is present
 #2435 tar writer: fix bug when -s/a/b/ used more than once with b flag
 #2459 7-zip reader: add POWERPC filter support for non-LZMA compressors
 #2519 libarchive: handle ARCHIVE_FILTER_LZOP in archive_read_append_filter
 #2539 libarchive: add missing seeker function to archive_read_open_FILE()
 #2544 gzip: allow setting the original filename for gzip compressed files
 #2564 libarchive: improve lseek handling
 #2582 rar: support large headers on 32 bit systems
 #2587 bsdtar: don't hardlink negative inode files together
 #2596 rar: support large headers on 32 bit systems
 #2606 libarchive: support @-prefixed Unix epoch timestamps as date strings
 #2634 tar: Support negative time values with pax
 #2637 tar: Keep block alignment after pax error
 #2642 libarchive: fix FILE_skip regression
 #2643 tar: Handle extra bytes after sparse entries
 #2649 compress: Prevent call stack overflow
 #2651 iso9660: always check archive_string_ensure return value

CVE:		CVE-2024-57970, CVE-2025-1632, CVE-2025-25724,
		CVE-2025-5914, CVE-2025-5915, CVE-2025-5916,
		CVE-2025-5917, CVE-2025-5918
PR:		286944 (exp-run on main, libarchive 3.8.0)

Approved by:	so
Security:	FreeBSD-SA-25:07.libarchive

(cherry picked from commit 2e113ef824)
(cherry picked from commit f47afeb2ce)
2025-08-07 16:50:06 -07:00
Gordon Tetlow 341d92aef0 Add UPDATING entries and bump version.
Approved by:    so
2025-07-01 23:01:59 -07:00
Gordon Tetlow 95e9c54b39 Fix Use-after-free in multi-threaded xz decoder.
Approved by:	so
Security:	FreeBSD-SA-25:06.xz
Security:	CVE-2025-31115
2025-07-01 22:55:41 -07:00
Arthur Kiyanovski 575644144d ena: Bump driver version to v2.8.1
Approved by:	so
Security:	FreeBSD-EN-25:11.ena

(cherry picked from commit 59b30c1a86)
(cherry picked from commit 7ea71ba86a)
2025-07-01 22:53:06 -07:00
David Arinzon 35c2729211 ena: Fix misconfiguration when requesting regular LLQ
Patch 0a33c047a443 introduced new values to
hw.ena.force_large_llq_header. The default value of 2 means no
preference, while 0 and 1 act as the previous false and true
respectively, which allowed forcefully setting regular or large LLQ.

There are 2 ways to force the driver to select regular LLQ:

1. Setting hw.ena.force_large_llq_header = 0 via sysctl.
2. Turning on ena express, which makes the recommendation by the FW to
   be regular LLQ.

When the device supports large LLQ but the driver is forced to
regular LLQ, llq_config->llq_ring_entry_size_value is never initialized
and since it is a variable allocated on the stack, it stays garbage.

Since this variable is involved in calculating max_entries_in_tx_burst,
it could cause the maximum burst size to be zero. This causes the driver
to ignore the real maximum burst size of the device, leading to driver
resets in devices that have a maximum burst size (Nitro v4 and on. see
[1] for more information).

In case the garbage value is 0, the calculation of
max_entries_in_tx_burst divides by 0 and causes kernel panic.

The patch modifies the logic to take into account all use-cases and
ensure that the relevant fields are properly initialized.

[1]: https://docs.aws.amazon.com/ec2/latest/instancetypes/ec2-nitro-instances.html

Fixes: 0a33c047a443 ("ena: Support LLQ entry size recommendation from device")
Sponsored by: Amazon, Inc.
Differential Revision: https://reviews.freebsd.org/D50040
Approved by:	so
Security:	FreeBSD-EN-25:11.ena

(cherry picked from commit 56c45700f2)
(cherry picked from commit 162b5bbb40)
2025-07-01 22:52:31 -07:00
Gordon Tetlow 4d9c4ecf6a Fix corruption in ZFS replication streams from encrypted datasets.
From the upstream pull request merges:
 #17340 b144b160b Fix 2 bugs in non-raw send with encryption

Obtained from:	OpenZFS
Approved by:	so
Security:	FreeBSD-EN-25:10.zfs
2025-07-01 22:47:29 -07:00
Aurélien Croc de Suray f936833911 libc: allow __cxa_atexit handlers to be added during __cxa_finalize
science/dlib-cpp reveals an interesting scenario that works fine on
other platforms but not on FreeBSD; notably, it ends up creating a new
global object from some destructor which is called during
__cxa_finalize.  This breaks when libdlib is dlopen()ed and then
subsequently dlclose()ed, as we never end up invoking the created
object's dtor until program exit when the shlib is already unmapped.

Fix it by noting when we're in the middle of __cxa_finalize for a dso,
and then restarting the search if __cxa_atexit() was called in the
middle somewhere.

We wait until we've processed the initial set before starting over and
processing the newly added handlers as if it were a complete set of
handlers added during runtime.  The alternative is calling them as
they're added to maintain a LIFO in terms of total ordering, but in
theory a constructor could add another global object that also needs to
be destroyed, and that object needs to be destroyed after the one that
constructed it to avoid creating unexpected lifetime issues.

This manifests in the pdlib PHP extension for dlib crashing, see [0].

[0] https://github.com/goodspb/pdlib/issues/39

PR:		285870
Reviewed by:	kevans (also supplied commit message)
Approved by:	so
Security:	FreeBSD-EN-25:09.libc

(cherry picked from commit 23427c8e1f)
(cherry picked from commit 04f7496f89)
2025-07-01 22:42:46 -07:00
Philip Paeps 37edc07ede Add UPDATING entries and bump version
Approved by:	so
2025-04-10 22:39:09 +08:00
Michael Osipov 74176002ff caroot: update the root bundle
Summary:
- Seven (7) new roots
- Four (4) distrusted roots
- Fourteen (14) removed (expired) roots

Approved by:	so
Security:	FreeBSD-EN-25:08.caroot
Reviewed by:	kevans
Differential Revision:	https://reviews.freebsd.org/D49294

(cherry picked from commit 0100da4deb)
(cherry picked from commit f89c056e11)
2025-04-10 22:39:08 +08:00
Philip Paeps dec0bf8096 contrib/expat: update libexpat from 2.6.4 to 2.7.1
Changes: https://github.com/libexpat/libexpat/blob/R_2_7_1/expat/Changes

Note that libbsdxml(3) is only intended to used by utilities in the
FreeBSD base system.  The vulnerability addressed by expat 2.7.0 is not
exploitable on FreeBSD as supported by the security-officer@ team.

Approved by:	so
Security:	FreeBSD-EN-25:05.expat
Security:	CVE-2024-8176

(cherry picked from commit fe9278888f)
(cherry picked from commit 41b768ae19)
(cherry picked from commit 03a1992591)
(cherry picked from commit adc9e9e8db)
(cherry picked from commit 00c8538e87)
(cherry picked from commit 5630672e6f)
2025-04-10 22:39:08 +08:00
Philip Paeps 74aa5e2a7b contrib/tzdata: import tzdata 2025b
Changes: https://github.com/eggert/tz/blob/2025b/NEWS

Approved by:	so
Security:	FreeBSD-EN-25:04.tzdata

(cherry picked from commit d2cccdef30)
(cherry picked from commit 7b17666c32)
2025-04-10 22:39:08 +08:00
Colin Percival 882b9f3f22 Update in preparation for 13.5-RELEASE
- Bump BRANCH to RELEASE
- Add the anticipated RELEASE announcement date
- Set a static __FreeBSD_version

Approved by:	re (implicit)
Sponsored by:	Amazon
2025-03-07 00:00:00 +00:00
Colin Percival a24b044a1e 13.5: Update to RC1
Approved by:	re (implicit)
Sponsored by:	Amazon
2025-02-27 16:48:37 -08:00
Colin Percival 956fb94dd6 13.5: Switch from "quarterly" to "release" pkgs
Approved by:	re (implicit)
Sponsored by:	Amazon
2025-02-27 16:48:26 -08:00
Olivier Certner cf411e5ed3 queue: Fix STAILQ_ASSERT_EMPTY()
The 'while' part corresponding to the 'do' was missing.

Did not notice the problem as later commits using it have been stashed
and never reworked up to now, and it is currently unused in the tree.

While here, fix spacing after the '#define' in the !(_KERNEL &&
INVARIANS) part.

Fixes:          34740937f7 ("queue: New debug macros for STAILQ")
MFC after:      1 minute
Sponsored by:   The FreeBSD Foundation

(cherry picked from commit d3c4b002d1)
(cherry picked from commit 4fd887f08b)

Approved by:    re (cperciva)
2025-02-28 00:33:27 +01:00
Jose Luis Duran e8043c76e3 openssh: Fix blacklistd sshd-session integration
In version 9.8, the server was split into a listener binary, sshd(8),
and a per-session binary "sshd-session".

Our blacklistd changes also have to be moved from sshd.c to
sshd-session.c.

Reviewed by:	emaste
Approved by:	emaste (mentor)
Fixes:	0fdf8fae8b ("openssh: Update to 9.8p1")
MFC after:	3 days
Differential Revision:	https://reviews.freebsd.org/D49116

(cherry picked from commit 61d8af38bf)
(cherry picked from commit 707ac59c2b)
(cherry picked from commit f931a32bca)

Approved by:	re (cperciva)
2025-02-26 17:16:16 +00:00
Colin Percival 93b7f9301c pkg-stage.sh: Remove kde entirely
The package set for FreeBSD 13.5 comes from the 2025Q1 branch, which
doesn't have the new x11/kde (aka KDE 6) port; but shipping x11/kde5
(which is still in the 2025Q1 branch) doesn't make much sense either
since a few weeks after the release that will no longer be available
in either "latest" or "quarterly" package sets.

Just remove KDE packages from the 13.5 DVD entirely; this also makes
the DVD image fit into 4.7 GB size limit of physical DVDs again.

Direct commit to releng/13.5.

With hat:	re
Approved by:	re (cperciva)
Fixes:	ee6c7bf50b ("pkg-stage.sh: kde5 -> kde")
Sponsored by:	Amazon
2025-02-21 08:18:19 -08:00
Colin Percival 7f6d09003a 13.5: Update to BETA3
Approved by:	re (implicit)
Sponsored by:	Amazon
2025-02-20 16:05:22 -08:00
Colin Percival ee6c7bf50b pkg-stage.sh: kde5 -> kde
The "kde5" package no longer exists; KDE goes to 6.

Note: Depending on the size of 13.5-BETA3 DVD images, KDE might end
up being removed from this list in the near future.

With hat:	re@
Approved by:	re (cperciva)
MFC after:	30 seconds
Sponsored by:	Amazon

(cherry picked from commit 0d7b98c06c)
(cherry picked from commit 4ddbb7945c)
2025-02-20 16:05:11 -08:00
Ed Maste 31dcdee20a openssh: Update to 9.9p2
This release exists primarily to fix two security bugs.  The fixes have
been independently imported into FreeBSD.  This import serves to update
the ssh and sshd version number.

A few minor bug fixes are also included; see the upstream release notes
for full details of the 9.9p2 release
(https://www.openssh.com/releasenotes.html).

Sponsored by:	The FreeBSD Foundation

(cherry picked from commit 0ae642c7dd)

Approved by:	re (accelerated MFC)

(cherry picked from commit 059b786b7d)
(cherry picked from commit a8c1ea2614)

Approved by:	re (cperciva)
2025-02-20 13:45:48 -05:00
Ed Maste cb8e164fbb openssh: Update to 9.9p1
Highlights from the release notes are reproduced below.  Bug fixes and
improvements that were previously merged into FreeBSD have been elided.

See the upstream release notes for full details of the 9.9p1 release
(https://www.openssh.com/releasenotes.html).

---

Future deprecation notice
=========================

OpenSSH plans to remove support for the DSA signature algorithm in
early 2025.

Potentially-incompatible changes
--------------------------------

 * ssh(1): remove support for pre-authentication compression.

 * ssh(1), sshd(8): processing of the arguments to the "Match"
   configuration directive now follows more shell-like rules for
   quoted strings, including allowing nested quotes and \-escaped
   characters.

New features
------------

 * ssh(1), sshd(8): add support for a new hybrid post-quantum key
   exchange based on the FIPS 203 Module-Lattice Key Enapsulation
   mechanism (ML-KEM) combined with X25519 ECDH as described by
   https://datatracker.ietf.org/doc/html/draft-kampanakis-curdle-ssh-pq-ke-03
   This algorithm "mlkem768x25519-sha256" is available by default.

 * ssh(1), sshd(8), ssh-agent(1): prevent private keys from being
   included in core dump files for most of their lifespans. This is
   in addition to pre-existing controls in ssh-agent(1) and sshd(8)
   that prevented coredumps. This feature is supported on OpenBSD,
   Linux and FreeBSD.

 * All: convert key handling to use the libcrypto EVP_PKEY API, with
   the exception of DSA.

Bugfixes
--------

 * sshd(8): do not apply authorized_keys options when signature
   verification fails. Prevents more restrictive key options being
   incorrectly applied to subsequent keys in authorized_keys. bz3733

 * ssh-keygen(1): include pathname in some of ssh-keygen's passphrase
   prompts. Helps the user know what's going on when ssh-keygen is
   invoked via other tools. Requested in GHPR503

 * ssh(1), ssh-add(1): make parsing user@host consistently look for
   the last '@' in the string rather than the first. This makes it
   possible to more consistently use usernames that contain '@'
   characters.

 * ssh(1), sshd(8): be more strict in parsing key type names. Only
   allow short names (e.g "rsa") in user-interface code and require
   full SSH protocol names (e.g. "ssh-rsa") everywhere else. bz3725

 * ssh-keygen(1): clarify that ed25519 is the default key type
   generated and clarify that rsa-sha2-512 is the default signature
   scheme when RSA is in use. GHPR505

---

Reviewed by:	jlduran (build infrastructure)
Reviewed by:	cy (build infrastructure)
Sponsored by:	The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D48947

(cherry picked from commit 3d9fd9fcb4)

Approved by:	re (accelerated MFC)

(cherry picked from commit 802386cd37)
(cherry picked from commit 6e688e6d4f)

Approved by:	re (cperciva)
2025-02-20 13:45:36 -05:00
Ed Maste b74bb7f011 openssh: Update to 9.8p1
Highlights from the release notes are reproduced below.  Some security
and bug fixes were previously merged into FreeBSD and have been elided.
See the upstream release notes for full details
(https://www.openssh.com/releasenotes.html).

---

Future deprecation notice
=========================

OpenSSH plans to remove support for the DSA signature algorithm in
early 2025.

Potentially-incompatible changes
--------------------------------

 * sshd(8): the server will now block client addresses that
   repeatedly fail authentication, repeatedly connect without ever
   completing authentication or that crash the server. See the
   discussion of PerSourcePenalties below for more information.
   Operators of servers that accept connections from many users, or
   servers that accept connections from addresses behind NAT or
   proxies may need to consider these settings.

 * sshd(8): the server has been split into a listener binary, sshd(8),
   and a per-session binary "sshd-session". This allows for a much
   smaller listener binary, as it no longer needs to support the SSH
   protocol. As part of this work, support for disabling privilege
   separation (which previously required code changes to disable) and
   disabling re-execution of sshd(8) has been removed. Further
   separation of sshd-session into additional, minimal binaries is
   planned for the future.

 * sshd(8): several log messages have changed. In particular, some
   log messages will be tagged with as originating from a process
   named "sshd-session" rather than "sshd".

 * ssh-keyscan(1): this tool previously emitted comment lines
   containing the hostname and SSH protocol banner to standard error.
   This release now emits them to standard output, but adds a new
   "-q" flag to silence them altogether.

 * sshd(8): (portable OpenSSH only) sshd will no longer use argv[0]
   as the PAM service name. A new "PAMServiceName" sshd_config(5)
   directive allows selecting the service name at runtime. This
   defaults to "sshd". bz2101

New features
------------

 * sshd(8): sshd(8) will now penalise client addresses that, for various
   reasons, do not successfully complete authentication. This feature is
   controlled by a new sshd_config(5) PerSourcePenalties option and is
   on by default.

 * ssh(8): allow the HostkeyAlgorithms directive to disable the
   implicit fallback from certificate host key to plain host keys.

Portability
-----------

 * sshd(8): expose SSH_AUTH_INFO_0 always to PAM auth modules
   unconditionally. The previous behaviour was to expose it only when
   particular authentication methods were in use.

 * ssh(1), ssh-agent(8): allow the presence of the WAYLAND_DISPLAY
   environment variable to enable SSH_ASKPASS, similarly to the X11
   DISPLAY environment variable. GHPR479

---

Sponsored by:	The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D48914

(cherry picked from commit 0fdf8fae8b)
(cherry picked from commit b4bb480ae9)
(cherry picked from commit e95979047a)
(cherry picked from commit dcb4ae528d)

Approved by:	re (accelerated MFC)

(cherry picked from commit ff2fd01609)
(cherry picked from commit c845ae4755)

Approved by:	re (cperciva)
2025-02-20 13:45:19 -05:00
Ed Maste d2b7937c2c ssh_config.5: Remove redundant CheckHostIP default text
In 2000 (commit a95c122521) we changed the CheckHostIP default to
"no".  We added text to ssh_config(5) documenting FreeBSD's default.

In 2021 OpenSSH made the same change, released with OpenSSH 8.5p1.
When we imported the update the added text remained, resulting in:

    If the option is set to no (the default), the check will not be
    executed.  The default is no.

Remove the now-redundant text.

Fixes: 206be79acb ("Vendor import of OpenSSH 8.5p1")
Sponsored by:	The FreeBSD Foundation

(cherry picked from commit 06016adacc)
(cherry picked from commit 2c97e33316)
(cherry picked from commit 935e29dcdd)

Approved by:	re (cperciva)
2025-02-20 13:45:11 -05:00
Ed Maste ef280c2e5f libssh: Remove progressmeter
It is used only by scp and sftp, and already included directly in their
Makefiles.  It does not belong in libssh.

Fixes: d8b043c8d4 ("Update for 3.6.1p1; also remove Kerberos IV shims.")
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D48871

(cherry picked from commit c0af329525)
(cherry picked from commit 8a02eb2c1e)
(cherry picked from commit 63d3c24522)

Approved by:	re (cperciva)
2025-02-20 13:45:03 -05:00
Ed Maste 6cb9cfffa8 ssh: Move XAUTH_PATH setting to ssh.mk
XAUTH_PATH is normally set (in the upstream build infrastructure) in
config.h.  We previously set it in ssh and sshd's Makefiles if LOCALBASE
is set, and over time have sometimes also defined it in config.h.

Leave it unset in config.h and move the CFLAGS logic to to ssh.mk so
that it will be set when building all ssh libraries and programs but
still be set by LOCALBASE.

Reviewed by:	jlduran
Sponsored by:	The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D48907

(cherry picked from commit a63701848f)
(cherry picked from commit 73dd56ffcd)
(cherry picked from commit 10e9add50f)

Approved by:	re (cperciva)
2025-02-20 13:44:55 -05:00
Ed Maste 78b4f77518 ssh: Bump VersionAddendum for CVE fixes
Approved by:	so
Sponsored by:	The FreeBSD Foundation

(cherry picked from commit 62df41ae0a)
(cherry picked from commit 24ce323f02)
(cherry picked from commit 2fc62d0bd4)

Approved by:	re (implicit)
2025-02-20 13:00:27 -05:00
Ed Maste 88fcdcb08a ssh: Fix cases where error codes were not correctly set
Obtained from:	OpenSSH 38df39ecf278
Security:	CVE-2025-26465
Approved by:	so
Sponsored by:	The FreeBSD Foundation

(cherry picked from commit 170059d6d3)
(cherry picked from commit 4ad8c195cf)
(cherry picked from commit 8c67967cb1)

Approved by:	re (implicit)
2025-02-20 13:00:19 -05:00
Ed Maste fb30987533 ssh: Don't reply to PING in preauth phase or during KEX
Obtained from:	OpenSSH 5e07dee272c3
Security:	CVE-2025-26466
Approved by:	so
Sponsored by:	The FreeBSD Foundation

(cherry picked from commit 8a16d0831e)
(cherry picked from commit 34798cb576)
(cherry picked from commit 3ea366f744)

Approved by:	re (implicit)
2025-02-20 13:00:11 -05:00
Colin Percival 6e06a07978 13.5: Update to BETA2
Approved by:	re (implicit)
Sponsored by:	Amazon
2025-02-14 00:00:00 +00:00
Zhenlei Huang 6b0086795d sysctl: Harden sysctl_handle_string() against unterminated string
In case a variable string which is not null-terminated is passed in,
strlen() may report a length exceeding the max length, hence it is
possible to leak a portion of kernel memory to the userland.

Harden that by using strnlen() to limit the length to the max length.
While here, refactor the code a little to improve readability.

Note that, when calculating the out length, the null terminator '\0' of
the string is taken into account if available. This is not really
necessary but userland applications may have already relied on this
behavior.

Reviewed by:	avg, kib, olce
Approved by:	re (cperciva)
Fixes:		210176ad76 sysctl(9): add CTLFLAG_NEEDGIANT flag
MFC after:	4 days
Differential Revision:	https://reviews.freebsd.org/D48881

(cherry picked from commit 1951235537)
(cherry picked from commit 8ca77f9f9e)
(cherry picked from commit dcd7286d90)
2025-02-14 00:52:50 +08:00
Zhenlei Huang 3afa8f08bc MAC: mac_biba, mac_lomac: Fix setting loader tunables
A string loader tunable requires setting the len parameter to a nonzero
value, typically the size of the string, to have the flag CTLFLAG_TUN
work correctly [1] [2].

Without this fix security.mac.{biba,lomac}.trusted_interfaces would
have no effect at all.

[1] 3da1cf1e88 Extend the meaning of the CTLFLAG_TUN flag to automatically ...
[2] 6a3287f889 Fix regression issue after r267961. Handle special string case ...

Reviewed by:	olce, kib
Approved by:	re (cperciva)
Fixes:		af3b2549c4 Pull in r267961 and r267973 again ...
MFC after:	3 days
Differential Revision:	https://reviews.freebsd.org/D48898

(cherry picked from commit 7d4c0fac8c)
(cherry picked from commit 04f360b782)
(cherry picked from commit 87836ab994)
2025-02-14 00:52:50 +08:00
Michael Tuexen cd91df3292 icmp: use per rate limit randomized jitter
Using the same random jitter for multiple rate limits allows an
attacker to use one rate limiter to figure out the current jitter
and then use this knowledge to de-randomize the other rate limiters.
This can be mitigated by using a separate randomized jitter for each
rate limiter.
This issue was reported as issue number 10 in Keyu Man et al.:
SCAD: Towards a Universal and Automated Network Side-Channel
Vulnerability Detection

Reviewed by:		rrs, Peter Lei, glebius
Sponsored by:		Netflix, Inc.
Differential Revision:	https://reviews.freebsd.org/D48804
Approved by:		re (cperciva)

(cherry picked from commit 923c223f27)
(cherry picked from commit e1dd07ede9)
2025-02-13 15:04:39 +01:00
Michael Tuexen 5f2744d520 icmp: improve INVARIANTS check
Actually check the conditions that are enforced by the error checking
code instead of a condition which is
* checking a number to be non-negative instead of positive
* depending on a random number
Perform the checks consistently for ICMPv4 and ICMPv6.

Reviewed by:		glebius, rrs, cc
Sponsored by:		Netflix, Inc.
Differential Revision:	https://reviews.freebsd.org/D48001
Approved by:		re (cperciva)

(cherry picked from commit c9febea3dc)
(cherry picked from commit bd6a89a6c3)
2025-02-13 15:03:55 +01:00
Gleb Smirnoff a3b66c4bf0 icmp: correct the assertion that checks limit + jitter
Fixes:	4399e055ea
Approved by:	re (cperciva)

(cherry picked from commit f7c4d12bcd)
(cherry picked from commit 1b4561cf4b)
2025-02-13 15:03:13 +01:00
Gleb Smirnoff 881ba70c1a icmp: allow zero value for ICMP limits
Zero means limit is disabled, so the value doesn't need to be checked
against jitter value.

Fixes:	ac44739fd8
Fixes:	a03aff88a1
Approved by:	re (cperciva)

(cherry picked from commit 4399e055ea)
(cherry picked from commit 0b29ef1e3f)
2025-02-13 15:02:12 +01:00
Gleb Smirnoff ebda0be762 icmp6: bring rate limiting on a par with IPv4
Use counter_ratecheck() instead of racy and slow ppsratecheck. Use a
separate counter for every currently known type of ICMPv6. Provide logging
of ratelimit events. Provide jitter to counter open UDP port detection.

With minor tweaks from tuexen@ to fix merge problems.

Reviewed by:		tuexen, zlei
Differential Revision:	https://reviews.freebsd.org/D44482
Approved by:		re (cperciva)

(cherry picked from commit a03aff88a1)
(cherry picked from commit 1cc0ac5ef3)
2025-02-13 15:01:36 +01:00
Gleb Smirnoff a7ad643719 icmp6: rate limit our echo replies
The generation of ICMP6_ECHO_REPLY bypasses icmp6_error(), thus rate
limit was not applied.

Reviewed by:		tuexen, zlei
Differential Revision:	https://reviews.freebsd.org/D44480
Approved by:		re (cperciva)

(cherry picked from commit 32aeee8ce7)
(cherry picked from commit 90ecc3fc67)
2025-02-13 15:00:57 +01:00
Gleb Smirnoff 9880ce0765 icmp6: make icmp6_ratelimit() responsible to update the stats counter
Reviewed by:		tuexen
Differential Revision:	https://reviews.freebsd.org/D44479
Approved by:		re (cperciva)

(cherry picked from commit c6c96aaba8)
(cherry picked from commit dc167e64dc)
2025-02-13 15:00:23 +01:00
Gleb Smirnoff 1ed60133f6 icmp: improve ICMP limit jitter
Instead of fixing up invalid values set by a user in badport_bandlim()
which is a fast path function, provide a sysctl handler
sysctl_icmplim_and_jitter(), that will check that jitter is less than the
limit.

Provide jitter initilization function icmplim_new_jitter() used at boot,
in the sysctl handler and when we actually hit the limit.  This also fixes
no jitter on a fresh booted system until first limit hit.

Instead of CVE number provide link the the actual paper that explains what
and why we are doing here.  The CVE number isn't very informative, it will
just tell you what RedHat version you need to upgrade to.

Reviewed by:		kp, tuexen, zlei
Differential Revision:	https://reviews.freebsd.org/D44478
Approved by:		re (cperciva)

(cherry picked from commit ac44739fd8)
(cherry picked from commit 18058544c6)
2025-02-13 14:59:46 +01:00
Gleb Smirnoff b6dc660155 icmp: when logging ICMP ratelimiting message use correct jitter value
The limiting of the very last second has been done using certain jitter
value.  We update the jitter for the next second.  But the logging should
report the jitter before the change.

Reviewed by:		kp, tuexen, zlei
Differential Revision:	https://reviews.freebsd.org/D44477
Approved by:		re (cperciva)

(cherry picked from commit b508545ce0)
(cherry picked from commit a71eee300b)
2025-02-13 14:59:09 +01:00
Gleb Smirnoff a0146592cd icmp: hide icmp_bandlimit_uninit() under VIMAGE
The uninitialization may be executed only on a kernel with VIMAGE.

Reviewed by:		kp, tuexen, zlei
Differential Revision:	https://reviews.freebsd.org/D44476
Approved by:		re (cperciva)

(cherry picked from commit 9d7f17d746)
(cherry picked from commit a6d5c6a04f)
2025-02-13 14:57:18 +01:00
Gleb Smirnoff ebc96321e7 icmp: do not store per-VNET identical array of strings
We need per-VNET struct counter_rate, but we don't need per-VNET set of
const char *.  Also, identical word "response" can go into the format
string instead of being stored 7 times.

Reviewed by:		kp, zlei, tuexen
Differential Revision:	https://reviews.freebsd.org/D44475
Approved by:		re (cperciva)

(cherry picked from commit 7142ab4790)
(cherry picked from commit 0939f3a046)
2025-02-13 14:56:10 +01:00
Ronald Klop e375421e24 Remove obsolete clang18 files for aarch64
This fixes a warning from "make delete-old" about a non-empty directory
on aarch64.

Reviewed by:	dim
Approved by:	re (cperciva)
Fixes:		0fca6ea1d4
MFC after:	3 days
Differential Revision: https://reviews.freebsd.org/D48904

(cherry picked from commit 09b435d3dc)
(cherry picked from commit 9370c2c331)
2025-02-13 16:59:36 +01:00
Dag-Erling Smørgrav 1aaec1978a unifdef: Fix collision check when adding symbols.
findsym() is intended for use while parsing input, so it should not be
called from addsym2() or indirectsym(), which are called before any
input is processed.

MFC after:	1 week
Sponsored by:	Klara, Inc.
Reviewed by:	kevans
Differential Revision:	https://reviews.freebsd.org/D48733
Approved by:	re (cperciva)

(cherry picked from commit c63af363c2)
(cherry picked from commit 931b099029)
2025-02-13 16:12:02 +01:00
Kirk McKusick dfe803fdbc Defer the January 19, 2038 date limit in UFS1 filesystems to February 7, 2106
Standardize the definition of a UFS dinode.

Differential Revision: https://reviews.freebsd.org/D48472

(cherry picked from commit 1111a44301)
(cherry picked from commit aa90fbed15)
(cherry picked from commit 256389eaf1)
(cherry picked from commit 6cd973d903)
(cherry picked from commit e1ebda4458)
(cherry picked from commit 6f87402a02)

Approved-by: re (cperciva)
2025-02-09 23:38:51 -08:00
Colin Percival ef6b3c5888 release: Chase location of pkg repo databases
pkg used to store copies of upstream repository databases in
/var/db/pkg/repo-*.sqlite.  About a year ago this was moved to
/var/db/pkg/repos/*/, resulting in FreeBSD cloud images no longer
having those (unhelpful since they'll be long out of date before
the cloud images are launched) databases removed.

Remove the correct location, and hope that future pkg updates don't
break the base system again.

Sponsored by:	Amazon
Approved by:	re (cperciva)

(cherry picked from commit 078e8b34b1)
(cherry picked from commit 8984d070d6)
2025-02-09 13:18:40 -08:00
Colin Percival a8f9845e39 13.5: create releng/13.5 branch
Update from PRERELEASE to BETA1
Switch pkg(8) configuration to use the quarterly repository
Bump __FreeBSD_version

Approved by:	re (implicit)
Sponsored by:	Amazon
2025-02-07 00:00:00 +00:00
537 changed files with 56054 additions and 14599 deletions

No files matched your search

+22
View File
@@ -51,6 +51,26 @@
# xargs -n1 | sort | uniq -d;
# done
# 20250310: caroot bundle updated
OLD_FILES+=usr/share/certs/trusted/Entrust_Root_Certification_Authority_-_G4.pem
OLD_FILES+=usr/share/certs/trusted/SecureSign_RootCA11.pem
OLD_FILES+=usr/share/certs/trusted/Security_Communication_RootCA3.pem
OLD_FILES+=usr/share/certs/trusted/SwissSign_Silver_CA_-_G2.pem
OLD_FILES+=usr/share/certs/blacklisted/AddTrust_External_Root.pem
OLD_FILES+=usr/share/certs/blacklisted/AddTrust_Low-Value_Services_Root.pem
OLD_FILES+=usr/share/certs/blacklisted/Staat_der_Nederlanden_Root_CA_-_G2.pem
OLD_FILES+=usr/share/certs/blacklisted/Cybertrust_Global_Root.pem
OLD_FILES+=usr/share/certs/blacklisted/DST_Root_CA_X3.pem
OLD_FILES+=usr/share/certs/blacklisted/GlobalSign_Root_CA_-_R2.pem
OLD_FILES+=usr/share/certs/blacklisted/QuoVadis_Root_CA.pem
OLD_FILES+=usr/share/certs/blacklisted/Sonera_Class_2_Root_CA.pem
OLD_FILES+=usr/share/certs/blacklisted/GeoTrust_Global_CA.pem
OLD_FILES+=usr/share/certs/blacklisted/Staat_der_Nederlanden_EV_Root_CA.pem
OLD_FILES+=usr/share/certs/blacklisted/E-Tugra_Certification_Authority.pem
OLD_FILES+=usr/share/certs/blacklisted/Hongkong_Post_Root_CA_1.pem
OLD_FILES+=usr/share/certs/blacklisted/Security_Communication_Root_CA.pem
OLD_FILES+=usr/share/certs/blacklisted/Trustis_FPS_Root_CA.pem
# 20241201: new clang import which bumps version from 18 to 19
OLD_FILES+=usr/lib/clang/18/include/__clang_cuda_builtin_vars.h
OLD_FILES+=usr/lib/clang/18/include/__clang_cuda_cmath.h
@@ -347,6 +367,7 @@ OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_cxx-powerpc64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_cxx-powerpc64le.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_cxx-riscv64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_static-aarch64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_static-i386.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_static-powerpc64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_static-powerpc64le.a
@@ -365,6 +386,7 @@ OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.dd-aarch64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.dd-x86_64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.fuzzer-aarch64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.fuzzer-x86_64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.fuzzer_interceptors-aarch64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.fuzzer_interceptors-x86_64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a
+128
View File
@@ -12,6 +12,134 @@ Items affecting the ports and packages system can be found in
/usr/ports/UPDATING. Please read that file before updating system packages
and/or ports.
20260430:
13.5-RELEASE-p14 EN-26:11.dhclient
dhclient(8) lease validation is too strict. [EN-26:11.dhclient]
20260429:
13.5-RELEASE-p13 SA-26:12.dhclient
SA-26:13.exec
SA-26:14.pf
SA-26:15.dhclient
SA-26:16.libnv
SA-26:17.libnv
EN-26:09.tzdata
Remote code execution via malicious DHCP options. [SA-26:12.dhclient]
Local privilege escalation via execve(). [SA-26:13.exec]
pf can overflow the stack parsing crafted SCTP packets. [SA-26:14.pf]
Remotely triggerable out-of-bounds heap write in dhclient. [SA-26:15.dhclient]
Stack overflow via select() file descriptor set overflow. [SA-26:16.libnv]
Heap overflow in libnv. [SA-26:17.libnv]
Timezone database information update. [EN-26:09.tzdata]
20260421:
13.5-RELEASE-p12 SA-26:10.tty
SA-26:11.amd64
EN-26:05.vm
Kernel use-after-free bug in the TIOCNOTTY handler. [SA-26:10.tty]
Missing large page handling in pmap_pkru_update_range(). [SA-26:11.amd64]
The page fault handler fails to zero memory. [EN-26:05.vm]
20260325:
13.5-RELEASE-p11 SA-26:08.rpcsec_gss
Remote code execution via RPCSEC_GSS packet validation. [SA-26:08.rpcsec_gss]
20260224:
13.5-RELEASE-p10 SA-26:04.jail
SA-26:05.route
Jail chroot escape via fd exchange with a different jail. [SA-26:04.jail]
Local DoS and possible privilege escalation via routing sockets. [SA-26:05.route]
20260127:
13.5-RELEASE-p9 SA-26:01.openssl
SA-26:02.jail
EN-26:03.vm
Fix multiple vulnerabilities in OpenSSL. [SA-26:01.openssl]
Jail escape by a privileged user via nullfs. [SA-26:02.jail]
The page fault handler fails to zero memory. [EN-26:03.vm]
20251216:
13.5-RELEASE-p8 SA-25:11.ipfw
SA-25:12.rtsold
ipfw denial of service. [SA-25:11.ipfw]
Remote code execution via ND6 Router Advertisements. [SA-25:12.rtsold]
20251126:
13.5-RELEASE-p7 SA-25:10.unbound
Fix cache poison in local-unbound service. [SA-25:10.unbound]
20251022:
13.5-RELEASE-p6 SA-25:09.netinet
SO_REUSEPORT_LB breaks connect(2) for UDP sockets. [SA-25:09.netinet]
20250930:
13.5-RELEASE-p5 EN-25:18.freebsd-update
SA-25:08.openssl
Fix freebsd-update(8) installing libraries in incorrect order. [EN-25:18.freebsd-update]
Fix multiple vulnerabilities in OpenSSL. [SA-25:08.openssl]
20250916:
13.5-RELEASE-p4 EN-25:15.arm64
Fix arm64 syscall(2) allows unprivileged user to panic kernel. [EN-25:15.arm64]
20250808:
13.5-RELEASE-p3 SA-25:07.libarchive
Update libarchive to 3.8.1 to fix integer overflow leading to double
free. [SA-25:07.libarchive]
20250702:
13.5-RELEASE-p2 EN-25:09.libc
EN-25:10.zfs
EN-25:11.ena
SA-25:06.xz
Fix dynamically-loaded C++ libraries crashing at exit [EN-25:09.libc]
Fix corruption in ZFS replication streams from encrypted datasets [EN-25:10.zfs]
Fix ena resets and kernel panic on Nitro v4 or newer instances [EN-25:11.ena]
Fix use-after-free in multi-threaded xz decoder [SA-25:06.xz]
20250410:
13.5-RELEASE-p1 EN-25:04.tzdata
EN-25:05.expat
EN-25:08.caroot
Timezone database information update [EN-25:04.tzdata]
Update expat to 2.7.1 [EN-25:05.expat]
Root certificate bundle update [EN-25:08.caroot]
20250311:
13.5-RELEASE.
20250117:
The layout of NFS file handles for the cd9660 and ext2fs file systems
has changed. An NFS server that exports any of these file systems will
+1 -1
View File
@@ -1,5 +1,5 @@
Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper
Copyright (c) 2001-2022 Expat maintainers
Copyright (c) 2001-2025 Expat maintainers
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
+121 -2
View File
@@ -11,16 +11,23 @@
!! The following topics need *additional skilled C developers* to progress !!
!! in a timely manner or at all (loosely ordered by descending priority): !!
!! !!
!! - <blink>fixing a complex non-public security issue</blink>, !!
!! - teaming up on researching and fixing future security reports and !!
!! ClusterFuzz findings with few-days-max response times in communication !!
!! in order to (1) have a sound fix ready before the end of a 90 days !!
!! grace period and (2) in a sustainable manner, !!
!! - helping CPython Expat bindings with supporting Expat's billion laughs !!
!! attack protection API (https://github.com/python/cpython/issues/90949): !!
!! - XML_SetBillionLaughsAttackProtectionActivationThreshold !!
!! - XML_SetBillionLaughsAttackProtectionMaximumAmplification !!
!! - helping Perl's XML::Parser Expat bindings with supporting Expat's !!
!! security API (https://github.com/cpan-authors/XML-Parser/issues/102): !!
!! - XML_SetBillionLaughsAttackProtectionActivationThreshold !!
!! - XML_SetBillionLaughsAttackProtectionMaximumAmplification !!
!! - XML_SetReparseDeferralEnabled !!
!! - implementing and auto-testing XML 1.0r5 support !!
!! (needs discussion before pull requests), !!
!! - smart ideas on fixing the Autotools CMake files generation issue !!
!! without breaking CI (needs discussion before pull requests), !!
!! - the Windows binaries topic (needs requirements engineering first), !!
!! - pushing migration from `int` to `size_t` further !!
!! including edge-cases test coverage (needs discussion before anything). !!
!! !!
@@ -30,6 +37,116 @@
!! THANK YOU! Sebastian Pipping -- Berlin, 2024-03-09 !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Release 2.7.1 Thu March 27 2025
Bug fixes:
#980 #989 Restore event pointer behavior from Expat 2.6.4
(that the fix to CVE-2024-8176 changed in 2.7.0);
affected API functions are:
- XML_GetCurrentByteCount
- XML_GetCurrentByteIndex
- XML_GetCurrentColumnNumber
- XML_GetCurrentLineNumber
- XML_GetInputContext
Other changes:
#976 #977 Autotools: Integrate files "fuzz/xml_lpm_fuzzer.{cpp,proto}"
with Automake that were missing from 2.7.0 release tarballs
#983 #984 Fix printf format specifiers for 32bit Emscripten
#992 docs: Promote OpenSSF Best Practices self-certification
#978 tests/benchmark: Resolve mistaken double close
#986 Address compiler warnings
#990 #993 Version info bumped from 11:1:10 (libexpat*.so.1.10.1)
to 11:2:10 (libexpat*.so.1.10.2); see https://verbump.de/
for what these numbers do
Infrastructure:
#982 CI: Start running Perl XML::Parser integration tests
#987 CI: Enforce Clang Static Analyzer clean code
#991 CI: Re-enable warning clang-analyzer-valist.Uninitialized
for clang-tidy
#981 CI: Cover compilation with musl
#983 #984 CI: Cover compilation with 32bit Emscripten
#976 #977 CI: Protect against fuzzer files missing from future
release archives
Special thanks to:
Berkay Eren Ürün
Matthew Fernandez
and
Perl XML::Parser
Release 2.7.0 Thu March 13 2025
Security fixes:
#893 #973 CVE-2024-8176 -- Fix crash from chaining a large number
of entities caused by stack overflow by resolving use of
recursion, for all three uses of entities:
- general entities in character data ("<e>&g1;</e>")
- general entities in attribute values ("<e k1='&g1;'/>")
- parameter entities ("%p1;")
Known impact is (reliable and easy) denial of service:
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H/E:H/RL:O/RC:C
(Base Score: 7.5, Temporal Score: 7.2)
Please note that a layer of compression around XML can
significantly reduce the minimum attack payload size.
Other changes:
#935 #937 Autotools: Make generated CMake files look for
libexpat.@[email protected] on macOS
#925 Autotools: Sync CMake templates with CMake 3.29
#945 #962 #966 CMake: Drop support for CMake <3.13
#942 CMake: Small fuzzing related improvements
#921 docs: Add missing documentation of error code
XML_ERROR_NOT_STARTED that was introduced with 2.6.4
#941 docs: Document need for C++11 compiler for use from C++
#959 tests/benchmark: Fix a (harmless) TOCTTOU
#944 Windows: Fix installer target location of file xmlwf.xml
for CMake
#953 Windows: Address warning -Wunknown-warning-option
about -Wno-pedantic-ms-format from LLVM MinGW
#971 Address Cppcheck warnings
#969 #970 Mass-migrate links from http:// to https://
#947 #958 ..
#974 #975 Document changes since the previous release
#974 #975 Version info bumped from 11:0:10 (libexpat*.so.1.10.0)
to 11:1:10 (libexpat*.so.1.10.1); see https://verbump.de/
for what these numbers do
Infrastructure:
#926 tests: Increase robustness
#927 #932 ..
#930 #933 tests: Increase test coverage
#617 #950 ..
#951 #952 ..
#954 #955 .. Fuzzing: Add new fuzzer "xml_lpm_fuzzer" based on
#961 Google's libprotobuf-mutator ("LPM")
#957 Fuzzing|CI: Start producing fuzzing code coverage reports
#936 CI: Pass -q -q for LCOV >=2.1 in coverage.sh
#942 CI: Small fuzzing related improvements
#139 #203 ..
#791 #946 CI: Make GitHub Actions build using MSVC on Windows and
produce 32bit and 64bit Windows binaries
#956 CI: Get off of about-to-be-removed Ubuntu 20.04
#960 #964 CI: Start uploading to Coverity Scan for static analysis
#972 CI: Stop loading DTD from the internet to address flaky CI
#971 CI: Adapt to breaking changes in Cppcheck
Special thanks to:
Alexander Gieringer
Berkay Eren Ürün
Hanno Böck
Jann Horn
Mark Brand
Sebastian Andrzej Siewior
Snild Dolkow
Thomas Pröll
Tomas Korbar
valord577
and
Google Project Zero
Linutronix
Red Hat
Siemens
Release 2.6.4 Wed November 6 2024
Security fixes:
#915 CVE-2024-50602 -- Fix crash within function XML_ResumeParser
@@ -46,6 +163,8 @@ Release 2.6.4 Wed November 6 2024
#904 tests: Resolve duplicate handler
#317 #918 tests: Improve tests on doctype closing (ex CVE-2019-15903)
#914 Fix signedness of format strings
#915 For use from C++, expat.h started requiring C++11 due to
use of C99 features
#919 #920 Version info bumped from 10:3:9 (libexpat*.so.1.9.3)
to 11:0:10 (libexpat*.so.1.10.0); see https://verbump.de/
for what these numbers do
+3 -1
View File
@@ -6,7 +6,7 @@
# \___/_/\_\ .__/ \__,_|\__|
# |_| XML parser
#
# Copyright (c) 2017-2023 Sebastian Pipping <[email protected]>
# Copyright (c) 2017-2025 Sebastian Pipping <[email protected]>
# Copyright (c) 2018 KangLin <[email protected]>
# Copyright (c) 2022 Johnny Jazeix <[email protected]>
# Copyright (c) 2023 Sony Corporation / Snild Dolkow <[email protected]>
@@ -96,6 +96,8 @@ EXTRA_DIST = \
conftools/expat.m4 \
conftools/get-version.sh \
\
fuzz/xml_lpm_fuzzer.cpp \
fuzz/xml_lpm_fuzzer.proto \
fuzz/xml_parsebuffer_fuzzer.c \
fuzz/xml_parse_fuzzer.c \
\
+3 -1
View File
@@ -22,7 +22,7 @@
# \___/_/\_\ .__/ \__,_|\__|
# |_| XML parser
#
# Copyright (c) 2017-2023 Sebastian Pipping <[email protected]>
# Copyright (c) 2017-2025 Sebastian Pipping <[email protected]>
# Copyright (c) 2018 KangLin <[email protected]>
# Copyright (c) 2022 Johnny Jazeix <[email protected]>
# Copyright (c) 2023 Sony Corporation / Snild Dolkow <[email protected]>
@@ -494,6 +494,8 @@ EXTRA_DIST = \
conftools/expat.m4 \
conftools/get-version.sh \
\
fuzz/xml_lpm_fuzzer.cpp \
fuzz/xml_lpm_fuzzer.proto \
fuzz/xml_parsebuffer_fuzzer.c \
fuzz/xml_parse_fuzzer.c \
\
+7 -11
View File
@@ -3,6 +3,7 @@
[![Packaging status](https://repology.org/badge/tiny-repos/expat.svg)](https://repology.org/metapackage/expat/versions)
[![Downloads SourceForge](https://img.shields.io/sourceforge/dt/expat?label=Downloads%20SourceForge)](https://sourceforge.net/projects/expat/files/)
[![Downloads GitHub](https://img.shields.io/github/downloads/libexpat/libexpat/total?label=Downloads%20GitHub)](https://github.com/libexpat/libexpat/releases)
[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/10205/badge)](https://www.bestpractices.dev/projects/10205)
> [!CAUTION]
>
@@ -11,7 +12,7 @@
> at the top of the `Changes` file.
# Expat, Release 2.6.4
# Expat, Release 2.7.1
This is Expat, a C99 library for parsing
[XML 1.0 Fourth Edition](https://www.w3.org/TR/2006/REC-xml-20060816/), started by
@@ -22,9 +23,9 @@ are called when the parser discovers the associated structures in the
document being parsed. A start tag is an example of the kind of
structures for which you may register handlers.
Expat supports the following compilers:
Expat supports the following C99 compilers:
- GNU GCC >=4.5
- GNU GCC >=4.5 (for use from C) or GNU GCC >=4.8.1 (for use from C++)
- LLVM Clang >=3.5
- Microsoft Visual Studio >=16.0/2019 (rolling `${today} minus 5 years`)
@@ -52,7 +53,7 @@ This approach leverages CMake's own [module `FindEXPAT`](https://cmake.org/cmake
Notice the *uppercase* `EXPAT` in the following example:
```cmake
cmake_minimum_required(VERSION 3.0) # or 3.10, see below
cmake_minimum_required(VERSION 3.10)
project(hello VERSION 1.0.0)
@@ -62,12 +63,7 @@ add_executable(hello
hello.c
)
# a) for CMake >=3.10 (see CMake's FindEXPAT docs)
target_link_libraries(hello PUBLIC EXPAT::EXPAT)
# b) for CMake >=3.0
target_include_directories(hello PRIVATE ${EXPAT_INCLUDE_DIRS})
target_link_libraries(hello PUBLIC ${EXPAT_LIBRARIES})
```
### b) `find_package` with Config Mode
@@ -85,7 +81,7 @@ or
Notice the *lowercase* `expat` in the following example:
```cmake
cmake_minimum_required(VERSION 3.0)
cmake_minimum_required(VERSION 3.10)
project(hello VERSION 1.0.0)
@@ -295,7 +291,7 @@ EXPAT_ENABLE_INSTALL:BOOL=ON
// Use /MT flag (static CRT) when compiling in MSVC
EXPAT_MSVC_STATIC_CRT:BOOL=OFF
// Build fuzzers via ossfuzz for the expat library
// Build fuzzers via OSS-Fuzz for the expat library
EXPAT_OSSFUZZ_BUILD:BOOL=OFF
// Build a shared expat library
+2 -2
View File
@@ -11,7 +11,7 @@ dnl Copyright (c) 2000 Clark Cooper <[email protected]>
dnl Copyright (c) 2000-2005 Fred L. Drake, Jr. <[email protected]>
dnl Copyright (c) 2001-2003 Greg Stein <[email protected]>
dnl Copyright (c) 2006-2012 Karl Waclawek <[email protected]>
dnl Copyright (c) 2016-2024 Sebastian Pipping <[email protected]>
dnl Copyright (c) 2016-2025 Sebastian Pipping <[email protected]>
dnl Copyright (c) 2017 S. P. Zeidler <[email protected]>
dnl Copyright (c) 2017 Stephen Groat <[email protected]>
dnl Copyright (c) 2017-2020 Joe Orton <[email protected]>
@@ -85,7 +85,7 @@ dnl If the API changes incompatibly set LIBAGE back to 0
dnl
LIBCURRENT=11 # sync
LIBREVISION=0 # with
LIBREVISION=2 # with
LIBAGE=10 # CMakeLists.txt!
AC_CONFIG_HEADERS([expat_config.h])
+7 -2
View File
@@ -14,7 +14,7 @@
Copyright (c) 2000 Clark Cooper <[email protected]>
Copyright (c) 2000-2004 Fred L. Drake, Jr. <[email protected]>
Copyright (c) 2002-2012 Karl Waclawek <[email protected]>
Copyright (c) 2017-2024 Sebastian Pipping <[email protected]>
Copyright (c) 2017-2025 Sebastian Pipping <[email protected]>
Copyright (c) 2017 Jakub Wilk <[email protected]>
Copyright (c) 2021 Tomas Korbar <[email protected]>
Copyright (c) 2021 Nicolas Cavallari <nicolas.cavallari@green-communications.fr>
@@ -52,7 +52,7 @@
<div>
<h1>
The Expat XML Parser
<small>Release 2.6.4</small>
<small>Release 2.7.1</small>
</h1>
</div>
<div class="content">
@@ -1267,6 +1267,11 @@ call-backs, except when parsing an external parameter entity and
<code>XML_STATUS_ERROR</code> otherwise. The possible error codes
are:</p>
<dl>
<dt><code>XML_ERROR_NOT_STARTED</code></dt>
<dd>
when stopping or suspending a parser before it has started,
added in Expat 2.6.4.
</dd>
<dt><code>XML_ERROR_SUSPENDED</code></dt>
<dd>when suspending an already suspended parser.</dd>
<dt><code>XML_ERROR_FINISHED</code></dt>
+1 -1
View File
@@ -5,7 +5,7 @@
\\$2 \(la\\$1\(ra\\$3
..
.if \n(.g .mso www.tmac
.TH XMLWF 1 "November 6, 2024" "" ""
.TH XMLWF 1 "March 27, 2025" "" ""
.SH NAME
xmlwf \- Determines if an XML document is well-formed
.SH SYNOPSIS
+2 -2
View File
@@ -9,7 +9,7 @@
Copyright (c) 2001 Scott Bronson <[email protected]>
Copyright (c) 2002-2003 Fred L. Drake, Jr. <[email protected]>
Copyright (c) 2009 Karl Waclawek <[email protected]>
Copyright (c) 2016-2024 Sebastian Pipping <[email protected]>
Copyright (c) 2016-2025 Sebastian Pipping <[email protected]>
Copyright (c) 2016 Ardo van Rangelrooij <[email protected]>
Copyright (c) 2017 Rhodri James <[email protected]>
Copyright (c) 2020 Joe Orton <[email protected]>
@@ -21,7 +21,7 @@
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
<!ENTITY dhfirstname "<firstname>Scott</firstname>">
<!ENTITY dhsurname "<surname>Bronson</surname>">
<!ENTITY dhdate "<date>November 6, 2024</date>">
<!ENTITY dhdate "<date>March 27, 2025</date>">
<!-- Please adjust this^^ date whenever cutting a new release. -->
<!ENTITY dhsection "<manvolnum>1</manvolnum>">
<!ENTITY dhemail "<email>[email protected]</email>">
+464
View File
@@ -0,0 +1,464 @@
/*
__ __ _
___\ \/ /_ __ __ _| |_
/ _ \\ /| '_ \ / _` | __|
| __// \| |_) | (_| | |_
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
Copyright (c) 2022 Mark Brand <markbrand@google.com>
Copyright (c) 2025 Sebastian Pipping <sebastian@pipping.org>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit
persons to whom the Software is furnished to do so, subject to the
following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#if defined(NDEBUG)
# undef NDEBUG // because checks below rely on assert(...)
#endif
#include <assert.h>
#include <stdint.h>
#include <vector>
#include "expat.h"
#include "xml_lpm_fuzzer.pb.h"
#include "src/libfuzzer/libfuzzer_macro.h"
static const char *g_encoding = nullptr;
static const char *g_external_entity = nullptr;
static size_t g_external_entity_size = 0;
void
SetEncoding(const xml_lpm_fuzzer::Encoding &e) {
switch (e) {
case xml_lpm_fuzzer::Encoding::UTF8:
g_encoding = "UTF-8";
break;
case xml_lpm_fuzzer::Encoding::UTF16:
g_encoding = "UTF-16";
break;
case xml_lpm_fuzzer::Encoding::ISO88591:
g_encoding = "ISO-8859-1";
break;
case xml_lpm_fuzzer::Encoding::ASCII:
g_encoding = "US-ASCII";
break;
case xml_lpm_fuzzer::Encoding::NONE:
g_encoding = NULL;
break;
default:
g_encoding = "UNKNOWN";
break;
}
}
static int g_allocation_count = 0;
static std::vector<int> g_fail_allocations = {};
void *
MallocHook(size_t size) {
g_allocation_count += 1;
for (auto index : g_fail_allocations) {
if (index == g_allocation_count) {
return NULL;
}
}
return malloc(size);
}
void *
ReallocHook(void *ptr, size_t size) {
g_allocation_count += 1;
for (auto index : g_fail_allocations) {
if (index == g_allocation_count) {
return NULL;
}
}
return realloc(ptr, size);
}
void
FreeHook(void *ptr) {
free(ptr);
}
XML_Memory_Handling_Suite memory_handling_suite
= {MallocHook, ReallocHook, FreeHook};
void InitializeParser(XML_Parser parser);
// We want a parse function that supports resumption, so that we can cover the
// suspend/resume code.
enum XML_Status
Parse(XML_Parser parser, const char *input, int input_len, int is_final) {
enum XML_Status status = XML_Parse(parser, input, input_len, is_final);
while (status == XML_STATUS_SUSPENDED) {
status = XML_ResumeParser(parser);
}
return status;
}
// When the fuzzer is compiled with instrumentation such as ASan, then the
// accesses in TouchString will fault if they access invalid memory (ie. detect
// either a use-after-free or buffer-overflow). By calling TouchString in each
// of the callbacks, we can check that the arguments meet the API specifications
// in terms of length/null-termination. no_optimize is used to ensure that the
// compiler has to emit actual memory reads, instead of removing them.
static volatile size_t no_optimize = 0;
static void
TouchString(const XML_Char *ptr, int len = -1) {
if (! ptr) {
return;
}
if (len == -1) {
for (XML_Char value = *ptr++; value; value = *ptr++) {
no_optimize += value;
}
} else {
for (int i = 0; i < len; ++i) {
no_optimize += ptr[i];
}
}
}
static void
TouchNodeAndRecurse(XML_Content *content) {
switch (content->type) {
case XML_CTYPE_EMPTY:
case XML_CTYPE_ANY:
assert(content->quant == XML_CQUANT_NONE);
assert(content->name == NULL);
assert(content->numchildren == 0);
assert(content->children == NULL);
break;
case XML_CTYPE_MIXED:
assert(content->quant == XML_CQUANT_NONE
|| content->quant == XML_CQUANT_REP);
assert(content->name == NULL);
for (unsigned int i = 0; i < content->numchildren; ++i) {
assert(content->children[i].type == XML_CTYPE_NAME);
assert(content->children[i].quant == XML_CQUANT_NONE);
assert(content->children[i].numchildren == 0);
assert(content->children[i].children == NULL);
TouchString(content->children[i].name);
}
break;
case XML_CTYPE_NAME:
assert((content->quant == XML_CQUANT_NONE)
|| (content->quant == XML_CQUANT_OPT)
|| (content->quant == XML_CQUANT_REP)
|| (content->quant == XML_CQUANT_PLUS));
assert(content->numchildren == 0);
assert(content->children == NULL);
TouchString(content->name);
break;
case XML_CTYPE_CHOICE:
case XML_CTYPE_SEQ:
assert((content->quant == XML_CQUANT_NONE)
|| (content->quant == XML_CQUANT_OPT)
|| (content->quant == XML_CQUANT_REP)
|| (content->quant == XML_CQUANT_PLUS));
assert(content->name == NULL);
for (unsigned int i = 0; i < content->numchildren; ++i) {
TouchNodeAndRecurse(&content->children[i]);
}
break;
default:
assert(false);
}
}
static void XMLCALL
ElementDeclHandler(void *userData, const XML_Char *name, XML_Content *model) {
TouchString(name);
TouchNodeAndRecurse(model);
XML_FreeContentModel((XML_Parser)userData, model);
}
static void XMLCALL
AttlistDeclHandler(void *userData, const XML_Char *elname,
const XML_Char *attname, const XML_Char *atttype,
const XML_Char *dflt, int isrequired) {
(void)userData;
TouchString(elname);
TouchString(attname);
TouchString(atttype);
TouchString(dflt);
(void)isrequired;
}
static void XMLCALL
XmlDeclHandler(void *userData, const XML_Char *version,
const XML_Char *encoding, int standalone) {
(void)userData;
TouchString(version);
TouchString(encoding);
(void)standalone;
}
static void XMLCALL
StartElementHandler(void *userData, const XML_Char *name,
const XML_Char **atts) {
(void)userData;
TouchString(name);
for (size_t i = 0; atts[i] != NULL; ++i) {
TouchString(atts[i]);
}
}
static void XMLCALL
EndElementHandler(void *userData, const XML_Char *name) {
(void)userData;
TouchString(name);
}
static void XMLCALL
CharacterDataHandler(void *userData, const XML_Char *s, int len) {
(void)userData;
TouchString(s, len);
}
static void XMLCALL
ProcessingInstructionHandler(void *userData, const XML_Char *target,
const XML_Char *data) {
(void)userData;
TouchString(target);
TouchString(data);
}
static void XMLCALL
CommentHandler(void *userData, const XML_Char *data) {
TouchString(data);
// Use the comment handler to trigger parser suspend, so that we can get
// coverage of that code.
XML_StopParser((XML_Parser)userData, XML_TRUE);
}
static void XMLCALL
StartCdataSectionHandler(void *userData) {
(void)userData;
}
static void XMLCALL
EndCdataSectionHandler(void *userData) {
(void)userData;
}
static void XMLCALL
DefaultHandler(void *userData, const XML_Char *s, int len) {
(void)userData;
TouchString(s, len);
}
static void XMLCALL
StartDoctypeDeclHandler(void *userData, const XML_Char *doctypeName,
const XML_Char *sysid, const XML_Char *pubid,
int has_internal_subset) {
(void)userData;
TouchString(doctypeName);
TouchString(sysid);
TouchString(pubid);
(void)has_internal_subset;
}
static void XMLCALL
EndDoctypeDeclHandler(void *userData) {
(void)userData;
}
static void XMLCALL
EntityDeclHandler(void *userData, const XML_Char *entityName,
int is_parameter_entity, const XML_Char *value,
int value_length, const XML_Char *base,
const XML_Char *systemId, const XML_Char *publicId,
const XML_Char *notationName) {
(void)userData;
TouchString(entityName);
(void)is_parameter_entity;
TouchString(value, value_length);
TouchString(base);
TouchString(systemId);
TouchString(publicId);
TouchString(notationName);
}
static void XMLCALL
NotationDeclHandler(void *userData, const XML_Char *notationName,
const XML_Char *base, const XML_Char *systemId,
const XML_Char *publicId) {
(void)userData;
TouchString(notationName);
TouchString(base);
TouchString(systemId);
TouchString(publicId);
}
static void XMLCALL
StartNamespaceDeclHandler(void *userData, const XML_Char *prefix,
const XML_Char *uri) {
(void)userData;
TouchString(prefix);
TouchString(uri);
}
static void XMLCALL
EndNamespaceDeclHandler(void *userData, const XML_Char *prefix) {
(void)userData;
TouchString(prefix);
}
static int XMLCALL
NotStandaloneHandler(void *userData) {
(void)userData;
return XML_STATUS_OK;
}
static int XMLCALL
ExternalEntityRefHandler(XML_Parser parser, const XML_Char *context,
const XML_Char *base, const XML_Char *systemId,
const XML_Char *publicId) {
int rc = XML_STATUS_ERROR;
TouchString(context);
TouchString(base);
TouchString(systemId);
TouchString(publicId);
if (g_external_entity) {
XML_Parser ext_parser
= XML_ExternalEntityParserCreate(parser, context, g_encoding);
rc = Parse(ext_parser, g_external_entity, g_external_entity_size, 1);
XML_ParserFree(ext_parser);
}
return rc;
}
static void XMLCALL
SkippedEntityHandler(void *userData, const XML_Char *entityName,
int is_parameter_entity) {
(void)userData;
TouchString(entityName);
(void)is_parameter_entity;
}
static int XMLCALL
UnknownEncodingHandler(void *encodingHandlerData, const XML_Char *name,
XML_Encoding *info) {
(void)encodingHandlerData;
TouchString(name);
(void)info;
return XML_STATUS_ERROR;
}
void
InitializeParser(XML_Parser parser) {
XML_SetUserData(parser, (void *)parser);
XML_SetHashSalt(parser, 0x41414141);
XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
XML_SetElementDeclHandler(parser, ElementDeclHandler);
XML_SetAttlistDeclHandler(parser, AttlistDeclHandler);
XML_SetXmlDeclHandler(parser, XmlDeclHandler);
XML_SetElementHandler(parser, StartElementHandler, EndElementHandler);
XML_SetCharacterDataHandler(parser, CharacterDataHandler);
XML_SetProcessingInstructionHandler(parser, ProcessingInstructionHandler);
XML_SetCommentHandler(parser, CommentHandler);
XML_SetCdataSectionHandler(parser, StartCdataSectionHandler,
EndCdataSectionHandler);
// XML_SetDefaultHandler disables entity expansion
XML_SetDefaultHandlerExpand(parser, DefaultHandler);
XML_SetDoctypeDeclHandler(parser, StartDoctypeDeclHandler,
EndDoctypeDeclHandler);
// Note: This is mutually exclusive with XML_SetUnparsedEntityDeclHandler,
// and there isn't any significant code change between the two.
XML_SetEntityDeclHandler(parser, EntityDeclHandler);
XML_SetNotationDeclHandler(parser, NotationDeclHandler);
XML_SetNamespaceDeclHandler(parser, StartNamespaceDeclHandler,
EndNamespaceDeclHandler);
XML_SetNotStandaloneHandler(parser, NotStandaloneHandler);
XML_SetExternalEntityRefHandler(parser, ExternalEntityRefHandler);
XML_SetSkippedEntityHandler(parser, SkippedEntityHandler);
XML_SetUnknownEncodingHandler(parser, UnknownEncodingHandler, (void *)parser);
}
DEFINE_TEXT_PROTO_FUZZER(const xml_lpm_fuzzer::Testcase &testcase) {
g_external_entity = nullptr;
if (! testcase.actions_size()) {
return;
}
g_allocation_count = 0;
g_fail_allocations.clear();
for (int i = 0; i < testcase.fail_allocations_size(); ++i) {
g_fail_allocations.push_back(testcase.fail_allocations(i));
}
SetEncoding(testcase.encoding());
XML_Parser parser
= XML_ParserCreate_MM(g_encoding, &memory_handling_suite, "|");
InitializeParser(parser);
for (int i = 0; i < testcase.actions_size(); ++i) {
const auto &action = testcase.actions(i);
switch (action.action_case()) {
case xml_lpm_fuzzer::Action::kChunk:
if (XML_STATUS_ERROR
== Parse(parser, action.chunk().data(), action.chunk().size(), 0)) {
// Force a reset after parse error.
XML_ParserReset(parser, g_encoding);
InitializeParser(parser);
}
break;
case xml_lpm_fuzzer::Action::kLastChunk:
Parse(parser, action.last_chunk().data(), action.last_chunk().size(), 1);
XML_ParserReset(parser, g_encoding);
InitializeParser(parser);
break;
case xml_lpm_fuzzer::Action::kReset:
XML_ParserReset(parser, g_encoding);
InitializeParser(parser);
break;
case xml_lpm_fuzzer::Action::kExternalEntity:
g_external_entity = action.external_entity().data();
g_external_entity_size = action.external_entity().size();
break;
default:
break;
}
}
XML_ParserFree(parser);
}
+58
View File
@@ -0,0 +1,58 @@
/*
__ __ _
___\ \/ /_ __ __ _| |_
/ _ \\ /| '_ \ / _` | __|
| __// \| |_) | (_| | |_
\___/_/\_\ .__/ \__,_|\__|
|_| XML parser
Copyright (c) 2022 Mark Brand <[email protected]>
Copyright (c) 2025 Sebastian Pipping <[email protected]>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit
persons to whom the Software is furnished to do so, subject to the
following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
syntax = "proto2";
package xml_lpm_fuzzer;
enum Encoding {
UTF8 = 0;
UTF16 = 1;
ISO88591 = 2;
ASCII = 3;
UNKNOWN = 4;
NONE = 5;
}
message Action {
oneof action {
string chunk = 1;
string last_chunk = 2;
bool reset = 3;
string external_entity = 4;
}
}
message Testcase {
required Encoding encoding = 1;
repeated Action actions = 2;
repeated int32 fail_allocations = 3;
}
+1 -1
View File
@@ -5,7 +5,7 @@
* 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
* https://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,
+1 -1
View File
@@ -5,7 +5,7 @@
* 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
* https://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,
+3 -3
View File
@@ -11,7 +11,7 @@
Copyright (c) 2000-2005 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
Copyright (c) 2001-2002 Greg Stein <gstein@users.sourceforge.net>
Copyright (c) 2002-2016 Karl Waclawek <karl@waclawek.net>
Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2016-2025 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2016 Cristian Rodríguez <crrodriguez@opensuse.org>
Copyright (c) 2016 Thomas Beutlich <tc@tbeu.de>
Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
@@ -1067,8 +1067,8 @@ XML_SetReparseDeferralEnabled(XML_Parser parser, XML_Bool enabled);
See https://semver.org
*/
#define XML_MAJOR_VERSION 2
#define XML_MINOR_VERSION 6
#define XML_MICRO_VERSION 4
#define XML_MINOR_VERSION 7
#define XML_MICRO_VERSION 1
#ifdef __cplusplus
}
+4 -1
View File
@@ -28,7 +28,7 @@
Copyright (c) 2002-2003 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
Copyright (c) 2002-2006 Karl Waclawek <karl@waclawek.net>
Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2016-2025 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2018 Yury Gribov <tetra2005@gmail.com>
Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow <snild@sony.com>
@@ -127,6 +127,9 @@
# elif ULONG_MAX == 18446744073709551615u // 2^64-1
# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "ld"
# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "lu"
# elif defined(EMSCRIPTEN) // 32bit mode Emscripten
# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "ld"
# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "zu"
# else
# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "u"
+428 -158
View File
@@ -1,4 +1,4 @@
/* c5625880f4bf417c1463deee4eb92d86ff413f802048621c57e25fe483eb59e4 (2.6.4+)
/* d19ae032c224863c1527ba44d228cc34b99192c3a4c5a27af1f4e054d45ee031 (2.7.1+)
__ __ _
___\ \/ /_ __ __ _| |_
/ _ \\ /| '_ \ / _` | __|
@@ -13,7 +13,7 @@
Copyright (c) 2002-2016 Karl Waclawek <karl@waclawek.net>
Copyright (c) 2005-2009 Steven Solie <steven@solie.ca>
Copyright (c) 2016 Eric Rahm <erahm@mozilla.com>
Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2016-2025 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2016 Gaurav <g.gupta@samsung.com>
Copyright (c) 2016 Thomas Beutlich <tc@tbeu.de>
Copyright (c) 2016 Gustavo Grieco <gustavo.grieco@imag.fr>
@@ -39,7 +39,7 @@
Copyright (c) 2022 Sean McBride <sean@rogue-research.com>
Copyright (c) 2023 Owain Davies <owaind@bath.edu>
Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow <snild@sony.com>
Copyright (c) 2024 Berkay Eren Ürün <berkay.ueruen@siemens.com>
Copyright (c) 2024-2025 Berkay Eren Ürün <berkay.ueruen@siemens.com>
Copyright (c) 2024 Hanno Böck <hanno@gentoo.org>
Licensed under the MIT license:
@@ -325,6 +325,10 @@ typedef struct {
const XML_Char *publicId;
const XML_Char *notation;
XML_Bool open;
XML_Bool hasMore; /* true if entity has not been completely processed */
/* An entity can be open while being already completely processed (hasMore ==
XML_FALSE). The reason is the delayed closing of entities until their inner
entities are processed and closed */
XML_Bool is_param;
XML_Bool is_internal; /* true if declared in internal subset outside PE */
} ENTITY;
@@ -415,6 +419,12 @@ typedef struct {
int *scaffIndex;
} DTD;
enum EntityType {
ENTITY_INTERNAL,
ENTITY_ATTRIBUTE,
ENTITY_VALUE,
};
typedef struct open_internal_entity {
const char *internalEventPtr;
const char *internalEventEndPtr;
@@ -422,6 +432,7 @@ typedef struct open_internal_entity {
ENTITY *entity;
int startTagLevel;
XML_Bool betweenDecl; /* WFC: PE Between Declarations */
enum EntityType type;
} OPEN_INTERNAL_ENTITY;
enum XML_Account {
@@ -481,8 +492,8 @@ static enum XML_Error doProlog(XML_Parser parser, const ENCODING *enc,
const char *next, const char **nextPtr,
XML_Bool haveMore, XML_Bool allowClosingDoctype,
enum XML_Account account);
static enum XML_Error processInternalEntity(XML_Parser parser, ENTITY *entity,
XML_Bool betweenDecl);
static enum XML_Error processEntity(XML_Parser parser, ENTITY *entity,
XML_Bool betweenDecl, enum EntityType type);
static enum XML_Error doContent(XML_Parser parser, int startTagLevel,
const ENCODING *enc, const char *start,
const char *end, const char **endPtr,
@@ -513,18 +524,22 @@ static enum XML_Error storeAttributeValue(XML_Parser parser,
const char *ptr, const char *end,
STRING_POOL *pool,
enum XML_Account account);
static enum XML_Error appendAttributeValue(XML_Parser parser,
const ENCODING *enc,
XML_Bool isCdata, const char *ptr,
const char *end, STRING_POOL *pool,
enum XML_Account account);
static enum XML_Error
appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
const char *ptr, const char *end, STRING_POOL *pool,
enum XML_Account account, const char **nextPtr);
static ATTRIBUTE_ID *getAttributeId(XML_Parser parser, const ENCODING *enc,
const char *start, const char *end);
static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType);
#if XML_GE == 1
static enum XML_Error storeEntityValue(XML_Parser parser, const ENCODING *enc,
const char *start, const char *end,
enum XML_Account account);
enum XML_Account account,
const char **nextPtr);
static enum XML_Error callStoreEntityValue(XML_Parser parser,
const ENCODING *enc,
const char *start, const char *end,
enum XML_Account account);
#else
static enum XML_Error storeSelfEntityValue(XML_Parser parser, ENTITY *entity);
#endif
@@ -709,6 +724,10 @@ struct XML_ParserStruct {
const char *m_positionPtr;
OPEN_INTERNAL_ENTITY *m_openInternalEntities;
OPEN_INTERNAL_ENTITY *m_freeInternalEntities;
OPEN_INTERNAL_ENTITY *m_openAttributeEntities;
OPEN_INTERNAL_ENTITY *m_freeAttributeEntities;
OPEN_INTERNAL_ENTITY *m_openValueEntities;
OPEN_INTERNAL_ENTITY *m_freeValueEntities;
XML_Bool m_defaultExpandInternalEntities;
int m_tagLevel;
ENTITY *m_declEntity;
@@ -756,6 +775,7 @@ struct XML_ParserStruct {
ACCOUNTING m_accounting;
ENTITY_STATS m_entity_stats;
#endif
XML_Bool m_reenter;
};
#define MALLOC(parser, s) (parser->m_mem.malloc_fcn((s)))
@@ -1028,7 +1048,29 @@ callProcessor(XML_Parser parser, const char *start, const char *end,
#if defined(XML_TESTING)
g_bytesScanned += (unsigned)have_now;
#endif
const enum XML_Error ret = parser->m_processor(parser, start, end, endPtr);
// Run in a loop to eliminate dangerous recursion depths
enum XML_Error ret;
*endPtr = start;
while (1) {
// Use endPtr as the new start in each iteration, since it will
// be set to the next start point by m_processor.
ret = parser->m_processor(parser, *endPtr, end, endPtr);
// Make parsing status (and in particular XML_SUSPENDED) take
// precedence over re-enter flag when they disagree
if (parser->m_parsingStatus.parsing != XML_PARSING) {
parser->m_reenter = XML_FALSE;
}
if (! parser->m_reenter) {
break;
}
parser->m_reenter = XML_FALSE;
if (ret != XML_ERROR_NONE)
return ret;
}
if (ret == XML_ERROR_NONE) {
// if we consumed nothing, remember what we had on this parse attempt.
if (*endPtr == start) {
@@ -1139,6 +1181,8 @@ parserCreate(const XML_Char *encodingName,
parser->m_freeBindingList = NULL;
parser->m_freeTagList = NULL;
parser->m_freeInternalEntities = NULL;
parser->m_freeAttributeEntities = NULL;
parser->m_freeValueEntities = NULL;
parser->m_groupSize = 0;
parser->m_groupConnector = NULL;
@@ -1241,6 +1285,8 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) {
parser->m_eventEndPtr = NULL;
parser->m_positionPtr = NULL;
parser->m_openInternalEntities = NULL;
parser->m_openAttributeEntities = NULL;
parser->m_openValueEntities = NULL;
parser->m_defaultExpandInternalEntities = XML_TRUE;
parser->m_tagLevel = 0;
parser->m_tagStack = NULL;
@@ -1251,6 +1297,8 @@ parserInit(XML_Parser parser, const XML_Char *encodingName) {
parser->m_unknownEncodingData = NULL;
parser->m_parentParser = NULL;
parser->m_parsingStatus.parsing = XML_INITIALIZED;
// Reentry can only be triggered inside m_processor calls
parser->m_reenter = XML_FALSE;
#ifdef XML_DTD
parser->m_isParamEntity = XML_FALSE;
parser->m_useForeignDTD = XML_FALSE;
@@ -1310,6 +1358,24 @@ XML_ParserReset(XML_Parser parser, const XML_Char *encodingName) {
openEntity->next = parser->m_freeInternalEntities;
parser->m_freeInternalEntities = openEntity;
}
/* move m_openAttributeEntities to m_freeAttributeEntities (i.e. same task but
* for attributes) */
openEntityList = parser->m_openAttributeEntities;
while (openEntityList) {
OPEN_INTERNAL_ENTITY *openEntity = openEntityList;
openEntityList = openEntity->next;
openEntity->next = parser->m_freeAttributeEntities;
parser->m_freeAttributeEntities = openEntity;
}
/* move m_openValueEntities to m_freeValueEntities (i.e. same task but
* for value entities) */
openEntityList = parser->m_openValueEntities;
while (openEntityList) {
OPEN_INTERNAL_ENTITY *openEntity = openEntityList;
openEntityList = openEntity->next;
openEntity->next = parser->m_freeValueEntities;
parser->m_freeValueEntities = openEntity;
}
moveToFreeBindingList(parser, parser->m_inheritedBindings);
FREE(parser, parser->m_unknownEncodingMem);
if (parser->m_unknownEncodingRelease)
@@ -1323,6 +1389,19 @@ XML_ParserReset(XML_Parser parser, const XML_Char *encodingName) {
return XML_TRUE;
}
static XML_Bool
parserBusy(XML_Parser parser) {
switch (parser->m_parsingStatus.parsing) {
case XML_PARSING:
case XML_SUSPENDED:
return XML_TRUE;
case XML_INITIALIZED:
case XML_FINISHED:
default:
return XML_FALSE;
}
}
enum XML_Status XMLCALL
XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName) {
if (parser == NULL)
@@ -1331,8 +1410,7 @@ XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName) {
XXX There's no way for the caller to determine which of the
XXX possible error cases caused the XML_STATUS_ERROR return.
*/
if (parser->m_parsingStatus.parsing == XML_PARSING
|| parser->m_parsingStatus.parsing == XML_SUSPENDED)
if (parserBusy(parser))
return XML_STATUS_ERROR;
/* Get rid of any previous encoding name */
@@ -1569,7 +1647,34 @@ XML_ParserFree(XML_Parser parser) {
entityList = entityList->next;
FREE(parser, openEntity);
}
/* free m_openAttributeEntities and m_freeAttributeEntities */
entityList = parser->m_openAttributeEntities;
for (;;) {
OPEN_INTERNAL_ENTITY *openEntity;
if (entityList == NULL) {
if (parser->m_freeAttributeEntities == NULL)
break;
entityList = parser->m_freeAttributeEntities;
parser->m_freeAttributeEntities = NULL;
}
openEntity = entityList;
entityList = entityList->next;
FREE(parser, openEntity);
}
/* free m_openValueEntities and m_freeValueEntities */
entityList = parser->m_openValueEntities;
for (;;) {
OPEN_INTERNAL_ENTITY *openEntity;
if (entityList == NULL) {
if (parser->m_freeValueEntities == NULL)
break;
entityList = parser->m_freeValueEntities;
parser->m_freeValueEntities = NULL;
}
openEntity = entityList;
entityList = entityList->next;
FREE(parser, openEntity);
}
destroyBindings(parser->m_freeBindingList, parser);
destroyBindings(parser->m_inheritedBindings, parser);
poolDestroy(&parser->m_tempPool);
@@ -1611,8 +1716,7 @@ XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD) {
return XML_ERROR_INVALID_ARGUMENT;
#ifdef XML_DTD
/* block after XML_Parse()/XML_ParseBuffer() has been called */
if (parser->m_parsingStatus.parsing == XML_PARSING
|| parser->m_parsingStatus.parsing == XML_SUSPENDED)
if (parserBusy(parser))
return XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING;
parser->m_useForeignDTD = useDTD;
return XML_ERROR_NONE;
@@ -1627,8 +1731,7 @@ XML_SetReturnNSTriplet(XML_Parser parser, int do_nst) {
if (parser == NULL)
return;
/* block after XML_Parse()/XML_ParseBuffer() has been called */
if (parser->m_parsingStatus.parsing == XML_PARSING
|| parser->m_parsingStatus.parsing == XML_SUSPENDED)
if (parserBusy(parser))
return;
parser->m_ns_triplets = do_nst ? XML_TRUE : XML_FALSE;
}
@@ -1897,8 +2000,7 @@ XML_SetParamEntityParsing(XML_Parser parser,
if (parser == NULL)
return 0;
/* block after XML_Parse()/XML_ParseBuffer() has been called */
if (parser->m_parsingStatus.parsing == XML_PARSING
|| parser->m_parsingStatus.parsing == XML_SUSPENDED)
if (parserBusy(parser))
return 0;
#ifdef XML_DTD
parser->m_paramEntityParsing = peParsing;
@@ -1915,8 +2017,7 @@ XML_SetHashSalt(XML_Parser parser, unsigned long hash_salt) {
if (parser->m_parentParser)
return XML_SetHashSalt(parser->m_parentParser, hash_salt);
/* block after XML_Parse()/XML_ParseBuffer() has been called */
if (parser->m_parsingStatus.parsing == XML_PARSING
|| parser->m_parsingStatus.parsing == XML_SUSPENDED)
if (parserBusy(parser))
return 0;
parser->m_hash_secret_salt = hash_salt;
return 1;
@@ -2230,6 +2331,11 @@ XML_GetBuffer(XML_Parser parser, int len) {
return parser->m_bufferEnd;
}
static void
triggerReenter(XML_Parser parser) {
parser->m_reenter = XML_TRUE;
}
enum XML_Status XMLCALL
XML_StopParser(XML_Parser parser, XML_Bool resumable) {
if (parser == NULL)
@@ -2704,8 +2810,9 @@ static enum XML_Error PTRCALL
contentProcessor(XML_Parser parser, const char *start, const char *end,
const char **endPtr) {
enum XML_Error result = doContent(
parser, 0, parser->m_encoding, start, end, endPtr,
(XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_ACCOUNT_DIRECT);
parser, parser->m_parentParser ? 1 : 0, parser->m_encoding, start, end,
endPtr, (XML_Bool)! parser->m_parsingStatus.finalBuffer,
XML_ACCOUNT_DIRECT);
if (result == XML_ERROR_NONE) {
if (! storeRawNames(parser))
return XML_ERROR_NO_MEMORY;
@@ -2793,6 +2900,11 @@ externalEntityInitProcessor3(XML_Parser parser, const char *start,
return XML_ERROR_NONE;
case XML_FINISHED:
return XML_ERROR_ABORTED;
case XML_PARSING:
if (parser->m_reenter) {
return XML_ERROR_UNEXPECTED_STATE; // LCOV_EXCL_LINE
}
/* Fall through */
default:
start = next;
}
@@ -2966,7 +3078,7 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
reportDefault(parser, enc, s, next);
break;
}
result = processInternalEntity(parser, entity, XML_FALSE);
result = processEntity(parser, entity, XML_FALSE, ENTITY_INTERNAL);
if (result != XML_ERROR_NONE)
return result;
} else if (parser->m_externalEntityRefHandler) {
@@ -3092,7 +3204,9 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
}
if ((parser->m_tagLevel == 0)
&& (parser->m_parsingStatus.parsing != XML_FINISHED)) {
if (parser->m_parsingStatus.parsing == XML_SUSPENDED)
if (parser->m_parsingStatus.parsing == XML_SUSPENDED
|| (parser->m_parsingStatus.parsing == XML_PARSING
&& parser->m_reenter))
parser->m_processor = epilogProcessor;
else
return epilogProcessor(parser, next, end, nextPtr);
@@ -3153,7 +3267,9 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
}
if ((parser->m_tagLevel == 0)
&& (parser->m_parsingStatus.parsing != XML_FINISHED)) {
if (parser->m_parsingStatus.parsing == XML_SUSPENDED)
if (parser->m_parsingStatus.parsing == XML_SUSPENDED
|| (parser->m_parsingStatus.parsing == XML_PARSING
&& parser->m_reenter))
parser->m_processor = epilogProcessor;
else
return epilogProcessor(parser, next, end, nextPtr);
@@ -3286,14 +3402,22 @@ doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
break;
/* LCOV_EXCL_STOP */
}
*eventPP = s = next;
switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
*eventPP = next;
*nextPtr = next;
return XML_ERROR_NONE;
case XML_FINISHED:
*eventPP = next;
return XML_ERROR_ABORTED;
case XML_PARSING:
if (parser->m_reenter) {
*nextPtr = next;
return XML_ERROR_NONE;
}
/* Fall through */
default:;
*eventPP = s = next;
}
}
/* not reached */
@@ -4210,14 +4334,21 @@ doCdataSection(XML_Parser parser, const ENCODING *enc, const char **startPtr,
/* LCOV_EXCL_STOP */
}
*eventPP = s = next;
switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
*eventPP = next;
*nextPtr = next;
return XML_ERROR_NONE;
case XML_FINISHED:
*eventPP = next;
return XML_ERROR_ABORTED;
case XML_PARSING:
if (parser->m_reenter) {
return XML_ERROR_UNEXPECTED_STATE; // LCOV_EXCL_LINE
}
/* Fall through */
default:;
*eventPP = s = next;
}
}
/* not reached */
@@ -4549,7 +4680,7 @@ entityValueInitProcessor(XML_Parser parser, const char *s, const char *end,
}
/* found end of entity value - can store it now */
return storeEntityValue(parser, parser->m_encoding, s, end,
XML_ACCOUNT_DIRECT);
XML_ACCOUNT_DIRECT, NULL);
} else if (tok == XML_TOK_XML_DECL) {
enum XML_Error result;
result = processXmlDecl(parser, 0, start, next);
@@ -4676,7 +4807,7 @@ entityValueProcessor(XML_Parser parser, const char *s, const char *end,
break;
}
/* found end of entity value - can store it now */
return storeEntityValue(parser, enc, s, end, XML_ACCOUNT_DIRECT);
return storeEntityValue(parser, enc, s, end, XML_ACCOUNT_DIRECT, NULL);
}
start = next;
}
@@ -5119,9 +5250,9 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
#if XML_GE == 1
// This will store the given replacement text in
// parser->m_declEntity->textPtr.
enum XML_Error result
= storeEntityValue(parser, enc, s + enc->minBytesPerChar,
next - enc->minBytesPerChar, XML_ACCOUNT_NONE);
enum XML_Error result = callStoreEntityValue(
parser, enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar,
XML_ACCOUNT_NONE);
if (parser->m_declEntity) {
parser->m_declEntity->textPtr = poolStart(&dtd->entityValuePool);
parser->m_declEntity->textLen
@@ -5546,7 +5677,7 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
enum XML_Error result;
XML_Bool betweenDecl
= (role == XML_ROLE_PARAM_ENTITY_REF ? XML_TRUE : XML_FALSE);
result = processInternalEntity(parser, entity, betweenDecl);
result = processEntity(parser, entity, betweenDecl, ENTITY_INTERNAL);
if (result != XML_ERROR_NONE)
return result;
handleDefault = XML_FALSE;
@@ -5751,6 +5882,12 @@ doProlog(XML_Parser parser, const ENCODING *enc, const char *s, const char *end,
return XML_ERROR_NONE;
case XML_FINISHED:
return XML_ERROR_ABORTED;
case XML_PARSING:
if (parser->m_reenter) {
*nextPtr = next;
return XML_ERROR_NONE;
}
/* Fall through */
default:
s = next;
tok = XmlPrologTok(enc, s, end, &next);
@@ -5818,28 +5955,58 @@ epilogProcessor(XML_Parser parser, const char *s, const char *end,
default:
return XML_ERROR_JUNK_AFTER_DOC_ELEMENT;
}
parser->m_eventPtr = s = next;
switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
parser->m_eventPtr = next;
*nextPtr = next;
return XML_ERROR_NONE;
case XML_FINISHED:
parser->m_eventPtr = next;
return XML_ERROR_ABORTED;
case XML_PARSING:
if (parser->m_reenter) {
return XML_ERROR_UNEXPECTED_STATE; // LCOV_EXCL_LINE
}
/* Fall through */
default:;
parser->m_eventPtr = s = next;
}
}
}
static enum XML_Error
processInternalEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl) {
const char *textStart, *textEnd;
const char *next;
enum XML_Error result;
OPEN_INTERNAL_ENTITY *openEntity;
processEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl,
enum EntityType type) {
OPEN_INTERNAL_ENTITY *openEntity, **openEntityList, **freeEntityList;
switch (type) {
case ENTITY_INTERNAL:
parser->m_processor = internalEntityProcessor;
openEntityList = &parser->m_openInternalEntities;
freeEntityList = &parser->m_freeInternalEntities;
break;
case ENTITY_ATTRIBUTE:
openEntityList = &parser->m_openAttributeEntities;
freeEntityList = &parser->m_freeAttributeEntities;
break;
case ENTITY_VALUE:
openEntityList = &parser->m_openValueEntities;
freeEntityList = &parser->m_freeValueEntities;
break;
/* default case serves merely as a safety net in case of a
* wrong entityType. Therefore we exclude the following lines
* from the test coverage.
*
* LCOV_EXCL_START
*/
default:
// Should not reach here
assert(0);
/* LCOV_EXCL_STOP */
}
if (parser->m_freeInternalEntities) {
openEntity = parser->m_freeInternalEntities;
parser->m_freeInternalEntities = openEntity->next;
if (*freeEntityList) {
openEntity = *freeEntityList;
*freeEntityList = openEntity->next;
} else {
openEntity
= (OPEN_INTERNAL_ENTITY *)MALLOC(parser, sizeof(OPEN_INTERNAL_ENTITY));
@@ -5847,55 +6014,34 @@ processInternalEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl) {
return XML_ERROR_NO_MEMORY;
}
entity->open = XML_TRUE;
entity->hasMore = XML_TRUE;
#if XML_GE == 1
entityTrackingOnOpen(parser, entity, __LINE__);
#endif
entity->processed = 0;
openEntity->next = parser->m_openInternalEntities;
parser->m_openInternalEntities = openEntity;
openEntity->next = *openEntityList;
*openEntityList = openEntity;
openEntity->entity = entity;
openEntity->type = type;
openEntity->startTagLevel = parser->m_tagLevel;
openEntity->betweenDecl = betweenDecl;
openEntity->internalEventPtr = NULL;
openEntity->internalEventEndPtr = NULL;
textStart = (const char *)entity->textPtr;
textEnd = (const char *)(entity->textPtr + entity->textLen);
/* Set a safe default value in case 'next' does not get set */
next = textStart;
if (entity->is_param) {
int tok
= XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next);
result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd,
tok, next, &next, XML_FALSE, XML_FALSE,
XML_ACCOUNT_ENTITY_EXPANSION);
} else {
result = doContent(parser, parser->m_tagLevel, parser->m_internalEncoding,
textStart, textEnd, &next, XML_FALSE,
XML_ACCOUNT_ENTITY_EXPANSION);
// Only internal entities make use of the reenter flag
// therefore no need to set it for other entity types
if (type == ENTITY_INTERNAL) {
triggerReenter(parser);
}
if (result == XML_ERROR_NONE) {
if (textEnd != next && parser->m_parsingStatus.parsing == XML_SUSPENDED) {
entity->processed = (int)(next - textStart);
parser->m_processor = internalEntityProcessor;
} else if (parser->m_openInternalEntities->entity == entity) {
#if XML_GE == 1
entityTrackingOnClose(parser, entity, __LINE__);
#endif /* XML_GE == 1 */
entity->open = XML_FALSE;
parser->m_openInternalEntities = openEntity->next;
/* put openEntity back in list of free instances */
openEntity->next = parser->m_freeInternalEntities;
parser->m_freeInternalEntities = openEntity;
}
}
return result;
return XML_ERROR_NONE;
}
static enum XML_Error PTRCALL
internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
const char **nextPtr) {
UNUSED_P(s);
UNUSED_P(end);
UNUSED_P(nextPtr);
ENTITY *entity;
const char *textStart, *textEnd;
const char *next;
@@ -5905,68 +6051,67 @@ internalEntityProcessor(XML_Parser parser, const char *s, const char *end,
return XML_ERROR_UNEXPECTED_STATE;
entity = openEntity->entity;
textStart = ((const char *)entity->textPtr) + entity->processed;
textEnd = (const char *)(entity->textPtr + entity->textLen);
/* Set a safe default value in case 'next' does not get set */
next = textStart;
if (entity->is_param) {
int tok
= XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next);
result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd,
tok, next, &next, XML_FALSE, XML_TRUE,
XML_ACCOUNT_ENTITY_EXPANSION);
} else {
result = doContent(parser, openEntity->startTagLevel,
parser->m_internalEncoding, textStart, textEnd, &next,
XML_FALSE, XML_ACCOUNT_ENTITY_EXPANSION);
}
// This will return early
if (entity->hasMore) {
textStart = ((const char *)entity->textPtr) + entity->processed;
textEnd = (const char *)(entity->textPtr + entity->textLen);
/* Set a safe default value in case 'next' does not get set */
next = textStart;
if (result != XML_ERROR_NONE)
if (entity->is_param) {
int tok
= XmlPrologTok(parser->m_internalEncoding, textStart, textEnd, &next);
result = doProlog(parser, parser->m_internalEncoding, textStart, textEnd,
tok, next, &next, XML_FALSE, XML_FALSE,
XML_ACCOUNT_ENTITY_EXPANSION);
} else {
result = doContent(parser, openEntity->startTagLevel,
parser->m_internalEncoding, textStart, textEnd, &next,
XML_FALSE, XML_ACCOUNT_ENTITY_EXPANSION);
}
if (result != XML_ERROR_NONE)
return result;
// Check if entity is complete, if not, mark down how much of it is
// processed
if (textEnd != next
&& (parser->m_parsingStatus.parsing == XML_SUSPENDED
|| (parser->m_parsingStatus.parsing == XML_PARSING
&& parser->m_reenter))) {
entity->processed = (int)(next - (const char *)entity->textPtr);
return result;
}
// Entity is complete. We cannot close it here since we need to first
// process its possible inner entities (which are added to the
// m_openInternalEntities during doProlog or doContent calls above)
entity->hasMore = XML_FALSE;
triggerReenter(parser);
return result;
} // End of entity processing, "if" block will return here
if (textEnd != next && parser->m_parsingStatus.parsing == XML_SUSPENDED) {
entity->processed = (int)(next - (const char *)entity->textPtr);
return result;
}
// Remove fully processed openEntity from open entity list.
#if XML_GE == 1
entityTrackingOnClose(parser, entity, __LINE__);
#endif
// openEntity is m_openInternalEntities' head, as we set it at the start of
// this function and we skipped doProlog and doContent calls with hasMore set
// to false. This means we can directly remove the head of
// m_openInternalEntities
assert(parser->m_openInternalEntities == openEntity);
entity->open = XML_FALSE;
parser->m_openInternalEntities = openEntity->next;
parser->m_openInternalEntities = parser->m_openInternalEntities->next;
/* put openEntity back in list of free instances */
openEntity->next = parser->m_freeInternalEntities;
parser->m_freeInternalEntities = openEntity;
// If there are more open entities we want to stop right here and have the
// upcoming call to XML_ResumeParser continue with entity content, or it would
// be ignored altogether.
if (parser->m_openInternalEntities != NULL
&& parser->m_parsingStatus.parsing == XML_SUSPENDED) {
return XML_ERROR_NONE;
}
if (entity->is_param) {
int tok;
parser->m_processor = prologProcessor;
tok = XmlPrologTok(parser->m_encoding, s, end, &next);
return doProlog(parser, parser->m_encoding, s, end, tok, next, nextPtr,
(XML_Bool)! parser->m_parsingStatus.finalBuffer, XML_TRUE,
XML_ACCOUNT_DIRECT);
} else {
parser->m_processor = contentProcessor;
/* see externalEntityContentProcessor vs contentProcessor */
result = doContent(parser, parser->m_parentParser ? 1 : 0,
parser->m_encoding, s, end, nextPtr,
(XML_Bool)! parser->m_parsingStatus.finalBuffer,
XML_ACCOUNT_DIRECT);
if (result == XML_ERROR_NONE) {
if (! storeRawNames(parser))
return XML_ERROR_NO_MEMORY;
}
return result;
if (parser->m_openInternalEntities == NULL) {
parser->m_processor = entity->is_param ? prologProcessor : contentProcessor;
}
triggerReenter(parser);
return XML_ERROR_NONE;
}
static enum XML_Error PTRCALL
@@ -5982,8 +6127,70 @@ static enum XML_Error
storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
const char *ptr, const char *end, STRING_POOL *pool,
enum XML_Account account) {
enum XML_Error result
= appendAttributeValue(parser, enc, isCdata, ptr, end, pool, account);
const char *next = ptr;
enum XML_Error result = XML_ERROR_NONE;
while (1) {
if (! parser->m_openAttributeEntities) {
result = appendAttributeValue(parser, enc, isCdata, next, end, pool,
account, &next);
} else {
OPEN_INTERNAL_ENTITY *const openEntity = parser->m_openAttributeEntities;
if (! openEntity)
return XML_ERROR_UNEXPECTED_STATE;
ENTITY *const entity = openEntity->entity;
const char *const textStart
= ((const char *)entity->textPtr) + entity->processed;
const char *const textEnd
= (const char *)(entity->textPtr + entity->textLen);
/* Set a safe default value in case 'next' does not get set */
const char *nextInEntity = textStart;
if (entity->hasMore) {
result = appendAttributeValue(
parser, parser->m_internalEncoding, isCdata, textStart, textEnd,
pool, XML_ACCOUNT_ENTITY_EXPANSION, &nextInEntity);
if (result != XML_ERROR_NONE)
break;
// Check if entity is complete, if not, mark down how much of it is
// processed. A XML_SUSPENDED check here is not required as
// appendAttributeValue will never suspend the parser.
if (textEnd != nextInEntity) {
entity->processed
= (int)(nextInEntity - (const char *)entity->textPtr);
continue;
}
// Entity is complete. We cannot close it here since we need to first
// process its possible inner entities (which are added to the
// m_openAttributeEntities during appendAttributeValue)
entity->hasMore = XML_FALSE;
continue;
} // End of entity processing, "if" block skips the rest
// Remove fully processed openEntity from open entity list.
#if XML_GE == 1
entityTrackingOnClose(parser, entity, __LINE__);
#endif
// openEntity is m_openAttributeEntities' head, since we set it at the
// start of this function and because we skipped appendAttributeValue call
// with hasMore set to false. This means we can directly remove the head
// of m_openAttributeEntities
assert(parser->m_openAttributeEntities == openEntity);
entity->open = XML_FALSE;
parser->m_openAttributeEntities = parser->m_openAttributeEntities->next;
/* put openEntity back in list of free instances */
openEntity->next = parser->m_freeAttributeEntities;
parser->m_freeAttributeEntities = openEntity;
}
// Break if an error occurred or there is nothing left to process
if (result || (parser->m_openAttributeEntities == NULL && end == next)) {
break;
}
}
if (result)
return result;
if (! isCdata && poolLength(pool) && poolLastChar(pool) == 0x20)
@@ -5996,7 +6203,7 @@ storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
static enum XML_Error
appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
const char *ptr, const char *end, STRING_POOL *pool,
enum XML_Account account) {
enum XML_Account account, const char **nextPtr) {
DTD *const dtd = parser->m_dtd; /* save one level of indirection */
#ifndef XML_DTD
UNUSED_P(account);
@@ -6014,6 +6221,9 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
#endif
switch (tok) {
case XML_TOK_NONE:
if (nextPtr) {
*nextPtr = next;
}
return XML_ERROR_NONE;
case XML_TOK_INVALID:
if (enc == parser->m_encoding)
@@ -6154,21 +6364,11 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
return XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF;
} else {
enum XML_Error result;
const XML_Char *textEnd = entity->textPtr + entity->textLen;
entity->open = XML_TRUE;
#if XML_GE == 1
entityTrackingOnOpen(parser, entity, __LINE__);
#endif
result = appendAttributeValue(parser, parser->m_internalEncoding,
isCdata, (const char *)entity->textPtr,
(const char *)textEnd, pool,
XML_ACCOUNT_ENTITY_EXPANSION);
#if XML_GE == 1
entityTrackingOnClose(parser, entity, __LINE__);
#endif
entity->open = XML_FALSE;
if (result)
return result;
result = processEntity(parser, entity, XML_FALSE, ENTITY_ATTRIBUTE);
if ((result == XML_ERROR_NONE) && (nextPtr != NULL)) {
*nextPtr = next;
}
return result;
}
} break;
default:
@@ -6197,7 +6397,7 @@ appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
static enum XML_Error
storeEntityValue(XML_Parser parser, const ENCODING *enc,
const char *entityTextPtr, const char *entityTextEnd,
enum XML_Account account) {
enum XML_Account account, const char **nextPtr) {
DTD *const dtd = parser->m_dtd; /* save one level of indirection */
STRING_POOL *pool = &(dtd->entityValuePool);
enum XML_Error result = XML_ERROR_NONE;
@@ -6215,8 +6415,9 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
return XML_ERROR_NO_MEMORY;
}
const char *next;
for (;;) {
const char *next
next
= entityTextPtr; /* XmlEntityValueTok doesn't always set the last arg */
int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next);
@@ -6278,16 +6479,8 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
} else
dtd->keepProcessing = dtd->standalone;
} else {
entity->open = XML_TRUE;
entityTrackingOnOpen(parser, entity, __LINE__);
result = storeEntityValue(
parser, parser->m_internalEncoding, (const char *)entity->textPtr,
(const char *)(entity->textPtr + entity->textLen),
XML_ACCOUNT_ENTITY_EXPANSION);
entityTrackingOnClose(parser, entity, __LINE__);
entity->open = XML_FALSE;
if (result)
goto endEntityValue;
result = processEntity(parser, entity, XML_FALSE, ENTITY_VALUE);
goto endEntityValue;
}
break;
}
@@ -6375,6 +6568,81 @@ endEntityValue:
# ifdef XML_DTD
parser->m_prologState.inEntityValue = oldInEntityValue;
# endif /* XML_DTD */
// If 'nextPtr' is given, it should be updated during the processing
if (nextPtr != NULL) {
*nextPtr = next;
}
return result;
}
static enum XML_Error
callStoreEntityValue(XML_Parser parser, const ENCODING *enc,
const char *entityTextPtr, const char *entityTextEnd,
enum XML_Account account) {
const char *next = entityTextPtr;
enum XML_Error result = XML_ERROR_NONE;
while (1) {
if (! parser->m_openValueEntities) {
result
= storeEntityValue(parser, enc, next, entityTextEnd, account, &next);
} else {
OPEN_INTERNAL_ENTITY *const openEntity = parser->m_openValueEntities;
if (! openEntity)
return XML_ERROR_UNEXPECTED_STATE;
ENTITY *const entity = openEntity->entity;
const char *const textStart
= ((const char *)entity->textPtr) + entity->processed;
const char *const textEnd
= (const char *)(entity->textPtr + entity->textLen);
/* Set a safe default value in case 'next' does not get set */
const char *nextInEntity = textStart;
if (entity->hasMore) {
result = storeEntityValue(parser, parser->m_internalEncoding, textStart,
textEnd, XML_ACCOUNT_ENTITY_EXPANSION,
&nextInEntity);
if (result != XML_ERROR_NONE)
break;
// Check if entity is complete, if not, mark down how much of it is
// processed. A XML_SUSPENDED check here is not required as
// appendAttributeValue will never suspend the parser.
if (textEnd != nextInEntity) {
entity->processed
= (int)(nextInEntity - (const char *)entity->textPtr);
continue;
}
// Entity is complete. We cannot close it here since we need to first
// process its possible inner entities (which are added to the
// m_openValueEntities during storeEntityValue)
entity->hasMore = XML_FALSE;
continue;
} // End of entity processing, "if" block skips the rest
// Remove fully processed openEntity from open entity list.
# if XML_GE == 1
entityTrackingOnClose(parser, entity, __LINE__);
# endif
// openEntity is m_openValueEntities' head, since we set it at the
// start of this function and because we skipped storeEntityValue call
// with hasMore set to false. This means we can directly remove the head
// of m_openValueEntities
assert(parser->m_openValueEntities == openEntity);
entity->open = XML_FALSE;
parser->m_openValueEntities = parser->m_openValueEntities->next;
/* put openEntity back in list of free instances */
openEntity->next = parser->m_freeValueEntities;
parser->m_freeValueEntities = openEntity;
}
// Break if an error occurred or there is nothing left to process
if (result
|| (parser->m_openValueEntities == NULL && entityTextEnd == next)) {
break;
}
}
return result;
}
@@ -7983,7 +8251,7 @@ entityTrackingReportStats(XML_Parser rootParser, ENTITY *entity,
(void *)rootParser, rootParser->m_entity_stats.countEverOpened,
rootParser->m_entity_stats.currentDepth,
rootParser->m_entity_stats.maximumDepthSeen,
(rootParser->m_entity_stats.currentDepth - 1) * 2, "",
((int)rootParser->m_entity_stats.currentDepth - 1) * 2, "",
entity->is_param ? "%" : "&", entityName, action, entity->textLen,
sourceLine);
}
@@ -8542,11 +8810,13 @@ unsignedCharToPrintable(unsigned char c) {
return "\\xFE";
case 255:
return "\\xFF";
// LCOV_EXCL_START
default:
assert(0); /* never gets here */
return "dead code";
}
assert(0); /* never gets here */
// LCOV_EXCL_STOP
}
#endif /* XML_GE == 1 */
+4 -1
View File
@@ -360,13 +360,16 @@ END_TEST
START_TEST(test_helper_unsigned_char_to_printable) {
// Smoke test
unsigned char uc = 0;
for (; uc < (unsigned char)-1; uc++) {
for (;; uc++) {
set_subtest("char %u", (unsigned)uc);
const char *const printable = unsignedCharToPrintable(uc);
if (printable == NULL)
fail("unsignedCharToPrintable returned NULL");
else if (strlen(printable) < (size_t)1)
fail("unsignedCharToPrintable returned empty string");
if (uc == (unsigned char)-1) {
break;
}
}
// Two concrete samples
+27
View File
@@ -19,6 +19,7 @@
Copyright (c) 2020 Tim Gates <tim.gates@iress.com>
Copyright (c) 2021 Donghee Na <donghee.na@python.org>
Copyright (c) 2023 Sony Corporation / Snild Dolkow <snild@sony.com>
Copyright (c) 2025 Berkay Eren Ürün <berkay.ueruen@siemens.com>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -450,6 +451,31 @@ START_TEST(test_alloc_internal_entity) {
}
END_TEST
START_TEST(test_alloc_parameter_entity) {
const char *text = "<!DOCTYPE foo ["
"<!ENTITY % param1 \"<!ENTITY internal 'some_text'>\">"
"%param1;"
"]> <foo>&internal;content</foo>";
int i;
const int alloc_test_max_repeats = 30;
for (i = 0; i < alloc_test_max_repeats; i++) {
g_allocation_count = i;
XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
!= XML_STATUS_ERROR)
break;
alloc_teardown();
alloc_setup();
}
g_allocation_count = -1;
if (i == 0)
fail("Parameter entity processed despite duff allocator");
if (i == alloc_test_max_repeats)
fail("Parameter entity not processed at max allocation count");
}
END_TEST
/* Test the robustness against allocation failure of element handling
* Based on test_dtd_default_handling().
*/
@@ -2079,6 +2105,7 @@ make_alloc_test_case(Suite *s) {
tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_external_entity);
tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_ext_entity_set_encoding);
tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_internal_entity);
tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_parameter_entity);
tcase_add_test__ifdef_xml_dtd(tc_alloc, test_alloc_dtd_default_handling);
tcase_add_test(tc_alloc, test_alloc_explicit_encoding);
tcase_add_test(tc_alloc, test_alloc_set_base);
+322 -9
View File
@@ -10,7 +10,7 @@
Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2016-2025 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
Copyright (c) 2017 Joe Orton <jorton@redhat.com>
Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com>
@@ -19,6 +19,7 @@
Copyright (c) 2020 Tim Gates <tim.gates@iress.com>
Copyright (c) 2021 Donghee Na <donghee.na@python.org>
Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow <snild@sony.com>
Copyright (c) 2024-2025 Berkay Eren Ürün <berkay.ueruen@siemens.com>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -1191,6 +1192,22 @@ START_TEST(test_not_standalone_handler_accept) {
}
END_TEST
START_TEST(test_entity_start_tag_level_greater_than_one) {
const char *const text = "<!DOCTYPE t1 [\n"
" <!ENTITY e1 'hello'>\n"
"]>\n"
"<t1>\n"
" <t2>&e1;</t2>\n"
"</t1>\n";
XML_Parser parser = XML_ParserCreate(NULL);
assert_true(_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text),
/*isFinal*/ XML_TRUE)
== XML_STATUS_OK);
XML_ParserFree(parser);
}
END_TEST
START_TEST(test_wfc_no_recursive_entity_refs) {
const char *text = "<!DOCTYPE doc [\n"
" <!ENTITY entity '&#38;entity;'>\n"
@@ -1202,6 +1219,93 @@ START_TEST(test_wfc_no_recursive_entity_refs) {
}
END_TEST
START_TEST(test_no_indirectly_recursive_entity_refs) {
struct TestCase {
const char *doc;
bool usesParameterEntities;
};
const struct TestCase cases[] = {
// general entity + character data
{"<!DOCTYPE a [\n"
" <!ENTITY e1 '&e2;'>\n"
" <!ENTITY e2 '&e1;'>\n"
"]><a>&e2;</a>\n",
false},
// general entity + attribute value
{"<!DOCTYPE a [\n"
" <!ENTITY e1 '&e2;'>\n"
" <!ENTITY e2 '&e1;'>\n"
"]><a k1='&e2;' />\n",
false},
// parameter entity
{"<!DOCTYPE doc [\n"
" <!ENTITY % p1 '&#37;p2;'>\n"
" <!ENTITY % p2 '&#37;p1;'>\n"
" <!ENTITY % define_g \"<!ENTITY g '&#37;p2;'>\">\n"
" %define_g;\n"
"]>\n"
"<doc/>\n",
true},
};
const XML_Bool reset_or_not[] = {XML_TRUE, XML_FALSE};
for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
for (size_t j = 0; j < sizeof(reset_or_not) / sizeof(reset_or_not[0]);
j++) {
const XML_Bool reset_wanted = reset_or_not[j];
const char *const doc = cases[i].doc;
const bool usesParameterEntities = cases[i].usesParameterEntities;
set_subtest("[%i,reset=%i] %s", (int)i, (int)j, doc);
#ifdef XML_DTD // both GE and DTD
const bool rejection_expected = true;
#elif XML_GE == 1 // GE but not DTD
const bool rejection_expected = ! usesParameterEntities;
#else // neither DTD nor GE
const bool rejection_expected = false;
#endif
XML_Parser parser = XML_ParserCreate(NULL);
#ifdef XML_DTD
if (usesParameterEntities) {
assert_true(
XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS)
== 1);
}
#else
UNUSED_P(usesParameterEntities);
#endif // XML_DTD
const enum XML_Status status
= _XML_Parse_SINGLE_BYTES(parser, doc, (int)strlen(doc),
/*isFinal*/ XML_TRUE);
if (rejection_expected) {
assert_true(status == XML_STATUS_ERROR);
assert_true(XML_GetErrorCode(parser) == XML_ERROR_RECURSIVE_ENTITY_REF);
} else {
assert_true(status == XML_STATUS_OK);
}
if (reset_wanted) {
// This covers free'ing of (eventually) all three open entity lists by
// XML_ParserReset.
XML_ParserReset(parser, NULL);
}
// This covers free'ing of (eventually) all three open entity lists by
// XML_ParserFree (unless XML_ParserReset has already done that above).
XML_ParserFree(parser);
}
}
}
END_TEST
START_TEST(test_recursive_external_parameter_entity_2) {
struct TestCase {
const char *doc;
@@ -1417,7 +1521,9 @@ START_TEST(test_suspend_parser_between_char_data_calls) {
XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
g_resumable = XML_TRUE;
if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
// can't use SINGLE_BYTES here, because it'll return early on suspension, and
// we won't know exactly how much input we actually managed to give Expat.
if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
!= XML_STATUS_SUSPENDED)
xml_failure(g_parser);
if (XML_GetErrorCode(g_parser) != XML_ERROR_NONE)
@@ -1446,7 +1552,9 @@ START_TEST(test_repeated_stop_parser_between_char_data_calls) {
XML_SetCharacterDataHandler(g_parser, parser_stop_character_handler);
g_resumable = XML_TRUE;
g_abortable = XML_FALSE;
if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
// can't use SINGLE_BYTES here, because it'll return early on suspension, and
// we won't know exactly how much input we actually managed to give Expat.
if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
!= XML_STATUS_SUSPENDED)
fail("Failed to double-suspend parser");
@@ -1830,12 +1938,19 @@ END_TEST
/* Test suspending the parser in cdata handler */
START_TEST(test_suspend_parser_between_cdata_calls) {
if (g_chunkSize != 0) {
// this test does not use SINGLE_BYTES, because of suspension
return;
}
const char *text = long_cdata_text;
enum XML_Status result;
XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
g_resumable = XML_TRUE;
result = _XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE);
// can't use SINGLE_BYTES here, because it'll return early on suspension, and
// we won't know exactly how much input we actually managed to give Expat.
result = XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE);
if (result != XML_STATUS_SUSPENDED) {
if (result == XML_STATUS_ERROR)
xml_failure(g_parser);
@@ -2378,6 +2493,11 @@ END_TEST
* entity. Exercises some obscure code in XML_ParserReset().
*/
START_TEST(test_reset_in_entity) {
if (g_chunkSize != 0) {
// this test does not use SINGLE_BYTES, because of suspension
return;
}
const char *text = "<!DOCTYPE doc [\n"
"<!ENTITY wombat 'wom'>\n"
"<!ENTITY entity 'hi &wom; there'>\n"
@@ -2387,7 +2507,9 @@ START_TEST(test_reset_in_entity) {
g_resumable = XML_TRUE;
XML_SetCharacterDataHandler(g_parser, clearing_aborting_character_handler);
if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
// can't use SINGLE_BYTES here, because it'll return early on suspension, and
// we won't know exactly how much input we actually managed to give Expat.
if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
== XML_STATUS_ERROR)
xml_failure(g_parser);
XML_GetParsingStatus(g_parser, &status);
@@ -3634,7 +3756,9 @@ START_TEST(test_suspend_xdecl) {
XML_SetXmlDeclHandler(g_parser, entity_suspending_xdecl_handler);
XML_SetUserData(g_parser, g_parser);
g_resumable = XML_TRUE;
if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
// can't use SINGLE_BYTES here, because it'll return early on suspension, and
// we won't know exactly how much input we actually managed to give Expat.
if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
!= XML_STATUS_SUSPENDED)
xml_failure(g_parser);
if (XML_GetErrorCode(g_parser) != XML_ERROR_NONE)
@@ -3830,13 +3954,20 @@ END_TEST
/* Test syntax error is caught at parse resumption */
START_TEST(test_resume_entity_with_syntax_error) {
if (g_chunkSize != 0) {
// this test does not use SINGLE_BYTES, because of suspension
return;
}
const char *text = "<!DOCTYPE doc [\n"
"<!ENTITY foo '<suspend>Hi</wombat>'>\n"
"]>\n"
"<doc>&foo;</doc>\n";
XML_SetStartElementHandler(g_parser, start_element_suspender);
if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
// can't use SINGLE_BYTES here, because it'll return early on suspension, and
// we won't know exactly how much input we actually managed to give Expat.
if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
!= XML_STATUS_SUSPENDED)
xml_failure(g_parser);
if (XML_ResumeParser(g_parser) != XML_STATUS_ERROR)
@@ -3960,7 +4091,7 @@ START_TEST(test_skipped_null_loaded_ext_entity) {
= {"<!ENTITY % pe1 SYSTEM 'http://example.org/two.ent'>\n"
"<!ENTITY % pe2 '%pe1;'>\n"
"%pe2;\n",
external_entity_null_loader};
external_entity_null_loader, NULL};
XML_SetUserData(g_parser, &test_data);
XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
@@ -3978,7 +4109,7 @@ START_TEST(test_skipped_unloaded_ext_entity) {
= {"<!ENTITY % pe1 SYSTEM 'http://example.org/two.ent'>\n"
"<!ENTITY % pe2 '%pe1;'>\n"
"%pe2;\n",
NULL};
NULL, NULL};
XML_SetUserData(g_parser, &test_data);
XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
@@ -5278,6 +5409,151 @@ START_TEST(test_pool_integrity_with_unfinished_attr) {
}
END_TEST
/* Test a possible early return location in internalEntityProcessor */
START_TEST(test_entity_ref_no_elements) {
const char *const text = "<!DOCTYPE foo [\n"
"<!ENTITY e1 \"test\">\n"
"]> <foo>&e1;"; // intentionally missing newline
XML_Parser parser = XML_ParserCreate(NULL);
assert_true(_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
== XML_STATUS_ERROR);
assert_true(XML_GetErrorCode(parser) == XML_ERROR_NO_ELEMENTS);
XML_ParserFree(parser);
}
END_TEST
/* Tests if chained entity references lead to unbounded recursion */
START_TEST(test_deep_nested_entity) {
const size_t N_LINES = 60000;
const size_t SIZE_PER_LINE = 50;
char *const text = (char *)malloc((N_LINES + 4) * SIZE_PER_LINE);
if (text == NULL) {
fail("malloc failed");
}
char *textPtr = text;
// Create the XML
textPtr += snprintf(textPtr, SIZE_PER_LINE,
"<!DOCTYPE foo [\n"
" <!ENTITY s0 'deepText'>\n");
for (size_t i = 1; i < N_LINES; ++i) {
textPtr += snprintf(textPtr, SIZE_PER_LINE, " <!ENTITY s%lu '&s%lu;'>\n",
(long unsigned)i, (long unsigned)(i - 1));
}
snprintf(textPtr, SIZE_PER_LINE, "]> <foo>&s%lu;</foo>\n",
(long unsigned)(N_LINES - 1));
const XML_Char *const expected = XCS("deepText");
CharData storage;
CharData_Init(&storage);
XML_Parser parser = XML_ParserCreate(NULL);
XML_SetCharacterDataHandler(parser, accumulate_characters);
XML_SetUserData(parser, &storage);
if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
== XML_STATUS_ERROR)
xml_failure(parser);
CharData_CheckXMLChars(&storage, expected);
XML_ParserFree(parser);
free(text);
}
END_TEST
/* Tests if chained entity references in attributes
lead to unbounded recursion */
START_TEST(test_deep_nested_attribute_entity) {
const size_t N_LINES = 60000;
const size_t SIZE_PER_LINE = 100;
char *const text = (char *)malloc((N_LINES + 4) * SIZE_PER_LINE);
if (text == NULL) {
fail("malloc failed");
}
char *textPtr = text;
// Create the XML
textPtr += snprintf(textPtr, SIZE_PER_LINE,
"<!DOCTYPE foo [\n"
" <!ENTITY s0 'deepText'>\n");
for (size_t i = 1; i < N_LINES; ++i) {
textPtr += snprintf(textPtr, SIZE_PER_LINE, " <!ENTITY s%lu '&s%lu;'>\n",
(long unsigned)i, (long unsigned)(i - 1));
}
snprintf(textPtr, SIZE_PER_LINE, "]> <foo name='&s%lu;'>mainText</foo>\n",
(long unsigned)(N_LINES - 1));
AttrInfo doc_info[] = {{XCS("name"), XCS("deepText")}, {NULL, NULL}};
ElementInfo info[] = {{XCS("foo"), 1, NULL, NULL}, {NULL, 0, NULL, NULL}};
info[0].attributes = doc_info;
XML_Parser parser = XML_ParserCreate(NULL);
ParserAndElementInfo parserPlusElemenInfo = {parser, info};
XML_SetStartElementHandler(parser, counting_start_element_handler);
XML_SetUserData(parser, &parserPlusElemenInfo);
if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
== XML_STATUS_ERROR)
xml_failure(parser);
XML_ParserFree(parser);
free(text);
}
END_TEST
START_TEST(test_deep_nested_entity_delayed_interpretation) {
const size_t N_LINES = 70000;
const size_t SIZE_PER_LINE = 100;
char *const text = (char *)malloc((N_LINES + 4) * SIZE_PER_LINE);
if (text == NULL) {
fail("malloc failed");
}
char *textPtr = text;
// Create the XML
textPtr += snprintf(textPtr, SIZE_PER_LINE,
"<!DOCTYPE foo [\n"
" <!ENTITY %% s0 'deepText'>\n");
for (size_t i = 1; i < N_LINES; ++i) {
textPtr += snprintf(textPtr, SIZE_PER_LINE,
" <!ENTITY %% s%lu '&#37;s%lu;'>\n", (long unsigned)i,
(long unsigned)(i - 1));
}
snprintf(textPtr, SIZE_PER_LINE,
" <!ENTITY %% define_g \"<!ENTITY g '&#37;s%lu;'>\">\n"
" %%define_g;\n"
"]>\n"
"<foo/>\n",
(long unsigned)(N_LINES - 1));
XML_Parser parser = XML_ParserCreate(NULL);
XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
== XML_STATUS_ERROR)
xml_failure(parser);
XML_ParserFree(parser);
free(text);
}
END_TEST
START_TEST(test_nested_entity_suspend) {
const char *const text = "<!DOCTYPE a [\n"
" <!ENTITY e1 '<!--e1-->'>\n"
@@ -5308,6 +5584,35 @@ START_TEST(test_nested_entity_suspend) {
}
END_TEST
START_TEST(test_nested_entity_suspend_2) {
const char *const text = "<!DOCTYPE doc [\n"
" <!ENTITY ge1 'head1Ztail1'>\n"
" <!ENTITY ge2 'head2&ge1;tail2'>\n"
" <!ENTITY ge3 'head3&ge2;tail3'>\n"
"]>\n"
"<doc>&ge3;</doc>";
const XML_Char *const expected = XCS("head3") XCS("head2") XCS("head1")
XCS("Z") XCS("tail1") XCS("tail2") XCS("tail3");
CharData storage;
CharData_Init(&storage);
XML_Parser parser = XML_ParserCreate(NULL);
ParserPlusStorage parserPlusStorage = {parser, &storage};
XML_SetCharacterDataHandler(parser, accumulate_char_data_and_suspend);
XML_SetUserData(parser, &parserPlusStorage);
enum XML_Status status = XML_Parse(parser, text, (int)strlen(text), XML_TRUE);
while (status == XML_STATUS_SUSPENDED) {
status = XML_ResumeParser(parser);
}
if (status != XML_STATUS_OK)
xml_failure(parser);
CharData_CheckXMLChars(&storage, expected);
XML_ParserFree(parser);
}
END_TEST
/* Regression test for quadratic parsing on large tokens */
START_TEST(test_big_tokens_scale_linearly) {
const struct {
@@ -5968,7 +6273,9 @@ make_basic_test_case(Suite *s) {
tcase_add_test(tc_basic, test_wfc_undeclared_entity_with_external_subset);
tcase_add_test(tc_basic, test_not_standalone_handler_reject);
tcase_add_test(tc_basic, test_not_standalone_handler_accept);
tcase_add_test(tc_basic, test_entity_start_tag_level_greater_than_one);
tcase_add_test__if_xml_ge(tc_basic, test_wfc_no_recursive_entity_refs);
tcase_add_test(tc_basic, test_no_indirectly_recursive_entity_refs);
tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_invalid_parse);
tcase_add_test__if_xml_ge(tc_basic, test_dtd_default_handling);
tcase_add_test(tc_basic, test_dtd_attr_handling);
@@ -6147,7 +6454,13 @@ make_basic_test_case(Suite *s) {
tcase_add_test(tc_basic, test_empty_element_abort);
tcase_add_test__ifdef_xml_dtd(tc_basic,
test_pool_integrity_with_unfinished_attr);
tcase_add_test__if_xml_ge(tc_basic, test_entity_ref_no_elements);
tcase_add_test__if_xml_ge(tc_basic, test_deep_nested_entity);
tcase_add_test__if_xml_ge(tc_basic, test_deep_nested_attribute_entity);
tcase_add_test__if_xml_ge(tc_basic,
test_deep_nested_entity_delayed_interpretation);
tcase_add_test__if_xml_ge(tc_basic, test_nested_entity_suspend);
tcase_add_test__if_xml_ge(tc_basic, test_nested_entity_suspend_2);
tcase_add_test(tc_basic, test_big_tokens_scale_linearly);
tcase_add_test(tc_basic, test_set_reparse_deferral);
tcase_add_test(tc_basic, test_reparse_deferral_is_inherited);
+40 -17
View File
@@ -8,7 +8,7 @@
Copyright (c) 2003-2006 Karl Waclawek <karl@waclawek.net>
Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
Copyright (c) 2017-2023 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2017-2025 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
Licensed under the MIT license:
@@ -32,10 +32,18 @@
USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#define _POSIX_C_SOURCE 1 // fdopen
#if defined(_MSC_VER)
# include <io.h> // _open, _close
#else
# include <unistd.h> // close
#endif
#include <fcntl.h> // open
#include <sys/stat.h>
#include <assert.h>
#include <stddef.h> // ptrdiff_t
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "expat.h"
@@ -52,17 +60,18 @@
# define XML_FMT_STR "s"
#endif
static void
static int
usage(const char *prog, int rc) {
fprintf(stderr, "usage: %s [-n] filename bufferSize nr_of_loops\n", prog);
exit(rc);
return rc;
}
int
main(int argc, char *argv[]) {
XML_Parser parser;
char *XMLBuf, *XMLBufEnd, *XMLBufPtr;
FILE *fd;
int fd;
FILE *file;
struct stat fileAttr;
int nrOfLoops, bufferSize, i, isFinal;
size_t fileSize;
@@ -76,34 +85,48 @@ main(int argc, char *argv[]) {
ns = 1;
j = 1;
} else
usage(argv[0], 1);
return usage(argv[0], 1);
}
}
if (argc != j + 4)
usage(argv[0], 1);
return usage(argv[0], 1);
if (stat(argv[j + 1], &fileAttr) != 0) {
fprintf(stderr, "could not access file '%s'\n", argv[j + 1]);
fd = open(argv[j + 1], O_RDONLY);
if (fd == -1) {
fprintf(stderr, "could not open file '%s'\n", argv[j + 1]);
return 2;
}
fd = fopen(argv[j + 1], "r");
if (! fd) {
fprintf(stderr, "could not open file '%s'\n", argv[j + 1]);
exit(2);
if (fstat(fd, &fileAttr) != 0) {
close(fd);
fprintf(stderr, "could not fstat file '%s'\n", argv[j + 1]);
return 2;
}
file = fdopen(fd, "r");
if (! file) {
close(fd);
fprintf(stderr, "could not fdopen file '%s'\n", argv[j + 1]);
return 2;
}
bufferSize = atoi(argv[j + 2]);
nrOfLoops = atoi(argv[j + 3]);
if (bufferSize <= 0 || nrOfLoops <= 0) {
fclose(file); // NOTE: this closes fd as well
fprintf(stderr, "buffer size and nr of loops must be greater than zero.\n");
exit(3);
return 3;
}
XMLBuf = malloc(fileAttr.st_size);
fileSize = fread(XMLBuf, sizeof(char), fileAttr.st_size, fd);
fclose(fd);
if (XMLBuf == NULL) {
fclose(file); // NOTE: this closes fd as well
fprintf(stderr, "ouf of memory.\n");
return 5;
}
fileSize = fread(XMLBuf, sizeof(char), fileAttr.st_size, file);
fclose(file); // NOTE: this closes fd as well
if (ns)
parser = XML_ParserCreateNS(NULL, '!');
@@ -132,7 +155,7 @@ main(int argc, char *argv[]) {
XML_GetCurrentColumnNumber(parser));
free(XMLBuf);
XML_ParserFree(parser);
exit(4);
return 4;
}
XMLBufPtr += bufferSize;
} while (! isFinal);
+32 -1
View File
@@ -10,7 +10,7 @@
Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2016-2025 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
Copyright (c) 2017 Joe Orton <jorton@redhat.com>
Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com>
@@ -42,6 +42,8 @@
*/
#include <assert.h>
#include <errno.h>
#include <stdint.h> // for SIZE_MAX
#include <stdio.h>
#include <string.h>
@@ -202,6 +204,12 @@ _XML_Parse_SINGLE_BYTES(XML_Parser parser, const char *s, int len,
for (; len > chunksize; len -= chunksize, s += chunksize) {
enum XML_Status res = XML_Parse(parser, s, chunksize, XML_FALSE);
if (res != XML_STATUS_OK) {
if ((res == XML_STATUS_SUSPENDED) && (len > chunksize)) {
fail("Use of function _XML_Parse_SINGLE_BYTES with a chunk size "
"greater than 0 (from g_chunkSize) does not work well with "
"suspension. Please consider use of plain XML_Parse at this "
"place in your test, instead.");
}
return res;
}
}
@@ -294,3 +302,26 @@ duff_reallocator(void *ptr, size_t size) {
g_reallocation_count--;
return realloc(ptr, size);
}
// Portable remake of strndup(3) for C99; does not care about space efficiency
char *
portable_strndup(const char *s, size_t n) {
if ((s == NULL) || (n == SIZE_MAX)) {
errno = EINVAL;
return NULL;
}
char *const buffer = (char *)malloc(n + 1);
if (buffer == NULL) {
errno = ENOMEM;
return NULL;
}
errno = 0;
memcpy(buffer, s, n);
buffer[n] = '\0';
return buffer;
}
+3 -1
View File
@@ -10,7 +10,7 @@
Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2016-2025 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
Copyright (c) 2017 Joe Orton <jorton@redhat.com>
Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com>
@@ -146,6 +146,8 @@ extern void *duff_allocator(size_t size);
extern void *duff_reallocator(void *ptr, size_t size);
extern char *portable_strndup(const char *s, size_t n);
#endif /* XML_COMMON_H */
#ifdef __cplusplus
+23
View File
@@ -1842,6 +1842,15 @@ element_decl_suspender(void *userData, const XML_Char *name,
XML_FreeContentModel(g_parser, model);
}
void XMLCALL
suspend_after_element_declaration(void *userData, const XML_Char *name,
XML_Content *model) {
UNUSED_P(name);
XML_Parser parser = (XML_Parser)userData;
assert_true(XML_StopParser(parser, /*resumable*/ XML_TRUE) == XML_STATUS_OK);
XML_FreeContentModel(parser, model);
}
void XMLCALL
accumulate_pi_characters(void *userData, const XML_Char *target,
const XML_Char *data) {
@@ -1882,6 +1891,20 @@ accumulate_entity_decl(void *userData, const XML_Char *entityName,
CharData_AppendXMLChars(storage, XCS("\n"), 1);
}
void XMLCALL
accumulate_char_data_and_suspend(void *userData, const XML_Char *s, int len) {
ParserPlusStorage *const parserPlusStorage = (ParserPlusStorage *)userData;
CharData_AppendXMLChars(parserPlusStorage->storage, s, len);
for (int i = 0; i < len; i++) {
if (s[i] == 'Z') {
XML_StopParser(parserPlusStorage->parser, /*resumable=*/XML_TRUE);
break;
}
}
}
void XMLCALL
accumulate_start_element(void *userData, const XML_Char *name,
const XML_Char **atts) {
+9
View File
@@ -325,6 +325,7 @@ extern int XMLCALL external_entity_devaluer(XML_Parser parser,
typedef struct ext_hdlr_data {
const char *parse_text;
XML_ExternalEntityRefHandler handler;
CharData *storage;
} ExtHdlrData;
extern int XMLCALL external_entity_oneshot_loader(XML_Parser parser,
@@ -557,6 +558,10 @@ extern void XMLCALL suspending_comment_handler(void *userData,
extern void XMLCALL element_decl_suspender(void *userData, const XML_Char *name,
XML_Content *model);
extern void XMLCALL suspend_after_element_declaration(void *userData,
const XML_Char *name,
XML_Content *model);
extern void XMLCALL accumulate_pi_characters(void *userData,
const XML_Char *target,
const XML_Char *data);
@@ -569,6 +574,10 @@ extern void XMLCALL accumulate_entity_decl(
const XML_Char *systemId, const XML_Char *publicId,
const XML_Char *notationName);
extern void XMLCALL accumulate_char_data_and_suspend(void *userData,
const XML_Char *s,
int len);
extern void XMLCALL accumulate_start_element(void *userData,
const XML_Char *name,
const XML_Char **atts);
+4 -2
View File
@@ -14,7 +14,7 @@
Copyright (c) 2004-2006 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
Copyright (c) 2006-2012 Karl Waclawek <karl@waclawek.net>
Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2016-2025 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2022 Rhodri James <rhodri@wildebeest.org.uk>
Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow <snild@sony.com>
Licensed under the MIT license:
@@ -129,8 +129,10 @@ void _check_set_test_info(char const *function, char const *filename,
* Prototypes for the actual implementation.
*/
# if defined(__GNUC__)
# if defined(__has_attribute)
# if __has_attribute(noreturn)
__attribute__((noreturn))
# endif
# endif
void
_fail(const char *file, int line, const char *msg);
+205 -44
View File
@@ -10,7 +10,7 @@
Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
Copyright (c) 2005-2007 Steven Solie <steven@solie.ca>
Copyright (c) 2005-2012 Karl Waclawek <karl@waclawek.net>
Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2016-2025 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
Copyright (c) 2017 Joe Orton <jorton@redhat.com>
Copyright (c) 2017 José Gutiérrez de la Concha <jose@zeroc.com>
@@ -59,6 +59,9 @@
#include "handlers.h"
#include "misc_tests.h"
void XMLCALL accumulate_characters_ext_handler(void *userData,
const XML_Char *s, int len);
/* Test that a failure to allocate the parser structure fails gracefully */
START_TEST(test_misc_alloc_create_parser) {
XML_Memory_Handling_Suite memsuite = {duff_allocator, realloc, free};
@@ -208,7 +211,7 @@ START_TEST(test_misc_version) {
if (! versions_equal(&read_version, &parsed_version))
fail("Version mismatch");
if (xcstrcmp(version_text, XCS("expat_2.6.4"))) /* needs bump on releases */
if (xcstrcmp(version_text, XCS("expat_2.7.1"))) /* needs bump on releases */
fail("XML_*_VERSION in expat.h out of sync?\n");
}
END_TEST
@@ -294,6 +297,7 @@ START_TEST(test_misc_stop_during_end_handler_issue_240_1) {
parser = XML_ParserCreate(NULL);
XML_SetElementHandler(parser, start_element_issue_240, end_element_issue_240);
mydata = (DataIssue240 *)malloc(sizeof(DataIssue240));
assert_true(mydata != NULL);
mydata->parser = parser;
mydata->deep = 0;
XML_SetUserData(parser, mydata);
@@ -315,6 +319,7 @@ START_TEST(test_misc_stop_during_end_handler_issue_240_2) {
parser = XML_ParserCreate(NULL);
XML_SetElementHandler(parser, start_element_issue_240, end_element_issue_240);
mydata = (DataIssue240 *)malloc(sizeof(DataIssue240));
assert_true(mydata != NULL);
mydata->parser = parser;
mydata->deep = 0;
XML_SetUserData(parser, mydata);
@@ -328,64 +333,119 @@ START_TEST(test_misc_stop_during_end_handler_issue_240_2) {
END_TEST
START_TEST(test_misc_deny_internal_entity_closing_doctype_issue_317) {
const char *const inputOne = "<!DOCTYPE d [\n"
"<!ENTITY % e ']><d/>'>\n"
"\n"
"%e;";
const char *const inputOne
= "<!DOCTYPE d [\n"
"<!ENTITY % element_d '<!ELEMENT d (#PCDATA)*>'>\n"
"%element_d;\n"
"<!ENTITY % e ']><d/>'>\n"
"\n"
"%e;";
const char *const inputTwo
= "<!DOCTYPE d [\n"
"<!ENTITY % element_d '<!ELEMENT d (#PCDATA)*>'>\n"
"%element_d;\n"
"<!ENTITY % e1 ']><d/>'><!ENTITY % e2 '&#37;e1;'>\n"
"\n"
"%e2;";
const char *const inputThree = "<!DOCTYPE d [\n"
"<!ENTITY % e ']><d'>\n"
"\n"
"%e;/>";
const char *const inputIssue317 = "<!DOCTYPE doc [\n"
"<!ENTITY % foo ']>\n"
"<doc>Hell<oc (#PCDATA)*>'>\n"
"%foo;\n"
"]>\n"
"<doc>Hello, world</dVc>";
const char *const inputThree
= "<!DOCTYPE d [\n"
"<!ENTITY % element_d '<!ELEMENT d (#PCDATA)*>'>\n"
"%element_d;\n"
"<!ENTITY % e ']><d'>\n"
"\n"
"%e;/>";
const char *const inputIssue317
= "<!DOCTYPE doc [\n"
"<!ENTITY % element_doc '<!ELEMENT doc (#PCDATA)*>'>\n"
"%element_doc;\n"
"<!ENTITY % foo ']>\n"
"<doc>Hell<oc (#PCDATA)*>'>\n"
"%foo;\n"
"]>\n"
"<doc>Hello, world</dVc>";
const char *const inputs[] = {inputOne, inputTwo, inputThree, inputIssue317};
const XML_Bool suspendOrNot[] = {XML_FALSE, XML_TRUE};
size_t inputIndex = 0;
for (; inputIndex < sizeof(inputs) / sizeof(inputs[0]); inputIndex++) {
set_subtest("%s", inputs[inputIndex]);
XML_Parser parser;
enum XML_Status parseResult;
int setParamEntityResult;
XML_Size lineNumber;
XML_Size columnNumber;
const char *const input = inputs[inputIndex];
for (size_t suspendOrNotIndex = 0;
suspendOrNotIndex < sizeof(suspendOrNot) / sizeof(suspendOrNot[0]);
suspendOrNotIndex++) {
const char *const input = inputs[inputIndex];
const XML_Bool suspend = suspendOrNot[suspendOrNotIndex];
if (suspend && (g_chunkSize > 0)) {
// We cannot use _XML_Parse_SINGLE_BYTES below due to suspension, and
// so chunk sizes >0 would only repeat the very same test
// due to use of plain XML_Parse; we are saving upon that runtime:
return;
}
parser = XML_ParserCreate(NULL);
setParamEntityResult
= XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
if (setParamEntityResult != 1)
fail("Failed to set XML_PARAM_ENTITY_PARSING_ALWAYS.");
set_subtest("[input=%d suspend=%s] %s", (int)inputIndex,
suspend ? "true" : "false", input);
XML_Parser parser;
enum XML_Status parseResult;
int setParamEntityResult;
XML_Size lineNumber;
XML_Size columnNumber;
parser = XML_ParserCreate(NULL);
setParamEntityResult
= XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
if (setParamEntityResult != 1)
fail("Failed to set XML_PARAM_ENTITY_PARSING_ALWAYS.");
if (suspend) {
XML_SetUserData(parser, parser);
XML_SetElementDeclHandler(parser, suspend_after_element_declaration);
}
if (suspend) {
// can't use SINGLE_BYTES here, because it'll return early on
// suspension, and we won't know exactly how much input we actually
// managed to give Expat.
parseResult = XML_Parse(parser, input, (int)strlen(input), 0);
while (parseResult == XML_STATUS_SUSPENDED) {
parseResult = XML_ResumeParser(parser);
}
if (parseResult != XML_STATUS_ERROR) {
// can't use SINGLE_BYTES here, because it'll return early on
// suspension, and we won't know exactly how much input we actually
// managed to give Expat.
parseResult = XML_Parse(parser, "", 0, 1);
}
while (parseResult == XML_STATUS_SUSPENDED) {
parseResult = XML_ResumeParser(parser);
}
} else {
parseResult
= _XML_Parse_SINGLE_BYTES(parser, input, (int)strlen(input), 0);
if (parseResult != XML_STATUS_ERROR) {
parseResult = _XML_Parse_SINGLE_BYTES(parser, "", 0, 1);
}
}
parseResult = _XML_Parse_SINGLE_BYTES(parser, input, (int)strlen(input), 0);
if (parseResult != XML_STATUS_ERROR) {
parseResult = _XML_Parse_SINGLE_BYTES(parser, "", 0, 1);
if (parseResult != XML_STATUS_ERROR) {
fail("Parsing was expected to fail but succeeded.");
}
if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN)
fail("Error code does not match XML_ERROR_INVALID_TOKEN");
lineNumber = XML_GetCurrentLineNumber(parser);
if (lineNumber != 6)
fail("XML_GetCurrentLineNumber does not work as expected.");
columnNumber = XML_GetCurrentColumnNumber(parser);
if (columnNumber != 0)
fail("XML_GetCurrentColumnNumber does not work as expected.");
XML_ParserFree(parser);
}
if (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN)
fail("Error code does not match XML_ERROR_INVALID_TOKEN");
lineNumber = XML_GetCurrentLineNumber(parser);
if (lineNumber != 4)
fail("XML_GetCurrentLineNumber does not work as expected.");
columnNumber = XML_GetCurrentColumnNumber(parser);
if (columnNumber != 0)
fail("XML_GetCurrentColumnNumber does not work as expected.");
XML_ParserFree(parser);
}
}
END_TEST
@@ -519,6 +579,105 @@ START_TEST(test_misc_stopparser_rejects_unstarted_parser) {
}
END_TEST
/* Adaptation of accumulate_characters that takes ExtHdlrData input to work with
* test_renter_loop_finite_content below */
void XMLCALL
accumulate_characters_ext_handler(void *userData, const XML_Char *s, int len) {
ExtHdlrData *const test_data = (ExtHdlrData *)userData;
CharData_AppendXMLChars(test_data->storage, s, len);
}
/* Test that internalEntityProcessor does not re-enter forever;
* based on files tests/xmlconf/xmltest/valid/ext-sa/012.{xml,ent} */
START_TEST(test_renter_loop_finite_content) {
CharData storage;
CharData_Init(&storage);
const char *const text = "<!DOCTYPE doc [\n"
"<!ENTITY e1 '&e2;'>\n"
"<!ENTITY e2 '&e3;'>\n"
"<!ENTITY e3 SYSTEM '012.ent'>\n"
"<!ENTITY e4 '&e5;'>\n"
"<!ENTITY e5 '(e5)'>\n"
"<!ELEMENT doc (#PCDATA)>\n"
"]>\n"
"<doc>&e1;</doc>\n";
ExtHdlrData test_data = {"&e4;\n", external_entity_null_loader, &storage};
const XML_Char *const expected = XCS("(e5)\n");
XML_Parser parser = XML_ParserCreate(NULL);
assert_true(parser != NULL);
XML_SetUserData(parser, &test_data);
XML_SetExternalEntityRefHandler(parser, external_entity_oneshot_loader);
XML_SetCharacterDataHandler(parser, accumulate_characters_ext_handler);
if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
== XML_STATUS_ERROR)
xml_failure(parser);
CharData_CheckXMLChars(&storage, expected);
XML_ParserFree(parser);
}
END_TEST
// Inspired by function XML_OriginalString of Perl's XML::Parser
static char *
dup_original_string(XML_Parser parser) {
const int byte_count = XML_GetCurrentByteCount(parser);
assert_true(byte_count >= 0);
int offset = -1;
int size = -1;
const char *const context = XML_GetInputContext(parser, &offset, &size);
#if XML_CONTEXT_BYTES > 0
assert_true(context != NULL);
assert_true(offset >= 0);
assert_true(size >= 0);
return portable_strndup(context + offset, byte_count);
#else
assert_true(context == NULL);
return NULL;
#endif
}
static void
on_characters_issue_980(void *userData, const XML_Char *s, int len) {
(void)s;
(void)len;
XML_Parser parser = (XML_Parser)userData;
char *const original_string = dup_original_string(parser);
#if XML_CONTEXT_BYTES > 0
assert_true(original_string != NULL);
assert_true(strcmp(original_string, "&draft.day;") == 0);
free(original_string);
#else
assert_true(original_string == NULL);
#endif
}
START_TEST(test_misc_expected_event_ptr_issue_980) {
// NOTE: This is a tiny subset of sample "REC-xml-19980210.xml"
// from Perl's XML::Parser
const char *const doc = "<!DOCTYPE day [\n"
" <!ENTITY draft.day '10'>\n"
"]>\n"
"<day>&draft.day;</day>\n";
XML_Parser parser = XML_ParserCreate(NULL);
XML_SetUserData(parser, parser);
XML_SetCharacterDataHandler(parser, on_characters_issue_980);
assert_true(_XML_Parse_SINGLE_BYTES(parser, doc, (int)strlen(doc),
/*isFinal=*/XML_TRUE)
== XML_STATUS_OK);
XML_ParserFree(parser);
}
END_TEST
void
make_miscellaneous_test_case(Suite *s) {
TCase *tc_misc = tcase_create("miscellaneous tests");
@@ -545,4 +704,6 @@ make_miscellaneous_test_case(Suite *s) {
tcase_add_test(tc_misc, test_misc_char_handler_stop_without_leak);
tcase_add_test(tc_misc, test_misc_resumeparser_not_crashing);
tcase_add_test(tc_misc, test_misc_stopparser_rejects_unstarted_parser);
tcase_add_test__if_xml_ge(tc_misc, test_renter_loop_finite_content);
tcase_add_test(tc_misc, test_misc_expected_event_ptr_issue_980);
}
+3 -2
View File
@@ -2,8 +2,8 @@
# EXPAT TEST SCRIPT FOR W3C XML TEST SUITE
#
# This script can be used to exercise Expat against the
# w3c.org xml test suite, available from
# http://www.w3.org/XML/Test/xmlts20020606.zip.
# w3c.org xml test suite, available from:
# https://www.w3.org/XML/Test/xmlts20020606.zip
#
# To run this script, first set XMLWF below so that xmlwf can be
# found, then set the output directory with OUTPUT.
@@ -30,6 +30,7 @@
# Copyright (c) 2002 Karl Waclawek <[email protected]>
# Copyright (c) 2008-2019 Sebastian Pipping <[email protected]>
# Copyright (c) 2017 Rhodri James <[email protected]>
# Copyright (c) 2025 Hanno Böck <[email protected]>
# Licensed under the MIT license:
#
# Permission is hereby granted, free of charge, to any person obtaining
+2 -1
View File
@@ -14,6 +14,7 @@
Copyright (c) 2017 Rhodri James <rhodri@wildebeest.org.uk>
Copyright (c) 2017 Franek Korta <fkorta@gmail.com>
Copyright (c) 2022 Sean McBride <sean@rogue-research.com>
Copyright (c) 2025 Hanno Böck <hanno@gentoo.org>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -55,7 +56,7 @@
# define EXPAT_read_count_t int
# define EXPAT_read_req_t unsigned int
#else /* POSIX */
/* http://pubs.opengroup.org/onlinepubs/009695399/functions/read.html */
/* https://pubs.opengroup.org/onlinepubs/009695399/functions/read.html */
# define EXPAT_read read
# define EXPAT_read_count_t ssize_t
# define EXPAT_read_req_t size_t
+1 -1
View File
@@ -20,7 +20,7 @@ the actual statements in the files are controlling.
libarchive/mtree.5
* The following source files are in the public domain:
libarchive/archive_getdate.c
libarchive/archive_parse_date.c
* The following source files are triple-licensed with the ability to choose
from CC0 1.0 Universal, OpenSSL or Apache 2.0 licenses:
+8
View File
@@ -1,3 +1,11 @@
Jun 01, 2026: libarchive 3.8.1 released
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
+6 -3
View File
@@ -85,13 +85,14 @@ Currently, the library automatically detects and reads the following formats:
* PWB binary cpio
* ISO9660 CD-ROM images (with optional Rockridge or Joliet extensions)
* ZIP archives (with uncompressed or "deflate" compressed entries, including support for encrypted Zip archives)
* ZIPX archives (with support for bzip2, ppmd8, lzma and xz compressed entries)
* ZIPX archives (with support for bzip2, zstd, ppmd8, lzma and xz compressed entries)
* GNU and BSD 'ar' archives
* 'mtree' format
* 7-Zip archives (including archives that use zstandard compression)
* Microsoft CAB format
* LHA and LZH archives
* RAR and RAR 5.0 archives (with some limitations due to RAR's proprietary status)
* WARC archives
* XAR archives
The library also detects and handles any of the following before evaluating the archive:
@@ -120,15 +121,18 @@ The library can create archives in any of the following formats:
* PWB binary cpio
* shar archives
* ZIP archives (with uncompressed or "deflate" compressed entries)
* ZIPX archives (with bzip2, zstd, lzma or xz compressed entries)
* GNU and BSD 'ar' archives
* 'mtree' format
* ISO9660 format
* 7-Zip archives
* 7-Zip archives (including archives that use zstandard compression)
* WARC archives
* XAR archives
When creating archives, the result can be filtered with any of the following:
* uuencode
* base64
* gzip compression
* bzip2 compression
* compress/LZW compression
@@ -241,4 +245,3 @@ questions we are asked about libarchive:
appropriate. It has many advantages over other tar formats
(including the legacy GNU tar format) and is widely supported by
current tar implementations.
@@ -0,0 +1,19 @@
#!/bin/sh
set -eux
# Uncommenting these adds a full minute to the CI time
#brew update > /dev/null
#brew upgrade > /dev/null
# This does an upgrade if the package is already installed
brew install \
autoconf \
automake \
libtool \
pkg-config \
cmake \
xz \
lz4 \
zstd \
libxml2 \
openssl
+1 -1
View File
@@ -1206,7 +1206,7 @@ list_item_verbose(struct cpio *cpio, struct archive_entry *entry)
else
strcpy(date, "invalid mtime");
fprintf(out, "%s%3d %-8s %-8s %8s %12s %s",
fprintf(out, "%s%3u %-8s %-8s %8s %12s %s",
archive_entry_strmode(entry),
archive_entry_nlink(entry),
uname, gname, size, date,
@@ -189,10 +189,10 @@ DEFINE_TEST(test_format_newc)
gid = from_hex(e + 30, 8); /* gid */
assertEqualMem(e + 38, "00000003", 8); /* nlink */
t = from_hex(e + 46, 8); /* mtime */
failure("t=%#08jx now=%#08jx=%jd", (intmax_t)t, (intmax_t)now,
failure("t=%#08jx now=%#08jx=%jd", (uintmax_t)t, (uintmax_t)now,
(intmax_t)now);
assert(t <= now); /* File wasn't created in future. */
failure("t=%#08jx now - 2=%#08jx=%jd", (intmax_t)t, (intmax_t)now - 2,
failure("t=%#08jx now - 2=%#08jx=%jd", (uintmax_t)t, (uintmax_t)now - 2,
(intmax_t)now - 2);
assert(t >= now - 2); /* File was created w/in last 2 secs. */
failure("newc format stores body only with last appearance of a link\n"
@@ -219,7 +219,7 @@ DEFINE_TEST(test_format_newc)
assert(is_hex(e, 110));
assertEqualMem(e + 0, "070701", 6); /* Magic */
assert(is_hex(e + 6, 8)); /* ino */
#if defined(_WIN32) && !defined(CYGWIN)
#if defined(_WIN32) && !defined(__CYGWIN__)
/* Mode: Group members bits and others bits do not work. */
assertEqualInt(0xa180, from_hex(e + 14, 8) & 0xffc0);
#else
@@ -230,7 +230,7 @@ DEFINE_TEST(test_format_newc)
assertEqualMem(e + 38, "00000001", 8); /* nlink */
t2 = from_hex(e + 46, 8); /* mtime */
failure("First entry created at t=%#08jx this entry created"
" at t2=%#08jx", (intmax_t)t, (intmax_t)t2);
" at t2=%#08jx", (uintmax_t)t, (uintmax_t)t2);
assert(t2 == t || t2 == t + 1); /* Almost same as first entry. */
assertEqualMem(e + 54, "00000005", 8); /* File size */
fs = (uint64_t)from_hex(e + 54, 8);
@@ -266,7 +266,7 @@ DEFINE_TEST(test_format_newc)
#endif
t2 = from_hex(e + 46, 8); /* mtime */
failure("First entry created at t=%#08jx this entry created at"
"t2=%#08jx", (intmax_t)t, (intmax_t)t2);
"t2=%#08jx", (uintmax_t)t, (uintmax_t)t2);
assert(t2 == t || t2 == t + 1); /* Almost same as first entry. */
assertEqualMem(e + 54, "00000000", 8); /* File size */
fs = (uint64_t)from_hex(e + 54, 8);
@@ -300,7 +300,7 @@ DEFINE_TEST(test_format_newc)
assertEqualMem(e + 38, "00000003", 8); /* nlink */
t2 = from_hex(e + 46, 8); /* mtime */
failure("First entry created at t=%#08jx this entry created at"
"t2=%#08jx", (intmax_t)t, (intmax_t)t2);
"t2=%#08jx", (uintmax_t)t, (uintmax_t)t2);
assert(t2 == t || t2 == t + 1); /* Almost same as first entry. */
assertEqualInt(10, from_hex(e + 54, 8)); /* File size */
fs = (uint64_t)from_hex(e + 54, 8);
+1 -1
View File
@@ -52,7 +52,7 @@ test_create(void)
* #ifdef this section out. Most of the test below is
* still valid. */
memset(&times, 0, sizeof(times));
#if defined(_WIN32) && !defined(CYGWIN)
#if defined(_WIN32) && !defined(__CYGWIN__)
times.actime = 86400;
times.modtime = 86400;
#else
+4 -4
View File
@@ -18,7 +18,7 @@ is_octal(const char *p, size_t l)
return (1);
}
static long long int
static unsigned long long int
from_octal(const char *p, size_t l)
{
long long int r = 0;
@@ -117,7 +117,7 @@ DEFINE_TEST(test_option_c)
gid = (int)from_octal(e + 30, 6);
assertEqualMem(e + 36, "000001", 6); /* nlink */
failure("file entries should not have rdev set (dev field was 0%o)",
dev);
(unsigned int)dev);
assertEqualMem(e + 42, "000000", 6); /* rdev */
t = from_octal(e + 48, 11); /* mtime */
assert(t <= now); /* File wasn't created in future. */
@@ -133,7 +133,7 @@ DEFINE_TEST(test_option_c)
assert(is_octal(e, 76)); /* Entire header is octal digits. */
assertEqualMem(e + 0, "070707", 6); /* Magic */
assertEqualInt(dev, from_octal(e + 6, 6)); /* dev */
assert(ino != from_octal(e + 12, 6)); /* ino */
assert(ino != (int)from_octal(e + 12, 6)); /* ino */
#if !defined(_WIN32) || defined(__CYGWIN__)
/* On Windows, symbolic link and group members bits and
* others bits do not work. */
@@ -163,7 +163,7 @@ DEFINE_TEST(test_option_c)
assertEqualInt(dev, from_octal(e + 6, 6));
/* Ino must be different from first entry. */
assert(is_octal(e + 12, 6)); /* ino */
assert(ino != from_octal(e + 12, 6));
assert(ino != (int)from_octal(e + 12, 6));
#if defined(_WIN32) && !defined(__CYGWIN__)
/* Group members bits and others bits do not work. */
assertEqualMem(e + 18, "040777", 6); /* Mode */
+54 -3
View File
@@ -34,12 +34,15 @@
* assert that ARCHIVE_VERSION_NUMBER >= 2012108.
*/
/* Note: Compiler will complain if this does not match archive_entry.h! */
#define ARCHIVE_VERSION_NUMBER 3007007
#define ARCHIVE_VERSION_NUMBER 3008001
#include <sys/stat.h>
#include <stddef.h> /* for wchar_t */
#include <stdio.h> /* For FILE * */
#if ARCHIVE_VERSION_NUMBER < 4000000
/* time_t is slated to be removed from public includes in 4.0 */
#include <time.h> /* For time_t */
#endif
/*
* Note: archive.h is for use outside of libarchive; the configuration
@@ -63,12 +66,15 @@
#define __LA_INT64_T_DEFINED
# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__)
typedef __int64 la_int64_t;
typedef unsigned __int64 la_uint64_t;
# else
# include <unistd.h> /* ssize_t */
# if defined(_SCO_DS) || defined(__osf__)
typedef long long la_int64_t;
typedef unsigned long long la_uint64_t;
# else
typedef int64_t la_int64_t;
typedef uint64_t la_uint64_t;
# endif
# endif
#endif
@@ -94,6 +100,22 @@ typedef ssize_t la_ssize_t;
# endif
#endif
#if ARCHIVE_VERSION_NUMBER < 4000000
/* Use the platform types for time_t */
#define __LA_TIME_T time_t
#else
/* Use 64-bits integer types for time_t */
#define __LA_TIME_T la_int64_t
#endif
#if ARCHIVE_VERSION_NUMBER < 4000000
/* Use the platform types for dev_t */
#define __LA_DEV_T dev_t
#else
/* Use 64-bits integer types for dev_t */
#define __LA_DEV_T la_int64_t
#endif
/* Large file support for Android */
#if defined(__LIBARCHIVE_BUILD) && defined(__ANDROID__)
#include "android_lf.h"
@@ -132,7 +154,7 @@ typedef ssize_t la_ssize_t;
#define __LA_PRINTF(fmtarg, firstvararg) /* nothing */
#endif
#if defined(__GNUC__) && __GNUC__ >= 3 && __GNUC_MINOR__ >= 1
#if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
# define __LA_DEPRECATED __attribute__((deprecated))
#else
# define __LA_DEPRECATED
@@ -155,7 +177,7 @@ __LA_DECL int archive_version_number(void);
/*
* Textual name/version of the library, useful for version displays.
*/
#define ARCHIVE_VERSION_ONLY_STRING "3.7.7"
#define ARCHIVE_VERSION_ONLY_STRING "3.8.1"
#define ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING
__LA_DECL const char * archive_version_string(void);
@@ -178,6 +200,23 @@ __LA_DECL const char * archive_liblzma_version(void);
__LA_DECL const char * archive_bzlib_version(void);
__LA_DECL const char * archive_liblz4_version(void);
__LA_DECL const char * archive_libzstd_version(void);
__LA_DECL const char * archive_liblzo2_version(void);
__LA_DECL const char * archive_libexpat_version(void);
__LA_DECL const char * archive_libbsdxml_version(void);
__LA_DECL const char * archive_libxml2_version(void);
__LA_DECL const char * archive_mbedtls_version(void);
__LA_DECL const char * archive_nettle_version(void);
__LA_DECL const char * archive_openssl_version(void);
__LA_DECL const char * archive_libmd_version(void);
__LA_DECL const char * archive_commoncrypto_version(void);
__LA_DECL const char * archive_cng_version(void);
__LA_DECL const char * archive_wincrypt_version(void);
__LA_DECL const char * archive_librichacl_version(void);
__LA_DECL const char * archive_libacl_version(void);
__LA_DECL const char * archive_libattr_version(void);
__LA_DECL const char * archive_libiconv_version(void);
__LA_DECL const char * archive_libpcre_version(void);
__LA_DECL const char * archive_libpcre2_version(void);
/* Declare our basic types. */
struct archive;
@@ -449,6 +488,8 @@ __LA_DECL int archive_read_support_format_by_code(struct archive *, int);
__LA_DECL int archive_read_support_format_cab(struct archive *);
__LA_DECL int archive_read_support_format_cpio(struct archive *);
__LA_DECL int archive_read_support_format_empty(struct archive *);
/* archive_read_support_format_gnutar() is an alias for historical reasons
* of archive_read_support_format_tar(). */
__LA_DECL int archive_read_support_format_gnutar(struct archive *);
__LA_DECL int archive_read_support_format_iso9660(struct archive *);
__LA_DECL int archive_read_support_format_lha(struct archive *);
@@ -828,6 +869,10 @@ __LA_DECL int archive_write_set_format_filter_by_ext(struct archive *a, const ch
__LA_DECL int archive_write_set_format_filter_by_ext_def(struct archive *a, const char *filename, const char * def_ext);
__LA_DECL int archive_write_zip_set_compression_deflate(struct archive *);
__LA_DECL int archive_write_zip_set_compression_store(struct archive *);
__LA_DECL int archive_write_zip_set_compression_lzma(struct archive *);
__LA_DECL int archive_write_zip_set_compression_xz(struct archive *);
__LA_DECL int archive_write_zip_set_compression_bzip2(struct archive *);
__LA_DECL int archive_write_zip_set_compression_zstd(struct archive *);
/* Deprecated; use archive_write_open2 instead */
__LA_DECL int archive_write_open(struct archive *, void *,
archive_open_callback *, archive_write_callback *,
@@ -1083,6 +1128,10 @@ __LA_DECL int archive_compression(struct archive *)
__LA_DEPRECATED;
#endif
/* Parses a date string relative to the current time.
* NOTE: This is not intended for general date parsing, and the resulting timestamp should only be used for libarchive. */
__LA_DECL time_t archive_parse_date(time_t now, const char *datestr);
__LA_DECL int archive_errno(struct archive *);
__LA_DECL const char *archive_error_string(struct archive *);
__LA_DECL const char *archive_format_name(struct archive *);
@@ -1201,8 +1250,10 @@ __LA_DECL int archive_match_include_gname_w(struct archive *,
const wchar_t *);
/* Utility functions */
#if ARCHIVE_VERSION_NUMBER < 4000000
/* Convenience function to sort a NULL terminated list of strings */
__LA_DECL int archive_utility_string_sort(char **);
#endif
#ifdef __cplusplus
}
+12 -2
View File
@@ -1185,8 +1185,13 @@ archive_acl_from_text_w(struct archive_acl *acl, const wchar_t *text,
/* Set remaining fields to blank. */
for (n = fields; n < numfields; ++n)
field[n].start = field[n].end = NULL;
if (field[0].start == NULL || field[0].end == NULL) {
/* This should never happen */
return (ARCHIVE_FATAL);
}
if (field[0].start != NULL && *(field[0].start) == L'#') {
if (*(field[0].start) == L'#') {
/* Comment, skip entry */
continue;
}
@@ -1676,7 +1681,12 @@ archive_acl_from_text_nl(struct archive_acl *acl, const char *text,
for (n = fields; n < numfields; ++n)
field[n].start = field[n].end = NULL;
if (field[0].start != NULL && *(field[0].start) == '#') {
if (field[0].start == NULL || field[0].end == NULL) {
/* This should never happen */
return (ARCHIVE_FATAL);
}
if (*(field[0].start) == '#') {
/* Comment, skip entry */
continue;
}
@@ -80,4 +80,4 @@ int archive_acl_from_text_l(struct archive_acl *, const char * /* text */,
int archive_acl_from_text_nl(struct archive_acl *, const char * /* text */,
size_t /* size of text */, int /* type */, struct archive_string_conv *);
#endif /* ARCHIVE_ENTRY_PRIVATE_H_INCLUDED */
#endif /* !ARCHIVE_ACL_PRIVATE_H_INCLUDED */
@@ -71,7 +71,7 @@ get_argument(struct archive_string *as, const char *p)
archive_string_empty(as);
/* Skip beginning space characters. */
while (*s != '\0' && *s == ' ')
while (*s == ' ')
s++;
/* Copy non-space characters. */
while (*s != '\0' && *s != ' ') {
@@ -64,6 +64,7 @@ typedef struct {
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
#include <bcrypt.h>
#define ARCHIVE_CRYPTOR_USE_CNG 1
/* Common in other bcrypt implementations, but missing from VS2008. */
#ifndef BCRYPT_SUCCESS
@@ -86,6 +87,7 @@ typedef struct {
#include <mbedtls/aes.h>
#include <mbedtls/md.h>
#include <mbedtls/pkcs5.h>
#define ARCHIVE_CRYPTOR_USE_MBED 1
#define AES_MAX_KEY_SIZE 32
#define AES_BLOCK_SIZE 16
@@ -105,6 +107,7 @@ typedef struct {
#endif
#include <nettle/aes.h>
#include <nettle/version.h>
#define ARCHIVE_CRYPTOR_USE_NETTLE 1
typedef struct {
#if NETTLE_VERSION_MAJOR < 3
@@ -125,6 +128,7 @@ typedef struct {
#elif defined(HAVE_LIBCRYPTO)
#include "archive_openssl_evp_private.h"
#define ARCHIVE_CRYPTOR_USE_OPENSSL 1
#define AES_BLOCK_SIZE 16
#define AES_MAX_KEY_SIZE 32
@@ -140,6 +144,10 @@ typedef struct {
#else
#if defined(_WIN32) && !defined(__CYGWIN__) && !(defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA)
#define ARCHIVE_CRYPTOR_USE_WINCRYPT 1
#endif
#define AES_BLOCK_SIZE 16
#define AES_MAX_KEY_SIZE 32
typedef int archive_crypto_ctx;
+214 -130
View File
@@ -196,6 +196,13 @@ __archive_md5final(archive_md5_ctx *ctx, void *md)
#elif defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM)
// These functions are available in macOS 10.4 and later, but deprecated from 10.15 onwards.
// We need to continue supporting this feature regardless, so suppress the warnings.
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
static int
__archive_md5init(archive_md5_ctx *ctx)
{
@@ -218,13 +225,46 @@ __archive_md5final(archive_md5_ctx *ctx, void *md)
return (ARCHIVE_OK);
}
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
#elif defined(ARCHIVE_CRYPTO_MD5_WIN)
static int
__archive_md5init(archive_md5_ctx *ctx)
{
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
return (win_crypto_init(ctx, BCRYPT_MD5_ALGORITHM));
#else
return (win_crypto_init(ctx, PROV_RSA_FULL, CALG_MD5));
#endif
}
static int
__archive_md5update(archive_md5_ctx *ctx, const void *indata,
size_t insize)
{
return (win_crypto_Update(ctx, indata, insize));
}
static int
__archive_md5final(archive_md5_ctx *ctx, void *md)
{
return (win_crypto_Final(md, 16, ctx));
}
#elif defined(ARCHIVE_CRYPTO_MD5_MBEDTLS)
static int
__archive_md5init(archive_md5_ctx *ctx)
{
mbedtls_md5_init(ctx);
#if MBEDTLS_VERSION_NUMBER > 0x03000000
if (mbedtls_md5_starts(ctx) == 0)
#else
if (mbedtls_md5_starts_ret(ctx) == 0)
#endif
return (ARCHIVE_OK);
else
return (ARCHIVE_FATAL);
@@ -234,7 +274,11 @@ static int
__archive_md5update(archive_md5_ctx *ctx, const void *indata,
size_t insize)
{
#if MBEDTLS_VERSION_NUMBER > 0x03000000
if (mbedtls_md5_update(ctx, indata, insize) == 0)
#else
if (mbedtls_md5_update_ret(ctx, indata, insize) == 0)
#endif
return (ARCHIVE_OK);
else
return (ARCHIVE_FATAL);
@@ -243,7 +287,11 @@ __archive_md5update(archive_md5_ctx *ctx, const void *indata,
static int
__archive_md5final(archive_md5_ctx *ctx, void *md)
{
#if MBEDTLS_VERSION_NUMBER > 0x03000000
if (mbedtls_md5_finish(ctx, md) == 0) {
#else
if (mbedtls_md5_finish_ret(ctx, md) == 0) {
#endif
mbedtls_md5_free(ctx);
return (ARCHIVE_OK);
} else {
@@ -311,31 +359,6 @@ __archive_md5final(archive_md5_ctx *ctx, void *md)
return (ARCHIVE_OK);
}
#elif defined(ARCHIVE_CRYPTO_MD5_WIN)
static int
__archive_md5init(archive_md5_ctx *ctx)
{
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
return (win_crypto_init(ctx, BCRYPT_MD5_ALGORITHM));
#else
return (win_crypto_init(ctx, PROV_RSA_FULL, CALG_MD5));
#endif
}
static int
__archive_md5update(archive_md5_ctx *ctx, const void *indata,
size_t insize)
{
return (win_crypto_Update(ctx, indata, insize));
}
static int
__archive_md5final(archive_md5_ctx *ctx, void *md)
{
return (win_crypto_Final(md, 16, ctx));
}
#else
static int
@@ -420,7 +443,11 @@ static int
__archive_ripemd160init(archive_rmd160_ctx *ctx)
{
mbedtls_ripemd160_init(ctx);
#if MBEDTLS_VERSION_NUMBER > 0x03000000
if (mbedtls_ripemd160_starts(ctx) == 0)
#else
if (mbedtls_ripemd160_starts_ret(ctx) == 0)
#endif
return (ARCHIVE_OK);
else
return (ARCHIVE_FATAL);
@@ -430,7 +457,11 @@ static int
__archive_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
size_t insize)
{
#if MBEDTLS_VERSION_NUMBER > 0x03000000
if (mbedtls_ripemd160_update(ctx, indata, insize) == 0)
#else
if (mbedtls_ripemd160_update_ret(ctx, indata, insize) == 0)
#endif
return (ARCHIVE_OK);
else
return (ARCHIVE_FATAL);
@@ -439,7 +470,11 @@ __archive_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
static int
__archive_ripemd160final(archive_rmd160_ctx *ctx, void *md)
{
#if MBEDTLS_VERSION_NUMBER > 0x03000000
if (mbedtls_ripemd160_finish(ctx, md) == 0) {
#else
if (mbedtls_ripemd160_finish_ret(ctx, md) == 0) {
#endif
mbedtls_ripemd160_free(ctx);
return (ARCHIVE_OK);
} else {
@@ -605,13 +640,42 @@ __archive_sha1final(archive_sha1_ctx *ctx, void *md)
return (ARCHIVE_OK);
}
#elif defined(ARCHIVE_CRYPTO_SHA1_WIN)
static int
__archive_sha1init(archive_sha1_ctx *ctx)
{
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
return (win_crypto_init(ctx, BCRYPT_SHA1_ALGORITHM));
#else
return (win_crypto_init(ctx, PROV_RSA_FULL, CALG_SHA1));
#endif
}
static int
__archive_sha1update(archive_sha1_ctx *ctx, const void *indata,
size_t insize)
{
return (win_crypto_Update(ctx, indata, insize));
}
static int
__archive_sha1final(archive_sha1_ctx *ctx, void *md)
{
return (win_crypto_Final(md, 20, ctx));
}
#elif defined(ARCHIVE_CRYPTO_SHA1_MBEDTLS)
static int
__archive_sha1init(archive_sha1_ctx *ctx)
{
mbedtls_sha1_init(ctx);
#if MBEDTLS_VERSION_NUMBER > 0x03000000
if (mbedtls_sha1_starts(ctx) == 0)
#else
if (mbedtls_sha1_starts_ret(ctx) == 0)
#endif
return (ARCHIVE_OK);
else
return (ARCHIVE_FATAL);
@@ -621,7 +685,11 @@ static int
__archive_sha1update(archive_sha1_ctx *ctx, const void *indata,
size_t insize)
{
#if MBEDTLS_VERSION_NUMBER > 0x03000000
if (mbedtls_sha1_update(ctx, indata, insize) == 0)
#else
if (mbedtls_sha1_update_ret(ctx, indata, insize) == 0)
#endif
return (ARCHIVE_OK);
else
return (ARCHIVE_FATAL);
@@ -630,7 +698,11 @@ __archive_sha1update(archive_sha1_ctx *ctx, const void *indata,
static int
__archive_sha1final(archive_sha1_ctx *ctx, void *md)
{
#if MBEDTLS_VERSION_NUMBER > 0x03000000
if (mbedtls_sha1_finish(ctx, md) == 0) {
#else
if (mbedtls_sha1_finish_ret(ctx, md) == 0) {
#endif
mbedtls_sha1_free(ctx);
return (ARCHIVE_OK);
} else {
@@ -698,31 +770,6 @@ __archive_sha1final(archive_sha1_ctx *ctx, void *md)
return (ARCHIVE_OK);
}
#elif defined(ARCHIVE_CRYPTO_SHA1_WIN)
static int
__archive_sha1init(archive_sha1_ctx *ctx)
{
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
return (win_crypto_init(ctx, BCRYPT_SHA1_ALGORITHM));
#else
return (win_crypto_init(ctx, PROV_RSA_FULL, CALG_SHA1));
#endif
}
static int
__archive_sha1update(archive_sha1_ctx *ctx, const void *indata,
size_t insize)
{
return (win_crypto_Update(ctx, indata, insize));
}
static int
__archive_sha1final(archive_sha1_ctx *ctx, void *md)
{
return (win_crypto_Final(md, 20, ctx));
}
#else
static int
@@ -873,13 +920,42 @@ __archive_sha256final(archive_sha256_ctx *ctx, void *md)
return (ARCHIVE_OK);
}
#elif defined(ARCHIVE_CRYPTO_SHA256_WIN)
static int
__archive_sha256init(archive_sha256_ctx *ctx)
{
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
return (win_crypto_init(ctx, BCRYPT_SHA256_ALGORITHM));
#else
return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_256));
#endif
}
static int
__archive_sha256update(archive_sha256_ctx *ctx, const void *indata,
size_t insize)
{
return (win_crypto_Update(ctx, indata, insize));
}
static int
__archive_sha256final(archive_sha256_ctx *ctx, void *md)
{
return (win_crypto_Final(md, 32, ctx));
}
#elif defined(ARCHIVE_CRYPTO_SHA256_MBEDTLS)
static int
__archive_sha256init(archive_sha256_ctx *ctx)
{
mbedtls_sha256_init(ctx);
#if MBEDTLS_VERSION_NUMBER > 0x03000000
if (mbedtls_sha256_starts(ctx, 0) == 0)
#else
if (mbedtls_sha256_starts_ret(ctx, 0) == 0)
#endif
return (ARCHIVE_OK);
else
return (ARCHIVE_FATAL);
@@ -889,7 +965,11 @@ static int
__archive_sha256update(archive_sha256_ctx *ctx, const void *indata,
size_t insize)
{
#if MBEDTLS_VERSION_NUMBER > 0x03000000
if (mbedtls_sha256_update(ctx, indata, insize) == 0)
#else
if (mbedtls_sha256_update_ret(ctx, indata, insize) == 0)
#endif
return (ARCHIVE_OK);
else
return (ARCHIVE_FATAL);
@@ -898,7 +978,11 @@ __archive_sha256update(archive_sha256_ctx *ctx, const void *indata,
static int
__archive_sha256final(archive_sha256_ctx *ctx, void *md)
{
#if MBEDTLS_VERSION_NUMBER > 0x03000000
if (mbedtls_sha256_finish(ctx, md) == 0) {
#else
if (mbedtls_sha256_finish_ret(ctx, md) == 0) {
#endif
mbedtls_sha256_free(ctx);
return (ARCHIVE_OK);
} else {
@@ -962,31 +1046,6 @@ __archive_sha256final(archive_sha256_ctx *ctx, void *md)
return (ARCHIVE_OK);
}
#elif defined(ARCHIVE_CRYPTO_SHA256_WIN)
static int
__archive_sha256init(archive_sha256_ctx *ctx)
{
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
return (win_crypto_init(ctx, BCRYPT_SHA256_ALGORITHM));
#else
return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_256));
#endif
}
static int
__archive_sha256update(archive_sha256_ctx *ctx, const void *indata,
size_t insize)
{
return (win_crypto_Update(ctx, indata, insize));
}
static int
__archive_sha256final(archive_sha256_ctx *ctx, void *md)
{
return (win_crypto_Final(md, 32, ctx));
}
#else
static int
@@ -1113,13 +1172,42 @@ __archive_sha384final(archive_sha384_ctx *ctx, void *md)
return (ARCHIVE_OK);
}
#elif defined(ARCHIVE_CRYPTO_SHA384_WIN)
static int
__archive_sha384init(archive_sha384_ctx *ctx)
{
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
return (win_crypto_init(ctx, BCRYPT_SHA384_ALGORITHM));
#else
return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_384));
#endif
}
static int
__archive_sha384update(archive_sha384_ctx *ctx, const void *indata,
size_t insize)
{
return (win_crypto_Update(ctx, indata, insize));
}
static int
__archive_sha384final(archive_sha384_ctx *ctx, void *md)
{
return (win_crypto_Final(md, 48, ctx));
}
#elif defined(ARCHIVE_CRYPTO_SHA384_MBEDTLS)
static int
__archive_sha384init(archive_sha384_ctx *ctx)
{
mbedtls_sha512_init(ctx);
#if MBEDTLS_VERSION_NUMBER > 0x03000000
if (mbedtls_sha512_starts(ctx, 1) == 0)
#else
if (mbedtls_sha512_starts_ret(ctx, 1) == 0)
#endif
return (ARCHIVE_OK);
else
return (ARCHIVE_FATAL);
@@ -1129,7 +1217,11 @@ static int
__archive_sha384update(archive_sha384_ctx *ctx, const void *indata,
size_t insize)
{
#if MBEDTLS_VERSION_NUMBER > 0x03000000
if (mbedtls_sha512_update(ctx, indata, insize) == 0)
#else
if (mbedtls_sha512_update_ret(ctx, indata, insize) == 0)
#endif
return (ARCHIVE_OK);
else
return (ARCHIVE_FATAL);
@@ -1138,7 +1230,11 @@ __archive_sha384update(archive_sha384_ctx *ctx, const void *indata,
static int
__archive_sha384final(archive_sha384_ctx *ctx, void *md)
{
#if MBEDTLS_VERSION_NUMBER > 0x03000000
if (mbedtls_sha512_finish(ctx, md) == 0) {
#else
if (mbedtls_sha512_finish_ret(ctx, md) == 0) {
#endif
mbedtls_sha512_free(ctx);
return (ARCHIVE_OK);
} else {
@@ -1202,31 +1298,6 @@ __archive_sha384final(archive_sha384_ctx *ctx, void *md)
return (ARCHIVE_OK);
}
#elif defined(ARCHIVE_CRYPTO_SHA384_WIN)
static int
__archive_sha384init(archive_sha384_ctx *ctx)
{
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
return (win_crypto_init(ctx, BCRYPT_SHA384_ALGORITHM));
#else
return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_384));
#endif
}
static int
__archive_sha384update(archive_sha384_ctx *ctx, const void *indata,
size_t insize)
{
return (win_crypto_Update(ctx, indata, insize));
}
static int
__archive_sha384final(archive_sha384_ctx *ctx, void *md)
{
return (win_crypto_Final(md, 48, ctx));
}
#else
static int
@@ -1377,13 +1448,42 @@ __archive_sha512final(archive_sha512_ctx *ctx, void *md)
return (ARCHIVE_OK);
}
#elif defined(ARCHIVE_CRYPTO_SHA512_WIN)
static int
__archive_sha512init(archive_sha512_ctx *ctx)
{
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
return (win_crypto_init(ctx, BCRYPT_SHA512_ALGORITHM));
#else
return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_512));
#endif
}
static int
__archive_sha512update(archive_sha512_ctx *ctx, const void *indata,
size_t insize)
{
return (win_crypto_Update(ctx, indata, insize));
}
static int
__archive_sha512final(archive_sha512_ctx *ctx, void *md)
{
return (win_crypto_Final(md, 64, ctx));
}
#elif defined(ARCHIVE_CRYPTO_SHA512_MBEDTLS)
static int
__archive_sha512init(archive_sha512_ctx *ctx)
{
mbedtls_sha512_init(ctx);
#if MBEDTLS_VERSION_NUMBER > 0x03000000
if (mbedtls_sha512_starts(ctx, 0) == 0)
#else
if (mbedtls_sha512_starts_ret(ctx, 0) == 0)
#endif
return (ARCHIVE_OK);
else
return (ARCHIVE_FATAL);
@@ -1393,7 +1493,11 @@ static int
__archive_sha512update(archive_sha512_ctx *ctx, const void *indata,
size_t insize)
{
#if MBEDTLS_VERSION_NUMBER > 0x03000000
if (mbedtls_sha512_update(ctx, indata, insize) == 0)
#else
if (mbedtls_sha512_update_ret(ctx, indata, insize) == 0)
#endif
return (ARCHIVE_OK);
else
return (ARCHIVE_FATAL);
@@ -1402,7 +1506,11 @@ __archive_sha512update(archive_sha512_ctx *ctx, const void *indata,
static int
__archive_sha512final(archive_sha512_ctx *ctx, void *md)
{
#if MBEDTLS_VERSION_NUMBER > 0x03000000
if (mbedtls_sha512_finish(ctx, md) == 0) {
#else
if (mbedtls_sha512_finish_ret(ctx, md) == 0) {
#endif
mbedtls_sha512_free(ctx);
return (ARCHIVE_OK);
} else {
@@ -1466,31 +1574,6 @@ __archive_sha512final(archive_sha512_ctx *ctx, void *md)
return (ARCHIVE_OK);
}
#elif defined(ARCHIVE_CRYPTO_SHA512_WIN)
static int
__archive_sha512init(archive_sha512_ctx *ctx)
{
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
return (win_crypto_init(ctx, BCRYPT_SHA512_ALGORITHM));
#else
return (win_crypto_init(ctx, PROV_RSA_AES, CALG_SHA_512));
#endif
}
static int
__archive_sha512update(archive_sha512_ctx *ctx, const void *indata,
size_t insize)
{
return (win_crypto_Update(ctx, indata, insize));
}
static int
__archive_sha512final(archive_sha512_ctx *ctx, void *md)
{
return (win_crypto_Final(md, 64, ctx));
}
#else
static int
@@ -1525,11 +1608,12 @@ __archive_sha512final(archive_sha512_ctx *ctx, void *md)
* 1. libc
* 2. libc2
* 3. libc3
* 4. libSystem
* 5. Nettle
* 6. OpenSSL
* 7. libmd
* 8. Windows API
* 4. libmd
* 5. libSystem
* 6. Windows API
* 7. mbedTLS
* 8. Nettle
* 9. OpenSSL
*/
const struct archive_digest __archive_digest =
{
@@ -113,6 +113,7 @@
defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM) ||\
defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM)
#include <CommonCrypto/CommonDigest.h>
#define ARCHIVE_CRYPTO_CommonCrypto 1
#endif
/* mbed TLS crypto headers */
@@ -167,6 +168,7 @@
#if defined(HAVE_BCRYPT_H) && _WIN32_WINNT >= _WIN32_WINNT_VISTA
/* don't use bcrypt when XP needs to be supported */
#include <bcrypt.h>
#define ARCHIVE_CRYPTO_CNG 1
typedef struct {
int valid;
BCRYPT_ALG_HANDLE hAlg;
@@ -175,6 +177,7 @@ typedef struct {
#else
#include <windows.h>
#include <wincrypt.h>
#define ARCHIVE_CRYPTO_WINCRYPT 1
typedef struct {
int valid;
HCRYPTPROV cryptProv;
@@ -190,14 +193,16 @@ typedef MD5_CTX archive_md5_ctx;
typedef MD5_CTX archive_md5_ctx;
#elif defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM)
typedef CC_MD5_CTX archive_md5_ctx;
#elif defined(ARCHIVE_CRYPTO_MD5_WIN)
typedef Digest_CTX archive_md5_ctx;
#elif defined(ARCHIVE_CRYPTO_MD5_MBEDTLS)
#define ARCHIVE_CRYPTO_MBED 1
typedef mbedtls_md5_context archive_md5_ctx;
#elif defined(ARCHIVE_CRYPTO_MD5_NETTLE)
#define ARCHIVE_CRYPTO_NETTLE 1
typedef struct md5_ctx archive_md5_ctx;
#elif defined(ARCHIVE_CRYPTO_MD5_OPENSSL)
typedef EVP_MD_CTX *archive_md5_ctx;
#elif defined(ARCHIVE_CRYPTO_MD5_WIN)
typedef Digest_CTX archive_md5_ctx;
#else
typedef unsigned char archive_md5_ctx;
#endif
@@ -207,8 +212,10 @@ typedef RMD160_CTX archive_rmd160_ctx;
#elif defined(ARCHIVE_CRYPTO_RMD160_LIBMD)
typedef RIPEMD160_CTX archive_rmd160_ctx;
#elif defined(ARCHIVE_CRYPTO_RMD160_MBEDTLS)
#define ARCHIVE_CRYPTO_MBED 1
typedef mbedtls_ripemd160_context archive_rmd160_ctx;
#elif defined(ARCHIVE_CRYPTO_RMD160_NETTLE)
#define ARCHIVE_CRYPTO_NETTLE 1
typedef struct ripemd160_ctx archive_rmd160_ctx;
#elif defined(ARCHIVE_CRYPTO_RMD160_OPENSSL)
typedef EVP_MD_CTX *archive_rmd160_ctx;
@@ -222,14 +229,16 @@ typedef SHA1_CTX archive_sha1_ctx;
typedef SHA1_CTX archive_sha1_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM)
typedef CC_SHA1_CTX archive_sha1_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA1_WIN)
typedef Digest_CTX archive_sha1_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA1_MBEDTLS)
#define ARCHIVE_CRYPTO_MBED 1
typedef mbedtls_sha1_context archive_sha1_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA1_NETTLE)
#define ARCHIVE_CRYPTO_NETTLE 1
typedef struct sha1_ctx archive_sha1_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA1_OPENSSL)
typedef EVP_MD_CTX *archive_sha1_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA1_WIN)
typedef Digest_CTX archive_sha1_ctx;
#else
typedef unsigned char archive_sha1_ctx;
#endif
@@ -244,14 +253,16 @@ typedef SHA2_CTX archive_sha256_ctx;
typedef SHA256_CTX archive_sha256_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM)
typedef CC_SHA256_CTX archive_sha256_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA256_WIN)
typedef Digest_CTX archive_sha256_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA256_MBEDTLS)
#define ARCHIVE_CRYPTO_MBED 1
typedef mbedtls_sha256_context archive_sha256_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA256_NETTLE)
#define ARCHIVE_CRYPTO_NETTLE 1
typedef struct sha256_ctx archive_sha256_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA256_OPENSSL)
typedef EVP_MD_CTX *archive_sha256_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA256_WIN)
typedef Digest_CTX archive_sha256_ctx;
#else
typedef unsigned char archive_sha256_ctx;
#endif
@@ -264,14 +275,16 @@ typedef SHA384_CTX archive_sha384_ctx;
typedef SHA2_CTX archive_sha384_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM)
typedef CC_SHA512_CTX archive_sha384_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA384_WIN)
typedef Digest_CTX archive_sha384_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA384_MBEDTLS)
#define ARCHIVE_CRYPTO_MBED 1
typedef mbedtls_sha512_context archive_sha384_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA384_NETTLE)
#define ARCHIVE_CRYPTO_NETTLE 1
typedef struct sha384_ctx archive_sha384_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA384_OPENSSL)
typedef EVP_MD_CTX *archive_sha384_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA384_WIN)
typedef Digest_CTX archive_sha384_ctx;
#else
typedef unsigned char archive_sha384_ctx;
#endif
@@ -286,14 +299,16 @@ typedef SHA2_CTX archive_sha512_ctx;
typedef SHA512_CTX archive_sha512_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM)
typedef CC_SHA512_CTX archive_sha512_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA512_WIN)
typedef Digest_CTX archive_sha512_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA512_MBEDTLS)
#define ARCHIVE_CRYPTO_MBED 1
typedef mbedtls_sha512_context archive_sha512_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA512_NETTLE)
#define ARCHIVE_CRYPTO_NETTLE 1
typedef struct sha512_ctx archive_sha512_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA512_OPENSSL)
typedef EVP_MD_CTX *archive_sha512_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA512_WIN)
typedef Digest_CTX archive_sha512_ctx;
#else
typedef unsigned char archive_sha512_ctx;
#endif
@@ -262,7 +262,7 @@ translate_acl(struct archive_read_disk *a,
}
for (i = 0; i < acl_nfs4_flag_map_size; ++i) {
r = acl_get_flag_np(acl_flagset,
acl_nfs4_flag_map[i].p_perm);
(acl_flag_t)acl_nfs4_flag_map[i].p_perm);
if (r == -1) {
archive_set_error(&a->archive, errno,
"Failed to check flag in a NFSv4 "
@@ -517,7 +517,7 @@ set_acl(struct archive *a, int fd, const char *name,
for (i = 0; i < acl_nfs4_flag_map_size; ++i) {
if (ae_permset & acl_nfs4_flag_map[i].a_perm) {
if (acl_add_flag_np(acl_flagset,
acl_nfs4_flag_map[i].p_perm) != 0) {
(acl_flag_t)acl_nfs4_flag_map[i].p_perm) != 0) {
archive_set_error(a, errno,
"Failed to add flag to "
"NFSv4 ACL flagset");
+32 -22
View File
@@ -275,7 +275,7 @@ archive_entry_new2(struct archive *a)
* Functions for reading fields from an archive_entry.
*/
time_t
__LA_TIME_T
archive_entry_atime(struct archive_entry *entry)
{
return (entry->ae_stat.aest_atime);
@@ -293,7 +293,7 @@ archive_entry_atime_is_set(struct archive_entry *entry)
return (entry->ae_set & AE_SET_ATIME);
}
time_t
__LA_TIME_T
archive_entry_birthtime(struct archive_entry *entry)
{
return (entry->ae_stat.aest_birthtime);
@@ -311,7 +311,7 @@ archive_entry_birthtime_is_set(struct archive_entry *entry)
return (entry->ae_set & AE_SET_BIRTHTIME);
}
time_t
__LA_TIME_T
archive_entry_ctime(struct archive_entry *entry)
{
return (entry->ae_stat.aest_ctime);
@@ -329,7 +329,7 @@ archive_entry_ctime_nsec(struct archive_entry *entry)
return (entry->ae_stat.aest_ctime_nsec);
}
dev_t
__LA_DEV_T
archive_entry_dev(struct archive_entry *entry)
{
if (entry->ae_stat.aest_dev_is_broken_down)
@@ -345,7 +345,7 @@ archive_entry_dev_is_set(struct archive_entry *entry)
return (entry->ae_set & AE_SET_DEV);
}
dev_t
__LA_DEV_T
archive_entry_devmajor(struct archive_entry *entry)
{
if (entry->ae_stat.aest_dev_is_broken_down)
@@ -354,7 +354,7 @@ archive_entry_devmajor(struct archive_entry *entry)
return major(entry->ae_stat.aest_dev);
}
dev_t
__LA_DEV_T
archive_entry_devminor(struct archive_entry *entry)
{
if (entry->ae_stat.aest_dev_is_broken_down)
@@ -568,7 +568,7 @@ archive_entry_mode(struct archive_entry *entry)
return (entry->acl.mode);
}
time_t
__LA_TIME_T
archive_entry_mtime(struct archive_entry *entry)
{
return (entry->ae_stat.aest_mtime);
@@ -667,7 +667,7 @@ archive_entry_rdev_is_set(struct archive_entry *entry)
return (entry->ae_set & AE_SET_RDEV);
}
dev_t
__LA_DEV_T
archive_entry_rdev(struct archive_entry *entry)
{
if (archive_entry_rdev_is_set(entry)) {
@@ -681,7 +681,7 @@ archive_entry_rdev(struct archive_entry *entry)
}
}
dev_t
__LA_DEV_T
archive_entry_rdevmajor(struct archive_entry *entry)
{
if (archive_entry_rdev_is_set(entry)) {
@@ -694,7 +694,7 @@ archive_entry_rdevmajor(struct archive_entry *entry)
}
}
dev_t
__LA_DEV_T
archive_entry_rdevminor(struct archive_entry *entry)
{
if (archive_entry_rdev_is_set(entry)) {
@@ -984,7 +984,9 @@ void
archive_entry_set_ino(struct archive_entry *entry, la_int64_t ino)
{
if (ino < 0) {
ino = 0;
entry->stat_valid = 0;
entry->ae_set &= ~AE_SET_INO;
return;
}
entry->stat_valid = 0;
entry->ae_set |= AE_SET_INO;
@@ -995,7 +997,9 @@ void
archive_entry_set_ino64(struct archive_entry *entry, la_int64_t ino)
{
if (ino < 0) {
ino = 0;
entry->stat_valid = 0;
entry->ae_set &= ~AE_SET_INO;
return;
}
entry->stat_valid = 0;
entry->ae_set |= AE_SET_INO;
@@ -1088,7 +1092,7 @@ _archive_entry_copy_hardlink_l(struct archive_entry *entry,
}
void
archive_entry_set_atime(struct archive_entry *entry, time_t t, long ns)
archive_entry_set_atime(struct archive_entry *entry, __LA_TIME_T t, long ns)
{
FIX_NS(t, ns);
entry->stat_valid = 0;
@@ -1105,7 +1109,7 @@ archive_entry_unset_atime(struct archive_entry *entry)
}
void
archive_entry_set_birthtime(struct archive_entry *entry, time_t t, long ns)
archive_entry_set_birthtime(struct archive_entry *entry, __LA_TIME_T t, long ns)
{
FIX_NS(t, ns);
entry->stat_valid = 0;
@@ -1122,7 +1126,7 @@ archive_entry_unset_birthtime(struct archive_entry *entry)
}
void
archive_entry_set_ctime(struct archive_entry *entry, time_t t, long ns)
archive_entry_set_ctime(struct archive_entry *entry, __LA_TIME_T t, long ns)
{
FIX_NS(t, ns);
entry->stat_valid = 0;
@@ -1139,7 +1143,7 @@ archive_entry_unset_ctime(struct archive_entry *entry)
}
void
archive_entry_set_dev(struct archive_entry *entry, dev_t d)
archive_entry_set_dev(struct archive_entry *entry, __LA_DEV_T d)
{
entry->stat_valid = 0;
entry->ae_set |= AE_SET_DEV;
@@ -1148,7 +1152,7 @@ archive_entry_set_dev(struct archive_entry *entry, dev_t d)
}
void
archive_entry_set_devmajor(struct archive_entry *entry, dev_t m)
archive_entry_set_devmajor(struct archive_entry *entry, __LA_DEV_T m)
{
entry->stat_valid = 0;
entry->ae_set |= AE_SET_DEV;
@@ -1157,7 +1161,7 @@ archive_entry_set_devmajor(struct archive_entry *entry, dev_t m)
}
void
archive_entry_set_devminor(struct archive_entry *entry, dev_t m)
archive_entry_set_devminor(struct archive_entry *entry, __LA_DEV_T m)
{
entry->stat_valid = 0;
entry->ae_set |= AE_SET_DEV;
@@ -1243,7 +1247,7 @@ archive_entry_set_mode(struct archive_entry *entry, mode_t m)
}
void
archive_entry_set_mtime(struct archive_entry *entry, time_t t, long ns)
archive_entry_set_mtime(struct archive_entry *entry, __LA_TIME_T t, long ns)
{
FIX_NS(t, ns);
entry->stat_valid = 0;
@@ -1319,7 +1323,7 @@ archive_entry_set_perm(struct archive_entry *entry, mode_t p)
}
void
archive_entry_set_rdev(struct archive_entry *entry, dev_t m)
archive_entry_set_rdev(struct archive_entry *entry, __LA_DEV_T m)
{
entry->stat_valid = 0;
entry->ae_stat.aest_rdev = m;
@@ -1330,7 +1334,7 @@ archive_entry_set_rdev(struct archive_entry *entry, dev_t m)
}
void
archive_entry_set_rdevmajor(struct archive_entry *entry, dev_t m)
archive_entry_set_rdevmajor(struct archive_entry *entry, __LA_DEV_T m)
{
entry->stat_valid = 0;
entry->ae_stat.aest_rdev_is_broken_down = 1;
@@ -1340,7 +1344,7 @@ archive_entry_set_rdevmajor(struct archive_entry *entry, dev_t m)
}
void
archive_entry_set_rdevminor(struct archive_entry *entry, dev_t m)
archive_entry_set_rdevminor(struct archive_entry *entry, __LA_DEV_T m)
{
entry->stat_valid = 0;
entry->ae_stat.aest_rdev_is_broken_down = 1;
@@ -1603,21 +1607,27 @@ archive_entry_set_digest(struct archive_entry *entry, int type,
switch (type) {
case ARCHIVE_ENTRY_DIGEST_MD5:
copy_digest(entry, md5, digest);
entry->mset_digest |= AE_MSET_DIGEST_MD5;
break;
case ARCHIVE_ENTRY_DIGEST_RMD160:
copy_digest(entry, rmd160, digest);
entry->mset_digest |= AE_MSET_DIGEST_RMD160;
break;
case ARCHIVE_ENTRY_DIGEST_SHA1:
copy_digest(entry, sha1, digest);
entry->mset_digest |= AE_MSET_DIGEST_SHA1;
break;
case ARCHIVE_ENTRY_DIGEST_SHA256:
copy_digest(entry, sha256, digest);
entry->mset_digest |= AE_MSET_DIGEST_SHA256;
break;
case ARCHIVE_ENTRY_DIGEST_SHA384:
copy_digest(entry, sha384, digest);
entry->mset_digest |= AE_MSET_DIGEST_SHA384;
break;
case ARCHIVE_ENTRY_DIGEST_SHA512:
copy_digest(entry, sha512, digest);
entry->mset_digest |= AE_MSET_DIGEST_SHA512;
break;
default:
return ARCHIVE_WARN;
+58 -26
View File
@@ -28,7 +28,7 @@
#define ARCHIVE_ENTRY_H_INCLUDED
/* Note: Compiler will complain if this does not match archive.h! */
#define ARCHIVE_VERSION_NUMBER 3007007
#define ARCHIVE_VERSION_NUMBER 3008001
/*
* Note: archive_entry.h is for use outside of libarchive; the
@@ -40,8 +40,11 @@
#include <sys/types.h>
#include <stddef.h> /* for wchar_t */
#include <stdint.h>
#include <stdint.h> /* for C99 int64_t, etc. */
#if ARCHIVE_VERSION_NUMBER < 4000000
/* time_t is slated to be removed from public includes in 4.0 */
#include <time.h>
#endif
#if defined(_WIN32) && !defined(__CYGWIN__)
#include <windows.h>
@@ -55,12 +58,15 @@
#define __LA_INT64_T_DEFINED
# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__)
typedef __int64 la_int64_t;
typedef unsigned __int64 la_uint64_t;
# else
#include <unistd.h>
# if defined(_SCO_DS) || defined(__osf__)
typedef long long la_int64_t;
typedef unsigned long long la_uint64_t;
# else
typedef int64_t la_int64_t;
typedef uint64_t la_uint64_t;
# endif
# endif
#endif
@@ -96,6 +102,30 @@ typedef ssize_t la_ssize_t;
# define __LA_MODE_T mode_t
#endif
#if ARCHIVE_VERSION_NUMBER < 4000000
/* Use the platform types for time_t */
#define __LA_TIME_T time_t
#else
/* Use 64-bits integer types for time_t */
#define __LA_TIME_T la_int64_t
#endif
#if ARCHIVE_VERSION_NUMBER < 4000000
/* Use the platform types for dev_t */
#define __LA_DEV_T dev_t
#else
/* Use 64-bits integer types for dev_t */
#define __LA_DEV_T la_int64_t
#endif
#if ARCHIVE_VERSION_NUMBER < 4000000
/* Libarchive 3.x used signed int64 for inode numbers */
#define __LA_INO_T la_int64_t
#else
/* Switch to unsigned for libarchive 4.0 */
#define __LA_INO_T la_uint64_t
#endif
/* Large file support for Android */
#if defined(__LIBARCHIVE_BUILD) && defined(__ANDROID__)
#include "android_lf.h"
@@ -127,7 +157,8 @@ typedef ssize_t la_ssize_t;
# define __LA_DECL
#endif
#if defined(__GNUC__) && __GNUC__ >= 3 && __GNUC_MINOR__ >= 1
#if defined(__GNUC__) && (__GNUC__ > 3 || \
(__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
# define __LA_DEPRECATED __attribute__((deprecated))
#else
# define __LA_DEPRECATED
@@ -235,19 +266,19 @@ __LA_DECL struct archive_entry *archive_entry_new2(struct archive *);
* also return NULL when implicit character set conversions fail.
* This is usually what you want.
*/
__LA_DECL time_t archive_entry_atime(struct archive_entry *);
__LA_DECL __LA_TIME_T archive_entry_atime(struct archive_entry *);
__LA_DECL long archive_entry_atime_nsec(struct archive_entry *);
__LA_DECL int archive_entry_atime_is_set(struct archive_entry *);
__LA_DECL time_t archive_entry_birthtime(struct archive_entry *);
__LA_DECL __LA_TIME_T archive_entry_birthtime(struct archive_entry *);
__LA_DECL long archive_entry_birthtime_nsec(struct archive_entry *);
__LA_DECL int archive_entry_birthtime_is_set(struct archive_entry *);
__LA_DECL time_t archive_entry_ctime(struct archive_entry *);
__LA_DECL __LA_TIME_T archive_entry_ctime(struct archive_entry *);
__LA_DECL long archive_entry_ctime_nsec(struct archive_entry *);
__LA_DECL int archive_entry_ctime_is_set(struct archive_entry *);
__LA_DECL dev_t archive_entry_dev(struct archive_entry *);
__LA_DECL __LA_DEV_T archive_entry_dev(struct archive_entry *);
__LA_DECL int archive_entry_dev_is_set(struct archive_entry *);
__LA_DECL dev_t archive_entry_devmajor(struct archive_entry *);
__LA_DECL dev_t archive_entry_devminor(struct archive_entry *);
__LA_DECL __LA_DEV_T archive_entry_devmajor(struct archive_entry *);
__LA_DECL __LA_DEV_T archive_entry_devminor(struct archive_entry *);
__LA_DECL __LA_MODE_T archive_entry_filetype(struct archive_entry *);
__LA_DECL int archive_entry_filetype_is_set(struct archive_entry *);
__LA_DECL void archive_entry_fflags(struct archive_entry *,
@@ -264,8 +295,8 @@ __LA_DECL const char *archive_entry_hardlink(struct archive_entry *);
__LA_DECL const char *archive_entry_hardlink_utf8(struct archive_entry *);
__LA_DECL const wchar_t *archive_entry_hardlink_w(struct archive_entry *);
__LA_DECL int archive_entry_hardlink_is_set(struct archive_entry *);
__LA_DECL la_int64_t archive_entry_ino(struct archive_entry *);
__LA_DECL la_int64_t archive_entry_ino64(struct archive_entry *);
__LA_DECL __LA_INO_T archive_entry_ino(struct archive_entry *);
__LA_DECL __LA_INO_T archive_entry_ino64(struct archive_entry *);
__LA_DECL int archive_entry_ino_is_set(struct archive_entry *);
__LA_DECL __LA_MODE_T archive_entry_mode(struct archive_entry *);
__LA_DECL time_t archive_entry_mtime(struct archive_entry *);
@@ -278,9 +309,9 @@ __LA_DECL const wchar_t *archive_entry_pathname_w(struct archive_entry *);
__LA_DECL __LA_MODE_T archive_entry_perm(struct archive_entry *);
__LA_DECL int archive_entry_perm_is_set(struct archive_entry *);
__LA_DECL int archive_entry_rdev_is_set(struct archive_entry *);
__LA_DECL dev_t archive_entry_rdev(struct archive_entry *);
__LA_DECL dev_t archive_entry_rdevmajor(struct archive_entry *);
__LA_DECL dev_t archive_entry_rdevminor(struct archive_entry *);
__LA_DECL __LA_DEV_T archive_entry_rdev(struct archive_entry *);
__LA_DECL __LA_DEV_T archive_entry_rdevmajor(struct archive_entry *);
__LA_DECL __LA_DEV_T archive_entry_rdevminor(struct archive_entry *);
__LA_DECL const char *archive_entry_sourcepath(struct archive_entry *);
__LA_DECL const wchar_t *archive_entry_sourcepath_w(struct archive_entry *);
__LA_DECL la_int64_t archive_entry_size(struct archive_entry *);
@@ -309,18 +340,18 @@ __LA_DECL int archive_entry_is_encrypted(struct archive_entry *);
* always copied.
*/
__LA_DECL void archive_entry_set_atime(struct archive_entry *, time_t, long);
__LA_DECL void archive_entry_set_atime(struct archive_entry *, __LA_TIME_T, long);
__LA_DECL void archive_entry_unset_atime(struct archive_entry *);
#if defined(_WIN32) && !defined(__CYGWIN__)
__LA_DECL void archive_entry_copy_bhfi(struct archive_entry *, BY_HANDLE_FILE_INFORMATION *);
#endif
__LA_DECL void archive_entry_set_birthtime(struct archive_entry *, time_t, long);
__LA_DECL void archive_entry_set_birthtime(struct archive_entry *, __LA_TIME_T, long);
__LA_DECL void archive_entry_unset_birthtime(struct archive_entry *);
__LA_DECL void archive_entry_set_ctime(struct archive_entry *, time_t, long);
__LA_DECL void archive_entry_set_ctime(struct archive_entry *, __LA_TIME_T, long);
__LA_DECL void archive_entry_unset_ctime(struct archive_entry *);
__LA_DECL void archive_entry_set_dev(struct archive_entry *, dev_t);
__LA_DECL void archive_entry_set_devmajor(struct archive_entry *, dev_t);
__LA_DECL void archive_entry_set_devminor(struct archive_entry *, dev_t);
__LA_DECL void archive_entry_set_dev(struct archive_entry *, __LA_DEV_T);
__LA_DECL void archive_entry_set_devmajor(struct archive_entry *, __LA_DEV_T);
__LA_DECL void archive_entry_set_devminor(struct archive_entry *, __LA_DEV_T);
__LA_DECL void archive_entry_set_filetype(struct archive_entry *, unsigned int);
__LA_DECL void archive_entry_set_fflags(struct archive_entry *,
unsigned long /* set */, unsigned long /* clear */);
@@ -343,15 +374,15 @@ __LA_DECL void archive_entry_set_hardlink_utf8(struct archive_entry *, const cha
__LA_DECL void archive_entry_copy_hardlink(struct archive_entry *, const char *);
__LA_DECL void archive_entry_copy_hardlink_w(struct archive_entry *, const wchar_t *);
__LA_DECL int archive_entry_update_hardlink_utf8(struct archive_entry *, const char *);
__LA_DECL void archive_entry_set_ino(struct archive_entry *, la_int64_t);
__LA_DECL void archive_entry_set_ino64(struct archive_entry *, la_int64_t);
__LA_DECL void archive_entry_set_ino(struct archive_entry *, __LA_INO_T);
__LA_DECL void archive_entry_set_ino64(struct archive_entry *, __LA_INO_T);
__LA_DECL void archive_entry_set_link(struct archive_entry *, const char *);
__LA_DECL void archive_entry_set_link_utf8(struct archive_entry *, const char *);
__LA_DECL void archive_entry_copy_link(struct archive_entry *, const char *);
__LA_DECL void archive_entry_copy_link_w(struct archive_entry *, const wchar_t *);
__LA_DECL int archive_entry_update_link_utf8(struct archive_entry *, const char *);
__LA_DECL void archive_entry_set_mode(struct archive_entry *, __LA_MODE_T);
__LA_DECL void archive_entry_set_mtime(struct archive_entry *, time_t, long);
__LA_DECL void archive_entry_set_mtime(struct archive_entry *, __LA_TIME_T, long);
__LA_DECL void archive_entry_unset_mtime(struct archive_entry *);
__LA_DECL void archive_entry_set_nlink(struct archive_entry *, unsigned int);
__LA_DECL void archive_entry_set_pathname(struct archive_entry *, const char *);
@@ -360,9 +391,9 @@ __LA_DECL void archive_entry_copy_pathname(struct archive_entry *, const char *)
__LA_DECL void archive_entry_copy_pathname_w(struct archive_entry *, const wchar_t *);
__LA_DECL int archive_entry_update_pathname_utf8(struct archive_entry *, const char *);
__LA_DECL void archive_entry_set_perm(struct archive_entry *, __LA_MODE_T);
__LA_DECL void archive_entry_set_rdev(struct archive_entry *, dev_t);
__LA_DECL void archive_entry_set_rdevmajor(struct archive_entry *, dev_t);
__LA_DECL void archive_entry_set_rdevminor(struct archive_entry *, dev_t);
__LA_DECL void archive_entry_set_rdev(struct archive_entry *, __LA_DEV_T);
__LA_DECL void archive_entry_set_rdevmajor(struct archive_entry *, __LA_DEV_T);
__LA_DECL void archive_entry_set_rdevminor(struct archive_entry *, __LA_DEV_T);
__LA_DECL void archive_entry_set_size(struct archive_entry *, la_int64_t);
__LA_DECL void archive_entry_unset_size(struct archive_entry *);
__LA_DECL void archive_entry_copy_sourcepath(struct archive_entry *, const char *);
@@ -418,6 +449,7 @@ __LA_DECL void archive_entry_copy_mac_metadata(struct archive_entry *, const voi
#define ARCHIVE_ENTRY_DIGEST_SHA512 0x00000006
__LA_DECL const unsigned char * archive_entry_digest(struct archive_entry *, int /* type */);
__LA_DECL int archive_entry_set_digest(struct archive_entry *, int, const unsigned char *);
/*
* ACL routines. This used to simply store and return text-format ACL
@@ -280,6 +280,10 @@ find_entry(struct archive_entry_linkresolver *res,
dev_t dev;
int64_t ino;
if (!archive_entry_ino_is_set(entry) || !archive_entry_dev_is_set(entry)) {
return (NULL);
}
/* Free a held entry. */
if (res->spare != NULL) {
archive_entry_free(res->spare->canonical);
@@ -369,6 +373,10 @@ insert_entry(struct archive_entry_linkresolver *res,
struct links_entry *le;
size_t hash, bucket;
if (!archive_entry_ino_is_set(entry) || !archive_entry_dev_is_set(entry)) {
return (NULL);
}
/* Add this entry to the links cache. */
le = calloc(1, sizeof(struct links_entry));
if (le == NULL)
@@ -87,4 +87,4 @@ int _archive_entry_copy_symlink_l(struct archive_entry *,
int _archive_entry_copy_uname_l(struct archive_entry *,
const char *, size_t, struct archive_string_conv *);
#endif /* ARCHIVE_ENTRY_LOCALE_H_INCLUDED */
#endif /* !ARCHIVE_ENTRY_LOCALE_H_INCLUDED */
@@ -174,6 +174,13 @@ struct archive_entry {
size_t mac_metadata_size;
/* Digest support. */
#define AE_MSET_DIGEST_MD5 1
#define AE_MSET_DIGEST_RMD160 2
#define AE_MSET_DIGEST_SHA1 4
#define AE_MSET_DIGEST_SHA256 8
#define AE_MSET_DIGEST_SHA384 16
#define AE_MSET_DIGEST_SHA512 32
uint_least32_t mset_digest;
struct ae_digest digest;
/* ACL support. */
@@ -195,8 +202,4 @@ struct archive_entry {
int ae_symlink_type;
};
int
archive_entry_set_digest(struct archive_entry *entry, int type,
const unsigned char *digest);
#endif /* ARCHIVE_ENTRY_PRIVATE_H_INCLUDED */
#endif /* !ARCHIVE_ENTRY_PRIVATE_H_INCLUDED */
@@ -116,4 +116,4 @@ struct archive_hmac {
};
extern const struct archive_hmac __archive_hmac;
#endif /* ARCHIVE_HMAC_PRIVATE_H_INCLUDED */
#endif /* !ARCHIVE_HMAC_PRIVATE_H_INCLUDED */
+37 -65
View File
@@ -35,14 +35,17 @@
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#include "archive.h"
#include "archive_private.h"
#include "archive_entry.h"
#include "archive_getdate.h"
#include "archive_pathmatch.h"
#include "archive_rb.h"
#include "archive_string.h"
#include "archive_time_private.h"
struct match {
struct match *next;
@@ -53,8 +56,7 @@ struct match {
struct match_list {
struct match *first;
struct match **last;
int count;
int unmatched_count;
size_t unmatched_count;
struct match *unmatched_next;
int unmatched_eof;
};
@@ -73,7 +75,6 @@ struct match_file {
struct entry_list {
struct match_file *first;
struct match_file **last;
int count;
};
struct id_array {
@@ -144,12 +145,15 @@ static int add_pattern_mbs(struct archive_match *, struct match_list *,
const char *);
static int add_pattern_wcs(struct archive_match *, struct match_list *,
const wchar_t *);
#if !defined(_WIN32) || defined(__CYGWIN__)
static int cmp_key_mbs(const struct archive_rb_node *, const void *);
static int cmp_key_wcs(const struct archive_rb_node *, const void *);
static int cmp_node_mbs(const struct archive_rb_node *,
const struct archive_rb_node *);
#else
static int cmp_key_wcs(const struct archive_rb_node *, const void *);
static int cmp_node_wcs(const struct archive_rb_node *,
const struct archive_rb_node *);
#endif
static void entry_list_add(struct entry_list *, struct match_file *);
static void entry_list_free(struct entry_list *);
static void entry_list_init(struct entry_list *);
@@ -187,14 +191,14 @@ static int time_excluded(struct archive_match *,
struct archive_entry *);
static int validate_time_flag(struct archive *, int, const char *);
#define get_date __archive_get_date
#define get_date archive_parse_date
static const struct archive_rb_tree_ops rb_ops_mbs = {
static const struct archive_rb_tree_ops rb_ops = {
#if !defined(_WIN32) || defined(__CYGWIN__)
cmp_node_mbs, cmp_key_mbs
};
static const struct archive_rb_tree_ops rb_ops_wcs = {
#else
cmp_node_wcs, cmp_key_wcs
#endif
};
/*
@@ -228,7 +232,7 @@ archive_match_new(void)
a->recursive_include = 1;
match_list_init(&(a->inclusions));
match_list_init(&(a->exclusions));
__archive_rb_tree_init(&(a->exclusion_tree), &rb_ops_mbs);
__archive_rb_tree_init(&(a->exclusion_tree), &rb_ops);
entry_list_init(&(a->exclusion_entry_list));
match_list_init(&(a->inclusion_unames));
match_list_init(&(a->inclusion_gnames));
@@ -507,7 +511,9 @@ archive_match_path_unmatched_inclusions(struct archive *_a)
ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions");
a = (struct archive_match *)_a;
return (a->inclusions.unmatched_count);
if (a->inclusions.unmatched_count > (size_t)INT_MAX)
return INT_MAX;
return (int)(a->inclusions.unmatched_count);
}
int
@@ -650,7 +656,7 @@ add_pattern_from_file(struct archive_match *a, struct match_list *mlist,
break;
}
} else {
if (*b == 0x0d || *b == 0x0a) {
if (*b == 0x0d || *b == 0x0a) {
found_separator = 1;
break;
}
@@ -735,7 +741,7 @@ path_excluded(struct archive_match *a, int mbs, const void *pathname)
}
}
/* Exclusions take priority */
/* Exclusions take priority. */
for (match = a->exclusions.first; match != NULL;
match = match->next){
r = match_path_exclusion(a, match, mbs, pathname);
@@ -834,7 +840,6 @@ match_list_init(struct match_list *list)
{
list->first = NULL;
list->last = &(list->first);
list->count = 0;
}
static void
@@ -855,7 +860,6 @@ match_list_add(struct match_list *list, struct match *m)
{
*list->last = m;
list->last = &(m->next);
list->count++;
list->unmatched_count++;
}
@@ -1145,36 +1149,15 @@ set_timefilter_date_w(struct archive_match *a, int timetype,
}
#if defined(_WIN32) && !defined(__CYGWIN__)
#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
static int
set_timefilter_find_data(struct archive_match *a, int timetype,
DWORD ftLastWriteTime_dwHighDateTime, DWORD ftLastWriteTime_dwLowDateTime,
DWORD ftCreationTime_dwHighDateTime, DWORD ftCreationTime_dwLowDateTime)
const FILETIME* ftLastWriteTime, const FILETIME* ftCreationTime)
{
ULARGE_INTEGER utc;
time_t ctime_sec, mtime_sec;
long ctime_ns, mtime_ns;
uint32_t ctime_ns, mtime_ns;
utc.HighPart = ftCreationTime_dwHighDateTime;
utc.LowPart = ftCreationTime_dwLowDateTime;
if (utc.QuadPart >= EPOC_TIME) {
utc.QuadPart -= EPOC_TIME;
ctime_sec = (time_t)(utc.QuadPart / 10000000);
ctime_ns = (long)(utc.QuadPart % 10000000) * 100;
} else {
ctime_sec = 0;
ctime_ns = 0;
}
utc.HighPart = ftLastWriteTime_dwHighDateTime;
utc.LowPart = ftLastWriteTime_dwLowDateTime;
if (utc.QuadPart >= EPOC_TIME) {
utc.QuadPart -= EPOC_TIME;
mtime_sec = (time_t)(utc.QuadPart / 10000000);
mtime_ns = (long)(utc.QuadPart % 10000000) * 100;
} else {
mtime_sec = 0;
mtime_ns = 0;
}
ntfs_to_unix(FILETIME_to_ntfs(ftLastWriteTime), &mtime_sec, &mtime_ns);
ntfs_to_unix(FILETIME_to_ntfs(ftCreationTime), &ctime_sec, &ctime_ns);
return set_timefilter(a, timetype,
mtime_sec, mtime_ns, ctime_sec, ctime_ns);
}
@@ -1199,9 +1182,7 @@ set_timefilter_pathname_mbs(struct archive_match *a, int timetype,
return (ARCHIVE_FAILED);
}
FindClose(h);
return set_timefilter_find_data(a, timetype,
d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime,
d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime);
return set_timefilter_find_data(a, timetype, &d.ftLastWriteTime, &d.ftCreationTime);
}
static int
@@ -1223,9 +1204,7 @@ set_timefilter_pathname_wcs(struct archive_match *a, int timetype,
return (ARCHIVE_FAILED);
}
FindClose(h);
return set_timefilter_find_data(a, timetype,
d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime,
d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime);
return set_timefilter_find_data(a, timetype, &d.ftLastWriteTime, &d.ftCreationTime);
}
#else /* _WIN32 && !__CYGWIN__ */
@@ -1300,6 +1279,7 @@ set_timefilter_pathname_wcs(struct archive_match *a, int timetype,
/*
* Call back functions for archive_rb.
*/
#if !defined(_WIN32) || defined(__CYGWIN__)
static int
cmp_node_mbs(const struct archive_rb_node *n1,
const struct archive_rb_node *n2)
@@ -1316,7 +1296,7 @@ cmp_node_mbs(const struct archive_rb_node *n1,
return (-1);
return (strcmp(p1, p2));
}
static int
cmp_key_mbs(const struct archive_rb_node *n, const void *key)
{
@@ -1328,7 +1308,7 @@ cmp_key_mbs(const struct archive_rb_node *n, const void *key)
return (-1);
return (strcmp(p, (const char *)key));
}
#else
static int
cmp_node_wcs(const struct archive_rb_node *n1,
const struct archive_rb_node *n2)
@@ -1345,7 +1325,7 @@ cmp_node_wcs(const struct archive_rb_node *n1,
return (-1);
return (wcscmp(p1, p2));
}
static int
cmp_key_wcs(const struct archive_rb_node *n, const void *key)
{
@@ -1357,13 +1337,13 @@ cmp_key_wcs(const struct archive_rb_node *n, const void *key)
return (-1);
return (wcscmp(p, (const wchar_t *)key));
}
#endif
static void
entry_list_init(struct entry_list *list)
{
list->first = NULL;
list->last = &(list->first);
list->count = 0;
}
static void
@@ -1384,7 +1364,6 @@ entry_list_add(struct entry_list *list, struct match_file *file)
{
*list->last = file;
list->last = &(file->next);
list->count++;
}
static int
@@ -1407,9 +1386,7 @@ add_entry(struct archive_match *a, int flag,
return (ARCHIVE_FAILED);
}
archive_mstring_copy_wcs(&(f->pathname), pathname);
a->exclusion_tree.rbt_ops = &rb_ops_wcs;
#else
(void)rb_ops_wcs;
pathname = archive_entry_pathname(entry);
if (pathname == NULL) {
free(f);
@@ -1417,7 +1394,6 @@ add_entry(struct archive_match *a, int flag,
return (ARCHIVE_FAILED);
}
archive_mstring_copy_mbs(&(f->pathname), pathname);
a->exclusion_tree.rbt_ops = &rb_ops_mbs;
#endif
f->flag = flag;
f->mtime_sec = archive_entry_mtime(entry);
@@ -1542,16 +1518,13 @@ time_excluded(struct archive_match *a, struct archive_entry *entry)
}
/* If there is no exclusion list, include the file. */
if (a->exclusion_entry_list.count == 0)
if (a->exclusion_entry_list.first == NULL)
return (0);
#if defined(_WIN32) && !defined(__CYGWIN__)
pathname = archive_entry_pathname_w(entry);
a->exclusion_tree.rbt_ops = &rb_ops_wcs;
#else
(void)rb_ops_wcs;
pathname = archive_entry_pathname(entry);
a->exclusion_tree.rbt_ops = &rb_ops_mbs;
#endif
if (pathname == NULL)
return (0);
@@ -1707,7 +1680,7 @@ archive_match_owner_excluded(struct archive *_a,
static int
add_owner_id(struct archive_match *a, struct id_array *ids, int64_t id)
{
unsigned i;
size_t i;
if (ids->count + 1 >= ids->size) {
void *p;
@@ -1744,10 +1717,10 @@ add_owner_id(struct archive_match *a, struct id_array *ids, int64_t id)
static int
match_owner_id(struct id_array *ids, int64_t id)
{
unsigned b, m, t;
size_t b, m, t;
t = 0;
b = (unsigned)ids->count;
b = ids->count;
while (t < b) {
m = (t + b)>>1;
if (ids->ids[m] == id)
@@ -1842,7 +1815,7 @@ owner_excluded(struct archive_match *a, struct archive_entry *entry)
return (1);
}
if (a->inclusion_unames.count) {
if (a->inclusion_unames.first != NULL) {
#if defined(_WIN32) && !defined(__CYGWIN__)
r = match_owner_name_wcs(a, &(a->inclusion_unames),
archive_entry_uname_w(entry));
@@ -1856,7 +1829,7 @@ owner_excluded(struct archive_match *a, struct archive_entry *entry)
return (r);
}
if (a->inclusion_gnames.count) {
if (a->inclusion_gnames.first != NULL) {
#if defined(_WIN32) && !defined(__CYGWIN__)
r = match_owner_name_wcs(a, &(a->inclusion_gnames),
archive_entry_gname_w(entry));
@@ -1871,4 +1844,3 @@ owner_excluded(struct archive_match *a, struct archive_entry *entry)
}
return (0);
}
@@ -38,7 +38,7 @@ parse_option(const char **str,
int
_archive_set_option(struct archive *a,
const char *m, const char *o, const char *v,
int magic, const char *fn, option_handler use_option)
unsigned int magic, const char *fn, option_handler use_option)
{
const char *mp, *op, *vp;
int r;
@@ -97,7 +97,7 @@ _archive_set_either_option(struct archive *a, const char *m, const char *o, cons
int
_archive_set_options(struct archive *a, const char *options,
int magic, const char *fn, option_handler use_option)
unsigned int magic, const char *fn, option_handler use_option)
{
int allok = 1, anyok = 0, ignore_mod_err = 0, r;
char *data;
@@ -35,11 +35,11 @@ typedef int (*option_handler)(struct archive *a,
int
_archive_set_option(struct archive *a,
const char *mod, const char *opt, const char *val,
int magic, const char *fn, option_handler use_option);
unsigned int magic, const char *fn, option_handler use_option);
int
_archive_set_options(struct archive *a, const char *options,
int magic, const char *fn, option_handler use_option);
unsigned int magic, const char *fn, option_handler use_option);
int
_archive_set_either_option(struct archive *a,
@@ -46,4 +46,4 @@ pack_t pack_native;
(((y) << 12) & 0xfff00000) | \
(((y) << 0) & 0x000000ff)))
#endif /* ARCHIVE_PACK_DEV_H */
#endif /* !ARCHIVE_PACK_DEV_H */
@@ -35,8 +35,7 @@
#include <string.h>
#include <time.h>
#define __LIBARCHIVE_BUILD 1
#include "archive_getdate.h"
#include "archive.h"
/* Basic time units. */
#define EPOCH 1970
@@ -820,6 +819,23 @@ RelativeMonth(time_t Start, time_t Timezone, time_t RelMonth)
Timezone, DSTmaybe));
}
/*
* Parses and consumes an unsigned number.
* Returns 1 if any number is parsed. Otherwise, *value is unchanged.
*/
static char
consume_unsigned_number(const char **in, time_t *value)
{
char c;
if (isdigit((unsigned char)(c = **in))) {
for (*value = 0; isdigit((unsigned char)(c = *(*in)++)); )
*value = 10 * *value + c - '0';
(*in)--;
return 1;
}
return 0;
}
/*
* Tokenizer.
*/
@@ -861,7 +877,8 @@ nexttoken(const char **in, time_t *value)
&& i < sizeof(buff)-1) {
if (*src != '.') {
if (isupper((unsigned char)*src))
buff[i++] = tolower((unsigned char)*src);
buff[i++] = (char)tolower(
(unsigned char)*src);
else
buff[i++] = *src;
}
@@ -895,10 +912,7 @@ nexttoken(const char **in, time_t *value)
* Because '-' and '+' have other special meanings, I
* don't deal with signed numbers here.
*/
if (isdigit((unsigned char)(c = **in))) {
for (*value = 0; isdigit((unsigned char)(c = *(*in)++)); )
*value = 10 * *value + c - '0';
(*in)--;
if (consume_unsigned_number(in, value)) {
return (tUNUMBER);
}
@@ -914,7 +928,7 @@ difftm (struct tm *a, struct tm *b)
{
int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
int days = (
long days = (
/* difference in day of year */
a->tm_yday - b->tm_yday
/* + intervening leap days */
@@ -929,6 +943,32 @@ difftm (struct tm *a, struct tm *b)
+ (a->tm_sec - b->tm_sec));
}
/*
* Parses a Unix epoch timestamp (seconds).
* This supports a subset of what GNU tar accepts from black box testing,
* but covers common use cases.
*/
static time_t
parse_unix_epoch(const char *p)
{
time_t epoch;
/* may begin with + */
if (*p == '+') {
p++;
}
/* followed by some number */
if (!consume_unsigned_number(&p, &epoch))
return (time_t)-1;
/* ...and nothing else */
if (*p != '\0')
return (time_t)-1;
return epoch;
}
/*
*
* The public function.
@@ -936,7 +976,7 @@ difftm (struct tm *a, struct tm *b)
* TODO: tokens[] array should be dynamically sized.
*/
time_t
__archive_get_date(time_t now, const char *p)
archive_parse_date(time_t now, const char *p)
{
struct token tokens[256];
struct gdstate _gds;
@@ -948,6 +988,13 @@ __archive_get_date(time_t now, const char *p)
time_t tod;
long tzone;
/*
* @-prefixed Unix epoch timestamps (seconds)
* Skip the complex tokenizer - We do not want to accept strings like "@tenth"
*/
if (*p == '@')
return parse_unix_epoch(p + 1);
/* Clear out the parsed token array. */
memset(tokens, 0, sizeof(tokens));
/* Initialize the parser state. */
@@ -61,6 +61,11 @@
# endif
#endif
/* For cygwin, to avoid missing LONG, ULONG, PUCHAR, ... definitions */
#ifdef __CYGWIN__
#include <windef.h>
#endif
/* It should be possible to get rid of this by extending the feature-test
* macros to cover Windows API functions, probably along with non-trivial
* refactoring of code to find structures that sit more cleanly on top of
@@ -50,4 +50,4 @@
#define ARCHIVE_ACL_SUPPORT 1
#endif
#endif /* ARCHIVE_PLATFORM_ACL_H_INCLUDED */
#endif /* !ARCHIVE_PLATFORM_ACL_H_INCLUDED */
@@ -42,4 +42,4 @@
#define ARCHIVE_XATTR_SUPPORT 1
#endif
#endif /* ARCHIVE_PLATFORM_XATTR_H_INCLUDED */
#endif /* !ARCHIVE_PLATFORM_XATTR_H_INCLUDED */
@@ -287,9 +287,14 @@ static void *AllocUnits(CPpmd7 *p, unsigned indx)
return AllocUnitsRare(p, indx);
}
#define MyMem12Cpy(dest, src, num) \
{ UInt32 *d = (UInt32 *)dest; const UInt32 *s = (const UInt32 *)src; UInt32 n = num; \
do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } while(--n); }
#define MyMem12Cpy(dest, src, num) do { \
UInt32 *d = (UInt32 *)dest; \
const UInt32 *s = (const UInt32 *)src; \
UInt32 n = num; \
do { \
d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; \
} while(--n); \
} while (0)
static void *ShrinkUnits(CPpmd7 *p, void *oldPtr, unsigned oldNU, unsigned newNU)
{
+11 -4
View File
@@ -242,9 +242,14 @@ static void *AllocUnits(CPpmd8 *p, unsigned indx)
return AllocUnitsRare(p, indx);
}
#define MyMem12Cpy(dest, src, num) \
{ UInt32 *d = (UInt32 *)dest; const UInt32 *z = (const UInt32 *)src; UInt32 n = num; \
do { d[0] = z[0]; d[1] = z[1]; d[2] = z[2]; z += 3; d += 3; } while (--n); }
#define MyMem12Cpy(dest, src, num) do { \
UInt32 *d = (UInt32 *)dest; \
const UInt32 *z = (const UInt32 *)src; \
UInt32 n = num; \
do { \
d[0] = z[0]; d[1] = z[1]; d[2] = z[2]; z += 3; d += 3; \
} while (--n); \
} while (0)
static void *ShrinkUnits(CPpmd8 *p, void *oldPtr, unsigned oldNU, unsigned newNU)
{
@@ -341,7 +346,9 @@ static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v)
(p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF);
}
#define RESET_TEXT(offs) { p->Text = p->Base + p->AlignOffset + (offs); }
#define RESET_TEXT(offs) do { \
p->Text = p->Base + p->AlignOffset + (offs); \
} while (0)
static void RestartModel(CPpmd8 *p)
{
@@ -109,8 +109,12 @@ typedef struct
Byte Count; /* Count to next change of Shift */
} CPpmd_See;
#define Ppmd_See_Update(p) if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) \
{ (p)->Summ <<= 1; (p)->Count = (Byte)(3 << (p)->Shift++); }
#define Ppmd_See_Update(p) do { \
if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) { \
(p)->Summ <<= 1; \
(p)->Count = (Byte)(3 << (p)->Shift++); \
} \
} while (0)
typedef struct
{
@@ -144,8 +148,12 @@ typedef
#endif
CPpmd_Byte_Ref;
#define PPMD_SetAllBitsIn256Bytes(p) \
{ unsigned j; for (j = 0; j < 256 / sizeof(p[0]); j += 8) { \
p[j+7] = p[j+6] = p[j+5] = p[j+4] = p[j+3] = p[j+2] = p[j+1] = p[j+0] = ~(size_t)0; }}
#define PPMD_SetAllBitsIn256Bytes(p) do { \
unsigned j; \
for (j = 0; j < 256 / sizeof(p[0]); j += 8) { \
p[j+7] = p[j+6] = p[j+5] = p[j+4] = \
p[j+3] = p[j+2] = p[j+1] = p[j+0] = ~(size_t)0; \
} \
} while (0)
#endif
@@ -33,4 +33,4 @@
/* Random number generator. */
int archive_random(void *buf, size_t nbytes);
#endif /* ARCHIVE_RANDOM_PRIVATE_H_INCLUDED */
#endif /* !ARCHIVE_RANDOM_PRIVATE_H_INCLUDED */
+1 -1
View File
@@ -110,4 +110,4 @@ struct archive_rb_node *
__archive_rb_tree_iterate(struct archive_rb_tree *,
struct archive_rb_node *, const unsigned int);
#endif /* ARCHIVE_RB_H_*/
#endif /* !ARCHIVE_RB_H_INCLUDED */
@@ -176,15 +176,9 @@ client_skip_proxy(struct archive_read_filter *self, int64_t request)
return 0;
if (self->archive->client.skipper != NULL) {
/* Seek requests over 1GiB are broken down into
* multiple seeks. This avoids overflows when the
* requests get passed through 32-bit arguments. */
int64_t skip_limit = (int64_t)1 << 30;
int64_t total = 0;
for (;;) {
int64_t get, ask = request;
if (ask > skip_limit)
ask = skip_limit;
get = (self->archive->client.skipper)
(&self->archive->archive, self->data, ask);
total += get;
@@ -96,6 +96,10 @@ archive_read_append_filter(struct archive *_a, int code)
strcpy(str, "lzip");
r1 = archive_read_support_filter_lzip(_a);
break;
case ARCHIVE_FILTER_LZOP:
strcpy(str, "lzop");
r1 = archive_read_support_filter_lzop(_a);
break;
case ARCHIVE_FILTER_LRZIP:
strcpy(str, "lrzip");
r1 = archive_read_support_filter_lrzip(_a);
@@ -888,7 +888,7 @@ setup_sparse_fiemap(struct archive_read_disk *a,
count = (sizeof(buff) - sizeof(*fm))/sizeof(*fe);
fm = (struct fiemap *)buff;
fm->fm_start = 0;
fm->fm_length = ~0ULL;;
fm->fm_length = ~0ULL;
fm->fm_flags = FIEMAP_FLAG_SYNC;
fm->fm_extent_count = count;
do_fiemap = 1;
@@ -276,7 +276,7 @@ tree_dir_next_posix(struct tree *t);
#endif
/* Initiate/terminate a tree traversal. */
static struct tree *tree_open(const char *, int, int);
static struct tree *tree_open(const char *, char, int);
static struct tree *tree_reopen(struct tree *, const char *, int);
static void tree_close(struct tree *);
static void tree_free(struct tree *);
@@ -514,7 +514,7 @@ _archive_read_close(struct archive *_a)
static void
setup_symlink_mode(struct archive_read_disk *a, char symlink_mode,
int follow_symlinks)
char follow_symlinks)
{
a->symlink_mode = symlink_mode;
a->follow_symlinks = follow_symlinks;
@@ -778,7 +778,8 @@ _archive_read_data_block(struct archive *_a, const void **buff,
*/
if (t->current_sparse->offset > t->entry_total) {
if (lseek(t->entry_fd,
(off_t)t->current_sparse->offset, SEEK_SET) < 0) {
(off_t)t->current_sparse->offset, SEEK_SET) !=
t->current_sparse->offset) {
archive_set_error(&a->archive, errno, "Seek error");
r = ARCHIVE_FATAL;
a->archive.state = ARCHIVE_STATE_FATAL;
@@ -2180,7 +2181,7 @@ tree_append(struct tree *t, const char *name, size_t name_length)
* Open a directory tree for traversal.
*/
static struct tree *
tree_open(const char *path, int symlink_mode, int restore_time)
tree_open(const char *path, char symlink_mode, int restore_time)
{
struct tree *t;
@@ -52,10 +52,11 @@ struct archive_read_disk {
/*
* Since symlink interaction changes, we need to track whether
* we're following symlinks for the current item. 'L' mode above
* sets this true, 'P' sets it false, 'H' changes it as we traverse.
* we're following symlinks for the current item, governed by the above
* symlink_mode. 'L' sets this true, 'P' sets it false, 'H' changes it
* as we traverse.
*/
char follow_symlinks; /* Either 'L' or 'P'. */
char follow_symlinks; /* Either 0 or 1. */
/* Directory traversals. */
struct tree *tree;
@@ -37,8 +37,10 @@
.Nm archive_read_support_format_lha ,
.Nm archive_read_support_format_mtree ,
.Nm archive_read_support_format_rar ,
.Nm archive_read_support_format_rar5 ,
.Nm archive_read_support_format_raw ,
.Nm archive_read_support_format_tar ,
.Nm archive_read_support_format_warc ,
.Nm archive_read_support_format_xar ,
.Nm archive_read_support_format_zip
.Nd functions for reading streaming archives
@@ -70,10 +72,14 @@ Streaming Archive Library (libarchive, -larchive)
.Ft int
.Fn archive_read_support_format_rar "struct archive *"
.Ft int
.Fn archive_read_support_format_rar5 "struct archive *"
.Ft int
.Fn archive_read_support_format_raw "struct archive *"
.Ft int
.Fn archive_read_support_format_tar "struct archive *"
.Ft int
.Fn archive_read_support_format_warc "struct archive *"
.Ft int
.Fn archive_read_support_format_xar "struct archive *"
.Ft int
.Fn archive_read_support_format_zip "struct archive *"
@@ -89,8 +95,10 @@ Streaming Archive Library (libarchive, -larchive)
.Fn archive_read_support_format_lha ,
.Fn archive_read_support_format_mtree ,
.Fn archive_read_support_format_rar ,
.Fn archive_read_support_format_rar5 ,
.Fn archive_read_support_format_raw ,
.Fn archive_read_support_format_tar ,
.Fn archive_read_support_format_warc ,
.Fn archive_read_support_format_xar ,
.Fn archive_read_support_format_zip
.Xc
@@ -100,6 +108,13 @@ For example,
.Fn archive_read_support_format_tar
enables support for a variety of standard tar formats, old-style tar,
ustar, pax interchange format, and many common variants.
.Fn archive_read_support_format_zip
enables support for both the streaming and the seeking zip readers,
which can separately be enabled by respectively
.Fn archive_read_support_format_zip_streamable
and
.Fn archive_read_support_format_zip_seekable
.
.It Fn archive_read_support_format_all
Enables support for all available formats except the
.Dq raw
@@ -52,6 +52,7 @@
struct read_fd_data {
int fd;
size_t block_size;
int64_t size;
char use_lseek;
void *buffer;
};
@@ -95,6 +96,7 @@ archive_read_open_fd(struct archive *a, int fd, size_t block_size)
if (S_ISREG(st.st_mode)) {
archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino);
mine->use_lseek = 1;
mine->size = st.st_size;
}
#if defined(__CYGWIN__) || defined(_WIN32)
setmode(mine->fd, O_BINARY);
@@ -131,7 +133,7 @@ static int64_t
file_skip(struct archive *a, void *client_data, int64_t request)
{
struct read_fd_data *mine = (struct read_fd_data *)client_data;
int64_t skip = request;
off_t skip = (off_t)request;
int64_t old_offset, new_offset;
int skip_bits = sizeof(skip) * 8 - 1; /* off_t is a signed type. */
@@ -140,20 +142,25 @@ file_skip(struct archive *a, void *client_data, int64_t request)
/* Reduce a request that would overflow the 'skip' variable. */
if (sizeof(request) > sizeof(skip)) {
int64_t max_skip =
const int64_t max_skip =
(((int64_t)1 << (skip_bits - 1)) - 1) * 2 + 1;
if (request > max_skip)
skip = max_skip;
skip = (off_t)max_skip;
}
/* Reduce request to the next smallest multiple of block_size */
request = (request / mine->block_size) * mine->block_size;
if (request == 0)
/* Reduce 'skip' to the next smallest multiple of block_size */
skip = (off_t)(((int64_t)skip / mine->block_size) * mine->block_size);
if (skip == 0)
return (0);
if (((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0) &&
((new_offset = lseek(mine->fd, skip, SEEK_CUR)) >= 0))
return (new_offset - old_offset);
if ((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0) {
if (old_offset >= mine->size ||
skip > mine->size - old_offset) {
/* Do not seek past end of file. */
errno = ESPIPE;
} else if ((new_offset = lseek(mine->fd, skip, SEEK_CUR)) >= 0)
return (new_offset - old_offset);
}
/* If seek failed once, it will probably fail again. */
mine->use_lseek = 0;
@@ -178,11 +185,24 @@ static int64_t
file_seek(struct archive *a, void *client_data, int64_t request, int whence)
{
struct read_fd_data *mine = (struct read_fd_data *)client_data;
off_t seek = (off_t)request;
int64_t r;
int seek_bits = sizeof(seek) * 8 - 1; /* off_t is a signed type. */
/* We use off_t here because lseek() is declared that way. */
/* See above for notes about when off_t is less than 64 bits. */
r = lseek(mine->fd, request, whence);
/* Reduce a request that would overflow the 'seek' variable. */
if (sizeof(request) > sizeof(seek)) {
const int64_t max_seek =
(((int64_t)1 << (seek_bits - 1)) - 1) * 2 + 1;
const int64_t min_seek = ~max_seek;
if (request > max_seek)
seek = (off_t)max_seek;
else if (request < min_seek)
seek = (off_t)min_seek;
}
r = lseek(mine->fd, seek, whence);
if (r >= 0)
return r;
@@ -52,13 +52,15 @@
struct read_FILE_data {
FILE *f;
size_t block_size;
int64_t size;
void *buffer;
char can_skip;
};
static int file_close(struct archive *, void *);
static ssize_t file_read(struct archive *, void *, const void **buff);
static int64_t file_skip(struct archive *, void *, int64_t request);
static int FILE_close(struct archive *, void *);
static ssize_t FILE_read(struct archive *, void *, const void **buff);
static int64_t FILE_seek(struct archive *, void *, int64_t, int);
static int64_t FILE_skip(struct archive *, void *, int64_t);
int
archive_read_open_FILE(struct archive *a, FILE *f)
@@ -69,7 +71,7 @@ archive_read_open_FILE(struct archive *a, FILE *f)
void *b;
archive_clear_error(a);
mine = malloc(sizeof(*mine));
mine = calloc(1, sizeof(*mine));
b = malloc(block_size);
if (mine == NULL || b == NULL) {
archive_set_error(a, ENOMEM, "No memory");
@@ -90,22 +92,23 @@ archive_read_open_FILE(struct archive *a, FILE *f)
archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino);
/* Enable the seek optimization only for regular files. */
mine->can_skip = 1;
} else
mine->can_skip = 0;
mine->size = st.st_size;
}
#if defined(__CYGWIN__) || defined(_WIN32)
setmode(fileno(mine->f), O_BINARY);
#endif
archive_read_set_read_callback(a, file_read);
archive_read_set_skip_callback(a, file_skip);
archive_read_set_close_callback(a, file_close);
archive_read_set_read_callback(a, FILE_read);
archive_read_set_skip_callback(a, FILE_skip);
archive_read_set_seek_callback(a, FILE_seek);
archive_read_set_close_callback(a, FILE_close);
archive_read_set_callback_data(a, mine);
return (archive_read_open1(a));
}
static ssize_t
file_read(struct archive *a, void *client_data, const void **buff)
FILE_read(struct archive *a, void *client_data, const void **buff)
{
struct read_FILE_data *mine = (struct read_FILE_data *)client_data;
size_t bytes_read;
@@ -119,16 +122,17 @@ file_read(struct archive *a, void *client_data, const void **buff)
}
static int64_t
file_skip(struct archive *a, void *client_data, int64_t request)
FILE_skip(struct archive *a, void *client_data, int64_t request)
{
struct read_FILE_data *mine = (struct read_FILE_data *)client_data;
#if HAVE_FSEEKO
off_t skip = (off_t)request;
#elif HAVE__FSEEKI64
#if HAVE__FSEEKI64
int64_t skip = request;
#elif HAVE_FSEEKO
off_t skip = (off_t)request;
#else
long skip = (long)request;
#endif
int64_t old_offset, new_offset = -1;
int skip_bits = sizeof(skip) * 8 - 1;
(void)a; /* UNUSED */
@@ -144,7 +148,7 @@ file_skip(struct archive *a, void *client_data, int64_t request)
/* If request is too big for a long or an off_t, reduce it. */
if (sizeof(request) > sizeof(skip)) {
int64_t max_skip =
const int64_t max_skip =
(((int64_t)1 << (skip_bits - 1)) - 1) * 2 + 1;
if (request > max_skip)
skip = max_skip;
@@ -152,23 +156,92 @@ file_skip(struct archive *a, void *client_data, int64_t request)
#ifdef __ANDROID__
/* fileno() isn't safe on all platforms ... see above. */
if (lseek(fileno(mine->f), skip, SEEK_CUR) < 0)
old_offset = lseek(fileno(mine->f), 0, SEEK_CUR);
#elif HAVE__FSEEKI64
if (_fseeki64(mine->f, skip, SEEK_CUR) != 0)
old_offset = _ftelli64(mine->f);
#elif HAVE_FSEEKO
if (fseeko(mine->f, skip, SEEK_CUR) != 0)
old_offset = ftello(mine->f);
#else
if (fseek(mine->f, skip, SEEK_CUR) != 0)
old_offset = ftell(mine->f);
#endif
{
mine->can_skip = 0;
return (0);
if (old_offset >= 0) {
if (old_offset < mine->size &&
skip <= mine->size - old_offset) {
#ifdef __ANDROID__
new_offset = lseek(fileno(mine->f), skip, SEEK_CUR);
#elif HAVE__FSEEKI64
if (_fseeki64(mine->f, skip, SEEK_CUR) == 0)
new_offset = _ftelli64(mine->f);
#elif HAVE_FSEEKO
if (fseeko(mine->f, skip, SEEK_CUR) == 0)
new_offset = ftello(mine->f);
#else
if (fseek(mine->f, skip, SEEK_CUR) == 0)
new_offset = ftell(mine->f);
#endif
if (new_offset >= 0)
return (new_offset - old_offset);
}
}
return (request);
mine->can_skip = 0;
return (0);
}
/*
* TODO: Store the offset and use it in the read callback.
*/
static int64_t
FILE_seek(struct archive *a, void *client_data, int64_t request, int whence)
{
struct read_FILE_data *mine = (struct read_FILE_data *)client_data;
#if HAVE__FSEEKI64
int64_t seek = request;
#elif HAVE_FSEEKO
off_t seek = (off_t)request;
#else
long seek = (long)request;
#endif
int seek_bits = sizeof(seek) * 8 - 1;
(void)a; /* UNUSED */
/* Reduce a request that would overflow the 'seek' variable. */
if (sizeof(request) > sizeof(seek)) {
const int64_t max_seek =
(((int64_t)1 << (seek_bits - 1)) - 1) * 2 + 1;
const int64_t min_seek = ~max_seek;
if (request > max_seek)
seek = max_seek;
else if (request < min_seek)
seek = min_seek;
}
#ifdef __ANDROID__
/* Newer Android versions have fseeko...to meditate. */
int64_t ret = lseek(fileno(mine->f), seek, whence);
if (ret >= 0) {
return ret;
}
#elif HAVE__FSEEKI64
if (_fseeki64(mine->f, seek, whence) == 0) {
return _ftelli64(mine->f);
}
#elif HAVE_FSEEKO
if (fseeko(mine->f, seek, whence) == 0) {
return ftello(mine->f);
}
#else
if (fseek(mine->f, seek, whence) == 0) {
return ftell(mine->f);
}
#endif
/* If we arrive here, the input is corrupted or truncated so fail. */
archive_set_error(a, errno, "Error seeking in FILE* pointer");
return (ARCHIVE_FATAL);
}
static int
file_close(struct archive *a, void *client_data)
FILE_close(struct archive *a, void *client_data)
{
struct read_FILE_data *mine = (struct read_FILE_data *)client_data;
@@ -74,6 +74,7 @@ struct read_file_data {
size_t block_size;
void *buffer;
mode_t st_mode; /* Mode bits for opened file. */
int64_t size;
char use_lseek;
enum fnt_e { FNT_STDIN, FNT_MBS, FNT_WCS } filename_type;
union {
@@ -303,7 +304,7 @@ file_open(struct archive *a, void *client_data)
}
if (fd < 0) {
archive_set_error(a, errno,
"Failed to open '%S'", wfilename);
"Failed to open '%ls'", wfilename);
return (ARCHIVE_FATAL);
}
#else
@@ -315,7 +316,7 @@ file_open(struct archive *a, void *client_data)
if (fstat(fd, &st) != 0) {
#if defined(_WIN32) && !defined(__CYGWIN__)
if (mine->filename_type == FNT_WCS)
archive_set_error(a, errno, "Can't stat '%S'",
archive_set_error(a, errno, "Can't stat '%ls'",
wfilename);
else
#endif
@@ -400,8 +401,10 @@ file_open(struct archive *a, void *client_data)
mine->st_mode = st.st_mode;
/* Disk-like inputs can use lseek(). */
if (is_disk_like)
if (is_disk_like) {
mine->use_lseek = 1;
mine->size = st.st_size;
}
return (ARCHIVE_OK);
fail:
@@ -447,7 +450,7 @@ file_read(struct archive *a, void *client_data, const void **buff)
"Error reading '%s'", mine->filename.m);
else
archive_set_error(a, errno,
"Error reading '%S'", mine->filename.w);
"Error reading '%ls'", mine->filename.w);
}
return (bytes_read);
}
@@ -479,21 +482,30 @@ file_skip_lseek(struct archive *a, void *client_data, int64_t request)
struct read_file_data *mine = (struct read_file_data *)client_data;
#if defined(_WIN32) && !defined(__CYGWIN__)
/* We use _lseeki64() on Windows. */
int64_t old_offset, new_offset;
int64_t old_offset, new_offset, skip = request;
#else
off_t old_offset, new_offset;
off_t old_offset, new_offset, skip = (off_t)request;
#endif
int skip_bits = sizeof(skip) * 8 - 1;
/* We use off_t here because lseek() is declared that way. */
/* TODO: Deal with case where off_t isn't 64 bits.
* This shouldn't be a problem on Linux or other POSIX
* systems, since the configuration logic for libarchive
* tries to obtain a 64-bit off_t.
*/
if ((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0 &&
(new_offset = lseek(mine->fd, request, SEEK_CUR)) >= 0)
return (new_offset - old_offset);
/* Reduce a request that would overflow the 'skip' variable. */
if (sizeof(request) > sizeof(skip)) {
const int64_t max_skip =
(((int64_t)1 << (skip_bits - 1)) - 1) * 2 + 1;
if (request > max_skip)
skip = max_skip;
}
if ((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0) {
if (old_offset >= mine->size ||
skip > mine->size - old_offset) {
/* Do not seek past end of file. */
errno = ESPIPE;
} else if ((new_offset = lseek(mine->fd, skip, SEEK_CUR)) >= 0)
return (new_offset - old_offset);
}
/* If lseek() fails, don't bother trying again. */
mine->use_lseek = 0;
@@ -509,7 +521,7 @@ file_skip_lseek(struct archive *a, void *client_data, int64_t request)
archive_set_error(a, errno, "Error seeking in '%s'",
mine->filename.m);
else
archive_set_error(a, errno, "Error seeking in '%S'",
archive_set_error(a, errno, "Error seeking in '%ls'",
mine->filename.w);
return (-1);
}
@@ -540,11 +552,24 @@ static int64_t
file_seek(struct archive *a, void *client_data, int64_t request, int whence)
{
struct read_file_data *mine = (struct read_file_data *)client_data;
off_t seek = (off_t)request;
int64_t r;
int seek_bits = sizeof(seek) * 8 - 1;
/* We use off_t here because lseek() is declared that way. */
/* See above for notes about when off_t is less than 64 bits. */
r = lseek(mine->fd, request, whence);
/* Reduce a request that would overflow the 'seek' variable. */
if (sizeof(request) > sizeof(seek)) {
const int64_t max_seek =
(((int64_t)1 << (seek_bits - 1)) - 1) * 2 + 1;
const int64_t min_seek = ~max_seek;
if (request > max_seek)
seek = (off_t)max_seek;
else if (request < min_seek)
seek = (off_t)min_seek;
}
r = lseek(mine->fd, seek, whence);
if (r >= 0)
return r;
@@ -555,7 +580,7 @@ file_seek(struct archive *a, void *client_data, int64_t request, int whence)
archive_set_error(a, errno, "Error seeking in '%s'",
mine->filename.m);
else
archive_set_error(a, errno, "Error seeking in '%S'",
archive_set_error(a, errno, "Error seeking in '%ls'",
mine->filename.w);
return (ARCHIVE_FATAL);
}
@@ -37,46 +37,32 @@ archive_read_support_filter_by_code(struct archive *a, int filter_code)
switch (filter_code) {
case ARCHIVE_FILTER_NONE:
return archive_read_support_filter_none(a);
break;
case ARCHIVE_FILTER_GZIP:
return archive_read_support_filter_gzip(a);
break;
case ARCHIVE_FILTER_BZIP2:
return archive_read_support_filter_bzip2(a);
break;
case ARCHIVE_FILTER_COMPRESS:
return archive_read_support_filter_compress(a);
break;
case ARCHIVE_FILTER_LZMA:
return archive_read_support_filter_lzma(a);
break;
case ARCHIVE_FILTER_XZ:
return archive_read_support_filter_xz(a);
break;
case ARCHIVE_FILTER_UU:
return archive_read_support_filter_uu(a);
break;
case ARCHIVE_FILTER_RPM:
return archive_read_support_filter_rpm(a);
break;
case ARCHIVE_FILTER_LZIP:
return archive_read_support_filter_lzip(a);
break;
case ARCHIVE_FILTER_LRZIP:
return archive_read_support_filter_lrzip(a);
break;
case ARCHIVE_FILTER_LZOP:
return archive_read_support_filter_lzop(a);
break;
case ARCHIVE_FILTER_GRZIP:
return archive_read_support_filter_grzip(a);
break;
case ARCHIVE_FILTER_LZ4:
return archive_read_support_filter_lz4(a);
break;
case ARCHIVE_FILTER_ZSTD:
return archive_read_support_filter_zstd(a);
break;
}
return (ARCHIVE_FATAL);
}
@@ -328,6 +328,7 @@ next_code(struct archive_read_filter *self)
static int debug_buff[1024];
static unsigned debug_index;
again:
code = newcode = getbits(self, state->bits);
if (code < 0)
return (code);
@@ -360,7 +361,7 @@ next_code(struct archive_read_filter *self)
state->section_end_code = (1 << state->bits) - 1;
state->free_ent = 257;
state->oldcode = -1;
return (next_code(self));
goto again;
}
if (code > state->free_ent
@@ -323,7 +323,6 @@ lz4_filter_read(struct archive_read_filter *self, const void **p)
archive_set_error(&self->archive->archive,
ARCHIVE_ERRNO_MISC, "Program error.");
return (ARCHIVE_FATAL);
break;
}
while (state->stage == SELECT_STREAM) {
@@ -28,6 +28,9 @@
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#if HAVE_STDINT_H
#include <stdint.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
@@ -50,6 +53,7 @@
#include "archive_ppmd7_private.h"
#include "archive_private.h"
#include "archive_read_private.h"
#include "archive_time_private.h"
#include "archive_endian.h"
#ifndef HAVE_ZLIB_H
@@ -59,7 +63,26 @@
#define _7ZIP_SIGNATURE "7z\xBC\xAF\x27\x1C"
#define SFX_MIN_ADDR 0x27000
#define SFX_MAX_ADDR 0x60000
#define SFX_MAX_OFFSET (SFX_MAX_ADDR - SFX_MIN_ADDR)
/*
* PE format
*/
#define PE_DOS_HDR_LEN 0x40
#define PE_DOS_HDR_ELFANEW_OFFSET 0x3c
#define PE_COFF_HDR_LEN 0x18
#define PE_COFF_HDR_SEC_CNT_OFFSET 0x6
#define PE_COFF_HDR_OPT_SZ_OFFSET 0x14
#define PE_SEC_HDR_LEN 0x28
#define PE_SEC_HDR_RAW_ADDR_OFFSET 0x14
#define PE_SEC_HDR_RAW_SZ_OFFSET 0x10
/*
* ELF format
*/
#define ELF_HDR_MIN_LEN 0x34
#define ELF_HDR_EI_CLASS_OFFSET 0x04
#define ELF_HDR_EI_DATA_OFFSET 0x05
/*
* Codec ID
@@ -83,6 +106,7 @@
#define _7Z_ARM 0x03030501
#define _7Z_ARMTHUMB 0x03030701
#define _7Z_ARM64 0xa
#define _7Z_RISCV 0xb
#define _7Z_SPARC 0x03030805
#define _7Z_ZSTD 0x4F71101 /* Copied from https://github.com/mcmilk/7-Zip-zstd.git */
@@ -144,7 +168,6 @@ struct _7z_digests {
uint32_t *digests;
};
struct _7z_folder {
uint64_t numCoders;
struct _7z_coder {
@@ -224,13 +247,13 @@ struct _7zip_entry {
#define CRC32_IS_SET (1<<3)
#define HAS_STREAM (1<<4)
time_t mtime;
time_t atime;
time_t ctime;
long mtime_ns;
long atime_ns;
long ctime_ns;
uint32_t mode;
int64_t mtime;
int64_t atime;
int64_t ctime;
uint32_t mtime_ns;
uint32_t atime_ns;
uint32_t ctime_ns;
__LA_MODE_T mode;
uint32_t attr;
};
@@ -388,7 +411,6 @@ static int decode_encoded_header_info(struct archive_read *,
static int decompress(struct archive_read *, struct _7zip *,
void *, size_t *, const void *, size_t *);
static ssize_t extract_pack_stream(struct archive_read *, size_t);
static void fileTimeToUtc(uint64_t, time_t *, long *);
static uint64_t folder_uncompressed_size(struct _7z_folder *);
static void free_CodersInfo(struct _7z_coders_info *);
static void free_Digest(struct _7z_digests *);
@@ -424,7 +446,9 @@ static ssize_t read_stream(struct archive_read *, const void **, size_t,
size_t);
static int seek_pack(struct archive_read *);
static int64_t skip_stream(struct archive_read *, size_t);
static int skip_sfx(struct archive_read *, ssize_t);
static int skip_sfx(struct archive_read *, const ssize_t);
static ssize_t find_pe_overlay(struct archive_read *);
static ssize_t find_elf_data_sec(struct archive_read *);
static int slurp_central_directory(struct archive_read *, struct _7zip *,
struct _7z_header_info *);
static int setup_decode_folder(struct archive_read *, struct _7z_folder *,
@@ -435,6 +459,8 @@ static void arm_Init(struct _7zip *);
static size_t arm_Convert(struct _7zip *, uint8_t *, size_t);
static size_t arm64_Convert(struct _7zip *, uint8_t *, size_t);
static ssize_t Bcj2_Decode(struct _7zip *, uint8_t *, size_t);
static size_t sparc_Convert(struct _7zip *, uint8_t *, size_t);
static size_t powerpc_Convert(struct _7zip *, uint8_t *, size_t);
int
@@ -522,15 +548,17 @@ archive_read_format_7zip_bid(struct archive_read *a, int best_bid)
* It may a 7-Zip SFX archive file. If first two bytes are
* 'M' and 'Z' available on Windows or first four bytes are
* "\x7F\x45LF" available on posix like system, seek the 7-Zip
* signature. Although we will perform a seek when reading
* a header, what we do not use __archive_read_seek() here is
* due to a bidding performance.
* signature. While find_pe_overlay can be performed without
* performing a seek, find_elf_data_sec requires one,
* thus a performance difference between the two is expected.
*/
if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) {
ssize_t offset = SFX_MIN_ADDR;
const ssize_t min_addr = p[0] == 'M' ? find_pe_overlay(a) :
find_elf_data_sec(a);
ssize_t offset = min_addr;
ssize_t window = 4096;
ssize_t bytes_avail;
while (offset + window <= (SFX_MAX_ADDR)) {
while (offset + window <= (min_addr + SFX_MAX_OFFSET)) {
const char *buff = __archive_read_ahead(a,
offset + window, &bytes_avail);
if (buff == NULL) {
@@ -580,21 +608,14 @@ check_7zip_header_in_sfx(const char *p)
}
static int
skip_sfx(struct archive_read *a, ssize_t bytes_avail)
skip_sfx(struct archive_read *a, const ssize_t min_addr)
{
const void *h;
const char *p, *q;
size_t skip, offset;
ssize_t bytes, window;
/*
* If bytes_avail > SFX_MIN_ADDR we do not have to call
* __archive_read_seek() at this time since we have
* already had enough data.
*/
if (bytes_avail > SFX_MIN_ADDR)
__archive_read_consume(a, SFX_MIN_ADDR);
else if (__archive_read_seek(a, SFX_MIN_ADDR, SEEK_SET) < 0)
if (__archive_read_seek(a, min_addr, SEEK_SET) < 0)
return (ARCHIVE_FATAL);
offset = 0;
@@ -627,7 +648,7 @@ skip_sfx(struct archive_read *a, ssize_t bytes_avail)
(struct _7zip *)a->format->data;
skip = p - (const char *)h;
__archive_read_consume(a, skip);
zip->seek_base = SFX_MIN_ADDR + offset + skip;
zip->seek_base = min_addr + offset + skip;
return (ARCHIVE_OK);
}
p += step;
@@ -644,6 +665,207 @@ fatal:
return (ARCHIVE_FATAL);
}
static ssize_t
find_pe_overlay(struct archive_read *a)
{
const char *h;
ssize_t bytes, max_offset, offset, sec_end;
ssize_t opt_hdr_sz, sec_cnt;
for (;;) {
/*
* Read Dos header to find e_lfanew
*/
h = __archive_read_ahead(a, PE_DOS_HDR_LEN, &bytes);
if (h == NULL || h[0] != 'M' || h[1] != 'Z') {
break;
}
offset = archive_le32dec(h + PE_DOS_HDR_ELFANEW_OFFSET);
/*
* Read COFF header to find opt header size and sec cnt
*/
if (bytes < offset + PE_COFF_HDR_LEN) {
h = __archive_read_ahead(a, offset + PE_COFF_HDR_LEN,
&bytes);
if (h == NULL || h[offset] != 'P' ||
h[offset + 1] != 'E') {
break;
}
}
sec_cnt = archive_le16dec(
h + offset + PE_COFF_HDR_SEC_CNT_OFFSET);
opt_hdr_sz = archive_le16dec(
h + offset + PE_COFF_HDR_OPT_SZ_OFFSET);
/*
* Skip optional header
*/
if (opt_hdr_sz != 0) {
offset += PE_COFF_HDR_LEN + opt_hdr_sz;
} else {
break;
}
/*
* Traverse sec table to find max raw offset (i.e., overlay)
*/
if (bytes < offset + sec_cnt * PE_SEC_HDR_LEN) {
h = __archive_read_ahead(a,
offset + sec_cnt * PE_SEC_HDR_LEN, NULL);
if (h == NULL) {
break;
}
}
max_offset = offset;
while (sec_cnt > 0) {
sec_end = archive_le32dec(
h + offset + PE_SEC_HDR_RAW_SZ_OFFSET) +
archive_le32dec(
h + offset + PE_SEC_HDR_RAW_ADDR_OFFSET);
if (sec_end > max_offset) {
max_offset = sec_end;
}
offset += PE_SEC_HDR_LEN;
sec_cnt--;
}
return (max_offset);
}
/*
* If encounter any weirdness, revert to old brute-force style search
*/
return (SFX_MIN_ADDR);
}
static ssize_t
find_elf_data_sec(struct archive_read *a)
{
const char *h;
char big_endian, format_64;
ssize_t bytes, min_addr = SFX_MIN_ADDR;
uint64_t e_shoff, strtab_offset, strtab_size;
uint16_t e_shentsize, e_shnum, e_shstrndx;
uint16_t (*dec16)(const void *);
uint32_t (*dec32)(const void *);
uint64_t (*dec64)(const void *);
for (;;) {
/*
* Read Elf header to find bitness & endianness
*/
h = __archive_read_ahead(a, ELF_HDR_MIN_LEN, &bytes);
if (h == NULL || memcmp(h, "\x7F\x45LF", 4) != 0) {
break;
}
format_64 = h[ELF_HDR_EI_CLASS_OFFSET] == 0x2;
big_endian = h[ELF_HDR_EI_DATA_OFFSET] == 0x2;
if (big_endian) {
dec16 = &archive_be16dec;
dec32 = &archive_be32dec;
dec64 = &archive_be64dec;
} else {
dec16 = &archive_le16dec;
dec32 = &archive_le32dec;
dec64 = &archive_le64dec;
}
/*
* Read section header table info
*/
if (format_64) {
e_shoff = (*dec64)(h + 0x28);
e_shentsize = (*dec16)(h + 0x3A);
e_shnum = (*dec16)(h + 0x3C);
e_shstrndx = (*dec16)(h + 0x3E);
if (e_shnum < e_shstrndx || e_shentsize < 0x28)
break;
} else {
e_shoff = (*dec32)(h + 0x20);
e_shentsize = (*dec16)(h + 0x2E);
e_shnum = (*dec16)(h + 0x30);
e_shstrndx = (*dec16)(h + 0x32);
if (e_shnum < e_shstrndx || e_shentsize < 0x18)
break;
}
/*
* Reading the section table to find strtab section
*/
if (__archive_read_seek(a, e_shoff, SEEK_SET) < 0) {
break;
}
h = __archive_read_ahead(a, (size_t)e_shnum * (size_t)e_shentsize, NULL);
if (h == NULL) {
break;
}
if (format_64) {
strtab_offset = (*dec64)(
h + e_shstrndx * e_shentsize + 0x18);
strtab_size = (*dec64)(
h + e_shstrndx * e_shentsize + 0x20);
} else {
strtab_offset = (*dec32)(
h + e_shstrndx * e_shentsize + 0x10);
strtab_size = (*dec32)(
h + e_shstrndx * e_shentsize + 0x14);
}
/*
* Read the STRTAB section to find the .data offset
*/
if (__archive_read_seek(a, strtab_offset, SEEK_SET) < 0) {
break;
}
h = __archive_read_ahead(a, strtab_size, NULL);
if (h == NULL) {
break;
}
ssize_t data_sym_offset = -1;
for (size_t offset = 0; offset < strtab_size - 6; offset++) {
if (memcmp(h + offset, ".data\00", 6) == 0) {
data_sym_offset = offset;
break;
}
}
if (data_sym_offset == -1) {
break;
}
/*
* Find the section with the .data name
*/
if (__archive_read_seek(a, e_shoff, SEEK_SET) < 0) {
break;
}
h = __archive_read_ahead(a, (size_t)e_shnum * (size_t)e_shentsize, NULL);
if (h == NULL) {
break;
}
ssize_t sec_tbl_offset = 0, name_offset;
while (e_shnum > 0) {
name_offset = (*dec32)(h + sec_tbl_offset);
if (name_offset == data_sym_offset) {
if (format_64) {
min_addr = (*dec64)(
h + sec_tbl_offset + 0x18);
} else {
min_addr = (*dec32)(
h + sec_tbl_offset + 0x10);
}
break;
}
sec_tbl_offset += e_shentsize;
e_shnum--;
}
break;
}
__archive_read_seek(a, 0, SEEK_SET);
return (min_addr);
}
static int
archive_read_format_7zip_read_header(struct archive_read *a,
struct archive_entry *entry)
@@ -770,7 +992,7 @@ archive_read_format_7zip_read_header(struct archive_read *a,
/* allocate for ",rdonly,hidden,system" */
fflags_text = malloc(22 * sizeof(*fflags_text));
if (fflags_text != NULL) {
ptr = fflags_text;
ptr = fflags_text;
if (zip_entry->attr & FILE_ATTRIBUTE_READONLY) {
strcpy(ptr, ",rdonly");
ptr = ptr + 7;
@@ -1109,7 +1331,9 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
if (coder2->codec != _7Z_X86 &&
coder2->codec != _7Z_X86_BCJ2 &&
coder2->codec != _7Z_ARM &&
coder2->codec != _7Z_ARM64) {
coder2->codec != _7Z_ARM64 &&
coder2->codec != _7Z_POWERPC &&
coder2->codec != _7Z_SPARC) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
"Unsupported filter %lx for %lx",
@@ -1223,6 +1447,12 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
filters[fi].id = LZMA_FILTER_ARM64;
fi++;
break;
#endif
#ifdef LZMA_FILTER_RISCV
case _7Z_RISCV:
filters[fi].id = LZMA_FILTER_RISCV;
fi++;
break;
#endif
case _7Z_SPARC:
filters[fi].id = LZMA_FILTER_SPARC;
@@ -1396,6 +1626,7 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
case _7Z_ARM:
case _7Z_ARMTHUMB:
case _7Z_ARM64:
case _7Z_RISCV:
case _7Z_SPARC:
case _7Z_DELTA:
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
@@ -1708,6 +1939,10 @@ decompress(struct archive_read *a, struct _7zip *zip,
*outbytes = arm_Convert(zip, buff, *outbytes);
} else if (zip->codec2 == _7Z_ARM64) {
*outbytes = arm64_Convert(zip, buff, *outbytes);
} else if (zip->codec2 == _7Z_SPARC) {
*outbytes = sparc_Convert(zip, buff, *outbytes);
} else if (zip->codec2 == _7Z_POWERPC) {
*outbytes = powerpc_Convert(zip, buff, *outbytes);
}
}
@@ -2841,23 +3076,6 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
return (0);
}
#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
static void
fileTimeToUtc(uint64_t fileTime, time_t *timep, long *ns)
{
if (fileTime >= EPOC_TIME) {
fileTime -= EPOC_TIME;
/* milli seconds base */
*timep = (time_t)(fileTime / 10000000);
/* nano seconds base */
*ns = (long)(fileTime % 10000000) * 100;
} else {
*timep = 0;
*ns = 0;
}
}
static int
read_Times(struct archive_read *a, struct _7z_header_info *h, int type)
{
@@ -2900,19 +3118,19 @@ read_Times(struct archive_read *a, struct _7z_header_info *h, int type)
goto failed;
switch (type) {
case kCTime:
fileTimeToUtc(archive_le64dec(p),
ntfs_to_unix(archive_le64dec(p),
&(entries[i].ctime),
&(entries[i].ctime_ns));
entries[i].flg |= CTIME_IS_SET;
break;
case kATime:
fileTimeToUtc(archive_le64dec(p),
ntfs_to_unix(archive_le64dec(p),
&(entries[i].atime),
&(entries[i].atime_ns));
entries[i].flg |= ATIME_IS_SET;
break;
case kMTime:
fileTimeToUtc(archive_le64dec(p),
ntfs_to_unix(archive_le64dec(p),
&(entries[i].mtime),
&(entries[i].mtime_ns));
entries[i].flg |= MTIME_IS_SET;
@@ -3007,7 +3225,9 @@ slurp_central_directory(struct archive_read *a, struct _7zip *zip,
if ((p[0] == 'M' && p[1] == 'Z') || memcmp(p, "\x7F\x45LF", 4) == 0) {
/* This is an executable ? Must be self-extracting... */
r = skip_sfx(a, bytes_avail);
const ssize_t min_addr = p[0] == 'M' ? find_pe_overlay(a) :
find_elf_data_sec(a);
r = skip_sfx(a, min_addr);
if (r < ARCHIVE_WARN)
return (r);
if ((p = __archive_read_ahead(a, 32, &bytes_avail)) == NULL)
@@ -4007,6 +4227,121 @@ arm64_Convert(struct _7zip *zip, uint8_t *buf, size_t size)
return i;
}
static size_t
sparc_Convert(struct _7zip *zip, uint8_t *buf, size_t size)
{
// This function was adapted from
// static size_t bcj_sparc(struct xz_dec_bcj *s, uint8_t *buf, size_t size)
// in https://git.tukaani.org/xz-embedded.git
/*
* Branch/Call/Jump (BCJ) filter decoders
*
* Authors: Lasse Collin <lasse.collin@tukaani.org>
* Igor Pavlov <https://7-zip.org/>
*
* Copyright (C) The XZ Embedded authors and contributors
*
* Permission to use, copy, modify, and/or distribute this
* software for any purpose with or without fee is hereby granted.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
size_t i;
uint32_t instr;
size &= ~(size_t)3;
for (i = 0; i < size; i += 4) {
instr = (uint32_t)(buf[i] << 24)
| ((uint32_t)buf[i+1] << 16)
| ((uint32_t)buf[i+2] << 8)
| (uint32_t)buf[i+3];
if ((instr >> 22) == 0x100 || (instr >> 22) == 0x1FF) {
instr <<= 2;
instr -= zip->bcj_ip + (uint32_t)i;
instr >>= 2;
instr = ((uint32_t)0x40000000 - (instr & 0x400000))
| 0x40000000 | (instr & 0x3FFFFF);
buf[i] = (uint8_t)(instr >> 24);
buf[i+1] = (uint8_t)(instr >> 16);
buf[i+2] = (uint8_t)(instr >> 8);
buf[i+3] = (uint8_t)instr;
}
}
zip->bcj_ip += (uint32_t)i;
return i;
}
static size_t
powerpc_Convert(struct _7zip *zip, uint8_t *buf, size_t size)
{
// This function was adapted from
// static size_t powerpc_code(void *simple, uint32_t now_pos, bool is_encoder, uint8_t *buffer, size_t size)
// in https://git.tukaani.org/xz.git
/*
* Filter for PowerPC (big endian) binaries
*
* Authors: Igor Pavlov
* Lasse Collin
*
* Copyright (C) The XZ Utils authors and contributors
*
* Permission to use, copy, modify, and/or distribute this
* software for any purpose with or without fee is hereby granted.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
size &= ~(size_t)3;
size_t i;
for (i = 0; i < size; i += 4) {
// PowerPC branch 6(48) 24(Offset) 1(Abs) 1(Link)
if ((buf[i] >> 2) == 0x12
&& ((buf[i + 3] & 3) == 1)) {
const uint32_t src
= (((uint32_t)(buf[i + 0]) & 3) << 24)
| ((uint32_t)(buf[i + 1]) << 16)
| ((uint32_t)(buf[i + 2]) << 8)
| ((uint32_t)(buf[i + 3]) & ~UINT32_C(3));
uint32_t dest = src - (zip->bcj_ip + (uint32_t)(i));
buf[i + 0] = 0x48 | ((dest >> 24) & 0x03);
buf[i + 1] = (dest >> 16);
buf[i + 2] = (dest >> 8);
buf[i + 3] &= 0x03;
buf[i + 3] |= dest;
}
}
zip->bcj_ip += (uint32_t)i;
return i;
}
/*
* Brought from LZMA SDK.
*
@@ -4029,8 +4364,17 @@ arm64_Convert(struct _7zip *zip, uint8_t *buf, size_t size)
#define RC_READ_BYTE (*buffer++)
#define RC_TEST { if (buffer == bufferLim) return SZ_ERROR_DATA; }
#define RC_INIT2 zip->bcj2_code = 0; zip->bcj2_range = 0xFFFFFFFF; \
{ int ii; for (ii = 0; ii < 5; ii++) { RC_TEST; zip->bcj2_code = (zip->bcj2_code << 8) | RC_READ_BYTE; }}
#define RC_INIT2 do { \
zip->bcj2_code = 0; \
zip->bcj2_range = 0xFFFFFFFF; \
{ \
int ii; \
for (ii = 0; ii < 5; ii++) { \
RC_TEST; \
zip->bcj2_code = (zip->bcj2_code << 8) | RC_READ_BYTE; \
} \
} \
} while (0)
#define NORMALIZE if (zip->bcj2_range < kTopValue) { RC_TEST; zip->bcj2_range <<= 8; zip->bcj2_code = (zip->bcj2_code << 8) | RC_READ_BYTE; }
@@ -4177,4 +4521,3 @@ Bcj2_Decode(struct _7zip *zip, uint8_t *outBuf, size_t outSize)
return ((ssize_t)outPos);
}
@@ -41,49 +41,34 @@ archive_read_support_format_by_code(struct archive *a, int format_code)
switch (format_code & ARCHIVE_FORMAT_BASE_MASK) {
case ARCHIVE_FORMAT_7ZIP:
return archive_read_support_format_7zip(a);
break;
case ARCHIVE_FORMAT_AR:
return archive_read_support_format_ar(a);
break;
case ARCHIVE_FORMAT_CAB:
return archive_read_support_format_cab(a);
break;
case ARCHIVE_FORMAT_CPIO:
return archive_read_support_format_cpio(a);
break;
case ARCHIVE_FORMAT_EMPTY:
return archive_read_support_format_empty(a);
break;
case ARCHIVE_FORMAT_ISO9660:
return archive_read_support_format_iso9660(a);
break;
case ARCHIVE_FORMAT_LHA:
return archive_read_support_format_lha(a);
break;
case ARCHIVE_FORMAT_MTREE:
return archive_read_support_format_mtree(a);
break;
case ARCHIVE_FORMAT_RAR:
return archive_read_support_format_rar(a);
break;
case ARCHIVE_FORMAT_RAR_V5:
return archive_read_support_format_rar5(a);
break;
case ARCHIVE_FORMAT_RAW:
return archive_read_support_format_raw(a);
break;
case ARCHIVE_FORMAT_TAR:
return archive_read_support_format_tar(a);
break;
case ARCHIVE_FORMAT_WARC:
return archive_read_support_format_warc(a);
break;
case ARCHIVE_FORMAT_XAR:
return archive_read_support_format_xar(a);
break;
case ARCHIVE_FORMAT_ZIP:
return archive_read_support_format_zip(a);
break;
}
archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
"Invalid format code specified");
@@ -363,7 +363,12 @@ archive_read_support_format_cab(struct archive *_a)
return (ARCHIVE_FATAL);
}
archive_string_init(&cab->ws);
archive_wstring_ensure(&cab->ws, 256);
if (archive_wstring_ensure(&cab->ws, 256) == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate memory");
free(cab);
return (ARCHIVE_FATAL);
}
r = __archive_read_register_format(a,
cab,
@@ -189,6 +189,7 @@ struct cpio {
};
static int64_t atol16(const char *, unsigned);
static uint64_t atol16u(const char *, unsigned);
static int64_t atol8(const char *, unsigned);
static int archive_read_format_cpio_bid(struct archive_read *, int);
static int archive_read_format_cpio_options(struct archive_read *,
@@ -835,6 +836,7 @@ header_afiol(struct archive_read *a, struct cpio *cpio,
struct archive_entry *entry, size_t *namelength, size_t *name_pad)
{
int64_t t;
uint64_t u;
const void *h;
const char *header;
@@ -851,12 +853,12 @@ header_afiol(struct archive_read *a, struct cpio *cpio,
archive_entry_set_dev(entry,
(dev_t)atol16(header + afiol_dev_offset, afiol_dev_size));
t = atol16(header + afiol_ino_offset, afiol_ino_size);
if (t < 0) {
archive_set_error(&a->archive, 0, "Nonsensical ino value");
return (ARCHIVE_FATAL);
}
archive_entry_set_ino(entry, t);
u = atol16u(header + afiol_ino_offset, afiol_ino_size);
#if ARCHIVE_VERSION_NUMBER < 4000000
archive_entry_set_ino(entry, (int64_t)(u & INT64_MAX));
#else
archive_entry_set_ino(entry, u);
#endif
archive_entry_set_mode(entry,
(mode_t)atol8(header + afiol_mode_offset, afiol_mode_size));
archive_entry_set_uid(entry, atol16(header + afiol_uid_offset, afiol_uid_size));
@@ -1030,6 +1032,12 @@ atol8(const char *p, unsigned char_cnt)
static int64_t
atol16(const char *p, unsigned char_cnt)
{
return ((int64_t)atol16u(p, char_cnt));
}
static uint64_t
atol16u(const char *p, unsigned char_cnt)
{
uint64_t l;
int digit;
@@ -1048,7 +1056,7 @@ atol16(const char *p, unsigned char_cnt)
l <<= 4;
l |= digit;
}
return ((int64_t)l);
return (l);
}
static int
@@ -1429,7 +1429,7 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
* information first, then store all file bodies. */
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Ignoring out-of-order file @%jx (%s) %jd < %jd",
(intmax_t)file->number,
(uintmax_t)file->number,
iso9660->pathname.s,
(intmax_t)file->offset,
(intmax_t)iso9660->current_position);
@@ -2273,7 +2273,7 @@ parse_rockridge(struct archive_read *a, struct file_info *file,
if (version == 1) {
if (data_length >= 8)
file->mode
= toi(data, 4);
= (__LA_MODE_T)toi(data, 4);
if (data_length >= 16)
file->nlinks
= toi(data + 8, 4);
@@ -43,6 +43,7 @@
#include "archive_entry_locale.h"
#include "archive_private.h"
#include "archive_read_private.h"
#include "archive_time_private.h"
#include "archive_endian.h"
@@ -162,12 +163,12 @@ struct lha {
#define ATIME_IS_SET 2
#define UNIX_MODE_IS_SET 4
#define CRC_IS_SET 8
time_t birthtime;
long birthtime_tv_nsec;
time_t mtime;
long mtime_tv_nsec;
time_t atime;
long atime_tv_nsec;
int64_t birthtime;
uint32_t birthtime_tv_nsec;
int64_t mtime;
uint32_t mtime_tv_nsec;
int64_t atime;
uint32_t atime_tv_nsec;
mode_t mode;
int64_t uid;
int64_t gid;
@@ -230,8 +231,6 @@ static int lha_read_file_extended_header(struct archive_read *,
struct lha *, uint16_t *, int, uint64_t, size_t *);
static size_t lha_check_header_format(const void *);
static int lha_skip_sfx(struct archive_read *);
static time_t lha_dos_time(const unsigned char *);
static time_t lha_win_time(uint64_t, long *);
static unsigned char lha_calcsum(unsigned char, const void *,
int, size_t);
static int lha_parse_linkname(struct archive_wstring *,
@@ -819,7 +818,7 @@ lha_read_file_header_0(struct archive_read *a, struct lha *lha)
headersum = p[H0_HEADER_SUM_OFFSET];
lha->compsize = archive_le32dec(p + H0_COMP_SIZE_OFFSET);
lha->origsize = archive_le32dec(p + H0_ORIG_SIZE_OFFSET);
lha->mtime = lha_dos_time(p + H0_DOS_TIME_OFFSET);
lha->mtime = dos_to_unix(archive_le32dec(p + H0_DOS_TIME_OFFSET));
namelen = p[H0_NAME_LEN_OFFSET];
extdsize = (int)lha->header_size - H0_FIXED_SIZE - namelen;
if ((namelen > 221 || extdsize < 0) && extdsize != -2) {
@@ -919,7 +918,7 @@ lha_read_file_header_1(struct archive_read *a, struct lha *lha)
/* Note: An extended header size is included in a compsize. */
lha->compsize = archive_le32dec(p + H1_COMP_SIZE_OFFSET);
lha->origsize = archive_le32dec(p + H1_ORIG_SIZE_OFFSET);
lha->mtime = lha_dos_time(p + H1_DOS_TIME_OFFSET);
lha->mtime = dos_to_unix(archive_le32dec(p + H1_DOS_TIME_OFFSET));
namelen = p[H1_NAME_LEN_OFFSET];
/* Calculate a padding size. The result will be normally 0 only(?) */
padding = ((int)lha->header_size) - H1_FIXED_SIZE - namelen;
@@ -1090,7 +1089,7 @@ lha_read_file_header_3(struct archive_read *a, struct lha *lha)
if (archive_le16dec(p + H3_FIELD_LEN_OFFSET) != 4)
goto invalid;
lha->header_size =archive_le32dec(p + H3_HEADER_SIZE_OFFSET);
lha->header_size = archive_le32dec(p + H3_HEADER_SIZE_OFFSET);
lha->compsize = archive_le32dec(p + H3_COMP_SIZE_OFFSET);
lha->origsize = archive_le32dec(p + H3_ORIG_SIZE_OFFSET);
lha->mtime = archive_le32dec(p + H3_TIME_OFFSET);
@@ -1326,16 +1325,16 @@ lha_read_file_extended_header(struct archive_read *a, struct lha *lha,
break;
case EXT_TIMESTAMP:
if (datasize == (sizeof(uint64_t) * 3)) {
lha->birthtime = lha_win_time(
archive_le64dec(extdheader),
ntfs_to_unix(archive_le64dec(extdheader),
&lha->birthtime,
&lha->birthtime_tv_nsec);
extdheader += sizeof(uint64_t);
lha->mtime = lha_win_time(
archive_le64dec(extdheader),
ntfs_to_unix(archive_le64dec(extdheader),
&lha->mtime,
&lha->mtime_tv_nsec);
extdheader += sizeof(uint64_t);
lha->atime = lha_win_time(
archive_le64dec(extdheader),
ntfs_to_unix(archive_le64dec(extdheader),
&lha->atime,
&lha->atime_tv_nsec);
lha->setflag |= BIRTHTIME_IS_SET |
ATIME_IS_SET;
@@ -1716,45 +1715,6 @@ lha_parse_linkname(struct archive_wstring *linkname,
return (0);
}
/* Convert an MSDOS-style date/time into Unix-style time. */
static time_t
lha_dos_time(const unsigned char *p)
{
int msTime, msDate;
struct tm ts;
msTime = archive_le16dec(p);
msDate = archive_le16dec(p+2);
memset(&ts, 0, sizeof(ts));
ts.tm_year = ((msDate >> 9) & 0x7f) + 80; /* Years since 1900. */
ts.tm_mon = ((msDate >> 5) & 0x0f) - 1; /* Month number. */
ts.tm_mday = msDate & 0x1f; /* Day of month. */
ts.tm_hour = (msTime >> 11) & 0x1f;
ts.tm_min = (msTime >> 5) & 0x3f;
ts.tm_sec = (msTime << 1) & 0x3e;
ts.tm_isdst = -1;
return (mktime(&ts));
}
/* Convert an MS-Windows-style date/time into Unix-style time. */
static time_t
lha_win_time(uint64_t wintime, long *ns)
{
#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
if (wintime >= EPOC_TIME) {
wintime -= EPOC_TIME; /* 1970-01-01 00:00:00 (UTC) */
if (ns != NULL)
*ns = (long)(wintime % 10000000) * 100;
return (wintime / 10000000);
} else {
if (ns != NULL)
*ns = 0;
return (0);
}
}
static unsigned char
lha_calcsum(unsigned char sum, const void *pp, int offset, size_t size)
{
@@ -2917,4 +2877,3 @@ lzh_decode_huffman(struct huffman *hf, unsigned rbits)
/* This bit pattern needs to be found out at a huffman tree. */
return (lzh_decode_huffman_tree(hf, rbits, c));
}
@@ -335,8 +335,8 @@ struct rar
int found_first_header;
char has_endarc_header;
struct data_block_offsets *dbo;
unsigned int cursor;
unsigned int nodes;
size_t cursor;
size_t nodes;
char filename_must_match;
/* LZSS members */
@@ -451,7 +451,7 @@ static int read_filter(struct archive_read *, int64_t *);
static int rar_decode_byte(struct archive_read*, uint8_t *);
static int execute_filter(struct archive_read*, struct rar_filter *,
struct rar_virtual_machine *, size_t);
static int copy_from_lzss_window(struct archive_read *, void *, int64_t, int);
static int copy_from_lzss_window(struct archive_read *, uint8_t *, int64_t, int);
static inline void vm_write_32(struct rar_virtual_machine*, size_t, uint32_t);
static inline uint32_t vm_read_32(struct rar_virtual_machine*, size_t);
@@ -475,7 +475,7 @@ static inline uint32_t vm_read_32(struct rar_virtual_machine*, size_t);
((rar_br_has(br, (n)) || rar_br_fillup(a, br)) || rar_br_has(br, (n)))
/* Notify how many bits we consumed. */
#define rar_br_consume(br, n) ((br)->cache_avail -= (n))
#define rar_br_consume_unalined_bits(br) ((br)->cache_avail &= ~7)
#define rar_br_consume_unaligned_bits(br) ((br)->cache_avail &= ~7)
static const uint32_t cache_masks[] = {
0x00000000, 0x00000001, 0x00000003, 0x00000007,
@@ -741,11 +741,11 @@ archive_read_support_format_rar(struct archive *_a)
return (ARCHIVE_FATAL);
}
/*
* Until enough data has been read, we cannot tell about
* any encrypted entries yet.
*/
rar->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;
/*
* Until enough data has been read, we cannot tell about
* any encrypted entries yet.
*/
rar->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;
r = __archive_read_register_format(a,
rar,
@@ -768,21 +768,21 @@ archive_read_support_format_rar(struct archive *_a)
static int
archive_read_support_format_rar_capabilities(struct archive_read * a)
{
(void)a; /* UNUSED */
return (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA
| ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA);
(void)a; /* UNUSED */
return (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA
| ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA);
}
static int
archive_read_format_rar_has_encrypted_entries(struct archive_read *_a)
{
if (_a && _a->format) {
struct rar * rar = (struct rar *)_a->format->data;
if (rar) {
return rar->has_encrypted_entries;
}
}
return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;
if (_a && _a->format) {
struct rar * rar = (struct rar *)_a->format->data;
if (rar) {
return rar->has_encrypted_entries;
}
}
return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;
}
@@ -793,7 +793,7 @@ archive_read_format_rar_bid(struct archive_read *a, int best_bid)
/* If there's already a bid > 30, we'll never win. */
if (best_bid > 30)
return (-1);
return (-1);
if ((p = __archive_read_ahead(a, 7, NULL)) == NULL)
return (-1);
@@ -865,7 +865,7 @@ skip_sfx(struct archive_read *a)
}
skip = p - (const char *)h;
__archive_read_consume(a, skip);
total += skip;
total += skip;
}
fatal:
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
@@ -910,7 +910,7 @@ archive_read_format_rar_read_header(struct archive_read *a,
const void *h;
const char *p;
struct rar *rar;
size_t skip;
int64_t skip;
char head_type;
int ret;
unsigned flags;
@@ -930,7 +930,7 @@ archive_read_format_rar_read_header(struct archive_read *a,
* as well.
*/
if (rar->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {
rar->has_encrypted_entries = 0;
rar->has_encrypted_entries = 0;
}
/* RAR files can be generated without EOF headers, so return ARCHIVE_EOF if
@@ -953,8 +953,11 @@ archive_read_format_rar_read_header(struct archive_read *a,
{
unsigned long crc32_val;
if ((h = __archive_read_ahead(a, 7, NULL)) == NULL)
if ((h = __archive_read_ahead(a, 7, NULL)) == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Failed to read next header.");
return (ARCHIVE_FATAL);
}
p = h;
head_type = p[2];
@@ -972,7 +975,7 @@ archive_read_format_rar_read_header(struct archive_read *a,
case MAIN_HEAD:
rar->main_flags = archive_le16dec(p + 3);
skip = archive_le16dec(p + 5);
if (skip < 7 + sizeof(rar->reserved1) + sizeof(rar->reserved2)) {
if ((size_t)skip < 7 + sizeof(rar->reserved1) + sizeof(rar->reserved2)) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Invalid header size");
return (ARCHIVE_FATAL);
@@ -984,7 +987,8 @@ archive_read_format_rar_read_header(struct archive_read *a,
memcpy(rar->reserved2, p + 7 + sizeof(rar->reserved1),
sizeof(rar->reserved2));
if (rar->main_flags & MHD_ENCRYPTVER) {
if (skip < 7 + sizeof(rar->reserved1) + sizeof(rar->reserved2)+1) {
if ((size_t)skip <
7 + sizeof(rar->reserved1) + sizeof(rar->reserved2) + 1) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Invalid header size");
return (ARCHIVE_FATAL);
@@ -1053,28 +1057,30 @@ archive_read_format_rar_read_header(struct archive_read *a,
/* Skim the entire header and compute the CRC. */
crc32_val = 0;
while (skip > 0) {
size_t to_read = skip;
if (to_read > 32 * 1024)
to_read = 32 * 1024;
if ((h = __archive_read_ahead(a, to_read, NULL)) == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Bad RAR file");
return (ARCHIVE_FATAL);
}
p = h;
crc32_val = crc32(crc32_val, (const unsigned char *)p, (unsigned int)to_read);
__archive_read_consume(a, to_read);
skip -= to_read;
unsigned to_read;
if (skip > 32 * 1024)
to_read = 32 * 1024;
else
to_read = (unsigned)skip;
if ((h = __archive_read_ahead(a, to_read, NULL)) == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Bad RAR file");
return (ARCHIVE_FATAL);
}
p = h;
crc32_val = crc32(crc32_val, (const unsigned char *)p, to_read);
__archive_read_consume(a, to_read);
skip -= to_read;
}
if ((crc32_val & 0xffff) != crc32_expected) {
#ifndef DONT_FAIL_ON_CRC_ERROR
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Header CRC error");
return (ARCHIVE_FATAL);
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Header CRC error");
return (ARCHIVE_FATAL);
#endif
}
if (head_type == ENDARC_HEAD)
return (ARCHIVE_EOF);
return (ARCHIVE_EOF);
break;
case NEWSUB_HEAD:
@@ -1083,7 +1089,7 @@ archive_read_format_rar_read_header(struct archive_read *a,
break;
default:
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Bad RAR file");
return (ARCHIVE_FATAL);
}
@@ -1098,7 +1104,7 @@ archive_read_format_rar_read_data(struct archive_read *a, const void **buff,
int ret;
if (rar->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {
rar->has_encrypted_entries = 0;
rar->has_encrypted_entries = 0;
}
if (rar->bytes_unconsumed > 0) {
@@ -1186,7 +1192,7 @@ archive_read_format_rar_seek_data(struct archive_read *a, int64_t offset,
int whence)
{
int64_t client_offset, ret;
unsigned int i;
size_t i;
struct rar *rar = (struct rar *)(a->format->data);
if (rar->compression_method == COMPRESS_METHOD_STORE)
@@ -1433,7 +1439,11 @@ read_header(struct archive_read *a, struct archive_entry *entry,
}
if ((h = __archive_read_ahead(a, (size_t)header_size - 7, NULL)) == NULL)
{
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Failed to read full header content.");
return (ARCHIVE_FATAL);
}
/* File Header CRC check. */
crc32_computed = crc32(crc32_computed, h, (unsigned)(header_size - 7));
@@ -1460,8 +1470,8 @@ read_header(struct archive_read *a, struct archive_entry *entry,
if (rar->file_flags & FHD_PASSWORD)
{
archive_entry_set_is_data_encrypted(entry, 1);
rar->has_encrypted_entries = 1;
archive_entry_set_is_data_encrypted(entry, 1);
rar->has_encrypted_entries = 1;
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"RAR encryption support unavailable.");
/* Since it is only the data part itself that is encrypted we can at least
@@ -1506,10 +1516,23 @@ read_header(struct archive_read *a, struct archive_entry *entry,
*/
if (head_type == NEWSUB_HEAD) {
size_t distance = p - (const char *)h;
if (rar->packed_size > INT64_MAX - header_size) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Extended header size too large.");
return (ARCHIVE_FATAL);
}
header_size += rar->packed_size;
if ((uintmax_t)header_size > SIZE_MAX) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Unable to read extended header data.");
return (ARCHIVE_FATAL);
}
/* Make sure we have the extended data. */
if ((h = __archive_read_ahead(a, (size_t)header_size - 7, NULL)) == NULL)
return (ARCHIVE_FATAL);
if ((h = __archive_read_ahead(a, (size_t)header_size - 7, NULL)) == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Failed to read extended header data.");
return (ARCHIVE_FATAL);
}
p = h;
endp = p + header_size - 7;
p += distance;
@@ -1670,6 +1693,8 @@ read_header(struct archive_read *a, struct archive_entry *entry,
!memcmp(rar->filename, rar->filename_save, filename_size + 1))
{
__archive_read_consume(a, header_size - 7);
rar->br.avail_in = 0;
rar->br.next_in = NULL;
rar->cursor++;
if (rar->cursor >= rar->nodes)
{
@@ -1689,6 +1714,12 @@ read_header(struct archive_read *a, struct archive_entry *entry,
}
if (rar->dbo[rar->cursor].start_offset < 0)
{
if (rar->packed_size > INT64_MAX - a->filter->position)
{
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Unable to store offsets.");
return (ARCHIVE_FATAL);
}
rar->dbo[rar->cursor].start_offset = a->filter->position;
rar->dbo[rar->cursor].end_offset = rar->dbo[rar->cursor].start_offset +
rar->packed_size;
@@ -1745,6 +1776,11 @@ read_header(struct archive_read *a, struct archive_entry *entry,
}
__archive_read_consume(a, header_size - 7);
if (rar->packed_size > INT64_MAX - a->filter->position) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Unable to store offsets.");
return (ARCHIVE_FATAL);
}
rar->dbo[0].start_offset = a->filter->position;
rar->dbo[0].end_offset = rar->dbo[0].start_offset + rar->packed_size;
@@ -1753,7 +1789,7 @@ read_header(struct archive_read *a, struct archive_entry *entry,
case OS_MSDOS:
case OS_OS2:
case OS_WIN32:
rar->mode = archive_le32dec(file_header.file_attr);
rar->mode = (__LA_MODE_T)archive_le32dec(file_header.file_attr);
if (rar->mode & FILE_ATTRIBUTE_DIRECTORY)
rar->mode = AE_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
else
@@ -1764,7 +1800,7 @@ read_header(struct archive_read *a, struct archive_entry *entry,
case OS_UNIX:
case OS_MAC_OS:
case OS_BEOS:
rar->mode = archive_le32dec(file_header.file_attr);
rar->mode = (__LA_MODE_T)archive_le32dec(file_header.file_attr);
break;
default:
@@ -1780,6 +1816,7 @@ read_header(struct archive_read *a, struct archive_entry *entry,
rar->offset_outgoing = 0;
rar->br.cache_avail = 0;
rar->br.avail_in = 0;
rar->br.next_in = NULL;
rar->crc_calculated = 0;
rar->entry_eof = 0;
rar->valid = 1;
@@ -1941,8 +1978,18 @@ read_symlink_stored(struct archive_read *a, struct archive_entry *entry,
int ret = (ARCHIVE_OK);
rar = (struct rar *)(a->format->data);
if ((h = rar_read_ahead(a, (size_t)rar->packed_size, NULL)) == NULL)
if ((uintmax_t)rar->packed_size > SIZE_MAX)
{
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Unable to read link.");
return (ARCHIVE_FATAL);
}
if ((h = rar_read_ahead(a, (size_t)rar->packed_size, NULL)) == NULL)
{
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Failed to read link.");
return (ARCHIVE_FATAL);
}
p = h;
if (archive_entry_copy_symlink_l(entry,
@@ -2224,7 +2271,7 @@ read_data_compressed(struct archive_read *a, const void **buff, size_t *size,
ret = expand(a, &end);
if (ret != ARCHIVE_OK)
return (ret);
return (ret);
rar->bytes_uncopied = end - start;
rar->filters.lastend = end;
@@ -2276,7 +2323,7 @@ parse_codes(struct archive_read *a)
free_codes(a);
/* Skip to the next byte */
rar_br_consume_unalined_bits(br);
rar_br_consume_unaligned_bits(br);
/* PPMd block flag */
if (!rar_br_read_ahead(a, br, 1))
@@ -2332,9 +2379,9 @@ parse_codes(struct archive_read *a)
__archive_ppmd7_functions.Ppmd7_Construct(&rar->ppmd7_context);
if (rar->dictionary_size == 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Invalid zero dictionary size");
return (ARCHIVE_FATAL);
return (ARCHIVE_FATAL);
}
if (!__archive_ppmd7_functions.Ppmd7_Alloc(&rar->ppmd7_context,
@@ -2803,7 +2850,7 @@ make_table(struct archive_read *a, struct huffman_code *code)
else
code->tablesize = code->maxlength;
code->table = calloc(1U << code->tablesize, sizeof(*code->table));
code->table = calloc(((size_t)1U) << code->tablesize, sizeof(*code->table));
return make_table_recurse(a, code, 0, code->table, 0, code->tablesize);
}
@@ -2929,11 +2976,11 @@ expand(struct archive_read *a, int64_t *end)
}
if ((symbol = read_next_symbol(a, &rar->maincode)) < 0)
return (ARCHIVE_FATAL);
goto bad_data;
if (symbol < 256)
{
lzss_emit_literal(rar, symbol);
lzss_emit_literal(rar, (uint8_t)symbol);
continue;
}
else if (symbol == 256)
@@ -2956,14 +3003,14 @@ expand(struct archive_read *a, int64_t *end)
else
{
if (parse_codes(a) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
goto bad_data;
continue;
}
}
else if(symbol==257)
{
if (!read_filter(a, end))
return (ARCHIVE_FATAL);
goto bad_data;
continue;
}
else if(symbol==258)
@@ -3048,7 +3095,7 @@ expand(struct archive_read *a, int64_t *end)
{
if ((lowoffsetsymbol =
read_next_symbol(a, &rar->lowoffsetcode)) < 0)
return (ARCHIVE_FATAL);
goto bad_data;
if(lowoffsetsymbol == 16)
{
rar->numlowoffsetrepeats = 15;
@@ -3096,7 +3143,7 @@ bad_data:
}
static int
copy_from_lzss_window(struct archive_read *a, void *buffer,
copy_from_lzss_window(struct archive_read *a, uint8_t *buffer,
int64_t startpos, int length)
{
int windowoffs, firstpart;
@@ -3111,7 +3158,7 @@ copy_from_lzss_window(struct archive_read *a, void *buffer,
}
if (firstpart < length) {
memcpy(buffer, &rar->lzss.window[windowoffs], firstpart);
memcpy(buffer, &rar->lzss.window[0], length - firstpart);
memcpy(buffer + firstpart, &rar->lzss.window[0], length - firstpart);
} else {
memcpy(buffer, &rar->lzss.window[windowoffs], length);
}
@@ -3180,8 +3227,12 @@ static const void *
rar_read_ahead(struct archive_read *a, size_t min, ssize_t *avail)
{
struct rar *rar = (struct rar *)(a->format->data);
const void *h = __archive_read_ahead(a, min, avail);
const void *h;
int ret;
again:
h = __archive_read_ahead(a, min, avail);
if (avail)
{
if (a->archive.read_data_is_posix_read && *avail > (ssize_t)a->archive.read_data_requested)
@@ -3203,7 +3254,7 @@ rar_read_ahead(struct archive_read *a, size_t min, ssize_t *avail)
rar->filename_must_match = 0;
if (ret != (ARCHIVE_OK))
return NULL;
return rar_read_ahead(a, min, avail);
goto again;
}
}
return h;
@@ -3266,6 +3317,9 @@ parse_filter(struct archive_read *a, const uint8_t *bytes, uint16_t length, uint
else
blocklength = prog ? prog->oldfilterlength : 0;
if (blocklength > rar->dictionary_size)
return 0;
registers[3] = PROGRAM_SYSTEM_GLOBAL_ADDRESS;
registers[4] = blocklength;
registers[5] = prog ? prog->usagecount : 0;
@@ -46,6 +46,7 @@
#include "archive_entry_locale.h"
#include "archive_ppmd7_private.h"
#include "archive_entry_private.h"
#include "archive_time_private.h"
#ifdef HAVE_BLAKE2_H
#include <blake2.h>
@@ -100,10 +101,12 @@ struct file_header {
uint8_t dir : 1; /* Is this file entry a directory? */
/* Optional time fields. */
uint64_t e_mtime;
uint64_t e_ctime;
uint64_t e_atime;
uint32_t e_unix_ns;
int64_t e_mtime;
int64_t e_ctime;
int64_t e_atime;
uint32_t e_mtime_ns;
uint32_t e_ctime_ns;
uint32_t e_atime_ns;
/* Optional hash fields. */
uint32_t stored_crc32;
@@ -691,7 +694,8 @@ static int run_filter(struct archive_read* a, struct filter_info* flt) {
default:
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Unsupported filter type: 0x%x", flt->type);
"Unsupported filter type: 0x%x",
(unsigned int)flt->type);
return ARCHIVE_FATAL;
}
@@ -1100,22 +1104,22 @@ static int read_consume_bits(struct archive_read* a, struct rar5* rar,
return ARCHIVE_OK;
}
static int read_u32(struct archive_read* a, uint32_t* pvalue) {
static char read_u32(struct archive_read* a, uint32_t* pvalue) {
const uint8_t* p;
if(!read_ahead(a, 4, &p))
return 0;
*pvalue = archive_le32dec(p);
return ARCHIVE_OK == consume(a, 4) ? 1 : 0;
return ARCHIVE_OK == consume(a, 4);
}
static int read_u64(struct archive_read* a, uint64_t* pvalue) {
static char read_u64(struct archive_read* a, uint64_t* pvalue) {
const uint8_t* p;
if(!read_ahead(a, 8, &p))
return 0;
*pvalue = archive_le64dec(p);
return ARCHIVE_OK == consume(a, 8) ? 1 : 0;
return ARCHIVE_OK == consume(a, 8);
}
static int bid_standard(struct archive_read* a) {
@@ -1293,21 +1297,15 @@ static int parse_file_extra_hash(struct archive_read* a, struct rar5* rar,
*extra_data_size -= hash_size;
} else {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Unsupported hash type (0x%x)", (int) hash_type);
"Unsupported hash type (0x%jx)", (uintmax_t)hash_type);
return ARCHIVE_FATAL;
}
return ARCHIVE_OK;
}
static uint64_t time_win_to_unix(uint64_t win_time) {
const size_t ns_in_sec = 10000000;
const uint64_t sec_to_unix = 11644473600LL;
return win_time / ns_in_sec - sec_to_unix;
}
static int parse_htime_item(struct archive_read* a, char unix_time,
uint64_t* where, int64_t* extra_data_size)
int64_t* sec, uint32_t* nsec, int64_t* extra_data_size)
{
if(unix_time) {
uint32_t time_val;
@@ -1315,13 +1313,13 @@ static int parse_htime_item(struct archive_read* a, char unix_time,
return ARCHIVE_EOF;
*extra_data_size -= 4;
*where = (uint64_t) time_val;
*sec = (int64_t) time_val;
} else {
uint64_t windows_time;
if(!read_u64(a, &windows_time))
return ARCHIVE_EOF;
*where = time_win_to_unix(windows_time);
ntfs_to_unix(windows_time, sec, nsec);
*extra_data_size -= 8;
}
@@ -1385,7 +1383,7 @@ static int parse_file_extra_version(struct archive_read* a,
static int parse_file_extra_htime(struct archive_read* a,
struct archive_entry* e, struct rar5* rar, int64_t* extra_data_size)
{
char unix_time = 0;
char unix_time, has_unix_ns, has_mtime, has_ctime, has_atime;
size_t flags = 0;
size_t value_len;
@@ -1406,32 +1404,62 @@ static int parse_file_extra_htime(struct archive_read* a,
}
unix_time = flags & IS_UNIX;
has_unix_ns = unix_time && (flags & HAS_UNIX_NS);
has_mtime = flags & HAS_MTIME;
has_atime = flags & HAS_ATIME;
has_ctime = flags & HAS_CTIME;
rar->file.e_atime_ns = rar->file.e_ctime_ns = rar->file.e_mtime_ns = 0;
if(flags & HAS_MTIME) {
if(has_mtime) {
parse_htime_item(a, unix_time, &rar->file.e_mtime,
extra_data_size);
archive_entry_set_mtime(e, rar->file.e_mtime, 0);
&rar->file.e_mtime_ns, extra_data_size);
}
if(flags & HAS_CTIME) {
if(has_ctime) {
parse_htime_item(a, unix_time, &rar->file.e_ctime,
extra_data_size);
archive_entry_set_ctime(e, rar->file.e_ctime, 0);
&rar->file.e_ctime_ns, extra_data_size);
}
if(flags & HAS_ATIME) {
if(has_atime) {
parse_htime_item(a, unix_time, &rar->file.e_atime,
extra_data_size);
archive_entry_set_atime(e, rar->file.e_atime, 0);
&rar->file.e_atime_ns, extra_data_size);
}
if(flags & HAS_UNIX_NS) {
if(!read_u32(a, &rar->file.e_unix_ns))
if(has_mtime && has_unix_ns) {
if(!read_u32(a, &rar->file.e_mtime_ns))
return ARCHIVE_EOF;
*extra_data_size -= 4;
}
if(has_ctime && has_unix_ns) {
if(!read_u32(a, &rar->file.e_ctime_ns))
return ARCHIVE_EOF;
*extra_data_size -= 4;
}
if(has_atime && has_unix_ns) {
if(!read_u32(a, &rar->file.e_atime_ns))
return ARCHIVE_EOF;
*extra_data_size -= 4;
}
/* The seconds and nanoseconds are either together, or separated in two
* fields so we parse them, then set the archive_entry's times. */
if(has_mtime) {
archive_entry_set_mtime(e, rar->file.e_mtime, rar->file.e_mtime_ns);
}
if(has_ctime) {
archive_entry_set_ctime(e, rar->file.e_ctime, rar->file.e_ctime_ns);
}
if(has_atime) {
archive_entry_set_atime(e, rar->file.e_atime, rar->file.e_atime_ns);
}
return ARCHIVE_OK;
}
@@ -1896,7 +1924,8 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
} else {
/* Unknown host OS */
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Unsupported Host OS: 0x%x", (int) host_os);
"Unsupported Host OS: 0x%jx",
(uintmax_t)host_os);
return ARCHIVE_FATAL;
}
@@ -2104,8 +2133,8 @@ static int process_head_main(struct archive_read* a, struct rar5* rar,
default:
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Unsupported extra type (0x%x)",
(int) extra_field_id);
"Unsupported extra type (0x%jx)",
(uintmax_t)extra_field_id);
return ARCHIVE_FATAL;
}
@@ -3093,7 +3122,7 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
* can be stored in the output buffer directly.
*
* - Code 256 defines a new filter, which is later used to
* ransform the data block accordingly to the filter type.
* transform the data block accordingly to the filter type.
* The data block needs to be fully uncompressed first.
*
* - Code bigger than 257 and smaller than 262 define
@@ -3983,7 +4012,7 @@ static int do_unpack(struct archive_read* a, struct rar5* rar,
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Compression method not supported: 0x%x",
rar->cstate.method);
(unsigned int)rar->cstate.method);
return ARCHIVE_FATAL;
}
@@ -129,7 +129,11 @@ struct tar {
int64_t entry_offset;
int64_t entry_padding;
int64_t entry_bytes_unconsumed;
int64_t realsize;
int64_t disk_size;
int64_t GNU_sparse_realsize;
int64_t GNU_sparse_size;
int64_t SCHILY_sparse_realsize;
int64_t pax_size;
struct sparse_block *sparse_list;
struct sparse_block *sparse_last;
int64_t sparse_offset;
@@ -138,6 +142,7 @@ struct tar {
int sparse_gnu_minor;
char sparse_gnu_attributes_seen;
char filetype;
char size_fields; /* Bits defined below */
struct archive_string localname;
struct archive_string_conv *opt_sconv;
@@ -148,9 +153,15 @@ struct tar {
int compat_2x;
int process_mac_extensions;
int read_concatenated_archives;
int realsize_override;
};
/* Track which size fields were present in the headers */
#define TAR_SIZE_PAX_SIZE 1
#define TAR_SIZE_GNU_SPARSE_REALSIZE 2
#define TAR_SIZE_GNU_SPARSE_SIZE 4
#define TAR_SIZE_SCHILY_SPARSE_REALSIZE 8
static int archive_block_is_null(const char *p);
static char *base64_decode(const char *, size_t, size_t *);
static int gnu_add_sparse_entry(struct archive_read *, struct tar *,
@@ -158,36 +169,36 @@ static int gnu_add_sparse_entry(struct archive_read *, struct tar *,
static void gnu_clear_sparse_list(struct tar *);
static int gnu_sparse_old_read(struct archive_read *, struct tar *,
const struct archive_entry_header_gnutar *header, size_t *);
const struct archive_entry_header_gnutar *header, int64_t *);
static int gnu_sparse_old_parse(struct archive_read *, struct tar *,
const struct gnu_sparse *sparse, int length);
static int gnu_sparse_01_parse(struct archive_read *, struct tar *,
const char *, size_t);
static ssize_t gnu_sparse_10_read(struct archive_read *, struct tar *,
size_t *);
static int64_t gnu_sparse_10_read(struct archive_read *, struct tar *,
int64_t *);
static int header_Solaris_ACL(struct archive_read *, struct tar *,
struct archive_entry *, const void *, size_t *);
struct archive_entry *, const void *, int64_t *);
static int header_common(struct archive_read *, struct tar *,
struct archive_entry *, const void *);
static int header_old_tar(struct archive_read *, struct tar *,
struct archive_entry *, const void *);
static int header_pax_extension(struct archive_read *, struct tar *,
struct archive_entry *, const void *, size_t *);
struct archive_entry *, const void *, int64_t *);
static int header_pax_global(struct archive_read *, struct tar *,
struct archive_entry *, const void *h, size_t *);
struct archive_entry *, const void *h, int64_t *);
static int header_gnu_longlink(struct archive_read *, struct tar *,
struct archive_entry *, const void *h, size_t *);
struct archive_entry *, const void *h, int64_t *);
static int header_gnu_longname(struct archive_read *, struct tar *,
struct archive_entry *, const void *h, size_t *);
struct archive_entry *, const void *h, int64_t *);
static int is_mac_metadata_entry(struct archive_entry *entry);
static int read_mac_metadata_blob(struct archive_read *,
struct archive_entry *, size_t *);
struct archive_entry *, int64_t *);
static int header_volume(struct archive_read *, struct tar *,
struct archive_entry *, const void *h, size_t *);
struct archive_entry *, const void *h, int64_t *);
static int header_ustar(struct archive_read *, struct tar *,
struct archive_entry *, const void *h);
static int header_gnutar(struct archive_read *, struct tar *,
struct archive_entry *, const void *h, size_t *);
struct archive_entry *, const void *h, int64_t *);
static int archive_read_format_tar_bid(struct archive_read *, int);
static int archive_read_format_tar_options(struct archive_read *,
const char *, const char *);
@@ -200,7 +211,7 @@ static int archive_read_format_tar_read_header(struct archive_read *,
static int checksum(struct archive_read *, const void *);
static int pax_attribute(struct archive_read *, struct tar *,
struct archive_entry *, const char *key, size_t key_length,
size_t value_length, size_t *unconsumed);
size_t value_length, int64_t *unconsumed);
static int pax_attribute_LIBARCHIVE_xattr(struct archive_entry *,
const char *, size_t, const char *, size_t);
static int pax_attribute_SCHILY_acl(struct archive_read *, struct tar *,
@@ -209,20 +220,20 @@ static int pax_attribute_SUN_holesdata(struct archive_read *, struct tar *,
struct archive_entry *, const char *, size_t);
static void pax_time(const char *, size_t, int64_t *sec, long *nanos);
static ssize_t readline(struct archive_read *, struct tar *, const char **,
ssize_t limit, size_t *);
ssize_t limit, int64_t *);
static int read_body_to_string(struct archive_read *, struct tar *,
struct archive_string *, const void *h, size_t *);
struct archive_string *, const void *h, int64_t *);
static int read_bytes_to_string(struct archive_read *,
struct archive_string *, size_t, size_t *);
struct archive_string *, size_t, int64_t *);
static int64_t tar_atol(const char *, size_t);
static int64_t tar_atol10(const char *, size_t);
static int64_t tar_atol256(const char *, size_t);
static int64_t tar_atol8(const char *, size_t);
static int tar_read_header(struct archive_read *, struct tar *,
struct archive_entry *, size_t *);
struct archive_entry *, int64_t *);
static int tohex(int c);
static char *url_decode(const char *, size_t);
static void tar_flush_unconsumed(struct archive_read *, size_t *);
static void tar_flush_unconsumed(struct archive_read *, int64_t *);
/* Sanity limits: These numbers should be low enough to
* prevent a maliciously-crafted archive from forcing us to
@@ -467,7 +478,7 @@ archive_read_format_tar_options(struct archive_read *a,
* anything outstanding since we're going to do read_aheads
*/
static void
tar_flush_unconsumed(struct archive_read *a, size_t *unconsumed)
tar_flush_unconsumed(struct archive_read *a, int64_t *unconsumed)
{
if (*unconsumed) {
/*
@@ -515,7 +526,8 @@ archive_read_format_tar_read_header(struct archive_read *a,
const char *p;
const wchar_t *wp;
int r;
size_t l, unconsumed = 0;
size_t l;
int64_t unconsumed = 0;
/* Assign default device/inode values. */
archive_entry_set_dev(entry, 1 + default_dev); /* Don't use zero. */
@@ -529,8 +541,7 @@ archive_read_format_tar_read_header(struct archive_read *a,
tar = (struct tar *)(a->format->data);
tar->entry_offset = 0;
gnu_clear_sparse_list(tar);
tar->realsize = -1; /* Mark this as "unset" */
tar->realsize_override = 0;
tar->size_fields = 0; /* We don't have any size info yet */
/* Setup default string conversion. */
tar->sconv = tar->opt_sconv;
@@ -617,12 +628,15 @@ archive_read_format_tar_read_data(struct archive_read *a,
/* If we're at end of file, return EOF. */
if (tar->sparse_list == NULL ||
tar->entry_bytes_remaining == 0) {
if (__archive_read_consume(a, tar->entry_padding) < 0)
int64_t request = tar->entry_bytes_remaining +
tar->entry_padding;
if (__archive_read_consume(a, request) != request)
return (ARCHIVE_FATAL);
tar->entry_padding = 0;
*buff = NULL;
*size = 0;
*offset = tar->realsize;
*offset = tar->disk_size;
return (ARCHIVE_EOF);
}
@@ -655,29 +669,15 @@ archive_read_format_tar_read_data(struct archive_read *a,
static int
archive_read_format_tar_skip(struct archive_read *a)
{
int64_t bytes_skipped;
int64_t request;
struct sparse_block *p;
struct tar* tar;
tar = (struct tar *)(a->format->data);
/* Do not consume the hole of a sparse file. */
request = 0;
for (p = tar->sparse_list; p != NULL; p = p->next) {
if (!p->hole) {
if (p->remaining >= INT64_MAX - request) {
return ARCHIVE_FATAL;
}
request += p->remaining;
}
}
if (request > tar->entry_bytes_remaining)
request = tar->entry_bytes_remaining;
request += tar->entry_padding + tar->entry_bytes_unconsumed;
request = tar->entry_bytes_remaining + tar->entry_padding +
tar->entry_bytes_unconsumed;
bytes_skipped = __archive_read_consume(a, request);
if (bytes_skipped < 0)
if (__archive_read_consume(a, request) != request)
return (ARCHIVE_FATAL);
tar->entry_bytes_remaining = 0;
@@ -690,13 +690,29 @@ archive_read_format_tar_skip(struct archive_read *a)
return (ARCHIVE_OK);
}
/*
* This function resets the accumulated state while reading
* a header.
*/
static void
tar_reset_header_state(struct tar *tar)
{
tar->pax_hdrcharset_utf8 = 1;
tar->sparse_gnu_attributes_seen = 0;
archive_string_empty(&(tar->entry_gname));
archive_string_empty(&(tar->entry_pathname));
archive_string_empty(&(tar->entry_pathname_override));
archive_string_empty(&(tar->entry_uname));
archive_string_empty(&tar->entry_linkpath);
}
/*
* This function reads and interprets all of the headers associated
* with a single entry.
*/
static int
tar_read_header(struct archive_read *a, struct tar *tar,
struct archive_entry *entry, size_t *unconsumed)
struct archive_entry *entry, int64_t *unconsumed)
{
ssize_t bytes;
int err = ARCHIVE_OK, err2;
@@ -715,13 +731,7 @@ tar_read_header(struct archive_read *a, struct tar *tar,
static const int32_t seen_x_header = 32; /* Also X */
static const int32_t seen_mac_metadata = 512;
tar->pax_hdrcharset_utf8 = 1;
tar->sparse_gnu_attributes_seen = 0;
archive_string_empty(&(tar->entry_gname));
archive_string_empty(&(tar->entry_pathname));
archive_string_empty(&(tar->entry_pathname_override));
archive_string_empty(&(tar->entry_uname));
archive_string_empty(&tar->entry_linkpath);
tar_reset_header_state(tar);
/* Ensure format is set. */
if (a->archive.archive_format_name == NULL) {
@@ -750,7 +760,7 @@ tar_read_header(struct archive_read *a, struct tar *tar,
* if there's no regular header, then this is
* a premature EOF. */
archive_set_error(&a->archive, EINVAL,
"Damaged tar archive");
"Damaged tar archive (end-of-archive within a sequence of headers)");
return (ARCHIVE_FATAL);
} else {
return (ARCHIVE_EOF);
@@ -760,7 +770,7 @@ tar_read_header(struct archive_read *a, struct tar *tar,
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated tar archive"
" detected while reading next heaader");
" detected while reading next header");
return (ARCHIVE_FATAL);
}
*unconsumed += 512;
@@ -787,7 +797,8 @@ tar_read_header(struct archive_read *a, struct tar *tar,
/* This is NOT a null block, so it must be a valid header. */
if (!checksum(a, h)) {
tar_flush_unconsumed(a, unconsumed);
archive_set_error(&a->archive, EINVAL, "Damaged tar archive");
archive_set_error(&a->archive, EINVAL,
"Damaged tar archive (bad header checksum)");
/* If we've read some critical information (pax headers, etc)
* and _then_ see a bad header, we can't really recover. */
if (eof_fatal) {
@@ -804,6 +815,8 @@ tar_read_header(struct archive_read *a, struct tar *tar,
switch(header->typeflag[0]) {
case 'A': /* Solaris tar ACL */
if (seen_headers & seen_A_header) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Redundant 'A' header");
return (ARCHIVE_FATAL);
}
seen_headers |= seen_A_header;
@@ -813,6 +826,8 @@ tar_read_header(struct archive_read *a, struct tar *tar,
break;
case 'g': /* POSIX-standard 'g' header. */
if (seen_headers & seen_g_header) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Redundant 'g' header");
return (ARCHIVE_FATAL);
}
seen_headers |= seen_g_header;
@@ -822,27 +837,41 @@ tar_read_header(struct archive_read *a, struct tar *tar,
break;
case 'K': /* Long link name (GNU tar, others) */
if (seen_headers & seen_K_header) {
return (ARCHIVE_FATAL);
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Damaged archive: Redundant 'K' headers may cause linknames to be incorrect");
err = err_combine(err, ARCHIVE_WARN);
}
seen_headers |= seen_K_header;
a->archive.archive_format = ARCHIVE_FORMAT_TAR_GNUTAR;
a->archive.archive_format_name = "GNU tar format";
err2 = header_gnu_longlink(a, tar, entry, h, unconsumed);
break;
case 'L': /* Long filename (GNU tar, others) */
if (seen_headers & seen_L_header) {
return (ARCHIVE_FATAL);
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Damaged archive: Redundant 'L' headers may cause filenames to be incorrect");
err = err_combine(err, ARCHIVE_WARN);
}
seen_headers |= seen_L_header;
a->archive.archive_format = ARCHIVE_FORMAT_TAR_GNUTAR;
a->archive.archive_format_name = "GNU tar format";
err2 = header_gnu_longname(a, tar, entry, h, unconsumed);
break;
case 'V': /* GNU volume header */
if (seen_headers & seen_V_header) {
return (ARCHIVE_FATAL);
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Redundant 'V' header");
err = err_combine(err, ARCHIVE_WARN);
}
seen_headers |= seen_V_header;
a->archive.archive_format = ARCHIVE_FORMAT_TAR_GNUTAR;
a->archive.archive_format_name = "GNU tar format";
err2 = header_volume(a, tar, entry, h, unconsumed);
break;
case 'X': /* Used by SUN tar; same as 'x'. */
if (seen_headers & seen_x_header) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Redundant 'X'/'x' header");
return (ARCHIVE_FATAL);
}
seen_headers |= seen_x_header;
@@ -853,6 +882,8 @@ tar_read_header(struct archive_read *a, struct tar *tar,
break;
case 'x': /* POSIX-standard 'x' header. */
if (seen_headers & seen_x_header) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Redundant 'x' header");
return (ARCHIVE_FATAL);
}
seen_headers |= seen_x_header;
@@ -904,6 +935,7 @@ tar_read_header(struct archive_read *a, struct tar *tar,
err = err_combine(err, err2);
/* Note: Other headers can appear again. */
seen_headers = seen_mac_metadata;
tar_reset_header_state(tar);
break;
}
@@ -1032,13 +1064,13 @@ archive_block_is_null(const char *p)
*/
static int
header_Solaris_ACL(struct archive_read *a, struct tar *tar,
struct archive_entry *entry, const void *h, size_t *unconsumed)
struct archive_entry *entry, const void *h, int64_t *unconsumed)
{
const struct archive_entry_header_ustar *header;
struct archive_string acl_text;
size_t size;
int err, acl_type;
int64_t type;
uint64_t type;
char *acl, *p;
header = (const struct archive_entry_header_ustar *)h;
@@ -1075,7 +1107,7 @@ header_Solaris_ACL(struct archive_read *a, struct tar *tar,
}
p++;
}
switch ((int)type & ~0777777) {
switch (type & ~0777777) {
case 01000000:
/* POSIX.1e ACL */
acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
@@ -1086,8 +1118,8 @@ header_Solaris_ACL(struct archive_read *a, struct tar *tar,
break;
default:
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Malformed Solaris ACL attribute (unsupported type %o)",
(int)type);
"Malformed Solaris ACL attribute (unsupported type %llu)",
(unsigned long long)type);
archive_string_free(&acl_text);
return (ARCHIVE_WARN);
}
@@ -1138,14 +1170,16 @@ header_Solaris_ACL(struct archive_read *a, struct tar *tar,
*/
static int
header_gnu_longlink(struct archive_read *a, struct tar *tar,
struct archive_entry *entry, const void *h, size_t *unconsumed)
struct archive_entry *entry, const void *h, int64_t *unconsumed)
{
int err;
struct archive_string linkpath;
archive_string_init(&linkpath);
err = read_body_to_string(a, tar, &linkpath, h, unconsumed);
archive_entry_set_link(entry, linkpath.s);
if (err == ARCHIVE_OK) {
archive_entry_set_link(entry, linkpath.s);
}
archive_string_free(&linkpath);
return (err);
}
@@ -1170,7 +1204,7 @@ set_conversion_failed_error(struct archive_read *a,
*/
static int
header_gnu_longname(struct archive_read *a, struct tar *tar,
struct archive_entry *entry, const void *h, size_t *unconsumed)
struct archive_entry *entry, const void *h, int64_t *unconsumed)
{
int err;
struct archive_string longname;
@@ -1191,7 +1225,7 @@ header_gnu_longname(struct archive_read *a, struct tar *tar,
*/
static int
header_volume(struct archive_read *a, struct tar *tar,
struct archive_entry *entry, const void *h, size_t *unconsumed)
struct archive_entry *entry, const void *h, int64_t *unconsumed)
{
const struct archive_entry_header_ustar *header;
int64_t size, to_consume;
@@ -1217,7 +1251,7 @@ header_volume(struct archive_read *a, struct tar *tar,
static int
read_bytes_to_string(struct archive_read *a,
struct archive_string *as, size_t size,
size_t *unconsumed) {
int64_t *unconsumed) {
const void *src;
/* Fail if we can't make our buffer big enough. */
@@ -1250,7 +1284,7 @@ read_bytes_to_string(struct archive_read *a,
*/
static int
read_body_to_string(struct archive_read *a, struct tar *tar,
struct archive_string *as, const void *h, size_t *unconsumed)
struct archive_string *as, const void *h, int64_t *unconsumed)
{
int64_t size;
const struct archive_entry_header_ustar *header;
@@ -1259,18 +1293,21 @@ read_body_to_string(struct archive_read *a, struct tar *tar,
(void)tar; /* UNUSED */
header = (const struct archive_entry_header_ustar *)h;
size = tar_atol(header->size, sizeof(header->size));
if (size > entry_limit) {
if (size < 0 || size > entry_limit) {
archive_set_error(&a->archive, EINVAL,
"Special header has invalid size: %lld",
(long long)size);
return (ARCHIVE_FATAL);
}
if ((size > (int64_t)pathname_limit) || (size < 0)) {
if (size > (int64_t)pathname_limit) {
archive_string_empty(as);
int64_t to_consume = ((size + 511) & ~511);
if (to_consume != __archive_read_consume(a, to_consume)) {
return (ARCHIVE_FATAL);
}
archive_set_error(&a->archive, EINVAL,
"Special header too large: %d > 1MiB",
(int)size);
"Special header too large: %lld > 1MiB",
(long long)size);
return (ARCHIVE_WARN);
}
r = read_bytes_to_string(a, as, size, unconsumed);
@@ -1287,6 +1324,11 @@ read_body_to_string(struct archive_read *a, struct tar *tar,
* allows header_old_tar and header_ustar
* to handle filenames differently, while still putting most of the
* common parsing into one place.
*
* This is called _after_ ustar, GNU tar, Schily, etc, special
* fields have already been parsed into the `tar` structure.
* So we can make final decisions here about how to reconcile
* size, mode, etc, information.
*/
static int
header_common(struct archive_read *a, struct tar *tar,
@@ -1308,34 +1350,73 @@ header_common(struct archive_read *a, struct tar *tar,
archive_entry_set_perm(entry,
(mode_t)tar_atol(header->mode, sizeof(header->mode)));
}
/* Set uid, gid, mtime if not already set */
if (!archive_entry_uid_is_set(entry)) {
archive_entry_set_uid(entry, tar_atol(header->uid, sizeof(header->uid)));
}
if (!archive_entry_gid_is_set(entry)) {
archive_entry_set_gid(entry, tar_atol(header->gid, sizeof(header->gid)));
}
if (!archive_entry_mtime_is_set(entry)) {
archive_entry_set_mtime(entry, tar_atol(header->mtime, sizeof(header->mtime)), 0);
}
tar->entry_bytes_remaining = tar_atol(header->size, sizeof(header->size));
/* Reconcile the size info. */
/* First, how big is the file on disk? */
if ((tar->size_fields & TAR_SIZE_GNU_SPARSE_REALSIZE) != 0) {
/* GNU sparse format 1.0 uses `GNU.sparse.realsize`
* to hold the size of the file on disk. */
tar->disk_size = tar->GNU_sparse_realsize;
} else if ((tar->size_fields & TAR_SIZE_GNU_SPARSE_SIZE) != 0
&& (tar->sparse_gnu_major == 0)) {
/* GNU sparse format 0.0 and 0.1 use `GNU.sparse.size`
* to hold the size of the file on disk. */
tar->disk_size = tar->GNU_sparse_size;
} else if ((tar->size_fields & TAR_SIZE_SCHILY_SPARSE_REALSIZE) != 0) {
tar->disk_size = tar->SCHILY_sparse_realsize;
} else if ((tar->size_fields & TAR_SIZE_PAX_SIZE) != 0) {
tar->disk_size = tar->pax_size;
} else {
/* There wasn't a suitable pax header, so use the ustar info */
tar->disk_size = tar_atol(header->size, sizeof(header->size));
}
if (tar->disk_size < 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Tar entry has negative file size");
return (ARCHIVE_FATAL);
} else if (tar->disk_size > entry_limit) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Tar entry size overflow");
return (ARCHIVE_FATAL);
} else {
archive_entry_set_size(entry, tar->disk_size);
}
/* Second, how big is the data in the archive? */
if ((tar->size_fields & TAR_SIZE_GNU_SPARSE_SIZE) != 0
&& (tar->sparse_gnu_major == 1)) {
/* GNU sparse format 1.0 uses `GNU.sparse.size`
* to hold the size of the data in the archive. */
tar->entry_bytes_remaining = tar->GNU_sparse_size;
} else if ((tar->size_fields & TAR_SIZE_PAX_SIZE) != 0) {
tar->entry_bytes_remaining = tar->pax_size;
} else {
tar->entry_bytes_remaining
= tar_atol(header->size, sizeof(header->size));
}
if (tar->entry_bytes_remaining < 0) {
tar->entry_bytes_remaining = 0;
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Tar entry has negative size");
"Tar entry has negative size");
return (ARCHIVE_FATAL);
}
if (tar->entry_bytes_remaining > entry_limit) {
} else if (tar->entry_bytes_remaining > entry_limit) {
tar->entry_bytes_remaining = 0;
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Tar entry size overflow");
"Tar entry size overflow");
return (ARCHIVE_FATAL);
}
if (!tar->realsize_override) {
tar->realsize = tar->entry_bytes_remaining;
}
archive_entry_set_size(entry, tar->realsize);
if (!archive_entry_mtime_is_set(entry)) {
archive_entry_set_mtime(entry, tar_atol(header->mtime, sizeof(header->mtime)), 0);
}
/* Handle the tar type flag appropriately. */
tar->filetype = header->typeflag[0];
@@ -1597,7 +1678,7 @@ is_mac_metadata_entry(struct archive_entry *entry) {
*/
static int
read_mac_metadata_blob(struct archive_read *a,
struct archive_entry *entry, size_t *unconsumed)
struct archive_entry *entry, int64_t *unconsumed)
{
int64_t size;
size_t msize;
@@ -1654,7 +1735,7 @@ read_mac_metadata_blob(struct archive_read *a,
*/
static int
header_pax_global(struct archive_read *a, struct tar *tar,
struct archive_entry *entry, const void *h, size_t *unconsumed)
struct archive_entry *entry, const void *h, int64_t *unconsumed)
{
const struct archive_entry_header_ustar *header;
int64_t size, to_consume;
@@ -1665,7 +1746,10 @@ header_pax_global(struct archive_read *a, struct tar *tar,
header = (const struct archive_entry_header_ustar *)h;
size = tar_atol(header->size, sizeof(header->size));
if (size > entry_limit) {
if (size < 0 || size > entry_limit) {
archive_set_error(&a->archive, EINVAL,
"Special header has invalid size: %lld",
(long long)size);
return (ARCHIVE_FATAL);
}
to_consume = ((size + 511) & ~511);
@@ -1761,7 +1845,7 @@ header_ustar(struct archive_read *a, struct tar *tar,
static int
header_pax_extension(struct archive_read *a, struct tar *tar,
struct archive_entry *entry, const void *h, size_t *unconsumed)
struct archive_entry *entry, const void *h, int64_t *unconsumed)
{
/* Sanity checks: The largest `x` body I've ever heard of was
* a little over 4MB. So I doubt there has ever been a
@@ -1812,8 +1896,8 @@ header_pax_extension(struct archive_read *a, struct tar *tar,
return (ARCHIVE_FATAL);
}
archive_set_error(&a->archive, EINVAL,
"Ignoring oversized pax extensions: %d > %d",
(int)ext_size, (int)ext_size_limit);
"Ignoring oversized pax extensions: %lld > %lld",
(long long)ext_size, (long long)ext_size_limit);
return (ARCHIVE_WARN);
}
tar_flush_unconsumed(a, unconsumed);
@@ -1912,6 +1996,13 @@ header_pax_extension(struct archive_read *a, struct tar *tar,
*unconsumed += p - attr_start;
tar_flush_unconsumed(a, unconsumed);
if (value_length == 0) {
archive_set_error(&a->archive, EINVAL,
"Malformed pax attributes");
*unconsumed += ext_size + ext_padding;
return (ARCHIVE_WARN);
}
/* pax_attribute will consume value_length - 1 */
r = pax_attribute(a, tar, entry, attr_name.s, archive_strlen(&attr_name), value_length - 1, unconsumed);
ext_size -= value_length - 1;
@@ -2121,8 +2212,9 @@ pax_attribute_SCHILY_acl(struct archive_read *a, struct tar *tar,
if (value_length > acl_limit) {
__archive_read_consume(a, value_length);
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Unreasonably large ACL: %d > %d",
(int)value_length, (int)acl_limit);
"Unreasonably large ACL: %llu > %llu",
(unsigned long long)value_length,
(unsigned long long)acl_limit);
return (ARCHIVE_WARN);
}
@@ -2154,7 +2246,7 @@ pax_attribute_SCHILY_acl(struct archive_read *a, struct tar *tar,
}
static int
pax_attribute_read_time(struct archive_read *a, size_t value_length, int64_t *ps, long *pn, size_t *unconsumed) {
pax_attribute_read_time(struct archive_read *a, size_t value_length, int64_t *ps, long *pn, int64_t *unconsumed) {
struct archive_string as;
int r;
@@ -2169,12 +2261,16 @@ pax_attribute_read_time(struct archive_read *a, size_t value_length, int64_t *ps
r = read_bytes_to_string(a, &as, value_length, unconsumed);
if (r < ARCHIVE_OK) {
archive_string_free(&as);
*ps = 0;
*pn = 0;
return (r);
}
pax_time(as.s, archive_strlen(&as), ps, pn);
archive_string_free(&as);
if (*ps < 0 || *ps == INT64_MAX) {
if (*ps == INT64_MIN) {
*ps = 0;
*pn = 0;
return (ARCHIVE_WARN);
}
return (ARCHIVE_OK);
@@ -2183,7 +2279,7 @@ pax_attribute_read_time(struct archive_read *a, size_t value_length, int64_t *ps
static int
pax_attribute_read_number(struct archive_read *a, size_t value_length, int64_t *result) {
struct archive_string as;
size_t unconsumed = 0;
int64_t unconsumed = 0;
int r;
if (value_length > 64) {
@@ -2197,6 +2293,7 @@ pax_attribute_read_number(struct archive_read *a, size_t value_length, int64_t *
tar_flush_unconsumed(a, &unconsumed);
if (r < ARCHIVE_OK) {
archive_string_free(&as);
*result = 0;
return (r);
}
@@ -2223,7 +2320,7 @@ pax_attribute_read_number(struct archive_read *a, size_t value_length, int64_t *
*/
static int
pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *entry,
const char *key, size_t key_length, size_t value_length, size_t *unconsumed)
const char *key, size_t key_length, size_t value_length, int64_t *unconsumed)
{
int64_t t;
long n;
@@ -2289,10 +2386,13 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
}
else if (key_length == 4 && memcmp(key, "size", 4) == 0) {
/* GNU.sparse.size */
/* This is either the size of stored entry OR the size of data on disk,
* depending on which GNU sparse format version is in use.
* Since pax attributes can be in any order, we may not actually
* know at this point how to interpret this. */
if ((err = pax_attribute_read_number(a, value_length, &t)) == ARCHIVE_OK) {
tar->realsize = t;
archive_entry_set_size(entry, tar->realsize);
tar->realsize_override = 1;
tar->GNU_sparse_size = t;
tar->size_fields |= TAR_SIZE_GNU_SPARSE_SIZE;
}
return (err);
}
@@ -2304,8 +2404,9 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
tar->sparse_gnu_minor = 1;
if (value_length > sparse_map_limit) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Unreasonably large sparse map: %d > %d",
(int)value_length, (int)sparse_map_limit);
"Unreasonably large sparse map: %llu > %llu",
(unsigned long long)value_length,
(unsigned long long)sparse_map_limit);
err = ARCHIVE_FAILED;
} else {
p = __archive_read_ahead(a, value_length, &bytes_read);
@@ -2360,11 +2461,10 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
return (err);
}
else if (key_length == 8 && memcmp(key, "realsize", 8) == 0) {
/* GNU.sparse.realsize */
/* GNU.sparse.realsize = size of file on disk */
if ((err = pax_attribute_read_number(a, value_length, &t)) == ARCHIVE_OK) {
tar->realsize = t;
archive_entry_set_size(entry, tar->realsize);
tar->realsize_override = 1;
tar->GNU_sparse_realsize = t;
tar->size_fields |= TAR_SIZE_GNU_SPARSE_REALSIZE;
}
return (err);
}
@@ -2413,8 +2513,8 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
} else {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"symlink type is very long"
"(longest recognized value is 4 bytes, this is %d)",
(int)value_length);
"(longest recognized value is 4 bytes, this is %llu)",
(unsigned long long)value_length);
err = ARCHIVE_WARN;
}
__archive_read_consume(a, value_length);
@@ -2450,8 +2550,9 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
if (value_length > xattr_limit) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Ignoring unreasonably large security.selinux attribute:"
" %d > %d",
(int)value_length, (int)xattr_limit);
" %llu > %llu",
(unsigned long long)value_length,
(unsigned long long)xattr_limit);
/* TODO: Should this be FAILED instead? */
err = ARCHIVE_WARN;
} else {
@@ -2545,12 +2646,12 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
}
else if (key_length == 8 && memcmp(key, "realsize", 8) == 0) {
if ((err = pax_attribute_read_number(a, value_length, &t)) == ARCHIVE_OK) {
tar->realsize = t;
tar->realsize_override = 1;
archive_entry_set_size(entry, tar->realsize);
tar->SCHILY_sparse_realsize = t;
tar->size_fields |= TAR_SIZE_SCHILY_SPARSE_REALSIZE;
}
return (err);
}
/* TODO: Is there a SCHILY.sparse.size similar to GNU.sparse.size ? */
else if (key_length > 6 && memcmp(key, "xattr.", 6) == 0) {
key_length -= 6;
key += 6;
@@ -2568,8 +2669,9 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
}
} else {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Unreasonably large xattr: %d > %d",
(int)value_length, (int)xattr_limit);
"Unreasonably large xattr: %llu > %llu",
(unsigned long long)value_length,
(unsigned long long)xattr_limit);
err = ARCHIVE_WARN;
}
__archive_read_consume(a, value_length);
@@ -2599,8 +2701,9 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
}
} else {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Unreasonably large sparse map: %d > %d",
(int)value_length, (int)sparse_map_limit);
"Unreasonably large sparse map: %llu > %llu",
(unsigned long long)value_length,
(unsigned long long)sparse_map_limit);
err = ARCHIVE_FAILED;
}
__archive_read_consume(a, value_length);
@@ -2669,8 +2772,8 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
}
} else {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"hdrcharset attribute is unreasonably large (%d bytes)",
(int)value_length);
"hdrcharset attribute is unreasonably large (%llu bytes)",
(unsigned long long)value_length);
err = ARCHIVE_WARN;
}
__archive_read_consume(a, value_length);
@@ -2717,19 +2820,8 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
if (key_length == 4 && memcmp(key, "size", 4) == 0) {
/* "size" is the size of the data in the entry. */
if ((err = pax_attribute_read_number(a, value_length, &t)) == ARCHIVE_OK) {
tar->entry_bytes_remaining = t;
/*
* The "size" pax header keyword always overrides the
* "size" field in the tar header.
* GNU.sparse.realsize, GNU.sparse.size and
* SCHILY.realsize override this value.
*/
if (!tar->realsize_override) {
archive_entry_set_size(entry,
tar->entry_bytes_remaining);
tar->realsize
= tar->entry_bytes_remaining;
}
tar->pax_size = t;
tar->size_fields |= TAR_SIZE_PAX_SIZE;
}
else if (t == INT64_MAX) {
/* Note: pax_attr_read_number returns INT64_MAX on overflow or < 0 */
@@ -2768,7 +2860,9 @@ pax_attribute(struct archive_read *a, struct tar *tar, struct archive_entry *ent
/*
* parse a decimal time value, which may include a fractional portion
* Parse a decimal time value, which may include a fractional portion
*
* Sets ps to INT64_MIN on error.
*/
static void
pax_time(const char *p, size_t length, int64_t *ps, long *pn)
@@ -2784,6 +2878,7 @@ pax_time(const char *p, size_t length, int64_t *ps, long *pn)
if (length <= 0) {
*ps = 0;
*pn = 0;
return;
}
s = 0;
@@ -2797,8 +2892,9 @@ pax_time(const char *p, size_t length, int64_t *ps, long *pn)
digit = *p - '0';
if (s > limit ||
(s == limit && digit > last_digit_limit)) {
s = INT64_MAX;
break;
*ps = INT64_MIN;
*pn = 0;
return;
}
s = (s * 10) + digit;
++p;
@@ -2829,7 +2925,7 @@ pax_time(const char *p, size_t length, int64_t *ps, long *pn)
*/
static int
header_gnutar(struct archive_read *a, struct tar *tar,
struct archive_entry *entry, const void *h, size_t *unconsumed)
struct archive_entry *entry, const void *h, int64_t *unconsumed)
{
const struct archive_entry_header_gnutar *header;
int64_t t;
@@ -2841,11 +2937,6 @@ header_gnutar(struct archive_read *a, struct tar *tar,
* filename is stored as in old-style archives.
*/
/* Grab fields common to all tar variants. */
err = header_common(a, tar, entry, h);
if (err == ARCHIVE_FATAL)
return (err);
/* Copy filename over (to ensure null termination). */
header = (const struct archive_entry_header_gnutar *)h;
const char *existing_pathname = archive_entry_pathname(entry);
@@ -2894,8 +2985,6 @@ header_gnutar(struct archive_read *a, struct tar *tar,
archive_entry_set_rdev(entry, 0);
}
tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining);
/* Grab GNU-specific fields. */
if (!archive_entry_atime_is_set(entry)) {
t = tar_atol(header->atime, sizeof(header->atime));
@@ -2909,10 +2998,10 @@ header_gnutar(struct archive_read *a, struct tar *tar,
}
if (header->realsize[0] != 0) {
tar->realsize
/* Treat as a synonym for the pax GNU.sparse.realsize attr */
tar->GNU_sparse_realsize
= tar_atol(header->realsize, sizeof(header->realsize));
archive_entry_set_size(entry, tar->realsize);
tar->realsize_override = 1;
tar->size_fields |= TAR_SIZE_GNU_SPARSE_REALSIZE;
}
if (header->sparse[0].offset[0] != 0) {
@@ -2925,6 +3014,13 @@ header_gnutar(struct archive_read *a, struct tar *tar,
}
}
/* Grab fields common to all tar variants. */
err = header_common(a, tar, entry, h);
if (err == ARCHIVE_FATAL)
return (err);
tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining);
return (err);
}
@@ -2980,7 +3076,7 @@ gnu_clear_sparse_list(struct tar *tar)
static int
gnu_sparse_old_read(struct archive_read *a, struct tar *tar,
const struct archive_entry_header_gnutar *header, size_t *unconsumed)
const struct archive_entry_header_gnutar *header, int64_t *unconsumed)
{
ssize_t bytes_read;
const void *data;
@@ -3104,8 +3200,7 @@ gnu_sparse_01_parse(struct archive_read *a, struct tar *tar, const char *p, size
* it's not possible to support both variants. This code supports
* the later variant at the expense of not supporting the former.
*
* This variant also replaced GNU.sparse.size with GNU.sparse.realsize
* and introduced the GNU.sparse.major/GNU.sparse.minor attributes.
* This variant also introduced the GNU.sparse.major/GNU.sparse.minor attributes.
*/
/*
@@ -3115,7 +3210,7 @@ gnu_sparse_01_parse(struct archive_read *a, struct tar *tar, const char *p, size
*/
static int64_t
gnu_sparse_10_atol(struct archive_read *a, struct tar *tar,
int64_t *remaining, size_t *unconsumed)
int64_t *remaining, int64_t *unconsumed)
{
int64_t l, limit, last_digit_limit;
const char *p;
@@ -3160,12 +3255,10 @@ gnu_sparse_10_atol(struct archive_read *a, struct tar *tar,
* Returns length (in bytes) of the sparse data description
* that was read.
*/
static ssize_t
gnu_sparse_10_read(struct archive_read *a, struct tar *tar, size_t *unconsumed)
static int64_t
gnu_sparse_10_read(struct archive_read *a, struct tar *tar, int64_t *unconsumed)
{
ssize_t bytes_read;
int entries;
int64_t offset, size, to_skip, remaining;
int64_t bytes_read, entries, offset, size, to_skip, remaining;
/* Clear out the existing sparse list. */
gnu_clear_sparse_list(tar);
@@ -3173,7 +3266,7 @@ gnu_sparse_10_read(struct archive_read *a, struct tar *tar, size_t *unconsumed)
remaining = tar->entry_bytes_remaining;
/* Parse entries. */
entries = (int)gnu_sparse_10_atol(a, tar, &remaining, unconsumed);
entries = gnu_sparse_10_atol(a, tar, &remaining, unconsumed);
if (entries < 0)
return (ARCHIVE_FATAL);
/* Parse the individual entries. */
@@ -3191,14 +3284,14 @@ gnu_sparse_10_read(struct archive_read *a, struct tar *tar, size_t *unconsumed)
}
/* Skip rest of block... */
tar_flush_unconsumed(a, unconsumed);
bytes_read = (ssize_t)(tar->entry_bytes_remaining - remaining);
bytes_read = tar->entry_bytes_remaining - remaining;
to_skip = 0x1ff & -bytes_read;
/* Fail if tar->entry_bytes_remaing would get negative */
if (to_skip > remaining)
return (ARCHIVE_FATAL);
if (to_skip != __archive_read_consume(a, to_skip))
return (ARCHIVE_FATAL);
return ((ssize_t)(bytes_read + to_skip));
return (bytes_read + to_skip);
}
/*
@@ -3408,7 +3501,7 @@ tar_atol256(const char *_p, size_t char_cnt)
*/
static ssize_t
readline(struct archive_read *a, struct tar *tar, const char **start,
ssize_t limit, size_t *unconsumed)
ssize_t limit, int64_t *unconsumed)
{
ssize_t bytes_read;
ssize_t total_size = 0;
@@ -386,7 +386,8 @@ start_over:
case LAST_WT:
default:
/* consume the content and start over */
_warc_skip(a);
if (_warc_skip(a) < 0)
return (ARCHIVE_FATAL);
goto start_over;
}
return (ARCHIVE_OK);
@@ -439,7 +440,9 @@ _warc_skip(struct archive_read *a)
{
struct warc_s *w = a->format->data;
__archive_read_consume(a, w->cntlen + 4U/*\r\n\r\n separator*/);
if (__archive_read_consume(a, w->cntlen) < 0 ||
__archive_read_consume(a, 4U/*\r\n\r\n separator*/) < 0)
return (ARCHIVE_FATAL);
w->cntlen = 0U;
w->cntoff = 0U;
return (ARCHIVE_OK);
@@ -36,6 +36,10 @@
#include <bsdxml.h>
#elif HAVE_EXPAT_H
#include <expat.h>
#elif HAVE_XMLLITE_H
#include <objidl.h>
#include <initguid.h>
#include <xmllite.h>
#endif
#ifdef HAVE_BZLIB_H
#include <bzlib.h>
@@ -56,12 +60,13 @@
#include "archive_read_private.h"
#if (!defined(HAVE_LIBXML_XMLREADER_H) && \
!defined(HAVE_BSDXML_H) && !defined(HAVE_EXPAT_H)) ||\
!defined(HAVE_BSDXML_H) && !defined(HAVE_EXPAT_H) && \
!defined(HAVE_XMLLITE_H)) ||\
!defined(HAVE_ZLIB_H) || \
!defined(ARCHIVE_HAS_MD5) || !defined(ARCHIVE_HAS_SHA1)
/*
* xar needs several external libraries.
* o libxml2 or expat --- XML parser
* o libxml2, expat or (Windows only) xmllite --- XML parser
* o openssl or MD5/SHA1 hash function
* o zlib
* o bzlib2 (option)
@@ -438,6 +443,8 @@ static void expat_start_cb(void *, const XML_Char *, const XML_Char **);
static void expat_end_cb(void *, const XML_Char *);
static void expat_data_cb(void *, const XML_Char *, int);
static int expat_read_toc(struct archive_read *);
#elif defined(HAVE_XMLLITE_H)
static int xmllite_read_toc(struct archive_read *);
#endif
int
@@ -589,6 +596,8 @@ read_toc(struct archive_read *a)
r = xml2_read_toc(a);
#elif defined(HAVE_BSDXML_H) || defined(HAVE_EXPAT_H)
r = expat_read_toc(a);
#elif defined(HAVE_XMLLITE_H)
r = xmllite_read_toc(a);
#endif
if (r != ARCHIVE_OK)
return (r);
@@ -1110,17 +1119,17 @@ atohex(unsigned char *b, size_t bsize, const char *p, size_t psize)
while (bsize && psize > 1) {
unsigned char x;
if (p[0] >= 'a' && p[0] <= 'z')
if (p[0] >= 'a' && p[0] <= 'f')
x = (p[0] - 'a' + 0x0a) << 4;
else if (p[0] >= 'A' && p[0] <= 'Z')
else if (p[0] >= 'A' && p[0] <= 'F')
x = (p[0] - 'A' + 0x0a) << 4;
else if (p[0] >= '0' && p[0] <= '9')
x = (p[0] - '0') << 4;
else
return (-1);
if (p[1] >= 'a' && p[1] <= 'z')
if (p[1] >= 'a' && p[1] <= 'f')
x |= p[1] - 'a' + 0x0a;
else if (p[1] >= 'A' && p[1] <= 'Z')
else if (p[1] >= 'A' && p[1] <= 'F')
x |= p[1] - 'A' + 0x0a;
else if (p[1] >= '0' && p[1] <= '9')
x |= p[1] - '0';
@@ -1745,15 +1754,6 @@ decompression_cleanup(struct archive_read *a)
#if defined(HAVE_LZMA_H) && defined(HAVE_LIBLZMA)
if (xar->lzstream_valid)
lzma_end(&(xar->lzstream));
#elif defined(HAVE_LZMA_H) && defined(HAVE_LIBLZMA)
if (xar->lzstream_valid) {
if (lzmadec_end(&(xar->lzstream)) != LZMADEC_OK) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
"Failed to clean up lzmadec decompressor");
r = ARCHIVE_FATAL;
}
}
#endif
return (r);
}
@@ -2070,7 +2070,7 @@ xml_start(struct archive_read *a, const char *name, struct xmlattr_list *list)
if (xar->file->link > 0)
if (add_link(a, xar, xar->file) != ARCHIVE_OK) {
return (ARCHIVE_FATAL);
};
}
}
}
}
@@ -2851,7 +2851,6 @@ xml_data(void *userData, const char *s, size_t len)
xar->file->has |= HAS_XATTR;
archive_strncpy(&(xar->xattr->fstype), s, len);
break;
break;
case FILE_ACL_DEFAULT:
case FILE_ACL_ACCESS:
case FILE_ACL_APPLEEXTENDED:
@@ -3343,6 +3342,326 @@ expat_read_toc(struct archive_read *a)
XML_ParserFree(parser);
return (ud.state);
}
#endif /* defined(HAVE_BSDXML_H) || defined(HAVE_EXPAT_H) */
#elif defined(HAVE_XMLLITE_H)
struct ArchiveStreamAdapter {
const ISequentialStreamVtbl *lpVtbl; /* see asaStaticVtable */
struct archive_read *a;
};
static HRESULT STDMETHODCALLTYPE
asaQueryInterface(ISequentialStream *this, REFIID riid, void **ppv)
{
if (!IsEqualIID(riid, &IID_ISequentialStream)) {
*ppv = NULL;
return E_NOINTERFACE;
}
*ppv = this;
return S_OK;
}
/*
* We can dispense with reference counting as we tightly manage the lifetime
* of an ArchiveStreamAdapter.
*/
static ULONG STDMETHODCALLTYPE
asaAddRef(ISequentialStream *this)
{
(void)this; /* UNUSED */
return ULONG_MAX;
}
static ULONG STDMETHODCALLTYPE
asaRelease(ISequentialStream *this)
{
(void)this; /* UNUSED */
return ULONG_MAX;
}
static HRESULT STDMETHODCALLTYPE
asaRead(ISequentialStream *this, void *pv, ULONG cb, ULONG *pcbRead)
{
struct ArchiveStreamAdapter *asa = (struct ArchiveStreamAdapter *)this;
struct archive_read *a;
struct xar *xar;
const void *d = pv;
size_t outbytes = cb;
size_t used = 0;
int r;
a = asa->a;
xar = (struct xar *)(a->format->data);
*pcbRead = 0;
if (xar->toc_remaining <= 0)
return cb != 0 ? S_FALSE : S_OK;
r = rd_contents(a, &d, &outbytes, &used, xar->toc_remaining);
if (r != ARCHIVE_OK)
return E_FAIL;
__archive_read_consume(a, used);
xar->toc_remaining -= used;
xar->offset += used;
xar->toc_total += outbytes;
PRINT_TOC(pv, outbytes);
*pcbRead = (ULONG)outbytes;
return outbytes < cb ? S_FALSE : S_OK;
}
static HRESULT STDMETHODCALLTYPE
asaWrite(ISequentialStream *this, const void *pv, ULONG cb, ULONG *pcbWritten)
{
(void)this; /* UNUSED */
(void)pv; /* UNUSED */
(void)cb; /* UNUSED */
if (!pcbWritten) return E_INVALIDARG;
*pcbWritten = 0;
return E_NOTIMPL;
}
static const ISequentialStreamVtbl asaStaticVtable = {
.QueryInterface = asaQueryInterface,
.AddRef = asaAddRef,
.Release = asaRelease,
.Read = asaRead,
.Write = asaWrite,
};
static int
xmllite_create_stream_adapter(struct archive_read *a,
struct ArchiveStreamAdapter **pasa)
{
struct ArchiveStreamAdapter *asa =
calloc(1, sizeof(struct ArchiveStreamAdapter));
if (!asa) {
archive_set_error(&(a->archive), ENOMEM, "Out of memory");
return (ARCHIVE_FATAL);
}
asa->lpVtbl = &asaStaticVtable;
asa->a = a;
*pasa = asa;
return (ARCHIVE_OK);
}
typedef HRESULT(STDMETHODCALLTYPE *xmllite_wstr_func)(IXmlReader *, LPCWSTR *,
UINT *);
/*
* Returns an narrow-char archive_string in *as after calling
* the wide-char COM API callee() on the XmlReader reader.
* Sets an appropriate error on the archive if it fails.
*/
static int
xmllite_call_return_as(struct archive_read *a, struct archive_string *as,
IXmlReader *reader, xmllite_wstr_func callee)
{
LPCWSTR wcs;
UINT wlen;
if (FAILED(callee(reader, &wcs, &wlen))) {
archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
"Failed to read XML data");
return (ARCHIVE_FATAL);
}
archive_string_init(as);
if (archive_string_append_from_wcs(as, wcs, (size_t)wlen) < 0) {
archive_string_free(as);
archive_set_error(&(a->archive), ENOMEM, "Out of memory");
return (ARCHIVE_FATAL);
}
return (ARCHIVE_OK);
}
static char *
xmllite_call_return_mbs(struct archive_read *a, IXmlReader *reader,
xmllite_wstr_func callee)
{
char *ret;
struct archive_string as;
if (xmllite_call_return_as(a, &as, reader, callee) < 0) {
return NULL;
}
ret = strdup(as.s);
archive_string_free(&as);
if (ret == NULL) {
archive_set_error(&(a->archive), ENOMEM, "Out of memory");
return NULL;
}
return ret;
}
static int
xmllite_xmlattr_setup(struct archive_read *a,
struct xmlattr_list *list, IXmlReader *reader)
{
struct xmlattr *attr;
HRESULT hr;
list->first = NULL;
list->last = &(list->first);
hr = reader->lpVtbl->MoveToFirstAttribute(reader);
/* Contrary to other checks, we're not using SUCCEEDED/FAILED
* because MoveToNextAttribute returns *S_FALSE* (success!)
* when it runs out of attributes.
*/
while (hr == S_OK) {
/* Attributes implied as being default by the DTD are ignored */
if (reader->lpVtbl->IsDefault(reader))
continue;
attr = malloc(sizeof*(attr));
if (attr == NULL) {
archive_set_error(&(a->archive), ENOMEM,
"Out of memory");
return (ARCHIVE_FATAL);
}
attr->name = xmllite_call_return_mbs(a, reader,
reader->lpVtbl->GetLocalName);
if (attr->name == NULL) {
free(attr);
/* xmllite_call_return_mbs sets an appropriate error */
return (ARCHIVE_FATAL);
}
attr->value = xmllite_call_return_mbs(a, reader,
reader->lpVtbl->GetValue);
if (attr->value == NULL) {
free(attr->name);
free(attr);
/* xmllite_call_return_mbs sets an appropriate error */
return (ARCHIVE_FATAL);
}
attr->next = NULL;
*list->last = attr;
list->last = &(attr->next);
hr = reader->lpVtbl->MoveToNextAttribute(reader);
}
if (FAILED(hr)) {
archive_set_error(&(a->archive), ARCHIVE_ERRNO_FILE_FORMAT,
"Failed to parse XML document");
return (ARCHIVE_FAILED);
}
return (ARCHIVE_OK);
}
static int
xmllite_read_toc(struct archive_read *a)
{
struct ArchiveStreamAdapter *asa = NULL;
char *name;
struct archive_string as;
BOOL empty;
XmlNodeType type;
struct xmlattr_list list;
IXmlReader *reader = NULL;
int r = ARCHIVE_OK;
if ((r = xmllite_create_stream_adapter(a, &asa)) < 0) {
goto out;
}
if (FAILED(CreateXmlReader(&IID_IXmlReader, (void **)&reader, NULL))) {
r = ARCHIVE_FATAL;
goto out;
}
if (FAILED(reader->lpVtbl->SetInput(reader, (IUnknown *)asa))) {
archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
"Failed to prepare XML stream");
r = ARCHIVE_FATAL;
goto out;
}
while (!reader->lpVtbl->IsEOF(reader)) {
if (FAILED(reader->lpVtbl->Read(reader, &type))) {
archive_set_error(&(a->archive), ARCHIVE_ERRNO_MISC,
"Failed to read XML stream");
r = ARCHIVE_FATAL;
goto out;
}
switch (type) {
case XmlNodeType_Element:
empty = reader->lpVtbl->IsEmptyElement(reader);
name = xmllite_call_return_mbs(a, reader,
reader->lpVtbl->GetLocalName);
if (name == NULL) {
/* xmllite_call_return_mbs sets an appropriate error */
r = ARCHIVE_FATAL;
goto out;
}
r = xmllite_xmlattr_setup(a, &list, reader);
if (r == ARCHIVE_OK) {
r = xml_start(a, name, &list);
}
xmlattr_cleanup(&list);
if (r == ARCHIVE_OK && empty) {
xml_end(a, name);
}
free(name);
if (r != ARCHIVE_OK) {
goto out;
}
break;
case XmlNodeType_EndElement:
name = xmllite_call_return_mbs(a, reader,
reader->lpVtbl->GetLocalName);
if (name == NULL) {
/* xmllite_call_return_mbs sets an appropriate error */
r = ARCHIVE_FATAL;
goto out;
}
xml_end(a, name);
free(name);
break;
case XmlNodeType_Text:
r = xmllite_call_return_as(a, &as, reader,
reader->lpVtbl->GetValue);
if (r != ARCHIVE_OK) {
/* xmllite_call_return_as sets an appropriate error */
goto out;
}
xml_data(a, as.s, (int)archive_strlen(&as));
archive_string_free(&as);
case XmlNodeType_None:
case XmlNodeType_Attribute:
case XmlNodeType_CDATA:
case XmlNodeType_ProcessingInstruction:
case XmlNodeType_Comment:
case XmlNodeType_DocumentType:
case XmlNodeType_Whitespace:
case XmlNodeType_XmlDeclaration:
default:
break;
}
}
out:
if (reader)
reader->lpVtbl->Release(reader);
free(asa);
return r;
}
#endif /* defined(XMLLITE) */
#endif /* Support xar format */
@@ -71,6 +71,7 @@
#include "archive_private.h"
#include "archive_rb.h"
#include "archive_read_private.h"
#include "archive_time_private.h"
#include "archive_ppmd8_private.h"
#ifndef HAVE_ZLIB_H
@@ -465,27 +466,6 @@ compression_name(const int compression)
return "??";
}
/* Convert an MSDOS-style date/time into Unix-style time. */
static time_t
zip_time(const char *p)
{
int msTime, msDate;
struct tm ts;
msTime = (0xff & (unsigned)p[0]) + 256 * (0xff & (unsigned)p[1]);
msDate = (0xff & (unsigned)p[2]) + 256 * (0xff & (unsigned)p[3]);
memset(&ts, 0, sizeof(ts));
ts.tm_year = ((msDate >> 9) & 0x7f) + 80; /* Years since 1900. */
ts.tm_mon = ((msDate >> 5) & 0x0f) - 1; /* Month number. */
ts.tm_mday = msDate & 0x1f; /* Day of month. */
ts.tm_hour = (msTime >> 11) & 0x1f;
ts.tm_min = (msTime >> 5) & 0x3f;
ts.tm_sec = (msTime << 1) & 0x3e;
ts.tm_isdst = -1;
return mktime(&ts);
}
/*
* The extra data is stored as a list of
* id1+size1+data1 + id2+size2+data2 ...
@@ -978,7 +958,7 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
}
zip->init_decryption = (zip_entry->zip_flags & ZIP_ENCRYPTED);
zip_entry->compression = (char)archive_le16dec(p + 8);
zip_entry->mtime = zip_time(p + 10);
zip_entry->mtime = dos_to_unix(archive_le32dec(p + 10));
zip_entry->crc32 = archive_le32dec(p + 14);
if (zip_entry->zip_flags & ZIP_LENGTH_AT_END)
zip_entry->decdat = p[11];
@@ -2134,15 +2114,15 @@ zipx_ppmd8_init(struct archive_read *a, struct zip *zip)
if(order < 2 || restore_method > 2) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Invalid parameter set in PPMd8 stream (order=%" PRId32 ", "
"restore=%" PRId32 ")", order, restore_method);
"Invalid parameter set in PPMd8 stream (order=%" PRIu32 ", "
"restore=%" PRIu32 ")", order, restore_method);
return (ARCHIVE_FAILED);
}
/* Allocate the memory needed to properly decompress the file. */
if(!__archive_ppmd8_functions.Ppmd8_Alloc(&zip->ppmd8, mem << 20)) {
archive_set_error(&a->archive, ENOMEM,
"Unable to allocate memory for PPMd8 stream: %" PRId32 " bytes",
"Unable to allocate memory for PPMd8 stream: %" PRIu32 " bytes",
mem << 20);
return (ARCHIVE_FATAL);
}
@@ -3168,7 +3148,6 @@ archive_read_format_zip_read_data(struct archive_read *a,
/* We can't decompress this entry, but we will
* be able to skip() it and try the next entry. */
return (ARCHIVE_FAILED);
break;
}
if (r != ARCHIVE_OK)
return (r);
@@ -3987,7 +3966,7 @@ slurp_central_directory(struct archive_read *a, struct archive_entry* entry,
zip->has_encrypted_entries = 1;
}
zip_entry->compression = (char)archive_le16dec(p + 10);
zip_entry->mtime = zip_time(p + 12);
zip_entry->mtime = dos_to_unix(archive_le32dec(p + 12));
zip_entry->crc32 = archive_le32dec(p + 16);
if (zip_entry->zip_flags & ZIP_LENGTH_AT_END)
zip_entry->decdat = p[13];
+91 -50
View File
@@ -154,7 +154,6 @@ static int archive_wstring_append_from_mbs_in_codepage(
struct archive_string_conv *);
static int archive_string_append_from_wcs_in_codepage(struct archive_string *,
const wchar_t *, size_t, struct archive_string_conv *);
static int is_big_endian(void);
static int strncat_in_codepage(struct archive_string *, const void *,
size_t, struct archive_string_conv *);
static int win_strncat_from_utf16be(struct archive_string *, const void *,
@@ -199,6 +198,29 @@ static int archive_string_normalize_D(struct archive_string *, const void *,
static int archive_string_append_unicode(struct archive_string *,
const void *, size_t, struct archive_string_conv *);
#if defined __LITTLE_ENDIAN__
#define IS_BIG_ENDIAN 0
#elif defined __BIG_ENDIAN__
#define IS_BIG_ENDIAN 1
#elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
#define IS_BIG_ENDIAN 0
#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#define IS_BIG_ENDIAN 1
#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64) || defined(_M_ARM64))
#define IS_BIG_ENDIAN 0
#else
// Detect endianness at runtime.
static int
is_big_endian(void)
{
uint16_t d = 1;
return (archive_be16dec(&d) == 1);
}
#define IS_BIG_ENDIAN is_big_endian()
#endif
static struct archive_string *
archive_string_append(struct archive_string *as, const char *p, size_t s)
{
@@ -450,7 +472,8 @@ static int
archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest,
const char *s, size_t length, struct archive_string_conv *sc)
{
int count, ret = 0;
int ret = 0;
size_t count;
UINT from_cp;
if (sc != NULL)
@@ -472,7 +495,7 @@ archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest,
ws = dest->s + dest->length;
mp = (const unsigned char *)s;
count = 0;
while (count < (int)length && *mp) {
while (count < length && *mp) {
*ws++ = (wchar_t)*mp++;
count++;
}
@@ -485,7 +508,7 @@ archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest,
struct archive_string u16;
int saved_flag = sc->flag;/* save current flag. */
if (is_big_endian())
if (IS_BIG_ENDIAN)
sc->flag |= SCONV_TO_UTF16BE;
else
sc->flag |= SCONV_TO_UTF16LE;
@@ -495,16 +518,16 @@ archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest,
* UTF-16BE/LE NFD ===> UTF-16 NFC
* UTF-16BE/LE NFC ===> UTF-16 NFD
*/
count = (int)utf16nbytes(s, length);
count = utf16nbytes(s, length);
} else {
/*
* UTF-8 NFD ===> UTF-16 NFC
* UTF-8 NFC ===> UTF-16 NFD
*/
count = (int)mbsnbytes(s, length);
count = mbsnbytes(s, length);
}
u16.s = (char *)dest->s;
u16.length = dest->length << 1;;
u16.length = dest->length << 1;
u16.buffer_length = dest->buffer_length;
if (sc->flag & SCONV_NORMALIZATION_C)
ret = archive_string_normalize_C(&u16, s, count, sc);
@@ -516,23 +539,23 @@ archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest,
sc->flag = saved_flag;/* restore the saved flag. */
return (ret);
} else if (sc != NULL && (sc->flag & SCONV_FROM_UTF16)) {
count = (int)utf16nbytes(s, length);
count = utf16nbytes(s, length);
count >>= 1; /* to be WCS length */
/* Allocate memory for WCS. */
if (NULL == archive_wstring_ensure(dest,
dest->length + count + 1))
return (-1);
wmemcpy(dest->s + dest->length, (const wchar_t *)s, count);
if ((sc->flag & SCONV_FROM_UTF16BE) && !is_big_endian()) {
if ((sc->flag & SCONV_FROM_UTF16BE) && !IS_BIG_ENDIAN) {
uint16_t *u16 = (uint16_t *)(dest->s + dest->length);
int b;
size_t b;
for (b = 0; b < count; b++) {
uint16_t val = archive_le16dec(u16+b);
archive_be16enc(u16+b, val);
}
} else if ((sc->flag & SCONV_FROM_UTF16LE) && is_big_endian()) {
} else if ((sc->flag & SCONV_FROM_UTF16LE) && IS_BIG_ENDIAN) {
uint16_t *u16 = (uint16_t *)(dest->s + dest->length);
int b;
size_t b;
for (b = 0; b < count; b++) {
uint16_t val = archive_be16dec(u16+b);
archive_le16enc(u16+b, val);
@@ -556,21 +579,28 @@ archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest,
buffsize = dest->length + length + 1;
do {
int r;
/* MultiByteToWideChar is limited to int. */
if (length > (size_t)INT_MAX ||
(dest->buffer_length >> 1) > (size_t)INT_MAX)
return (-1);
/* Allocate memory for WCS. */
if (NULL == archive_wstring_ensure(dest, buffsize))
return (-1);
/* Convert MBS to WCS. */
count = MultiByteToWideChar(from_cp,
r = MultiByteToWideChar(from_cp,
mbflag, s, (int)length, dest->s + dest->length,
(int)(dest->buffer_length >> 1) -1);
if (count == 0 &&
if (r == 0 &&
GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
/* Expand the WCS buffer. */
buffsize = dest->buffer_length << 1;
continue;
}
if (count == 0 && length != 0)
if (r == 0 && length != 0)
ret = -1;
count = (size_t)r;
break;
} while (1);
}
@@ -679,9 +709,9 @@ archive_string_append_from_wcs_in_codepage(struct archive_string *as,
const wchar_t *ws, size_t len, struct archive_string_conv *sc)
{
BOOL defchar_used, *dp;
int count, ret = 0;
int ret = 0;
UINT to_cp;
int wslen = (int)len;
size_t count, wslen = len;
if (sc != NULL)
to_cp = sc->to_cp;
@@ -720,13 +750,13 @@ archive_string_append_from_wcs_in_codepage(struct archive_string *as,
count = 0;
defchar_used = 0;
if (sc->flag & SCONV_TO_UTF16BE) {
while (count < (int)len && *ws) {
while (count < len && *ws) {
archive_be16enc(u16+count, *ws);
ws++;
count++;
}
} else {
while (count < (int)len && *ws) {
while (count < len && *ws) {
archive_le16enc(u16+count, *ws);
ws++;
count++;
@@ -739,15 +769,21 @@ archive_string_append_from_wcs_in_codepage(struct archive_string *as,
archive_string_ensure(as, as->length + len * 2 + 1))
return (-1);
do {
int r;
defchar_used = 0;
if (to_cp == CP_UTF8 || sc == NULL)
dp = NULL;
else
dp = &defchar_used;
count = WideCharToMultiByte(to_cp, 0, ws, wslen,
/* WideCharToMultiByte is limited to int. */
if (as->buffer_length - as->length - 1 > (size_t)INT_MAX ||
wslen > (size_t)INT_MAX)
return (-1);
r = WideCharToMultiByte(to_cp, 0, ws, (int)wslen,
as->s + as->length,
(int)as->buffer_length - (int)as->length - 1, NULL, dp);
if (count == 0 &&
(int)(as->buffer_length - as->length - 1), NULL, dp);
if (r == 0 &&
GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
/* Expand the MBS buffer and retry. */
if (NULL == archive_string_ensure(as,
@@ -755,8 +791,9 @@ archive_string_append_from_wcs_in_codepage(struct archive_string *as,
return (-1);
continue;
}
if (count == 0)
if (r == 0)
ret = -1;
count = (size_t)r;
break;
} while (1);
}
@@ -2032,7 +2069,7 @@ iconv_strncat_in_locale(struct archive_string *as, const void *_p,
char *outp;
size_t avail, bs;
int return_value = 0; /* success */
int to_size, from_size;
size_t to_size, from_size;
if (sc->flag & SCONV_TO_UTF16)
to_size = 2;
@@ -2051,7 +2088,7 @@ iconv_strncat_in_locale(struct archive_string *as, const void *_p,
remaining = length;
outp = as->s + as->length;
avail = as->buffer_length - as->length - to_size;
while (remaining >= (size_t)from_size) {
while (remaining >= from_size) {
size_t result = iconv(cd, &itp, &remaining, &outp, &avail);
if (result != (size_t)-1)
@@ -2174,6 +2211,8 @@ invalid_mbs(const void *_p, size_t n, struct archive_string_conv *sc)
if (codepage != CP_UTF8)
mbflag |= MB_PRECOMPOSED;
if (n > (size_t)INT_MAX)
return (-1); /* Invalid */
if (MultiByteToWideChar(codepage, mbflag, p, (int)n, NULL, 0) == 0)
return (-1); /* Invalid */
return (0); /* Okay */
@@ -2327,7 +2366,7 @@ _utf8_to_unicode(uint32_t *pwc, const char *s, size_t n)
cnt = utf8_count[ch];
/* Invalid sequence or there are not plenty bytes. */
if ((int)n < cnt) {
if (n < (size_t)cnt) {
cnt = (int)n;
for (i = 1; i < cnt; i++) {
if ((s[i] & 0xc0) != 0x80) {
@@ -2396,7 +2435,7 @@ _utf8_to_unicode(uint32_t *pwc, const char *s, size_t n)
cnt = 6;
else
cnt = 1;
if ((int)n < cnt)
if (n < (size_t)cnt)
cnt = (int)n;
for (i = 1; i < cnt; i++) {
if ((s[i] & 0xc0) != 0x80) {
@@ -2612,7 +2651,7 @@ unicode_to_utf16be(char *p, size_t remaining, uint32_t uc)
} else {
if (remaining < 2)
return (0);
archive_be16enc(utf16, uc);
archive_be16enc(utf16, (uint16_t)uc);
return (2);
}
}
@@ -2634,7 +2673,7 @@ unicode_to_utf16le(char *p, size_t remaining, uint32_t uc)
} else {
if (remaining < 2)
return (0);
archive_le16enc(utf16, uc);
archive_le16enc(utf16, (uint16_t)uc);
return (2);
}
}
@@ -3499,10 +3538,9 @@ win_strncat_from_utf16(struct archive_string *as, const void *_p, size_t bytes,
{
struct archive_string tmp;
const char *u16;
int ll;
BOOL defchar;
char *mbs;
size_t mbs_size, b;
size_t mbs_size, b, ll;
int ret = 0;
bytes &= ~1;
@@ -3538,7 +3576,7 @@ win_strncat_from_utf16(struct archive_string *as, const void *_p, size_t bytes,
archive_string_init(&tmp);
if (be) {
if (is_big_endian()) {
if (IS_BIG_ENDIAN) {
u16 = _p;
} else {
if (archive_string_ensure(&tmp, bytes+2) == NULL)
@@ -3551,7 +3589,7 @@ win_strncat_from_utf16(struct archive_string *as, const void *_p, size_t bytes,
u16 = tmp.s;
}
} else {
if (!is_big_endian()) {
if (!IS_BIG_ENDIAN) {
u16 = _p;
} else {
if (archive_string_ensure(&tmp, bytes+2) == NULL)
@@ -3566,18 +3604,24 @@ win_strncat_from_utf16(struct archive_string *as, const void *_p, size_t bytes,
}
do {
int r;
defchar = 0;
ll = WideCharToMultiByte(sc->to_cp, 0,
/* WideCharToMultiByte is limited to int. */
if (bytes > (size_t)INT_MAX || mbs_size > (size_t)INT_MAX)
return (-1);
r = WideCharToMultiByte(sc->to_cp, 0,
(LPCWSTR)u16, (int)bytes>>1, mbs, (int)mbs_size,
NULL, &defchar);
/* Exit loop if we succeeded */
if (ll != 0 ||
if (r != 0 ||
GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
ll = (size_t)r;
break;
}
/* Else expand buffer and loop to try again. */
ll = WideCharToMultiByte(sc->to_cp, 0,
r = WideCharToMultiByte(sc->to_cp, 0,
(LPCWSTR)u16, (int)bytes, NULL, 0, NULL, NULL);
ll = (size_t)r;
if (archive_string_ensure(as, ll +1) == NULL)
return (-1);
mbs = as->s + as->length;
@@ -3605,14 +3649,6 @@ win_strncat_from_utf16le(struct archive_string *as, const void *_p,
return (win_strncat_from_utf16(as, _p, bytes, sc, 0));
}
static int
is_big_endian(void)
{
uint16_t d = 1;
return (archive_be16dec(&d) == 1);
}
/*
* Convert a current locale string to UTF-16BE/LE and copy the result.
* Return -1 if conversion fails.
@@ -3651,16 +3687,21 @@ win_strncat_to_utf16(struct archive_string *as16, const void *_p,
return (0);
}
do {
count = MultiByteToWideChar(sc->from_cp,
int r;
if (length > (size_t)INT_MAX || (avail >> 1) > (size_t)INT_MAX)
return (-1);
r = MultiByteToWideChar(sc->from_cp,
MB_PRECOMPOSED, s, (int)length, (LPWSTR)u16, (int)avail>>1);
/* Exit loop if we succeeded */
if (count != 0 ||
if (r != 0 ||
GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
count = (size_t)r;
break;
}
/* Expand buffer and try again */
count = MultiByteToWideChar(sc->from_cp,
r = MultiByteToWideChar(sc->from_cp,
MB_PRECOMPOSED, s, (int)length, NULL, 0);
count = (size_t)r;
if (archive_string_ensure(as16, (count +1) * 2)
== NULL)
return (-1);
@@ -3673,7 +3714,7 @@ win_strncat_to_utf16(struct archive_string *as16, const void *_p,
if (count == 0)
return (-1);
if (is_big_endian()) {
if (IS_BIG_ENDIAN) {
if (!bigendian) {
while (count > 0) {
uint16_t v = archive_be16dec(u16);
@@ -3811,9 +3852,9 @@ best_effort_strncat_to_utf16(struct archive_string *as16, const void *_p,
ret = -1;
}
if (bigendian)
archive_be16enc(utf16, c);
archive_be16enc(utf16, (uint16_t)c);
else
archive_le16enc(utf16, c);
archive_le16enc(utf16, (uint16_t)c);
utf16 += 2;
}
as16->length = utf16 - as16->s;
@@ -2286,5 +2286,4 @@ static const struct unicode_decomposition_table u_decomposition_table[] = {
{ 0x110AB , 0x110A5 , 0x110BA },
};
#endif /* ARCHIVE_STRING_COMPOSITION_H_INCLUDED */
#endif /* !ARCHIVE_STRING_COMPOSITION_H_INCLUDED */
@@ -116,8 +116,14 @@ archive_string_vsprintf(struct archive_string *as, const char *fmt,
long_flag = '\0';
switch(*p) {
case 'j':
case 'l':
if (p[1] == 'l') {
long_flag = 'L';
p += 2;
break;
}
__LA_FALLTHROUGH;
case 'j':
case 'z':
long_flag = *p;
p++;
@@ -136,6 +142,7 @@ archive_string_vsprintf(struct archive_string *as, const char *fmt,
switch(long_flag) {
case 'j': s = va_arg(ap, intmax_t); break;
case 'l': s = va_arg(ap, long); break;
case 'L': s = va_arg(ap, long long); break;
case 'z': s = va_arg(ap, ssize_t); break;
default: s = va_arg(ap, int); break;
}
@@ -144,6 +151,7 @@ archive_string_vsprintf(struct archive_string *as, const char *fmt,
case 's':
switch(long_flag) {
case 'l':
case 'L':
pw = va_arg(ap, wchar_t *);
if (pw == NULL)
pw = L"(null)";
@@ -172,6 +180,7 @@ archive_string_vsprintf(struct archive_string *as, const char *fmt,
switch(long_flag) {
case 'j': u = va_arg(ap, uintmax_t); break;
case 'l': u = va_arg(ap, unsigned long); break;
case 'L': u = va_arg(ap, unsigned long long); break;
case 'z': u = va_arg(ap, size_t); break;
default: u = va_arg(ap, unsigned int); break;
}
@@ -0,0 +1,163 @@
/*-
* Copyright © 2025 ARJANEN Loïc Jean David
* 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.
* 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 "archive_platform.h"
#include "archive_private.h"
#include "archive_time_private.h"
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#define NTFS_EPOC_TIME ARCHIVE_LITERAL_ULL(11644473600)
#define NTFS_TICKS ARCHIVE_LITERAL_ULL(10000000)
#define NTFS_EPOC_TICKS (NTFS_EPOC_TIME * NTFS_TICKS)
#define DOS_MIN_TIME 0x00210000U
#define DOS_MAX_TIME 0xff9fbf7dU
#if defined(_WIN32) && !defined(__CYGWIN__)
#include <winnt.h>
/* Windows FILETIME to NTFS time. */
uint64_t
FILETIME_to_ntfs(const FILETIME* filetime)
{
ULARGE_INTEGER utc;
utc.HighPart = filetime->dwHighDateTime;
utc.LowPart = filetime->dwLowDateTime;
return utc.QuadPart;
}
#endif
/* Convert an MSDOS-style date/time into Unix-style time. */
int64_t
dos_to_unix(uint32_t dos_time)
{
uint16_t msTime, msDate;
struct tm ts;
time_t t;
msTime = (0xFFFF & dos_time);
msDate = (dos_time >> 16);
memset(&ts, 0, sizeof(ts));
ts.tm_year = ((msDate >> 9) & 0x7f) + 80; /* Years since 1900. */
ts.tm_mon = ((msDate >> 5) & 0x0f) - 1; /* Month number. */
ts.tm_mday = msDate & 0x1f; /* Day of month. */
ts.tm_hour = (msTime >> 11) & 0x1f;
ts.tm_min = (msTime >> 5) & 0x3f;
ts.tm_sec = (msTime << 1) & 0x3e;
ts.tm_isdst = -1;
t = mktime(&ts);
return (int64_t)(t == (time_t)-1 ? INT32_MAX : t);
}
/* Convert into MSDOS-style date/time. */
uint32_t
unix_to_dos(int64_t unix_time)
{
struct tm *t;
uint32_t dt;
time_t ut = unix_time;
#if defined(HAVE_LOCALTIME_R) || defined(HAVE_LOCALTIME_S)
struct tm tmbuf;
#endif
if (sizeof(time_t) < sizeof(int64_t) && (int64_t)ut != unix_time) {
ut = (time_t)(unix_time > 0 ? INT32_MAX : INT32_MIN);
}
#if defined(HAVE_LOCALTIME_S)
t = localtime_s(&tmbuf, &ut) ? NULL : &tmbuf;
#elif defined(HAVE_LOCALTIME_R)
t = localtime_r(&ut, &tmbuf);
#else
t = localtime(&ut);
#endif
dt = 0;
if (t != NULL && t->tm_year >= INT_MIN + 80) {
const int year = t->tm_year - 80;
if (year & ~0x7f) {
dt = year > 0 ? DOS_MAX_TIME : DOS_MIN_TIME;
}
else {
dt += (year & 0x7f) << 9;
dt += ((t->tm_mon + 1) & 0x0f) << 5;
dt += (t->tm_mday & 0x1f);
dt <<= 16;
dt += (t->tm_hour & 0x1f) << 11;
dt += (t->tm_min & 0x3f) << 5;
/* Only counting every 2 seconds. */
dt += (t->tm_sec & 0x3e) >> 1;
}
}
if (dt > DOS_MAX_TIME) {
dt = DOS_MAX_TIME;
}
else if (dt < DOS_MIN_TIME) {
dt = DOS_MIN_TIME;
}
return dt;
}
/* Convert NTFS time to Unix sec/nsec */
void
ntfs_to_unix(uint64_t ntfs, int64_t* secs, uint32_t* nsecs)
{
if (ntfs > INT64_MAX) {
ntfs -= NTFS_EPOC_TICKS;
*secs = ntfs / NTFS_TICKS;
*nsecs = 100 * (ntfs % NTFS_TICKS);
}
else {
lldiv_t tdiv;
int64_t value = (int64_t)ntfs - (int64_t)NTFS_EPOC_TICKS;
tdiv = lldiv(value, NTFS_TICKS);
*secs = tdiv.quot;
*nsecs = (uint32_t)(tdiv.rem * 100);
}
}
/* Convert Unix sec/nsec to NTFS time */
uint64_t
unix_to_ntfs(int64_t secs, uint32_t nsecs)
{
uint64_t ntfs;
if (secs < -(int64_t)NTFS_EPOC_TIME)
return 0;
ntfs = secs + NTFS_EPOC_TIME;
if (ntfs > UINT64_MAX / NTFS_TICKS)
return UINT64_MAX;
ntfs *= NTFS_TICKS;
if (ntfs > UINT64_MAX - nsecs/100)
return UINT64_MAX;
return ntfs + nsecs/100;
}
@@ -1,5 +1,5 @@
/*-
* Copyright (c) 2003-2015 Tim Kientzle
* Copyright © 2025 ARJANEN Loïc Jean David
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -22,16 +22,26 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef ARCHIVE_GETDATE_H_INCLUDED
#define ARCHIVE_GETDATE_H_INCLUDED
#ifndef ARCHIVE_TIME_PRIVATE_H_INCLUDED
#define ARCHIVE_TIME_PRIVATE_H_INCLUDED
#ifndef __LIBARCHIVE_BUILD
#error This header is only to be used internally to libarchive.
#endif
#include <stdint.h>
#include <time.h>
time_t __archive_get_date(time_t now, const char *);
/* NTFS time to Unix sec/nsec. */
void ntfs_to_unix(uint64_t ntfs, int64_t* secs, uint32_t* nsecs);
/* DOS time to Unix sec. */
int64_t dos_to_unix(uint32_t dos);
/* Unix sec/nsec to NTFS time. */
uint64_t unix_to_ntfs(int64_t secs, uint32_t nsecs);
/* Unix sec to DOS time. */
uint32_t unix_to_dos(int64_t secs);
#if defined(_WIN32) && !defined(__CYGWIN__)
#include <windef.h>
#include <winbase.h>
/* Windows FILETIME to NTFS time. */
uint64_t FILETIME_to_ntfs(const FILETIME* filetime);
#endif
#endif /* ARCHIVE_TIME_PRIVATE_H_INCLUDED */
+16 -60
View File
@@ -77,7 +77,9 @@
#define O_CLOEXEC 0
#endif
static int archive_utility_string_sort_helper(char **, unsigned int);
#if ARCHIVE_VERSION_NUMBER < 4000000
static int __LA_LIBC_CC archive_utility_string_sort_helper(const void *, const void *);
#endif
/* Generic initialization of 'struct archive' objects. */
int
@@ -629,74 +631,28 @@ __archive_ensure_cloexec_flag(int fd)
#endif
}
#if ARCHIVE_VERSION_NUMBER < 4000000
/*
* Utility function to sort a group of strings using quicksort.
* Utility functions to sort a group of strings using quicksort.
*/
static int
archive_utility_string_sort_helper(char **strings, unsigned int n)
__LA_LIBC_CC
archive_utility_string_sort_helper(const void *p1, const void *p2)
{
unsigned int i, lesser_count, greater_count;
char **lesser, **greater, **tmp, *pivot;
int retval1, retval2;
const char * const * const s1 = p1;
const char * const * const s2 = p2;
/* A list of 0 or 1 elements is already sorted */
if (n <= 1)
return (ARCHIVE_OK);
lesser_count = greater_count = 0;
lesser = greater = NULL;
pivot = strings[0];
for (i = 1; i < n; i++)
{
if (strcmp(strings[i], pivot) < 0)
{
lesser_count++;
tmp = realloc(lesser, lesser_count * sizeof(*tmp));
if (!tmp) {
free(greater);
free(lesser);
return (ARCHIVE_FATAL);
}
lesser = tmp;
lesser[lesser_count - 1] = strings[i];
}
else
{
greater_count++;
tmp = realloc(greater, greater_count * sizeof(*tmp));
if (!tmp) {
free(greater);
free(lesser);
return (ARCHIVE_FATAL);
}
greater = tmp;
greater[greater_count - 1] = strings[i];
}
}
/* quicksort(lesser) */
retval1 = archive_utility_string_sort_helper(lesser, lesser_count);
for (i = 0; i < lesser_count; i++)
strings[i] = lesser[i];
free(lesser);
/* pivot */
strings[lesser_count] = pivot;
/* quicksort(greater) */
retval2 = archive_utility_string_sort_helper(greater, greater_count);
for (i = 0; i < greater_count; i++)
strings[lesser_count + 1 + i] = greater[i];
free(greater);
return (retval1 < retval2) ? retval1 : retval2;
return strcmp(*s1, *s2);
}
int
archive_utility_string_sort(char **strings)
{
unsigned int size = 0;
while (strings[size] != NULL)
size_t size = 0;
while (strings[size] != NULL)
size++;
return archive_utility_string_sort_helper(strings, size);
qsort(strings, size, sizeof(char *),
archive_utility_string_sort_helper);
return (ARCHIVE_OK);
}
#endif
@@ -46,11 +46,125 @@
#endif
#ifdef HAVE_ZSTD_H
#include <zstd.h>
#include <stdio.h>
#endif
#ifdef HAVE_LZO_LZOCONF_H
#include <lzo/lzoconf.h>
#endif
#if HAVE_LIBXML_XMLVERSION_H
#include <libxml/xmlversion.h>
#elif HAVE_BSDXML_H
#include <bsdxml.h>
#elif HAVE_EXPAT_H
#include <expat.h>
#endif
#if HAVE_MBEDTLS_VERSION_H
#include <mbedtls/version.h>
#endif
#if HAVE_NETTLE_VERSION_H
#include <nettle/version.h>
#include <stdio.h>
#endif
#if HAVE_OPENSSL_OPENSSLV_H
#include <openssl/opensslv.h>
#include <stdio.h>
#endif
#if HAVE_ICONV_H
#include <iconv.h>
#endif
#if HAVE_PCRE_H
#include <pcre.h>
#endif
#if HAVE_PCRE2_H
#include <pcre2.h>
#endif
#include "archive.h"
#include "archive_private.h"
#include "archive_string.h"
#include "archive_cryptor_private.h"
#include "archive_digest_private.h"
static void
archive_regex_version(struct archive_string* str)
{
#if HAVE_LIBPCREPOSIX && HAVE_PCRE_H
archive_strcat(str, " libpcre/");
archive_strcat(str, archive_libpcre_version());
#elif HAVE_LIBPCRE2POSIX && HAVE_PCRE2_H
archive_strcat(str, " libpcre2/");
archive_strcat(str, archive_libpcre2_version());
#else
(void)str; /* UNUSED */
#endif
}
static void
archive_xml_version(struct archive_string* str)
{
#if HAVE_LIBXML_XMLVERSION_H && HAVE_LIBXML2
archive_strcat(str, " libxml2/");
archive_strcat(str, archive_libxml2_version());
#elif HAVE_BSDXML_H && HAVE_LIBBSDXML
archive_strcat(str, " bsdxml/");
archive_strcat(str, archive_libbsdxml_version());
#elif HAVE_EXPAT_H && HAVE_LIBEXPAT
archive_strcat(str, " expat/");
archive_strcat(str, archive_libexpat_version());
#else
(void)str; /* UNUSED */
#endif
}
static void
archive_libb2_version(struct archive_string* str)
{
archive_strcat(str, " libb2/");
#if HAVE_BLAKE2_H && HAVE_LIBB2
#if defined(LIBB2_PKGCONFIG_VERSION)
archive_strcat(str, LIBB2_PKGCONFIG_VERSION);
#else
archive_strcat(str, "system");
#endif
#else
archive_strcat(str, "bundled");
#endif
}
static void
archive_crypto_version(struct archive_string* str)
{
#if defined(ARCHIVE_CRYPTOR_USE_Apple_CommonCrypto)
archive_strcat(str, " CommonCrypto/");
archive_strcat(str, archive_commoncrypto_version());
#endif
#if defined(ARCHIVE_CRYPTOR_USE_CNG)
archive_strcat(str, " cng/");
archive_strcat(str, archive_cng_version());
#endif
#if defined(ARCHIVE_CRYPTOR_USE_MBED)
archive_strcat(str, " mbedtls/");
archive_strcat(str, archive_mbedtls_version());
#endif
#if defined(ARCHIVE_CRYPTOR_USE_NETTLE)
archive_strcat(str, " nettle/");
archive_strcat(str, archive_nettle_version());
#endif
#if defined(ARCHIVE_CRYPTOR_USE_OPENSSL)
archive_strcat(str, " openssl/");
archive_strcat(str, archive_openssl_version());
#endif
#if defined(ARCHIVE_CRYPTOR_USE_LIBMD)
archive_strcat(str, " libmd/");
archive_strcat(str, archive_libmd_version());
#endif
#if defined(ARCHIVE_CRYPTOR_USE_WINCRYPT)
archive_strcat(str, " WinCrypt/");
archive_strcat(str, archive_wincrypt_version());
#endif
// Just in case
(void)str; /* UNUSED */
}
const char *
archive_version_details(void)
@@ -62,12 +176,17 @@ archive_version_details(void)
const char *bzlib = archive_bzlib_version();
const char *liblz4 = archive_liblz4_version();
const char *libzstd = archive_libzstd_version();
const char *liblzo = archive_liblzo2_version();
const char *libiconv = archive_libiconv_version();
const char *libacl = archive_libacl_version();
const char *librichacl = archive_librichacl_version();
const char *libattr = archive_libacl_version();
if (!init) {
archive_string_init(&str);
archive_strcat(&str, ARCHIVE_VERSION_STRING);
if (zlib != NULL) {
if (zlib) {
archive_strcat(&str, " zlib/");
archive_strcat(&str, zlib);
}
@@ -91,6 +210,30 @@ archive_version_details(void)
archive_strcat(&str, " libzstd/");
archive_strcat(&str, libzstd);
}
if (liblzo) {
archive_strcat(&str, " liblzo2/");
archive_strcat(&str, liblzo);
}
archive_xml_version(&str);
archive_regex_version(&str);
archive_crypto_version(&str);
archive_libb2_version(&str);
if (librichacl) {
archive_strcat(&str, " librichacl/");
archive_strcat(&str, librichacl);
}
if (libacl) {
archive_strcat(&str, " libacl/");
archive_strcat(&str, libacl);
}
if (libattr) {
archive_strcat(&str, " libattr/");
archive_strcat(&str, libattr);
}
if (libiconv) {
archive_strcat(&str, " libiconv/");
archive_strcat(&str, libiconv);
}
}
return str.s;
}
@@ -98,8 +241,8 @@ archive_version_details(void)
const char *
archive_zlib_version(void)
{
#ifdef HAVE_ZLIB_H
return ZLIB_VERSION;
#if HAVE_ZLIB_H && HAVE_LIBZ
return zlibVersion();
#else
return NULL;
#endif
@@ -108,8 +251,8 @@ archive_zlib_version(void)
const char *
archive_liblzma_version(void)
{
#ifdef HAVE_LZMA_H
return LZMA_VERSION_STRING;
#if HAVE_LZMA_H && HAVE_LIBLZMA
return lzma_version_string();
#else
return NULL;
#endif
@@ -118,7 +261,7 @@ archive_liblzma_version(void)
const char *
archive_bzlib_version(void)
{
#ifdef HAVE_BZLIB_H
#if HAVE_BZLIB_H && HAVE_LIBBZ2
return BZ2_bzlibVersion();
#else
return NULL;
@@ -128,12 +271,22 @@ archive_bzlib_version(void)
const char *
archive_liblz4_version(void)
{
#if defined(HAVE_LZ4_H) && defined(HAVE_LIBLZ4)
#if HAVE_LZ4_H && HAVE_LIBLZ4
#if LZ4_VERSION_NUMBER > 10705
return LZ4_versionString();
#elif LZ4_VERSION_NUMBER > 10300
div_t major = div(LZ4_versionNumber(), 10000);
div_t minor = div(major.rem, 100);
static char lz4_version[9];
snprintf(lz4_version, 9, "%d.%d.%d", major.quot, minor.quot, minor.rem);
return lz4_version;
#else
#define str(s) #s
#define NUMBER(x) str(x)
return NUMBER(LZ4_VERSION_MAJOR) "." NUMBER(LZ4_VERSION_MINOR) "." NUMBER(LZ4_VERSION_RELEASE);
#undef NUMBER
#undef str
#endif
#else
return NULL;
#endif
@@ -143,7 +296,243 @@ const char *
archive_libzstd_version(void)
{
#if HAVE_ZSTD_H && HAVE_LIBZSTD
return ZSTD_VERSION_STRING;
#if ZSTD_VERSION_NUMBER > 10300
return ZSTD_versionString();
#else
div_t major = div(ZSTD_versionNumber(), 10000);
div_t minor = div(major.rem, 100);
static char zstd_version[9];
snprintf(zstd_version, 9, "%d.%d.%d", major.quot, minor.quot, minor.rem);
return zstd_version;
#endif
#else
return NULL;
#endif
}
const char *
archive_liblzo2_version(void)
{
#if HAVE_LZO_LZOCONF_H && HAVE_LIBLZO2
return LZO_VERSION_STRING;
#else
return NULL;
#endif
}
const char *
archive_libbsdxml_version(void)
{
#if HAVE_BSDXML_H && HAVE_LIBBSDXML
return XML_ExpatVersion();
#else
return NULL;
#endif
}
const char *
archive_libxml2_version(void)
{
#if HAVE_LIBXML_XMLREADER_H && HAVE_LIBXML2
return LIBXML_DOTTED_VERSION;
#else
return NULL;
#endif
}
const char *
archive_libexpat_version(void)
{
#if HAVE_EXPAT_H && HAVE_LIBEXPAT
return XML_ExpatVersion();
#else
return NULL;
#endif
}
const char *
archive_mbedtls_version(void)
{
#if defined(ARCHIVE_CRYPTOR_USE_MBED) || defined(ARCHIVE_CRYPTO_MBED)
static char mbed_version[9];
mbedtls_version_get_string(mbed_version);
return mbed_version;
#else
return NULL;
#endif
}
const char *
archive_nettle_version(void)
{
#if defined(ARCHIVE_CRYPTOR_USE_NETTLE) || defined(ARCHIVE_CRYPTO_NETTLE)
static char nettle_version[6];
snprintf(nettle_version, 6, "%d.%d", nettle_version_major(), nettle_version_minor());
return nettle_version;
#else
return NULL;
#endif
}
const char *
archive_openssl_version(void)
{
#if defined(ARCHIVE_CRYPTOR_USE_OPENSSL) || defined(ARCHIVE_CRYPTO_OPENSSL)
#ifdef OPENSSL_VERSION_STR
return OPENSSL_VERSION_STR;
#else
#define OPENSSL_MAJOR (OPENSSL_VERSION_NUMBER >> 28)
#define OPENSSL_MINOR ((OPENSSL_VERSION_NUMBER >> 20) & 0xFF)
static char openssl_version[6];
snprintf(openssl_version, 6, "%ld.%ld", OPENSSL_MAJOR, OPENSSL_MINOR);
return openssl_version;
#undef OPENSSL_MAJOR
#undef OPENSSL_MINOR
#endif
#else
return NULL;
#endif
}
const char *
archive_libmd_version(void)
{
#if defined(ARCHIVE_CRYPTOR_USE_LIBMD) || defined(ARCHIVE_CRYPTO_LIBMD)
return "system";
#else
return NULL;
#endif
}
const char *
archive_commoncrypto_version(void)
{
#if defined(ARCHIVE_CRYPTOR_USE_Apple_CommonCrypto) || defined(ARCHIVE_CRYPTO_CommonCrypto)
return "system";
#else
return NULL;
#endif
}
const char *
archive_cng_version(void)
{
#if defined(ARCHIVE_CRYPTOR_USE_CNG) || defined(ARCHIVE_CRYPTO_CNG)
#ifdef BCRYPT_HASH_INTERFACE_MAJORVERSION_2
return "2.0";
#else
return "1.0";
#endif
#else
return NULL;
#endif
}
const char *
archive_wincrypt_version(void)
{
#if defined(ARCHIVE_CRYPTOR_USE_WINCRYPT) || defined(ARCHIVE_CRYPTO_WINCRYPT)
HCRYPTPROV prov;
if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
if (GetLastError() != (DWORD)NTE_BAD_KEYSET)
return NULL;
if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET))
return NULL;
}
DWORD version, length = sizeof(version);
if (!CryptGetProvParam(prov, PP_VERSION, (BYTE *)&version, &length, 0)) {
return NULL;
} else {
char major = (version >> 8) & 0xFF;
char minor = version & 0xFF;
static char wincrypt_version[6];
snprintf(wincrypt_version, 6, "%hhd.%hhd", major, minor);
return wincrypt_version;
}
#else
return NULL;
#endif
}
const char *
archive_librichacl_version(void)
{
#if HAVE_LIBRICHACL
#if defined(LIBRICHACL_PKGCONFIG_VERSION)
return LIBRICHACL_PKGCONFIG_VERSION;
#else
return "system";
#endif
#else
return NULL;
#endif
}
const char *
archive_libacl_version(void)
{
#if HAVE_LIBACL
#if defined(LIBACL_PKGCONFIG_VERSION)
return LIBACL_PKGCONFIG_VERSION;
#else
return "system";
#endif
#else
return NULL;
#endif
}
const char *
archive_libattr_version(void)
{
#if HAVE_LIBATTR
#if defined(LIBATTR_PKGCONFIG_VERSION)
return LIBATTR_PKGCONFIG_VERSION;
#else
return "system";
#endif
#else
return NULL;
#endif
}
const char *
archive_libiconv_version(void)
{
#if HAVE_LIBCHARSET && HAVE_ICONV_H
char major = _libiconv_version >> 8;
char minor = _libiconv_version & 0xFF;
static char charset_version[6];
snprintf(charset_version, 6, "%hhd.%hhd", major, minor);
return charset_version;
#else
return NULL;
#endif
}
const char *
archive_libpcre_version(void)
{
#if HAVE_LIBPCREPOSIX && HAVE_PCRE_H
#define str(s) #s
#define NUMBER(x) str(x)
return NUMBER(PCRE_MAJOR) "." NUMBER(PCRE_MINOR);
#undef NUMBER
#undef str
#else
return NULL;
#endif
}
const char *
archive_libpcre2_version(void)
{
#if HAVE_LIBPCRE2POSIX && HAVE_PCRE2_H
#define str(s) #s
#define NUMBER(x) str(x)
return NUMBER(PCRE2_MAJOR) "." NUMBER(PCRE2_MINOR);
#undef NUMBER
#undef str
#else
return NULL;
#endif
@@ -283,7 +283,7 @@ __archive_write_filters_open(struct archive_write *a)
}
/*
* Close all filtes
* Close all filters
*/
static int
__archive_write_filters_close(struct archive_write *a)
@@ -166,7 +166,7 @@ archive_filter_b64encode_open(struct archive_write_filter *f)
}
archive_string_sprintf(&state->encoded_buff, "begin-base64 %o %s\n",
state->mode, state->name.s);
(unsigned int)state->mode, state->name.s);
f->data = state;
return (0);
@@ -58,6 +58,7 @@ archive_write_set_compression_gzip(struct archive *a)
struct private_data {
int compression_level;
int timestamp;
char *original_filename;
#ifdef HAVE_ZLIB_H
z_stream stream;
int64_t total_in;
@@ -113,6 +114,8 @@ archive_write_add_filter_gzip(struct archive *_a)
f->free = &archive_compressor_gzip_free;
f->code = ARCHIVE_FILTER_GZIP;
f->name = "gzip";
data->original_filename = NULL;
#ifdef HAVE_ZLIB_H
data->compression_level = Z_DEFAULT_COMPRESSION;
return (ARCHIVE_OK);
@@ -140,6 +143,7 @@ archive_compressor_gzip_free(struct archive_write_filter *f)
#else
__archive_write_program_free(data->pdata);
#endif
free((void*)data->original_filename);
free(data);
f->data = NULL;
return (ARCHIVE_OK);
@@ -165,6 +169,13 @@ archive_compressor_gzip_options(struct archive_write_filter *f, const char *key,
data->timestamp = (value == NULL)?-1:1;
return (ARCHIVE_OK);
}
if (strcmp(key, "original-filename") == 0) {
free((void*)data->original_filename);
data->original_filename = NULL;
if (value)
data->original_filename = strdup(value);
return (ARCHIVE_OK);
}
/* Note: The "warn" return is just to inform the options
* supervisor that we didn't handle it. It will generate
@@ -210,7 +221,7 @@ archive_compressor_gzip_open(struct archive_write_filter *f)
data->compressed[0] = 0x1f; /* GZip signature bytes */
data->compressed[1] = 0x8b;
data->compressed[2] = 0x08; /* "Deflate" compression */
data->compressed[3] = 0; /* No options */
data->compressed[3] = data->original_filename == NULL ? 0 : 0x8;
if (data->timestamp >= 0) {
time_t t = time(NULL);
data->compressed[4] = (uint8_t)(t)&0xff; /* Timestamp */
@@ -229,6 +240,12 @@ archive_compressor_gzip_open(struct archive_write_filter *f)
data->stream.next_out += 10;
data->stream.avail_out -= 10;
if (data->original_filename != NULL) {
strcpy((char*)data->compressed + 10, data->original_filename);
data->stream.next_out += strlen(data->original_filename) + 1;
data->stream.avail_out -= strlen(data->original_filename) + 1;
}
f->write = archive_compressor_gzip_write;
/* Initialize compression library. */
@@ -155,7 +155,7 @@ archive_filter_uuencode_open(struct archive_write_filter *f)
}
archive_string_sprintf(&state->encoded_buff, "begin %o %s\n",
state->mode, state->name.s);
(unsigned int)state->mode, state->name.s);
f->data = state;
return (0);
Loaded 100 of 537 files, more files were not shown because too many files have changed in this diff. Show more