Update vendor/libarchive to 3.7.6

Security fixes:
 #2330 iso: be more cautious about parsing ISO-9660 timestamps
 #2343 tar: clean up linkpath between entries

Important bugfixes:
 #2338 tar: fix memory leaks when processing symlinks or parsing pax headers

Obtained from:	libarchive
Vendor commit:	f0a0bc6b3046e34c9d6981f8c026da51fea12c89
This commit is contained in:
Martin Matuska 2024-09-23 11:46:43 +02:00
parent 2022efa030
commit e6330bf497
10 changed files with 213 additions and 42 deletions

2
NEWS
View file

@ -1,3 +1,5 @@
Sep 23, 2024: libarchive 3.7.6 released
Sep 13, 2024: libarchive 3.7.5 released
Apr 26, 2024: libarchive 3.7.4 released

View file

@ -1 +1 @@
3007005
3007006

View file

@ -4,8 +4,8 @@ dnl First, define all of the version numbers up front.
dnl In particular, this allows the version macro to be used in AC_INIT
dnl These first two version numbers are updated automatically on each release.
m4_define([LIBARCHIVE_VERSION_S],[3.7.5])
m4_define([LIBARCHIVE_VERSION_N],[3007005])
m4_define([LIBARCHIVE_VERSION_S],[3.7.6])
m4_define([LIBARCHIVE_VERSION_N],[3007006])
dnl bsdtar and bsdcpio versioning tracks libarchive
m4_define([BSDTAR_VERSION_S],LIBARCHIVE_VERSION_S())

View file

