Skip to content

Commit 6e34b19

Browse files
committed
Address review comments
1 parent 4568aeb commit 6e34b19

File tree

2 files changed

+48
-35
lines changed

2 files changed

+48
-35
lines changed

crates/rrg/Cargo.toml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ action-execute_signed_command = []
5555
# in most RRG builds. Once that mechanism is no longer needed, this should be
5656
# deleted.
5757
action-execute_signed_command-preverified = ["action-execute_signed_command"]
58-
action-dump_process_memory = []
58+
action-dump_process_memory = ["dep:windows-sys"]
5959

6060
test-setfattr = []
6161
test-chattr = []
@@ -145,6 +145,7 @@ version = "1.0.3"
145145

146146
[target.'cfg(target_family = "windows")'.dependencies.windows-sys]
147147
version = "0.59.0"
148+
optional = true
148149
features = [
149150
"Win32_Foundation",
150151
"Win32_System_Memory",
@@ -154,6 +155,13 @@ features = [
154155
"Win32_System_ProcessStatus",
155156
]
156157

158+
[target.'cfg(target_family = "windows")'.dev-dependencies.windows-sys]
159+
version = "0.59.0"
160+
features = [
161+
"Win32_Foundation",
162+
"Win32_Storage_FileSystem",
163+
]
164+
157165
[dependencies.ed25519-dalek]
158166
version = "2.1.1"
159167

crates/rrg/src/action/dump_process_memory.rs

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -212,10 +212,6 @@ mod linux {
212212
}
213213

214214
impl MemoryReader for ReadableProcessMemory {
215-
/// Reads a slice `\[offset..(offset+length)\]` of the opened process' memory
216-
/// and returns it as a [`Vec<u8>`]. `offset` is considered as an absolute offset
217-
/// in the process' address space. If the slice falls outside the memory's address space,
218-
/// the returned buffer will be truncated.
219215
fn read_chunk(&mut self, offset: u64, length: u64) -> std::io::Result<Vec<u8>> {
220216
self.mem_file.seek(SeekFrom::Start(offset))?;
221217
let mut buf = Vec::new();
@@ -267,12 +263,12 @@ mod linux {
267263
}
268264

269265
#[cfg(test)]
270-
mod test {
266+
mod tests {
271267
use super::*;
272268

273269
#[test]
274270
fn region_iter_detects_mmap() {
275-
// `mmap` a file and check that the mapping is detected among those returned by
271+
// `mmap` a file and check that the mappinsg is detected among those returned by
276272
// `MappedRegionIter`.
277273
use std::io::Write as _;
278274
use std::os::unix::fs::MetadataExt;
@@ -339,7 +335,7 @@ mod windows {
339335

340336
impl ProcessHandle {
341337
fn open(pid: u32) -> std::io::Result<Self> {
342-
// Open a handle to the process with all access rights
338+
// SAFETY: the returned handle will be closed by the `drop` impl.
343339
let handle: HANDLE = unsafe { OpenProcess(PROCESS_ALL_ACCESS, 0, pid) };
344340
if handle.is_null() {
345341
Err(std::io::Error::last_os_error())
@@ -351,6 +347,8 @@ mod windows {
351347

352348
impl Drop for ProcessHandle {
353349
fn drop(&mut self) {
350+
// SAFETY: since this struct has no `Clone` or `Copy` impl,
351+
// this handle will not be used again after the struct is dropped.
354352
unsafe { CloseHandle(self.0) };
355353
}
356354
}
@@ -390,16 +388,12 @@ mod windows {
390388
mem_info.AllocationProtect
391389
};
392390

393-
let execute = flags & EXECUTE_FLAGS != 0;
394-
let write = flags & WRITE_FLAGS != 0;
395-
// The only flag which disables write access is PAGE_NOACCESS
396-
let read = flags & PAGE_NOACCESS == 0;
397-
let private = mem_info.Type == MEM_PRIVATE;
398391
Permissions {
399-
read,
400-
write,
401-
execute,
402-
private,
392+
// The only flag which disables read access is PAGE_NOACCESS
393+
read: flags & PAGE_NOACCESS == 0,
394+
write: flags & WRITE_FLAGS != 0,
395+
execute: flags & EXECUTE_FLAGS != 0,
396+
private: mem_info.Type == MEM_PRIVATE,
403397
shared: false,
404398
}
405399
}
@@ -412,6 +406,8 @@ mod windows {
412406
use std::os::windows::ffi::OsStringExt;
413407

414408
let mut buf = [0u16; (MAX_PATH + 1) as usize];
409+
// SAFETY: `GetMappedFileNameW` will only write up to `nSize` (last argument)
410+
// characters in `buf` (null-terminator included). Therefore there can be no buffer overflow.
415411
let len = unsafe { GetMappedFileNameW(process.0, addr, buf.as_mut_ptr(), buf.len() as u32) }
416412
as usize;
417413
// A return value of 0 indicates an error, and nSize indicates that the path was
@@ -429,14 +425,17 @@ mod windows {
429425
let mem_info: MEMORY_BASIC_INFORMATION = {
430426
let mut mem: std::mem::MaybeUninit<MEMORY_BASIC_INFORMATION> =
431427
MaybeUninit::zeroed();
432-
if unsafe {
428+
// SAFETY: `VirtualQueryEx` will only write up to `dwLength` (last argument)
429+
// bytes in `mem`.
430+
let status = unsafe {
433431
VirtualQueryEx(
434432
self.process.0,
435433
self.cur_addr,
436434
mem.as_mut_ptr(),
437435
std::mem::size_of::<MEMORY_BASIC_INFORMATION>(),
438-
) == 0
439-
} {
436+
)
437+
};
438+
if status == 0 {
440439
let err = std::io::Error::last_os_error();
441440
// InvalidInput is returned when the given address
442441
// falls beyond the last page accessible by the process,
@@ -446,6 +445,8 @@ mod windows {
446445
}
447446
break Some(Err(err));
448447
}
448+
// SAFETY: We just checked that the call to `VirtualQueryEx`
449+
// has succeeded, so we can safely assume that `mem` was initialized.
449450
unsafe { mem.assume_init() }
450451
};
451452

@@ -484,23 +485,21 @@ mod windows {
484485
}
485486

486487
impl MemoryReader for ReadableProcessMemory {
487-
/// Reads a slice `\[offset..(offset+length)\]` of the opened process' memory
488-
/// and returns it as a [`Vec<u8>`]. `offset` is considered as an absolute offset
489-
/// in the process' address space. If the slice falls outside the memory's address space,
490-
/// the returned buffer will be truncated.
491488
fn read_chunk(&mut self, offset: u64, length: u64) -> std::io::Result<Vec<u8>> {
492489
let mut buf = vec![0; length as usize];
493490
let mut bytes_read = 0;
494-
if unsafe {
491+
// SAFETY: `ReadProcessMemory` will write at most `nSize` (second to last argument) bytes
492+
// in `buf`, so the bounded length prevents a buffer overflow.
493+
let status = unsafe {
495494
ReadProcessMemory(
496495
self.process.0,
497496
std::ptr::without_provenance_mut(offset as usize),
498497
buf.as_mut_ptr().cast(),
499498
buf.len(),
500499
&mut bytes_read,
501500
)
502-
} == 0
503-
{
501+
};
502+
if status == 0 {
504503
return Err(std::io::Error::last_os_error());
505504
}
506505
buf.truncate(bytes_read);
@@ -509,7 +508,7 @@ mod windows {
509508
}
510509

511510
#[cfg(test)]
512-
mod test {
511+
mod tests {
513512
use super::*;
514513

515514
#[test]
@@ -529,7 +528,8 @@ mod windows {
529528
let meta = file.metadata().unwrap();
530529
let length = meta.len() as usize;
531530

532-
// Create a file mapping object for the file
531+
// SAFETY: the returned mapping will be dropped
532+
// by `OwnedHandle`'s `drop` impl.
533533
let mapping = unsafe {
534534
CreateFileMappingW(
535535
file.as_raw_handle(),
@@ -542,9 +542,11 @@ mod windows {
542542
};
543543

544544
if mapping.is_null() {
545-
panic!("Could not create file mapping");
545+
panic!("could not create file mapping");
546546
}
547547

548+
// SAFETY: we just cheched that the mapping was created succesfully.
549+
// The raw handle was also not copied to another variable in the meantime
548550
let mapping = unsafe { OwnedHandle::from_raw_handle(mapping) };
549551

550552
/// RAII wrapper around a `mmap`ed pointer that will `munmap` on drop.
@@ -554,6 +556,7 @@ mod windows {
554556

555557
impl Drop for MappedView {
556558
fn drop(&mut self) {
559+
// SAFETY: we only need `unsafe` to call the FFI function here.
557560
unsafe {
558561
UnmapViewOfFile(self.addr);
559562
}
@@ -563,6 +566,8 @@ mod windows {
563566
// Map the view and test the results.
564567

565568
let view = unsafe {
569+
// SAFETY: the returned mapping will be unmapped by `MappedView`'s `drop`
570+
// impl. We check right away if the returned handle is valid.
566571
let addr = MapViewOfFile(
567572
mapping.as_raw_handle(), // handle to mapping object
568573
FILE_MAP_ALL_ACCESS, // read/write
@@ -575,9 +580,9 @@ mod windows {
575580
};
576581

577582
let regions: Vec<MappedRegion> = MappedRegionIter::from_pid(std::process::id())
578-
.expect("Could not read memory regions of current process")
583+
.expect("could not read memory regions of current process")
579584
.collect::<Result<_, _>>()
580-
.expect("Reading maps");
585+
.expect("reading maps");
581586

582587
assert!(regions.into_iter().any(|r| {
583588
r.address_start == view.addr.Value as u64
@@ -959,7 +964,7 @@ where
959964
}
960965

961966
#[cfg(test)]
962-
mod test {
967+
mod tests {
963968
use super::*;
964969

965970
struct FakeProcessMemory {
@@ -989,9 +994,9 @@ mod test {
989994
fn can_read_this_process_memory() {
990995
let pid = std::process::id();
991996
let regions: Vec<MappedRegion> = MappedRegionIter::from_pid(pid)
992-
.expect("Could not read memory regions of current process")
997+
.expect("could not read memory regions of current process")
993998
.collect::<Result<_, _>>()
994-
.expect("Reading maps");
999+
.expect("reading maps");
9951000

9961001
let mut memory = ReadableProcessMemory::open(pid).expect("Could not open process memory");
9971002
assert! {

0 commit comments

Comments
 (0)