Support force-write via `/proc/pid/mem`

This commit is contained in:
Wang Siyuan 2026-01-07 13:29:25 +00:00
parent 35b9841cee
commit bf7709f345
2 changed files with 33 additions and 14 deletions

View File

@ -331,15 +331,7 @@ impl VmMapping {
page_fault_info: &PageFaultInfo, page_fault_info: &PageFaultInfo,
rss_delta: &mut RssDelta, rss_delta: &mut RssDelta,
) -> Result<()> { ) -> Result<()> {
if !self.perms.contains(page_fault_info.required_perms) { self.check_perms_for_page_fault(page_fault_info)?;
trace!(
"self.perms {:?}, page_fault_info.required_perms {:?}, self.range {:?}",
self.perms,
page_fault_info.required_perms,
self.range()
);
return_errno_with_message!(Errno::EACCES, "perm check fails");
}
let page_aligned_addr = page_fault_info.address.align_down(PAGE_SIZE); let page_aligned_addr = page_fault_info.address.align_down(PAGE_SIZE);
let is_write = page_fault_info.required_perms.contains(VmPerms::WRITE); let is_write = page_fault_info.required_perms.contains(VmPerms::WRITE);
@ -379,6 +371,33 @@ impl VmMapping {
) )
} }
fn check_perms_for_page_fault(&self, page_fault_info: &PageFaultInfo) -> Result<()> {
trace!(
"self.perms {:?}, page_fault_info.required_perms {:?}, self.range {:?}",
self.perms,
page_fault_info.required_perms,
self.range()
);
let mut perms = self.perms;
// Reference: <https://elixir.bootlin.com/linux/v6.16.5/source/mm/gup.c#L1282-L1311>
if page_fault_info.is_forced {
if perms.contains(VmPerms::MAY_READ) {
perms.insert(VmPerms::READ);
}
if self.is_cow() {
perms.insert(VmPerms::WRITE);
}
}
if !perms.contains(page_fault_info.required_perms) {
return_errno_with_message!(Errno::EACCES, "perm check fails");
}
Ok(())
}
fn handle_single_page_fault( fn handle_single_page_fault(
&self, &self,
vm_space: &VmSpace, vm_space: &VmSpace,
@ -430,7 +449,6 @@ impl VmMapping {
let new_frame = duplicate_frame(&frame)?; let new_frame = duplicate_frame(&frame)?;
prop.flags |= new_flags; prop.flags |= new_flags;
cursor.map(new_frame.into(), prop); cursor.map(new_frame.into(), prop);
rss_delta.add(self.rss_type(), 1);
} }
cursor.flusher().sync_tlb_flush(); cursor.flusher().sync_tlb_flush();
} }

View File

@ -37,8 +37,9 @@ FN_TEST(proc_mem_remote)
CHECK(close(pipe_p2c[1])); CHECK(close(pipe_p2c[1]));
int fd = CHECK(open(FILE_NAME, O_RDONLY)); int fd = CHECK(open(FILE_NAME, O_RDONLY));
void *addr = // The parent should successfully read from and (force) write to this
CHECK_WITH(mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, // memory region via `/proc/pid/mem`, although it isn't `PROT_WRITE`.
void *addr = CHECK_WITH(mmap(NULL, PAGE_SIZE, PROT_READ,
MAP_PRIVATE, fd, 0), MAP_PRIVATE, fd, 0),
_ret != MAP_FAILED); _ret != MAP_FAILED);
CHECK(write(pipe_c2p[1], &addr, sizeof(addr))); CHECK(write(pipe_c2p[1], &addr, sizeof(addr)));