opnsense-src/contrib/libarchive/test_utils/test_utils.c
Martin Matuska 4e9261006a 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, main, libarchive 3.8.0)
Approved by:	so
Security:	FreeBSD-SA-25:07.libarchive

(cherry picked from commit 2e113ef82465598b8c26e0ca415fbe90677fbd47)
(cherry picked from commit 6dad4525a2910496ecf3c41de659aac906f6c1f4)
2025-08-08 11:49:21 +02:00

159 lines
4.8 KiB
C

/*
* Copyright (c) 2003-2012 Tim Kientzle
* Copyright (c) 2012 Andres Mejia
* 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 "test_utils.h"
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
static inline uint64_t
xorshift64(uint64_t *state)
{
uint64_t x = *state;
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
*state = x;
return (x);
}
/*
* Fill a buffer with reproducible pseudo-random data using a simple xorshift
* algorithm. Originally, most tests filled buffers with a loop that calls
* rand() once for each byte. However, this initialization can be extremely
* slow when running on emulated platforms such as QEMU where 16M calls to
* rand() take a long time: Before the test_write_format_7zip_large_copy test
* took ~22 seconds, whereas using a xorshift random number generator (that can
* be inlined) reduces it to ~17 seconds on QEMU RISC-V.
*/
static void
fill_with_pseudorandom_data_seed(uint64_t seed, void *buffer, size_t size)
{
uint64_t *aligned_buffer;
size_t num_values;
size_t i;
size_t unaligned_suffix;
size_t unaligned_prefix = 0;
/*
* To avoid unaligned stores we only fill the aligned part of the buffer
* with pseudo-random data and fill the unaligned prefix with 0xab and
* the suffix with 0xcd.
*/
if ((uintptr_t)buffer % sizeof(uint64_t)) {
unaligned_prefix =
sizeof(uint64_t) - (uintptr_t)buffer % sizeof(uint64_t);
aligned_buffer =
(uint64_t *)((char *)buffer + unaligned_prefix);
memset(buffer, 0xab, unaligned_prefix);
} else {
aligned_buffer = (uint64_t *)buffer;
}
assert((uintptr_t)aligned_buffer % sizeof(uint64_t) == 0);
num_values = (size - unaligned_prefix) / sizeof(uint64_t);
unaligned_suffix =
size - unaligned_prefix - num_values * sizeof(uint64_t);
for (i = 0; i < num_values; i++) {
aligned_buffer[i] = xorshift64(&seed);
}
if (unaligned_suffix) {
memset((char *)buffer + size - unaligned_suffix, 0xcd,
unaligned_suffix);
}
}
void
fill_with_pseudorandom_data(void *buffer, size_t size)
{
uint64_t seed;
const char* seed_str;
/*
* Check if a seed has been specified in the environment, otherwise fall
* back to using rand() as a seed.
*/
if ((seed_str = getenv("TEST_RANDOM_SEED")) != NULL) {
errno = 0;
seed = strtoull(seed_str, NULL, 10);
if (errno != 0) {
fprintf(stderr, "strtoull(%s) failed: %s", seed_str,
strerror(errno));
seed = rand();
}
} else {
seed = rand();
}
fill_with_pseudorandom_data_seed(seed, buffer, size);
}
unsigned long
bitcrc32(unsigned long c, const void *_p, size_t s)
{
/* This is a drop-in replacement for crc32() from zlib.
* Libarchive should be able to correctly read archives (including
* correct CRCs) even when zlib is unavailable, and this function
* helps us verify that. Yes, this is very, very slow and unsuitable
* for production use, but it's obviously correct, compact, and
* works well enough for this particular usage. Libarchive
* internally uses a much more efficient implementation if zlib is
* unavailable. */
const unsigned char *p = _p;
char bitctr;
if (p == NULL)
return (0);
for (; s > 0; --s) {
c ^= *p++;
for (bitctr = 8; bitctr > 0; --bitctr) {
if (c & 1) c = (c >> 1);
else c = (c >> 1) ^ 0xedb88320;
c ^= 0x80000000;
}
}
return (c);
}
/* Read little-endian integers */
unsigned short
i2le(const void* p_)
{
const unsigned char *p = p_;
return (p[0] | (p[1] << 8));
}
unsigned int
i4le(const void* p_)
{
const char *p = p_;
return (i2le(p) | (i2le(p + 2) << 16));
}
unsigned long long
i8le(const void* p_)
{
const char *p = p_;
return (i4le(p) | ((unsigned long long)i4le(p + 4) << 32));
}