@ -34,7 +34,7 @@
* assert that ARCHIVE_VERSION_NUMBER >= 2012108.
*/
/* Note: Compiler will complain if this does not match archive_entry.h! */
#define ARCHIVE_VERSION_NUMBER 3007005
#define ARCHIVE_VERSION_NUMBER 3007006
#include <sys/stat.h>
#include <stddef.h> /* for wchar_t */
@ -155,7 +155,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.5"
#define ARCHIVE_VERSION_ONLY_STRING "3.7.6"
#define ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING
__LA_DECL const char * archive_version_string(void);

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 3007005
#define ARCHIVE_VERSION_NUMBER 3007006
/*
* Note: archive_entry.h is for use outside of libarchive; the

View file

@ -273,7 +273,7 @@ struct file_info {
char re; /* Having RRIP "RE" extension. */
char re_descendant;
uint64_t cl_offset; /* Having RRIP "CL" extension. */
int birthtime_is_set;
int time_is_set; /* Bitmask indicating which times are known */
time_t birthtime; /* File created time. */
time_t mtime; /* File last modified time. */
time_t atime; /* File last accessed time. */
@ -306,6 +306,11 @@ struct file_info {
} rede_files;
};
#define BIRTHTIME_IS_SET 1
#define MTIME_IS_SET 2
#define ATIME_IS_SET 4
#define CTIME_IS_SET 8
struct heap_queue {
struct file_info **files;
int allocated;
@ -394,7 +399,9 @@ static void dump_isodirrec(FILE *, const unsigned char *isodirrec);
#endif
static time_t time_from_tm(struct tm *);
static time_t isodate17(const unsigned char *);
static int isodate17_valid(const unsigned char *);
static time_t isodate7(const unsigned char *);
static int isodate7_valid(const unsigned char *);
static int isBootRecord(struct iso9660 *, const unsigned char *);
static int isVolumePartition(struct iso9660 *, const unsigned char *);
static int isVDSetTerminator(struct iso9660 *, const unsigned char *);
@ -1351,13 +1358,22 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
archive_entry_set_uid(entry, file->uid);
archive_entry_set_gid(entry, file->gid);
archive_entry_set_nlink(entry, file->nlinks);
if (file->birthtime_is_set)
if ((file->time_is_set & BIRTHTIME_IS_SET))
archive_entry_set_birthtime(entry, file->birthtime, 0);
else
archive_entry_unset_birthtime(entry);
archive_entry_set_mtime(entry, file->mtime, 0);
archive_entry_set_ctime(entry, file->ctime, 0);
archive_entry_set_atime(entry, file->atime, 0);
if ((file->time_is_set & MTIME_IS_SET))
archive_entry_set_mtime(entry, file->mtime, 0);
else
archive_entry_unset_mtime(entry);
if ((file->time_is_set & CTIME_IS_SET))
archive_entry_set_ctime(entry, file->ctime, 0);
else
archive_entry_unset_ctime(entry);
if ((file->time_is_set & ATIME_IS_SET))
archive_entry_set_atime(entry, file->atime, 0);
else
archive_entry_unset_atime(entry);
/* N.B.: Rock Ridge supports 64-bit device numbers. */
archive_entry_set_rdev(entry, (dev_t)file->rdev);
archive_entry_set_size(entry, iso9660->entry_bytes_remaining);
@ -1898,8 +1914,11 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
file->parent = parent;
file->offset = offset;
file->size = fsize;
file->mtime = isodate7(isodirrec + DR_date_offset);
file->ctime = file->atime = file->mtime;
if (isodate7_valid(isodirrec + DR_date_offset)) {
file->time_is_set |= MTIME_IS_SET | ATIME_IS_SET | CTIME_IS_SET;
file->mtime = isodate7(isodirrec + DR_date_offset);
file->ctime = file->atime = file->mtime;
}
file->rede_files.first = NULL;
file->rede_files.last = &(file->rede_files.first);
@ -2573,51 +2592,73 @@ parse_rockridge_TF1(struct file_info *file, const unsigned char *data,
/* Use 17-byte time format. */
if ((flag & 1) && data_length >= 17) {
/* Create time. */
file->birthtime_is_set = 1;
file->birthtime = isodate17(data);
if (isodate17_valid(data)) {
file->time_is_set |= BIRTHTIME_IS_SET;
file->birthtime = isodate17(data);
}
data += 17;
data_length -= 17;
}
if ((flag & 2) && data_length >= 17) {
/* Modify time. */
file->mtime = isodate17(data);
if (isodate17_valid(data)) {
file->time_is_set |= MTIME_IS_SET;
file->mtime = isodate17(data);
}
data += 17;
data_length -= 17;
}
if ((flag & 4) && data_length >= 17) {
/* Access time. */
file->atime = isodate17(data);
if (isodate17_valid(data)) {
file->time_is_set |= ATIME_IS_SET;
file->atime = isodate17(data);
}
data += 17;
data_length -= 17;
}
if ((flag & 8) && data_length >= 17) {
/* Attribute change time. */
file->ctime = isodate17(data);
if (isodate17_valid(data)) {
file->time_is_set |= CTIME_IS_SET;
file->ctime = isodate17(data);
}
}
} else {
/* Use 7-byte time format. */
if ((flag & 1) && data_length >= 7) {
/* Create time. */
file->birthtime_is_set = 1;
file->birthtime = isodate7(data);
if (isodate7_valid(data)) {
file->time_is_set |= BIRTHTIME_IS_SET;
file->birthtime = isodate7(data);
}
data += 7;
data_length -= 7;
}
if ((flag & 2) && data_length >= 7) {
/* Modify time. */
file->mtime = isodate7(data);
if (isodate7_valid(data)) {
file->time_is_set |= MTIME_IS_SET;
file->mtime = isodate7(data);
}
data += 7;
data_length -= 7;
}
if ((flag & 4) && data_length >= 7) {
/* Access time. */
file->atime = isodate7(data);
if (isodate7_valid(data)) {
file->time_is_set |= ATIME_IS_SET;
file->atime = isodate7(data);
}
data += 7;
data_length -= 7;
}
if ((flag & 8) && data_length >= 7) {
/* Attribute change time. */
file->ctime = isodate7(data);
if (isodate7_valid(data)) {
file->time_is_set |= CTIME_IS_SET;
file->ctime = isodate7(data);
}
}
}
}
@ -3226,6 +3267,56 @@ isValid733Integer(const unsigned char *p)
&& p[3] == p[4]);
}
static int
isodate7_valid(const unsigned char *v)
{
int year = v[0];
int month = v[1];
int day = v[2];
int hour = v[3];
int minute = v[4];
int second = v[5];
int gmt_off = (signed char)v[6];
/* ECMA-119 9.1.5 "If all seven values are zero, it shall mean
* that the date is unspecified" */
if (year == 0
&& month == 0
&& day == 0
&& hour == 0
&& minute == 0
&& second == 0
&& gmt_off == 0)
return 0;
/*
* Sanity-test each individual field
*/
/* Year can have any value */
/* Month must be 1-12 */
if (month < 1 || month > 12)
return 0;
/* Day must be 1-31 */
if (day < 1 || day > 31)
return 0;
/* Hour must be 0-23 */
if (hour > 23)
return 0;
/* Minute must be 0-59 */
if (minute > 59)
return 0;
/* second must be 0-59 according to ECMA-119 9.1.5 */
/* BUT: we should probably allow for the time being in UTC, which
allows up to 61 seconds in a minute in certain cases */
if (second > 61)
return 0;
/* Offset from GMT must be -48 to +52 */
if (gmt_off < -48 || gmt_off > +52)
return 0;
/* All tests pass, this is OK */
return 1;
}
static time_t
isodate7(const unsigned char *v)
{
@ -3252,6 +3343,67 @@ isodate7(const unsigned char *v)
return (t);
}
static int
isodate17_valid(const unsigned char *v)
{
/* First 16 bytes are all ASCII digits */
for (int i = 0; i < 16; i++) {
if (v[i] < '0' || v[i] > '9')
return 0;
}
int year = (v[0] - '0') * 1000 + (v[1] - '0') * 100
+ (v[2] - '0') * 10 + (v[3] - '0');
int month = (v[4] - '0') * 10 + (v[5] - '0');
int day = (v[6] - '0') * 10 + (v[7] - '0');
int hour = (v[8] - '0') * 10 + (v[9] - '0');
int minute = (v[10] - '0') * 10 + (v[11] - '0');
int second = (v[12] - '0') * 10 + (v[13] - '0');
int hundredths = (v[14] - '0') * 10 + (v[15] - '0');
int gmt_off = (signed char)v[16];
if (year == 0 && month == 0 && day == 0
&& hour == 0 && minute == 0 && second == 0
&& hundredths == 0 && gmt_off == 0)
return 0;
/*
* Sanity-test each individual field
*/
/* Year must be 1900-2300 */
/* (Not specified in ECMA-119, but these seem
like reasonable limits. */
if (year < 1900 || year > 2300)
return 0;
/* Month must be 1-12 */
if (month < 1 || month > 12)
return 0;
/* Day must be 1-31 */
if (day < 1 || day > 31)
return 0;
/* Hour must be 0-23 */
if (hour > 23)
return 0;
/* Minute must be 0-59 */
if (minute > 59)
return 0;
/* second must be 0-59 according to ECMA-119 9.1.5 */
/* BUT: we should probably allow for the time being in UTC, which
allows up to 61 seconds in a minute in certain cases */
if (second > 61)
return 0;
/* Hundredths must be 0-99 */
if (hundredths > 99)
return 0;
/* Offset from GMT must be -48 to +52 */
if (gmt_off < -48 || gmt_off > +52)
return 0;
/* All tests pass, this is OK */
return 1;
}
static time_t
isodate17(const unsigned char *v)
{

View file

@ -296,6 +296,7 @@ archive_read_format_tar_cleanup(struct archive_read *a)
archive_string_free(&tar->entry_pathname_override);
archive_string_free(&tar->entry_uname);
archive_string_free(&tar->entry_gname);
archive_string_free(&tar->entry_linkpath);
archive_string_free(&tar->line);
archive_string_free(&tar->pax_global);
archive_string_free(&tar->longname);
@ -726,6 +727,7 @@ tar_read_header(struct archive_read *a, struct tar *tar,
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);
/* Ensure format is set. */
if (a->archive.archive_format_name == NULL) {
@ -1935,6 +1937,7 @@ header_pax_extension(struct archive_read *a, struct tar *tar,
*unconsumed += 1;
tar_flush_unconsumed(a, unconsumed);
}
archive_string_free(&attr_name);
*unconsumed += ext_size + ext_padding;
/*

View file

@ -93,16 +93,20 @@ test_small(const char *name)
assertEqualIntA(a, ARCHIVE_OK,
archive_read_next_header(a, &ae));
assertEqualString(".", archive_entry_pathname(ae));
assertEqualIntA(a, 3443989665, archive_entry_atime(ae));
assertEqualIntA(a, 0, archive_entry_birthtime(ae));
assertEqualIntA(a, 3443989665, archive_entry_ctime(ae));
assertEqualInt(0, archive_entry_atime_is_set(ae));
assertEqualInt(0, archive_entry_atime(ae));
assertEqualInt(0, archive_entry_birthtime_is_set(ae));
assertEqualInt(0, archive_entry_birthtime(ae));
assertEqualInt(0, archive_entry_ctime_is_set(ae));
assertEqualInt(0, archive_entry_ctime(ae));
assertEqualIntA(a, 0, archive_entry_dev(ae));
assertEqualIntA(a, AE_IFDIR, archive_entry_filetype(ae));
assertEqualIntA(a, 0, archive_entry_gid(ae));
assertEqualStringA(a, NULL, archive_entry_gname(ae));
assertEqualIntA(a, 0, archive_entry_ino(ae));
assertEqualIntA(a, AE_IFDIR | 0700, archive_entry_mode(ae));
assertEqualIntA(a, 3443989665, archive_entry_mtime(ae));
assertEqualInt(0, archive_entry_mtime_is_set(ae));
assertEqualInt(0, archive_entry_mtime(ae));
assertEqualIntA(a, 4, archive_entry_nlink(ae));
assertEqualIntA(a, 0700, archive_entry_perm(ae));
assertEqualIntA(a, 2048, archive_entry_size(ae));

View file

@ -190,7 +190,7 @@ create_tree(void)
#define LIMIT_USTAR 100
static void
verify_tree(size_t limit)
verify_tree(size_t limit, const char *format)
{
char name1[260];
char name2[260];
@ -203,6 +203,7 @@ verify_tree(size_t limit)
/* Verify a file named "f/abcdef..." */
snprintf(name1, sizeof(name1), "f/%s", filenames[i]);
if (i <= limit) {
failure("Verifying %s", format);
assertFileExists(name1);
assertFileContents(name1, (int)strlen(name1), name1);
}
@ -210,6 +211,7 @@ verify_tree(size_t limit)
snprintf(name2, sizeof(name2), "l/%s", filenames[i]);
if (i + 2 <= limit) {
/* Verify hardlink "l/abcdef..." */
failure("Verifying %s", format);
assertIsHardlink(name1, name2);
/* Verify hardlink "m/abcdef..." */
name2[0] = 'm';
@ -220,13 +222,16 @@ verify_tree(size_t limit)
/* Verify symlink "s/abcdef..." */
snprintf(name1, sizeof(name1), "s/%s", filenames[i]);
snprintf(name2, sizeof(name2), "../f/%s", filenames[i]);
if (strlen(name2) <= limit)
if (strlen(name2) <= limit) {
failure("Verifying %s", format);
assertIsSymlink(name1, name2, 0);
}
}
/* Verify dir "d/abcdef...". */
snprintf(name1, sizeof(name1), "d/%s", filenames[i]);
if (i + 1 <= limit) { /* +1 for trailing slash */
failure("Verifying %s", format);
if (assertIsDir(name1, -1)) {
/* TODO: opendir/readdir this
* directory and make sure
@ -246,7 +251,7 @@ verify_tree(size_t limit)
char dir[2];
dir[0] = *dp; dir[1] = '\0';
d = opendir(dir);
failure("Unable to open dir '%s'", dir);
failure("Unable to open dir '%s' for testing %s", dir, format);
if (!assert(d != NULL))
continue;
while ((de = readdir(d)) != NULL) {
@ -278,25 +283,25 @@ verify_tree(size_t limit)
}
static void
copy_basic(void)
copy_basic(const char *extra_args, const char *name)
{
int r;
/* NOTE: for proper operation on cygwin-1.5 and windows, the
* length of the name of the directory below, "plain", must be
* length of the name of the directory below must be
* less than or equal to the length of the name of the original
* directory, "original" This restriction derives from the
* extremely limited pathname lengths on those platforms.
*/
assertMakeDir("plain", 0775);
assertEqualInt(0, chdir("plain"));
assertMakeDir(name, 0775);
assertEqualInt(0, chdir(name));
/*
* Use the tar program to create an archive.
*/
r = systemf("%s cf archive -C ../original f d l m s >pack.out 2>pack.err",
testprog);
failure("Error invoking \"%s cf\"", testprog);
r = systemf("%s cf archive %s -C ../original f d l m s >pack.out 2>pack.err",
testprog, extra_args);
failure("Error invoking \"%s cf archive %s\"", testprog, extra_args);
assertEqualInt(r, 0);
/* Verify that nothing went to stdout or stderr. */
@ -314,7 +319,7 @@ copy_basic(void)
assertEmptyFile("unpack.err");
assertEmptyFile("unpack.out");
verify_tree(LIMIT_NONE);
verify_tree(LIMIT_NONE, name);
assertEqualInt(0, chdir(".."));
}
@ -357,8 +362,8 @@ copy_ustar(void)
assertEmptyFile("unpack.err");
assertEmptyFile("unpack.out");
verify_tree(LIMIT_USTAR);
assertEqualInt(0, chdir("../.."));
verify_tree(LIMIT_USTAR, "ustar");
assertEqualInt(0, chdir(".."));
}
DEFINE_TEST(test_copy)
@ -367,8 +372,11 @@ DEFINE_TEST(test_copy)
create_tree(); /* Create sample files in "original" dir. */
/* Test simple "tar -c | tar -x" pipeline copy. */
copy_basic();
copy_basic("", "default");
/* Same, but constrain to ustar format. */
copy_ustar();
/* Same, but with pax format. */
copy_basic(" --format pax", "pax");
}

View file

@ -32,7 +32,9 @@
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_ATTR_XATTR_H
#if HAVE_SYS_XATTR_H
#include <sys/xattr.h>
#elif HAVE_ATTR_XATTR_H
#include <attr/xattr.h>
#endif
#ifdef HAVE_ERRNO_H