From d771cd9cfe6c22091dbd885c7a7a29b92958a855 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 24 Oct 2025 12:57:09 -0700 Subject: [PATCH 1/4] Fix `Dir::symlink_metadata` of "/" on Linux. Fix an overzealous optimization on Linux which inappropriately allowed `Dir::symlink_metadata` on a path of "/" to succeed. Fixes bytecodealliance/wasmtime#11606. --- .../src/rustix/linux/fs/stat_impl.rs | 11 +++++----- tests/fs_additional.rs | 20 +++++++++++++++++++ 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/cap-primitives/src/rustix/linux/fs/stat_impl.rs b/cap-primitives/src/rustix/linux/fs/stat_impl.rs index b018c16d..df358a01 100644 --- a/cap-primitives/src/rustix/linux/fs/stat_impl.rs +++ b/cap-primitives/src/rustix/linux/fs/stat_impl.rs @@ -18,13 +18,14 @@ pub(crate) fn stat_impl( use crate::fs::{stat_unchecked, OpenOptionsExt}; use std::path::Component; - // Optimization: if path has exactly one component and it's not ".." and - // we're not following symlinks we can go straight to `stat_unchecked`, - // which is faster than doing an open with a separate fstat. + // Optimization: if path has exactly one component and it's not ".." or + // anything non-normal and we're not following symlinks we can go straight + // to `stat_unchecked`, which is faster than doing an open with a separate + // `fstat`. if follow == FollowSymlinks::No { let mut components = path.components(); - if let Some(component) = components.next() { - if components.next().is_none() && component != Component::ParentDir { + if let Some(Component::Normal(component)) = components.next() { + if components.next().is_none() { return stat_unchecked(start, component.as_ref(), FollowSymlinks::No); } } diff --git a/tests/fs_additional.rs b/tests/fs_additional.rs index 4fe7a17c..0d32862a 100644 --- a/tests/fs_additional.rs +++ b/tests/fs_additional.rs @@ -1380,3 +1380,23 @@ fn dotdot_slashdot_at_end_of_symlink_all_inside_dir() { let _entry = check!(entry); } } + +/// Ensure that a path of "/" is rejected. +#[test] +fn statat_slash() { + let tmpdir = tmpdir(); + + error!(tmpdir.metadata("/"), "a path led outside of the filesystem"); + error!( + tmpdir.metadata("/foo"), + "a path led outside of the filesystem" + ); + error!( + tmpdir.symlink_metadata("/"), + "a path led outside of the filesyste" + ); + error!( + tmpdir.symlink_metadata("/foo"), + "a path led outside of the filesyste" + ); +} From 7fbdbc0d04f01f3ca1dd09c32f77b96fc5fa6fe7 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 24 Oct 2025 13:43:26 -0700 Subject: [PATCH 2/4] Disable `statat_slash` on Windows. --- tests/fs_additional.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/fs_additional.rs b/tests/fs_additional.rs index 0d32862a..660c723f 100644 --- a/tests/fs_additional.rs +++ b/tests/fs_additional.rs @@ -1383,6 +1383,7 @@ fn dotdot_slashdot_at_end_of_symlink_all_inside_dir() { /// Ensure that a path of "/" is rejected. #[test] +#[cfg_attr(windows, ignore)] fn statat_slash() { let tmpdir = tmpdir(); From bb53c3474c35e4065bfcd1a076de01702049c119 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 24 Oct 2025 13:48:24 -0700 Subject: [PATCH 3/4] Pin some dependencies for MSRV compatibilty. --- .github/workflows/main.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 43cbfc79..b9603350 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -373,7 +373,10 @@ jobs: toolchain: ${{ matrix.rust }} - name: Use specific dependency versions for Rust 1.63 compatibility. - run: cargo update --package=once_cell --precise=1.20.3 + run: | + cargo update --package=once_cell --precise=1.20.3 + cargo update --package=async-io --precise=2.5.0 + cargo update --package=polling --precise=3.10.0 # Don't use --all-features because some of the features have dependencies # that don't work on newer Rust versions. From e69da511a3e1ddc177bb050e199e4153f57de4b3 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 24 Oct 2025 13:51:13 -0700 Subject: [PATCH 4/4] Fix Windows compilation. --- tests/fs_additional.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/fs_additional.rs b/tests/fs_additional.rs index 660c723f..64716819 100644 --- a/tests/fs_additional.rs +++ b/tests/fs_additional.rs @@ -1383,20 +1383,19 @@ fn dotdot_slashdot_at_end_of_symlink_all_inside_dir() { /// Ensure that a path of "/" is rejected. #[test] -#[cfg_attr(windows, ignore)] fn statat_slash() { let tmpdir = tmpdir(); - error!(tmpdir.metadata("/"), "a path led outside of the filesystem"); - error!( + error_contains!(tmpdir.metadata("/"), "a path led outside of the filesystem"); + error_contains!( tmpdir.metadata("/foo"), "a path led outside of the filesystem" ); - error!( + error_contains!( tmpdir.symlink_metadata("/"), "a path led outside of the filesyste" ); - error!( + error_contains!( tmpdir.symlink_metadata("/foo"), "a path led outside of the filesyste" );