Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions SPECS/rpm-ostree/CVE-2026-33055.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
From bbf89c7d2c7647feda9e8e67280b771cf8de44f3 Mon Sep 17 00:00:00 2001
From: AllSpark <allspark@microsoft.com>
Date: Thu, 26 Mar 2026 08:27:31 +0000
Subject: [PATCH] archive: Unconditionally honor PAX size (#441)

This synchronizes our behavior with most other tar parsers
(including astral-tokio-tar and Go archive/tar) ensuring
that we don't parse things differently.

The problem with parsing size in particular differently is
it's easy to craft a tar archive that appears completely differently
between two parsers. This is the case with e.g. crates.io where
astral-tokio-tar is used for validation server side, but cargo uses
the crate to upload.

With this, the two projects agree.

Signed-off-by: Colin Walters <walters@verbum.org>
Co-authored-by: Colin Walters <walters@verbum.org>
Signed-off-by: Azure Linux Security Servicing Account <azurelinux-security@microsoft.com>
Upstream-reference: AI Backport of https://github.com/alexcrichton/tar-rs/commit/de1a5870e603758f430073688691165f21a33946.patch
---
vendor/tar/Cargo.toml | 10 ++++++++++
vendor/tar/src/archive.rs | 9 +++++----
2 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/vendor/tar/Cargo.toml b/vendor/tar/Cargo.toml
index 23771b56..e55390bd 100644
--- a/vendor/tar/Cargo.toml
+++ b/vendor/tar/Cargo.toml
@@ -24,9 +24,19 @@ license = "MIT/Apache-2.0"
repository = "https://github.com/alexcrichton/tar-rs"
[dependencies.filetime]
version = "0.2.8"
+[dev-dependencies.astral-tokio-tar]
+version = "0.5"
+
[dev-dependencies.tempfile]
version = "3"

+[dev-dependencies.tokio]
+version = "1"
+features = ["macros", "rt"]
+
+[dev-dependencies.tokio-stream]
+version = "0.1"
+
[features]
default = ["xattr"]
[target."cfg(unix)".dependencies.libc]
diff --git a/vendor/tar/src/archive.rs b/vendor/tar/src/archive.rs
index 1bed5124..221d1551 100644
--- a/vendor/tar/src/archive.rs
+++ b/vendor/tar/src/archive.rs
@@ -290,10 +290,11 @@ impl<'a> EntriesFields<'a> {

let file_pos = self.next;
let mut size = header.entry_size()?;
- if size == 0 {
- if let Some(pax_size) = pax_size {
- size = pax_size;
- }
+ // If this exists, it must override the header size. Disagreement among
+ // parsers allows construction of malicious archives that appear different
+ // when parsed.
+ if let Some(pax_size) = pax_size {
+ size = pax_size;
}
let ret = EntryFields {
size: size,
--
2.45.4

150 changes: 150 additions & 0 deletions SPECS/rpm-ostree/CVE-2026-33056.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
From aa3c496809405b04ad02a9f9a48d75dce43ef364 Mon Sep 17 00:00:00 2001
From: Alex Crichton <alex@alexcrichton.com>
Date: Thu, 19 Mar 2026 16:58:05 -0500
Subject: [PATCH] archive: Prevent symlink-directory collision chmod attack
(#442)

When unpacking a tarball containing a symlink followed by a directory
entry with the same path, unpack_dir previously used fs::metadata()
which follows symlinks. This allowed an attacker to modify permissions
on arbitrary directories outside the extraction path.

The fix uses fs::symlink_metadata() to detect symlinks and refuse to
treat them as valid existing directories.

Document more exhaustively+consistently security caveats.

Reported-by: Sergei Zimmerman <https://github.com/xokdvium>
Assisted-by: OpenCode (Claude claude-opus-4-5)

Signed-off-by: Colin Walters <walters@verbum.org>
Co-authored-by: Colin Walters <walters@verbum.org>
Signed-off-by: Azure Linux Security Servicing Account <azurelinux-security@microsoft.com>
Upstream-reference: https://github.com/alexcrichton/tar-rs/commit/17b1fd84e632071cb8eef9d3709bf347bd266446.patch
---
vendor/tar/src/archive.rs | 18 ++++++++++---
vendor/tar/src/entry.rs | 7 ++---
vendor/tar/tests/entry.rs | 56 +++++++++++++++++++++++++++++++++++++++
3 files changed, 75 insertions(+), 6 deletions(-)

diff --git a/vendor/tar/src/archive.rs b/vendor/tar/src/archive.rs
index 1bed5124..056eb71a 100644
--- a/vendor/tar/src/archive.rs
+++ b/vendor/tar/src/archive.rs
@@ -88,9 +88,21 @@ impl<R: Read> Archive<R> {
/// extracting each file in turn to the location specified by the entry's
/// path name.
///
- /// This operation is relatively sensitive in that it will not write files
- /// outside of the path specified by `dst`. Files in the archive which have
- /// a '..' in their path are skipped during the unpacking process.
+ /// # Security
+ ///
+ /// A best-effort is made to prevent writing files outside `dst` (paths
+ /// containing `..` are skipped, symlinks are validated). However, there
+ /// have been historical bugs in this area, and more may exist. For this
+ /// reason, when processing untrusted archives, stronger sandboxing is
+ /// encouraged: e.g. the [`cap-std`] crate and/or OS-level
+ /// containerization/virtualization.
+ ///
+ /// If `dst` does not exist, it is created. Unpacking into an existing
+ /// directory merges content. This function assumes `dst` is not
+ /// concurrently modified by untrusted processes. Protecting against
+ /// TOCTOU races is out of scope for this crate.
+ ///
+ /// [`cap-std`]: https://docs.rs/cap-std/
///
/// # Examples
///
diff --git a/vendor/tar/src/entry.rs b/vendor/tar/src/entry.rs
index 8f0b62ac..287d6890 100644
--- a/vendor/tar/src/entry.rs
+++ b/vendor/tar/src/entry.rs
@@ -210,8 +210,9 @@ impl<'a, R: Read> Entry<'a, R> {
/// also be propagated to the path `dst`. Any existing file at the location
/// `dst` will be overwritten.
///
- /// This function carefully avoids writing outside of `dst`. If the file has
- /// a '..' in its path, this function will skip it and return false.
+ /// # Security
+ ///
+ /// See [`Archive::unpack`].
///
/// # Examples
///
@@ -430,7 +431,7 @@ impl<'a> EntryFields<'a> {
// If the directory already exists just let it slide
fs::create_dir(dst).or_else(|err| {
if err.kind() == ErrorKind::AlreadyExists {
- let prev = fs::metadata(dst);
+ let prev = fs::symlink_metadata(dst);
if prev.map(|m| m.is_dir()).unwrap_or(false) {
return Ok(());
}
diff --git a/vendor/tar/tests/entry.rs b/vendor/tar/tests/entry.rs
index fa8eeaee..5e874fa5 100644
--- a/vendor/tar/tests/entry.rs
+++ b/vendor/tar/tests/entry.rs
@@ -377,3 +377,59 @@ fn modify_symlink_just_created() {
t!(t!(File::open(&test)).read_to_end(&mut contents));
assert_eq!(contents.len(), 0);
}
+
+/// Test that unpacking a tarball with a symlink followed by a directory entry
+/// with the same name does not allow modifying permissions of arbitrary directories
+/// outside the extraction path.
+#[test]
+#[cfg(unix)]
+fn symlink_dir_collision_does_not_modify_external_dir_permissions() {
+ use ::std::fs;
+ use ::std::os::unix::fs::PermissionsExt;
+
+ let td = Builder::new().prefix("tar").tempdir().unwrap();
+
+ let target_dir = td.path().join("target-dir");
+ fs::create_dir(&target_dir).unwrap();
+ fs::set_permissions(&target_dir, fs::Permissions::from_mode(0o700)).unwrap();
+ let before_mode = fs::metadata(&target_dir).unwrap().permissions().mode() & 0o7777;
+ assert_eq!(before_mode, 0o700);
+
+ let extract_dir = td.path().join("extract-dir");
+ fs::create_dir(&extract_dir).unwrap();
+
+ let mut ar = tar::Builder::new(Vec::new());
+
+ let mut header = tar::Header::new_gnu();
+ header.set_size(0);
+ header.set_entry_type(tar::EntryType::Symlink);
+ header.set_path("foo").unwrap();
+ header.set_link_name(&target_dir).unwrap();
+ header.set_mode(0o777);
+ header.set_cksum();
+ ar.append(&header, &[][..]).unwrap();
+
+ let mut header = tar::Header::new_gnu();
+ header.set_size(0);
+ header.set_entry_type(tar::EntryType::Directory);
+ header.set_path("foo").unwrap();
+ header.set_mode(0o777);
+ header.set_cksum();
+ ar.append(&header, &[][..]).unwrap();
+
+ let bytes = ar.into_inner().unwrap();
+ let mut ar = tar::Archive::new(&bytes[..]);
+
+ let result = ar.unpack(&extract_dir);
+ assert!(result.is_err());
+
+ let symlink_path = extract_dir.join("foo");
+ assert!(symlink_path
+ .symlink_metadata()
+ .unwrap()
+ .file_type()
+ .is_symlink());
+
+ let after_mode = fs::metadata(&target_dir).unwrap().permissions().mode() & 0o7777;
+ assert_eq!(after_mode, 0o700);
+}
--
2.45.4

7 changes: 6 additions & 1 deletion SPECS/rpm-ostree/rpm-ostree.spec
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Summary: Commit RPMs to an OSTree repository
Name: rpm-ostree
Version: 2022.1
Release: 8%{?dist}
Release: 9%{?dist}
License: LGPLv2+
Vendor: Microsoft Corporation
Distribution: Mariner
Expand All @@ -14,6 +14,8 @@ Patch3: rpm-ostree-drop-lint-which-treats-warning-as-error.patch
Patch4: CVE-2022-47085.patch
Patch5: CVE-2023-26964.patch
Patch6: CVE-2025-58160.patch
Patch7: CVE-2026-33055.patch
Patch8: CVE-2026-33056.patch

BuildRequires: attr-devel
BuildRequires: autoconf
Expand Down Expand Up @@ -160,6 +162,9 @@ make check
%{_datadir}/gir-1.0/*-1.0.gir

%changelog
* Thu Mar 26 2026 Azure Linux Security Servicing Account <azurelinux-security@microsoft.com> - 2022.1-9
- Patch for CVE-2026-33056, CVE-2026-33055

* Wed Jan 07 2026 BinduSri Adabala <v-badabala@microsoft.com> - 2022.1-8
- Patch for CVE-2025-58160

Expand Down
Loading