@@ -10,6 +10,10 @@ use libc::{pid_t, seccomp_notif};
1010use nix:: sys:: uio:: { RemoteIoVec , process_vm_readv} ;
1111
1212pub trait FromSyscallArg : Sized {
13+ /// Converts a raw syscall argument into this type.
14+ ///
15+ /// # Errors
16+ /// Returns an error if the argument value cannot be interpreted as this type.
1317 fn from_syscall_arg ( arg : u64 ) -> io:: Result < Self > ;
1418}
1519/// Represents the caller of a syscall. Needed to read memory from the caller's address space.
@@ -26,7 +30,8 @@ impl<'a> Caller<'a> {
2630 f ( Self { pid, _marker : std:: marker:: PhantomData } )
2731 }
2832
29- pub fn read_vm ( self , starting_addr : usize ) -> ProcessVmReader < ' a > {
33+ #[ must_use]
34+ pub const fn read_vm ( self , starting_addr : usize ) -> ProcessVmReader < ' a > {
3035 ProcessVmReader { caller : self , current_addr : starting_addr }
3136 }
3237}
@@ -36,17 +41,18 @@ pub struct ProcessVmReader<'a> {
3641 current_addr : usize ,
3742}
3843
39- impl < ' a > io:: Read for ProcessVmReader < ' a > {
44+ impl io:: Read for ProcessVmReader < ' _ > {
4045 fn read ( & mut self , buf : & mut [ u8 ] ) -> io:: Result < usize > {
4146 let buf_len = buf. len ( ) ;
4247 let read_len = process_vm_readv (
4348 nix:: unistd:: Pid :: from_raw ( self . caller . pid ) ,
4449 & mut [ IoSliceMut :: new ( buf) ] ,
4550 & [ RemoteIoVec { base : self . current_addr , len : buf_len } ] ,
4651 ) ?;
47- self . current_addr = self . current_addr . checked_add ( read_len) . ok_or_else ( || {
48- io:: Error :: new ( io:: ErrorKind :: Other , "address overflow while reading remote process" )
49- } ) ?;
52+ self . current_addr = self
53+ . current_addr
54+ . checked_add ( read_len)
55+ . ok_or_else ( || io:: Error :: other ( "address overflow while reading remote process" ) ) ?;
5056 Ok ( read_len)
5157 }
5258}
@@ -63,7 +69,10 @@ impl CStrPtr {
6369 /// - `Ok(None)` if the buffer was filled without encountering a null-terminator.
6470 /// - `Err(UnexpectedEof)` if Eof was reached without encountering a null-terminator.
6571 /// - `Err(other_err)` on other errors from reading the remote process memory.
66- pub fn read ( & self , caller : Caller < ' _ > , buf : & mut [ u8 ] ) -> io:: Result < Option < usize > > {
72+ ///
73+ /// # Errors
74+ /// Returns an error if reading from the remote process memory fails.
75+ pub fn read ( self , caller : Caller < ' _ > , buf : & mut [ u8 ] ) -> io:: Result < Option < usize > > {
6776 let mut reader = caller. read_vm ( self . remote_ptr ) ;
6877 let mut pos = 0 ;
6978 while let Some ( ( _, unfilled) ) = buf. split_at_mut_checked ( pos) {
@@ -87,8 +96,9 @@ impl CStrPtr {
8796}
8897
8998impl FromSyscallArg for CStrPtr {
99+ #[ expect( clippy:: cast_possible_truncation, reason = "syscall arg represents a pointer address" ) ]
90100 fn from_syscall_arg ( arg : u64 ) -> io:: Result < Self > {
91- Ok ( Self { remote_ptr : arg as _ } )
101+ Ok ( Self { remote_ptr : arg as usize } )
92102 }
93103}
94104
@@ -98,20 +108,28 @@ pub struct Ptr<T> {
98108}
99109impl < T > FromSyscallArg for Ptr < T > {
100110 fn from_syscall_arg ( arg : u64 ) -> io:: Result < Self > {
101- Ok ( Self { remote_ptr : arg as _ , _marker : PhantomData } )
111+ Ok ( Self { remote_ptr : arg as * mut c_void , _marker : PhantomData } )
102112 }
103113}
104114impl < T > Ptr < T > {
105115 /// Reads the value of type T from the remote process memory.
106- /// # Safety:
116+ ///
117+ /// # Safety
107118 /// The remote pointer must be valid and point to a value of type T in the remote process memory.
119+ ///
120+ /// # Errors
121+ /// Returns an error if reading from the remote process memory fails.
108122 pub unsafe fn read ( & self , caller : Caller < ' _ > ) -> io:: Result < T > {
109123 let mut reader = caller. read_vm ( self . remote_ptr as usize ) ;
110124 let mut buf = MaybeUninit :: < T > :: zeroed ( ) ;
125+ // SAFETY: `MaybeUninit<T>` has the same layout as `T`, so casting to a
126+ // byte slice of `size_of::<T>()` bytes is valid for writing into
111127 let buf_slice = unsafe {
112- std:: slice:: from_raw_parts_mut ( buf. as_mut_ptr ( ) as * mut u8 , std:: mem:: size_of :: < T > ( ) )
128+ std:: slice:: from_raw_parts_mut ( buf. as_mut_ptr ( ) . cast :: < u8 > ( ) , std:: mem:: size_of :: < T > ( ) )
113129 } ;
114130 reader. read_exact ( buf_slice) ?;
131+ // SAFETY: all bytes of `buf` have been initialized by `read_exact`,
132+ // and the caller guarantees the remote pointer points to a valid `T`
115133 Ok ( unsafe { buf. assume_init ( ) } )
116134 }
117135}
@@ -120,7 +138,7 @@ impl<T> Ptr<T> {
120138pub struct Ignored ( ( ) ) ;
121139impl FromSyscallArg for Ignored {
122140 fn from_syscall_arg ( _arg : u64 ) -> io:: Result < Self > {
123- Ok ( Ignored ( ( ) ) )
141+ Ok ( Self ( ( ) ) )
124142 }
125143}
126144
@@ -130,20 +148,26 @@ pub struct Fd {
130148}
131149
132150impl Fd {
133- pub fn cwd ( ) -> Self {
151+ #[ must_use]
152+ pub const fn cwd ( ) -> Self {
134153 Self { fd : libc:: AT_FDCWD }
135154 }
136155}
137156
138157impl FromSyscallArg for Fd {
158+ #[ expect( clippy:: cast_possible_truncation, reason = "syscall arg represents a file descriptor" ) ]
139159 fn from_syscall_arg ( arg : u64 ) -> io:: Result < Self > {
140- Ok ( Self { fd : arg as _ } )
160+ Ok ( Self { fd : arg as RawFd } )
141161 }
142162}
143163
144164impl Fd {
145165 // TODO: allocate in arena
146- pub fn get_path ( & self , caller : Caller < ' _ > ) -> nix:: Result < OsString > {
166+ /// Returns the filesystem path associated with this file descriptor.
167+ ///
168+ /// # Errors
169+ /// Returns an error if the `/proc` readlink fails (e.g., the process has exited).
170+ pub fn get_path ( self , caller : Caller < ' _ > ) -> nix:: Result < OsString > {
147171 nix:: fcntl:: readlink (
148172 if self . fd == libc:: AT_FDCWD {
149173 format ! ( "/proc/{}/cwd" , caller. pid)
@@ -156,12 +180,17 @@ impl Fd {
156180}
157181
158182impl FromSyscallArg for c_int {
183+ #[ expect( clippy:: cast_possible_truncation, reason = "syscall arg represents a c_int value" ) ]
159184 fn from_syscall_arg ( arg : u64 ) -> io:: Result < Self > {
160- Ok ( arg as _ )
185+ Ok ( arg as Self )
161186 }
162187}
163188
164189pub trait FromNotify : Sized {
190+ /// Parses syscall arguments from a seccomp notification.
191+ ///
192+ /// # Errors
193+ /// Returns an error if any argument cannot be parsed.
165194 fn from_notify ( notif : & seccomp_notif ) -> io:: Result < Self > ;
166195}
167196
0 commit comments