From 79e5f6d086e6b89287994fb62953d757a2fa1d64 Mon Sep 17 00:00:00 2001 From: Azure Linux Security Servicing Account Date: Tue, 1 Sep 2026 15:29:24 +0000 Subject: [PATCH] Patch tar for CVE-2026-5704 --- SPECS/tar/CVE-2026-5704.patch | 339 ++++++++++++++++++ SPECS/tar/tar.spec | 6 +- .../manifests/package/pkggen_core_aarch64.txt | 2 +- .../manifests/package/pkggen_core_x86_64.txt | 2 +- .../manifests/package/toolchain_aarch64.txt | 4 +- .../manifests/package/toolchain_x86_64.txt | 4 +- 6 files changed, 350 insertions(+), 7 deletions(-) create mode 100644 SPECS/tar/CVE-2026-5704.patch diff --git a/SPECS/tar/CVE-2026-5704.patch b/SPECS/tar/CVE-2026-5704.patch new file mode 100644 index 00000000000..bbda5a30282 --- /dev/null +++ b/SPECS/tar/CVE-2026-5704.patch @@ -0,0 +1,339 @@ +From 4c323ad56be72f0083c5ee78aa7f44f052f869af Mon Sep 17 00:00:00 2001 +From: AllSpark +Date: Tue, 1 Sep 2026 15:21:38 +0000 +Subject: [PATCH] Fix more -t/-x discrepancies + +Signed-off-by: Azure Linux Security Servicing Account +Upstream-reference: AI Backport of https://cgit.git.savannah.gnu.org/cgit/tar.git/patch/?id=b8d8a61b25588caca4efaf9bdd2e3f1a49da77e3 +--- + src/extract.c | 24 +++++++----------------- + src/incremen.c | 36 ++++++++++++++---------------------- + src/list.c | 23 ++++++++++------------- + tests/extrac32.at | 47 +++++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 78 insertions(+), 52 deletions(-) + create mode 100644 tests/extrac32.at + +diff --git a/src/extract.c b/src/extract.c +index 314d8bc..0ddb587 100644 +--- a/src/extract.c ++++ b/src/extract.c +@@ -1037,7 +1037,7 @@ safe_dir_mode (struct stat const *st) + /* Extractor functions for various member types */ + + static int +-extract_dir (char *file_name, int typeflag) ++extract_dir (char *file_name, int UNUSED_PARAM (typeflag)) + { + int status; + mode_t mode; +@@ -1060,8 +1060,6 @@ extract_dir (char *file_name, int typeflag) + if (incremental_option) + /* Read the entry and delete files that aren't listed in the archive. */ + purge_directory (file_name); +- else if (typeflag == GNUTYPE_DUMPDIR) +- skip_member (); + + mode = safe_dir_mode (¤t_stat_info.stat); + +@@ -1266,10 +1264,7 @@ extract_file (char *file_name, int typeflag) + { + fd = sys_exec_command (file_name, 'f', ¤t_stat_info); + if (fd < 0) +- { +- skip_member (); +- return 0; +- } ++ return 0; + } + else + { +@@ -1289,7 +1284,6 @@ extract_file (char *file_name, int typeflag) + int recover = maybe_recoverable (file_name, true, &interdir_made); + if (recover != RECOVER_OK) + { +- skip_member (); + if (recover == RECOVER_SKIP) + return 0; + open_error (file_name); +@@ -1337,6 +1331,7 @@ extract_file (char *file_name, int typeflag) + } + + skim_file (size, false); ++ current_stat_info.skipped = true; + + mv_end (); + +@@ -1844,15 +1839,10 @@ extract_archive (void) + typeflag = sparse_member_p (¤t_stat_info) ? + GNUTYPE_SPARSE : current_header->header.typeflag; + +- if (prepare_to_extract (current_stat_info.file_name, typeflag, &fun)) +- { +- if (fun (current_stat_info.file_name, typeflag) == 0) +- return; +- } +- else +- skip_member (); +- +- if (backup_option) ++ bool ok = (prepare_to_extract (current_stat_info.file_name, typeflag, &fun) ++ && fun (current_stat_info.file_name, typeflag) == 0); ++ skip_member (); ++ if (!ok && backup_option) + undo_last_backup (); + } + +diff --git a/src/incremen.c b/src/incremen.c +index 7bcfdb9..39bf215 100644 +--- a/src/incremen.c ++++ b/src/incremen.c +@@ -1154,7 +1154,7 @@ read_num (FILE *fp, char const *fieldname, + FATAL_ERROR ((0, 0, "%s: %s", + quotearg_colon (listed_incremental_option), + _("Unexpected EOF in snapshot file"))); +- return false; ++ return; + } + + if (c) +@@ -1551,7 +1551,7 @@ dumpdir_ok (char *dumpdir) + ERROR ((0, 0, + _("Malformed dumpdir: expected '%c' but found %#3o"), + expect, uc)); +- return false; ++ return; + } + switch (*p) + { +@@ -1560,7 +1560,7 @@ dumpdir_ok (char *dumpdir) + { + ERROR ((0, 0, + _("Malformed dumpdir: 'X' duplicated"))); +- return false; ++ return; + } + else + has_tempdir = 1; +@@ -1573,7 +1573,7 @@ dumpdir_ok (char *dumpdir) + { + ERROR ((0, 0, + _("Malformed dumpdir: empty name in 'R'"))); +- return false; ++ return; + } + else + has_tempdir = 0; +@@ -1586,13 +1586,13 @@ dumpdir_ok (char *dumpdir) + { + ERROR ((0, 0, + _("Malformed dumpdir: 'T' not preceded by 'R'"))); +- return false; ++ return; + } + if (p[1] == 0 && !has_tempdir) + { + ERROR ((0, 0, + _("Malformed dumpdir: empty name in 'T'"))); +- return false; ++ return; + } + expect = 0; + break; +@@ -1613,7 +1613,7 @@ dumpdir_ok (char *dumpdir) + ERROR ((0, 0, + _("Malformed dumpdir: expected '%c' but found end of data"), + expect)); +- return false; ++ return; + } + + if (has_tempdir) +@@ -1625,8 +1625,8 @@ dumpdir_ok (char *dumpdir) + + /* Examine the directories under directory_name and delete any + files that were not there at the time of the back-up. */ +-static bool +-try_purge_directory (char const *directory_name) ++void ++purge_directory (char const *directory_name) + { + char *current_dir; + char *cur, *arc, *p; +@@ -1634,18 +1634,18 @@ try_purge_directory (char const *directory_name) + struct dumpdir *dump; + + if (!is_dumpdir (¤t_stat_info)) +- return false; ++ return; + + current_dir = tar_savedir (directory_name, 0); + + if (!current_dir) + /* The directory doesn't exist now. It'll be created. In any + case, we don't have to delete any files out of it. */ +- return false; ++ return; + + /* Verify if dump directory is sane */ + if (!dumpdir_ok (current_stat_info.dumpdir)) +- return false; ++ return; + + /* Process renames */ + for (arc = current_stat_info.dumpdir; *arc; arc += strlen (arc) + 1) +@@ -1666,7 +1666,7 @@ try_purge_directory (char const *directory_name) + quote (temp_stub))); + free (temp_stub); + free (current_dir); +- return false; ++ return; + } + } + else if (*arc == 'R') +@@ -1700,7 +1700,7 @@ try_purge_directory (char const *directory_name) + free (current_dir); + /* FIXME: Make sure purge_directory(dst) will return + immediately */ +- return false; ++ return; + } + } + } +@@ -1758,14 +1758,6 @@ try_purge_directory (char const *directory_name) + dumpdir_free (dump); + + free (current_dir); +- return true; +-} +- +-void +-purge_directory (char const *directory_name) +-{ +- if (!try_purge_directory (directory_name)) +- skip_member (); + } + + void +diff --git a/src/list.c b/src/list.c +index e9a6815..81b5e4f 100644 +--- a/src/list.c ++++ b/src/list.c +@@ -437,20 +437,15 @@ read_header (union block **return_block, struct tar_stat_info *info, + if ((status = tar_checksum (header, false)) != HEADER_SUCCESS) + break; + +- /* Good block. Decode file size and return. */ +- +- if (header->header.typeflag == LNKTYPE) +- info->stat.st_size = 0; /* links 0 size on tape */ +- else ++ info->stat.st_size = OFF_FROM_HEADER (header->header.size); ++ if (info->stat.st_size < 0) + { +- info->stat.st_size = OFF_FROM_HEADER (header->header.size); +- if (info->stat.st_size < 0) +- { +- status = HEADER_FAILURE; +- break; +- } ++ status = HEADER_FAILURE; ++ break; + } + ++ info->skipped = false; ++ + if (header->header.typeflag == GNUTYPE_LONGNAME + || header->header.typeflag == GNUTYPE_LONGLINK + || header->header.typeflag == XHDTYPE +@@ -513,6 +508,7 @@ read_header (union block **return_block, struct tar_stat_info *info, + } + + *bp = '\0'; ++ info->skipped = true; + } + else if (header->header.typeflag == XHDTYPE + || header->header.typeflag == SOLARIS_XHDTYPE) +@@ -531,6 +527,7 @@ read_header (union block **return_block, struct tar_stat_info *info, + OFF_FROM_HEADER (header->header.size)); + xheader_decode_global (&xhdr); + xheader_destroy (&xhdr); ++ info->skipped = true; + if (mode == read_header_x_global) + { + status = HEADER_SUCCESS_EXTENDED; +@@ -1447,17 +1444,17 @@ skim_member (bool must_copy) + { + if (!current_stat_info.skipped) + { +- char save_typeflag = current_header->header.typeflag; + set_next_block_after (current_header); + + mv_begin_read (¤t_stat_info); + + if (current_stat_info.is_sparse) + sparse_skim_file (¤t_stat_info, must_copy); +- else if (save_typeflag != DIRTYPE) ++ else + skim_file (current_stat_info.stat.st_size, must_copy); + + mv_end (); ++ current_stat_info.skipped = true; + } + } + +diff --git a/tests/extrac32.at b/tests/extrac32.at +new file mode 100644 +index 0000000..3829a48 +--- /dev/null ++++ b/tests/extrac32.at +@@ -0,0 +1,47 @@ ++# Check for file injection bug with symlinks. -*- Autotest -*- ++ ++# Copyright 2026 Free Software Foundation, Inc. ++ ++# This file is part of GNU tar. ++ ++# GNU tar is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 3 of the License, or ++# (at your option) any later version. ++ ++# GNU tar is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++ ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# Thanks to Guillermo de Angel for the bug report and test cases; see: ++# https://lists.gnu.org/r/bug-tar/2026-03/msg00007.html ++ ++AT_SETUP([skip file injection]) ++AT_KEYWORDS([injection]) ++AT_DATA([archive.in], ++[/Td6WFoAAATm1rRGBMDbAYAcIQEcAAAAAAAAACYr+9LgDf8A010AMZhKvfVdtHe4Rxjj7M03ek97 ++UgeKfJ0ORqYg0XDFntWxdTH4PYrTOo9CoqBrnTM2NcwFBrRVr7aFwdd56vddyAw2QGDjxgNexDU3 ++ImTi/+z8ZOLMi/+AybdEpd5aA/M9Maa+8tQ84bySzSAwrmxMWJJ6W9IKvsqfiRa3TrD51v44PZU/ ++KLVKpocS56n/O3g+b+hiZwaysR0eLO+tiU8FB/e3PEq3vTtDFVi/YfZMieBWSzomSX9eF13K1yPY ++UuWgp7VokXqduL0YGNVV40MTPG9oAAAApD6mpajengIAAfcBgBwAAOM4xw6xxGf7AgAAAAAEWVo= ++]) ++AT_CHECK([base64 --help >/dev/null 2>&1 || AT_SKIP_TEST ++xz --help >/dev/null 2>&1 || AT_SKIP_TEST ++base64 -d < archive.in | xz -c -d > archive.tar ++]) ++cp archive.tar /tmp ++AT_CHECK([tar tf archive.tar], ++[0], ++[carrier_entry ++marker.txt ++]) ++AT_CHECK([tar xvf archive.tar], ++[0], ++[carrier_entry ++marker.txt ++]) ++AT_CLEANUP +-- +2.45.4 + diff --git a/SPECS/tar/tar.spec b/SPECS/tar/tar.spec index 0980bfed34a..54446f31df9 100644 --- a/SPECS/tar/tar.spec +++ b/SPECS/tar/tar.spec @@ -1,7 +1,7 @@ Summary: Archiving program Name: tar Version: 1.35 -Release: 2%{?dist} +Release: 3%{?dist} License: GPLv3+ URL: https://www.gnu.org/software/tar Group: Applications/System @@ -13,6 +13,7 @@ Source0: https://ftp.gnu.org/gnu/%{name}/%{name}-%{version}.tar.xz # https://web.git.kernel.org/pub/scm/libs/libcap/libcap.git/commit/?id=177cd418031b1acfcf73fe3b1af9f3279828681c Patch1: tar-1.33-fix-capabilities-test.patch Patch2: tar-1.35-add-forgotten-tests-from-upstream.patch +Patch3: CVE-2026-5704.patch %description Contains GNU archiving program @@ -50,6 +51,9 @@ make %{?_smp_mflags} check %{_mandir}/*/* %changelog +* Tue Sep 01 2026 Azure Linux Security Servicing Account - 1.35-3 +- Patch for CVE-2026-5704 + * Wed Apr 02 2025 Riken Maharjan - 1.35-2 - import patches from fedora (LICENSE:MIT) to fix libcap issue. * Mon Nov 27 2023 Andrew Phelps - 1.35-1 diff --git a/toolkit/resources/manifests/package/pkggen_core_aarch64.txt b/toolkit/resources/manifests/package/pkggen_core_aarch64.txt index 0df46a80c30..80419695e75 100644 --- a/toolkit/resources/manifests/package/pkggen_core_aarch64.txt +++ b/toolkit/resources/manifests/package/pkggen_core_aarch64.txt @@ -73,7 +73,7 @@ libcap-ng-devel-0.8.4-1.azl3.aarch64.rpm util-linux-2.40.2-5.azl3.aarch64.rpm util-linux-devel-2.40.2-5.azl3.aarch64.rpm util-linux-libs-2.40.2-5.azl3.aarch64.rpm -tar-1.35-2.azl3.aarch64.rpm +tar-1.35-3.azl3.aarch64.rpm xz-5.4.4-3.azl3.aarch64.rpm xz-devel-5.4.4-3.azl3.aarch64.rpm xz-lang-5.4.4-3.azl3.aarch64.rpm diff --git a/toolkit/resources/manifests/package/pkggen_core_x86_64.txt b/toolkit/resources/manifests/package/pkggen_core_x86_64.txt index c524e34dd7c..1ff985d9adc 100644 --- a/toolkit/resources/manifests/package/pkggen_core_x86_64.txt +++ b/toolkit/resources/manifests/package/pkggen_core_x86_64.txt @@ -73,7 +73,7 @@ libcap-ng-devel-0.8.4-1.azl3.x86_64.rpm util-linux-2.40.2-5.azl3.x86_64.rpm util-linux-devel-2.40.2-5.azl3.x86_64.rpm util-linux-libs-2.40.2-5.azl3.x86_64.rpm -tar-1.35-2.azl3.x86_64.rpm +tar-1.35-3.azl3.x86_64.rpm xz-5.4.4-3.azl3.x86_64.rpm xz-devel-5.4.4-3.azl3.x86_64.rpm xz-lang-5.4.4-3.azl3.x86_64.rpm diff --git a/toolkit/resources/manifests/package/toolchain_aarch64.txt b/toolkit/resources/manifests/package/toolchain_aarch64.txt index a0d058b1383..7d361926ad9 100644 --- a/toolkit/resources/manifests/package/toolchain_aarch64.txt +++ b/toolkit/resources/manifests/package/toolchain_aarch64.txt @@ -585,8 +585,8 @@ systemd-bootstrap-debuginfo-250.3-20.azl3.aarch64.rpm systemd-bootstrap-devel-250.3-20.azl3.aarch64.rpm systemd-bootstrap-libs-250.3-20.azl3.aarch64.rpm systemd-bootstrap-rpm-macros-250.3-20.azl3.noarch.rpm -tar-1.35-2.azl3.aarch64.rpm -tar-debuginfo-1.35-2.azl3.aarch64.rpm +tar-1.35-3.azl3.aarch64.rpm +tar-debuginfo-1.35-3.azl3.aarch64.rpm tdnf-3.5.8-8.azl3.aarch64.rpm tdnf-autoupdate-3.5.8-8.azl3.aarch64.rpm tdnf-cli-libs-3.5.8-8.azl3.aarch64.rpm diff --git a/toolkit/resources/manifests/package/toolchain_x86_64.txt b/toolkit/resources/manifests/package/toolchain_x86_64.txt index ad34529e69c..cc021e456bf 100644 --- a/toolkit/resources/manifests/package/toolchain_x86_64.txt +++ b/toolkit/resources/manifests/package/toolchain_x86_64.txt @@ -593,8 +593,8 @@ systemd-bootstrap-debuginfo-250.3-20.azl3.x86_64.rpm systemd-bootstrap-devel-250.3-20.azl3.x86_64.rpm systemd-bootstrap-libs-250.3-20.azl3.x86_64.rpm systemd-bootstrap-rpm-macros-250.3-20.azl3.noarch.rpm -tar-1.35-2.azl3.x86_64.rpm -tar-debuginfo-1.35-2.azl3.x86_64.rpm +tar-1.35-3.azl3.x86_64.rpm +tar-debuginfo-1.35-3.azl3.x86_64.rpm tdnf-3.5.8-8.azl3.x86_64.rpm tdnf-autoupdate-3.5.8-8.azl3.x86_64.rpm tdnf-cli-libs-3.5.8-8.azl3.x86_64.rpm