Update vendor/libarchive to git b3bd0b81a1a06909f766dea8be4072ef81de62b8
Vendor bugfixes: cpio reader sanity fix (OSS-Fuzz 504) WARC reader sanity fixes (OSS-Fuzz 511, 526, 532, 552) mtree reader time parsing fix (OSS-Fuzz 538) XAR reader memleak fix (OSS-Fuzz 551)
This commit is contained in:
parent
fed7941280
commit
d952c73b39
@ -634,7 +634,7 @@ libarchive_test_EXTRA_DIST=\
|
||||
libarchive/test/test_compat_mac-2.tar.Z.uu \
|
||||
libarchive/test/test_compat_pax_libarchive_2x.tar.Z.uu \
|
||||
libarchive/test/test_compat_perl_archive_tar.tar.uu \
|
||||
libarchive/test/test_compat_plexus_archiver_tar.uu \
|
||||
libarchive/test/test_compat_plexus_archiver_tar.tar.uu \
|
||||
libarchive/test/test_compat_solaris_pax_sparse_1.pax.Z.uu \
|
||||
libarchive/test/test_compat_solaris_pax_sparse_2.pax.Z.uu \
|
||||
libarchive/test/test_compat_solaris_tar_acl.tar.uu \
|
||||
@ -830,6 +830,7 @@ libarchive_test_EXTRA_DIST=\
|
||||
libarchive/test/test_read_large_splitted_rar_ac.uu \
|
||||
libarchive/test/test_read_large_splitted_rar_ad.uu \
|
||||
libarchive/test/test_read_large_splitted_rar_ae.uu \
|
||||
libarchive/test/test_read_pax_schily_xattr.tar.uu \
|
||||
libarchive/test/test_read_splitted_rar_aa.uu \
|
||||
libarchive/test/test_read_splitted_rar_ab.uu \
|
||||
libarchive/test/test_read_splitted_rar_ac.uu \
|
||||
|
@ -356,7 +356,7 @@ archive_read_format_cpio_read_header(struct archive_read *a,
|
||||
struct archive_entry *entry)
|
||||
{
|
||||
struct cpio *cpio;
|
||||
const void *h;
|
||||
const void *h, *hl;
|
||||
struct archive_string_conv *sconv;
|
||||
size_t namelength;
|
||||
size_t name_pad;
|
||||
@ -406,11 +406,11 @@ archive_read_format_cpio_read_header(struct archive_read *a,
|
||||
"Rejecting malformed cpio archive: symlink contents exceed 1 megabyte");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
h = __archive_read_ahead(a,
|
||||
hl = __archive_read_ahead(a,
|
||||
(size_t)cpio->entry_bytes_remaining, NULL);
|
||||
if (h == NULL)
|
||||
if (hl == NULL)
|
||||
return (ARCHIVE_FATAL);
|
||||
if (archive_entry_copy_symlink_l(entry, (const char *)h,
|
||||
if (archive_entry_copy_symlink_l(entry, (const char *)hl,
|
||||
(size_t)cpio->entry_bytes_remaining, sconv) != 0) {
|
||||
if (errno == ENOMEM) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
@ -434,7 +434,7 @@ archive_read_format_cpio_read_header(struct archive_read *a,
|
||||
* header. XXX */
|
||||
|
||||
/* Compare name to "TRAILER!!!" to test for end-of-archive. */
|
||||
if (namelength == 11 && memcmp((const char *)h, "TRAILER!!!",
|
||||
if (namelength == 11 && strncmp((const char *)h, "TRAILER!!!",
|
||||
11) == 0) {
|
||||
/* TODO: Store file location of start of block. */
|
||||
archive_clear_error(&a->archive);
|
||||
|
@ -1608,8 +1608,11 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
|
||||
if (*val == '.') {
|
||||
++val;
|
||||
ns = (long)mtree_atol10(&val);
|
||||
} else
|
||||
ns = 0;
|
||||
if (ns < 0)
|
||||
ns = 0;
|
||||
else if (ns > 999999999)
|
||||
ns = 999999999;
|
||||
}
|
||||
if (m > my_time_t_max)
|
||||
m = my_time_t_max;
|
||||
else if (m < my_time_t_min)
|
||||
|
@ -134,8 +134,8 @@ static ssize_t _warc_rdlen(const char *buf, size_t bsz);
|
||||
static time_t _warc_rdrtm(const char *buf, size_t bsz);
|
||||
static time_t _warc_rdmtm(const char *buf, size_t bsz);
|
||||
static const char *_warc_find_eoh(const char *buf, size_t bsz);
|
||||
static const char *_warc_find_eol(const char *buf, size_t bsz);
|
||||
|
||||
|
||||
int
|
||||
archive_read_support_format_warc(struct archive *_a)
|
||||
{
|
||||
@ -198,8 +198,8 @@ _warc_bid(struct archive_read *a, int best_bid)
|
||||
|
||||
/* otherwise snarf the record's version number */
|
||||
ver = _warc_rdver(hdr, nrd);
|
||||
if (ver == 0U || ver > 10000U) {
|
||||
/* oh oh oh, best not to wager ... */
|
||||
if (ver < 1200U || ver > 10000U) {
|
||||
/* we only support WARC 0.12 to 1.0 */
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -254,23 +254,32 @@ _warc_rdhdr(struct archive_read *a, struct archive_entry *entry)
|
||||
&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Bad record header");
|
||||
return (ARCHIVE_FATAL);
|
||||
} else if ((ver = _warc_rdver(buf, eoh - buf)) > 10000U) {
|
||||
/* nawww, I wish they promised backward compatibility
|
||||
* anyhoo, in their infinite wisdom the 28500 guys might
|
||||
* come up with something we can't possibly handle so
|
||||
* best end things here */
|
||||
}
|
||||
ver = _warc_rdver(buf, eoh - buf);
|
||||
/* we currently support WARC 0.12 to 1.0 */
|
||||
if (ver == 0U) {
|
||||
archive_set_error(
|
||||
&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Unsupported record version");
|
||||
"Invalid record version");
|
||||
return (ARCHIVE_FATAL);
|
||||
} else if ((cntlen = _warc_rdlen(buf, eoh - buf)) < 0) {
|
||||
} else if (ver < 1200U || ver > 10000U) {
|
||||
archive_set_error(
|
||||
&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Unsupported record version: %u.%u",
|
||||
ver / 10000, (ver % 10000) / 100);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
cntlen = _warc_rdlen(buf, eoh - buf);
|
||||
if (cntlen < 0) {
|
||||
/* nightmare! the specs say content-length is mandatory
|
||||
* so I don't feel overly bad stopping the reader here */
|
||||
archive_set_error(
|
||||
&a->archive, EINVAL,
|
||||
"Bad content length");
|
||||
return (ARCHIVE_FATAL);
|
||||
} else if ((rtime = _warc_rdrtm(buf, eoh - buf)) == (time_t)-1) {
|
||||
}
|
||||
rtime = _warc_rdrtm(buf, eoh - buf);
|
||||
if (rtime == (time_t)-1) {
|
||||
/* record time is mandatory as per WARC/1.0,
|
||||
* so just barf here, fast and loud */
|
||||
archive_set_error(
|
||||
@ -284,7 +293,7 @@ _warc_rdhdr(struct archive_read *a, struct archive_entry *entry)
|
||||
if (ver != w->pver) {
|
||||
/* stringify this entry's version */
|
||||
archive_string_sprintf(&w->sver,
|
||||
"WARC/%u.%u", ver / 10000, ver % 10000);
|
||||
"WARC/%u.%u", ver / 10000, (ver % 10000) / 100);
|
||||
/* remember the version */
|
||||
w->pver = ver;
|
||||
}
|
||||
@ -577,51 +586,41 @@ xstrpisotime(const char *s, char **endptr)
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
_warc_rdver(const char buf[10], size_t bsz)
|
||||
_warc_rdver(const char *buf, size_t bsz)
|
||||
{
|
||||
static const char magic[] = "WARC/";
|
||||
unsigned int ver;
|
||||
unsigned int ver = 0U;
|
||||
unsigned int end = 0U;
|
||||
|
||||
(void)bsz; /* UNUSED */
|
||||
|
||||
if (memcmp(buf, magic, sizeof(magic) - 1U) != 0) {
|
||||
/* nope */
|
||||
return 99999U;
|
||||
if (bsz < 12 || memcmp(buf, magic, sizeof(magic) - 1U) != 0) {
|
||||
/* buffer too small or invalid magic */
|
||||
return ver;
|
||||
}
|
||||
/* looks good so far, read the version number for a laugh */
|
||||
buf += sizeof(magic) - 1U;
|
||||
/* most common case gets a quick-check here */
|
||||
if (memcmp(buf, "1.0\r\n", 5U) == 0) {
|
||||
ver = 10000U;
|
||||
} else {
|
||||
switch (*buf) {
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
if (buf[1U] == '.') {
|
||||
char *on;
|
||||
|
||||
/* set up major version */
|
||||
ver = (buf[0U] - '0') * 10000U;
|
||||
/* minor version, anyone? */
|
||||
ver += (strtol(buf + 2U, &on, 10)) * 100U;
|
||||
/* don't parse anything else */
|
||||
if (on > buf + 2U) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case '9':
|
||||
default:
|
||||
/* just make the version ridiculously high */
|
||||
ver = 999999U;
|
||||
break;
|
||||
if (isdigit(buf[0U]) && (buf[1U] == '.') && isdigit(buf[2U])) {
|
||||
/* we support a maximum of 2 digits in the minor version */
|
||||
if (isdigit(buf[3U]))
|
||||
end = 1U;
|
||||
/* set up major version */
|
||||
ver = (buf[0U] - '0') * 10000U;
|
||||
/* set up minor version */
|
||||
if (end == 1U) {
|
||||
ver += (buf[2U] - '0') * 1000U;
|
||||
ver += (buf[3U] - '0') * 100U;
|
||||
} else
|
||||
ver += (buf[2U] - '0') * 100U;
|
||||
/*
|
||||
* WARC below version 0.12 has a space-separated header
|
||||
* WARC 0.12 and above terminates the version with a CRLF
|
||||
*/
|
||||
if (ver >= 1200U) {
|
||||
if (memcmp(buf + 3U + end, "\r\n", 2U) != 0)
|
||||
ver = 0U;
|
||||
} else if (ver < 1200U) {
|
||||
if (!isblank(*(buf + 3U + end)))
|
||||
ver = 0U;
|
||||
}
|
||||
}
|
||||
return ver;
|
||||
@ -631,34 +630,27 @@ static unsigned int
|
||||
_warc_rdtyp(const char *buf, size_t bsz)
|
||||
{
|
||||
static const char _key[] = "\r\nWARC-Type:";
|
||||
const char *const eob = buf + bsz;
|
||||
const char *val;
|
||||
const char *val, *eol;
|
||||
|
||||
if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {
|
||||
/* no bother */
|
||||
return WT_NONE;
|
||||
}
|
||||
/* overread whitespace */
|
||||
val += sizeof(_key) - 1U;
|
||||
while (val < eob && isspace((unsigned char)*val))
|
||||
if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL) {
|
||||
/* no end of line */
|
||||
return WT_NONE;
|
||||
}
|
||||
|
||||
/* overread whitespace */
|
||||
while (val < eol && isblank((unsigned char)*val))
|
||||
++val;
|
||||
|
||||
if (val + 8U > eob) {
|
||||
;
|
||||
} else if (memcmp(val, "resource", 8U) == 0) {
|
||||
return WT_RSRC;
|
||||
} else if (memcmp(val, "warcinfo", 8U) == 0) {
|
||||
return WT_INFO;
|
||||
} else if (memcmp(val, "metadata", 8U) == 0) {
|
||||
return WT_META;
|
||||
} else if (memcmp(val, "request", 7U) == 0) {
|
||||
return WT_REQ;
|
||||
} else if (memcmp(val, "response", 8U) == 0) {
|
||||
return WT_RSP;
|
||||
} else if (memcmp(val, "conversi", 8U) == 0) {
|
||||
return WT_CONV;
|
||||
} else if (memcmp(val, "continua", 8U) == 0) {
|
||||
return WT_CONT;
|
||||
if (val + 8U == eol) {
|
||||
if (memcmp(val, "resource", 8U) == 0)
|
||||
return WT_RSRC;
|
||||
else if (memcmp(val, "response", 8U) == 0)
|
||||
return WT_RSP;
|
||||
}
|
||||
return WT_NONE;
|
||||
}
|
||||
@ -667,10 +659,7 @@ static warc_string_t
|
||||
_warc_rduri(const char *buf, size_t bsz)
|
||||
{
|
||||
static const char _key[] = "\r\nWARC-Target-URI:";
|
||||
const char *const eob = buf + bsz;
|
||||
const char *val;
|
||||
const char *uri;
|
||||
const char *eol;
|
||||
const char *val, *uri, *eol, *p;
|
||||
warc_string_t res = {0U, NULL};
|
||||
|
||||
if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {
|
||||
@ -679,25 +668,32 @@ _warc_rduri(const char *buf, size_t bsz)
|
||||
}
|
||||
/* overread whitespace */
|
||||
val += sizeof(_key) - 1U;
|
||||
while (val < eob && isspace((unsigned char)*val))
|
||||
++val;
|
||||
|
||||
/* overread URL designators */
|
||||
if ((uri = xmemmem(val, eob - val, "://", 3U)) == NULL) {
|
||||
/* not touching that! */
|
||||
return res;
|
||||
} else if ((eol = memchr(uri, '\n', eob - uri)) == NULL) {
|
||||
/* no end of line? :O */
|
||||
if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL) {
|
||||
/* no end of line */
|
||||
return res;
|
||||
}
|
||||
|
||||
/* massage uri to point to after :// */
|
||||
while (val < eol && isblank((unsigned char)*val))
|
||||
++val;
|
||||
|
||||
/* overread URL designators */
|
||||
if ((uri = xmemmem(val, eol - val, "://", 3U)) == NULL) {
|
||||
/* not touching that! */
|
||||
return res;
|
||||
}
|
||||
|
||||
/* spaces inside uri are not allowed, CRLF should follow */
|
||||
for (p = val; p < eol; p++) {
|
||||
if (isspace(*p))
|
||||
return res;
|
||||
}
|
||||
|
||||
/* there must be at least space for ftp */
|
||||
if (uri < (val + 3U))
|
||||
return res;
|
||||
|
||||
/* move uri to point to after :// */
|
||||
uri += 3U;
|
||||
/* also massage eol to point to the first whitespace
|
||||
* after the last non-whitespace character before
|
||||
* the end of the line */
|
||||
while (eol > uri && isspace((unsigned char)eol[-1]))
|
||||
--eol;
|
||||
|
||||
/* now then, inspect the URI */
|
||||
if (memcmp(val, "file", 4U) == 0) {
|
||||
@ -720,7 +716,7 @@ static ssize_t
|
||||
_warc_rdlen(const char *buf, size_t bsz)
|
||||
{
|
||||
static const char _key[] = "\r\nContent-Length:";
|
||||
const char *val;
|
||||
const char *val, *eol;
|
||||
char *on = NULL;
|
||||
long int len;
|
||||
|
||||
@ -728,14 +724,24 @@ _warc_rdlen(const char *buf, size_t bsz)
|
||||
/* no bother */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* strtol kindly overreads whitespace for us, so use that */
|
||||
val += sizeof(_key) - 1U;
|
||||
len = strtol(val, &on, 10);
|
||||
if (on == NULL || !isspace((unsigned char)*on)) {
|
||||
/* hm, can we trust that number? Best not. */
|
||||
if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL) {
|
||||
/* no end of line */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* skip leading whitespace */
|
||||
while (val < eol && isblank(*val))
|
||||
val++;
|
||||
/* there must be at least one digit */
|
||||
if (!isdigit(*val))
|
||||
return -1;
|
||||
len = strtol(val, &on, 10);
|
||||
if (on != eol) {
|
||||
/* line must end here */
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (size_t)len;
|
||||
}
|
||||
|
||||
@ -743,7 +749,7 @@ static time_t
|
||||
_warc_rdrtm(const char *buf, size_t bsz)
|
||||
{
|
||||
static const char _key[] = "\r\nWARC-Date:";
|
||||
const char *val;
|
||||
const char *val, *eol;
|
||||
char *on = NULL;
|
||||
time_t res;
|
||||
|
||||
@ -751,13 +757,17 @@ _warc_rdrtm(const char *buf, size_t bsz)
|
||||
/* no bother */
|
||||
return (time_t)-1;
|
||||
}
|
||||
val += sizeof(_key) - 1U;
|
||||
if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL ) {
|
||||
/* no end of line */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* xstrpisotime() kindly overreads whitespace for us, so use that */
|
||||
val += sizeof(_key) - 1U;
|
||||
res = xstrpisotime(val, &on);
|
||||
if (on == NULL || !isspace((unsigned char)*on)) {
|
||||
/* hm, can we trust that number? Best not. */
|
||||
return (time_t)-1;
|
||||
if (on != eol) {
|
||||
/* line must end here */
|
||||
return -1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@ -766,7 +776,7 @@ static time_t
|
||||
_warc_rdmtm(const char *buf, size_t bsz)
|
||||
{
|
||||
static const char _key[] = "\r\nLast-Modified:";
|
||||
const char *val;
|
||||
const char *val, *eol;
|
||||
char *on = NULL;
|
||||
time_t res;
|
||||
|
||||
@ -774,13 +784,17 @@ _warc_rdmtm(const char *buf, size_t bsz)
|
||||
/* no bother */
|
||||
return (time_t)-1;
|
||||
}
|
||||
val += sizeof(_key) - 1U;
|
||||
if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL ) {
|
||||
/* no end of line */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* xstrpisotime() kindly overreads whitespace for us, so use that */
|
||||
val += sizeof(_key) - 1U;
|
||||
res = xstrpisotime(val, &on);
|
||||
if (on == NULL || !isspace((unsigned char)*on)) {
|
||||
/* hm, can we trust that number? Best not. */
|
||||
return (time_t)-1;
|
||||
if (on != eol) {
|
||||
/* line must end here */
|
||||
return -1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@ -797,4 +811,12 @@ _warc_find_eoh(const char *buf, size_t bsz)
|
||||
return hit;
|
||||
}
|
||||
|
||||
static const char*
|
||||
_warc_find_eol(const char *buf, size_t bsz)
|
||||
{
|
||||
static const char _marker[] = "\r\n";
|
||||
const char *hit = xmemmem(buf, bsz, _marker, sizeof(_marker) - 1U);
|
||||
|
||||
return hit;
|
||||
}
|
||||
/* archive_read_support_format_warc.c ends here */
|
||||
|
@ -394,6 +394,7 @@ static void checksum_update(struct archive_read *, const void *,
|
||||
size_t, const void *, size_t);
|
||||
static int checksum_final(struct archive_read *, const void *,
|
||||
size_t, const void *, size_t);
|
||||
static void checksum_cleanup(struct archive_read *);
|
||||
static int decompression_init(struct archive_read *, enum enctype);
|
||||
static int decompress(struct archive_read *, const void **,
|
||||
size_t *, const void *, size_t *);
|
||||
@ -923,6 +924,7 @@ xar_cleanup(struct archive_read *a)
|
||||
int r;
|
||||
|
||||
xar = (struct xar *)(a->format->data);
|
||||
checksum_cleanup(a);
|
||||
r = decompression_cleanup(a);
|
||||
hdlink = xar->hdlink_list;
|
||||
while (hdlink != NULL) {
|
||||
@ -1719,6 +1721,16 @@ decompression_cleanup(struct archive_read *a)
|
||||
return (r);
|
||||
}
|
||||
|
||||
static void
|
||||
checksum_cleanup(struct archive_read *a) {
|
||||
struct xar *xar;
|
||||
|
||||
xar = (struct xar *)(a->format->data);
|
||||
|
||||
_checksum_final(&(xar->a_sumwrk), NULL, 0);
|
||||
_checksum_final(&(xar->e_sumwrk), NULL, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
xmlattr_cleanup(struct xmlattr_list *list)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user