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
42 changes: 42 additions & 0 deletions SPECS/trident/CVE-2026-33055.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
From f4826f2a2283222e87f8cef2c252342c05484268 Mon Sep 17 00:00:00 2001
From: AllSpark <allspark@microsoft.com>
Date: Thu, 26 Mar 2026 11:59:06 +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/src/archive.rs | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/vendor/tar/src/archive.rs b/vendor/tar/src/archive.rs
index 924e54a..3051dbb 100644
--- a/vendor/tar/src/archive.rs
+++ b/vendor/tar/src/archive.rs
@@ -339,10 +339,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/trident/CVE-2026-33056.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
From fa569268d51347b587d9d2bd171b6c37bd196273 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 924e54a..17938a8 100644
--- a/vendor/tar/src/archive.rs
+++ b/vendor/tar/src/archive.rs
@@ -92,9 +92,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 b6b48b4..c9f3b9f 100644
--- a/vendor/tar/src/entry.rs
+++ b/vendor/tar/src/entry.rs
@@ -212,8 +212,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
///
@@ -446,7 +447,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 4d612e2..92c11f6 100644
--- a/vendor/tar/tests/entry.rs
+++ b/vendor/tar/tests/entry.rs
@@ -409,3 +409,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/trident/trident.spec
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Summary: Declarative, security-first OS lifecycle agent designed primaril
Name: trident
# Use hard-coded versions for distro build
Version: 0.21.0
Release: 1%{?dist}
Release: 2%{?dist}
License: MIT
Vendor: Microsoft Corporation
Group: Applications/System
Expand All @@ -31,6 +31,8 @@ Source0: https://github.com/microsoft/trident/archive/refs/tags/v%{versio
Source1: %{name}-%{version}-cargo.tar.gz
%else
Source1: osmodifier
Patch0: CVE-2026-33055.patch
Patch1: CVE-2026-33056.patch
%endif

BuildRequires: openssl-devel
Expand Down Expand Up @@ -300,6 +302,9 @@ mkdir -p "$pcrlockroot"
)

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

* Mon Mar 2 2026 Brian Fjeldstad <bfjelds@microsoft.com> 0.21.0-1
- Original version for Azure Linux (license: MIT).
- License verified.
Loading