Skip to content

Commit

Permalink
Quickly reject tar entries > 2^60 bytes w/o risking overflow (libarch…
Browse files Browse the repository at this point in the history
…ive#2263)

In particular, this ensures that we cannot overflow rounding-up
calculations. Recent tar changes put in a lot of sanity limits on the
sizes of particular kinds of data, but the usual behavior in most cases
was to skip over-large values. The skipping behavior required
rounding-up and accumulating values that could potentially overflow
64-bit integers. This adds some coarser checks that fail more directly
when an entry claims to be more than 1 exbibyte (2^60 bytes), avoiding
any possibility of numeric overflow along these paths.

OSS-Fuzz Issue: 70062
  • Loading branch information
kientzle authored Jul 6, 2024
1 parent f710345 commit 808059a
Showing 1 changed file with 15 additions and 3 deletions.
18 changes: 15 additions & 3 deletions libarchive/archive_read_support_format_tar.c
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ static const size_t sparse_map_limit = 8 * 1048576; /* Longest sparse map: 8MiB
static const size_t xattr_limit = 16 * 1048576; /* Longest xattr: 16MiB */
static const size_t fflags_limit = 512; /* Longest fflags */
static const size_t acl_limit = 131072; /* Longest textual ACL: 128kiB */
static const int64_t entry_limit = 0xfffffffffffffffLL; /* 2^60 bytes = 1 ExbiByte */

int
archive_read_support_format_gnutar(struct archive *a)
Expand Down Expand Up @@ -1201,6 +1202,9 @@ header_volume(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 > (int64_t)pathname_limit) {
return (ARCHIVE_FATAL);
}
to_consume = ((size + 511) & ~511);
*unconsumed += to_consume;
return (ARCHIVE_OK);
Expand Down Expand Up @@ -1255,7 +1259,10 @@ 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 > 1048576) || (size < 0)) {
if (size > entry_limit) {
return (ARCHIVE_FATAL);
}
if ((size > (int64_t)pathname_limit) || (size < 0)) {
archive_string_empty(as);
int64_t to_consume = ((size + 511) & ~511);
if (to_consume != __archive_read_consume(a, to_consume)) {
Expand Down Expand Up @@ -1314,8 +1321,7 @@ header_common(struct archive_read *a, struct tar *tar,
"Tar entry has negative size");
return (ARCHIVE_FATAL);
}
if (tar->entry_bytes_remaining == INT64_MAX) {
/* Note: tar_atol returns INT64_MAX on overflow */
if (tar->entry_bytes_remaining > entry_limit) {
tar->entry_bytes_remaining = 0;
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Tar entry size overflow");
Expand Down Expand Up @@ -1643,6 +1649,9 @@ 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) {
return (ARCHIVE_FATAL);
}
to_consume = ((size + 511) & ~511);
*unconsumed += to_consume;
return (ARCHIVE_OK);
Expand Down Expand Up @@ -1768,6 +1777,9 @@ header_pax_extension(struct archive_read *a, struct tar *tar,

header = (const struct archive_entry_header_ustar *)h;
ext_size = tar_atol(header->size, sizeof(header->size));
if (ext_size > entry_limit) {
return (ARCHIVE_FATAL);
}
if (ext_size < 0) {
archive_set_error(&a->archive, EINVAL,
"pax extension header has invalid size: %lld",
Expand Down

0 comments on commit 808059a

Please sign in to comment.