From 3c3c7ad74c302dc4e162c4deb27e1dd40fc6f6eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=91=A8=E7=9D=BF?= Date: Tue, 7 Jul 2026 16:35:21 +0800 Subject: [PATCH] fix(starry-kernel): reject private mmap faults past eof --- os/StarryOS/kernel/src/axtest_exports.rs | 4 ++ .../kernel/src/mm/aspace/backend/cow.rs | 57 +++++++++++++++++-- .../kernel/src/mm/aspace/backend/mod.rs | 2 + os/StarryOS/kernel/tests/axtest_kernel.rs | 5 ++ 4 files changed, 62 insertions(+), 6 deletions(-) diff --git a/os/StarryOS/kernel/src/axtest_exports.rs b/os/StarryOS/kernel/src/axtest_exports.rs index 3d430e5f8c..6bf2c2ece1 100644 --- a/os/StarryOS/kernel/src/axtest_exports.rs +++ b/os/StarryOS/kernel/src/axtest_exports.rs @@ -45,3 +45,7 @@ pub fn pipe_resize_rejects_oversized_pipe() -> bool { pub fn fcntl_setpipe_size_returns_capacity() -> bool { super::syscall::fcntl_setpipe_size_returns_capacity_for_test() } + +pub fn private_mmap_rejects_fault_at_file_eof() -> bool { + super::mm::private_mmap_eof_check_for_test() +} diff --git a/os/StarryOS/kernel/src/mm/aspace/backend/cow.rs b/os/StarryOS/kernel/src/mm/aspace/backend/cow.rs index 62c4571106..4ee1eb7093 100644 --- a/os/StarryOS/kernel/src/mm/aspace/backend/cow.rs +++ b/os/StarryOS/kernel/src/mm/aspace/backend/cow.rs @@ -76,6 +76,48 @@ impl FrameTableRefCount { static FRAME_TABLE: SpinNoIrq = SpinNoIrq::new(FrameTableRefCount::new()); +fn cow_file_max_read_len( + file_len: u64, + file_end: Option, + file_read_offset: u64, + available: usize, +) -> AxResult { + let effective_end = match file_end { + Some(end) => end, + None => { + if file_read_offset >= file_len { + return Err(AxError::BadAddress); + } + file_len + } + }; + Ok(effective_end + .saturating_sub(file_read_offset) + .min(available as u64) as usize) +} + +fn cow_file_max_read( + file: &FileBackend, + file_end: Option, + file_read_offset: u64, + available: usize, +) -> AxResult { + let file_len = if file_end.is_none() { file.len()? } else { 0 }; + cow_file_max_read_len(file_len, file_end, file_read_offset, available) +} + +#[cfg(axtest)] +pub(crate) fn private_mmap_eof_check_for_test() -> bool { + matches!( + cow_file_max_read_len(4096, None, 4096, 4096), + Err(AxError::BadAddress) + ) && matches!(cow_file_max_read_len(4096, None, 2048, 4096), Ok(2048)) + && matches!( + cow_file_max_read_len(4096, Some(8192), 4096, 4096), + Ok(4096) + ) +} + /// Copy-on-write mapping backend. /// /// This corresponds to the `MAP_PRIVATE` flag. @@ -226,9 +268,14 @@ impl CowBackend { let file_read_offset = *file_start + vaddr.as_usize().saturating_sub(file_vaddr_base.as_usize()) as u64; - let max_read = file_end - .map_or(u64::MAX, |end| end.saturating_sub(file_read_offset)) - .min((buf.len() - start) as u64) as usize; + let max_read = + match cow_file_max_read(file, *file_end, file_read_offset, buf.len() - start) { + Ok(max_read) => max_read, + Err(err) => { + self.deinit_frame(frame); + return Err(err); + } + }; if let Err(err) = file.read_at(&mut &mut buf[start..start + max_read], file_read_offset) { @@ -274,9 +321,7 @@ impl CowBackend { let n = run.len(); let total = n * ps; let file_read_offset = file_start + (v0.as_usize() - file_vaddr_base.as_usize()) as u64; - let max_read = file_end - .map_or(u64::MAX, |end| end.saturating_sub(file_read_offset)) - .min(total as u64) as usize; + let max_read = cow_file_max_read(file, *file_end, file_read_offset, total)?; let mut buf = alloc::vec![0u8; total]; if max_read > 0 { file.read_at(&mut &mut buf[..max_read], file_read_offset)?; diff --git a/os/StarryOS/kernel/src/mm/aspace/backend/mod.rs b/os/StarryOS/kernel/src/mm/aspace/backend/mod.rs index e72737fe99..2de5cb6601 100644 --- a/os/StarryOS/kernel/src/mm/aspace/backend/mod.rs +++ b/os/StarryOS/kernel/src/mm/aspace/backend/mod.rs @@ -21,6 +21,8 @@ mod file; mod linear; mod shared; +#[cfg(axtest)] +pub(crate) use self::cow::private_mmap_eof_check_for_test; pub use self::shared::SharedPages; pub use super::accounting::RssKind; use super::{ diff --git a/os/StarryOS/kernel/tests/axtest_kernel.rs b/os/StarryOS/kernel/tests/axtest_kernel.rs index e2ceba1ffc..ca9f6ceca7 100644 --- a/os/StarryOS/kernel/tests/axtest_kernel.rs +++ b/os/StarryOS/kernel/tests/axtest_kernel.rs @@ -49,4 +49,9 @@ mod tests { fn fcntl_setpipe_size_returns_capacity() { ax_assert!(axtest_exports::fcntl_setpipe_size_returns_capacity()); } + + #[test] + fn private_mmap_rejects_fault_at_file_eof() { + ax_assert!(axtest_exports::private_mmap_rejects_fault_at_file_eof()); + } }