Skip to content

Commit dc8a6f0

Browse files
misc(vm): collate mmap flags into vm flags
Signed-off-by: Anhad Singh <[email protected]>
1 parent beb3cc5 commit dc8a6f0

File tree

6 files changed

+54
-39
lines changed

6 files changed

+54
-39
lines changed

src/aero_kernel/src/arch/x86_64/task.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,15 +80,15 @@ pub enum AuxvType {
8080
/// Returns the first address outside the user range.
8181
///
8282
/// ## Notes
83-
/// * On Intel CPUs, if a SYSCALL instruction is at the highest canonical address, then
84-
/// that syscall will enter the kernel with a non-canonical return address, and SYSRET will
85-
/// explode dangerously. We avoid this particular problem by preventing anything from
86-
/// being mapped at the maximum canonical address.
83+
/// * On Intel CPUs, if a SYSCALL instruction is at the highest canonical address, then that syscall
84+
/// will enter the kernel with a non-canonical return address, and SYSRET will explode
85+
/// dangerously. We avoid this particular problem by preventing anything from being mapped at the
86+
/// maximum canonical address.
8787
///
8888
/// * On AMD CPUs in the Ryzen family, there's a nasty bug in which the CPUs malfunction if they
89-
/// execute code from the highest canonical page. They'll speculate right off the end of the
90-
/// canonical space and bad things happen. This is worked around in the same way as the Intel
91-
/// problem.
89+
/// execute code from the highest canonical page. They'll speculate right off the end of the
90+
/// canonical space and bad things happen. This is worked around in the same way as the Intel
91+
/// problem.
9292
pub fn userland_last_address() -> VirtAddr {
9393
// Reference: https://elixir.bootlin.com/linux/latest/source/arch/x86/include/asm/page_64.h#L61
9494
static CACHED: spin::Once<VirtAddr> = spin::Once::new();

src/aero_kernel/src/fs/block/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,6 @@ impl CachedPage {
104104
}
105105

106106
pub fn mark_dirty(&self) {
107-
log::error!("marking dirty --------------------------------------");
108107
self.dirty.store(true, Ordering::SeqCst);
109108
}
110109

src/aero_kernel/src/fs/procfs.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,8 @@ impl INodeInterface for LockedProcINode {
199199
maps.push(serde_json::json!({
200200
"start": map.start_addr.as_u64(),
201201
"end": map.end_addr.as_u64(),
202-
"flags": map.flags.bits(),
202+
// "flags": map.flags.bits(),
203+
// do we need to tell if is shared?
203204
"protection": map.protection().bits(),
204205
}));
205206
});

src/aero_kernel/src/mem/paging/addr.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,19 @@ impl VirtAddr {
113113
self.0 == 0
114114
}
115115

116+
pub fn is_canonical(self) -> bool {
117+
let virtual_mask_shift = if super::level_5_paging_enabled() {
118+
56
119+
} else {
120+
47
121+
};
122+
123+
let shift = 64 - (virtual_mask_shift + 1);
124+
125+
// By doing the right shift as a signed operation will sign extend the value.
126+
((self.as_u64() << shift) as i64 >> shift) as u64 == self.as_u64()
127+
}
128+
116129
/// Validate reads `sizeof(T)` bytes from the virtual address and returns a mutable
117130
/// reference to the value (`&mut T`).
118131
///

src/aero_kernel/src/unwind.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,15 +112,14 @@ pub fn unwind_stack_trace() {
112112

113113
for depth in 0../*64*/16 {
114114
if let Some(rip_rbp) = rbp.checked_add(core::mem::size_of::<usize>()) {
115-
if offset_table
116-
.translate_addr(VirtAddr::new(rip_rbp as u64))
117-
.is_none()
118-
{
115+
let rip_rbp = VirtAddr::new(rip_rbp as u64);
116+
117+
if offset_table.translate_addr(rip_rbp).is_none() || !rip_rbp.is_canonical() {
119118
log::trace!("{:>2}: <guard page>", depth);
120119
break;
121120
}
122121

123-
let rip = unsafe { *(rip_rbp as *const usize) };
122+
let rip = unsafe { *(rip_rbp.as_ptr::<usize>()) };
124123

125124
if rip == 0 {
126125
break;

src/aero_kernel/src/userland/vm.rs

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ bitflags::bitflags! {
5454
const MAY_READ = 1 << 3;
5555
const MAY_WRITE = 1 << 4;
5656
const MAY_EXEC = 1 << 5;
57+
58+
const SHARED = 1 << 6;
5759
}
5860
}
5961

@@ -369,7 +371,6 @@ impl MMapFile {
369371

370372
#[derive(Clone)]
371373
pub struct Mapping {
372-
pub flags: MMapFlags,
373374
vm_flags: VmFlag,
374375

375376
pub start_addr: VirtAddr,
@@ -474,7 +475,7 @@ impl Mapping {
474475
let addr = addr.align_down(Size4KiB::SIZE);
475476
let size = Size4KiB::SIZE.min(file.size as u64 - (addr - self.start_addr));
476477

477-
return if self.flags.contains(MMapFlags::MAP_SHARED) {
478+
return if self.vm_flags.contains(VmFlag::SHARED) {
478479
self.handle_pf_shared_file(offset_table, reason, addr, offset as _, size as _)
479480
} else {
480481
self.handle_pf_private_file(offset_table, reason, addr, offset as _, size as _)
@@ -545,7 +546,7 @@ impl Mapping {
545546
let frame = mmap_file
546547
.file
547548
.inode()
548-
.mmap(offset, size, self.flags)
549+
.mmap(offset, size, MMapFlags::empty())
549550
.expect("handle_pf_file: file does not support mmap");
550551

551552
unsafe {
@@ -764,7 +765,6 @@ impl Mapping {
764765
});
765766

766767
let new_mapping = Mapping {
767-
flags: self.flags,
768768
start_addr: end,
769769
end_addr: end + (self.end_addr - end),
770770
file: new_file,
@@ -868,13 +868,10 @@ impl VmProtected {
868868
return false;
869869
}
870870

871-
let is_private = map.flags.contains(MMapFlags::MAP_PRIVATE);
872-
let is_annon = map.flags.contains(MMapFlags::MAP_ANONYOMUS);
873-
874871
let mut address_space = AddressSpace::this();
875872
let mut offset_table = address_space.offset_page_table();
876873

877-
match (is_private, is_annon) {
874+
match (!map.vm_flags.contains(VmFlag::SHARED), map.file.is_none()) {
878875
(true, true) => {
879876
map.handle_pf_private_anon(&mut offset_table, reason, accessed_address)
880877
}
@@ -970,9 +967,6 @@ impl VmProtected {
970967
file: Option<DirCacheItem>,
971968
vm_flags: VmFlag,
972969
) -> Option<VirtAddr> {
973-
// TODO: Check file permissions:
974-
// * Do not allow writing to an {read, append}-only file.
975-
976970
let z = file.clone();
977971

978972
// Offset is required to be a multiple of page size.
@@ -1030,19 +1024,16 @@ impl VmProtected {
10301024
// Merge same mappings instead of creating a new one.
10311025
if let Some(prev) = cursor.peek_prev() {
10321026
if prev.end_addr == addr
1033-
&& prev.flags == flags
1034-
&& prev.protection() == (vm_flags & VM_PROT_MASK)
1027+
&& prev.vm_flags == vm_flags
10351028
&& prev.file.is_none()
1029+
&& file.is_none()
10361030
{
10371031
prev.end_addr = addr + size_aligned;
1038-
10391032
return addr;
10401033
}
10411034
}
10421035

10431036
cursor.insert_before(Mapping {
1044-
flags,
1045-
10461037
start_addr: addr,
10471038
end_addr: addr + size_aligned,
10481039

@@ -1077,21 +1068,19 @@ impl VmProtected {
10771068
for mmap in &self.mappings {
10781069
if let Some(file) = mmap.file.as_ref() {
10791070
log::debug!(
1080-
"{:?}..{:?} => {:?}, {:?} (offset={:#x}, size={:#x})",
1071+
"{:?}..{:?} => {:?} (offset={:#x}, size={:#x})",
10811072
mmap.start_addr,
10821073
mmap.end_addr,
10831074
mmap.vm_flags,
1084-
mmap.flags,
10851075
file.offset,
10861076
file.size,
10871077
);
10881078
} else {
10891079
log::debug!(
1090-
"{:?}..{:?} => {:?}, {:?}",
1080+
"{:?}..{:?} => {:?}",
10911081
mmap.start_addr,
10921082
mmap.end_addr,
10931083
mmap.vm_flags,
1094-
mmap.flags,
10951084
);
10961085
}
10971086
}
@@ -1376,7 +1365,7 @@ impl VmProtected {
13761365

13771366
for map in self.mappings.iter().filter(|map| {
13781367
// Do not copy page table entries where a page fault can map them correctly.
1379-
!map.flags.contains(MMapFlags::MAP_SHARED) && map.vm_flags.contains(VmFlag::MAY_WRITE)
1368+
!map.vm_flags.contains(VmFlag::SHARED) && map.vm_flags.contains(VmFlag::MAY_WRITE)
13801369
}) {
13811370
offset_table.copy_page_range(&mut current, map.start_addr..=map.end_addr);
13821371
}
@@ -1406,18 +1395,31 @@ impl Vm {
14061395
offset: usize,
14071396
file: Option<Arc<FileHandle>>,
14081397
) -> Option<VirtAddr> {
1409-
let vm_flags =
1398+
let mut vm_flags =
14101399
VmFlag::from(protection) | VmFlag::MAY_READ | VmFlag::MAY_WRITE | VmFlag::MAY_EXEC;
14111400

14121401
let map_type = flags & (MMapFlags::MAP_SHARED | MMapFlags::MAP_PRIVATE);
14131402

14141403
match (map_type, file.as_ref()) {
14151404
(MMapFlags::MAP_SHARED, Some(file)) => {
1416-
if protection.contains(MMapProt::PROT_WRITE) && !file.is_writable() {
1417-
return None; // EACCES
1405+
vm_flags.insert(VmFlag::SHARED);
1406+
1407+
if !file.is_writable() {
1408+
if protection.contains(MMapProt::PROT_WRITE) {
1409+
return None; // EACCES
1410+
}
1411+
1412+
// The mapping is going to be read-only forever so, it can be converted into a
1413+
// private mapping.
1414+
vm_flags.remove(VmFlag::MAY_WRITE | VmFlag::SHARED);
14181415
}
14191416

1420-
// TODO: check for append-only files.
1417+
if !file.is_readable() {
1418+
// return None; // EACCES
1419+
}
1420+
1421+
// TODO: * check if the filsystem is noexec mounted and remove the MAY_EXEC flag.
1422+
// * error out if prot contains PROT_EXEC & filesystem is noexec.
14211423
}
14221424

14231425
(MMapFlags::MAP_PRIVATE, Some(file)) => {
@@ -1429,6 +1431,7 @@ impl Vm {
14291431
// * error out if prot contains PROT_EXEC & filesystem is noexec.
14301432
}
14311433

1434+
(MMapFlags::MAP_SHARED, None) => vm_flags.insert(VmFlag::SHARED),
14321435
_ => {}
14331436
}
14341437

0 commit comments

Comments
 (0)