From 3571074828d7b3a9d310a8871b75ce5b7b0041b8 Mon Sep 17 00:00:00 2001 From: ksgk1 Date: Fri, 1 May 2026 10:46:53 +0200 Subject: [PATCH 1/2] chown: Replace unsafe calls with rustix --- src/uucore/src/lib/features/perms.rs | 28 ++++++++-------- src/uucore/src/lib/features/safe_traversal.rs | 32 +++++++++---------- 2 files changed, 29 insertions(+), 31 deletions(-) diff --git a/src/uucore/src/lib/features/perms.rs b/src/uucore/src/lib/features/perms.rs index 79a51b0ccad..66dec7579dc 100644 --- a/src/uucore/src/lib/features/perms.rs +++ b/src/uucore/src/lib/features/perms.rs @@ -24,13 +24,11 @@ use walkdir::WalkDir; #[cfg(target_os = "linux")] use crate::features::safe_traversal::{DirFd, SymlinkBehavior}; -use std::ffi::CString; use std::fs::Metadata; use std::io::Error as IOError; use std::io::Result as IOResult; use std::os::unix::fs::MetadataExt; -use std::os::unix::ffi::OsStrExt; use std::path::{MAIN_SEPARATOR, Path}; /// The various level of verbosity @@ -59,19 +57,21 @@ impl Default for Verbosity { /// Actually perform the change of owner on a path fn chown>(path: P, uid: uid_t, gid: gid_t, follow: bool) -> IOResult<()> { - let path = path.as_ref(); - let s = CString::new(path.as_os_str().as_bytes()).unwrap(); - let ret = unsafe { - if follow { - libc::chown(s.as_ptr(), uid, gid) - } else { - libc::lchown(s.as_ptr(), uid, gid) - } - }; - if ret == 0 { - Ok(()) + let final_path = if follow { + // Canonicalize is used to resolve symlinks + path.as_ref() + .canonicalize() + .map_err(|_| IOError::last_os_error())? } else { - Err(IOError::last_os_error()) + path.as_ref().to_path_buf() + }; + match rustix::fs::chown( + final_path, + Some(rustix::process::Uid::from_raw(uid)), + Some(rustix::process::Gid::from_raw(gid)), + ) { + Ok(_) => Ok(()), + Err(e) => Err(IOError::from_raw_os_error(e.raw_os_error())), } } diff --git a/src/uucore/src/lib/features/safe_traversal.rs b/src/uucore/src/lib/features/safe_traversal.rs index 9fc8fb244b0..a9fc1c82311 100644 --- a/src/uucore/src/lib/features/safe_traversal.rs +++ b/src/uucore/src/lib/features/safe_traversal.rs @@ -26,7 +26,7 @@ use nix::dir::Dir; use nix::fcntl::{OFlag, openat}; use nix::libc; use nix::sys::stat::{FchmodatFlags, FileStat, Mode, fchmodat, fstatat, mkdirat}; -use nix::unistd::{Gid, Uid, UnlinkatFlags, fchown, fchownat, unlinkat}; +use nix::unistd::{UnlinkatFlags, unlinkat}; use os_display::Quotable; use crate::translate; @@ -258,32 +258,30 @@ impl DirFd { gid: Option, symlink_behavior: SymlinkBehavior, ) -> io::Result<()> { - let name_cstr = - CString::new(name.as_bytes()).map_err(|_| SafeTraversalError::PathContainsNull)?; - let flags = if symlink_behavior.should_follow() { - nix::fcntl::AtFlags::empty() + rustix::fs::AtFlags::empty() } else { - nix::fcntl::AtFlags::AT_SYMLINK_NOFOLLOW + rustix::fs::AtFlags::SYMLINK_NOFOLLOW }; - let uid = uid.map(Uid::from_raw); - let gid = gid.map(Gid::from_raw); - - fchownat(&self.fd, name_cstr.as_c_str(), uid, gid, flags) - .map_err(|e| io::Error::from_raw_os_error(e as i32))?; + let uid = uid.map(rustix::process::Uid::from_raw); + let gid = gid.map(rustix::process::Gid::from_raw); - Ok(()) + match rustix::fs::chownat(&self.fd, name, uid, gid, flags) { + Ok(_) => Ok(()), + Err(e) => Err(io::Error::from_raw_os_error(e.raw_os_error())), + } } /// Change ownership of this directory pub fn fchown(&self, uid: Option, gid: Option) -> io::Result<()> { - let uid = uid.map(Uid::from_raw); - let gid = gid.map(Gid::from_raw); + let uid = uid.map(rustix::process::Uid::from_raw); + let gid = gid.map(rustix::process::Gid::from_raw); - fchown(&self.fd, uid, gid).map_err(|e| io::Error::from_raw_os_error(e as i32))?; - - Ok(()) + match rustix::fs::fchown(&self.fd, uid, gid) { + Ok(_) => Ok(()), + Err(e) => Err(io::Error::from_raw_os_error(e.raw_os_error())), + } } /// Change mode of a file relative to this directory From 6dea9092a0ea68b32e9c0cbb56da413a12ddf95a Mon Sep 17 00:00:00 2001 From: ksgk1 Date: Fri, 1 May 2026 11:01:24 +0200 Subject: [PATCH 2/2] spellcheck: add ignore for chownat --- src/uucore/src/lib/features/safe_traversal.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uucore/src/lib/features/safe_traversal.rs b/src/uucore/src/lib/features/safe_traversal.rs index a9fc1c82311..8fa67b5c825 100644 --- a/src/uucore/src/lib/features/safe_traversal.rs +++ b/src/uucore/src/lib/features/safe_traversal.rs @@ -9,7 +9,7 @@ // Available on Unix // // spell-checker:ignore CLOEXEC RDONLY TOCTOU closedir dirp fdopendir fstatat openat REMOVEDIR unlinkat smallfile -// spell-checker:ignore RAII dirfd fchownat fchown FchmodatFlags fchmodat fchmod mkdirat CREAT WRONLY ELOOP ENOTDIR +// spell-checker:ignore RAII chownat dirfd fchownat fchown FchmodatFlags fchmodat fchmod mkdirat CREAT WRONLY ELOOP ENOTDIR // spell-checker:ignore atimensec mtimensec ctimensec #[cfg(test)]