Backport upstream commit f9af0142 to perl-Archive-Tar on c8s.
The patch adds a $MAX_FILE_SIZE variable (default 1 GiB) and a
size check in _read_tar() that refuses to allocate memory for
entries whose declared size exceeds the cap. This defends against
CVE-2026-9538, where an attacker-controlled tar header size field
could trigger multi-GB memory allocation via a small compressed
archive.
CVE: CVE-2026-9538
Upstream patches:
- f9af014260.patch
Resolves: RHEL-191913
This commit was backported by Ymir, a Red Hat Enterprise Linux software maintenance AI agent.
Assisted-by: Ymir
73 lines
2.7 KiB
Diff
73 lines
2.7 KiB
Diff
From a7794880779e9e7aa2d0fb966f2b5e46d0e278e2 Mon Sep 17 00:00:00 2001
|
|
From: Stig Palmquist <stig@stig.io>
|
|
Date: Mon, 25 May 2026 19:11:34 +0100
|
|
Subject: [PATCH] Cpan entry size during read
|
|
|
|
Cap entry size during read to defend against attacker-controlled
|
|
size-field memory DoS
|
|
|
|
The tar header's 12-byte size field is attacker-controlled. Archive::Tar's
|
|
non-skip extract path at Tar.pm:501 allocates a Perl scalar of the declared
|
|
size before returning the read-short error, allowing a few-KB compressed
|
|
archive declaring a 100 GB inner entry to trigger immediate multi-GB
|
|
allocation. The existing $EXTRACT_BLOCK_SIZE is an output-side syswrite
|
|
chunk size, not an input cap.
|
|
|
|
Add $MAX_FILE_SIZE (default 1 GiB) checked once per entry, gating both the
|
|
chunked-skip and full-slurp branches. Set to 0 to disable the cap.
|
|
|
|
Signed-off-by: Chris 'BinGOs' Williams <chris@bingosnet.co.uk>
|
|
---
|
|
lib/Archive/Tar.pm | 17 +++++++++++++++++
|
|
1 file changed, 17 insertions(+)
|
|
|
|
diff --git a/lib/Archive/Tar.pm b/lib/Archive/Tar.pm
|
|
index 5b968c8..356ab44 100644
|
|
--- a/lib/Archive/Tar.pm
|
|
+++ b/lib/Archive/Tar.pm
|
|
@@ -24,6 +24,7 @@ use strict;
|
|
use vars qw[$DEBUG $error $VERSION $WARN $FOLLOW_SYMLINK $CHOWN $CHMOD
|
|
$DO_NOT_USE_PREFIX $HAS_PERLIO $HAS_IO_STRING $SAME_PERMISSIONS
|
|
$INSECURE_EXTRACT_MODE $ZERO_PAD_NUMBERS @ISA @EXPORT $RESOLVE_SYMLINK
|
|
+ $MAX_FILE_SIZE
|
|
];
|
|
|
|
@ISA = qw[Exporter];
|
|
@@ -39,6 +40,7 @@ $DO_NOT_USE_PREFIX = 0;
|
|
$INSECURE_EXTRACT_MODE = 0;
|
|
$ZERO_PAD_NUMBERS = 0;
|
|
$RESOLVE_SYMLINK = $ENV{'PERL5_AT_RESOLVE_SYMLINK'} || 'speed';
|
|
+$MAX_FILE_SIZE = 1024 * 1024 * 1024;
|
|
|
|
BEGIN {
|
|
use Config;
|
|
@@ -416,6 +418,14 @@ sub _read_tar {
|
|
|
|
my $block = BLOCK_SIZE->( $entry->size );
|
|
|
|
+ if ( $MAX_FILE_SIZE && $entry->size > $MAX_FILE_SIZE ) {
|
|
+ $self->_error( qq[Entry '] . $entry->full_path .
|
|
+ qq[' declared size ] . $entry->size .
|
|
+ qq[ bytes exceeds \$Archive::Tar::MAX_FILE_SIZE ] .
|
|
+ qq[($MAX_FILE_SIZE); refusing to allocate] );
|
|
+ next LOOP;
|
|
+ }
|
|
+
|
|
$data = $entry->get_content_by_ref;
|
|
|
|
my $skip = 0;
|
|
@@ -2154,6 +2164,13 @@ numbers. Added for compatibility with C<busybox> implementations.
|
|
|
|
It won't work for terminal, pipe or sockets or every non seekable source.
|
|
|
|
+=head2 $Archive::Tar::MAX_FILE_SIZE
|
|
+
|
|
+This variable holds an upper bound on the per-entry declared size that
|
|
+C<Archive::Tar> will accept when reading an archive. Entries whose header
|
|
+claims a larger size are refused with an error before any read allocation.
|
|
+Defaults to 1 GiB. Set to 0 to disable the cap.
|
|
+
|
|
=cut
|
|
|
|
=head1 FAQ
|