diff --git a/crates/fspy_preload_unix/src/client/convert.rs b/crates/fspy_preload_unix/src/client/convert.rs index 57bb8df21..14d0e33ba 100644 --- a/crates/fspy_preload_unix/src/client/convert.rs +++ b/crates/fspy_preload_unix/src/client/convert.rs @@ -107,15 +107,15 @@ impl ToAbsolutePath for Fd { } } -pub struct PathAt(pub c_int, pub *const c_char); +pub struct PathAt<'a, R>(pub c_int, pub sigsafe::CStr<'a, R>); -impl ToAbsolutePath for PathAt { +impl ToAbsolutePath for PathAt<'_, Repr> { unsafe fn to_absolute_path) -> nix::Result>( self, f: F, ) -> nix::Result { - // SAFETY: self.1 is a non-null pointer to a valid null-terminated C string, as guaranteed by the libc calling convention - let pathname = unsafe { CStr::from_ptr(self.1) }.to_bytes().as_bstr(); + // SAFETY: self.1 is a valid NUL-terminated string. + let pathname = unsafe { CStr::from_ptr(self.1.as_ptr()) }.to_bytes().as_bstr(); if pathname.first().copied() == Some(b'/') { f(pathname.into()) @@ -148,12 +148,12 @@ impl ToAbsolutePath for PathAt { } } -impl ToAbsolutePath for *const c_char { +impl ToAbsolutePath for sigsafe::CStr<'_, Repr> { unsafe fn to_absolute_path) -> nix::Result>( self, f: F, ) -> nix::Result { - // SAFETY: delegates to PathAt::to_absolute_path with AT_FDCWD and the caller-provided C string pointer + // SAFETY: delegates the same caller-provided C string to PathAt. unsafe { PathAt(libc::AT_FDCWD, self).to_absolute_path(f) } } } diff --git a/crates/fspy_preload_unix/src/interceptions/access.rs b/crates/fspy_preload_unix/src/interceptions/access.rs index 0cae39220..cbae59d9e 100644 --- a/crates/fspy_preload_unix/src/interceptions/access.rs +++ b/crates/fspy_preload_unix/src/interceptions/access.rs @@ -10,7 +10,7 @@ intercept!(access(64): unsafe extern "C" fn(pathname: *const c_char, mode: c_int unsafe extern "C" fn access(pathname: *const c_char, mode: c_int) -> c_int { // SAFETY: pathname is a valid C string pointer provided by the caller of the interposed function unsafe { - handle_open(pathname, AccessMode::READ); + handle_open(sigsafe::CStr::from_ptr(pathname), AccessMode::READ); } // SAFETY: calling the original libc access() with the same arguments forwarded from the interposed function unsafe { access::original()(pathname, mode) } @@ -25,7 +25,7 @@ unsafe extern "C" fn faccessat( ) -> c_int { // SAFETY: dirfd and pathname are valid arguments provided by the caller of the interposed function unsafe { - handle_open(PathAt(dirfd, pathname), AccessMode::READ); + handle_open(PathAt(dirfd, sigsafe::CStr::from_ptr(pathname)), AccessMode::READ); } // SAFETY: calling the original libc faccessat() with the same arguments forwarded from the interposed function unsafe { faccessat::original()(dirfd, pathname, mode, flags) } diff --git a/crates/fspy_preload_unix/src/interceptions/dirent.rs b/crates/fspy_preload_unix/src/interceptions/dirent.rs index d2b11d39a..a58ae4de8 100644 --- a/crates/fspy_preload_unix/src/interceptions/dirent.rs +++ b/crates/fspy_preload_unix/src/interceptions/dirent.rs @@ -19,7 +19,7 @@ unsafe extern "C" fn scandir( compar: *const c_void, ) -> c_int { // SAFETY: dirname is a valid C string pointer provided by the caller of the interposed function - unsafe { handle_open(dirname, AccessMode::READ_DIR) } + unsafe { handle_open(sigsafe::CStr::from_ptr(dirname), AccessMode::READ_DIR) } // SAFETY: calling the original libc scandir() with the same arguments forwarded from the interposed function unsafe { scandir::original()(dirname, namelist, select, compar) } } @@ -41,7 +41,7 @@ mod macos_only { compar: *const c_void, ) -> c_int { // SAFETY: dirname is a valid C string pointer provided by the caller of the interposed function - unsafe { handle_open(dirname, AccessMode::READ_DIR) }; + unsafe { handle_open(sigsafe::CStr::from_ptr(dirname), AccessMode::READ_DIR) }; // SAFETY: calling the original libc scandir_b() with the same arguments forwarded from the interposed function unsafe { scandir_b::original()(dirname, namelist, select, compar) } } @@ -84,7 +84,7 @@ unsafe extern "C" fn fdopendir(fd: c_int) -> *mut DIR { intercept!(opendir(64): unsafe extern "C" fn (*const c_char) -> *mut DIR); unsafe extern "C" fn opendir(dir_name: *const c_char) -> *mut DIR { // SAFETY: dir_name is a valid C string pointer provided by the caller of the interposed function - unsafe { handle_open(dir_name, AccessMode::READ_DIR) }; + unsafe { handle_open(sigsafe::CStr::from_ptr(dir_name), AccessMode::READ_DIR) }; // SAFETY: calling the original libc opendir() with the same arguments forwarded from the interposed function unsafe { opendir::original()(dir_name) } } diff --git a/crates/fspy_preload_unix/src/interceptions/linux_syscall.rs b/crates/fspy_preload_unix/src/interceptions/linux_syscall.rs index 0731017d7..52941b8b8 100644 --- a/crates/fspy_preload_unix/src/interceptions/linux_syscall.rs +++ b/crates/fspy_preload_unix/src/interceptions/linux_syscall.rs @@ -45,7 +45,9 @@ unsafe extern "C" fn syscall(syscall_no: c_long, mut args: ...) -> c_long { } } else { // SAFETY: pathname is a non-null C string pointer provided by the statx syscall caller. - unsafe { handle_open(PathAt(dirfd, pathname), AccessMode::READ) }; + unsafe { + handle_open(PathAt(dirfd, sigsafe::CStr::from_ptr(pathname)), AccessMode::READ); + } } } // SAFETY: forwarding the syscall to the original libc syscall function with the extracted arguments diff --git a/crates/fspy_preload_unix/src/interceptions/open.rs b/crates/fspy_preload_unix/src/interceptions/open.rs index 641593a13..75bb1b966 100644 --- a/crates/fspy_preload_unix/src/interceptions/open.rs +++ b/crates/fspy_preload_unix/src/interceptions/open.rs @@ -28,7 +28,7 @@ type Mode = c_int; intercept!(open(64): unsafe extern "C" fn(*const c_char, c_int, args: ...) -> c_int); unsafe extern "C" fn open(path: *const c_char, flags: c_int, mut args: ...) -> c_int { // SAFETY: path is a valid C string pointer provided by the caller of the interposed function - unsafe { handle_open(path, OpenFlags(flags)) }; + unsafe { handle_open(sigsafe::CStr::from_ptr(path), OpenFlags(flags)) }; if has_mode_arg(flags) { // SAFETY: when O_CREAT or O_TMPFILE is set, a mode_t argument is required by the open() contract let mode: Mode = unsafe { args.next_arg() }; @@ -48,7 +48,7 @@ unsafe extern "C" fn openat( mut args: ... ) -> c_int { // SAFETY: dirfd and path are valid arguments provided by the caller of the interposed function - unsafe { handle_open(PathAt(dirfd, path), OpenFlags(flags)) }; + unsafe { handle_open(PathAt(dirfd, sigsafe::CStr::from_ptr(path)), OpenFlags(flags)) }; if has_mode_arg(flags) { // https://github.com/tailhook/openat/issues/21#issuecomment-535914957 @@ -67,7 +67,7 @@ intercept!(open_nocancel: unsafe extern "C" fn(*const c_char, c_int, ...) -> c_i #[cfg(target_os = "macos")] unsafe extern "C" fn open_nocancel(path: *const c_char, flags: c_int, mut args: ...) -> c_int { // SAFETY: path is a valid C string pointer provided by the caller of open$NOCANCEL - unsafe { handle_open(path, OpenFlags(flags)) }; + unsafe { handle_open(sigsafe::CStr::from_ptr(path), OpenFlags(flags)) }; if has_mode_arg(flags) { // SAFETY: O_CREAT requires a mode argument, matching the open$NOCANCEL contract let mode: Mode = unsafe { args.next_arg() }; @@ -89,7 +89,7 @@ unsafe extern "C" fn openat_nocancel( mut args: ... ) -> c_int { // SAFETY: dirfd and path are valid arguments provided by the caller of openat$NOCANCEL - unsafe { handle_open(PathAt(dirfd, path), OpenFlags(flags)) }; + unsafe { handle_open(PathAt(dirfd, sigsafe::CStr::from_ptr(path)), OpenFlags(flags)) }; if has_mode_arg(flags) { // SAFETY: O_CREAT requires a mode argument, matching the openat$NOCANCEL contract let mode: Mode = unsafe { args.next_arg() }; @@ -104,7 +104,7 @@ unsafe extern "C" fn openat_nocancel( intercept!(fopen(64): unsafe extern "C" fn(path: *const c_char, mode: *const c_char) -> *mut FILE); unsafe extern "C" fn fopen(path: *const c_char, mode: *const c_char) -> *mut libc::FILE { // SAFETY: path and mode are valid C string pointers provided by the caller of the interposed function - unsafe { handle_open(path, ModeStr(mode)) }; + unsafe { handle_open(sigsafe::CStr::from_ptr(path), ModeStr(mode)) }; // SAFETY: calling the original libc fopen() with the same arguments forwarded from the interposed function unsafe { fopen::original()(path, mode) } } @@ -116,7 +116,7 @@ unsafe extern "C" fn freopen( stream: *mut FILE, ) -> *mut FILE { // SAFETY: path and mode are valid C string pointers provided by the caller of the interposed function - unsafe { handle_open(path, ModeStr(mode)) }; + unsafe { handle_open(sigsafe::CStr::from_ptr(path), ModeStr(mode)) }; // SAFETY: calling the original libc freopen() with the same arguments forwarded from the interposed function unsafe { freopen::original()(path, mode, stream) } } diff --git a/crates/fspy_preload_unix/src/interceptions/spawn/exec/mod.rs b/crates/fspy_preload_unix/src/interceptions/spawn/exec/mod.rs index 182226eea..498a3f9bf 100644 --- a/crates/fspy_preload_unix/src/interceptions/spawn/exec/mod.rs +++ b/crates/fspy_preload_unix/src/interceptions/spawn/exec/mod.rs @@ -197,7 +197,7 @@ mod linux_only { let _unused = execveat::original; // SAFETY: PathAt wraps a valid dirfd and pathname pointer from the interposed execveat call let abs_path_result = unsafe { - PathAt(dirfd, pathname).to_absolute_path(|path| { + PathAt(dirfd, sigsafe::CStr::from_ptr(pathname)).to_absolute_path(|path| { let Some(path) = path else { return Ok(None); }; diff --git a/crates/fspy_preload_unix/src/interceptions/stat.rs b/crates/fspy_preload_unix/src/interceptions/stat.rs index ac4af7651..5ca06236d 100644 --- a/crates/fspy_preload_unix/src/interceptions/stat.rs +++ b/crates/fspy_preload_unix/src/interceptions/stat.rs @@ -12,7 +12,7 @@ intercept!(stat(64): unsafe extern "C" fn(path: *const c_char, buf: *mut stat_st unsafe extern "C" fn stat(path: *const c_char, buf: *mut stat_struct) -> c_int { // SAFETY: path is a valid C string pointer provided by the caller of the interposed function unsafe { - handle_open(path, AccessMode::READ); + handle_open(sigsafe::CStr::from_ptr(path), AccessMode::READ); } // SAFETY: calling the original libc stat() with the same arguments forwarded from the interposed function unsafe { stat::original()(path, buf) } @@ -23,7 +23,7 @@ unsafe extern "C" fn lstat(path: *const c_char, buf: *mut stat_struct) -> c_int // TODO: add accessmode ReadNoFollow // SAFETY: path is a valid C string pointer provided by the caller of the interposed function unsafe { - handle_open(path, AccessMode::READ); + handle_open(sigsafe::CStr::from_ptr(path), AccessMode::READ); } // SAFETY: calling the original libc lstat() with the same arguments forwarded from the interposed function unsafe { lstat::original()(path, buf) } @@ -38,7 +38,7 @@ unsafe extern "C" fn fstatat( ) -> c_int { // SAFETY: dirfd and pathname are valid arguments provided by the caller of the interposed function unsafe { - handle_open(PathAt(dirfd, pathname), AccessMode::READ); + handle_open(PathAt(dirfd, sigsafe::CStr::from_ptr(pathname)), AccessMode::READ); } // SAFETY: calling the original libc fstatat() with the same arguments forwarded from the interposed function unsafe { fstatat::original()(dirfd, pathname, buf, flags) } @@ -75,7 +75,7 @@ unsafe extern "C" fn statx( } } else { // SAFETY: pathname is a non-null C string pointer provided by the statx caller. - unsafe { handle_open(PathAt(dirfd, pathname), AccessMode::READ) }; + unsafe { handle_open(PathAt(dirfd, sigsafe::CStr::from_ptr(pathname)), AccessMode::READ) }; } // SAFETY: calling the original libc statx() with the same arguments forwarded from the interposed function unsafe { original(dirfd, pathname, flags, mask, statxbuf) }