1use crate::mm::barrier::{BarrierType, system_barrier};
6use crate::mm::mapping::MappingBackingMemory;
7use crate::mm::memory::MemoryObject;
8use crate::mm::private_anonymous_memory_manager::PrivateAnonymousMemoryManager;
9use crate::mm::{
10 FaultRegisterMode, InflightVmsplicedPayloads, MapInfoCache, Mapping, MappingAccess,
11 MappingBacking, MappingFlags, MappingMode, MappingName, MappingNameRef, MlockPinFlavor,
12 PrefetchMessage, ProtectionFlags, UserFault, VMEX_RESOURCE, VmsplicePayload,
13 VmsplicePayloadSegment,
14};
15use crate::security;
16use crate::signals::{SignalDetail, SignalInfo};
17use crate::task::{
18 CurrentTask, ExceptionResult, Kernel, PageFaultExceptionReport, Task, TaskContainer,
19};
20use crate::vfs::aio::AioContext;
21use crate::vfs::buffers::{InputBuffer, OutputBuffer};
22use crate::vfs::pseudo::dynamic_file::{
23 DynamicFile, DynamicFileBuf, DynamicFileSource, SequenceFileSource,
24};
25use crate::vfs::{
26 FileHandle, FileObject, FileOps, FsContext, FsString, NamespaceNode, fileops_impl_noop_sync,
27 fileops_impl_seekable,
28};
29use anyhow::{Error, anyhow};
30use bitflags::bitflags;
31use crossbeam::atomic::AtomicCell;
32use flyweights::FlyByteStr;
33use linux_uapi::BUS_ADRERR;
34use memory_pinning::PinnedMapping;
35use range_map::RangeMap;
36use rustc_hash::FxHashMap;
37use smallvec::SmallVec;
38use starnix_lifecycle::DropNotifier;
39use starnix_logging::{CATEGORY_STARNIX_MM, impossible_error, log_error, log_warn, track_stub};
40use starnix_sync::{
41 LockDepMutex, LockDepRwLock, LockDepWriteGuard, MemoryManagerCachedStatsLock,
42 MemoryManagerStateLock, assert_lock_level, ordered_write_lock,
43};
44use starnix_types::arch::ArchWidth;
45use starnix_types::futex_address::FutexAddress;
46use starnix_types::math::{round_down_to_system_page_size, round_up_to_system_page_size};
47use starnix_types::user_buffer::{UserBuffer, UserBuffers};
48use starnix_uapi::auth::CAP_IPC_LOCK;
49use starnix_uapi::errors::{EPERM, Errno};
50use starnix_uapi::personality::PersonalityFlags;
51use starnix_uapi::range_ext::RangeExt;
52use starnix_uapi::resource_limits::Resource;
53use starnix_uapi::restricted_aspace::{
54 RESTRICTED_ASPACE_BASE, RESTRICTED_ASPACE_HIGHEST_ADDRESS, RESTRICTED_ASPACE_RANGE,
55 RESTRICTED_ASPACE_SIZE,
56};
57use starnix_uapi::signals::{SIGBUS, SIGSEGV};
58use starnix_uapi::user_address::{ArchSpecific, UserAddress};
59use starnix_uapi::{
60 MADV_COLD, MADV_COLLAPSE, MADV_DODUMP, MADV_DOFORK, MADV_DONTDUMP, MADV_DONTFORK,
61 MADV_DONTNEED, MADV_DONTNEED_LOCKED, MADV_FREE, MADV_HUGEPAGE, MADV_HWPOISON, MADV_KEEPONFORK,
62 MADV_MERGEABLE, MADV_NOHUGEPAGE, MADV_NORMAL, MADV_PAGEOUT, MADV_POPULATE_READ, MADV_RANDOM,
63 MADV_REMOVE, MADV_SEQUENTIAL, MADV_SOFT_OFFLINE, MADV_UNMERGEABLE, MADV_WILLNEED,
64 MADV_WIPEONFORK, MREMAP_DONTUNMAP, MREMAP_FIXED, MREMAP_MAYMOVE, errno, error,
65 from_status_like_fdio,
66};
67use std::collections::HashMap;
68use std::hash::Hasher;
69use std::mem::MaybeUninit;
70use std::ops::{ControlFlow, Deref, DerefMut, Range, RangeBounds};
71use std::sync::{Arc, LazyLock, Weak};
72use zerocopy::IntoBytes;
73
74pub const ZX_VM_SPECIFIC_OVERWRITE: zx::VmarFlags =
75 zx::VmarFlags::from_bits_retain(zx::VmarFlagsExtended::SPECIFIC_OVERWRITE.bits());
76
77pub fn init_usercopy() {
84 let _ = usercopy();
86}
87
88thread_local! {
89 static LAST_SEEN_MAPPING_GENERATION: std::cell::Cell<u64> = const { std::cell::Cell::new(0) };
92}
93
94pub const GUARD_PAGE_COUNT_FOR_GROWSDOWN_MAPPINGS: usize = 256;
95
96#[cfg(target_arch = "x86_64")]
97const ASLR_RANDOM_BITS: usize = 27;
98
99#[cfg(target_arch = "aarch64")]
100const ASLR_RANDOM_BITS: usize = 28;
101
102#[cfg(target_arch = "riscv64")]
103const ASLR_RANDOM_BITS: usize = 18;
104
105const ASLR_32_RANDOM_BITS: usize = 8;
107
108const MAX_STACK_SIZE: usize = 512 * 1024 * 1024;
111
112const STUB_VM_RSS_HWM: usize = 2 * 1024 * 1024;
116
117fn usercopy() -> &'static usercopy::Usercopy {
118 static USERCOPY: LazyLock<usercopy::Usercopy> = LazyLock::new(|| {
119 usercopy::Usercopy::new(RESTRICTED_ASPACE_RANGE).unwrap()
122 });
123
124 LazyLock::force(&USERCOPY)
125}
126
127#[unsafe(no_mangle)]
139pub unsafe fn zxio_maybe_faultable_copy_impl(
140 dest: *mut u8,
141 src: *const u8,
142 count: usize,
143 ret_dest: bool,
144) -> bool {
145 let ret = unsafe { usercopy().raw_hermetic_copy(dest, src, count, ret_dest) };
148 ret == count
149}
150
151pub static PAGE_SIZE: LazyLock<u64> = LazyLock::new(|| zx::system_get_page_size() as u64);
152
153bitflags! {
154 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
155 pub struct MappingOptions: u32 {
156 const SHARED = 1 << 0;
157 const ANONYMOUS = 1 << 1;
158 const LOWER_32BIT = 1 << 2;
159 const GROWSDOWN = 1 << 3;
160 const ELF_BINARY = 1 << 4;
161 const DONTFORK = 1 << 5;
162 const WIPEONFORK = 1 << 6;
163 const DONT_SPLIT = 1 << 7;
164 const DONT_EXPAND = 1 << 8;
165 const LAZY_PRIVATE_FILE = 1 << 9;
166 const POPULATE = 1 << 10;
167 }
168}
169
170bitflags! {
171 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
172 pub struct MremapFlags: u32 {
173 const MAYMOVE = MREMAP_MAYMOVE;
174 const FIXED = MREMAP_FIXED;
175 const DONTUNMAP = MREMAP_DONTUNMAP;
176 }
177}
178
179bitflags! {
180 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
181 pub struct MsyncFlags: u32 {
182 const ASYNC = starnix_uapi::MS_ASYNC;
183 const INVALIDATE = starnix_uapi::MS_INVALIDATE;
184 const SYNC = starnix_uapi::MS_SYNC;
185 }
186}
187
188const PROGRAM_BREAK_LIMIT: u64 = 64 * 1024 * 1024;
189
190#[derive(Debug, Clone, Eq, PartialEq)]
191struct ProgramBreak {
192 base: UserAddress,
194
195 current: UserAddress,
200}
201
202#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)]
204pub enum DumpPolicy {
205 #[default]
209 Disable = 0,
210
211 User = 1,
215}
216
217impl From<DumpPolicy> for i32 {
218 fn from(policy: DumpPolicy) -> i32 {
219 policy as i32
220 }
221}
222
223impl TryFrom<i32> for DumpPolicy {
224 type Error = Errno;
225
226 fn try_from(value: i32) -> Result<Self, Errno> {
227 match value {
228 0 => Ok(Self::Disable),
229 1 => Ok(Self::User),
230 2 => {
231 track_stub!(TODO("https://fxbug.dev/322873960"), "SUID_DUMP_ROOT");
232 error!(EINVAL)
233 }
234 _ => error!(EINVAL),
235 }
236 }
237}
238
239static_assertions::const_assert!(AtomicCell::<DumpPolicy>::is_lock_free());
240
241pub enum MembarrierType {
243 Memory, SyncCore, }
246
247#[derive(Default, Clone)]
249struct MembarrierRegistrations {
250 memory: bool,
251 sync_core: bool,
252}
253
254#[derive(Default)]
255struct Mappings {
256 map: RangeMap<UserAddress, Mapping>,
258
259 generation: u64,
263
264 total_usage: usize,
266}
267
268impl Deref for Mappings {
269 type Target = RangeMap<UserAddress, Mapping>;
270
271 fn deref(&self) -> &Self::Target {
272 &self.map
273 }
274}
275
276impl Mappings {
277 pub fn insert(&mut self, range: std::ops::Range<UserAddress>, value: Mapping) -> Vec<Mapping> {
278 self.generation = self.generation.wrapping_add(1);
279 let range_len = range.end - range.start;
280 let removed_len: usize = self
281 .map
282 .range(range.clone())
283 .map(|(r, _)| {
284 let intersection = r.intersect(&range);
285 intersection.end - intersection.start
286 })
287 .sum();
288 let removed = self.map.insert(range, value);
289 self.total_usage = self.total_usage.saturating_add(range_len).saturating_sub(removed_len);
290 removed
291 }
292
293 pub fn remove(&mut self, range: std::ops::Range<UserAddress>) -> Vec<Mapping> {
294 self.generation = self.generation.wrapping_add(1);
295 let removed_len: usize = self
296 .map
297 .range(range.clone())
298 .map(|(r, _)| {
299 let intersection = r.intersect(&range);
300 intersection.end - intersection.start
301 })
302 .sum();
303 let removed = self.map.remove(range);
304 self.total_usage = self.total_usage.saturating_sub(removed_len);
305 removed
306 }
307
308 pub fn append_non_overlapping(
309 &mut self,
310 range: std::ops::Range<UserAddress>,
311 value: Mapping,
312 ) -> bool {
313 self.generation = self.generation.wrapping_add(1);
314 let range_len = range.end - range.start;
315 if self.map.append_non_overlapping(range, value) {
316 self.total_usage = self.total_usage.saturating_add(range_len);
317 true
318 } else {
319 false
320 }
321 }
322
323 pub fn update_exact<F, E>(
324 &mut self,
325 range: &std::ops::Range<UserAddress>,
326 f: F,
327 ) -> Result<bool, E>
328 where
329 F: FnOnce(&mut Mapping) -> Result<(), E>,
330 {
331 self.generation = self.generation.wrapping_add(1);
332 self.map.update_exact(range, f)
333 }
334}
335
336pub struct MemoryManagerState {
337 mappings: Mappings,
339
340 userfaultfds: Vec<Weak<UserFault>>,
342
343 shadow_mappings_for_mlock: RangeMap<UserAddress, Arc<PinnedMapping>>,
348
349 forkable_state: MemoryManagerForkableState,
350}
351
352const LOWER_4GB_LIMIT: UserAddress = UserAddress::const_from(0xffff_0000);
354
355#[derive(Default, Clone)]
356pub struct MemoryManagerForkableState {
357 brk: Option<ProgramBreak>,
359
360 executable_node: Option<NamespaceNode>,
362
363 pub stack_start: UserAddress,
364 pub auxv_start: UserAddress,
365 pub auxv_end: UserAddress,
366 pub argv_start: UserAddress,
367 pub argv_end: UserAddress,
368 pub environ_start: UserAddress,
369 pub environ_end: UserAddress,
370
371 pub vdso_base: UserAddress,
373
374 pub mmap_top: UserAddress,
376 pub stack_origin: UserAddress,
377 pub brk_origin: UserAddress,
378
379 membarrier_registrations: MembarrierRegistrations,
381}
382
383impl Deref for MemoryManagerState {
384 type Target = MemoryManagerForkableState;
385 fn deref(&self) -> &Self::Target {
386 &self.forkable_state
387 }
388}
389
390impl DerefMut for MemoryManagerState {
391 fn deref_mut(&mut self) -> &mut Self::Target {
392 &mut self.forkable_state
393 }
394}
395
396#[derive(Debug, Default)]
397struct ReleasedMappings {
398 doomed: Vec<Mapping>,
399 doomed_pins: Vec<Arc<PinnedMapping>>,
400}
401
402impl ReleasedMappings {
403 fn extend(&mut self, mappings: impl IntoIterator<Item = Mapping>) {
404 self.doomed.extend(mappings);
405 }
406
407 fn extend_pins(&mut self, mappings: impl IntoIterator<Item = Arc<PinnedMapping>>) {
408 self.doomed_pins.extend(mappings);
409 }
410
411 fn is_empty(&self) -> bool {
412 self.doomed.is_empty() && self.doomed_pins.is_empty()
413 }
414
415 #[cfg(test)]
416 fn len(&self) -> usize {
417 self.doomed.len() + self.doomed_pins.len()
418 }
419
420 fn finalize(&mut self, mm_state: LockDepWriteGuard<'_, MemoryManagerState>) {
421 std::mem::drop(mm_state);
424 std::mem::take(&mut self.doomed);
425 std::mem::take(&mut self.doomed_pins);
426 }
427}
428
429impl Drop for ReleasedMappings {
430 fn drop(&mut self) {
431 assert!(self.is_empty(), "ReleasedMappings::finalize() must be called before drop");
432 }
433}
434
435fn map_in_vmar(
436 vmar: &zx::Vmar,
437 vmar_info: &zx::VmarInfo,
438 addr: SelectedAddress,
439 memory: &MemoryObject,
440 memory_offset: u64,
441 length: usize,
442 flags: MappingFlags,
443 populate: bool,
444) -> Result<(), Errno> {
445 let vmar_offset = addr.addr().checked_sub(vmar_info.base).ok_or_else(|| errno!(ENOMEM))?;
446 let vmar_extra_flags = match addr {
447 SelectedAddress::Fixed(_) => zx::VmarFlags::SPECIFIC,
448 SelectedAddress::FixedOverwrite(_) => ZX_VM_SPECIFIC_OVERWRITE,
449 };
450
451 if populate {
452 let op = if flags.contains(MappingFlags::WRITE) {
453 zx::VmoOp::COMMIT
455 } else {
456 zx::VmoOp::PREFETCH
459 };
460 fuchsia_trace::duration!(CATEGORY_STARNIX_MM, "MmapCommitPages");
461 let _ = memory.op_range(op, memory_offset, length as u64);
462 }
464
465 let vmar_maybe_map_range = if populate && !vmar_extra_flags.contains(ZX_VM_SPECIFIC_OVERWRITE) {
466 zx::VmarFlags::MAP_RANGE
467 } else {
468 zx::VmarFlags::empty()
469 };
470 let vmar_flags = flags.access_flags().to_vmar_flags()
471 | zx::VmarFlags::ALLOW_FAULTS
472 | vmar_extra_flags
473 | vmar_maybe_map_range;
474
475 let map_result = memory.map_in_vmar(vmar, vmar_offset.ptr(), memory_offset, length, vmar_flags);
476 let mapped_addr = map_result.map_err(MemoryManager::get_errno_for_map_err)?;
477
478 let expected_addr = addr.addr().ptr();
479 debug_assert_eq!(
480 mapped_addr, expected_addr,
481 "Zircon mapped to a different address than requested!"
482 );
483
484 Ok(())
485}
486
487#[derive(Clone, Copy, Debug, PartialEq, Eq)]
490enum MadviseFlagAdvice {
491 DontFork,
492 DoFork,
493 WipeOnFork,
494 KeepOnFork,
495 DontDump,
496 DoDump,
497 Mergeable,
498 Unmergeable,
499}
500
501#[derive(Clone, Copy, Debug, PartialEq, Eq)]
504enum MadviseReadOnlyAdvice {
505 Normal,
506 Random,
507 Sequential,
508 DontNeed,
509 DontNeedLocked,
510 WillNeed,
511 Cold,
512 PageOut,
513 PopulateRead,
514 Free,
515 Remove,
516 HwPoison,
517 SoftOffline,
518 HugePage,
519 Collapse,
520 NoHugePage,
521 Unknown(u32),
522}
523
524#[derive(Clone, Copy, Debug, PartialEq, Eq)]
525enum MadviseAdvice {
526 UpdateFlags(MadviseFlagAdvice),
527 ReadOnly(MadviseReadOnlyAdvice),
528}
529
530impl MadviseAdvice {
531 fn from_raw(advice: u32) -> Self {
532 match advice {
533 MADV_DONTFORK => Self::UpdateFlags(MadviseFlagAdvice::DontFork),
534 MADV_DOFORK => Self::UpdateFlags(MadviseFlagAdvice::DoFork),
535 MADV_WIPEONFORK => Self::UpdateFlags(MadviseFlagAdvice::WipeOnFork),
536 MADV_KEEPONFORK => Self::UpdateFlags(MadviseFlagAdvice::KeepOnFork),
537 MADV_DONTDUMP => Self::UpdateFlags(MadviseFlagAdvice::DontDump),
538 MADV_DODUMP => Self::UpdateFlags(MadviseFlagAdvice::DoDump),
539 MADV_MERGEABLE => Self::UpdateFlags(MadviseFlagAdvice::Mergeable),
540 MADV_UNMERGEABLE => Self::UpdateFlags(MadviseFlagAdvice::Unmergeable),
541 MADV_NORMAL => Self::ReadOnly(MadviseReadOnlyAdvice::Normal),
542 MADV_RANDOM => Self::ReadOnly(MadviseReadOnlyAdvice::Random),
543 MADV_SEQUENTIAL => Self::ReadOnly(MadviseReadOnlyAdvice::Sequential),
544 MADV_DONTNEED => Self::ReadOnly(MadviseReadOnlyAdvice::DontNeed),
545 MADV_DONTNEED_LOCKED => Self::ReadOnly(MadviseReadOnlyAdvice::DontNeedLocked),
546 MADV_WILLNEED => Self::ReadOnly(MadviseReadOnlyAdvice::WillNeed),
547 MADV_COLD => Self::ReadOnly(MadviseReadOnlyAdvice::Cold),
548 MADV_PAGEOUT => Self::ReadOnly(MadviseReadOnlyAdvice::PageOut),
549 MADV_POPULATE_READ => Self::ReadOnly(MadviseReadOnlyAdvice::PopulateRead),
550 MADV_FREE => Self::ReadOnly(MadviseReadOnlyAdvice::Free),
551 MADV_REMOVE => Self::ReadOnly(MadviseReadOnlyAdvice::Remove),
552 MADV_HWPOISON => Self::ReadOnly(MadviseReadOnlyAdvice::HwPoison),
553 MADV_SOFT_OFFLINE => Self::ReadOnly(MadviseReadOnlyAdvice::SoftOffline),
554 MADV_HUGEPAGE => Self::ReadOnly(MadviseReadOnlyAdvice::HugePage),
555 MADV_COLLAPSE => Self::ReadOnly(MadviseReadOnlyAdvice::Collapse),
556 MADV_NOHUGEPAGE => Self::ReadOnly(MadviseReadOnlyAdvice::NoHugePage),
557 other => Self::ReadOnly(MadviseReadOnlyAdvice::Unknown(other)),
558 }
559 }
560}
561
562fn file_lacking_executable_memory(mapping: &Mapping) -> Option<(&FileHandle, &Arc<MemoryObject>)> {
568 let file = mapping.name().as_file()?;
569 let memory = mapping.get_backing_internal().as_memory()?.memory();
570 if memory.get_rights().contains(zx::Rights::EXECUTE) || !mapping.may_exec() {
571 return None;
572 }
573 Some((file.file(), memory))
574}
575
576#[derive(Default)]
583struct ExecutableMemoryProbes(Vec<(FileHandle, bool)>);
584
585impl ExecutableMemoryProbes {
586 fn provides_executable_memory(&self, file: &FileHandle) -> Option<bool> {
588 self.0.iter().find(|(probed, _)| Arc::ptr_eq(probed, file)).map(|(_, provides)| *provides)
589 }
590
591 fn unprobed_files(
594 &self,
595 state: &MemoryManagerState,
596 range: Range<UserAddress>,
597 ) -> Vec<FileHandle> {
598 let mut files: Vec<FileHandle> = state
599 .mappings
600 .range(range)
601 .filter_map(|(_, mapping)| file_lacking_executable_memory(mapping))
602 .map(|(file, _)| file.clone())
603 .collect();
604 files.retain(|file| self.provides_executable_memory(file).is_none());
605 files.dedup_by(|a, b| Arc::ptr_eq(a, b));
606 files
607 }
608
609 fn probe(&mut self, current_task: &CurrentTask, files: Vec<FileHandle>) {
611 for file in files {
612 let provides_executable_memory = file.ops().can_map_executable()
613 && file
614 .get_memory(
615 current_task,
616 None,
617 ProtectionFlags::READ | ProtectionFlags::EXEC,
618 )
619 .is_ok();
620 self.0.push((file, provides_executable_memory));
621 }
622 }
623}
624
625fn executable_memory_handle(memory: &MemoryObject) -> Result<MemoryObject, zx::Status> {
628 memory
629 .duplicate_handle(zx::Rights::SAME_RIGHTS)
630 .and_then(|memory| memory.replace_as_executable(&VMEX_RESOURCE))
631}
632
633fn executable_memory_for_mapping(
641 mapping: &Mapping,
642 prot_flags: ProtectionFlags,
643 probes: &ExecutableMemoryProbes,
644) -> Result<Option<Arc<MemoryObject>>, Errno> {
645 let Some((file, memory)) = file_lacking_executable_memory(mapping) else {
646 return Ok(None);
647 };
648 if prot_flags.contains(ProtectionFlags::WRITE)
650 && !memory.get_rights().contains(zx::Rights::WRITE)
651 {
652 return error!(EACCES);
653 }
654 if probes.provides_executable_memory(file) != Some(true) {
656 return error!(EACCES);
657 }
658 let memory = executable_memory_handle(memory).map_err(|status| match status {
661 zx::Status::NO_MEMORY => errno!(ENOMEM),
662 _ => errno!(EACCES),
665 })?;
666 Ok(Some(Arc::new(memory)))
667}
668
669fn protect_mapping_range(
675 mapping_context: &MappingContext,
676 range: &Range<UserAddress>,
677 mapping: &mut Mapping,
678 prot_flags: ProtectionFlags,
679 probes: &ExecutableMemoryProbes,
680) -> Result<bool, Errno> {
681 if prot_flags.contains(ProtectionFlags::WRITE)
684 && let MappingBacking::Memory(backing) = mapping.get_backing_internal()
685 && !backing.memory().get_rights().contains(zx::Rights::WRITE)
686 {
687 return error!(EACCES);
688 }
689
690 mapping.set_flags(mapping.flags().with_access_flags(prot_flags));
691
692 if prot_flags.contains(ProtectionFlags::EXEC) {
693 if let Some(memory) = executable_memory_for_mapping(mapping, prot_flags, probes)? {
694 mapping_context
699 .replace_mapping_memory(range, mapping, memory)
700 .map_err(|e| if e == EPERM { errno!(EACCES) } else { e })?;
701 return Ok(true);
702 }
703 }
704
705 mapping_context.protect_vmar_range(
706 range.start,
707 range.end - range.start,
708 mapping.vmar_flags().access_flags(),
709 )?;
710 Ok(false)
711}
712
713fn can_become_executable(mapping: &Mapping, probes: &ExecutableMemoryProbes) -> bool {
716 if mapping.can_exec() {
717 return true;
718 }
719 if !mapping.may_exec() {
720 return false;
721 }
722 match mapping.get_backing_internal() {
723 MappingBacking::PrivateAnonymous => true,
724 MappingBacking::Memory(backing) => {
725 backing.memory().get_rights().contains(zx::Rights::EXECUTE)
726 || file_lacking_executable_memory(mapping)
727 .is_some_and(|(file, _)| probes.provides_executable_memory(file) == Some(true))
728 }
729 }
730}
731
732fn effective_prot_flags(
738 mapping: &Mapping,
739 prot_flags: ProtectionFlags,
740 personality: PersonalityFlags,
741 probes: &ExecutableMemoryProbes,
742) -> ProtectionFlags {
743 if prot_flags.contains(ProtectionFlags::READ)
744 && personality.contains(PersonalityFlags::READ_IMPLIES_EXEC)
745 && can_become_executable(mapping, probes)
746 {
747 prot_flags | ProtectionFlags::EXEC
748 } else {
749 prot_flags
750 }
751}
752
753#[derive(Default)]
756struct ForkedMemory {
757 clones: SmallVec<[(zx::Rights, Arc<MemoryObject>); 1]>,
761}
762
763impl ForkedMemory {
764 fn get_or_clone(
766 &mut self,
767 memory: &Arc<MemoryObject>,
768 rights: zx::Rights,
769 options: MappingOptions,
770 ) -> Result<Arc<MemoryObject>, Errno> {
771 if let Some((_, clone)) = self.clones.iter().find(|(r, _)| *r == rights) {
772 return Ok(clone.clone());
773 }
774 let snapshot = self.clones.iter().find(|(r, clone)| {
778 r.symmetric_difference(rights) == zx::Rights::EXECUTE && !Arc::ptr_eq(clone, memory)
779 });
780 let clone = match snapshot {
781 Some((_, snapshot)) if rights.contains(zx::Rights::EXECUTE) => {
782 Arc::new(executable_memory_handle(snapshot).map_err(|_| errno!(ENOMEM))?)
783 }
784 Some((_, snapshot)) => Arc::new(
785 snapshot
786 .duplicate_handle(snapshot.get_rights() - zx::Rights::EXECUTE)
787 .map_err(|_| errno!(ENOMEM))?,
788 ),
789 None => memory.clone_memory(rights, options)?,
790 };
791 self.clones.push((rights, clone.clone()));
792 Ok(clone)
793 }
794}
795
796impl MemoryManagerState {
797 fn get_occupied_address_ranges<'a>(
804 &'a self,
805 subrange: &'a Range<UserAddress>,
806 ) -> impl Iterator<Item = Range<UserAddress>> + 'a {
807 let query_range = subrange.start
808 ..(subrange
809 .end
810 .saturating_add(*PAGE_SIZE as usize * GUARD_PAGE_COUNT_FOR_GROWSDOWN_MAPPINGS));
811 self.mappings.range(query_range).filter_map(|(range, mapping)| {
812 let occupied_range = mapping.inflate_to_include_guard_pages(range);
813 if occupied_range.start < subrange.end && subrange.start < occupied_range.end {
814 Some(occupied_range)
815 } else {
816 None
817 }
818 })
819 }
820
821 fn count_possible_placements(
822 &self,
823 length: usize,
824 subrange: &Range<UserAddress>,
825 ) -> Option<usize> {
826 let mut occupied_ranges = self.get_occupied_address_ranges(subrange);
827 let mut possible_placements = 0;
828 let mut first_fill_end = subrange.start.checked_add(length)?;
831 while first_fill_end <= subrange.end {
832 let Some(mapping) = occupied_ranges.next() else {
833 possible_placements += (subrange.end - first_fill_end) / (*PAGE_SIZE as usize) + 1;
834 break;
835 };
836 if mapping.start >= first_fill_end {
837 possible_placements += (mapping.start - first_fill_end) / (*PAGE_SIZE as usize) + 1;
838 }
839 first_fill_end = mapping.end.checked_add(length)?;
840 }
841 Some(possible_placements)
842 }
843
844 fn pick_placement(
845 &self,
846 length: usize,
847 mut chosen_placement_idx: usize,
848 subrange: &Range<UserAddress>,
849 ) -> Option<UserAddress> {
850 let mut candidate =
851 Range { start: subrange.start, end: subrange.start.checked_add(length)? };
852 let mut occupied_ranges = self.get_occupied_address_ranges(subrange);
853 loop {
854 let Some(mapping) = occupied_ranges.next() else {
855 let res =
857 candidate.start.checked_add(chosen_placement_idx * *PAGE_SIZE as usize)?;
858 debug_assert!(res.checked_add(length)? <= subrange.end);
859 return Some(res);
860 };
861 if mapping.start < candidate.end {
862 candidate = Range { start: mapping.end, end: mapping.end.checked_add(length)? };
864 continue;
865 }
866 let unused_space =
867 (mapping.start.ptr() - candidate.end.ptr()) / (*PAGE_SIZE as usize) + 1;
868 if unused_space > chosen_placement_idx {
869 let res =
871 candidate.start.checked_add(chosen_placement_idx * *PAGE_SIZE as usize)?;
872 return Some(res);
873 }
874
875 chosen_placement_idx -= unused_space;
877 candidate = Range { start: mapping.end, end: mapping.end.checked_add(length)? };
878 }
879 }
880
881 fn find_random_unused_range(
882 &self,
883 length: usize,
884 subrange: &Range<UserAddress>,
885 ) -> Option<UserAddress> {
886 let possible_placements = self.count_possible_placements(length, subrange)?;
887 if possible_placements == 0 {
888 return None;
889 }
890 let chosen_placement_idx = rand::random_range(0..possible_placements);
891 self.pick_placement(length, chosen_placement_idx, subrange)
892 }
893
894 pub fn find_next_unused_range(&self, length: usize) -> Option<UserAddress> {
897 let gap_size = length as u64;
898 let mut upper_bound = self.mmap_top;
899
900 loop {
901 let gap_end = self.mappings.find_gap_end(gap_size, &upper_bound);
902 let candidate = gap_end.checked_sub(length)?;
903
904 let Some((occupied_range, mapping)) = self.mappings.get(gap_end) else {
906 return Some(candidate);
907 };
908 let occupied_range = mapping.inflate_to_include_guard_pages(occupied_range);
909 if occupied_range.start >= gap_end {
911 return Some(candidate);
912 }
913 upper_bound = occupied_range.start;
915 }
916 }
917
918 fn is_hint_acceptable(&self, hint_addr: UserAddress, length: usize) -> bool {
920 let Some(hint_end) = hint_addr.checked_add(length) else {
921 return false;
922 };
923 if !RESTRICTED_ASPACE_RANGE.contains(&hint_addr.ptr())
924 || !RESTRICTED_ASPACE_RANGE.contains(&hint_end.ptr())
925 {
926 return false;
927 };
928 self.get_occupied_address_ranges(&(hint_addr..hint_end)).next().is_none()
929 }
930
931 fn select_address(
932 &self,
933 addr: DesiredAddress,
934 length: usize,
935 flags: MappingFlags,
936 ) -> Result<SelectedAddress, Errno> {
937 let adjusted_length = round_up_to_system_page_size(length).or_else(|_| error!(ENOMEM))?;
938
939 let find_address = || -> Result<SelectedAddress, Errno> {
940 let new_addr = if flags.contains(MappingFlags::LOWER_32BIT) {
941 self.find_random_unused_range(
944 adjusted_length,
945 &(UserAddress::from_ptr(RESTRICTED_ASPACE_BASE)
946 ..UserAddress::from_ptr(0x80000000)),
947 )
948 .ok_or_else(|| errno!(ENOMEM))?
949 } else {
950 self.find_next_unused_range(adjusted_length).ok_or_else(|| errno!(ENOMEM))?
951 };
952
953 Ok(SelectedAddress::Fixed(new_addr))
954 };
955
956 Ok(match addr {
957 DesiredAddress::Any => find_address()?,
958 DesiredAddress::Hint(hint_addr) => {
959 let hint_addr =
961 UserAddress::from_ptr(hint_addr.ptr() - hint_addr.ptr() % *PAGE_SIZE as usize);
962 if self.is_hint_acceptable(hint_addr, adjusted_length) {
963 SelectedAddress::Fixed(hint_addr)
964 } else {
965 find_address()?
966 }
967 }
968 DesiredAddress::Fixed(addr) => SelectedAddress::Fixed(addr),
969 DesiredAddress::FixedOverwrite(addr) => SelectedAddress::FixedOverwrite(addr),
970 })
971 }
972
973 fn validate_addr(&self, addr: DesiredAddress, length: usize) -> Result<(), Errno> {
974 if length > RESTRICTED_ASPACE_SIZE {
975 return error!(ENOMEM);
976 }
977 match addr {
978 DesiredAddress::Fixed(a) | DesiredAddress::FixedOverwrite(a) => {
979 let end = a.checked_add(length).ok_or_else(|| errno!(ENOMEM))?;
980 if end > UserAddress::from_ptr(RESTRICTED_ASPACE_HIGHEST_ADDRESS as usize) {
981 return error!(ENOMEM);
982 }
983 if self.check_has_unauthorized_splits(a, length) {
984 return error!(ENOMEM);
985 }
986 }
987 _ => {}
988 }
989 Ok(())
990 }
991
992 fn add_memory_mapping(
997 &mut self,
998 mm: &MemoryManager,
999 addr: DesiredAddress,
1000 memory: Arc<MemoryObject>,
1001 memory_offset: u64,
1002 length: usize,
1003 flags: MappingFlags,
1004 populate: bool,
1005 cow_modified: bool,
1006 name: MappingName,
1007 mapping_mode: MappingMode,
1008 released_mappings: &mut ReleasedMappings,
1009 ) -> Result<UserAddress, Errno> {
1010 self.validate_addr(addr, length)?;
1011
1012 let selected_address = self.select_address(addr, length, flags)?;
1013 let mapped_addr = selected_address.addr();
1014 if !mapped_addr.is_aligned(*PAGE_SIZE) || memory_offset % *PAGE_SIZE != 0 {
1015 return error!(EINVAL);
1016 }
1017 let mut backing = MappingBackingMemory::new(mapped_addr, memory, memory_offset);
1018 if cow_modified {
1019 backing.set_cow_modified();
1020 }
1021 let mapping = Mapping::with_name(
1022 MappingBacking::Memory(Box::new(backing)),
1023 flags,
1024 name,
1025 mapping_mode,
1026 );
1027 if mapping_mode == MappingMode::Eager {
1028 mm.mapping_context.map_in_user_vmar(
1032 selected_address,
1033 Self::mapping_memory(&mm.mapping_context, &mapping),
1034 memory_offset,
1035 length,
1036 mapping.vmar_flags(),
1037 populate,
1038 )?;
1039 }
1040
1041 let end = (mapped_addr + length)?.round_up(*PAGE_SIZE)?;
1042
1043 if let DesiredAddress::FixedOverwrite(addr) = addr {
1044 assert_eq!(addr, mapped_addr);
1045 self.update_after_unmap(mm, addr, end - addr, released_mappings);
1046 }
1047
1048 released_mappings.extend(self.mappings.insert(mapped_addr..end, mapping));
1049
1050 Ok(mapped_addr)
1051 }
1052
1053 fn map_private_anonymous(
1054 &mut self,
1055 mm: &MemoryManager,
1056 addr: DesiredAddress,
1057 length: usize,
1058 prot_flags: ProtectionFlags,
1059 options: MappingOptions,
1060 populate: bool,
1061 name: MappingName,
1062 released_mappings: &mut ReleasedMappings,
1063 ) -> Result<UserAddress, Errno> {
1064 self.validate_addr(addr, length)?;
1065
1066 let flags = MappingFlags::from_access_flags_and_options(prot_flags, options);
1067 let selected_addr = self.select_address(addr, length, flags)?;
1068 let mapped_addr = selected_addr.addr();
1069 let backing_memory_offset = selected_addr.addr().ptr();
1070
1071 mm.mapping_context.map_in_user_vmar(
1072 selected_addr,
1073 &mm.mapping_context.private_anonymous.backing,
1074 backing_memory_offset as u64,
1075 length,
1076 flags,
1077 populate,
1078 )?;
1079
1080 let end = (mapped_addr + length)?.round_up(*PAGE_SIZE)?;
1081 if let DesiredAddress::FixedOverwrite(addr) = addr {
1082 assert_eq!(addr, mapped_addr);
1083 self.update_after_unmap(mm, addr, end - addr, released_mappings);
1084 }
1085
1086 let mapping = Mapping::new_private_anonymous(flags, name, MappingMode::Eager);
1087 released_mappings.extend(self.mappings.insert(mapped_addr..end, mapping));
1088
1089 Ok(mapped_addr)
1090 }
1091
1092 fn map_anonymous(
1093 &mut self,
1094 mm: &MemoryManager,
1095 addr: DesiredAddress,
1096 length: usize,
1097 prot_flags: ProtectionFlags,
1098 options: MappingOptions,
1099 name: MappingName,
1100 released_mappings: &mut ReleasedMappings,
1101 ) -> Result<UserAddress, Errno> {
1102 if !options.contains(MappingOptions::SHARED) {
1103 return self.map_private_anonymous(
1104 mm,
1105 addr,
1106 length,
1107 prot_flags,
1108 options,
1109 options.contains(MappingOptions::POPULATE),
1110 name,
1111 released_mappings,
1112 );
1113 }
1114 let memory = create_anonymous_mapping_memory(length as u64)?;
1115 let flags = MappingFlags::from_access_flags_and_options(prot_flags, options);
1116 self.add_memory_mapping(
1117 mm,
1118 addr,
1119 memory,
1120 0,
1121 length,
1122 flags,
1123 options.contains(MappingOptions::POPULATE),
1124 false,
1125 name,
1126 MappingMode::Eager,
1127 released_mappings,
1128 )
1129 }
1130
1131 fn mapping_needs_vmar_update(mapping: &Mapping, access: MappingAccess) -> bool {
1134 mapping.mapping_mode() == MappingMode::Lazy
1135 || (access == MappingAccess::ForWriting
1136 && mapping.can_write()
1137 && mapping.is_unmodified_private_file())
1138 }
1139
1140 fn any_ranges_need_vmar_update<I>(&self, ranges: I, access: MappingAccess) -> bool
1146 where
1147 I: IntoIterator<Item = (UserAddress, Option<usize>)>,
1148 {
1149 for (addr, length) in ranges {
1150 match length {
1151 None => {
1152 if let Some((_, mapping)) = self.mappings.get(addr) {
1153 if Self::mapping_needs_vmar_update(mapping, access) {
1154 return true;
1155 }
1156 }
1157 }
1158 Some(len) => {
1159 assert!(len > 0);
1160 let end = addr.checked_add(len).expect("address overflowed after validation");
1161 if self
1162 .mappings
1163 .range(addr..end)
1164 .any(|(_, mapping)| Self::mapping_needs_vmar_update(mapping, access))
1165 {
1166 return true;
1167 }
1168 }
1169 }
1170 }
1171 false
1172 }
1173
1174 fn ensure_range_mapped_in_user_vmar(
1179 &mut self,
1180 addr: UserAddress,
1181 length: Option<usize>,
1182 context: &MappingContext,
1183 ) -> Result<bool, Errno> {
1184 self.ensure_range_mapped_in_user_vmar_for_access(
1185 addr,
1186 length,
1187 MappingAccess::ForReading,
1188 context,
1189 )
1190 }
1191
1192 fn ensure_range_mapped_in_user_vmar_for_access(
1198 &mut self,
1199 addr: UserAddress,
1200 length: Option<usize>,
1201 access: MappingAccess,
1202 context: &MappingContext,
1203 ) -> Result<bool, Errno> {
1204 self.ensure_ranges_mapped_in_user_vmar_for_access(
1205 std::iter::once((addr, length)),
1206 access,
1207 context,
1208 )
1209 }
1210
1211 fn ensure_ranges_mapped_in_user_vmar_for_access<I>(
1219 &mut self,
1220 ranges: I,
1221 access: MappingAccess,
1222 context: &MappingContext,
1223 ) -> Result<bool, Errno>
1224 where
1225 I: IntoIterator<Item = (UserAddress, Option<usize>)>,
1226 {
1227 const MAX_BATCH_RANGES: usize = 64;
1232 const MAX_BATCH_BEFORE_FAULT: usize = 16;
1233 const BATCH_BACKWARD_WINDOW: usize = 4 * 1024 * 1024;
1234 const BATCH_FORWARD_WINDOW: usize = 8 * 1024 * 1024;
1235
1236 let mut ranges_to_update =
1237 SmallVec::<[std::ops::Range<UserAddress>; MAX_BATCH_RANGES]>::new();
1238 let mut cow_addrs = SmallVec::<[UserAddress; 1]>::new();
1241 for (addr, length) in ranges {
1242 match length {
1243 None => {
1250 if let Some((fault_range, mapping)) = self.mappings.get(addr) {
1251 if access == MappingAccess::ForWriting
1252 && mapping.can_write()
1253 && mapping.is_unmodified_private_file()
1254 && !cow_addrs.contains(&fault_range.start)
1255 {
1256 cow_addrs.push(fault_range.start);
1257 }
1258 if mapping.mapping_mode() == MappingMode::Lazy {
1259 let target_access = mapping.flags().access_flags();
1260 if ranges_to_update.is_empty() && !target_access.is_empty() {
1261 let fault_range = fault_range.clone();
1262 let window_start =
1263 fault_range.start.saturating_sub(BATCH_BACKWARD_WINDOW);
1264 let window_end = fault_range
1265 .end
1266 .checked_add(BATCH_FORWARD_WINDOW)
1267 .unwrap_or_else(|| context.max_address());
1268 for (range, m) in self.mappings.range(window_start..window_end) {
1269 if m.mapping_mode() != MappingMode::Lazy
1270 || m.flags().access_flags().is_empty()
1271 {
1272 continue;
1273 }
1274 if range.end <= fault_range.start {
1275 if ranges_to_update.len() == MAX_BATCH_BEFORE_FAULT {
1276 ranges_to_update.remove(0);
1277 }
1278 ranges_to_update.push(range.clone());
1279 } else if ranges_to_update.len() < MAX_BATCH_RANGES {
1280 ranges_to_update.push(range.clone());
1281 } else {
1282 break;
1283 }
1284 }
1285 } else if !ranges_to_update.contains(fault_range) {
1286 ranges_to_update.push(fault_range.clone());
1287 }
1288 }
1289 }
1290 }
1291 Some(len) => {
1295 assert!(len > 0);
1296 let end = addr.checked_add(len).expect("address overflowed after validation");
1297 for (range, mapping) in self.mappings.range(addr..end) {
1298 if access == MappingAccess::ForWriting
1299 && mapping.can_write()
1300 && mapping.is_unmodified_private_file()
1301 && !cow_addrs.contains(&range.start)
1302 {
1303 cow_addrs.push(range.start);
1304 }
1305 if mapping.mapping_mode() == MappingMode::Lazy
1306 && !ranges_to_update.contains(range)
1307 {
1308 ranges_to_update.push(range.clone());
1309 }
1310 }
1311 }
1312 }
1313 }
1314
1315 if ranges_to_update.is_empty() && cow_addrs.is_empty() {
1316 return Ok(false);
1317 }
1318
1319 for start_addr in cow_addrs {
1320 self.set_private_file_cow_modified(context, start_addr)?;
1321 }
1322
1323 if ranges_to_update.is_empty() {
1324 return Ok(true);
1325 }
1326
1327 ranges_to_update.sort_unstable_by_key(|r| r.start);
1328
1329 let flush_anon = |mappings: &mut Mappings,
1330 anon: (UserAddress, UserAddress, MappingFlags, Range<usize>),
1331 ranges_to_update: &[Range<UserAddress>]|
1332 -> Result<(), Errno> {
1333 let (anon_start, anon_end, anon_flags, indices) = anon;
1334 context.map_in_user_vmar(
1335 SelectedAddress::FixedOverwrite(anon_start),
1336 &context.private_anonymous.backing,
1337 anon_start.ptr() as u64,
1338 anon_end - anon_start,
1339 anon_flags,
1340 false,
1341 )?;
1342 for r in &ranges_to_update[indices] {
1343 let updated = mappings
1344 .update_exact(r, |m| {
1345 m.set_mapping_mode(MappingMode::Eager);
1346 Ok::<(), Errno>(())
1347 })
1348 .expect("infallible update");
1349 assert!(updated, "Expected to update exactly one mapping");
1350 }
1351 Ok(())
1352 };
1353
1354 let mut pending_anon: Option<(UserAddress, UserAddress, MappingFlags, Range<usize>)> = None;
1355 for (idx, range) in ranges_to_update.iter().enumerate() {
1356 let Some((_, mapping)) = self.mappings.get(range.start) else {
1357 continue;
1358 };
1359 if mapping.mapping_mode() != MappingMode::Lazy {
1360 continue;
1361 }
1362 let flags = mapping.vmar_flags();
1363 if matches!(mapping.get_backing_internal(), MappingBacking::PrivateAnonymous) {
1364 match &mut pending_anon {
1365 Some((_, anon_end, anon_flags, indices))
1366 if *anon_end == range.start
1367 && anon_flags.access_flags() == flags.access_flags() =>
1368 {
1369 *anon_end = range.end;
1370 indices.end = idx + 1;
1371 continue;
1372 }
1373 None => {
1374 pending_anon = Some((range.start, range.end, flags, idx..idx + 1));
1375 continue;
1376 }
1377 Some(_) => {}
1378 }
1379 }
1380
1381 if let Some(prev_anon) = pending_anon.take() {
1382 flush_anon(&mut self.mappings, prev_anon, &ranges_to_update)?;
1383 }
1384
1385 let Some((range, mapping)) = self.mappings.get(range.start) else {
1386 continue;
1387 };
1388 if mapping.mapping_mode() != MappingMode::Lazy {
1389 continue;
1390 }
1391 let range = range.clone();
1392 match mapping.get_backing_internal() {
1393 MappingBacking::PrivateAnonymous => {
1394 pending_anon = Some((range.start, range.end, flags, idx..idx + 1));
1395 }
1396 MappingBacking::Memory(backing) => {
1397 let addr = SelectedAddress::FixedOverwrite(range.start);
1398 let backing_memory_offset = backing.address_to_offset(addr.addr());
1399 let mapping_length = range.end - range.start;
1400 context.map_in_user_vmar(
1401 addr,
1402 backing.memory(),
1403 backing_memory_offset,
1404 mapping_length,
1405 mapping.vmar_flags(),
1406 false,
1407 )?;
1408 let updated = self
1409 .mappings
1410 .update_exact(&range, |m| {
1411 m.set_mapping_mode(MappingMode::Eager);
1412 Ok::<(), Errno>(())
1413 })
1414 .expect("infallible update");
1415 assert!(updated, "Expected to update exactly one mapping");
1416 }
1417 }
1418 }
1419
1420 if let Some(prev_anon) = pending_anon.take() {
1421 flush_anon(&mut self.mappings, prev_anon, &ranges_to_update)?;
1422 }
1423
1424 Ok(true)
1425 }
1426
1427 fn remap(
1428 &mut self,
1429 _current_task: &CurrentTask,
1430 mm: &MemoryManager,
1431 old_addr: UserAddress,
1432 old_length: usize,
1433 new_length: usize,
1434 flags: MremapFlags,
1435 new_addr: UserAddress,
1436 released_mappings: &mut ReleasedMappings,
1437 ) -> Result<UserAddress, Errno> {
1438 if flags.contains(MremapFlags::FIXED) && !flags.contains(MremapFlags::MAYMOVE) {
1440 return error!(EINVAL);
1441 }
1442
1443 if flags.contains(MremapFlags::DONTUNMAP)
1446 && (!flags.contains(MremapFlags::MAYMOVE) || old_length != new_length)
1447 {
1448 return error!(EINVAL);
1449 }
1450
1451 if new_length == 0 {
1452 return error!(EINVAL);
1453 }
1454
1455 if !old_addr.is_aligned(*PAGE_SIZE) {
1457 return error!(EINVAL);
1458 }
1459
1460 let old_length = round_up_to_system_page_size(old_length)?;
1461 let new_length = round_up_to_system_page_size(new_length)?;
1462
1463 if self.mappings.get(old_addr).is_none() {
1465 return error!(EFAULT);
1466 }
1467
1468 if !flags.contains(MremapFlags::MAYMOVE) && old_length == 0 {
1470 return error!(ENOMEM);
1471 }
1472
1473 if self.check_has_unauthorized_splits(old_addr, old_length) {
1474 return error!(EINVAL);
1475 }
1476
1477 if self.check_has_unauthorized_splits(new_addr, new_length) {
1478 return error!(EINVAL);
1479 }
1480
1481 if !flags.contains(MremapFlags::DONTUNMAP)
1482 && !flags.contains(MremapFlags::FIXED)
1483 && old_length != 0
1484 {
1485 if let Some(new_addr) =
1488 self.try_remap_in_place(mm, old_addr, old_length, new_length, released_mappings)?
1489 {
1490 return Ok(new_addr);
1491 }
1492 }
1493
1494 if flags.contains(MremapFlags::MAYMOVE) {
1496 let dst_address =
1497 if flags.contains(MremapFlags::FIXED) { Some(new_addr) } else { None };
1498 self.remap_move(
1499 mm,
1500 old_addr,
1501 old_length,
1502 dst_address,
1503 new_length,
1504 flags.contains(MremapFlags::DONTUNMAP),
1505 released_mappings,
1506 )
1507 } else {
1508 error!(ENOMEM)
1509 }
1510 }
1511
1512 fn try_remap_in_place(
1515 &mut self,
1516 mm: &MemoryManager,
1517 old_addr: UserAddress,
1518 old_length: usize,
1519 new_length: usize,
1520 released_mappings: &mut ReleasedMappings,
1521 ) -> Result<Option<UserAddress>, Errno> {
1522 let old_range = old_addr..old_addr.checked_add(old_length).ok_or_else(|| errno!(EINVAL))?;
1523 let new_range_in_place =
1524 old_addr..old_addr.checked_add(new_length).ok_or_else(|| errno!(EINVAL))?;
1525
1526 if new_length <= old_length {
1527 if new_length != old_length {
1530 self.unmap(mm, new_range_in_place.end, old_length - new_length, released_mappings)?;
1531 }
1532 return Ok(Some(old_addr));
1533 }
1534
1535 if self.mappings.range(old_range.end..new_range_in_place.end).next().is_some() {
1536 return Ok(None);
1538 }
1539
1540 let (original_range, mapping) =
1542 self.mappings.get(old_addr).ok_or_else(|| errno!(EFAULT))?;
1543
1544 if old_range.end > original_range.end {
1545 return error!(EFAULT);
1546 }
1547
1548 if mapping.flags().contains(MappingFlags::DONT_EXPAND) {
1549 return error!(EFAULT);
1550 }
1551
1552 let original_range = original_range.clone();
1553 let original_mapping = mapping.clone();
1554
1555 let final_length = (original_range.end - original_range.start) + (new_length - old_length);
1557
1558 match self.get_mapping_backing(&original_mapping) {
1559 MappingBacking::Memory(backing) => {
1560 Ok(Some(self.add_memory_mapping(
1562 mm,
1563 DesiredAddress::FixedOverwrite(original_range.start),
1564 backing.memory().clone(),
1565 backing.address_to_offset(original_range.start),
1566 final_length,
1567 original_mapping.flags(),
1568 false,
1569 original_mapping.has_cow_modifications(),
1570 original_mapping.name().to_owned(),
1571 original_mapping.mapping_mode(),
1572 released_mappings,
1573 )?))
1574 }
1575 MappingBacking::PrivateAnonymous => {
1576 let growth_start = original_range.end;
1577 let growth_length = new_length - old_length;
1578 let final_end = (original_range.start + final_length)?;
1579 mm.mapping_context.map_in_user_vmar(
1581 SelectedAddress::FixedOverwrite(growth_start),
1582 &mm.mapping_context.private_anonymous.backing,
1583 growth_start.ptr() as u64,
1584 growth_length,
1585 original_mapping.flags(),
1586 false,
1587 )?;
1588 released_mappings.extend(
1590 self.mappings.insert(original_range.start..final_end, original_mapping.clone()),
1591 );
1592 Ok(Some(original_range.start))
1593 }
1594 }
1595 }
1596
1597 fn remap_move(
1599 &mut self,
1600 mm: &MemoryManager,
1601 src_addr: UserAddress,
1602 src_length: usize,
1603 dst_addr: Option<UserAddress>,
1604 dst_length: usize,
1605 keep_source: bool,
1606 released_mappings: &mut ReleasedMappings,
1607 ) -> Result<UserAddress, Errno> {
1608 let src_range = src_addr..src_addr.checked_add(src_length).ok_or_else(|| errno!(EINVAL))?;
1609 let (original_range, src_mapping) =
1610 self.mappings.get(src_addr).ok_or_else(|| errno!(EFAULT))?;
1611 let original_range = original_range.clone();
1612 let src_mapping = src_mapping.clone();
1613
1614 if src_length == 0 && !src_mapping.flags().contains(MappingFlags::SHARED) {
1615 return error!(EINVAL);
1618 }
1619
1620 if src_length != 0 && src_length > dst_length {
1624 self.unmap(mm, (src_addr + dst_length)?, src_length - dst_length, released_mappings)?;
1625 }
1626
1627 let dst_addr_for_map = match dst_addr {
1628 None => DesiredAddress::Any,
1629 Some(dst_addr) => {
1630 let dst_range =
1632 dst_addr..(dst_addr.checked_add(dst_length).ok_or_else(|| errno!(EINVAL))?);
1633 if !src_range.intersect(&dst_range).is_empty() {
1634 return error!(EINVAL);
1635 }
1636
1637 self.unmap(mm, dst_addr, dst_length, released_mappings)?;
1640
1641 DesiredAddress::Fixed(dst_addr)
1642 }
1643 };
1644
1645 if dst_length > src_length && src_mapping.flags().contains(MappingFlags::DONT_EXPAND) {
1648 return error!(EFAULT);
1649 }
1650
1651 if src_range.end > original_range.end {
1652 return error!(EFAULT);
1655 }
1656
1657 match self.get_mapping_backing(&src_mapping) {
1658 MappingBacking::PrivateAnonymous => {
1659 let dst_addr =
1660 self.select_address(dst_addr_for_map, dst_length, src_mapping.flags())?.addr();
1661 let dst_end = (dst_addr + dst_length)?;
1662
1663 let length_to_move = std::cmp::min(dst_length, src_length) as u64;
1664 let growth_start_addr = (dst_addr + length_to_move)?;
1665
1666 if dst_addr != src_addr {
1667 let src_move_end = (src_range.start + length_to_move)?;
1668 let range_to_move = src_range.start..src_move_end;
1669 mm.mapping_context.private_anonymous.move_pages(&range_to_move, dst_addr)?;
1671 }
1672
1673 let new_flags =
1675 src_mapping.flags().difference(MappingFlags::UFFD | MappingFlags::UFFD_MISSING);
1676 if src_mapping.mapping_mode() == MappingMode::Eager {
1677 mm.mapping_context.map_in_user_vmar(
1678 SelectedAddress::FixedOverwrite(dst_addr),
1679 &mm.mapping_context.private_anonymous.backing,
1680 dst_addr.ptr() as u64,
1681 dst_length,
1682 new_flags,
1683 false,
1684 )?;
1685
1686 if dst_length > src_length {
1687 let growth_length = dst_length - src_length;
1689
1690 self.map_private_anonymous(
1691 mm,
1692 DesiredAddress::FixedOverwrite(growth_start_addr),
1693 growth_length,
1694 new_flags.access_flags(),
1695 new_flags.options(),
1696 false,
1697 src_mapping.name().to_owned(),
1698 released_mappings,
1699 )?;
1700 }
1701 }
1702
1703 released_mappings.extend(self.mappings.insert(
1704 dst_addr..dst_end,
1705 Mapping::new_private_anonymous(
1706 new_flags,
1707 src_mapping.name().to_owned(),
1708 src_mapping.mapping_mode(),
1709 ),
1710 ));
1711
1712 if dst_addr != src_addr && src_length != 0 && !keep_source {
1713 self.unmap(mm, src_addr, src_length, released_mappings)?;
1714 }
1715
1716 return Ok(dst_addr);
1717 }
1718 MappingBacking::Memory(backing) => {
1719 let (dst_memory_offset, memory) =
1723 (backing.address_to_offset(src_addr), backing.memory().clone());
1724
1725 let new_address = self.add_memory_mapping(
1726 mm,
1727 dst_addr_for_map,
1728 memory,
1729 dst_memory_offset,
1730 dst_length,
1731 src_mapping.flags(),
1732 false,
1733 src_mapping.has_cow_modifications(),
1734 src_mapping.name().to_owned(),
1735 src_mapping.mapping_mode(),
1736 released_mappings,
1737 )?;
1738
1739 if src_length != 0 && !keep_source {
1740 self.unmap(mm, src_addr, src_length, released_mappings)?;
1744 }
1745
1746 return Ok(new_address);
1747 }
1748 };
1749 }
1750
1751 fn check_has_unauthorized_splits(&self, addr: UserAddress, length: usize) -> bool {
1757 let query_range = addr..addr.saturating_add(length);
1758 let mut intersection = self.mappings.range(query_range.clone());
1759
1760 let check_if_mapping_has_unauthorized_split =
1763 |mapping: Option<(&Range<UserAddress>, &Mapping)>| {
1764 mapping.is_some_and(|(mapping_range, mapping)| {
1765 mapping.flags().contains(MappingFlags::DONT_SPLIT)
1766 && (mapping_range.start < query_range.start
1767 || query_range.end < mapping_range.end)
1768 })
1769 };
1770
1771 check_if_mapping_has_unauthorized_split(intersection.next())
1775 || check_if_mapping_has_unauthorized_split(intersection.next_back())
1776 }
1777
1778 fn unmap(
1780 &mut self,
1781 mm: &MemoryManager,
1782 addr: UserAddress,
1783 length: usize,
1784 released_mappings: &mut ReleasedMappings,
1785 ) -> Result<(), Errno> {
1786 if !addr.is_aligned(*PAGE_SIZE) {
1787 return error!(EINVAL);
1788 }
1789 let length = round_up_to_system_page_size(length)?;
1790 if length == 0 {
1791 return error!(EINVAL);
1792 }
1793
1794 if self.check_has_unauthorized_splits(addr, length) {
1795 return error!(EINVAL);
1796 }
1797
1798 #[allow(
1801 clippy::undocumented_unsafe_blocks,
1802 reason = "Force documented unsafe blocks in Starnix"
1803 )]
1804 match unsafe { mm.mapping_context.user_vmar.unmap(addr.ptr(), length) } {
1805 Ok(_) => (),
1806 Err(zx::Status::NOT_FOUND) => (),
1807 Err(zx::Status::INVALID_ARGS) => return error!(EINVAL),
1808 Err(status) => {
1809 impossible_error(status);
1810 }
1811 };
1812
1813 self.update_after_unmap(mm, addr, length, released_mappings);
1814
1815 Ok(())
1816 }
1817
1818 fn update_after_unmap(
1830 &mut self,
1831 mm: &MemoryManager,
1832 addr: UserAddress,
1833 length: usize,
1834 released_mappings: &mut ReleasedMappings,
1835 ) {
1836 let end_addr = addr.checked_add(length).expect("address overflow during unmap");
1837 let unmap_range = addr..end_addr;
1838
1839 released_mappings.extend_pins(self.shadow_mappings_for_mlock.remove(unmap_range.clone()));
1841
1842 for (range, mapping) in self.mappings.range(unmap_range.clone()) {
1843 if let MappingBacking::PrivateAnonymous = self.get_mapping_backing(mapping) {
1845 let unmapped_range = &unmap_range.intersect(range);
1846
1847 if let Err(e) = mm
1848 .inflight_vmspliced_payloads
1849 .handle_unmapping(&mm.mapping_context.private_anonymous.backing, unmapped_range)
1850 {
1851 log_error!("Failed to handle vmsplice unmapping: {:?}", e);
1852 }
1853
1854 if let Err(e) = mm
1855 .mapping_context
1856 .private_anonymous
1857 .zero(unmapped_range.start, unmapped_range.end - unmapped_range.start)
1858 {
1859 log_error!("Failed to zero private anonymous memory: {:?}", e);
1860 }
1861 }
1862 }
1863 released_mappings.extend(self.mappings.remove(unmap_range));
1864 }
1865
1866 fn protection_range(
1871 &self,
1872 addr: UserAddress,
1873 end: UserAddress,
1874 prot_flags: ProtectionFlags,
1875 ) -> Result<Range<UserAddress>, Errno> {
1876 if !prot_flags.contains(ProtectionFlags::GROWSDOWN) {
1877 return Ok(addr..end);
1878 }
1879 let Some((range, mapping)) = self.mappings.get(addr) else {
1880 return error!(EINVAL);
1881 };
1882 if !mapping.flags().contains(MappingFlags::GROWSDOWN) {
1884 return error!(EINVAL);
1885 }
1886 let access_flags = mapping.flags().access_flags();
1887 let mut start = range.start;
1895 while let Some((range, mapping)) =
1896 self.mappings.get(start.saturating_sub(*PAGE_SIZE as usize))
1897 {
1898 if !mapping.flags().contains(MappingFlags::GROWSDOWN)
1899 || mapping.flags().access_flags() != access_flags
1900 {
1901 break;
1902 }
1903 start = range.start;
1904 }
1905 Ok(start..end)
1906 }
1907
1908 fn protect(
1909 &mut self,
1910 current_task: &CurrentTask,
1911 addr: UserAddress,
1912 length: usize,
1913 prot_flags: ProtectionFlags,
1914 personality: PersonalityFlags,
1915 probes: &ExecutableMemoryProbes,
1916 released_mappings: &mut ReleasedMappings,
1917 ) -> Result<(), Errno> {
1918 let page_size = *PAGE_SIZE;
1919 let end = addr.checked_add(length).ok_or_else(|| errno!(EINVAL))?.round_up(page_size)?;
1920
1921 if self.check_has_unauthorized_splits(addr, length) {
1922 return error!(EINVAL);
1923 }
1924
1925 let prot_range = self.protection_range(addr, end, prot_flags)?;
1926
1927 let mapping_context = ¤t_task.mm()?.mapping_context;
1928
1929 let mut cursor = prot_range.start;
1933 while cursor < prot_range.end {
1934 let Some((range, mapping)) = self.mappings.range(cursor..prot_range.end).next() else {
1935 return error!(ENOMEM);
1936 };
1937 if range.start > cursor {
1938 return error!(ENOMEM);
1939 }
1940
1941 let intersection = range.intersect(&prot_range);
1942 let prot_flags = effective_prot_flags(mapping, prot_flags, personality, probes);
1943
1944 if prot_flags.contains(ProtectionFlags::EXEC)
1947 && !mapping.can_exec()
1948 && !mapping.may_exec()
1949 {
1950 return error!(EACCES);
1951 }
1952
1953 security::file_mprotect(current_task, &intersection, mapping, prot_flags)?;
1954
1955 if mapping.flags().contains(MappingFlags::UFFD) {
1956 track_stub!(
1957 TODO("https://fxbug.dev/297375964"),
1958 "mprotect on uffd-registered range should not alter protections"
1959 );
1960 return error!(EINVAL);
1961 }
1962
1963 if mapping.flags().access_flags() != prot_flags {
1964 let range = range.clone();
1965 let mut mapping = mapping.clone();
1966
1967 if prot_flags.contains(ProtectionFlags::WRITE)
1971 && Self::can_promote_lazy_private(&mapping)
1972 {
1973 mapping = self.promote_to_private_child(
1974 current_task.kernel(),
1975 mapping_context,
1976 range.clone(),
1977 mapping,
1978 released_mappings,
1979 )?;
1980 }
1981
1982 if mapping.mapping_mode() == MappingMode::Lazy {
1987 self.ensure_range_mapped_in_user_vmar(
1988 range.start,
1989 Some(range.end - range.start),
1990 mapping_context,
1991 )?;
1992 mapping.set_mapping_mode(MappingMode::Eager);
1995 }
1996
1997 let memory_replaced = protect_mapping_range(
1998 mapping_context,
1999 &intersection,
2000 &mut mapping,
2001 prot_flags,
2002 probes,
2003 )?;
2004 released_mappings
2005 .extend(self.mappings.insert(intersection.clone(), mapping.clone()));
2006 if memory_replaced && mapping.flags().contains(MappingFlags::LOCKED) {
2008 self.repin_locked_mapping(
2009 current_task.kernel(),
2010 mapping_context,
2011 &intersection,
2012 &mapping,
2013 released_mappings,
2014 )?;
2015 }
2016 }
2017
2018 cursor = intersection.end;
2019 }
2020
2021 Ok(())
2022 }
2023
2024 fn can_promote_lazy_private(mapping: &Mapping) -> bool {
2031 mapping.flags().contains(MappingFlags::LAZY_PRIVATE_FILE)
2032 && matches!(mapping.get_backing_internal(), MappingBacking::Memory(_))
2033 }
2034
2035 fn promote_to_private_child(
2052 &mut self,
2053 kernel: &Kernel,
2054 context: &MappingContext,
2055 range: Range<UserAddress>,
2056 mapping: Mapping,
2057 released_mappings: &mut ReleasedMappings,
2058 ) -> Result<Mapping, Errno> {
2059 debug_assert!(!mapping.flags().contains(MappingFlags::SHARED));
2060 let MappingBacking::Memory(backing) = mapping.get_backing_internal() else {
2061 unreachable!("only memory-backed mappings can be promoted to a private child");
2062 };
2063 let run = if mapping.flags().contains(MappingFlags::LAZY_PRIVATE_FILE) {
2064 self.collect_lazy_private_run(&range, &mapping, backing)
2065 } else {
2066 vec![(range.clone(), mapping.clone())]
2067 };
2068 let child_memory = Arc::new(
2069 backing
2070 .memory()
2071 .create_private_child()
2072 .map_err(MemoryManager::get_errno_for_vmo_err)?,
2073 );
2074
2075 let mut promoted_mapping = None;
2076 for (run_range, mut run_mapping) in run {
2077 let cow_modified = run_mapping.has_cow_modifications();
2078 let memory_offset = run_mapping.address_to_offset(run_range.start);
2079 let flags = run_mapping.flags().difference(MappingFlags::LAZY_PRIVATE_FILE);
2080 run_mapping.set_backing_internal(MappingBacking::Memory(Box::new(
2081 MappingBackingMemory::new(run_range.start, child_memory.clone(), memory_offset),
2082 )));
2083 if cow_modified {
2084 run_mapping.set_cow_modified();
2085 }
2086 run_mapping.set_flags(flags);
2087 context.map_in_user_vmar(
2091 SelectedAddress::FixedOverwrite(run_range.start),
2092 &child_memory,
2093 memory_offset,
2094 run_range.end - run_range.start,
2095 run_mapping.vmar_flags(),
2096 false,
2097 )?;
2098 run_mapping.set_mapping_mode(MappingMode::Eager);
2099 released_mappings.extend(self.mappings.insert(run_range.clone(), run_mapping.clone()));
2100 if run_mapping.flags().contains(MappingFlags::LOCKED) {
2101 self.repin_locked_mapping(
2102 kernel,
2103 context,
2104 &run_range,
2105 &run_mapping,
2106 released_mappings,
2107 )?;
2108 }
2109 if run_range == range {
2110 promoted_mapping = Some(run_mapping);
2111 }
2112 }
2113 Ok(promoted_mapping.expect("the run always contains `range`"))
2114 }
2115
2116 fn collect_lazy_private_run(
2124 &self,
2125 range: &Range<UserAddress>,
2126 mapping: &Mapping,
2127 backing: &MappingBackingMemory,
2128 ) -> Vec<(Range<UserAddress>, Mapping)> {
2129 let memory = backing.memory();
2130 let memory_koid = memory.get_koid();
2131 let has_exec_right = memory.get_rights().contains(zx::Rights::EXECUTE);
2132 let can_promote_together = |adj_mapping: &Mapping, shared_addr: UserAddress| -> bool {
2133 if !adj_mapping.flags().contains(MappingFlags::LAZY_PRIVATE_FILE)
2134 || adj_mapping.name() != mapping.name()
2135 {
2136 return false;
2137 }
2138 debug_assert!(!adj_mapping.flags().contains(MappingFlags::SHARED));
2139 let MappingBacking::Memory(adj_backing) = adj_mapping.get_backing_internal() else {
2140 return false;
2141 };
2142 if adj_backing.address_to_offset(shared_addr) != backing.address_to_offset(shared_addr)
2143 {
2144 return false;
2145 }
2146 let adj_memory = adj_backing.memory();
2147 (adj_memory == memory || adj_memory.get_koid() == memory_koid)
2148 && adj_memory.get_rights().contains(zx::Rights::EXECUTE) == has_exec_right
2149 };
2150
2151 let mut run = Vec::new();
2152 let mut cursor = range.start;
2153 for (prev_range, prev_mapping) in self.mappings.range(..range.start).rev() {
2154 if prev_range.end != cursor || !can_promote_together(prev_mapping, cursor) {
2155 break;
2156 }
2157 cursor = prev_range.start;
2158 run.push((prev_range.clone(), prev_mapping.clone()));
2159 }
2160 run.reverse();
2161
2162 run.push((range.clone(), mapping.clone()));
2163
2164 cursor = range.end;
2165 for (next_range, next_mapping) in self.mappings.range(range.end..) {
2166 if next_range.start != cursor || !can_promote_together(next_mapping, cursor) {
2167 break;
2168 }
2169 cursor = next_range.end;
2170 run.push((next_range.clone(), next_mapping.clone()));
2171 }
2172 run
2173 }
2174
2175 fn madvise_update_flags(
2180 &mut self,
2181 context: &MappingContext,
2182 addr: UserAddress,
2183 length: usize,
2184 advice: MadviseFlagAdvice,
2185 released_mappings: &mut ReleasedMappings,
2186 ) -> Result<(), Errno> {
2187 if !addr.is_aligned(*PAGE_SIZE) {
2188 return error!(EINVAL);
2189 }
2190
2191 let end_addr =
2192 addr.checked_add(length).ok_or_else(|| errno!(EINVAL))?.round_up(*PAGE_SIZE)?;
2193 if end_addr > context.max_address() {
2194 return error!(EFAULT);
2195 }
2196
2197 let mut updates = vec![];
2198 let range_for_op = addr..end_addr;
2199 for (range, mapping) in self.mappings.range(range_for_op.clone()) {
2200 let range_to_zero = range.intersect(&range_for_op);
2201 if range_to_zero.is_empty() {
2202 continue;
2203 }
2204 if advice == MadviseFlagAdvice::WipeOnFork && !mapping.private_anonymous() {
2209 return error!(EINVAL);
2210 }
2211 let new_flags = match advice {
2212 MadviseFlagAdvice::DontFork => mapping.flags() | MappingFlags::DONTFORK,
2213 MadviseFlagAdvice::DoFork => mapping.flags() & MappingFlags::DONTFORK.complement(),
2214 MadviseFlagAdvice::WipeOnFork => mapping.flags() | MappingFlags::WIPEONFORK,
2215 MadviseFlagAdvice::KeepOnFork => {
2216 mapping.flags() & MappingFlags::WIPEONFORK.complement()
2217 }
2218 MadviseFlagAdvice::DontDump => {
2219 track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_DONTDUMP");
2220 mapping.flags()
2221 }
2222 MadviseFlagAdvice::DoDump => {
2223 track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_DODUMP");
2224 mapping.flags()
2225 }
2226 MadviseFlagAdvice::Mergeable => {
2227 track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_MERGEABLE");
2228 mapping.flags()
2229 }
2230 MadviseFlagAdvice::Unmergeable => {
2231 track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_UNMERGEABLE");
2232 mapping.flags()
2233 }
2234 };
2235 let mut new_mapping = mapping.clone();
2236 new_mapping.set_flags(new_flags);
2237 updates.push((range_to_zero, new_mapping));
2238 }
2239 for (range, mapping) in updates {
2241 released_mappings.extend(self.mappings.insert(range, mapping));
2242 }
2243 Ok(())
2244 }
2245
2246 fn madvise_read_only(
2251 &self,
2252 current_task: &CurrentTask,
2253 context: &MappingContext,
2254 addr: UserAddress,
2255 length: usize,
2256 advice: MadviseReadOnlyAdvice,
2257 ) -> Result<(), Errno> {
2258 if !addr.is_aligned(*PAGE_SIZE) {
2259 return error!(EINVAL);
2260 }
2261
2262 let end_addr =
2263 addr.checked_add(length).ok_or_else(|| errno!(EINVAL))?.round_up(*PAGE_SIZE)?;
2264 if end_addr > context.max_address() {
2265 return error!(EFAULT);
2266 }
2267
2268 match advice {
2269 MadviseReadOnlyAdvice::Normal => {
2270 track_stub!(
2271 TODO("https://fxbug.dev/322874202"),
2272 "madvise paging hints",
2273 MADV_NORMAL
2274 );
2275 return Ok(());
2276 }
2277 MadviseReadOnlyAdvice::Random => {
2278 track_stub!(
2279 TODO("https://fxbug.dev/322874202"),
2280 "madvise paging hints",
2281 MADV_RANDOM
2282 );
2283 return Ok(());
2284 }
2285 MadviseReadOnlyAdvice::Sequential => {
2286 track_stub!(
2287 TODO("https://fxbug.dev/322874202"),
2288 "madvise paging hints",
2289 MADV_SEQUENTIAL
2290 );
2291 return Ok(());
2292 }
2293 _ => {}
2294 }
2295
2296 let range_for_op = addr..end_addr;
2297 for (range, mapping) in self.mappings.range(range_for_op.clone()) {
2298 let range_to_zero = range.intersect(&range_for_op);
2299 if range_to_zero.is_empty() {
2300 continue;
2301 }
2302 let start_offset = mapping.address_to_offset(range_to_zero.start);
2303 let end_offset = mapping.address_to_offset(range_to_zero.end);
2304 if mapping.flags().contains(MappingFlags::SHARED)
2305 && advice != MadviseReadOnlyAdvice::WillNeed
2306 {
2307 continue;
2308 }
2309 let op = match advice {
2310 MadviseReadOnlyAdvice::Normal
2311 | MadviseReadOnlyAdvice::Random
2312 | MadviseReadOnlyAdvice::Sequential => unreachable!(),
2313 MadviseReadOnlyAdvice::DontNeed
2314 if !mapping.flags().contains(MappingFlags::ANONYMOUS) =>
2315 {
2316 track_stub!(
2320 TODO("https://fxbug.dev/322874496"),
2321 "MADV_DONTNEED with file-backed mapping"
2322 );
2323 return Ok(());
2324 }
2325 MadviseReadOnlyAdvice::DontNeed
2326 if mapping.flags().contains(MappingFlags::LOCKED) =>
2327 {
2328 return error!(EINVAL);
2329 }
2330 MadviseReadOnlyAdvice::DontNeed => zx::VmoOp::ZERO,
2331 MadviseReadOnlyAdvice::DontNeedLocked => {
2332 track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_DONTNEED_LOCKED");
2333 return error!(EINVAL);
2334 }
2335 MadviseReadOnlyAdvice::WillNeed => {
2336 let memory = match self.get_mapping_backing(mapping) {
2337 MappingBacking::Memory(backing) => backing.memory(),
2338 MappingBacking::PrivateAnonymous => &context.private_anonymous.backing,
2339 };
2340 current_task.kernel().kthreads.prefetch_pool().enqueue(PrefetchMessage {
2341 memory: memory.clone(),
2342 offset: start_offset,
2343 length: end_offset - start_offset,
2344 });
2345 continue;
2346 }
2347 MadviseReadOnlyAdvice::Cold => {
2348 track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_COLD");
2349 return error!(EINVAL);
2350 }
2351 MadviseReadOnlyAdvice::PageOut => {
2352 track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_PAGEOUT");
2353 return error!(EINVAL);
2354 }
2355 MadviseReadOnlyAdvice::PopulateRead => {
2356 track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_POPULATE_READ");
2357 return error!(EINVAL);
2358 }
2359 MadviseReadOnlyAdvice::Free
2360 if !mapping.flags().contains(MappingFlags::ANONYMOUS) =>
2361 {
2362 track_stub!(
2363 TODO("https://fxbug.dev/411748419"),
2364 "MADV_FREE with file-backed mapping"
2365 );
2366 return error!(EINVAL);
2367 }
2368 MadviseReadOnlyAdvice::Free if mapping.flags().contains(MappingFlags::LOCKED) => {
2369 return error!(EINVAL);
2370 }
2371 MadviseReadOnlyAdvice::Free => {
2372 track_stub!(TODO("https://fxbug.dev/411748419"), "MADV_FREE");
2373 zx::VmoOp::ZERO
2376 }
2377 MadviseReadOnlyAdvice::Remove => {
2378 track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_REMOVE");
2379 return error!(EINVAL);
2380 }
2381 MadviseReadOnlyAdvice::HwPoison => {
2382 track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_HWPOISON");
2383 return error!(EINVAL);
2384 }
2385 MadviseReadOnlyAdvice::SoftOffline => {
2386 track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_SOFT_OFFLINE");
2387 return error!(EINVAL);
2388 }
2389 MadviseReadOnlyAdvice::HugePage => {
2390 track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_HUGEPAGE");
2391 return error!(EINVAL);
2392 }
2393 MadviseReadOnlyAdvice::Collapse => {
2394 track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_COLLAPSE");
2395 return error!(EINVAL);
2396 }
2397 MadviseReadOnlyAdvice::NoHugePage => return Ok(()),
2398 MadviseReadOnlyAdvice::Unknown(advice) => {
2399 track_stub!(TODO("https://fxbug.dev/322874202"), "madvise", advice);
2400 return error!(EINVAL);
2401 }
2402 };
2403
2404 let memory = match self.get_mapping_backing(mapping) {
2405 MappingBacking::Memory(backing) => backing.memory(),
2406 MappingBacking::PrivateAnonymous => &context.private_anonymous.backing,
2407 };
2408 memory.op_range(op, start_offset, end_offset - start_offset).map_err(|s| match s {
2409 zx::Status::OUT_OF_RANGE => errno!(EINVAL),
2410 zx::Status::NO_MEMORY => errno!(ENOMEM),
2411 zx::Status::INVALID_ARGS => errno!(EINVAL),
2412 zx::Status::ACCESS_DENIED => errno!(EACCES),
2413 _ => impossible_error(s),
2414 })?;
2415 }
2416 Ok(())
2417 }
2418
2419 fn mlock(
2420 &mut self,
2421 context: &MappingContext,
2422 current_task: &CurrentTask,
2423 desired_addr: UserAddress,
2424 desired_length: usize,
2425 on_fault: bool,
2426 released_mappings: &mut ReleasedMappings,
2427 ) -> Result<(), Errno> {
2428 let desired_end_addr =
2429 desired_addr.checked_add(desired_length).ok_or_else(|| errno!(EINVAL))?;
2430 let start_addr = round_down_to_system_page_size(desired_addr)?;
2431 let end_addr = round_up_to_system_page_size(desired_end_addr)?;
2432
2433 let mut updates = vec![];
2434 let mut bytes_mapped_in_range = 0;
2435 let mut num_new_locked_bytes = 0;
2436 let mut failed_to_lock = false;
2437 for (range, mapping) in self.mappings.range(start_addr..end_addr) {
2438 let mut range = range.clone();
2439 let mut mapping = mapping.clone();
2440
2441 range.start = std::cmp::max(range.start, start_addr);
2443 range.end = std::cmp::min(range.end, end_addr);
2445
2446 bytes_mapped_in_range += (range.end - range.start) as u64;
2447
2448 if !mapping
2450 .flags()
2451 .intersects(MappingFlags::READ | MappingFlags::WRITE | MappingFlags::EXEC)
2452 {
2453 failed_to_lock = true;
2454 }
2455
2456 if !mapping.flags().contains(MappingFlags::LOCKED) {
2457 num_new_locked_bytes += (range.end - range.start) as u64;
2458 let shadow_mapping = match current_task.kernel().features.mlock_pin_flavor {
2459 MlockPinFlavor::ShadowProcess => Some(self.pin_in_mlock_shadow_process(
2461 current_task.kernel(),
2462 context,
2463 &range,
2464 &mapping,
2465 )?),
2466
2467 MlockPinFlavor::Noop | MlockPinFlavor::VmarAlwaysNeed => None,
2469 };
2470 mapping.set_mlock();
2471 updates.push((range, mapping, shadow_mapping));
2472 }
2473 }
2474
2475 if bytes_mapped_in_range as usize != end_addr - start_addr {
2476 return error!(ENOMEM);
2477 }
2478
2479 let memlock_rlimit = current_task.thread_group().get_rlimit(Resource::MEMLOCK);
2480 let total_locked = self.num_locked_bytes(
2481 UserAddress::from(context.user_vmar_info.base as u64)
2482 ..UserAddress::from(
2483 (context.user_vmar_info.base + context.user_vmar_info.len) as u64,
2484 ),
2485 );
2486 if total_locked + num_new_locked_bytes > memlock_rlimit {
2487 if crate::security::check_task_capable(current_task, CAP_IPC_LOCK).is_err() {
2488 let code = if memlock_rlimit > 0 { errno!(ENOMEM) } else { errno!(EPERM) };
2489 return Err(code);
2490 }
2491 }
2492
2493 self.ensure_range_mapped_in_user_vmar(start_addr, Some(end_addr - start_addr), context)?;
2494
2495 if !on_fault && !current_task.kernel().features.mlock_always_onfault {
2496 context
2497 .user_vmar
2498 .op_range(zx::VmarOp::PREFETCH, start_addr.ptr(), end_addr - start_addr)
2499 .map_err(Self::mlock_op_range_status_to_errno)?;
2500 }
2501
2502 match current_task.kernel().features.mlock_pin_flavor {
2503 MlockPinFlavor::VmarAlwaysNeed => {
2504 context
2505 .user_vmar
2506 .op_range(zx::VmarOp::ALWAYS_NEED, start_addr.ptr(), end_addr - start_addr)
2507 .map_err(Self::mlock_op_range_status_to_errno)?;
2508 }
2509 MlockPinFlavor::Noop | MlockPinFlavor::ShadowProcess => (),
2511 }
2512
2513 for (range, mut mapping, shadow_mapping) in updates {
2514 if let Some(shadow_mapping) = shadow_mapping {
2515 released_mappings.extend_pins(
2516 self.shadow_mappings_for_mlock.insert(range.clone(), shadow_mapping),
2517 );
2518 }
2519 mapping.set_mapping_mode(MappingMode::Eager);
2522 released_mappings.extend(self.mappings.insert(range, mapping));
2523 }
2524
2525 if failed_to_lock { error!(ENOMEM) } else { Ok(()) }
2526 }
2527
2528 fn mlock_op_range_status_to_errno(e: zx::Status) -> Errno {
2529 match e {
2530 zx::Status::BAD_STATE | zx::Status::NOT_SUPPORTED => errno!(ENOMEM),
2531 zx::Status::INVALID_ARGS | zx::Status::OUT_OF_RANGE => errno!(EINVAL),
2532 zx::Status::ACCESS_DENIED => {
2533 unreachable!("user vmar should always have needed rights")
2534 }
2535 zx::Status::BAD_HANDLE => {
2536 unreachable!("user vmar should always be a valid handle")
2537 }
2538 zx::Status::WRONG_TYPE => unreachable!("user vmar handle should be a vmar"),
2539 _ => unreachable!("unknown error from op_range on user vmar for mlock: {e}"),
2540 }
2541 }
2542
2543 fn pin_in_mlock_shadow_process(
2546 &self,
2547 kernel: &Kernel,
2548 context: &MappingContext,
2549 range: &Range<UserAddress>,
2550 mapping: &Mapping,
2551 ) -> Result<Arc<PinnedMapping>, Errno> {
2552 let shadow_process = kernel.expando.get_or_try_init(|| {
2553 memory_pinning::ShadowProcess::new(zx::Name::new_lossy("starnix_mlock_pins"))
2554 .map(MlockShadowProcess)
2555 .map_err(|_| errno!(EPERM))
2556 })?;
2557
2558 let (vmo, offset) = match self.get_mapping_backing(mapping) {
2559 MappingBacking::Memory(m) => (
2560 m.memory().as_vmo().ok_or_else(|| errno!(ENOMEM))?,
2561 m.address_to_offset(range.start),
2562 ),
2563 MappingBacking::PrivateAnonymous => (
2564 context.private_anonymous.backing.as_vmo().ok_or_else(|| errno!(ENOMEM))?,
2565 range.start.ptr() as u64,
2566 ),
2567 };
2568 shadow_process.0.pin_pages(vmo, offset, range.end - range.start)
2569 }
2570
2571 fn repin_locked_mapping(
2577 &mut self,
2578 kernel: &Kernel,
2579 context: &MappingContext,
2580 range: &Range<UserAddress>,
2581 mapping: &Mapping,
2582 released_mappings: &mut ReleasedMappings,
2583 ) -> Result<(), Errno> {
2584 debug_assert!(mapping.flags().contains(MappingFlags::LOCKED));
2585 match kernel.features.mlock_pin_flavor {
2586 MlockPinFlavor::ShadowProcess => {
2587 let pin = self.pin_in_mlock_shadow_process(kernel, context, range, mapping)?;
2588 released_mappings
2589 .extend_pins(self.shadow_mappings_for_mlock.insert(range.clone(), pin));
2590 }
2591 MlockPinFlavor::VmarAlwaysNeed => {
2592 if mapping.mapping_mode() == MappingMode::Eager {
2593 context
2594 .user_vmar
2595 .op_range(
2596 zx::VmarOp::ALWAYS_NEED,
2597 range.start.ptr(),
2598 range.end - range.start,
2599 )
2600 .map_err(Self::mlock_op_range_status_to_errno)?;
2601 }
2602 }
2603 MlockPinFlavor::Noop => (),
2604 }
2605 Ok(())
2606 }
2607
2608 fn munlock(
2609 &mut self,
2610 _current_task: &CurrentTask,
2611 desired_addr: UserAddress,
2612 desired_length: usize,
2613 released_mappings: &mut ReleasedMappings,
2614 ) -> Result<(), Errno> {
2615 let desired_end_addr =
2616 desired_addr.checked_add(desired_length).ok_or_else(|| errno!(EINVAL))?;
2617 let start_addr = round_down_to_system_page_size(desired_addr)?;
2618 let end_addr = round_up_to_system_page_size(desired_end_addr)?;
2619
2620 let mut updates = vec![];
2621 let mut bytes_mapped_in_range = 0;
2622 for (range, mapping) in self.mappings.range(start_addr..end_addr) {
2623 let mut range = range.clone();
2624 let mut mapping = mapping.clone();
2625
2626 range.start = std::cmp::max(range.start, start_addr);
2628 range.end = std::cmp::min(range.end, end_addr);
2630
2631 bytes_mapped_in_range += (range.end - range.start) as u64;
2632
2633 if mapping.flags().contains(MappingFlags::LOCKED) {
2634 mapping.clear_mlock();
2638 updates.push((range, mapping));
2639 }
2640 }
2641
2642 if bytes_mapped_in_range as usize != end_addr - start_addr {
2643 return error!(ENOMEM);
2644 }
2645
2646 for (range, mapping) in updates {
2647 released_mappings.extend(self.mappings.insert(range.clone(), mapping));
2648 released_mappings.extend_pins(self.shadow_mappings_for_mlock.remove(range));
2649 }
2650
2651 Ok(())
2652 }
2653
2654 pub fn num_locked_bytes(&self, range: impl RangeBounds<UserAddress>) -> u64 {
2655 self.mappings
2656 .map
2657 .range(range)
2658 .filter(|(_, mapping)| mapping.flags().contains(MappingFlags::LOCKED))
2659 .map(|(range, _)| (range.end - range.start) as u64)
2660 .sum()
2661 }
2662
2663 fn get_mappings_for_vmsplice(
2671 &self,
2672 mm: &Arc<MemoryManager>,
2673 buffers: &UserBuffers,
2674 max_bytes: usize,
2675 ) -> Result<Vec<Arc<VmsplicePayload>>, Errno> {
2676 let page_size = *PAGE_SIZE as usize;
2677 let mut vmsplice_mappings = Vec::new();
2678 let mut remaining = max_bytes;
2679
2680 for UserBuffer { mut address, length } in buffers.iter().copied() {
2681 if remaining == 0 {
2682 break;
2683 }
2684 let length = std::cmp::min(length, remaining);
2686 if length == 0 {
2687 continue;
2688 }
2689 let mappings =
2692 match self.get_contiguous_mappings_at(address, length, &mm.mapping_context) {
2693 Ok(mappings) => mappings,
2694 Err(e) => {
2695 if vmsplice_mappings.is_empty() {
2696 return Err(e);
2697 }
2698 return Ok(vmsplice_mappings);
2699 }
2700 };
2701 let mut covered = 0;
2702 for (mapping, mut seg_len) in mappings {
2703 if !mapping.can_read() {
2706 if vmsplice_mappings.is_empty() {
2707 return error!(EFAULT);
2708 }
2709 return Ok(vmsplice_mappings);
2710 }
2711 while seg_len > 0 && remaining > 0 {
2715 let max_in_page = page_size - (address.ptr() % page_size);
2716 let chunk_len = std::cmp::min(seg_len, std::cmp::min(max_in_page, remaining));
2717 let Some(next_address) = address.checked_add(chunk_len) else {
2720 if vmsplice_mappings.is_empty() {
2721 return error!(EFAULT);
2722 }
2723 return Ok(vmsplice_mappings);
2724 };
2725 let vmsplice_payload = match self.get_mapping_backing(mapping) {
2726 MappingBacking::Memory(m) => VmsplicePayloadSegment {
2727 addr_offset: address,
2728 length: chunk_len,
2729 memory: m.memory().clone(),
2730 memory_offset: m.address_to_offset(address),
2731 should_snapshot_on_unmap: false,
2732 },
2733 MappingBacking::PrivateAnonymous => VmsplicePayloadSegment {
2734 addr_offset: address,
2735 length: chunk_len,
2736 memory: mm.mapping_context.private_anonymous.backing.clone(),
2737 memory_offset: address.ptr() as u64,
2738 should_snapshot_on_unmap: true,
2739 },
2740 };
2741 vmsplice_mappings
2742 .push(VmsplicePayload::new(Arc::downgrade(mm), vmsplice_payload));
2743
2744 address = next_address;
2745 seg_len -= chunk_len;
2746 covered += chunk_len;
2747 remaining -= chunk_len;
2748 }
2749 }
2750 if covered < length {
2754 if vmsplice_mappings.is_empty() {
2755 return error!(EFAULT);
2756 }
2757 return Ok(vmsplice_mappings);
2758 }
2759 }
2760
2761 Ok(vmsplice_mappings)
2762 }
2763
2764 fn get_contiguous_mappings_at(
2777 &self,
2778 addr: UserAddress,
2779 length: usize,
2780 context: &MappingContext,
2781 ) -> Result<impl Iterator<Item = (&Mapping, usize)>, Errno> {
2782 let end_addr = addr.checked_add(length).ok_or_else(|| errno!(EFAULT))?;
2783 if end_addr > context.max_address() {
2784 return error!(EFAULT);
2785 }
2786
2787 let mut mappings = self.mappings.range(addr..end_addr);
2789 let mut prev_range_end = None;
2790 let mut offset = 0;
2791 let result = std::iter::from_fn(move || {
2792 if offset != length {
2793 if let Some((range, mapping)) = mappings.next() {
2794 return match prev_range_end {
2795 None if range.start > addr => None,
2798
2799 Some(prev_range_end) if range.start != prev_range_end => None,
2801
2802 _ => {
2804 let mapping_length = std::cmp::min(length, range.end - addr) - offset;
2805 offset += mapping_length;
2806 prev_range_end = Some(range.end);
2807 Some((mapping, mapping_length))
2808 }
2809 };
2810 }
2811 }
2812
2813 None
2814 });
2815
2816 Ok(result)
2817 }
2818
2819 fn find_growsdown_mapping(&self, addr: UserAddress) -> Option<(UserAddress, &Mapping)> {
2827 match self.mappings.range(addr..).next() {
2828 Some((range, mapping)) => {
2829 if range.contains(&addr) {
2830 return None;
2832 } else if !mapping.flags().contains(MappingFlags::GROWSDOWN) {
2833 None
2836 } else {
2837 Some((range.start, mapping))
2838 }
2839 }
2840 None => None,
2841 }
2842 }
2843
2844 fn extend_growsdown_mapping_to_address(
2847 &mut self,
2848 mm: &MemoryManager,
2849 addr: UserAddress,
2850 is_write: bool,
2851 ) -> Result<bool, Error> {
2852 let Some((mapping_low_addr, mapping_to_grow)) = self.find_growsdown_mapping(addr) else {
2853 return Ok(false);
2854 };
2855 if (is_write && !mapping_to_grow.can_write()) || (!is_write && !mapping_to_grow.can_read())
2856 {
2857 return Ok(false);
2860 }
2861 if !mapping_to_grow.flags().contains(MappingFlags::ANONYMOUS) {
2862 return Ok(false);
2864 }
2865 let low_addr = (addr - (addr.ptr() as u64 % *PAGE_SIZE))?;
2866 if low_addr < mm.base_addr {
2867 return Ok(false);
2868 }
2869 let high_addr = mapping_low_addr;
2870
2871 let length = high_addr
2872 .ptr()
2873 .checked_sub(low_addr.ptr())
2874 .ok_or_else(|| anyhow!("Invalid growth range"))?;
2875 let mut released_mappings = ReleasedMappings::default();
2878 self.map_anonymous(
2879 mm,
2880 DesiredAddress::FixedOverwrite(low_addr),
2881 length,
2882 mapping_to_grow.flags().access_flags(),
2883 mapping_to_grow.flags().options(),
2884 mapping_to_grow.name().to_owned(),
2885 &mut released_mappings,
2886 )?;
2887 assert!(
2890 released_mappings.is_empty(),
2891 "expected to not remove mappings by inserting, got {released_mappings:#?}"
2892 );
2893 Ok(true)
2894 }
2895
2896 fn read_memory<'a>(
2902 &self,
2903 addr: UserAddress,
2904 bytes: &'a mut [MaybeUninit<u8>],
2905 context: &MappingContext,
2906 ) -> Result<&'a mut [u8], Errno> {
2907 let total_len = bytes.len();
2908 let bytes_read = self.read_memory_partial(addr, bytes, context)?;
2909 if bytes_read.len() != total_len { error!(EFAULT) } else { Ok(bytes_read) }
2910 }
2911
2912 fn read_mapping_memory<'a>(
2918 &self,
2919 addr: UserAddress,
2920 mapping: &Mapping,
2921 bytes: &'a mut [MaybeUninit<u8>],
2922 context: &MappingContext,
2923 ) -> Result<&'a mut [u8], Errno> {
2924 if !mapping.can_read() {
2925 return error!(EFAULT, "read_mapping_memory called on unreadable mapping");
2926 }
2927 match self.get_mapping_backing(mapping) {
2928 MappingBacking::Memory(backing) => backing.read_memory(addr, bytes),
2929 MappingBacking::PrivateAnonymous => context.private_anonymous.read_memory(addr, bytes),
2930 }
2931 }
2932
2933 fn read_memory_partial<'a>(
2943 &self,
2944 addr: UserAddress,
2945 bytes: &'a mut [MaybeUninit<u8>],
2946 context: &MappingContext,
2947 ) -> Result<&'a mut [u8], Errno> {
2948 let mut bytes_read = 0;
2949 for (mapping, len) in self.get_contiguous_mappings_at(addr, bytes.len(), context)? {
2950 let next_offset = bytes_read + len;
2951 if self
2952 .read_mapping_memory(
2953 (addr + bytes_read)?,
2954 mapping,
2955 &mut bytes[bytes_read..next_offset],
2956 context,
2957 )
2958 .is_err()
2959 {
2960 break;
2961 }
2962 bytes_read = next_offset;
2963 }
2964
2965 let initialized = &mut bytes[..bytes_read];
2966 let bytes = unsafe {
2973 std::slice::from_raw_parts_mut(initialized.as_mut_ptr() as *mut u8, bytes_read)
2974 };
2975 Ok(bytes)
2976 }
2977
2978 fn read_memory_partial_until_null_byte<'a>(
2981 &self,
2982 addr: UserAddress,
2983 bytes: &'a mut [MaybeUninit<u8>],
2984 context: &MappingContext,
2985 ) -> Result<&'a mut [u8], Errno> {
2986 let read_bytes = self.read_memory_partial(addr, bytes, context)?;
2987 let max_len = memchr::memchr(b'\0', read_bytes)
2988 .map_or_else(|| read_bytes.len(), |null_index| null_index + 1);
2989 Ok(&mut read_bytes[..max_len])
2990 }
2991
2992 fn write_memory(
3000 &self,
3001 addr: UserAddress,
3002 bytes: &[u8],
3003 context: &MappingContext,
3004 ) -> Result<usize, Errno> {
3005 let bytes_written = self.write_memory_partial(addr, bytes, context)?;
3006 if bytes_written != bytes.len() { error!(EFAULT) } else { Ok(bytes.len()) }
3007 }
3008
3009 fn write_mapping_memory(
3015 &self,
3016 addr: UserAddress,
3017 mapping: &Mapping,
3018 bytes: &[u8],
3019 context: &MappingContext,
3020 ) -> Result<(), Errno> {
3021 if !mapping.can_write() {
3022 return error!(EFAULT, "write_mapping_memory called on unwritable memory");
3023 }
3024 match self.get_mapping_backing(mapping) {
3025 MappingBacking::Memory(backing) => backing.write_memory(addr, bytes),
3026 MappingBacking::PrivateAnonymous => context.private_anonymous.write_memory(addr, bytes),
3027 }
3028 }
3029
3030 fn write_memory_partial(
3037 &self,
3038 addr: UserAddress,
3039 bytes: &[u8],
3040 context: &MappingContext,
3041 ) -> Result<usize, Errno> {
3042 let mut bytes_written = 0;
3043 for (mapping, len) in self.get_contiguous_mappings_at(addr, bytes.len(), context)? {
3044 let next_offset = bytes_written + len;
3045 if self
3046 .write_mapping_memory(
3047 (addr + bytes_written)?,
3048 mapping,
3049 &bytes[bytes_written..next_offset],
3050 context,
3051 )
3052 .is_err()
3053 {
3054 break;
3055 }
3056 bytes_written = next_offset;
3057 }
3058
3059 Ok(bytes_written)
3060 }
3061
3062 fn zero_partial(
3063 &self,
3064 addr: UserAddress,
3065 length: usize,
3066 context: &MappingContext,
3067 ) -> Result<usize, Errno> {
3068 let mut bytes_written = 0;
3069 for (mapping, len) in self.get_contiguous_mappings_at(addr, length, context)? {
3070 let next_offset = bytes_written + len;
3071 if self.zero_mapping((addr + bytes_written)?, mapping, len, context).is_err() {
3072 break;
3073 }
3074 bytes_written = next_offset;
3075 }
3076
3077 Ok(bytes_written)
3078 }
3079
3080 fn zero(
3081 &self,
3082 addr: UserAddress,
3083 length: usize,
3084 context: &MappingContext,
3085 ) -> Result<usize, Errno> {
3086 let bytes_written = self.zero_partial(addr, length, context)?;
3087 if length != bytes_written { error!(EFAULT) } else { Ok(length) }
3088 }
3089
3090 fn zero_mapping(
3091 &self,
3092 addr: UserAddress,
3093 mapping: &Mapping,
3094 length: usize,
3095 context: &MappingContext,
3096 ) -> Result<usize, Errno> {
3097 if !mapping.can_write() {
3098 return error!(EFAULT);
3099 }
3100
3101 match self.get_mapping_backing(mapping) {
3102 MappingBacking::Memory(backing) => backing.zero(addr, length),
3103 MappingBacking::PrivateAnonymous => context.private_anonymous.zero(addr, length),
3104 }
3105 }
3106
3107 pub fn get_mapping_backing<'a>(&self, mapping: &'a Mapping) -> &'a MappingBacking {
3108 mapping.get_backing_internal()
3109 }
3110
3111 fn get_aio_context(&self, addr: UserAddress) -> Option<(Range<UserAddress>, Arc<AioContext>)> {
3112 let Some((range, mapping)) = self.mappings.get(addr) else {
3113 return None;
3114 };
3115 let MappingNameRef::AioContext(ref aio_context) = mapping.name() else {
3116 return None;
3117 };
3118 if !mapping.can_read() {
3119 return None;
3120 }
3121 Some((range.clone(), Arc::clone(aio_context)))
3122 }
3123
3124 fn find_uffd(&self, addr: UserAddress) -> Option<Arc<UserFault>> {
3125 for userfault in self.userfaultfds.iter() {
3126 if let Some(userfault) = userfault.upgrade() {
3127 if userfault.contains_addr(addr) {
3128 return Some(userfault);
3129 }
3130 }
3131 }
3132 None
3133 }
3134
3135 fn cache_flush(
3136 &self,
3137 range: Range<UserAddress>,
3138 context: &MappingContext,
3139 ) -> Result<(), Errno> {
3140 let mut addr = range.start;
3141 let size = range.end - range.start;
3142 for (mapping, len) in self.get_contiguous_mappings_at(addr, size, context)? {
3143 if !mapping.can_read() {
3144 return error!(EFAULT);
3145 }
3146 if mapping.mapping_mode() == MappingMode::Lazy {
3147 addr = (addr + len)?;
3148 continue;
3149 }
3150 zx::Status::ok(unsafe {
3152 zx::sys::zx_cache_flush(
3153 addr.ptr() as *const u8,
3154 len,
3155 zx::sys::ZX_CACHE_FLUSH_DATA | zx::sys::ZX_CACHE_FLUSH_INSN,
3156 )
3157 })
3158 .map_err(impossible_error)?;
3159
3160 addr = (addr + len).unwrap(); }
3162 if addr != range.end { error!(EFAULT) } else { Ok(()) }
3164 }
3165
3166 pub fn register_membarrier_private_expedited(
3169 &mut self,
3170 mtype: MembarrierType,
3171 ) -> Result<(), Errno> {
3172 let registrations = &mut self.forkable_state.membarrier_registrations;
3173 match mtype {
3174 MembarrierType::Memory => {
3175 registrations.memory = true;
3176 }
3177 MembarrierType::SyncCore => {
3178 registrations.sync_core = true;
3179 }
3180 }
3181 Ok(())
3182 }
3183
3184 pub fn membarrier_private_expedited_registered(&self, mtype: MembarrierType) -> bool {
3187 let registrations = &self.forkable_state.membarrier_registrations;
3188 match mtype {
3189 MembarrierType::Memory => registrations.memory,
3190 MembarrierType::SyncCore => registrations.sync_core,
3191 }
3192 }
3193
3194 fn force_write_memory(
3195 &mut self,
3196 kernel: &Kernel,
3197 context: &MappingContext,
3198 addr: UserAddress,
3199 bytes: &[u8],
3200 released_mappings: &mut ReleasedMappings,
3201 ) -> Result<(), Errno> {
3202 if bytes.is_empty() {
3203 return Ok(());
3204 }
3205 let (range, mut mapping) = {
3206 let (r, m) = self.mappings.get(addr).ok_or_else(|| errno!(EFAULT))?;
3207 (r.clone(), m.clone())
3208 };
3209 if range.end < addr.saturating_add(bytes.len()) {
3210 track_stub!(
3211 TODO("https://fxbug.dev/445790710"),
3212 "ptrace poke across multiple mappings"
3213 );
3214 return error!(EFAULT);
3215 }
3216
3217 if mapping.flags().contains(MappingFlags::SHARED) && !mapping.can_write() {
3219 return error!(EIO);
3221 }
3222
3223 let addr_offset = mapping.address_to_offset(addr);
3224
3225 let needs_private_child = mapping.flags().contains(MappingFlags::LAZY_PRIVATE_FILE)
3230 || match Self::mapping_vmo(context, &mapping)?.write(bytes, addr_offset) {
3231 Ok(()) => false,
3232 Err(zx::Status::ACCESS_DENIED)
3234 if mapping.flags().contains(MappingFlags::SHARED) =>
3235 {
3236 return error!(EIO);
3237 }
3238 Err(zx::Status::ACCESS_DENIED)
3239 if matches!(mapping.get_backing_internal(), MappingBacking::Memory(_)) =>
3240 {
3241 true
3242 }
3243 Err(status) => return Err(MemoryManager::get_errno_for_vmo_err(status)),
3244 };
3245
3246 if needs_private_child {
3247 mapping =
3248 self.promote_to_private_child(kernel, context, range, mapping, released_mappings)?;
3249 Self::mapping_vmo(context, &mapping)?
3250 .write(bytes, addr_offset)
3251 .map_err(MemoryManager::get_errno_for_vmo_err)?;
3252 }
3253 if mapping.is_unmodified_private_file() {
3254 self.set_private_file_cow_modified(context, addr)?;
3255 }
3256
3257 if mapping.can_exec() {
3263 Self::mapping_memory(context, &mapping)
3266 .op_range(zx::VmoOp::CACHE_SYNC, addr_offset, bytes.len() as u64)
3267 .map_err(MemoryManager::get_errno_for_vmo_err)?;
3268 system_barrier(BarrierType::InstructionStream);
3269 }
3270
3271 Ok(())
3272 }
3273
3274 fn set_private_file_cow_modified(
3287 &mut self,
3288 context: &MappingContext,
3289 addr: UserAddress,
3290 ) -> Result<(), Errno> {
3291 let Some((_, mapping)) = self.mappings.get(addr) else {
3292 return Ok(());
3293 };
3294 if !mapping.is_unmodified_private_file()
3295 || mapping.flags().contains(MappingFlags::LAZY_PRIVATE_FILE)
3296 {
3297 return Ok(());
3298 }
3299 let MappingBacking::Memory(backing) = mapping.get_backing_internal() else {
3300 return Ok(());
3301 };
3302
3303 let Some(file) = mapping.name().as_file().cloned() else {
3304 return Ok(());
3305 };
3306 let memory = backing.memory().clone();
3307 let mut memory_koid = None;
3308 let ranges: SmallVec<[Range<UserAddress>; 1]> = self
3309 .mappings
3310 .iter()
3311 .filter_map(|(r, m)| {
3312 if !m.is_unmodified_private_file()
3313 || m.flags().contains(MappingFlags::LAZY_PRIVATE_FILE)
3314 || m.name().as_file() != Some(&file)
3315 {
3316 return None;
3317 }
3318 let MappingBacking::Memory(m_backing) = m.get_backing_internal() else {
3319 return None;
3320 };
3321 let m_memory = m_backing.memory();
3322 let same_vmo = *m_memory == memory
3323 || m_memory.get_koid() == *memory_koid.get_or_insert_with(|| memory.get_koid());
3324 same_vmo.then(|| r.clone())
3325 })
3326 .collect();
3327
3328 for run_range in ranges {
3329 let updated = self.mappings.update_exact(&run_range, |mapping| {
3330 if mapping.mapping_mode() == MappingMode::Eager && mapping.can_write() {
3333 context.protect_vmar_range(
3334 run_range.start,
3335 run_range.end - run_range.start,
3336 mapping.flags().access_flags(),
3337 )?;
3338 }
3339 mapping.set_cow_modified();
3340 Ok(())
3341 })?;
3342 assert!(updated, "Expected to update exactly one mapping");
3343 }
3344 Ok(())
3345 }
3346
3347 fn any_writable_private_file_mappings_unmodified(
3350 &self,
3351 addr: UserAddress,
3352 length: usize,
3353 context: &MappingContext,
3354 ) -> Result<bool, Errno> {
3355 Ok(self
3356 .get_contiguous_mappings_at(addr, length, context)?
3357 .take_while(|(mapping, _)| mapping.can_write())
3358 .any(|(mapping, _)| mapping.is_unmodified_private_file()))
3359 }
3360
3361 fn record_writable_private_file_mappings_modified(
3365 &mut self,
3366 addr: UserAddress,
3367 length: usize,
3368 context: &MappingContext,
3369 ) -> Result<(), Errno> {
3370 let mut addrs = SmallVec::<[UserAddress; 1]>::new();
3371 let mut cur_addr = addr;
3372 for (mapping, len) in self.get_contiguous_mappings_at(addr, length, context)? {
3373 if !mapping.can_write() {
3374 break;
3375 }
3376 if mapping.is_unmodified_private_file() {
3377 addrs.push(cur_addr);
3378 }
3379 cur_addr = (cur_addr + len)?;
3380 }
3381 for start_addr in addrs {
3382 self.set_private_file_cow_modified(context, start_addr)?;
3383 }
3384 Ok(())
3385 }
3386
3387 fn mapping_memory<'a>(context: &'a MappingContext, mapping: &'a Mapping) -> &'a MemoryObject {
3389 match mapping.get_backing_internal() {
3390 MappingBacking::PrivateAnonymous => &context.private_anonymous.backing,
3391 MappingBacking::Memory(backing) => backing.memory(),
3392 }
3393 }
3394
3395 fn mapping_vmo<'a>(
3397 context: &'a MappingContext,
3398 mapping: &'a Mapping,
3399 ) -> Result<&'a zx::Vmo, Errno> {
3400 Self::mapping_memory(context, mapping).as_vmo().ok_or_else(|| errno!(EFAULT))
3401 }
3402
3403 fn set_brk(
3404 &mut self,
3405 current_task: &CurrentTask,
3406 mm: &MemoryManager,
3407 addr: UserAddress,
3408 released_mappings: &mut ReleasedMappings,
3409 ) -> Result<UserAddress, Errno> {
3410 let rlimit_data = std::cmp::min(
3411 PROGRAM_BREAK_LIMIT,
3412 current_task.thread_group().get_rlimit(Resource::DATA),
3413 );
3414
3415 let brk = match self.brk.clone() {
3416 None => {
3417 let brk = ProgramBreak { base: self.brk_origin, current: self.brk_origin };
3418 self.brk = Some(brk.clone());
3419 brk
3420 }
3421 Some(brk) => brk,
3422 };
3423
3424 let Ok(last_address) = brk.base + rlimit_data else {
3425 return Ok(brk.current);
3428 };
3429
3430 if addr < brk.base || addr > last_address {
3431 return Ok(brk.current);
3434 }
3435
3436 let old_end = brk.current.round_up(*PAGE_SIZE).unwrap();
3437 let new_end = addr.round_up(*PAGE_SIZE).unwrap();
3438
3439 match new_end.cmp(&old_end) {
3440 std::cmp::Ordering::Less => {
3441 let delta = old_end - new_end;
3445
3446 if self.unmap(mm, new_end, delta, released_mappings).is_err() {
3447 return Ok(brk.current);
3448 }
3449 }
3450 std::cmp::Ordering::Greater => {
3451 let range = old_end..new_end;
3452 let delta = new_end - old_end;
3453
3454 if self.mappings.range(range).next().is_some() {
3456 return Ok(brk.current);
3457 }
3458
3459 if self
3460 .map_anonymous(
3461 mm,
3462 DesiredAddress::FixedOverwrite(old_end),
3463 delta,
3464 ProtectionFlags::READ | ProtectionFlags::WRITE,
3465 MappingOptions::ANONYMOUS,
3466 MappingName::Heap,
3467 released_mappings,
3468 )
3469 .is_err()
3470 {
3471 return Ok(brk.current);
3472 }
3473 }
3474 _ => {}
3475 };
3476
3477 let mut new_brk = brk;
3479 new_brk.current = addr;
3480 self.brk = Some(new_brk);
3481
3482 Ok(addr)
3483 }
3484
3485 fn register_with_uffd(
3486 &mut self,
3487 mm: &MemoryManager,
3488 addr: UserAddress,
3489 length: usize,
3490 userfault: &Arc<UserFault>,
3491 mode: FaultRegisterMode,
3492 released_mappings: &mut ReleasedMappings,
3493 ) -> Result<(), Errno> {
3494 let end_addr = addr.checked_add(length).ok_or_else(|| errno!(EINVAL))?;
3495 let range_for_op = addr..end_addr;
3496 self.ensure_range_mapped_in_user_vmar(addr, Some(length), &mm.mapping_context)?;
3497
3498 let mut updates = vec![];
3499
3500 for (range, mapping) in self.mappings.range(range_for_op.clone()) {
3501 if !mapping.private_anonymous() {
3502 track_stub!(TODO("https://fxbug.dev/391599171"), "uffd for shmem and hugetlbfs");
3503 return error!(EINVAL);
3504 }
3505 if mapping.flags().contains(MappingFlags::UFFD) {
3506 return error!(EBUSY);
3507 }
3508 let range = range.intersect(&range_for_op);
3509 let mut mapping = mapping.clone();
3510 mapping.set_uffd(mode);
3511 updates.push((range, mapping));
3512 }
3513 if updates.is_empty() {
3514 return error!(EINVAL);
3515 }
3516
3517 mm.mapping_context
3518 .protect_vmar_range(addr, length, ProtectionFlags::empty())
3519 .expect("Failed to remove protections on uffd-registered range");
3520
3521 for (range, mapping) in updates {
3523 released_mappings.extend(self.mappings.insert(range, mapping));
3524 }
3525
3526 userfault.insert_pages(range_for_op, false);
3527
3528 Ok(())
3529 }
3530
3531 fn unregister_range_from_uffd(
3532 &mut self,
3533 mm: &MemoryManager,
3534 userfault: &Arc<UserFault>,
3535 addr: UserAddress,
3536 length: usize,
3537 released_mappings: &mut ReleasedMappings,
3538 ) -> Result<(), Errno> {
3539 let end_addr = addr.checked_add(length).ok_or_else(|| errno!(EINVAL))?;
3540 let range_for_op = addr..end_addr;
3541 let mut updates = vec![];
3542
3543 for (range, mapping) in self.mappings.range(range_for_op.clone()) {
3544 if !mapping.private_anonymous() {
3545 track_stub!(TODO("https://fxbug.dev/391599171"), "uffd for shmem and hugetlbfs");
3546 return error!(EINVAL);
3547 }
3548 if mapping.flags().contains(MappingFlags::UFFD) {
3549 let range = range.intersect(&range_for_op);
3550 if userfault.remove_pages(range.clone()) {
3551 let mut mapping = mapping.clone();
3552 mapping.clear_uffd();
3553 updates.push((range, mapping));
3554 }
3555 }
3556 }
3557 for (range, mapping) in updates {
3558 let length = range.end - range.start;
3559 let restored_flags = mapping.vmar_flags().access_flags();
3560
3561 released_mappings.extend(self.mappings.insert(range.clone(), mapping));
3562
3563 mm.mapping_context
3564 .protect_vmar_range(range.start, length, restored_flags)
3565 .expect("Failed to restore original protection bits on uffd-registered range");
3566 }
3567 Ok(())
3568 }
3569
3570 fn unregister_uffd(
3571 &mut self,
3572 mm: &MemoryManager,
3573 userfault: &Arc<UserFault>,
3574 released_mappings: &mut ReleasedMappings,
3575 ) {
3576 let mut updates = vec![];
3577
3578 for (range, mapping) in self.mappings.iter() {
3579 if mapping.flags().contains(MappingFlags::UFFD) {
3580 for range in userfault.get_registered_pages_overlapping_range(range.clone()) {
3581 let mut mapping = mapping.clone();
3582 mapping.clear_uffd();
3583 updates.push((range, mapping));
3584 }
3585 }
3586 }
3587 for (range, mapping) in updates {
3589 let length = range.end - range.start;
3590 let restored_flags = mapping.vmar_flags().access_flags();
3591 released_mappings.extend(self.mappings.insert(range.clone(), mapping));
3592 mm.mapping_context
3594 .protect_vmar_range(range.start, length, restored_flags)
3595 .expect("Failed to restore original protection bits on uffd-registered range");
3596 }
3597
3598 userfault.remove_pages(
3599 UserAddress::from_ptr(RESTRICTED_ASPACE_BASE)
3600 ..UserAddress::from_ptr(RESTRICTED_ASPACE_HIGHEST_ADDRESS),
3601 );
3602
3603 let weak_userfault = Arc::downgrade(userfault);
3604 self.userfaultfds.retain(|uf| !Weak::ptr_eq(uf, &weak_userfault));
3605 }
3606
3607 fn set_mapping_name(
3608 &mut self,
3609 addr: UserAddress,
3610 length: usize,
3611 name: Option<FsString>,
3612 released_mappings: &mut ReleasedMappings,
3613 ) -> Result<(), Errno> {
3614 if addr.ptr() % *PAGE_SIZE as usize != 0 {
3615 return error!(EINVAL);
3616 }
3617 let end = match addr.checked_add(length) {
3618 Some(addr) => addr.round_up(*PAGE_SIZE).map_err(|_| errno!(ENOMEM))?,
3619 None => return error!(EINVAL),
3620 };
3621
3622 let mappings_in_range =
3623 self.mappings.range(addr..end).map(|(r, m)| (r.clone(), m.clone())).collect::<Vec<_>>();
3624
3625 if mappings_in_range.is_empty() {
3626 return error!(EINVAL);
3627 }
3628 if !mappings_in_range.first().unwrap().0.contains(&addr) {
3629 return error!(ENOMEM);
3630 }
3631
3632 let mut last_range_end = None;
3633 for (mut range, mut mapping) in mappings_in_range {
3637 if mapping.name().is_file() {
3638 return error!(EBADF);
3640 }
3641 range.start = std::cmp::max(range.start, addr);
3643 range.end = std::cmp::min(range.end, end);
3645
3646 if let Some(last_range_end) = last_range_end {
3647 if last_range_end != range.start {
3648 return error!(ENOMEM);
3650 }
3651 }
3652 last_range_end = Some(range.end.round_up(*PAGE_SIZE)?);
3653 if let MappingBacking::Memory(backing) = self.get_mapping_backing(&mapping) {
3656 match &name {
3657 Some(memory_name) => {
3658 backing.memory().set_zx_name(memory_name);
3659 }
3660 None => {
3661 backing.memory().set_zx_name(b"");
3662 }
3663 }
3664 }
3665 mapping.set_name(match &name {
3666 Some(name) => MappingName::Vma(FlyByteStr::new(name.as_bytes())),
3667 None => MappingName::None,
3668 });
3669 released_mappings.extend(self.mappings.insert(range, mapping));
3670 }
3671 if let Some(last_range_end) = last_range_end {
3672 if last_range_end < end {
3673 return error!(ENOMEM);
3675 }
3676 }
3677 Ok(())
3678 }
3679}
3680
3681pub struct MlockShadowProcess(memory_pinning::ShadowProcess);
3686
3687impl MemoryManager {
3688 pub fn ensure_range_mapped_in_user_vmar(
3693 &self,
3694 addr: UserAddress,
3695 length: Option<usize>,
3696 ) -> Result<bool, Errno> {
3697 self.ensure_range_mapped_in_user_vmar_for_access(addr, length, MappingAccess::ForReading)
3698 }
3699
3700 fn ensure_range_mapped_in_user_vmar_for_access(
3706 &self,
3707 addr: UserAddress,
3708 length: Option<usize>,
3709 access: MappingAccess,
3710 ) -> Result<bool, Errno> {
3711 self.ensure_ranges_mapped_in_user_vmar_for_access(std::iter::once((addr, length)), access)
3712 }
3713
3714 pub fn ensure_ranges_mapped_in_user_vmar_for_access<I>(
3722 &self,
3723 ranges: I,
3724 access: MappingAccess,
3725 ) -> Result<bool, Errno>
3726 where
3727 I: IntoIterator<Item = (UserAddress, Option<usize>)>,
3728 I::IntoIter: Clone,
3729 {
3730 let ranges = ranges.into_iter();
3731 if !self.state.read().any_ranges_need_vmar_update(ranges.clone(), access) {
3732 return Ok(false);
3733 }
3734 self.state.write().ensure_ranges_mapped_in_user_vmar_for_access(
3735 ranges,
3736 access,
3737 &self.mapping_context,
3738 )
3739 }
3740
3741 pub fn mrelease(&self) -> Result<(), Errno> {
3743 let _state = self.state.write();
3747 let base = UserAddress::from_ptr(self.mapping_context.user_vmar_info.base);
3748 let len = self.mapping_context.user_vmar_info.len;
3749 let end = base.checked_add(len).ok_or_else(|| errno!(EINVAL))?;
3750 self.inflight_vmspliced_payloads
3751 .handle_unmapping(&self.mapping_context.private_anonymous.backing, &(base..end))?;
3752 self.mapping_context.private_anonymous.zero(base, len)?;
3753 *self.cached_stats.lock() = None;
3754 Ok(())
3755 }
3756
3757 pub fn summarize(&self, summary: &mut crate::mm::MappingSummary) {
3758 let state = self.state.read();
3759 for (_, mapping) in state.mappings.iter() {
3760 summary.add(&state, mapping);
3761 }
3762 }
3763
3764 pub fn get_mappings_for_vmsplice(
3767 self: &Arc<MemoryManager>,
3768 buffers: &UserBuffers,
3769 max_bytes: usize,
3770 ) -> Result<Vec<Arc<VmsplicePayload>>, Errno> {
3771 self.state.read().get_mappings_for_vmsplice(self, buffers, max_bytes)
3772 }
3773
3774 pub fn has_same_address_space(&self, other: &Self) -> bool {
3775 std::ptr::eq(self, other)
3776 }
3777
3778 fn mapping_allows_access(&self, addr: UserAddress, is_write: bool) -> bool {
3780 self.state.read().mappings.get(addr).is_some_and(|(_, mapping)| {
3781 if is_write { mapping.can_write() } else { mapping.can_read() }
3782 })
3783 }
3784
3785 fn unified_transfer_loop<F>(
3786 &self,
3787 addr: UserAddress,
3788 len: usize,
3789 is_write: bool,
3790 mut transfer_fn: F,
3791 ) -> Result<usize, Errno>
3792 where
3793 F: FnMut(UserAddress, usize) -> Result<ControlFlow<usize, usize>, Errno>,
3794 {
3795 assert_lock_level::<MemoryManagerStateLock>();
3800 let mut copied = 0;
3801 let mut retried_fault_addr = None;
3803 while copied < len {
3804 match transfer_fn((addr + copied)?, copied)? {
3805 ControlFlow::Continue(num_copied) => {
3806 if num_copied == 0 {
3807 let fault_addr = (addr + copied)?;
3808 let access = if is_write {
3820 MappingAccess::ForWriting
3821 } else {
3822 MappingAccess::ForReading
3823 };
3824 if self.ensure_range_mapped_in_user_vmar_for_access(
3825 fault_addr, None, access,
3826 )? {
3827 continue;
3828 }
3829 match self.extend_growsdown_mapping_to_address(fault_addr, is_write) {
3832 Ok(true) => continue,
3833 Ok(false) => {}
3834 Err(e) => {
3835 log_warn!("Error extending growsdown mapping: {e}");
3836 }
3837 }
3838 if retried_fault_addr != Some(fault_addr)
3843 && self.mapping_allows_access(fault_addr, is_write)
3844 {
3845 retried_fault_addr = Some(fault_addr);
3846 continue;
3847 }
3848 break;
3849 }
3850 copied += num_copied;
3851 }
3852 ControlFlow::Break(num_copied) => {
3853 copied += num_copied;
3854 break;
3855 }
3856 }
3857 }
3858 Ok(copied)
3859 }
3860
3861 unsafe fn finalize_partial_read<'a>(
3869 bytes: &'a mut [MaybeUninit<u8>],
3870 copied: usize,
3871 ) -> Result<&'a mut [u8], Errno> {
3872 if copied == 0 && !bytes.is_empty() {
3873 return error!(EFAULT);
3874 }
3875 let initialized = &mut bytes[..copied];
3876 Ok(unsafe { std::slice::from_raw_parts_mut(initialized.as_mut_ptr() as *mut u8, copied) })
3882 }
3883
3884 pub fn unified_read_memory<'a>(
3885 &self,
3886 current_task: &CurrentTask,
3887 addr: UserAddress,
3888 bytes: &'a mut [MaybeUninit<u8>],
3889 ) -> Result<&'a mut [u8], Errno> {
3890 let total_len = bytes.len();
3891 let bytes_read = self.unified_read_memory_partial(current_task, addr, bytes)?;
3892 if bytes_read.len() < total_len { error!(EFAULT) } else { Ok(bytes_read) }
3893 }
3894
3895 fn syscall_transfer_loop<F>(
3896 &self,
3897 addr: UserAddress,
3898 len: usize,
3899 is_write: bool,
3900 mut transfer_fn: F,
3901 ) -> Result<usize, Errno>
3902 where
3903 F: FnMut(
3904 &MemoryManagerState,
3905 UserAddress,
3906 usize,
3907 ) -> Result<ControlFlow<usize, usize>, Errno>,
3908 {
3909 let mut copied = 0;
3910 while copied < len {
3911 let cur_addr = (addr + copied)?;
3912 let flow = {
3913 let state = self.state.read();
3914 if is_write
3915 && state.any_writable_private_file_mappings_unmodified(
3916 cur_addr,
3917 len - copied,
3918 &self.mapping_context,
3919 )?
3920 {
3921 std::mem::drop(state);
3922 let mut state = self.state.write();
3923 let flow = transfer_fn(&state, cur_addr, copied)?;
3924 let (ControlFlow::Continue(num_copied) | ControlFlow::Break(num_copied)) = flow;
3925 if num_copied > 0 {
3926 if let Err(e) = state.record_writable_private_file_mappings_modified(
3927 cur_addr,
3928 num_copied,
3929 &self.mapping_context,
3930 ) {
3931 log_error!(
3932 "Failed to record private file CoW modification after write: {e}"
3933 );
3934 return Ok(copied + num_copied);
3935 }
3936 }
3937 flow
3938 } else {
3939 transfer_fn(&state, cur_addr, copied)?
3940 }
3941 };
3942 match flow {
3943 ControlFlow::Continue(num_copied) => {
3944 if num_copied == 0 {
3945 match self.extend_growsdown_mapping_to_address(cur_addr, is_write) {
3946 Ok(true) => continue,
3947 Ok(false) => {}
3948 Err(e) => {
3949 log_warn!("Error extending growsdown mapping: {e}");
3950 }
3951 }
3952 break;
3953 }
3954 copied += num_copied;
3955 }
3956 ControlFlow::Break(num_copied) => {
3957 copied += num_copied;
3958 break;
3959 }
3960 }
3961 }
3962 Ok(copied)
3963 }
3964
3965 pub fn syscall_read_memory<'a>(
3966 &self,
3967 addr: UserAddress,
3968 bytes: &'a mut [MaybeUninit<u8>],
3969 ) -> Result<&'a mut [u8], Errno> {
3970 let total_len = bytes.len();
3971 let bytes_read = self.syscall_read_memory_partial(addr, bytes)?;
3972 if bytes_read.len() < total_len { error!(EFAULT) } else { Ok(bytes_read) }
3973 }
3974
3975 pub fn unified_read_memory_partial_until_null_byte<'a>(
3976 &self,
3977 current_task: &CurrentTask,
3978 addr: UserAddress,
3979 bytes: &'a mut [MaybeUninit<u8>],
3980 ) -> Result<&'a mut [u8], Errno> {
3981 debug_assert!(self.has_same_address_space(¤t_task.mm().unwrap()));
3982
3983 let copied = self.unified_transfer_loop(
3984 addr,
3985 bytes.len(),
3986 false,
3987 |cur_addr, offset| {
3988 let (read_bytes, _unread_bytes) =
3989 usercopy().copyin_until_null_byte(cur_addr.ptr(), &mut bytes[offset..]);
3990
3991 let num_copied = read_bytes.len();
3992 if read_bytes.last().map(|b| *b == 0).unwrap_or(false) {
3993 Ok(ControlFlow::Break(num_copied))
3994 } else {
3995 Ok(ControlFlow::Continue(num_copied))
3996 }
3997 },
3998 )?;
3999 unsafe { Self::finalize_partial_read(bytes, copied) }
4003 }
4004
4005 pub fn syscall_read_memory_partial_until_null_byte<'a>(
4006 &self,
4007 addr: UserAddress,
4008 bytes: &'a mut [MaybeUninit<u8>],
4009 ) -> Result<&'a mut [u8], Errno> {
4010 let copied = self.syscall_transfer_loop(
4011 addr,
4012 bytes.len(),
4013 false,
4014 |state, cur_addr, offset| {
4015 let read_bytes = state.read_memory_partial_until_null_byte(
4016 cur_addr,
4017 &mut bytes[offset..],
4018 &self.mapping_context,
4019 )?;
4020 let num_copied = read_bytes.len();
4021 if read_bytes.last().map(|b| *b == 0).unwrap_or(false) {
4022 Ok(ControlFlow::Break(num_copied))
4023 } else {
4024 Ok(ControlFlow::Continue(num_copied))
4025 }
4026 },
4027 )?;
4028 unsafe { Self::finalize_partial_read(bytes, copied) }
4033 }
4034
4035 pub fn unified_read_memory_partial<'a>(
4036 &self,
4037 current_task: &CurrentTask,
4038 addr: UserAddress,
4039 bytes: &'a mut [MaybeUninit<u8>],
4040 ) -> Result<&'a mut [u8], Errno> {
4041 debug_assert!(self.has_same_address_space(¤t_task.mm().unwrap()));
4042
4043 let copied = self.unified_transfer_loop(
4044 addr,
4045 bytes.len(),
4046 false,
4047 |cur_addr, offset| {
4048 let (read_bytes, _unread_bytes) =
4049 usercopy().copyin(cur_addr.ptr(), &mut bytes[offset..]);
4050 Ok(ControlFlow::Continue(read_bytes.len()))
4051 },
4052 )?;
4053 unsafe { Self::finalize_partial_read(bytes, copied) }
4057 }
4058
4059 pub fn syscall_read_memory_partial<'a>(
4060 &self,
4061 addr: UserAddress,
4062 bytes: &'a mut [MaybeUninit<u8>],
4063 ) -> Result<&'a mut [u8], Errno> {
4064 let copied = self.syscall_transfer_loop(
4065 addr,
4066 bytes.len(),
4067 false,
4068 |state, cur_addr, offset| {
4069 let read_bytes = state.read_memory_partial(
4070 cur_addr,
4071 &mut bytes[offset..],
4072 &self.mapping_context,
4073 )?;
4074 Ok(ControlFlow::Continue(read_bytes.len()))
4075 },
4076 )?;
4077 unsafe { Self::finalize_partial_read(bytes, copied) }
4082 }
4083
4084 pub fn unified_write_memory(
4085 &self,
4086 current_task: &CurrentTask,
4087 addr: UserAddress,
4088 bytes: &[u8],
4089 ) -> Result<usize, Errno> {
4090 let copied = self.unified_write_memory_partial(current_task, addr, bytes)?;
4091 if copied < bytes.len() { error!(EFAULT) } else { Ok(copied) }
4092 }
4093
4094 pub fn force_write_memory(
4100 &self,
4101 kernel: &Kernel,
4102 addr: UserAddress,
4103 bytes: &[u8],
4104 ) -> Result<(), Errno> {
4105 let mut state = self.state.write();
4106 let mut released_mappings = ReleasedMappings::default();
4107 let result = state.force_write_memory(
4108 kernel,
4109 &self.mapping_context,
4110 addr,
4111 bytes,
4112 &mut released_mappings,
4113 );
4114 released_mappings.finalize(state);
4115 result
4116 }
4117
4118 pub fn syscall_write_memory(&self, addr: UserAddress, bytes: &[u8]) -> Result<usize, Errno> {
4119 let copied = self.syscall_write_memory_partial(addr, bytes)?;
4120 if copied < bytes.len() { error!(EFAULT) } else { Ok(copied) }
4121 }
4122
4123 pub fn unified_write_memory_partial(
4124 &self,
4125 current_task: &CurrentTask,
4126 addr: UserAddress,
4127 bytes: &[u8],
4128 ) -> Result<usize, Errno> {
4129 debug_assert!(self.has_same_address_space(¤t_task.mm().unwrap()));
4130
4131 let len = bytes.len();
4132 let copied =
4133 self.unified_transfer_loop(addr, len, true, |cur_addr, offset| {
4134 Ok(ControlFlow::Continue(usercopy().copyout(&bytes[offset..], cur_addr.ptr())))
4135 })?;
4136 if copied == 0 && !bytes.is_empty() { error!(EFAULT) } else { Ok(copied) }
4137 }
4138
4139 pub fn syscall_write_memory_partial(
4140 &self,
4141 addr: UserAddress,
4142 bytes: &[u8],
4143 ) -> Result<usize, Errno> {
4144 let len = bytes.len();
4145 let copied = self.syscall_transfer_loop(
4146 addr,
4147 len,
4148 true,
4149 |state, cur_addr, offset| {
4150 Ok(ControlFlow::Continue(state.write_memory_partial(
4151 cur_addr,
4152 &bytes[offset..],
4153 &self.mapping_context,
4154 )?))
4155 },
4156 )?;
4157 if copied == 0 && !bytes.is_empty() { error!(EFAULT) } else { Ok(copied) }
4158 }
4159
4160 pub fn unified_zero(
4161 &self,
4162 current_task: &CurrentTask,
4163 addr: UserAddress,
4164 length: usize,
4165 ) -> Result<usize, Errno> {
4166 debug_assert!(self.has_same_address_space(¤t_task.mm().unwrap()));
4167
4168 {
4169 let page_size = *PAGE_SIZE as usize;
4170 let next_page_boundary = round_up_to_system_page_size(addr.ptr())?;
4173 let length_with_atleast_one_full_page = page_size + (next_page_boundary - addr.ptr());
4176 if length >= length_with_atleast_one_full_page {
4183 return self.syscall_zero(addr, length);
4184 }
4185 }
4186
4187 let copied = self.unified_transfer_loop(
4188 addr,
4189 length,
4190 true,
4191 |cur_addr, offset| {
4192 Ok(ControlFlow::Continue(usercopy().zero(cur_addr.ptr(), length - offset)))
4193 },
4194 )?;
4195 if copied == 0 && length > 0 { error!(EFAULT) } else { Ok(copied) }
4196 }
4197
4198 pub fn syscall_zero(&self, addr: UserAddress, length: usize) -> Result<usize, Errno> {
4199 let copied = self.syscall_transfer_loop(
4200 addr,
4201 length,
4202 true,
4203 |state, cur_addr, offset| {
4204 Ok(ControlFlow::Continue(state.zero_partial(
4205 cur_addr,
4206 length - offset,
4207 &self.mapping_context,
4208 )?))
4209 },
4210 )?;
4211 if copied == 0 && length > 0 { error!(EFAULT) } else { Ok(copied) }
4212 }
4213
4214 pub fn cache_flush(&self, range: Range<UserAddress>) -> Result<(), Errno> {
4216 self.state.read().cache_flush(range, &self.mapping_context)
4217 }
4218
4219 pub fn register_membarrier_private_expedited(
4222 &self,
4223 mtype: MembarrierType,
4224 ) -> Result<(), Errno> {
4225 self.state.write().register_membarrier_private_expedited(mtype)
4226 }
4227
4228 pub fn membarrier_private_expedited_registered(&self, mtype: MembarrierType) -> bool {
4231 self.state.read().membarrier_private_expedited_registered(mtype)
4232 }
4233}
4234
4235pub struct MappingContext {
4245 pub user_vmar: zx::Vmar,
4255
4256 pub user_vmar_info: zx::VmarInfo,
4258
4259 pub private_anonymous: PrivateAnonymousMemoryManager,
4261}
4262
4263impl MappingContext {
4264 fn map_in_user_vmar(
4265 &self,
4266 addr: SelectedAddress,
4267 memory: &MemoryObject,
4268 memory_offset: u64,
4269 length: usize,
4270 flags: MappingFlags,
4271 populate: bool,
4272 ) -> Result<(), Errno> {
4273 map_in_vmar(
4274 &self.user_vmar,
4275 &self.user_vmar_info,
4276 addr,
4277 memory,
4278 memory_offset,
4279 length,
4280 flags,
4281 populate,
4282 )
4283 }
4284
4285 fn protect_vmar_range(
4288 &self,
4289 addr: UserAddress,
4290 length: usize,
4291 prot_flags: ProtectionFlags,
4292 ) -> Result<(), Errno> {
4293 let vmar_flags = prot_flags.to_vmar_flags();
4294 unsafe { self.user_vmar.protect(addr.ptr(), length, vmar_flags) }.map_err(|s| match s {
4296 zx::Status::INVALID_ARGS => errno!(EINVAL),
4297 zx::Status::NOT_FOUND => errno!(ENOMEM),
4298 zx::Status::ACCESS_DENIED => errno!(EACCES),
4299 _ => impossible_error(s),
4300 })
4301 }
4302
4303 fn replace_mapping_memory(
4309 &self,
4310 range: &Range<UserAddress>,
4311 mapping: &mut Mapping,
4312 memory: Arc<MemoryObject>,
4313 ) -> Result<(), Errno> {
4314 let memory_offset = mapping.address_to_offset(range.start);
4315 self.map_in_user_vmar(
4316 SelectedAddress::FixedOverwrite(range.start),
4317 &memory,
4318 memory_offset,
4319 range.end - range.start,
4320 mapping.vmar_flags(),
4321 false,
4322 )?;
4323 let mut backing = MappingBackingMemory::new(range.start, memory, memory_offset);
4324 if mapping.has_cow_modifications() {
4325 backing.set_cow_modified();
4326 }
4327 mapping.set_backing_internal(MappingBacking::Memory(Box::new(backing)));
4328 Ok(())
4329 }
4330
4331 pub fn max_address(&self) -> UserAddress {
4332 UserAddress::from_ptr(self.user_vmar_info.base + self.user_vmar_info.len)
4333 }
4334}
4335
4336pub struct MemoryManager {
4337 pub base_addr: UserAddress,
4339
4340 pub mapping_context: MappingContext,
4342
4343 pub state: LockDepRwLock<MemoryManagerState, MemoryManagerStateLock>,
4345
4346 pub dumpable: AtomicCell<DumpPolicy>,
4348
4349 pub maximum_valid_user_address: UserAddress,
4351
4352 pub inflight_vmspliced_payloads: InflightVmsplicedPayloads,
4361
4362 pub drop_notifier: DropNotifier,
4364
4365 pub arch_width: ArchWidth,
4367
4368 pub cached_stats: LockDepMutex<
4371 Option<(zx::MonotonicInstant, u64, MemoryStats)>,
4372 MemoryManagerCachedStatsLock,
4373 >,
4374}
4375
4376impl ArchSpecific for MemoryManager {
4377 fn is_arch32(&self) -> bool {
4378 self.arch_width.is_arch32()
4379 }
4380}
4381
4382fn check_access_permissions_in_page_fault(
4383 is_write: bool,
4384 is_execute: bool,
4385 mapping: &Mapping,
4386) -> bool {
4387 let exec_denied = is_execute && !mapping.can_exec();
4388 let write_denied = is_write && !mapping.can_write();
4389 let read_denied = (!is_execute && !is_write) && !mapping.can_read();
4390 !exec_denied && !write_denied && !read_denied
4391}
4392
4393impl MemoryManager {
4394 pub fn new_for_test(root_vmar: zx::Unowned<'_, zx::Vmar>, arch_width: ArchWidth) -> Arc<Self> {
4396 Self::new(root_vmar, arch_width, None, None).expect("can create MemoryManager")
4397 }
4398
4399 fn with_zx_mappings<R>(
4402 &self,
4403 current_task: &CurrentTask,
4404 op: impl FnOnce(&[zx::MapInfo]) -> R,
4405 ) -> R {
4406 MapInfoCache::get_or_init(current_task)
4407 .expect("must be able to retrieve map info cache")
4408 .with_map_infos(&self.mapping_context.user_vmar, |infos| match infos {
4409 Ok(infos) => op(infos),
4410 Err(_) => op(&[]),
4411 })
4412 }
4413
4414 pub fn total_locked_bytes(&self) -> u64 {
4415 self.state.read().num_locked_bytes(
4416 UserAddress::from(self.mapping_context.user_vmar_info.base as u64)
4417 ..UserAddress::from(
4418 (self.mapping_context.user_vmar_info.base
4419 + self.mapping_context.user_vmar_info.len) as u64,
4420 ),
4421 )
4422 }
4423
4424 fn new(
4428 root_vmar: zx::Unowned<'_, zx::Vmar>,
4429 arch_width: ArchWidth,
4430 executable_node: Option<NamespaceNode>,
4431 private_anonymous: Option<PrivateAnonymousMemoryManager>,
4432 ) -> Result<Arc<Self>, Errno> {
4433 debug_assert!(!root_vmar.is_invalid());
4434
4435 let mut vmar_info = root_vmar.info().map_err(|status| from_status_like_fdio!(status))?;
4436 if arch_width.is_arch32() {
4437 vmar_info.len = (LOWER_4GB_LIMIT.ptr() - vmar_info.base) as usize;
4438 }
4439
4440 let (user_vmar, ptr) = root_vmar
4441 .allocate(
4442 0,
4443 vmar_info.len,
4444 zx::VmarFlags::SPECIFIC
4445 | zx::VmarFlags::CAN_MAP_SPECIFIC
4446 | zx::VmarFlags::CAN_MAP_READ
4447 | zx::VmarFlags::CAN_MAP_WRITE
4448 | zx::VmarFlags::CAN_MAP_EXECUTE,
4449 )
4450 .map_err(|status| from_status_like_fdio!(status))?;
4451 assert_eq!(ptr, vmar_info.base);
4452
4453 let user_vmar_info = user_vmar.info().map_err(|status| from_status_like_fdio!(status))?;
4454
4455 debug_assert_eq!(RESTRICTED_ASPACE_BASE, user_vmar_info.base);
4457 if arch_width.is_arch32() {
4458 debug_assert_eq!(LOWER_4GB_LIMIT.ptr() - user_vmar_info.base, user_vmar_info.len);
4459 } else {
4460 debug_assert_eq!(RESTRICTED_ASPACE_SIZE, user_vmar_info.len);
4461 }
4462
4463 let backing_size = (user_vmar_info.base + user_vmar_info.len) as u64;
4468
4469 let stack_origin = UserAddress::from_ptr(
4472 user_vmar_info.base + user_vmar_info.len - generate_random_offset_for_aslr(arch_width),
4473 )
4474 .round_up(*PAGE_SIZE)?;
4475
4476 let mmap_top = stack_origin
4479 .checked_sub(MAX_STACK_SIZE + generate_random_offset_for_aslr(arch_width))
4480 .ok_or_else(|| errno!(EINVAL))?;
4481
4482 Ok(Arc::new(MemoryManager {
4483 base_addr: UserAddress::from_ptr(user_vmar_info.base),
4484 mapping_context: MappingContext {
4485 user_vmar,
4486 user_vmar_info,
4487 private_anonymous: private_anonymous
4488 .unwrap_or_else(|| PrivateAnonymousMemoryManager::new(backing_size)),
4489 },
4490 state: MemoryManagerState {
4491 mappings: Default::default(),
4492 userfaultfds: Default::default(),
4493 shadow_mappings_for_mlock: Default::default(),
4494 forkable_state: MemoryManagerForkableState {
4495 executable_node,
4496 stack_origin,
4497 mmap_top,
4498 ..Default::default()
4499 },
4500 }
4501 .into(),
4502 dumpable: AtomicCell::new(DumpPolicy::User),
4503 maximum_valid_user_address: UserAddress::from_ptr(
4504 user_vmar_info.base + user_vmar_info.len,
4505 ),
4506 inflight_vmspliced_payloads: Default::default(),
4507 drop_notifier: DropNotifier::default(),
4508 arch_width,
4509 cached_stats: LockDepMutex::default(),
4510 }))
4511 }
4512
4513 pub fn set_brk(
4514 self: &Arc<Self>,
4515 current_task: &CurrentTask,
4516 addr: UserAddress,
4517 ) -> Result<UserAddress, Errno> {
4518 let mut state = self.state.write();
4519 let mut released_mappings = ReleasedMappings::default();
4520 let result = state.set_brk(current_task, self, addr, &mut released_mappings);
4521 released_mappings.finalize(state);
4522 result
4523 }
4524
4525 pub fn register_uffd(&self, userfault: &Arc<UserFault>) {
4526 let mut state = self.state.write();
4527 state.userfaultfds.push(Arc::downgrade(userfault));
4528 }
4529
4530 pub fn register_with_uffd(
4532 self: &Arc<Self>,
4533 addr: UserAddress,
4534 length: usize,
4535 userfault: &Arc<UserFault>,
4536 mode: FaultRegisterMode,
4537 ) -> Result<(), Errno> {
4538 let mut state = self.state.write();
4539 let mut released_mappings = ReleasedMappings::default();
4540 let result =
4541 state.register_with_uffd(self, addr, length, userfault, mode, &mut released_mappings);
4542 released_mappings.finalize(state);
4543 result
4544 }
4545
4546 pub fn unregister_range_from_uffd(
4548 &self,
4549 userfault: &Arc<UserFault>,
4550 addr: UserAddress,
4551 length: usize,
4552 ) -> Result<(), Errno> {
4553 let mut state = self.state.write();
4554 let mut released_mappings = ReleasedMappings::default();
4555 let result =
4556 state.unregister_range_from_uffd(self, userfault, addr, length, &mut released_mappings);
4557 released_mappings.finalize(state);
4558 result
4559 }
4560
4561 pub fn unregister_uffd(&self, userfault: &Arc<UserFault>) {
4564 let mut state = self.state.write();
4565 let mut released_mappings = ReleasedMappings::default();
4566 state.unregister_uffd(self, userfault, &mut released_mappings);
4567 released_mappings.finalize(state);
4568 }
4569
4570 pub fn populate_from_uffd<F>(
4576 &self,
4577 addr: UserAddress,
4578 length: usize,
4579 userfault: &Arc<UserFault>,
4580 populate: F,
4581 ) -> Result<usize, Errno>
4582 where
4583 F: FnOnce(&MemoryManagerState, usize) -> Result<usize, Errno>,
4584 {
4585 let state = self.state.read();
4586 let mut bytes_registered_with_uffd = 0;
4589 for (mapping, len) in
4590 state.get_contiguous_mappings_at(addr, length, &self.mapping_context)?
4591 {
4592 if mapping.flags().contains(MappingFlags::UFFD) {
4593 if !userfault.contains_addr(addr) {
4596 track_stub!(
4597 TODO("https://fxbug.dev/391599171"),
4598 "operations across different uffds"
4599 );
4600 return error!(ENOTSUP);
4601 };
4602 } else {
4603 return error!(ENOENT);
4604 }
4605 bytes_registered_with_uffd += len;
4606 }
4607 if bytes_registered_with_uffd != length {
4608 return error!(ENOENT);
4609 }
4610
4611 let end_addr = addr.checked_add(length).ok_or_else(|| errno!(EINVAL))?;
4612
4613 let first_populated =
4615 userfault.get_first_populated_page_after(addr).ok_or_else(|| errno!(ENOENT))?;
4616 if first_populated == addr {
4618 return error!(EEXIST);
4619 }
4620 let trimmed_end = std::cmp::min(first_populated, end_addr);
4623 let effective_length = trimmed_end - addr;
4624
4625 populate(&state, effective_length)?;
4626 userfault.insert_pages(addr..trimmed_end, true);
4627
4628 for (range, mapping) in state.mappings.range(addr..trimmed_end) {
4633 let range_to_protect = range.intersect(&(addr..trimmed_end));
4634 let restored_flags = mapping.vmar_flags().access_flags();
4635 let length = range_to_protect.end - range_to_protect.start;
4636 self.mapping_context
4637 .protect_vmar_range(range_to_protect.start, length, restored_flags)
4638 .expect("Failed to restore original protection bits on uffd-registered range");
4639 }
4640 Ok(effective_length)
4643 }
4644
4645 pub fn zero_from_uffd(
4646 &self,
4647 addr: UserAddress,
4648 length: usize,
4649 userfault: &Arc<UserFault>,
4650 ) -> Result<usize, Errno> {
4651 self.populate_from_uffd(addr, length, userfault, |state, effective_length| {
4652 state.zero(addr, effective_length, &self.mapping_context)
4653 })
4654 }
4655
4656 pub fn fill_from_uffd(
4657 &self,
4658 addr: UserAddress,
4659 buf: &[u8],
4660 length: usize,
4661 userfault: &Arc<UserFault>,
4662 ) -> Result<usize, Errno> {
4663 self.populate_from_uffd(addr, length, userfault, |state, effective_length| {
4664 state.write_memory(addr, &buf[..effective_length], &self.mapping_context)
4665 })
4666 }
4667
4668 pub fn copy_from_uffd(
4669 &self,
4670 source_addr: UserAddress,
4671 dst_addr: UserAddress,
4672 length: usize,
4673 userfault: &Arc<UserFault>,
4674 ) -> Result<usize, Errno> {
4675 self.populate_from_uffd(dst_addr, length, userfault, |state, effective_length| {
4676 let mut buf = vec![std::mem::MaybeUninit::uninit(); effective_length];
4677 let buf = state.read_memory(source_addr, &mut buf, &self.mapping_context)?;
4678 state.write_memory(dst_addr, &buf[..effective_length], &self.mapping_context)
4679 })
4680 }
4681
4682 pub fn snapshot_of(
4686 source_mm: &Arc<MemoryManager>,
4687 root_vmar: zx::Unowned<'_, zx::Vmar>,
4688 arch_width: ArchWidth,
4689 ) -> Result<Arc<Self>, Errno> {
4690 fuchsia_trace::duration!(CATEGORY_STARNIX_MM, "snapshot_of");
4691 let backing_size = (source_mm.mapping_context.user_vmar_info.base
4692 + source_mm.mapping_context.user_vmar_info.len) as u64;
4693 let private_anonymous =
4694 source_mm.mapping_context.private_anonymous.snapshot(backing_size)?;
4695 let target = MemoryManager::new(
4696 root_vmar,
4697 arch_width,
4698 source_mm.executable_node(),
4699 Some(private_anonymous),
4700 )?;
4701
4702 {
4705 let (state, mut target_state) = ordered_write_lock(&source_mm.state, &target.state);
4706 debug_assert_eq!(
4707 source_mm.mapping_context.user_vmar_info,
4708 target.mapping_context.user_vmar_info
4709 );
4710
4711 let mut clone_cache = HashMap::<zx::Koid, ForkedMemory>::with_capacity(64);
4713
4714 for (range, mapping) in state.mappings.iter() {
4715 if mapping.flags().contains(MappingFlags::DONTFORK) {
4716 continue;
4717 }
4718 let target_mapping_flags = mapping.flags().difference(
4720 MappingFlags::LOCKED | MappingFlags::UFFD | MappingFlags::UFFD_MISSING,
4721 );
4722 match state.get_mapping_backing(mapping) {
4723 MappingBacking::Memory(backing) => {
4724 fuchsia_trace::duration!(CATEGORY_STARNIX_MM, "memory_backing_clone");
4725 let memory_offset = backing.address_to_offset(range.start);
4726
4727 let target_memory = if mapping.flags().contains(MappingFlags::SHARED)
4728 || mapping.name().is_vvar()
4729 {
4730 backing.memory().clone()
4733 } else {
4734 let memory_obj = backing.memory();
4735 let options = mapping.flags().options();
4736 let mut rights = memory_obj.get_rights();
4737 if mapping.flags().contains(MappingFlags::WRITE) {
4738 rights |= zx::Rights::WRITE;
4739 }
4740 clone_cache
4741 .entry(memory_obj.get_koid())
4742 .or_default()
4743 .get_or_clone(memory_obj, rights, options)?
4744 };
4745
4746 let mut target_backing =
4747 MappingBackingMemory::new(range.start, target_memory, memory_offset);
4748 if mapping.has_cow_modifications() {
4749 target_backing.set_cow_modified();
4750 }
4751 let mapping = Mapping::with_name(
4752 MappingBacking::Memory(Box::new(target_backing)),
4753 target_mapping_flags,
4754 mapping.name().to_owned(),
4755 MappingMode::Lazy,
4756 );
4757 assert!(
4758 target_state.mappings.append_non_overlapping(range.clone(), mapping)
4759 );
4760 }
4761 MappingBacking::PrivateAnonymous => {
4762 fuchsia_trace::duration!(
4763 CATEGORY_STARNIX_MM,
4764 "private_anonymous_backing_clone"
4765 );
4766 let length = range.end - range.start;
4767 if mapping.flags().contains(MappingFlags::WIPEONFORK) {
4768 target
4769 .mapping_context
4770 .private_anonymous
4771 .zero(range.start, length)
4772 .map_err(|_| errno!(ENOMEM))?;
4773 }
4774
4775 let mapping = Mapping::new_private_anonymous(
4776 target_mapping_flags,
4777 mapping.name().to_owned(),
4778 MappingMode::Lazy,
4779 );
4780 assert!(
4781 target_state.mappings.append_non_overlapping(range.clone(), mapping)
4782 );
4783 }
4784 };
4785 }
4786
4787 target_state.forkable_state = state.forkable_state.clone();
4788 }
4789
4790 target.dumpable.store(source_mm.dumpable.load());
4791
4792 Ok(target)
4793 }
4794
4795 pub fn exec(
4804 root_vmar: zx::Unowned<'_, zx::Vmar>,
4805 old_mm: Option<Arc<Self>>,
4806 exe_node: NamespaceNode,
4807 arch_width: ArchWidth,
4808 ) -> Result<Arc<Self>, Errno> {
4809 if let Some(old_mm) = old_mm {
4817 let _old_mappings = {
4818 let mut state = old_mm.state.write();
4819
4820 unsafe {
4823 old_mm
4824 .mapping_context
4825 .user_vmar
4826 .destroy()
4827 .map_err(|status| from_status_like_fdio!(status))?
4828 }
4829
4830 std::mem::replace(&mut state.mappings, Default::default())
4831 };
4832 }
4833
4834 Self::new(root_vmar, arch_width, Some(exe_node), None)
4835 }
4836
4837 pub fn initialize_brk_origin(
4838 &self,
4839 arch_width: ArchWidth,
4840 executable_end: UserAddress,
4841 ) -> Result<(), Errno> {
4842 self.state.write().brk_origin = executable_end
4843 .checked_add(generate_random_offset_for_aslr(arch_width))
4844 .ok_or_else(|| errno!(EINVAL))?;
4845 Ok(())
4846 }
4847
4848 pub fn get_random_base_for_executable(
4850 &self,
4851 arch_width: ArchWidth,
4852 length: usize,
4853 ) -> Result<UserAddress, Errno> {
4854 let state = self.state.read();
4855
4856 let base = round_up_to_system_page_size(2 * state.mmap_top.ptr() / 3).unwrap()
4858 + generate_random_offset_for_aslr(arch_width);
4859 if base.checked_add(length).ok_or_else(|| errno!(EINVAL))? <= state.mmap_top.ptr() {
4860 Ok(UserAddress::from_ptr(base))
4861 } else {
4862 error!(EINVAL)
4863 }
4864 }
4865 pub fn executable_node(&self) -> Option<NamespaceNode> {
4866 self.state.read().executable_node.clone()
4867 }
4868
4869 #[track_caller]
4870 pub fn get_errno_for_map_err(status: zx::Status) -> Errno {
4871 match status {
4872 zx::Status::INVALID_ARGS => errno!(EINVAL),
4873 zx::Status::ACCESS_DENIED => errno!(EPERM),
4874 zx::Status::NOT_SUPPORTED => errno!(ENODEV),
4875 zx::Status::NO_MEMORY => errno!(ENOMEM),
4876 zx::Status::NO_RESOURCES => errno!(ENOMEM),
4877 zx::Status::OUT_OF_RANGE => errno!(ENOMEM),
4878 zx::Status::ALREADY_EXISTS => errno!(EEXIST),
4879 zx::Status::BAD_STATE => errno!(EINVAL),
4880 _ => impossible_error(status),
4881 }
4882 }
4883
4884 #[track_caller]
4885 pub fn get_errno_for_vmo_err(status: zx::Status) -> Errno {
4886 match status {
4887 zx::Status::NO_MEMORY => errno!(ENOMEM),
4888 zx::Status::ACCESS_DENIED => errno!(EPERM),
4889 zx::Status::NOT_SUPPORTED => errno!(EIO),
4890 zx::Status::BAD_STATE => errno!(EIO),
4891 _ => return impossible_error(status),
4892 }
4893 }
4894
4895 pub fn map_memory(
4896 self: &Arc<Self>,
4897 addr: DesiredAddress,
4898 memory: Arc<MemoryObject>,
4899 memory_offset: u64,
4900 length: usize,
4901 prot_flags: ProtectionFlags,
4902 options: MappingOptions,
4903 name: MappingName,
4904 ) -> Result<UserAddress, Errno> {
4905 let flags = MappingFlags::from_access_flags_and_options(prot_flags, options);
4906
4907 let mut released_mappings = ReleasedMappings::default();
4909 let mut state = self.state.write();
4912 let result = state.add_memory_mapping(
4913 self,
4914 addr,
4915 memory,
4916 memory_offset,
4917 length,
4918 flags,
4919 options.contains(MappingOptions::POPULATE),
4920 false,
4921 name,
4922 MappingMode::Eager,
4923 &mut released_mappings,
4924 );
4925
4926 released_mappings.finalize(state);
4929
4930 result
4931 }
4932
4933 pub fn map_anonymous(
4934 self: &Arc<Self>,
4935 addr: DesiredAddress,
4936 length: usize,
4937 prot_flags: ProtectionFlags,
4938 options: MappingOptions,
4939 name: MappingName,
4940 ) -> Result<UserAddress, Errno> {
4941 let mut released_mappings = ReleasedMappings::default();
4942 let mut state = self.state.write();
4945 let result = state.map_anonymous(
4946 self,
4947 addr,
4948 length,
4949 prot_flags,
4950 options,
4951 name,
4952 &mut released_mappings,
4953 );
4954
4955 released_mappings.finalize(state);
4956
4957 result
4958 }
4959
4960 pub fn map_stack(
4962 self: &Arc<Self>,
4963 length: usize,
4964 prot_flags: ProtectionFlags,
4965 ) -> Result<UserAddress, Errno> {
4966 assert!(length <= MAX_STACK_SIZE);
4967 let addr = (self.state.read().stack_origin - length)?;
4968 let stack_addr = self.map_anonymous(
4975 DesiredAddress::Hint(addr),
4976 length,
4977 prot_flags,
4978 MappingOptions::ANONYMOUS | MappingOptions::GROWSDOWN,
4979 MappingName::Stack,
4980 )?;
4981 if stack_addr != addr {
4982 log_warn!(
4983 "An address designated for stack ({}) was unavailable, mapping at {} instead.",
4984 addr,
4985 stack_addr
4986 );
4987 }
4988 Ok(stack_addr)
4989 }
4990
4991 pub fn remap(
4992 self: &Arc<Self>,
4993 current_task: &CurrentTask,
4994 addr: UserAddress,
4995 old_length: usize,
4996 new_length: usize,
4997 flags: MremapFlags,
4998 new_addr: UserAddress,
4999 ) -> Result<UserAddress, Errno> {
5000 let mut released_mappings = ReleasedMappings::default();
5001 let mut state = self.state.write();
5004 let result = state.remap(
5005 current_task,
5006 self,
5007 addr,
5008 old_length,
5009 new_length,
5010 flags,
5011 new_addr,
5012 &mut released_mappings,
5013 );
5014
5015 released_mappings.finalize(state);
5016
5017 result
5018 }
5019
5020 pub fn unmap(self: &Arc<Self>, addr: UserAddress, length: usize) -> Result<(), Errno> {
5021 let mut released_mappings = ReleasedMappings::default();
5022 let mut state = self.state.write();
5025 let result = state.unmap(self, addr, length, &mut released_mappings);
5026
5027 released_mappings.finalize(state);
5028
5029 result
5030 }
5031
5032 pub fn protect(
5033 &self,
5034 current_task: &CurrentTask,
5035 addr: UserAddress,
5036 length: usize,
5037 prot_flags: ProtectionFlags,
5038 ) -> Result<(), Errno> {
5039 let page_size = *PAGE_SIZE;
5040 if !addr.is_aligned(page_size) {
5041 return error!(EINVAL);
5042 }
5043 if length == 0 {
5044 return Ok(());
5045 }
5046 let end = addr.checked_add(length).ok_or_else(|| errno!(ENOMEM))?.round_up(page_size)?;
5047 if end > self.maximum_valid_user_address {
5048 return error!(ENOMEM);
5049 }
5050
5051 let personality = current_task.thread_group().read().personality;
5052 let may_add_exec = prot_flags.contains(ProtectionFlags::EXEC)
5054 || (prot_flags.contains(ProtectionFlags::READ)
5055 && personality.contains(PersonalityFlags::READ_IMPLIES_EXEC));
5056
5057 let mut probes = ExecutableMemoryProbes::default();
5060 let mut state = loop {
5061 let state = self.state.write();
5062 if !may_add_exec {
5063 break state;
5064 }
5065 let Ok(prot_range) = state.protection_range(addr, end, prot_flags) else {
5069 break state;
5070 };
5071 let unprobed_files = probes.unprobed_files(&state, prot_range);
5072 if unprobed_files.is_empty() {
5073 break state;
5074 }
5075 std::mem::drop(state);
5076 probes.probe(current_task, unprobed_files);
5077 };
5078 let mut released_mappings = ReleasedMappings::default();
5079 let result = state.protect(
5080 current_task,
5081 addr,
5082 length,
5083 prot_flags,
5084 personality,
5085 &probes,
5086 &mut released_mappings,
5087 );
5088 released_mappings.finalize(state);
5089 result
5090 }
5091
5092 pub fn msync(
5093 &self,
5094 current_task: &CurrentTask,
5095 addr: UserAddress,
5096 length: usize,
5097 flags: MsyncFlags,
5098 ) -> Result<(), Errno> {
5099 if flags.contains(MsyncFlags::ASYNC) && flags.contains(MsyncFlags::SYNC) {
5107 return error!(EINVAL);
5108 }
5109
5110 if !addr.is_aligned(*PAGE_SIZE) {
5111 return error!(EINVAL);
5112 }
5113
5114 let mut nodes_to_sync = {
5119 let mm_state = self.state.read();
5120
5121 let length_rounded = round_up_to_system_page_size(length)?;
5122 let end_addr = addr.checked_add(length_rounded).ok_or_else(|| errno!(EINVAL))?;
5123
5124 let mut last_end = addr;
5125 let mut nodes = vec![];
5126 for (range, mapping) in mm_state.mappings.range(addr..end_addr) {
5127 if range.start > last_end {
5130 return error!(ENOMEM);
5131 }
5132 last_end = range.end;
5133
5134 if flags.contains(MsyncFlags::INVALIDATE)
5135 && mapping.flags().contains(MappingFlags::LOCKED)
5136 {
5137 return error!(EBUSY);
5138 }
5139
5140 if flags.contains(MsyncFlags::SYNC) {
5141 if let MappingNameRef::File(file_mapping) = mapping.name() {
5142 nodes.push(file_mapping.node().clone());
5143 }
5144 }
5145 }
5146 if last_end < end_addr {
5147 return error!(ENOMEM);
5148 }
5149 nodes
5150 };
5151
5152 nodes_to_sync.sort_by_key(|n| Arc::as_ptr(n) as usize);
5154 nodes_to_sync.dedup_by(|a, b| Arc::ptr_eq(a, b));
5155
5156 for node in nodes_to_sync {
5157 node.ops().sync(&node, current_task)?;
5163 }
5164 Ok(())
5165 }
5166
5167 pub fn madvise(
5168 &self,
5169 current_task: &CurrentTask,
5170 addr: UserAddress,
5171 length: usize,
5172 advice: u32,
5173 ) -> Result<(), Errno> {
5174 match MadviseAdvice::from_raw(advice) {
5175 MadviseAdvice::UpdateFlags(advice) => {
5176 let mut state = self.state.write();
5177 let mut released_mappings = ReleasedMappings::default();
5178 let result = state.madvise_update_flags(
5179 &self.mapping_context,
5180 addr,
5181 length,
5182 advice,
5183 &mut released_mappings,
5184 );
5185 released_mappings.finalize(state);
5186 result
5187 }
5188 MadviseAdvice::ReadOnly(advice) => {
5189 let state = self.state.read();
5190 state.madvise_read_only(current_task, &self.mapping_context, addr, length, advice)
5191 }
5192 }
5193 }
5194
5195 pub fn mlock(
5196 &self,
5197 current_task: &CurrentTask,
5198 desired_addr: UserAddress,
5199 desired_length: usize,
5200 on_fault: bool,
5201 ) -> Result<(), Errno> {
5202 let mut state = self.state.write();
5203 let mut released_mappings = ReleasedMappings::default();
5204 let result = state.mlock(
5205 &self.mapping_context,
5206 current_task,
5207 desired_addr,
5208 desired_length,
5209 on_fault,
5210 &mut released_mappings,
5211 );
5212 released_mappings.finalize(state);
5213 *self.cached_stats.lock() = None;
5214 result
5215 }
5216
5217 pub fn munlock(
5218 &self,
5219 current_task: &CurrentTask,
5220 desired_addr: UserAddress,
5221 desired_length: usize,
5222 ) -> Result<(), Errno> {
5223 let mut state = self.state.write();
5224 let mut released_mappings = ReleasedMappings::default();
5225 let result =
5226 state.munlock(current_task, desired_addr, desired_length, &mut released_mappings);
5227 released_mappings.finalize(state);
5228 *self.cached_stats.lock() = None;
5229 result
5230 }
5231
5232 pub fn log_memory_map(&self, task: &Task, fault_address: UserAddress) {
5233 let fs_context = task.fs();
5234 let state = self.state.read();
5235 log_warn!("Memory map for pid={}:", task.pid);
5236 let mut last_end = UserAddress::from_ptr(0);
5237 for (range, map) in state.mappings.iter() {
5238 if fault_address >= last_end && fault_address < range.start {
5239 log_warn!("{:08x} <= FAULT", fault_address.ptr());
5240 }
5241
5242 let perms = format!(
5243 "{}{}{}{}",
5244 if map.can_read() { 'r' } else { '-' },
5245 if map.can_write() { 'w' } else { '-' },
5246 if map.can_exec() { 'x' } else { '-' },
5247 if map.flags().contains(MappingFlags::SHARED) { 's' } else { 'p' }
5248 );
5249
5250 let backing = match state.get_mapping_backing(map) {
5251 MappingBacking::Memory(backing) => backing.address_to_offset(range.start),
5252 MappingBacking::PrivateAnonymous => 0,
5253 };
5254
5255 let name_str = match &map.name() {
5256 MappingNameRef::File(file) => {
5257 let Ok(ref fs) = fs_context else {
5258 log_warn!("Task {} is not running", task.get_tid());
5259 continue;
5260 };
5261 String::from_utf8_lossy(&file.name().path(fs)).into_owned()
5262 }
5263 MappingNameRef::None | MappingNameRef::AioContext(_) => {
5264 if map.flags().contains(MappingFlags::SHARED)
5265 && map.flags().contains(MappingFlags::ANONYMOUS)
5266 {
5267 "/dev/zero (deleted)".to_string()
5268 } else {
5269 "".to_string()
5270 }
5271 }
5272 MappingNameRef::Stack => "[stack]".to_string(),
5273 MappingNameRef::Heap => "[heap]".to_string(),
5274 MappingNameRef::Vdso => "[vdso]".to_string(),
5275 MappingNameRef::Vvar => "[vvar]".to_string(),
5276 _ => format!("{:?}", map.name()),
5277 };
5278
5279 let fault_marker = if range.contains(&fault_address) { " <= FAULT" } else { "" };
5280
5281 log_warn!(
5282 "{:08x}-{:08x} {} {:08x} {}{}",
5283 range.start.ptr(),
5284 range.end.ptr(),
5285 perms,
5286 backing,
5287 name_str,
5288 fault_marker
5289 );
5290 last_end = range.end;
5291 }
5292
5293 if fault_address >= last_end {
5294 log_warn!("{:08x} <= FAULT", fault_address.ptr());
5295 }
5296 }
5297
5298 pub fn handle_page_fault(
5299 self: &Arc<Self>,
5300 decoded: PageFaultExceptionReport,
5301 error_code: zx::Status,
5302 ) -> ExceptionResult {
5303 let PageFaultExceptionReport {
5304 faulting_address: raw_faulting_address,
5305 not_present,
5306 is_write,
5307 is_execute,
5308 } = decoded;
5309 #[cfg(target_arch = "aarch64")]
5310 let addr = if self.is_arch64() {
5313 UserAddress::from(raw_faulting_address & 0x00FF_FFFF_FFFF_FFFF)
5314 } else {
5315 UserAddress::from(raw_faulting_address)
5316 };
5317 #[cfg(not(target_arch = "aarch64"))]
5318 let addr = UserAddress::from(raw_faulting_address);
5319
5320 let mut checked_vmar_mapping = false;
5324 if error_code == zx::Status::ACCESS_DENIED {
5325 let state = self.state.read();
5326 if let Some((_, mapping)) = state.mappings.get(addr) {
5327 if check_access_permissions_in_page_fault(is_write, is_execute, mapping) {
5328 if mapping.flags().contains(MappingFlags::UFFD) {
5330 assert!(mapping.flags().contains(MappingFlags::UFFD_MISSING));
5332
5333 if let Some(_uffd) = state.find_uffd(addr) {
5334 return ExceptionResult::Signal(SignalInfo::with_detail(
5340 SIGBUS,
5341 BUS_ADRERR as i32,
5342 SignalDetail::SigFault { addr: raw_faulting_address },
5343 ));
5344 };
5345 }
5346 if is_write && !mapping.vmar_flags().contains(MappingFlags::WRITE) {
5347 std::mem::drop(state);
5348 checked_vmar_mapping = true;
5349 let mut state = self.state.write();
5350 match state.ensure_range_mapped_in_user_vmar_for_access(
5351 addr,
5352 None,
5353 MappingAccess::ForWriting,
5354 &self.mapping_context,
5355 ) {
5356 Ok(true) => return ExceptionResult::Handled,
5357 Ok(false) => {
5358 if state.mappings.get(addr).is_some_and(|(_, m)| m.can_write()) {
5362 return ExceptionResult::Handled;
5363 }
5364 }
5365 Err(e) => {
5366 log_error!("Failed to enable write access to mapping: {e}");
5367 }
5368 }
5369 } else {
5370 if !(is_write && mapping.is_private_file()) {
5375 track_stub!(
5376 TODO("https://fxbug.dev/435171399"),
5377 "Inconsistent permission fault"
5378 );
5379 }
5380 return ExceptionResult::Handled;
5381 }
5382 }
5383 }
5384 }
5385
5386 if not_present {
5387 if !checked_vmar_mapping {
5388 let access =
5389 if is_write { MappingAccess::ForWriting } else { MappingAccess::ForReading };
5390 let mut state = self.state.write();
5391 match state.ensure_range_mapped_in_user_vmar_for_access(
5392 addr,
5393 None,
5394 access,
5395 &self.mapping_context,
5396 ) {
5397 Ok(true) => return ExceptionResult::Handled,
5398 Ok(false) => {
5399 let current_gen = state.mappings.generation;
5405 let old_gen = LAST_SEEN_MAPPING_GENERATION.with(|c| c.replace(current_gen));
5406 if current_gen != old_gen {
5407 return ExceptionResult::Handled;
5408 }
5409 }
5410 Err(e) => {
5411 log_error!("Failed to map lazy memory: {e}")
5412 }
5413 }
5414 }
5415
5416 match self.extend_growsdown_mapping_to_address(addr, is_write) {
5422 Ok(true) => {
5423 return ExceptionResult::Handled;
5424 }
5425 Err(e) => {
5426 log_warn!("Error handling page fault: {e}")
5427 }
5428 _ => {}
5429 }
5430 }
5431
5432 let (signo, si_code) = match error_code {
5440 zx::Status::OUT_OF_RANGE => (SIGBUS, linux_uapi::BUS_ADRERR as i32),
5441 _ => {
5442 let code = if self.state.read().mappings.get(addr).is_some() {
5443 linux_uapi::SEGV_ACCERR
5444 } else {
5445 linux_uapi::SEGV_MAPERR
5446 };
5447 (SIGSEGV, code as i32)
5448 }
5449 };
5450 ExceptionResult::Signal(SignalInfo::with_detail(
5451 signo,
5452 si_code,
5453 SignalDetail::SigFault { addr: raw_faulting_address },
5454 ))
5455 }
5456
5457 pub fn set_mapping_name(
5458 &self,
5459 addr: UserAddress,
5460 length: usize,
5461 name: Option<FsString>,
5462 ) -> Result<(), Errno> {
5463 let mut state = self.state.write();
5464 let mut released_mappings = ReleasedMappings::default();
5465 let result = state.set_mapping_name(addr, length, name, &mut released_mappings);
5466 released_mappings.finalize(state);
5467 result
5468 }
5469
5470 pub fn ensure_mapped(&self, addr: UserAddress, length: usize) -> Result<(), Errno> {
5480 if !addr.is_aligned(*PAGE_SIZE) {
5481 return error!(EINVAL);
5482 }
5483
5484 let length = round_up_to_system_page_size(length)?;
5485 let end_addr = addr.checked_add(length).ok_or_else(|| errno!(EINVAL))?;
5486 let state = self.state.read();
5487 let mut last_end = addr;
5488 for (range, _) in state.mappings.range(addr..end_addr) {
5489 if range.start > last_end {
5490 return error!(ENOMEM);
5492 }
5493 last_end = range.end;
5494 }
5495 if last_end < end_addr {
5496 error!(ENOMEM)
5498 } else {
5499 Ok(())
5500 }
5501 }
5502
5503 pub fn get_mapping_memory(
5506 &self,
5507 addr: UserAddress,
5508 perms: ProtectionFlags,
5509 ) -> Result<(Arc<MemoryObject>, u64), Errno> {
5510 let state = self.state.read();
5511 let (_, mapping) = state.mappings.get(addr).ok_or_else(|| errno!(EFAULT))?;
5512 if !mapping.flags().access_flags().contains(perms) {
5513 return error!(EACCES);
5514 }
5515 match state.get_mapping_backing(mapping) {
5516 MappingBacking::Memory(backing) => {
5517 Ok((Arc::clone(backing.memory()), mapping.address_to_offset(addr)))
5518 }
5519 MappingBacking::PrivateAnonymous => {
5520 Ok((Arc::clone(&self.mapping_context.private_anonymous.backing), addr.ptr() as u64))
5521 }
5522 }
5523 }
5524
5525 pub fn check_plausible(&self, addr: UserAddress, buffer_size: usize) -> Result<(), Errno> {
5547 let state = self.state.read();
5548
5549 if let Some(range) = state.mappings.last_range() {
5550 if (range.end - buffer_size)? >= addr {
5551 return Ok(());
5552 }
5553 }
5554 error!(EFAULT)
5555 }
5556
5557 pub fn get_aio_context(&self, addr: UserAddress) -> Option<Arc<AioContext>> {
5558 let state = self.state.read();
5559 state.get_aio_context(addr).map(|(_, aio_context)| aio_context)
5560 }
5561
5562 pub fn destroy_aio_context(
5563 self: &Arc<Self>,
5564 addr: UserAddress,
5565 ) -> Result<Arc<AioContext>, Errno> {
5566 let mut released_mappings = ReleasedMappings::default();
5567
5568 let mut state = self.state.write();
5571
5572 let Some((range, aio_context)) = state.get_aio_context(addr) else {
5576 return error!(EINVAL);
5577 };
5578
5579 let length = range.end - range.start;
5580 let result = state.unmap(self, range.start, length, &mut released_mappings);
5581
5582 released_mappings.finalize(state);
5583
5584 result.map(|_| aio_context)
5585 }
5586
5587 #[cfg(test)]
5588 pub fn get_mapping_name(
5589 &self,
5590 addr: UserAddress,
5591 ) -> Result<Option<flyweights::FlyByteStr>, Errno> {
5592 let state = self.state.read();
5593 let (_, mapping) = state.mappings.get(addr).ok_or_else(|| errno!(EFAULT))?;
5594 if let MappingNameRef::Vma(name) = mapping.name() {
5595 Ok(Some(name.clone()))
5596 } else {
5597 Ok(None)
5598 }
5599 }
5600
5601 #[cfg(test)]
5602 pub fn get_mapping_count(&self) -> usize {
5603 let state = self.state.read();
5604 state.mappings.iter().count()
5605 }
5606
5607 pub fn extend_growsdown_mapping_to_address(
5608 &self,
5609 addr: UserAddress,
5610 is_write: bool,
5611 ) -> Result<bool, Error> {
5612 self.state.write().extend_growsdown_mapping_to_address(self, addr, is_write)
5613 }
5614
5615 pub fn get_total_usage(&self) -> usize {
5616 self.state.read().mappings.total_usage
5617 }
5618
5619 pub fn get_stats(
5620 &self,
5621 current_task: &CurrentTask,
5622 self_cache_mode: SelfStatsCacheMode,
5623 ) -> MemoryStats {
5624 let is_self_read =
5629 current_task.mm().map_or(false, |mm| std::ptr::eq(Arc::as_ptr(&mm), self));
5630
5631 let state = self.state.read();
5635 let generation = state.mappings.generation;
5636 let now = zx::MonotonicInstant::get();
5637 if !(self_cache_mode == SelfStatsCacheMode::BypassCache && is_self_read) {
5638 const CACHE_TTL: zx::MonotonicDuration = zx::MonotonicDuration::from_millis(2000);
5639 let cached = self.cached_stats.lock();
5640 if let Some((timestamp, cached_gen, stats)) = *cached {
5641 if cached_gen == generation && now - timestamp < CACHE_TTL {
5642 return stats;
5643 }
5644 }
5645 }
5646
5647 let mut stats = MemoryStats::default();
5648 stats.vm_stack = state
5649 .mappings
5650 .iter()
5651 .filter(|(_, m)| m.flags().contains(MappingFlags::GROWSDOWN))
5652 .map(|(range, _)| range.end - range.start)
5653 .sum();
5654
5655 self.with_zx_mappings(current_task, |zx_mappings| {
5656 let mut mappings_iter = state.mappings.iter().peekable();
5657 for zx_mapping in zx_mappings {
5658 let zx_details = zx_mapping.details();
5660 let Some(zx_details) = zx_details.as_mapping() else { continue };
5661 let user_address = UserAddress::from(zx_mapping.base as u64);
5662 while mappings_iter
5663 .peek()
5664 .is_some_and(|(mm_range, _)| mm_range.end.ptr() <= zx_mapping.base)
5665 {
5666 mappings_iter.next();
5667 }
5668 let (_, mm_mapping) = mappings_iter
5669 .peek()
5670 .filter(|(mm_range, _)| mm_range.start.ptr() <= zx_mapping.base)
5671 .unwrap_or_else(|| {
5672 panic!(
5673 "mapping bookkeeping must be consistent with zircon's: not found: {user_address:?}"
5674 )
5675 });
5676 debug_assert_eq!(
5677 match state.get_mapping_backing(mm_mapping) {
5678 MappingBacking::Memory(m)=>m.memory().get_koid(),
5679 MappingBacking::PrivateAnonymous=>self.mapping_context.private_anonymous.backing.get_koid(),
5680 },
5681 zx_details.vmo_koid,
5682 "MemoryManager and Zircon must agree on which VMO is mapped in this range",
5683 );
5684
5685 stats.vm_size += zx_mapping.size;
5686
5687 stats.vm_rss += zx_details.committed_bytes;
5688 stats.vm_swap += zx_details.populated_bytes - zx_details.committed_bytes;
5689
5690 if mm_mapping.flags().contains(MappingFlags::SHARED) {
5691 stats.rss_shared += zx_details.committed_bytes;
5692 } else if mm_mapping.flags().contains(MappingFlags::ANONYMOUS) {
5693 stats.rss_anonymous += zx_details.committed_bytes;
5694 } else if mm_mapping.name().is_file() {
5695 stats.rss_file += zx_details.committed_bytes;
5696 }
5697
5698 if mm_mapping.flags().contains(MappingFlags::LOCKED) {
5699 stats.vm_lck += zx_details.committed_bytes;
5700 }
5701
5702 if mm_mapping.flags().contains(MappingFlags::ELF_BINARY)
5703 && mm_mapping.flags().contains(MappingFlags::WRITE)
5704 {
5705 stats.vm_data += zx_mapping.size;
5706 }
5707
5708 if mm_mapping.flags().contains(MappingFlags::ELF_BINARY)
5709 && mm_mapping.flags().contains(MappingFlags::EXEC)
5710 {
5711 stats.vm_exe += zx_mapping.size;
5712 }
5713 }
5714 });
5715
5716 stats.vm_rss_hwm = STUB_VM_RSS_HWM;
5719 *self.cached_stats.lock() = Some((now, generation, stats));
5720 stats
5721 }
5722
5723 fn run_atomic_op<F, T>(
5724 &self,
5725 futex_addr: FutexAddress,
5726 access: MappingAccess,
5727 mut op: F,
5728 ) -> Result<T, Errno>
5729 where
5730 F: FnMut(&usercopy::Usercopy) -> Result<T, ()>,
5731 {
5732 let uc = usercopy();
5733 if let Ok(val) = op(uc) {
5739 return Ok(val);
5740 }
5741 self.ensure_range_mapped_in_user_vmar_for_access(
5742 futex_addr.into(),
5743 None,
5744 access,
5745 )?;
5746 op(uc).map_err(|_| errno!(EFAULT))
5747 }
5748
5749 pub fn atomic_load_u32_acquire(&self, futex_addr: FutexAddress) -> Result<u32, Errno> {
5750 self.run_atomic_op(futex_addr, MappingAccess::ForReading, |uc| {
5751 uc.atomic_load_u32_acquire(futex_addr.ptr())
5752 })
5753 }
5754
5755 pub fn atomic_load_u32_relaxed(&self, futex_addr: FutexAddress) -> Result<u32, Errno> {
5756 self.run_atomic_op(futex_addr, MappingAccess::ForReading, |uc| {
5757 uc.atomic_load_u32_relaxed(futex_addr.ptr())
5758 })
5759 }
5760
5761 pub fn atomic_store_u32_relaxed(
5762 &self,
5763 futex_addr: FutexAddress,
5764 value: u32,
5765 ) -> Result<(), Errno> {
5766 self.run_atomic_op(futex_addr, MappingAccess::ForWriting, |uc| {
5767 uc.atomic_store_u32_relaxed(futex_addr.ptr(), value)
5768 })
5769 }
5770
5771 pub fn atomic_compare_exchange_u32_acq_rel(
5772 &self,
5773 futex_addr: FutexAddress,
5774 current: u32,
5775 new: u32,
5776 ) -> CompareExchangeResult<u32> {
5777 CompareExchangeResult::from_usercopy(self.run_atomic_op(
5778 futex_addr,
5779 MappingAccess::ForWriting,
5780 |uc| uc.atomic_compare_exchange_u32_acq_rel(futex_addr.ptr(), current, new),
5781 ))
5782 }
5783
5784 pub fn atomic_compare_exchange_weak_u32_acq_rel(
5785 &self,
5786 futex_addr: FutexAddress,
5787 current: u32,
5788 new: u32,
5789 ) -> CompareExchangeResult<u32> {
5790 CompareExchangeResult::from_usercopy(self.run_atomic_op(
5791 futex_addr,
5792 MappingAccess::ForWriting,
5793 |uc| uc.atomic_compare_exchange_weak_u32_acq_rel(futex_addr.ptr(), current, new),
5794 ))
5795 }
5796}
5797
5798#[derive(Debug, Clone)]
5800pub enum CompareExchangeResult<T> {
5801 Success,
5804 Stale { observed: T },
5806 Error(Errno),
5808}
5809
5810impl<T> CompareExchangeResult<T> {
5811 fn from_usercopy(res: Result<Result<T, T>, Errno>) -> Self {
5812 match res {
5813 Ok(Ok(_)) => Self::Success,
5814 Ok(Err(observed)) => Self::Stale { observed },
5815 Err(e) => Self::Error(e),
5816 }
5817 }
5818}
5819
5820impl<T> From<Errno> for CompareExchangeResult<T> {
5821 fn from(e: Errno) -> Self {
5822 Self::Error(e)
5823 }
5824}
5825
5826#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5828pub enum DesiredAddress {
5829 Any,
5831 Hint(UserAddress),
5834 Fixed(UserAddress),
5837 FixedOverwrite(UserAddress),
5840}
5841
5842#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5844enum SelectedAddress {
5845 Fixed(UserAddress),
5847 FixedOverwrite(UserAddress),
5849}
5850
5851impl SelectedAddress {
5852 fn addr(&self) -> UserAddress {
5853 match self {
5854 SelectedAddress::Fixed(addr) => *addr,
5855 SelectedAddress::FixedOverwrite(addr) => *addr,
5856 }
5857 }
5858}
5859
5860fn write_map(
5862 task: &Task,
5863 fs_context: Option<&FsContext>,
5864 sink: &mut DynamicFileBuf,
5865 state: &MemoryManagerState,
5866 range: &Range<UserAddress>,
5867 map: &Mapping,
5868) -> Result<(), Errno> {
5869 let line_length = write!(
5870 sink,
5871 "{:08x}-{:08x} {}{}{}{} {:08x} 00:00 {} ",
5872 range.start.ptr(),
5873 range.end.ptr(),
5874 if map.can_read() { 'r' } else { '-' },
5875 if map.can_write() { 'w' } else { '-' },
5876 if map.can_exec() { 'x' } else { '-' },
5877 if map.flags().contains(MappingFlags::SHARED) { 's' } else { 'p' },
5878 match state.get_mapping_backing(map) {
5879 MappingBacking::Memory(backing) => backing.address_to_offset(range.start),
5880 MappingBacking::PrivateAnonymous => 0,
5881 },
5882 if let MappingNameRef::File(file) = &map.name() { file.node().ino } else { 0 }
5883 )?;
5884 let fill_to_name = |sink: &mut DynamicFileBuf| {
5885 const SPACES: [u8; 73] = [b' '; 73];
5887 if line_length < SPACES.len() {
5888 sink.write(&SPACES[line_length..]);
5889 }
5890 };
5891 match &map.name() {
5892 MappingNameRef::None | MappingNameRef::AioContext(_) => {
5893 if map.flags().contains(MappingFlags::SHARED)
5894 && map.flags().contains(MappingFlags::ANONYMOUS)
5895 {
5896 fill_to_name(sink);
5898 sink.write(b"/dev/zero (deleted)");
5899 }
5900 }
5901 MappingNameRef::Stack => {
5902 fill_to_name(sink);
5903 sink.write(b"[stack]");
5904 }
5905 MappingNameRef::Heap => {
5906 fill_to_name(sink);
5907 sink.write(b"[heap]");
5908 }
5909 MappingNameRef::Vdso => {
5910 fill_to_name(sink);
5911 sink.write(b"[vdso]");
5912 }
5913 MappingNameRef::Vvar => {
5914 fill_to_name(sink);
5915 sink.write(b"[vvar]");
5916 }
5917 MappingNameRef::File(file) => {
5918 fill_to_name(sink);
5919 let path = if let Some(fs_context) = fs_context {
5923 file.name().path(fs_context)
5924 } else {
5925 file.name().path(&*task.fs()?)
5926 };
5927 if !path.contains(&b'\n') {
5928 sink.write(&path);
5929 } else {
5930 sink.write_iter(
5931 path.iter()
5932 .flat_map(|b| if *b == b'\n' { b"\\012" } else { std::slice::from_ref(b) })
5933 .copied(),
5934 );
5935 }
5936 }
5937 MappingNameRef::Vma(name) => {
5938 fill_to_name(sink);
5939 if map.flags().contains(MappingFlags::SHARED) {
5940 sink.write(b"[anon_shmem:");
5941 } else {
5942 sink.write(b"[anon:");
5943 }
5944 sink.write(name.as_bytes());
5945 sink.write(b"]");
5946 }
5947 MappingNameRef::Ashmem(name) => {
5948 fill_to_name(sink);
5949 sink.write(b"/dev/ashmem/");
5950 sink.write(name.as_bytes());
5951 }
5952 }
5953 sink.write(b"\n");
5954 Ok(())
5955}
5956
5957#[derive(Clone, Copy, Debug, Eq, PartialEq)]
5960pub enum SelfStatsCacheMode {
5961 AllowCached,
5965 BypassCache,
5968}
5969
5970#[derive(Clone, Copy, Debug, Default)]
5971pub struct MemoryStats {
5972 pub vm_size: usize,
5973 pub vm_rss: usize,
5974 pub vm_rss_hwm: usize,
5975 pub rss_anonymous: usize,
5976 pub rss_file: usize,
5977 pub rss_shared: usize,
5978 pub vm_data: usize,
5979 pub vm_stack: usize,
5980 pub vm_exe: usize,
5981 pub vm_swap: usize,
5982 pub vm_lck: usize,
5983}
5984
5985#[derive(Clone)]
5987pub struct ProcMapsFile {
5988 mm: Weak<MemoryManager>,
5989 target: TaskContainer,
5990}
5991impl ProcMapsFile {
5992 pub fn new(task: Arc<Task>, target: TaskContainer) -> DynamicFile<Self> {
5993 let mm = task.mm().map_or_else(|_| Weak::default(), |mm| Arc::downgrade(&mm));
5995 DynamicFile::new(Self { mm, target })
5996 }
5997}
5998
5999impl SequenceFileSource for ProcMapsFile {
6000 type Cursor = UserAddress;
6001
6002 fn next(
6003 &self,
6004 _current_task: &CurrentTask,
6005 cursor: UserAddress,
6006 sink: &mut DynamicFileBuf,
6007 ) -> Result<Option<UserAddress>, Errno> {
6008 let task = self.target.get_task()?;
6009 let Some(mm) = self.mm.upgrade() else {
6011 return Ok(None);
6012 };
6013 let fs_context = task.fs().ok();
6014 let state = mm.state.read();
6015 if let Some((range, map)) = state.mappings.find_at_or_after(cursor) {
6016 write_map(&task, fs_context.as_deref(), sink, &state, range, map)?;
6017 return Ok(Some(range.end));
6018 }
6019 Ok(None)
6020 }
6021}
6022
6023#[derive(Clone)]
6024pub struct ProcSmapsFile {
6025 mm: Weak<MemoryManager>,
6026 target: TaskContainer,
6027}
6028impl ProcSmapsFile {
6029 pub fn new(task: Arc<Task>, target: TaskContainer) -> DynamicFile<Self> {
6030 let mm = task.mm().map_or_else(|_| Weak::default(), |mm| Arc::downgrade(&mm));
6032 DynamicFile::new(Self { mm, target })
6033 }
6034
6035 fn compute_committed_bytes(
6040 mm: &MemoryManager,
6041 state: &MemoryManagerState,
6042 zx_mappings: &[zx::MapInfo],
6043 ) -> Vec<u64> {
6044 let mut committed_bytes_vec = Vec::with_capacity(zx_mappings.len());
6045 let mut zx_idx = 0;
6046 for (mm_range, mm_mapping) in state.mappings.iter() {
6047 let mm_start = mm_range.start.ptr();
6048 let mm_end = mm_range.end.ptr();
6049 let mut committed_bytes = 0;
6050 while let Some(zx_mapping) = zx_mappings.get(zx_idx) {
6051 let details = zx_mapping.details();
6052 let Some(zx_details) = details.as_mapping() else {
6054 zx_idx += 1;
6055 continue;
6056 };
6057 let zx_start = zx_mapping.base;
6058 let zx_end = zx_start + zx_mapping.size;
6059 assert!(
6060 zx_end > mm_start,
6061 "Zircon mapping that isn't mapped from starnix: {zx_details:?}"
6062 );
6063 if zx_start >= mm_end {
6064 break;
6066 }
6067
6068 let intersect_size =
6074 std::cmp::min(mm_end, zx_end) - std::cmp::max(mm_start, zx_start);
6075 committed_bytes += if intersect_size != zx_mapping.size {
6076 let part = intersect_size as f32 / zx_mapping.size as f32;
6077 (part * zx_details.committed_bytes as f32) as u64
6078 } else {
6079 zx_details.committed_bytes as u64
6080 };
6081 assert_eq!(
6082 match state.get_mapping_backing(mm_mapping) {
6083 MappingBacking::Memory(m) => m.memory().get_koid(),
6084 MappingBacking::PrivateAnonymous =>
6085 mm.mapping_context.private_anonymous.backing.get_koid(),
6086 },
6087 zx_details.vmo_koid,
6088 "MemoryManager and Zircon must agree on which VMO is mapped in this range",
6089 );
6090 if zx_end <= mm_end {
6091 zx_idx += 1;
6092 } else {
6093 break;
6094 }
6095 }
6096 committed_bytes_vec.push(committed_bytes);
6097 }
6098 committed_bytes_vec
6099 }
6100}
6101
6102impl DynamicFileSource for ProcSmapsFile {
6103 fn generate(&self, current_task: &CurrentTask, sink: &mut DynamicFileBuf) -> Result<(), Errno> {
6104 let page_size_kb = *PAGE_SIZE / 1024;
6105 let task = self.target.get_task()?;
6106 let Some(mm) = self.mm.upgrade() else {
6108 return Ok(());
6109 };
6110
6111 let lazy_ranges: SmallVec<[_; 4]> = {
6115 let state = mm.state.read();
6116 state
6117 .mappings
6118 .iter()
6119 .filter(|(_, m)| m.mapping_mode() == MappingMode::Lazy)
6120 .map(|(range, _)| (range.start, Some(range.end - range.start)))
6121 .collect()
6122 };
6123 if !lazy_ranges.is_empty() {
6124 mm.state.write().ensure_ranges_mapped_in_user_vmar_for_access(
6125 lazy_ranges,
6126 MappingAccess::ForReading,
6127 &mm.mapping_context,
6128 )?;
6129 }
6130
6131 let fs_context = task.fs().ok();
6132 let fs_context_ref = fs_context.as_deref();
6133
6134 let state = mm.state.read();
6135 let committed_bytes_vec = mm.with_zx_mappings(current_task, |zx_mappings| {
6136 Self::compute_committed_bytes(&mm, &state, zx_mappings)
6137 });
6138
6139 let mut share_count_cache: FxHashMap<zx::Koid, u64> = FxHashMap::default();
6140
6141 for ((mm_range, mm_mapping), committed_bytes) in
6142 state.mappings.iter().zip(committed_bytes_vec.into_iter())
6143 {
6144 write_map(&task, fs_context_ref, sink, &state, mm_range, mm_mapping)?;
6145
6146 let size_kb = (mm_range.end.ptr() - mm_range.start.ptr()) / 1024;
6147 let rss_kb = committed_bytes / 1024;
6148
6149 if rss_kb == 0 {
6150 write!(
6154 sink,
6155 "Size: {size_kb:>8} kB\n\
6156 Rss: 0 kB\n\
6157 Pss: 0 kB\n\
6158 Shared_Clean: 0 kB\n\
6159 Shared_Dirty: 0 kB\n\
6160 Private_Clean: 0 kB\n\
6161 Private_Dirty: 0 kB\n\
6162 Anonymous: 0 kB\n\
6163 KernelPageSize: {page_size_kb:>8} kB\n\
6164 MMUPageSize: {page_size_kb:>8} kB\n\
6165 Locked: 0 kB\n\
6166 VmFlags: "
6167 )?;
6168 } else {
6169 let share_count = match state.get_mapping_backing(mm_mapping) {
6170 MappingBacking::Memory(backing) => {
6171 let memory = backing.memory();
6172 let koid = memory.get_koid();
6173 if let Some(count) = share_count_cache.get(&koid) {
6174 *count
6175 } else {
6176 let count = if memory.is_clock() {
6177 1
6179 } else {
6180 let memory_info = memory.info()?;
6181 memory_info.share_count as u64
6182 };
6183 let _ = share_count_cache.insert(koid, count);
6184 count
6185 }
6186 }
6187 MappingBacking::PrivateAnonymous => {
6188 1 }
6190 };
6191
6192 let is_shared = share_count > 1;
6193
6194 let pss_kb = if is_shared { rss_kb / share_count } else { rss_kb };
6195
6196 track_stub!(TODO("https://fxbug.dev/322874967"), "smaps dirty pages");
6197 let (shared_dirty_kb, private_dirty_kb) = (0, 0);
6198 let shared_clean_kb = if is_shared { rss_kb } else { 0 };
6199 let private_clean_kb = if is_shared { 0 } else { rss_kb };
6200
6201 let anonymous_kb = if mm_mapping.private_anonymous() { rss_kb } else { 0 };
6202 let locked_kb =
6203 if mm_mapping.flags().contains(MappingFlags::LOCKED) { rss_kb } else { 0 };
6204 write!(
6205 sink,
6206 "Size: {size_kb:>8} kB\n\
6207 Rss: {rss_kb:>8} kB\n\
6208 Pss: {pss_kb:>8} kB\n\
6209 Shared_Clean: {shared_clean_kb:>8} kB\n\
6210 Shared_Dirty: {shared_dirty_kb:>8} kB\n\
6211 Private_Clean: {private_clean_kb:>8} kB\n\
6212 Private_Dirty: {private_dirty_kb:>8} kB\n\
6213 Anonymous: {anonymous_kb:>8} kB\n\
6214 KernelPageSize: {page_size_kb:>8} kB\n\
6215 MMUPageSize: {page_size_kb:>8} kB\n\
6216 Locked: {locked_kb:>8} kB\n\
6217 VmFlags: "
6218 )?;
6219 }
6220
6221 mm_mapping.write_vm_flags(sink);
6222 sink.write(b"\n");
6223
6224 track_stub!(TODO("https://fxbug.dev/297444691"), "optional smaps fields");
6225 }
6226
6227 Ok(())
6228 }
6229}
6230
6231#[derive(Clone)]
6233pub struct ProcSmapsRollupFile {
6234 mm: Weak<MemoryManager>,
6235 target: TaskContainer,
6236}
6237impl ProcSmapsRollupFile {
6238 pub fn new(task: Arc<Task>, target: TaskContainer) -> DynamicFile<Self> {
6241 let mm = task.mm().map_or_else(|_| Weak::default(), |mm| Arc::downgrade(&mm));
6242 DynamicFile::new(Self { mm, target })
6243 }
6244}
6245impl DynamicFileSource for ProcSmapsRollupFile {
6246 fn generate(&self, current_task: &CurrentTask, sink: &mut DynamicFileBuf) -> Result<(), Errno> {
6247 let _task = self.target.get_task()?;
6248 let Some(mm) = self.mm.upgrade() else {
6249 return error!(ESRCH);
6250 };
6251
6252 let mem_stats = mm.get_stats(current_task, SelfStatsCacheMode::AllowCached);
6253 let rss_kb = mem_stats.vm_rss / 1024;
6254 let anon_kb = mem_stats.rss_anonymous / 1024;
6255 let file_kb = mem_stats.rss_file / 1024;
6256 let shmem_kb = mem_stats.rss_shared / 1024;
6257 let swap_kb = mem_stats.vm_swap / 1024;
6258 let locked_kb = mem_stats.vm_lck / 1024;
6259
6260 let private_dirty_kb = anon_kb;
6262 let shared_clean_kb = file_kb + shmem_kb;
6264 let private_clean_kb = 0;
6265 let pss_file_kb = file_kb / 5;
6268 let pss_shmem_kb = shmem_kb / 5;
6269 let pss_kb = anon_kb + pss_file_kb + pss_shmem_kb;
6270
6271 writeln!(sink, "00000000-ffffffffffffffff ---p 00000000 00:00 0 [rollup]")?;
6272 writeln!(sink, "Rss: {rss_kb:>8} kB")?;
6273 writeln!(sink, "Pss: {pss_kb:>8} kB")?;
6274 writeln!(sink, "Pss_Dirty: 0 kB")?;
6275 writeln!(sink, "Pss_Anon: {anon_kb:>8} kB")?;
6276 writeln!(sink, "Pss_File: {pss_file_kb:>8} kB")?;
6277 writeln!(sink, "Pss_Shmem: {pss_shmem_kb:>8} kB")?;
6278 writeln!(sink, "Shared_Clean: {shared_clean_kb:>8} kB")?;
6279 writeln!(sink, "Shared_Dirty: 0 kB")?;
6280 writeln!(sink, "Private_Clean: {private_clean_kb:>8} kB")?;
6281 writeln!(sink, "Private_Dirty: {private_dirty_kb:>8} kB")?;
6282 writeln!(sink, "Referenced: {rss_kb:>8} kB")?;
6283 writeln!(sink, "Anonymous: {anon_kb:>8} kB")?;
6284 writeln!(sink, "KSM: 0 kB")?;
6285 writeln!(sink, "LazyFree: 0 kB")?;
6286 writeln!(sink, "AnonHugePages: 0 kB")?;
6287 writeln!(sink, "ShmemPmdMapped: 0 kB")?;
6288 writeln!(sink, "FilePmdMapped: 0 kB")?;
6289 writeln!(sink, "Shared_Hugetlb: 0 kB")?;
6290 writeln!(sink, "Private_Hugetlb: 0 kB")?;
6291 writeln!(sink, "Swap: {swap_kb:>8} kB")?;
6292 writeln!(sink, "SwapPss: {swap_kb:>8} kB")?;
6293 writeln!(sink, "Locked: {locked_kb:>8} kB")?;
6294 Ok(())
6295 }
6296}
6297
6298const PAGEMAP_PFN_MASK: u64 = (1u64 << 55) - 1;
6299
6300fn compute_pseudo_pfn(koid: zx::Koid, vmo_page_idx: u64) -> u64 {
6322 let mut hasher = rustc_hash::FxHasher::default();
6323 hasher.write_u64(koid.raw_koid());
6324 hasher.finish().wrapping_add(vmo_page_idx) & PAGEMAP_PFN_MASK
6325}
6326
6327#[derive(Clone)]
6329pub struct ProcPagemapFile {
6330 mm: Weak<MemoryManager>,
6331 can_read_pfn: bool,
6332}
6333
6334impl ProcPagemapFile {
6335 pub fn new(current_task: &CurrentTask, task: &Task) -> Self {
6336 let mm = task.mm().map_or_else(|_| Weak::default(), |mm| Arc::downgrade(&mm));
6337 let can_read_pfn =
6338 security::is_task_capable_noaudit(current_task, starnix_uapi::auth::CAP_SYS_ADMIN);
6339 Self { mm, can_read_pfn }
6340 }
6341
6342 #[inline]
6351 fn compute_entry_flags(mm_mapping: &Mapping) -> u64 {
6352 let is_shared = mm_mapping.flags().contains(MappingFlags::SHARED);
6353 let is_file = matches!(mm_mapping.name(), MappingNameRef::File(_));
6354 (1u64 << 63) | if is_shared || is_file { 1u64 << 61 } else { 1u64 << 57 }
6355 }
6356
6357 #[inline]
6358 fn compute_start_pfn(
6359 mm: &MemoryManager,
6360 state: &MemoryManagerState,
6361 mm_mapping: &Mapping,
6362 addr: UserAddress,
6363 page_size: usize,
6364 ) -> u64 {
6365 let (koid, vmo_offset) = match state.get_mapping_backing(mm_mapping) {
6366 MappingBacking::Memory(backing) => {
6367 (backing.memory().get_koid(), backing.address_to_offset(addr))
6368 }
6369 MappingBacking::PrivateAnonymous => {
6370 (mm.mapping_context.private_anonymous.backing.get_koid(), addr.ptr() as u64)
6371 }
6372 };
6373 compute_pseudo_pfn(koid, vmo_offset / page_size as u64)
6374 }
6375
6376 #[inline]
6377 fn fill_contiguous_entries(slice: &mut [u64], flags: u64, start_pfn: u64, can_read_pfn: bool) {
6378 if !can_read_pfn {
6379 slice.fill(flags);
6380 return;
6381 }
6382 if start_pfn + (slice.len() as u64) <= PAGEMAP_PFN_MASK {
6383 let base_entry = flags | start_pfn;
6384 for (i, entry) in slice.iter_mut().enumerate() {
6385 *entry = base_entry + (i as u64);
6386 }
6387 } else {
6388 for (i, entry) in slice.iter_mut().enumerate() {
6389 let pfn = start_pfn.wrapping_add(i as u64) & PAGEMAP_PFN_MASK;
6390 *entry = flags | pfn;
6391 }
6392 }
6393 }
6394
6395 #[inline(never)]
6398 fn read_multi_page(
6399 &self,
6400 mm: &MemoryManager,
6401 offset: usize,
6402 to_read: usize,
6403 dst: &mut dyn OutputBuffer,
6404 ) -> Result<usize, Errno> {
6405 let entry_size = std::mem::size_of::<u64>();
6406 let page_size = *PAGE_SIZE as usize;
6407
6408 let unaligned_offset = offset % entry_size;
6409 let start_page_idx = offset / entry_size;
6410 let total_bytes_needed = unaligned_offset + to_read;
6411 let num_pages = (total_bytes_needed + entry_size - 1) / entry_size;
6412 let can_read_pfn = self.can_read_pfn;
6413
6414 let Some(start_addr) = start_page_idx.checked_mul(page_size) else {
6415 return Ok(0);
6416 };
6417 let read_start_vaddr = UserAddress::from(start_addr as u64);
6418 let read_end_vaddr = start_page_idx
6419 .checked_add(num_pages)
6420 .and_then(|end_page| end_page.checked_mul(page_size))
6421 .map_or_else(|| UserAddress::from(u64::MAX), |addr| UserAddress::from(addr as u64));
6422
6423 const CHUNK_PAGES: usize = 512;
6424 let mut chunk_buf = SmallVec::<[u64; CHUNK_PAGES]>::new();
6425 let mut pages_processed = 0;
6426 let mut bytes_written_total = 0;
6427
6428 let single_mapping_info = {
6433 let state = mm.state.read();
6434 if let Some((mm_range, mm_mapping)) = state.mappings.get(read_start_vaddr)
6435 && mm_range.end >= read_end_vaddr
6436 {
6437 let flags = Self::compute_entry_flags(mm_mapping);
6438 let base_pfn = if can_read_pfn {
6439 Self::compute_start_pfn(mm, &state, mm_mapping, read_start_vaddr, page_size)
6440 } else {
6441 0
6442 };
6443 Some((flags, base_pfn))
6444 } else {
6445 None
6446 }
6447 };
6448 if let Some((flags, base_pfn)) = single_mapping_info {
6449 while pages_processed < num_pages && bytes_written_total < to_read {
6450 let current_chunk_pages = std::cmp::min(CHUNK_PAGES, num_pages - pages_processed);
6451 let chunk_start_pfn =
6452 base_pfn.wrapping_add(pages_processed as u64) & PAGEMAP_PFN_MASK;
6453
6454 chunk_buf.resize(current_chunk_pages, 0);
6455 let chunk_slice = &mut chunk_buf[..current_chunk_pages];
6456 Self::fill_contiguous_entries(chunk_slice, flags, chunk_start_pfn, can_read_pfn);
6457
6458 let byte_slice = chunk_slice.as_bytes();
6459 let chunk_byte_offset = if pages_processed == 0 { unaligned_offset } else { 0 };
6460 let chunk_available_bytes = byte_slice.len().saturating_sub(chunk_byte_offset);
6461 let chunk_write_len =
6462 std::cmp::min(to_read - bytes_written_total, chunk_available_bytes);
6463
6464 dst.write_all(&byte_slice[chunk_byte_offset..chunk_byte_offset + chunk_write_len])?;
6465 bytes_written_total += chunk_write_len;
6466 pages_processed += current_chunk_pages;
6467 }
6468
6469 return Ok(bytes_written_total);
6470 }
6471
6472 while pages_processed < num_pages && bytes_written_total < to_read {
6474 let chunk_start_page = start_page_idx + pages_processed;
6475 let current_chunk_pages = std::cmp::min(CHUNK_PAGES, num_pages - pages_processed);
6476
6477 let chunk_start_vaddr = match chunk_start_page.checked_mul(page_size) {
6478 Some(addr) => UserAddress::from(addr as u64),
6479 None => break,
6480 };
6481 let chunk_end_vaddr =
6482 match (chunk_start_page + current_chunk_pages).checked_mul(page_size) {
6483 Some(addr) => UserAddress::from(addr as u64),
6484 None => UserAddress::from(u64::MAX),
6485 };
6486
6487 chunk_buf.clear();
6488 chunk_buf.resize(current_chunk_pages, 0);
6489 let chunk_slice = &mut chunk_buf[..current_chunk_pages];
6490
6491 {
6492 let state = mm.state.read();
6496
6497 for (mm_range, mm_mapping) in
6498 state.mappings.range(chunk_start_vaddr..chunk_end_vaddr)
6499 {
6500 let flags = Self::compute_entry_flags(mm_mapping);
6501
6502 let map_start_page = (mm_range.start.ptr() as usize) / page_size;
6503 let map_end_page = (mm_range.end.ptr() as usize) / page_size;
6504
6505 let first_page = std::cmp::max(chunk_start_page, map_start_page);
6506 let last_page =
6507 std::cmp::min(chunk_start_page + current_chunk_pages, map_end_page);
6508
6509 let first_page_vaddr = UserAddress::from((first_page * page_size) as u64);
6510 let start_pfn = if can_read_pfn {
6511 Self::compute_start_pfn(mm, &state, mm_mapping, first_page_vaddr, page_size)
6512 } else {
6513 0
6514 };
6515
6516 let sub_slice = &mut chunk_slice
6517 [first_page - chunk_start_page..last_page - chunk_start_page];
6518 Self::fill_contiguous_entries(sub_slice, flags, start_pfn, can_read_pfn);
6519 }
6520 }
6521
6522 let byte_slice = chunk_slice.as_bytes();
6523 let chunk_byte_offset = if pages_processed == 0 { unaligned_offset } else { 0 };
6524 let chunk_available_bytes = byte_slice.len().saturating_sub(chunk_byte_offset);
6525 let chunk_write_len =
6526 std::cmp::min(to_read - bytes_written_total, chunk_available_bytes);
6527
6528 dst.write_all(&byte_slice[chunk_byte_offset..chunk_byte_offset + chunk_write_len])?;
6529 bytes_written_total += chunk_write_len;
6530 pages_processed += current_chunk_pages;
6531 }
6532
6533 Ok(bytes_written_total)
6534 }
6535}
6536
6537impl FileOps for ProcPagemapFile {
6538 fileops_impl_seekable!();
6539 fileops_impl_noop_sync!();
6540
6541 fn read(
6542 &self,
6543 _file: &FileObject,
6544 _current_task: &CurrentTask,
6545 offset: usize,
6546 dst: &mut dyn OutputBuffer,
6547 ) -> Result<usize, Errno> {
6548 let Some(mm) = self.mm.upgrade() else {
6549 return Ok(0);
6550 };
6551
6552 let to_read = std::cmp::min(dst.available(), 1024 * 1024);
6553 if to_read == 0 {
6554 return Ok(0);
6555 }
6556
6557 let entry_size = std::mem::size_of::<u64>();
6558 let page_size = *PAGE_SIZE as usize;
6559 let unaligned_offset = offset % entry_size;
6560
6561 if unaligned_offset + to_read <= entry_size {
6563 let start_page_idx = offset / entry_size;
6564 let Some(addr) = start_page_idx.checked_mul(page_size) else {
6565 return Ok(0);
6566 };
6567 let start_vaddr = UserAddress::from(addr as u64);
6568 let state = mm.state.read();
6569 let entry = if let Some((_, mm_mapping)) = state.mappings.get(start_vaddr) {
6570 let flags = Self::compute_entry_flags(mm_mapping);
6571 let pfn = if self.can_read_pfn {
6572 Self::compute_start_pfn(&mm, &state, mm_mapping, start_vaddr, page_size)
6573 } else {
6574 0
6575 };
6576 flags | pfn
6577 } else {
6578 0
6579 };
6580 drop(state);
6581 let bytes = entry.to_ne_bytes();
6582 dst.write_all(&bytes[unaligned_offset..unaligned_offset + to_read])?;
6583 return Ok(to_read);
6584 }
6585
6586 self.read_multi_page(&mm, offset, to_read, dst)
6587 }
6588
6589 fn write(
6590 &self,
6591 _file: &FileObject,
6592 _current_task: &CurrentTask,
6593 _offset: usize,
6594 _data: &mut dyn InputBuffer,
6595 ) -> Result<usize, Errno> {
6596 starnix_uapi::error!(EPERM)
6597 }
6598}
6599
6600pub fn create_anonymous_mapping_memory(size: u64) -> Result<Arc<MemoryObject>, Errno> {
6602 let mut memory = MemoryObject::from(
6604 zx::Vmo::create_with_opts(zx::VmoOptions::RESIZABLE, size).map_err(|s| match s {
6605 zx::Status::NO_MEMORY => errno!(ENOMEM),
6606 zx::Status::OUT_OF_RANGE => errno!(ENOMEM),
6607 _ => impossible_error(s),
6608 })?,
6609 )
6610 .with_zx_name(b"starnix:memory_manager");
6611
6612 memory.set_zx_name(b"starnix-anon");
6613
6614 memory = memory.replace_as_executable(&VMEX_RESOURCE).map_err(impossible_error)?;
6616 Ok(Arc::new(memory))
6617}
6618
6619fn generate_random_offset_for_aslr(arch_width: ArchWidth) -> usize {
6620 let randomness = {
6622 let random_bits =
6623 if arch_width.is_arch32() { ASLR_32_RANDOM_BITS } else { ASLR_RANDOM_BITS };
6624 let mask = (1 << random_bits) - 1;
6625 let mut bytes = [0; std::mem::size_of::<usize>()];
6626 starnix_crypto::cprng_draw(&mut bytes);
6627 usize::from_le_bytes(bytes) & mask
6628 };
6629
6630 randomness * (*PAGE_SIZE as usize)
6632}
6633
6634#[cfg(test)]
6635mod tests {
6636 use super::*;
6637 use crate::mm::memory_accessor::{MemoryAccessor, MemoryAccessorExt};
6638 use crate::mm::syscalls::do_mmap;
6639 use crate::task::KernelFeatures;
6640 use crate::task::syscalls::sys_prctl;
6641 use crate::testing::*;
6642 use crate::vfs::{FdFlags, FdNumber, fileops_impl_memory, new_memfd};
6643 use assert_matches::assert_matches;
6644 use itertools::assert_equal;
6645 use starnix_uapi::open_flags::OpenFlags;
6646 use starnix_uapi::seal_flags::SealFlags;
6647 use starnix_uapi::user_address::{UserCString, UserRef};
6648 use starnix_uapi::{
6649 MAP_ANONYMOUS, MAP_FIXED, MAP_GROWSDOWN, MAP_PRIVATE, MAP_SHARED, PR_SET_VMA,
6650 PR_SET_VMA_ANON_NAME, PROT_EXEC, PROT_NONE, PROT_READ, PROT_WRITE,
6651 };
6652 use std::ffi::CString;
6653 use test_case::test_case;
6654 use zerocopy::{FromBytes, Immutable, KnownLayout};
6655
6656 #[::fuchsia::test]
6657 fn test_mapping_flags() {
6658 let options = MappingOptions::ANONYMOUS;
6659 let access_flags = ProtectionFlags::READ | ProtectionFlags::WRITE;
6660 let mapping_flags = MappingFlags::from_access_flags_and_options(access_flags, options);
6661 assert_eq!(mapping_flags.access_flags(), access_flags);
6662 assert_eq!(mapping_flags.options(), options);
6663
6664 let new_access_flags = ProtectionFlags::READ | ProtectionFlags::EXEC;
6665 let adusted_mapping_flags = mapping_flags.with_access_flags(new_access_flags);
6666 assert_eq!(adusted_mapping_flags.access_flags(), new_access_flags);
6667 assert_eq!(adusted_mapping_flags.options(), options);
6668 }
6669
6670 #[::fuchsia::test]
6671 fn test_write_vm_flags() {
6672 let options = MappingOptions::ANONYMOUS;
6673 let access_flags = ProtectionFlags::READ | ProtectionFlags::WRITE;
6674 let mapping_flags = MappingFlags::from_access_flags_and_options(access_flags, options);
6675 let mapping = Mapping::with_name(
6676 MappingBacking::PrivateAnonymous,
6677 mapping_flags,
6678 MappingName::None,
6679 MappingMode::Eager,
6680 );
6681 let mut sink = DynamicFileBuf::default();
6682 mapping.write_vm_flags(&mut sink);
6683 let bytes: Vec<u8> = sink.into();
6684 let str_flags = std::str::from_utf8(&bytes).unwrap();
6685 assert!(str_flags.contains("rd "));
6686 assert!(str_flags.contains("wr "));
6687 assert!(str_flags.contains("mr "));
6688 assert!(str_flags.contains("mw "));
6689 assert!(str_flags.contains("ac "));
6690
6691 let all_access = ProtectionFlags::READ | ProtectionFlags::WRITE | ProtectionFlags::EXEC;
6694 let all_options = MappingOptions::SHARED
6695 | MappingOptions::GROWSDOWN
6696 | MappingOptions::DONTFORK
6697 | MappingOptions::WIPEONFORK
6698 | MappingOptions::DONT_EXPAND;
6699 let mut exhaustive_flags =
6700 MappingFlags::from_access_flags_and_options(all_access, all_options);
6701 exhaustive_flags |= MappingFlags::LOCKED | MappingFlags::UFFD_MISSING;
6702
6703 let mapping_all = Mapping::with_name(
6704 MappingBacking::PrivateAnonymous,
6705 exhaustive_flags,
6706 MappingName::None,
6707 MappingMode::Eager,
6708 );
6709 let mut sink_all = DynamicFileBuf::default();
6710 mapping_all.write_vm_flags(&mut sink_all);
6711 let bytes_all: Vec<u8> = sink_all.into();
6712 let str_all = std::str::from_utf8(&bytes_all).unwrap();
6713
6714 assert_eq!(str_all, "rd wr ex sh mr mw me ms gd lo dc de ac wf um ");
6716 }
6717
6718 #[::fuchsia::test]
6719 async fn test_pad_to_column_boundaries() {
6720 spawn_kernel_and_run(async |current_task| {
6721 let mm = current_task.mm().unwrap();
6722 let state = mm.state.read();
6723 let fs_context = current_task.fs();
6724 let mapping_flags = MappingFlags::from_access_flags_and_options(
6725 ProtectionFlags::READ,
6726 MappingOptions::ANONYMOUS,
6727 );
6728 let range = UserAddress::from(0x10000)..UserAddress::from(0x20000);
6729
6730 let mapping_vdso = Mapping::with_name(
6732 MappingBacking::PrivateAnonymous,
6733 mapping_flags,
6734 MappingName::Vdso,
6735 MappingMode::Eager,
6736 );
6737 let mut sink_named = DynamicFileBuf::default();
6738 write_map(
6739 ¤t_task.task,
6740 Some(&fs_context),
6741 &mut sink_named,
6742 &state,
6743 &range,
6744 &mapping_vdso,
6745 )
6746 .expect("write_map");
6747 let bytes_named: Vec<u8> = sink_named.into();
6748 assert_eq!(&bytes_named[..40], b"00010000-00020000 r--p 00000000 00:00 0 ");
6749 assert_eq!(&bytes_named[40..73], &[b' '; 33]);
6750 assert_eq!(&bytes_named[73..], b"[vdso]\n");
6751
6752 let mapping_anon = Mapping::with_name(
6754 MappingBacking::PrivateAnonymous,
6755 mapping_flags,
6756 MappingName::None,
6757 MappingMode::Eager,
6758 );
6759 let mut sink = DynamicFileBuf::default();
6760 write_map(
6761 ¤t_task.task,
6762 Some(&fs_context),
6763 &mut sink,
6764 &state,
6765 &range,
6766 &mapping_anon,
6767 )
6768 .expect("write_map");
6769 let bytes: Vec<u8> = sink.into();
6770 let line = std::str::from_utf8(&bytes).unwrap();
6771 assert_eq!(line, "00010000-00020000 r--p 00000000 00:00 0 \n");
6772 let trimmed = &line[..line.len() - 1];
6773 assert!(trimmed.len() < 73, "Anonymous mapping line should not be padded to column 73");
6774 })
6775 .await;
6776 }
6777
6778 #[::fuchsia::test]
6779 async fn test_proc_smaps_generation() {
6780 spawn_kernel_with_features_and_run(
6781 async |current_task| {
6782 let _uncommitted = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
6783 let gap = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
6784 let committed = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
6785 current_task.mm().unwrap().unmap(gap, *PAGE_SIZE as usize).expect("unmap gap");
6786 current_task.write_memory(committed, &[0x42; 16]).expect("write committed page");
6787 let mm = current_task.mm().unwrap();
6788 assert_eq!(mm.get_mapping_count(), 2);
6789 let smaps = ProcSmapsFile {
6790 mm: Arc::downgrade(&mm),
6791 target: TaskContainer::from_task(¤t_task.task),
6792 };
6793 let mut sink = DynamicFileBuf::default();
6794 smaps.generate(current_task, &mut sink).expect("generate");
6795 let bytes: Vec<u8> = sink.into();
6796 let content = std::str::from_utf8(&bytes).unwrap();
6797 let page_kb = *PAGE_SIZE / 1024;
6798 assert!(content.contains("Size:"));
6799 assert!(content.contains("Rss: 0 kB"));
6800 assert!(content.contains(&format!("Rss: {page_kb:>8} kB")));
6801 assert!(content.contains("VmFlags:"));
6802 },
6803 KernelFeatures { cached_zx_map_info_bytes: 4096, ..Default::default() },
6804 )
6805 .await;
6806 }
6807
6808 #[::fuchsia::test]
6809 fn test_mapping_flags_populate_is_not_stored() {
6810 let options = MappingOptions::ANONYMOUS | MappingOptions::POPULATE;
6813 let access_flags = ProtectionFlags::READ | ProtectionFlags::WRITE;
6814 let mapping_flags = MappingFlags::from_access_flags_and_options(access_flags, options);
6815 assert!(!mapping_flags.contains(MappingFlags::LOCKED));
6816 assert_eq!(mapping_flags.options(), MappingOptions::ANONYMOUS);
6817
6818 let locked_flags = mapping_flags | MappingFlags::LOCKED;
6820 assert_eq!(locked_flags.options(), MappingOptions::ANONYMOUS);
6821 }
6822
6823 #[::fuchsia::test]
6824 async fn test_any_ranges_lazy() {
6825 spawn_kernel_and_run(async |current_task| {
6826 let mm = current_task.mm().unwrap();
6827 let page_size = *PAGE_SIZE as usize;
6828 let addr = (mm.base_addr + 10 * page_size).unwrap();
6829 let length = page_size;
6830
6831 let memory = create_anonymous_mapping_memory(length as u64).unwrap();
6832 let flags = MappingFlags::from_access_flags_and_options(
6833 ProtectionFlags::READ | ProtectionFlags::WRITE,
6834 MappingOptions::empty(),
6835 );
6836
6837 let mapping = Mapping::with_name(
6838 MappingBacking::Memory(Box::new(MappingBackingMemory::new(addr, memory, 0))),
6839 flags,
6840 MappingName::None,
6841 MappingMode::Lazy,
6842 );
6843
6844 {
6845 let mut state = mm.state.write();
6846 state.mappings.insert(addr..(addr + length).unwrap(), mapping);
6847 }
6848
6849 {
6850 let state = mm.state.read();
6851 assert!(state.any_ranges_need_vmar_update(
6852 std::iter::once((addr, Some(length))),
6853 MappingAccess::ForReading,
6854 ));
6855 }
6856
6857 assert!(mm.ensure_range_mapped_in_user_vmar(addr, Some(length)).unwrap());
6858
6859 {
6860 let state = mm.state.read();
6861 assert!(!state.any_ranges_need_vmar_update(
6862 std::iter::once((addr, Some(length))),
6863 MappingAccess::ForReading,
6864 ));
6865 }
6866 })
6867 .await;
6868 }
6869
6870 #[::fuchsia::test]
6871 async fn test_brk() {
6872 spawn_kernel_and_run(async |current_task| {
6873 let mm = current_task.mm().unwrap();
6874
6875 let get_range = |addr: UserAddress| {
6877 let state = mm.state.read();
6878 state
6879 .mappings
6880 .map
6881 .get(addr)
6882 .map(|(range, mapping)| (range.clone(), mapping.clone()))
6883 };
6884
6885 let base_addr = mm
6887 .set_brk(¤t_task, UserAddress::default())
6888 .expect("failed to set initial program break");
6889 assert!(base_addr > UserAddress::default());
6890
6891 assert_eq!(get_range(base_addr), None);
6893
6894 let addr0 =
6896 mm.set_brk(¤t_task, (base_addr + 1u64).unwrap()).expect("failed to grow brk");
6897 assert!(addr0 > base_addr);
6898 let (range0, _) = get_range(base_addr).expect("base_addr should be mapped");
6899 assert_eq!(range0.start, base_addr);
6900 assert_eq!(range0.end, (base_addr + *PAGE_SIZE).unwrap());
6901
6902 let addr1 =
6904 mm.set_brk(¤t_task, (base_addr + 2u64).unwrap()).expect("failed to grow brk");
6905 assert_eq!(addr1, (base_addr + 2u64).unwrap());
6906 let (range1, _) = get_range(base_addr).expect("base_addr should be mapped");
6907 assert_eq!(range1.start, range0.start);
6908 assert_eq!(range1.end, range0.end);
6909
6910 let addr2 = mm
6912 .set_brk(¤t_task, (base_addr + 24893u64).unwrap())
6913 .expect("failed to grow brk");
6914 assert_eq!(addr2, (base_addr + 24893u64).unwrap());
6915 let (range2, _) = get_range(base_addr).expect("base_addr should be mapped");
6916 assert_eq!(range2.start, base_addr);
6917 assert_eq!(range2.end, addr2.round_up(*PAGE_SIZE).unwrap());
6918
6919 let addr3 = mm
6921 .set_brk(¤t_task, (base_addr + 14832u64).unwrap())
6922 .expect("failed to shrink brk");
6923 assert_eq!(addr3, (base_addr + 14832u64).unwrap());
6924 let (range3, _) = get_range(base_addr).expect("base_addr should be mapped");
6925 assert_eq!(range3.start, base_addr);
6926 assert_eq!(range3.end, addr3.round_up(*PAGE_SIZE).unwrap());
6927
6928 let addr4 = mm
6930 .set_brk(¤t_task, (base_addr + 3u64).unwrap())
6931 .expect("failed to drastically shrink brk");
6932 assert_eq!(addr4, (base_addr + 3u64).unwrap());
6933 let (range4, _) = get_range(base_addr).expect("base_addr should be mapped");
6934 assert_eq!(range4.start, base_addr);
6935 assert_eq!(range4.end, addr4.round_up(*PAGE_SIZE).unwrap());
6936
6937 let addr5 = mm
6939 .set_brk(¤t_task, base_addr)
6940 .expect("failed to drastically shrink brk to zero");
6941 assert_eq!(addr5, base_addr);
6942 assert_eq!(get_range(base_addr), None);
6943 })
6944 .await;
6945 }
6946
6947 #[::fuchsia::test]
6948 async fn test_mm_exec() {
6949 spawn_kernel_and_run(async |current_task| {
6950 let mm = current_task.mm().unwrap().clone();
6951
6952 let has = |addr: UserAddress| -> bool {
6953 let state = mm.state.read();
6954 state.mappings.get(addr).is_some()
6955 };
6956
6957 let brk_addr = mm
6958 .set_brk(¤t_task, UserAddress::default())
6959 .expect("failed to set initial program break");
6960 assert!(brk_addr > UserAddress::default());
6961
6962 let _ = mm
6964 .set_brk(¤t_task, (brk_addr + 1u64).unwrap())
6965 .expect("failed to grow program break");
6966 assert!(has(brk_addr));
6967
6968 let mapped_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
6969 assert!(mapped_addr > UserAddress::default());
6970 assert!(has(mapped_addr));
6971
6972 let node = current_task.lookup_path_from_root("/".into()).unwrap();
6973 let new_mm = MemoryManager::exec(
6974 current_task.thread_group().root_vmar.unowned(),
6975 current_task.running_state().mm.upgrade(),
6976 node,
6977 ArchWidth::Arch64,
6978 )
6979 .expect("failed to exec memory manager");
6980 current_task.set_mm_for_test(new_mm);
6981
6982 assert!(!has(brk_addr));
6983 assert!(!has(mapped_addr));
6984
6985 let brk_addr2 = map_memory(¤t_task, brk_addr, *PAGE_SIZE);
6987 assert_eq!(brk_addr, brk_addr2);
6988 let mapped_addr2 = map_memory(¤t_task, mapped_addr, *PAGE_SIZE);
6989 assert_eq!(mapped_addr, mapped_addr2);
6990 })
6991 .await;
6992 }
6993
6994 #[::fuchsia::test]
6995 async fn test_get_contiguous_mappings_at() {
6996 spawn_kernel_and_run(async |current_task| {
6997 let mm = current_task.mm().unwrap();
6998 let context = &mm.mapping_context;
6999
7000 let page_size = *PAGE_SIZE as usize;
7002 let addr_a = (mm.base_addr + 10 * page_size).unwrap();
7003 let addr_b = (mm.base_addr + 11 * page_size).unwrap();
7004 let addr_c = (mm.base_addr + 12 * page_size).unwrap();
7005 let addr_d = (mm.base_addr + 14 * page_size).unwrap();
7006 assert_eq!(map_memory(¤t_task, addr_a, *PAGE_SIZE), addr_a);
7007 assert_eq!(map_memory(¤t_task, addr_b, *PAGE_SIZE), addr_b);
7008 assert_eq!(map_memory(¤t_task, addr_c, *PAGE_SIZE), addr_c);
7009 assert_eq!(map_memory(¤t_task, addr_d, *PAGE_SIZE), addr_d);
7010
7011 {
7012 let mm_state = mm.state.read();
7013 assert_equal(
7015 mm_state
7016 .get_contiguous_mappings_at((addr_a - 100u64).unwrap(), 50, &context)
7017 .unwrap(),
7018 vec![],
7019 );
7020 assert_equal(
7021 mm_state
7022 .get_contiguous_mappings_at((addr_a - 100u64).unwrap(), 200, &context)
7023 .unwrap(),
7024 vec![],
7025 );
7026
7027 assert_equal(
7029 mm_state.get_contiguous_mappings_at(addr_a, 0, &context).unwrap(),
7030 vec![],
7031 );
7032
7033 assert_eq!(
7035 mm_state
7036 .get_contiguous_mappings_at(UserAddress::from(100), usize::MAX, &context)
7037 .err()
7038 .unwrap(),
7039 errno!(EFAULT)
7040 );
7041 assert_eq!(
7042 mm_state
7043 .get_contiguous_mappings_at(
7044 (context.max_address() + 1u64).unwrap(),
7045 0,
7046 &context
7047 )
7048 .err()
7049 .unwrap(),
7050 errno!(EFAULT)
7051 );
7052 }
7053
7054 assert_eq!(mm.get_mapping_count(), 2);
7055 let mm_state = mm.state.read();
7056 let (map_a, map_b) = {
7057 let mut it = mm_state.mappings.iter();
7058 (it.next().unwrap().1, it.next().unwrap().1)
7059 };
7060
7061 assert_equal(
7062 mm_state.get_contiguous_mappings_at(addr_a, page_size, &context).unwrap(),
7063 vec![(map_a, page_size)],
7064 );
7065
7066 assert_equal(
7067 mm_state.get_contiguous_mappings_at(addr_a, page_size / 2, &context).unwrap(),
7068 vec![(map_a, page_size / 2)],
7069 );
7070
7071 assert_equal(
7072 mm_state.get_contiguous_mappings_at(addr_a, page_size * 3, &context).unwrap(),
7073 vec![(map_a, page_size * 3)],
7074 );
7075
7076 assert_equal(
7077 mm_state.get_contiguous_mappings_at(addr_b, page_size, &context).unwrap(),
7078 vec![(map_a, page_size)],
7079 );
7080
7081 assert_equal(
7082 mm_state.get_contiguous_mappings_at(addr_d, page_size, &context).unwrap(),
7083 vec![(map_b, page_size)],
7084 );
7085
7086 assert_equal(
7088 mm_state
7089 .get_contiguous_mappings_at(
7090 (addr_a + page_size / 2).unwrap(),
7091 page_size * 10,
7092 &context,
7093 )
7094 .unwrap(),
7095 vec![(map_a, page_size * 2 + page_size / 2)],
7096 );
7097
7098 assert_equal(
7100 mm_state.get_contiguous_mappings_at(addr_d, page_size * 10, &context).unwrap(),
7101 vec![(map_b, page_size)],
7102 );
7103 })
7104 .await;
7105 }
7106
7107 #[::fuchsia::test]
7108 async fn test_read_write_crossing_mappings() {
7109 spawn_kernel_and_run(async |current_task| {
7110 let mm = current_task.mm().unwrap();
7111 let ma = current_task.deref();
7112
7113 let page_size = *PAGE_SIZE;
7115 let addr = (mm.base_addr + 10 * page_size).unwrap();
7116 assert_eq!(map_memory(¤t_task, addr, page_size), addr);
7117 assert_eq!(
7118 map_memory(¤t_task, (addr + page_size).unwrap(), page_size),
7119 (addr + page_size).unwrap()
7120 );
7121 assert_eq!(mm.get_mapping_count(), 1);
7123
7124 let test_addr = (addr + page_size / 2).unwrap();
7126 let data: Vec<u8> = (0..page_size).map(|i| (i % 256) as u8).collect();
7127 ma.write_memory(test_addr, &data).expect("failed to write test data");
7128
7129 let data_readback =
7131 ma.read_memory_to_vec(test_addr, data.len()).expect("failed to read test data");
7132 assert_eq!(&data, &data_readback);
7133 })
7134 .await;
7135 }
7136
7137 #[::fuchsia::test]
7138 async fn test_read_write_errors() {
7139 spawn_kernel_and_run(async |current_task| {
7140 let ma = current_task.deref();
7141
7142 let page_size = *PAGE_SIZE;
7143 let addr = map_memory(¤t_task, UserAddress::default(), page_size);
7144 let buf = vec![0u8; page_size as usize];
7145
7146 let partial_addr_before = (addr - page_size / 2).unwrap();
7148 assert_eq!(ma.write_memory(partial_addr_before, &buf), error!(EFAULT));
7149 assert_eq!(ma.read_memory_to_vec(partial_addr_before, buf.len()), error!(EFAULT));
7150 let partial_addr_after = (addr + page_size / 2).unwrap();
7151 assert_eq!(ma.write_memory(partial_addr_after, &buf), error!(EFAULT));
7152 assert_eq!(ma.read_memory_to_vec(partial_addr_after, buf.len()), error!(EFAULT));
7153
7154 let unmapped_addr = (addr - 10 * page_size).unwrap();
7156 assert_eq!(ma.write_memory(unmapped_addr, &buf), error!(EFAULT));
7157 assert_eq!(ma.read_memory_to_vec(unmapped_addr, buf.len()), error!(EFAULT));
7158
7159 ma.write_memory(unmapped_addr, &[]).expect("failed to write no data");
7161 ma.read_memory_to_vec(unmapped_addr, 0).expect("failed to read no data");
7162 })
7163 .await;
7164 }
7165
7166 #[::fuchsia::test]
7167 async fn test_read_c_string_to_vec_large() {
7168 spawn_kernel_and_run(async |current_task| {
7169 let mm = current_task.mm().unwrap();
7170 let ma = current_task.deref();
7171
7172 let page_size = *PAGE_SIZE;
7173 let max_size = 4 * page_size as usize;
7174 let addr = (mm.base_addr + 10 * page_size).unwrap();
7175
7176 assert_eq!(map_memory(¤t_task, addr, max_size as u64), addr);
7177
7178 let mut random_data = vec![0; max_size];
7179 starnix_crypto::cprng_draw(&mut random_data);
7180 for i in 0..random_data.len() {
7182 if random_data[i] == 0 {
7183 random_data[i] = 1;
7184 }
7185 }
7186 random_data[max_size - 1] = 0;
7187
7188 ma.write_memory(addr, &random_data).expect("failed to write test string");
7189 assert_eq!(
7191 ma.read_c_string_to_vec(UserCString::new(current_task, addr), max_size).unwrap(),
7192 random_data[..max_size - 1]
7193 );
7194 })
7195 .await;
7196 }
7197
7198 #[::fuchsia::test]
7199 async fn test_read_c_string_to_vec() {
7200 spawn_kernel_and_run(async |current_task| {
7201 let mm = current_task.mm().unwrap();
7202 let ma = current_task.deref();
7203
7204 let page_size = *PAGE_SIZE;
7205 let max_size = 2 * page_size as usize;
7206 let addr = (mm.base_addr + 10 * page_size).unwrap();
7207
7208 assert_eq!(map_memory(¤t_task, addr, page_size), addr);
7210 let test_str = b"foo!";
7211 let test_addr =
7212 addr.checked_add(page_size as usize).unwrap().checked_sub(test_str.len()).unwrap();
7213 ma.write_memory(test_addr, test_str).expect("failed to write test string");
7214
7215 assert_eq!(
7217 ma.read_c_string_to_vec(UserCString::new(current_task, test_addr), max_size),
7218 error!(ENAMETOOLONG)
7219 );
7220
7221 ma.write_memory((addr + (page_size - 1)).unwrap(), b"\0").expect("failed to write nul");
7223 assert_eq!(
7224 ma.read_c_string_to_vec(UserCString::new(current_task, test_addr), max_size)
7225 .unwrap(),
7226 "foo"
7227 );
7228
7229 assert_eq!(
7231 map_memory(¤t_task, (addr + page_size).unwrap(), page_size),
7232 (addr + page_size).unwrap()
7233 );
7234 ma.write_memory((addr + (page_size - 1)).unwrap(), b"bar\0")
7238 .expect("failed to write extra chars");
7239 assert_eq!(
7240 ma.read_c_string_to_vec(UserCString::new(current_task, test_addr), max_size)
7241 .unwrap(),
7242 "foobar",
7243 );
7244
7245 assert_eq!(
7247 ma.read_c_string_to_vec(UserCString::new(current_task, test_addr), 2),
7248 error!(ENAMETOOLONG)
7249 );
7250
7251 assert_eq!(
7253 ma.read_c_string_to_vec(UserCString::null(current_task), max_size),
7254 error!(EFAULT)
7255 );
7256 })
7257 .await;
7258 }
7259
7260 #[::fuchsia::test]
7261 async fn can_read_argv_like_regions() {
7262 spawn_kernel_and_run(async |current_task| {
7263 let ma = current_task.deref();
7264
7265 let page_size = *PAGE_SIZE;
7267 let addr = map_memory_anywhere(¤t_task, page_size);
7268 assert!(!addr.is_null());
7269
7270 let mut payload = "first".as_bytes().to_vec();
7272 let mut expected_parses = vec![];
7273 ma.write_memory(addr, &payload).unwrap();
7274
7275 expected_parses.push(payload.clone());
7277 payload.push(0);
7278 ma.write_memory(addr, &payload).unwrap();
7279 assert_eq!(
7280 ma.read_nul_delimited_c_string_list(addr, payload.len()).unwrap(),
7281 expected_parses,
7282 );
7283
7284 let second = b"second";
7286 payload.extend(second);
7287 payload.push(0);
7288 expected_parses.push(second.to_vec());
7289
7290 let third = b"third";
7291 payload.extend(third);
7292 payload.push(0);
7293 expected_parses.push(third.to_vec());
7294
7295 ma.write_memory(addr, &payload).unwrap();
7296 assert_eq!(
7297 ma.read_nul_delimited_c_string_list(addr, payload.len()).unwrap(),
7298 expected_parses,
7299 );
7300 })
7301 .await;
7302 }
7303
7304 #[::fuchsia::test]
7305 async fn truncate_argv_like_regions() {
7306 spawn_kernel_and_run(async |current_task| {
7307 let ma = current_task.deref();
7308
7309 let page_size = *PAGE_SIZE;
7311 let addr = map_memory_anywhere(¤t_task, page_size);
7312 assert!(!addr.is_null());
7313
7314 let payload = b"first\0second\0third\0";
7315 ma.write_memory(addr, payload).unwrap();
7316 assert_eq!(
7317 ma.read_nul_delimited_c_string_list(addr, payload.len() - 3).unwrap(),
7318 vec![b"first".to_vec(), b"second".to_vec(), b"thi".to_vec()],
7319 "Skipping last three bytes of payload should skip last two bytes of 3rd string"
7320 );
7321 })
7322 .await;
7323 }
7324
7325 #[::fuchsia::test]
7326 async fn test_read_c_string() {
7327 spawn_kernel_and_run(async |current_task| {
7328 let mm = current_task.mm().unwrap();
7329 let ma = current_task.deref();
7330
7331 let page_size = *PAGE_SIZE;
7332 let buf_cap = 2 * page_size as usize;
7333 let mut buf = Vec::with_capacity(buf_cap);
7334 let buf = &mut buf.spare_capacity_mut()[..buf_cap];
7337 let addr = (mm.base_addr + 10 * page_size).unwrap();
7338
7339 assert_eq!(map_memory(¤t_task, addr, page_size), addr);
7341 let test_str = b"foo!";
7342 let test_addr = (addr + (page_size - test_str.len() as u64)).unwrap();
7343 ma.write_memory(test_addr, test_str).expect("failed to write test string");
7344
7345 assert_eq!(
7347 ma.read_c_string(UserCString::new(current_task, test_addr), buf),
7348 error!(ENAMETOOLONG)
7349 );
7350
7351 ma.write_memory((addr + (page_size - 1)).unwrap(), b"\0").expect("failed to write nul");
7353 assert_eq!(
7354 ma.read_c_string(UserCString::new(current_task, test_addr), buf).unwrap(),
7355 "foo"
7356 );
7357
7358 assert_eq!(
7360 map_memory(¤t_task, (addr + page_size).unwrap(), page_size),
7361 (addr + page_size).unwrap()
7362 );
7363 ma.write_memory((addr + (page_size - 1)).unwrap(), b"bar\0")
7367 .expect("failed to write extra chars");
7368 assert_eq!(
7369 ma.read_c_string(UserCString::new(current_task, test_addr), buf).unwrap(),
7370 "foobar"
7371 );
7372
7373 assert_eq!(
7375 ma.read_c_string(
7376 UserCString::new(current_task, test_addr),
7377 &mut [MaybeUninit::uninit(); 2]
7378 ),
7379 error!(ENAMETOOLONG)
7380 );
7381
7382 assert_eq!(ma.read_c_string(UserCString::null(current_task), buf), error!(EFAULT));
7384 })
7385 .await;
7386 }
7387
7388 #[::fuchsia::test]
7389 async fn test_find_next_unused_range() {
7390 spawn_kernel_and_run(async |current_task| {
7391 let mm = current_task.mm().unwrap();
7392
7393 let mmap_top = mm.state.read().find_next_unused_range(0).unwrap().ptr();
7394 let page_size = *PAGE_SIZE as usize;
7395 assert!(mmap_top <= RESTRICTED_ASPACE_HIGHEST_ADDRESS);
7396
7397 assert_eq!(
7399 mm.state.read().find_next_unused_range(page_size).unwrap(),
7400 UserAddress::from_ptr(mmap_top - page_size)
7401 );
7402
7403 let addr = UserAddress::from_ptr(mmap_top - page_size);
7405 assert_eq!(map_memory(¤t_task, addr, *PAGE_SIZE), addr);
7406
7407 assert_eq!(
7409 mm.state.read().find_next_unused_range(page_size).unwrap(),
7410 UserAddress::from_ptr(addr.ptr() - page_size)
7411 );
7412
7413 let addr2 = UserAddress::from_ptr(addr.ptr() - 2 * page_size);
7415 assert_eq!(map_memory(¤t_task, addr2, *PAGE_SIZE), addr2);
7416
7417 assert_eq!(
7419 mm.state.read().find_next_unused_range(page_size).unwrap(),
7420 UserAddress::from_ptr(addr.ptr() - page_size)
7421 );
7422
7423 assert_eq!(
7425 mm.state.read().find_next_unused_range(2 * page_size).unwrap(),
7426 UserAddress::from_ptr(addr2.ptr() - 2 * page_size)
7427 );
7428
7429 assert_eq!(mm.state.read().find_next_unused_range(mmap_top), None);
7431 })
7432 .await;
7433 }
7434
7435 #[::fuchsia::test]
7436 async fn test_count_placements() {
7437 spawn_kernel_and_run(async |current_task| {
7438 let mm = current_task.mm().unwrap();
7439
7440 let page_size = *PAGE_SIZE as usize;
7442 let subrange_ten = UserAddress::from_ptr(RESTRICTED_ASPACE_BASE)
7443 ..UserAddress::from_ptr(RESTRICTED_ASPACE_BASE + 10 * page_size);
7444
7445 assert_eq!(
7446 mm.state.read().count_possible_placements(11 * page_size, &subrange_ten),
7447 Some(0)
7448 );
7449 assert_eq!(
7450 mm.state.read().count_possible_placements(10 * page_size, &subrange_ten),
7451 Some(1)
7452 );
7453 assert_eq!(
7454 mm.state.read().count_possible_placements(9 * page_size, &subrange_ten),
7455 Some(2)
7456 );
7457 assert_eq!(
7458 mm.state.read().count_possible_placements(page_size, &subrange_ten),
7459 Some(10)
7460 );
7461
7462 let addr = UserAddress::from_ptr(RESTRICTED_ASPACE_BASE + 5 * page_size);
7464 assert_eq!(map_memory(¤t_task, addr, *PAGE_SIZE), addr);
7465
7466 assert_eq!(
7467 mm.state.read().count_possible_placements(10 * page_size, &subrange_ten),
7468 Some(0)
7469 );
7470 assert_eq!(
7471 mm.state.read().count_possible_placements(5 * page_size, &subrange_ten),
7472 Some(1)
7473 );
7474 assert_eq!(
7475 mm.state.read().count_possible_placements(4 * page_size, &subrange_ten),
7476 Some(3)
7477 );
7478 assert_eq!(
7479 mm.state.read().count_possible_placements(page_size, &subrange_ten),
7480 Some(9)
7481 );
7482 })
7483 .await;
7484 }
7485
7486 #[::fuchsia::test]
7487 async fn test_pick_placement() {
7488 spawn_kernel_and_run(async |current_task| {
7489 let mm = current_task.mm().unwrap();
7490
7491 let page_size = *PAGE_SIZE as usize;
7492 let subrange_ten = UserAddress::from_ptr(RESTRICTED_ASPACE_BASE)
7493 ..UserAddress::from_ptr(RESTRICTED_ASPACE_BASE + 10 * page_size);
7494
7495 let addr = UserAddress::from_ptr(RESTRICTED_ASPACE_BASE + 5 * page_size);
7496 assert_eq!(map_memory(¤t_task, addr, *PAGE_SIZE), addr);
7497 assert_eq!(
7498 mm.state.read().count_possible_placements(4 * page_size, &subrange_ten),
7499 Some(3)
7500 );
7501
7502 assert_eq!(
7503 mm.state.read().pick_placement(4 * page_size, 0, &subrange_ten),
7504 Some(UserAddress::from_ptr(RESTRICTED_ASPACE_BASE))
7505 );
7506 assert_eq!(
7507 mm.state.read().pick_placement(4 * page_size, 1, &subrange_ten),
7508 Some(UserAddress::from_ptr(RESTRICTED_ASPACE_BASE + page_size))
7509 );
7510 assert_eq!(
7511 mm.state.read().pick_placement(4 * page_size, 2, &subrange_ten),
7512 Some(UserAddress::from_ptr(RESTRICTED_ASPACE_BASE + 6 * page_size))
7513 );
7514 })
7515 .await;
7516 }
7517
7518 #[::fuchsia::test]
7519 async fn test_find_random_unused_range() {
7520 spawn_kernel_and_run(async |current_task| {
7521 let mm = current_task.mm().unwrap();
7522
7523 let page_size = *PAGE_SIZE as usize;
7525 let subrange_ten = UserAddress::from_ptr(RESTRICTED_ASPACE_BASE)
7526 ..UserAddress::from_ptr(RESTRICTED_ASPACE_BASE + 10 * page_size);
7527
7528 for _ in 0..10 {
7529 let addr = mm.state.read().find_random_unused_range(page_size, &subrange_ten);
7530 assert!(addr.is_some());
7531 assert_eq!(map_memory(¤t_task, addr.unwrap(), *PAGE_SIZE), addr.unwrap());
7532 }
7533 assert_eq!(mm.state.read().find_random_unused_range(page_size, &subrange_ten), None);
7534 })
7535 .await;
7536 }
7537
7538 #[::fuchsia::test]
7539 async fn test_grows_down_near_aspace_base() {
7540 spawn_kernel_and_run(async |current_task| {
7541 let mm = current_task.mm().unwrap();
7542
7543 let page_count = 10;
7544
7545 let page_size = *PAGE_SIZE as usize;
7546 let addr =
7547 (UserAddress::from_ptr(RESTRICTED_ASPACE_BASE) + page_count * page_size).unwrap();
7548 assert_eq!(
7549 map_memory_with_flags(
7550 ¤t_task,
7551 addr,
7552 page_size as u64,
7553 MAP_ANONYMOUS | MAP_PRIVATE | MAP_GROWSDOWN
7554 ),
7555 addr
7556 );
7557
7558 let subrange_ten = UserAddress::from_ptr(RESTRICTED_ASPACE_BASE)..addr;
7559 assert_eq!(mm.state.read().find_random_unused_range(page_size, &subrange_ten), None);
7560 })
7561 .await;
7562 }
7563
7564 #[::fuchsia::test]
7565 async fn test_unmap_returned_mappings() {
7566 spawn_kernel_and_run(async |current_task| {
7567 let mm = current_task.mm().unwrap();
7568
7569 let addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE * 2);
7570
7571 let mut released_mappings = ReleasedMappings::default();
7572 let mut mm_state = mm.state.write();
7573 let unmap_result =
7574 mm_state.unmap(&mm, addr, *PAGE_SIZE as usize, &mut released_mappings);
7575 assert!(unmap_result.is_ok());
7576 assert_eq!(released_mappings.len(), 1);
7577 released_mappings.finalize(mm_state);
7578 })
7579 .await;
7580 }
7581
7582 #[::fuchsia::test]
7583 async fn test_unmap_returns_multiple_mappings() {
7584 spawn_kernel_and_run(async |current_task| {
7585 let mm = current_task.mm().unwrap();
7586
7587 let addr = mm.state.read().find_next_unused_range(3 * *PAGE_SIZE as usize).unwrap();
7588 let addr = map_memory(¤t_task, addr, *PAGE_SIZE);
7589 let _ = map_memory(¤t_task, (addr + 2 * *PAGE_SIZE).unwrap(), *PAGE_SIZE);
7590
7591 let mut released_mappings = ReleasedMappings::default();
7592 let mut mm_state = mm.state.write();
7593 let unmap_result =
7594 mm_state.unmap(&mm, addr, (*PAGE_SIZE * 3) as usize, &mut released_mappings);
7595 assert!(unmap_result.is_ok());
7596 assert_eq!(released_mappings.len(), 2);
7597 released_mappings.finalize(mm_state);
7598 })
7599 .await;
7600 }
7601
7602 #[::fuchsia::test]
7605 async fn test_map_two_unmap_one() {
7606 spawn_kernel_and_run(async |current_task| {
7607 let mm = current_task.mm().unwrap();
7608
7609 let addr_reserve = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE * 2);
7611 let addr1 = do_mmap(
7612 ¤t_task,
7613 addr_reserve,
7614 *PAGE_SIZE as usize,
7615 PROT_READ, MAP_ANONYMOUS | MAP_SHARED | MAP_FIXED,
7617 FdNumber::from_raw(-1),
7618 0,
7619 )
7620 .expect("failed to mmap");
7621 let addr2 = map_memory_with_flags(
7622 ¤t_task,
7623 (addr_reserve + *PAGE_SIZE).unwrap(),
7624 *PAGE_SIZE,
7625 MAP_ANONYMOUS | MAP_SHARED | MAP_FIXED,
7626 );
7627 let state = mm.state.read();
7628 let (range1, _) = state.mappings.get(addr1).expect("mapping");
7629 assert_eq!(range1.start, addr1);
7630 assert_eq!(range1.end, (addr1 + *PAGE_SIZE).unwrap());
7631 let (range2, mapping2) = state.mappings.get(addr2).expect("mapping");
7632 assert_eq!(range2.start, addr2);
7633 assert_eq!(range2.end, (addr2 + *PAGE_SIZE).unwrap());
7634 let original_memory2 = {
7635 match state.get_mapping_backing(mapping2) {
7636 MappingBacking::Memory(backing) => {
7637 assert_eq!(backing.memory().get_size(), *PAGE_SIZE);
7638 backing.memory().clone()
7639 }
7640 MappingBacking::PrivateAnonymous => {
7641 panic!("Unexpected private anonymous mapping")
7642 }
7643 }
7644 };
7645 std::mem::drop(state);
7646
7647 assert_eq!(mm.unmap(addr1, *PAGE_SIZE as usize), Ok(()));
7648
7649 let state = mm.state.read();
7650
7651 assert!(state.mappings.get(addr1).is_none());
7653
7654 let (range2, mapping2) = state.mappings.get(addr2).expect("second page");
7656 assert_eq!(range2.start, addr2);
7657 assert_eq!(range2.end, (addr2 + *PAGE_SIZE).unwrap());
7658 match state.get_mapping_backing(mapping2) {
7659 MappingBacking::Memory(backing) => {
7660 assert_eq!(backing.memory().get_size(), *PAGE_SIZE);
7661 assert_eq!(original_memory2.get_koid(), backing.memory().get_koid());
7662 }
7663 MappingBacking::PrivateAnonymous => panic!("Unexpected private anonymous mapping"),
7664 }
7665 })
7666 .await;
7667 }
7668
7669 #[::fuchsia::test]
7670 async fn test_read_write_objects() {
7671 spawn_kernel_and_run(async |current_task| {
7672 let ma = current_task.deref();
7673 let addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
7674 let items_ref = UserRef::<i32>::new(addr);
7675
7676 let items_written = vec![0, 2, 3, 7, 1];
7677 ma.write_objects(items_ref, &items_written).expect("Failed to write object array.");
7678
7679 let items_read = ma
7680 .read_objects_to_vec(items_ref, items_written.len())
7681 .expect("Failed to read object array.");
7682
7683 assert_eq!(items_written, items_read);
7684 })
7685 .await;
7686 }
7687
7688 #[::fuchsia::test]
7689 async fn test_read_write_objects_null() {
7690 spawn_kernel_and_run(async |current_task| {
7691 let ma = current_task.deref();
7692 let items_ref = UserRef::<i32>::new(UserAddress::default());
7693
7694 let items_written = vec![];
7695 ma.write_objects(items_ref, &items_written)
7696 .expect("Failed to write empty object array.");
7697
7698 let items_read = ma
7699 .read_objects_to_vec(items_ref, items_written.len())
7700 .expect("Failed to read empty object array.");
7701
7702 assert_eq!(items_written, items_read);
7703 })
7704 .await;
7705 }
7706
7707 #[::fuchsia::test]
7708 async fn test_read_object_partial() {
7709 #[derive(Debug, Default, Copy, Clone, KnownLayout, FromBytes, Immutable, PartialEq)]
7710 struct Items {
7711 val: [i32; 4],
7712 }
7713
7714 spawn_kernel_and_run(async |current_task| {
7715 let ma = current_task.deref();
7716 let addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
7717 let items_array_ref = UserRef::<i32>::new(addr);
7718
7719 let items_written = vec![75, 23, 51, 98];
7721 ma.write_objects(items_array_ref, &items_written)
7722 .expect("Failed to write object array.");
7723
7724 let items_ref = UserRef::<Items>::new(addr);
7726 let items_read = ma
7727 .read_object_partial(items_ref, std::mem::size_of::<Items>())
7728 .expect("Failed to read object");
7729 assert_eq!(items_written, items_read.val);
7730
7731 let items_read = ma.read_object_partial(items_ref, 8).expect("Failed to read object");
7733 assert_eq!(vec![75, 23, 0, 0], items_read.val);
7734
7735 let items_read = ma.read_object_partial(items_ref, 0).expect("Failed to read object");
7738 assert_eq!(vec![0, 0, 0, 0], items_read.val);
7739
7740 assert_eq!(
7742 ma.read_object_partial(items_ref, std::mem::size_of::<Items>() + 8),
7743 error!(EINVAL)
7744 );
7745
7746 assert_eq!(
7748 ma.read_object_partial(UserRef::<Items>::new(UserAddress::from(1)), 16),
7749 error!(EFAULT)
7750 );
7751 })
7752 .await;
7753 }
7754
7755 #[::fuchsia::test]
7756 async fn test_partial_read() {
7757 spawn_kernel_and_run(async |current_task| {
7758 let mm = current_task.mm().unwrap();
7759 let ma = current_task.deref();
7760 let task_ma: &Task = ¤t_task.task;
7761
7762 let addr = mm.state.read().find_next_unused_range(2 * *PAGE_SIZE as usize).unwrap();
7763 let addr = map_memory(¤t_task, addr, *PAGE_SIZE);
7764 let second_map = map_memory(¤t_task, (addr + *PAGE_SIZE).unwrap(), *PAGE_SIZE);
7765
7766 let bytes = vec![0xf; (*PAGE_SIZE * 2) as usize];
7767 assert!(ma.write_memory(addr, &bytes).is_ok());
7768 let mut state = mm.state.write();
7769 let mut released_mappings = ReleasedMappings::default();
7770 state
7771 .protect(
7772 ma,
7773 second_map,
7774 *PAGE_SIZE as usize,
7775 ProtectionFlags::empty(),
7776 PersonalityFlags::empty(),
7777 &ExecutableMemoryProbes::default(),
7778 &mut released_mappings,
7779 )
7780 .unwrap();
7781 released_mappings.finalize(state);
7782 assert_eq!(
7783 ma.read_memory_partial_to_vec(addr, bytes.len()).unwrap().len(),
7784 *PAGE_SIZE as usize,
7785 );
7786 assert_eq!(
7787 task_ma.read_memory_partial_to_vec(addr, bytes.len()).unwrap().len(),
7788 *PAGE_SIZE as usize,
7789 );
7790 assert_eq!(ma.read_memory_partial_to_vec(second_map, bytes.len()), error!(EFAULT));
7791 assert_eq!(task_ma.read_memory_partial_to_vec(second_map, bytes.len()), error!(EFAULT));
7792 })
7793 .await;
7794 }
7795
7796 #[::fuchsia::test]
7797 async fn test_partial_write() {
7798 spawn_kernel_and_run(async |current_task| {
7799 let mm = current_task.mm().unwrap();
7800 let ma = current_task.deref();
7801 let task_ma: &Task = ¤t_task.task;
7802
7803 let addr = mm.state.read().find_next_unused_range(2 * *PAGE_SIZE as usize).unwrap();
7804 let addr = map_memory(¤t_task, addr, *PAGE_SIZE);
7805 let second_map = map_memory(¤t_task, (addr + *PAGE_SIZE).unwrap(), *PAGE_SIZE);
7806
7807 let mut state = mm.state.write();
7808 let mut released_mappings = ReleasedMappings::default();
7809 state
7810 .protect(
7811 ma,
7812 second_map,
7813 *PAGE_SIZE as usize,
7814 ProtectionFlags::empty(),
7815 PersonalityFlags::empty(),
7816 &ExecutableMemoryProbes::default(),
7817 &mut released_mappings,
7818 )
7819 .unwrap();
7820 released_mappings.finalize(state);
7821
7822 let bytes = vec![0xab; (*PAGE_SIZE * 2) as usize];
7823 assert_eq!(ma.write_memory_partial(addr, &bytes), Ok(*PAGE_SIZE as usize));
7824 assert_eq!(
7825 ma.read_memory_to_vec(addr, *PAGE_SIZE as usize).unwrap(),
7826 &bytes[..*PAGE_SIZE as usize]
7827 );
7828
7829 let bytes2 = vec![0xcd; (*PAGE_SIZE * 2) as usize];
7830 assert_eq!(task_ma.write_memory_partial(addr, &bytes2), Ok(*PAGE_SIZE as usize));
7831 assert_eq!(
7832 task_ma.read_memory_to_vec(addr, *PAGE_SIZE as usize).unwrap(),
7833 &bytes2[..*PAGE_SIZE as usize]
7834 );
7835
7836 assert_eq!(ma.write_memory_partial(second_map, &bytes), error!(EFAULT));
7837 assert_eq!(task_ma.write_memory_partial(second_map, &bytes), error!(EFAULT));
7838 assert_eq!(ma.write_memory_partial(second_map, &[]), Ok(0));
7839 assert_eq!(task_ma.write_memory_partial(second_map, &[]), Ok(0));
7840 })
7841 .await;
7842 }
7843
7844 fn map_memory_growsdown(current_task: &CurrentTask, length: u64) -> UserAddress {
7845 map_memory_with_flags(
7846 current_task,
7847 UserAddress::default(),
7848 length,
7849 MAP_ANONYMOUS | MAP_PRIVATE | MAP_GROWSDOWN,
7850 )
7851 }
7852
7853 #[::fuchsia::test]
7854 async fn test_grow_mapping_empty_mm() {
7855 spawn_kernel_and_run(async |current_task| {
7856 let mm = current_task.mm().unwrap();
7857
7858 let addr = UserAddress::from(0x100000);
7859
7860 assert_matches!(mm.extend_growsdown_mapping_to_address(addr, false), Ok(false));
7861 })
7862 .await;
7863 }
7864
7865 #[::fuchsia::test]
7866 async fn test_grow_inside_mapping() {
7867 spawn_kernel_and_run(async |current_task| {
7868 let mm = current_task.mm().unwrap();
7869
7870 let addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
7871
7872 assert_matches!(mm.extend_growsdown_mapping_to_address(addr, false), Ok(false));
7873 })
7874 .await;
7875 }
7876
7877 #[::fuchsia::test]
7878 async fn test_grow_write_fault_inside_read_only_mapping() {
7879 spawn_kernel_and_run(async |current_task| {
7880 let mm = current_task.mm().unwrap();
7881
7882 let addr = do_mmap(
7883 ¤t_task,
7884 UserAddress::default(),
7885 *PAGE_SIZE as usize,
7886 PROT_READ,
7887 MAP_ANONYMOUS | MAP_PRIVATE,
7888 FdNumber::from_raw(-1),
7889 0,
7890 )
7891 .expect("Could not map memory");
7892
7893 assert_matches!(mm.extend_growsdown_mapping_to_address(addr, false), Ok(false));
7894 assert_matches!(mm.extend_growsdown_mapping_to_address(addr, true), Ok(false));
7895 })
7896 .await;
7897 }
7898
7899 #[::fuchsia::test]
7900 async fn test_grow_fault_inside_prot_none_mapping() {
7901 spawn_kernel_and_run(async |current_task| {
7902 let mm = current_task.mm().unwrap();
7903
7904 let addr = do_mmap(
7905 ¤t_task,
7906 UserAddress::default(),
7907 *PAGE_SIZE as usize,
7908 PROT_NONE,
7909 MAP_ANONYMOUS | MAP_PRIVATE,
7910 FdNumber::from_raw(-1),
7911 0,
7912 )
7913 .expect("Could not map memory");
7914
7915 assert_matches!(mm.extend_growsdown_mapping_to_address(addr, false), Ok(false));
7916 assert_matches!(mm.extend_growsdown_mapping_to_address(addr, true), Ok(false));
7917 })
7918 .await;
7919 }
7920
7921 #[::fuchsia::test]
7922 async fn test_grow_below_mapping() {
7923 spawn_kernel_and_run(async |current_task| {
7924 let mm = current_task.mm().unwrap();
7925
7926 let addr = map_memory_growsdown(¤t_task, *PAGE_SIZE) - *PAGE_SIZE;
7927
7928 assert_matches!(mm.extend_growsdown_mapping_to_address(addr.unwrap(), false), Ok(true));
7929 })
7930 .await;
7931 }
7932
7933 #[::fuchsia::test]
7934 async fn test_handle_page_fault_growsdown() {
7935 spawn_kernel_and_run(async |current_task| {
7936 let mm = current_task.mm().unwrap();
7937
7938 let mapped_addr = map_memory_growsdown(¤t_task, *PAGE_SIZE);
7939 let fault_addr = (mapped_addr - *PAGE_SIZE).unwrap();
7940 assert!(mm.state.read().mappings.get(fault_addr).is_none());
7941
7942 #[cfg(target_arch = "aarch64")]
7943 let raw_faulting_address = fault_addr.ptr() as u64 | (0xab << 56);
7944 #[cfg(not(target_arch = "aarch64"))]
7945 let raw_faulting_address = fault_addr.ptr() as u64;
7946
7947 let make_report = || PageFaultExceptionReport {
7948 faulting_address: raw_faulting_address,
7949 not_present: true,
7950 is_write: true,
7951 is_execute: false,
7952 };
7953
7954 assert!(matches!(
7957 mm.handle_page_fault(make_report(), zx::Status::NOT_FOUND),
7958 ExceptionResult::Handled
7959 ));
7960 assert!(mm.state.read().mappings.get(fault_addr).is_none());
7961
7962 assert!(matches!(
7964 mm.handle_page_fault(make_report(), zx::Status::NOT_FOUND),
7965 ExceptionResult::Handled
7966 ));
7967 assert!(mm.state.read().mappings.get(fault_addr).is_some());
7968 })
7969 .await;
7970 }
7971
7972 #[::fuchsia::test]
7973 async fn test_growsdown_vm_stack_stats() {
7974 spawn_kernel_with_features_and_run(
7975 async |current_task| {
7976 let mm = current_task.mm().unwrap();
7977 let page_size = *PAGE_SIZE as usize;
7978
7979 assert_eq!(
7980 mm.get_stats(¤t_task, SelfStatsCacheMode::AllowCached).vm_stack,
7981 0
7982 );
7983
7984 let _regular_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
7987 assert_eq!(
7988 mm.get_stats(¤t_task, SelfStatsCacheMode::AllowCached).vm_stack,
7989 0
7990 );
7991
7992 let growsdown_addr = map_memory_growsdown(¤t_task, *PAGE_SIZE);
7993 assert_eq!(
7994 mm.get_stats(¤t_task, SelfStatsCacheMode::AllowCached).vm_stack,
7995 page_size
7996 );
7997
7998 let extended_low = (growsdown_addr - 2 * *PAGE_SIZE).unwrap();
8000 assert_matches!(
8001 mm.extend_growsdown_mapping_to_address(extended_low, false),
8002 Ok(true)
8003 );
8004 assert_eq!(
8005 mm.get_stats(¤t_task, SelfStatsCacheMode::AllowCached).vm_stack,
8006 3 * page_size
8007 );
8008
8009 mm.unmap(extended_low, 3 * page_size).unwrap();
8011 assert_eq!(
8012 mm.get_stats(¤t_task, SelfStatsCacheMode::AllowCached).vm_stack,
8013 0
8014 );
8015 },
8016 KernelFeatures { cached_zx_map_info_bytes: *PAGE_SIZE as u32, ..Default::default() },
8021 )
8022 .await;
8023 }
8024
8025 #[::fuchsia::test]
8026 async fn test_grow_above_mapping() {
8027 spawn_kernel_and_run(async |current_task| {
8028 let mm = current_task.mm().unwrap();
8029
8030 let addr = map_memory_growsdown(¤t_task, *PAGE_SIZE) + *PAGE_SIZE;
8031
8032 assert_matches!(
8033 mm.extend_growsdown_mapping_to_address(addr.unwrap(), false),
8034 Ok(false)
8035 );
8036 })
8037 .await;
8038 }
8039
8040 #[::fuchsia::test]
8041 async fn test_grow_write_fault_below_read_only_mapping() {
8042 spawn_kernel_and_run(async |current_task| {
8043 let mm = current_task.mm().unwrap();
8044
8045 let mapped_addr = map_memory_growsdown(¤t_task, *PAGE_SIZE);
8046
8047 mm.protect(¤t_task, mapped_addr, *PAGE_SIZE as usize, ProtectionFlags::READ)
8048 .unwrap();
8049
8050 assert_matches!(
8051 mm.extend_growsdown_mapping_to_address((mapped_addr - *PAGE_SIZE).unwrap(), true),
8052 Ok(false)
8053 );
8054
8055 assert_eq!(mm.get_mapping_count(), 1);
8056 })
8057 .await;
8058 }
8059
8060 #[::fuchsia::test]
8061 async fn test_grow_fault_below_prot_none_mapping() {
8062 spawn_kernel_and_run(async |current_task| {
8063 let mm = current_task.mm().unwrap();
8064
8065 let mapped_addr = map_memory_growsdown(¤t_task, *PAGE_SIZE);
8066
8067 mm.protect(¤t_task, mapped_addr, *PAGE_SIZE as usize, ProtectionFlags::empty())
8068 .unwrap();
8069
8070 assert_matches!(
8071 mm.extend_growsdown_mapping_to_address((mapped_addr - *PAGE_SIZE).unwrap(), false),
8072 Ok(false)
8073 );
8074 assert_matches!(
8075 mm.extend_growsdown_mapping_to_address((mapped_addr - *PAGE_SIZE).unwrap(), true),
8076 Ok(false)
8077 );
8078
8079 assert_eq!(mm.get_mapping_count(), 1);
8080 })
8081 .await;
8082 }
8083
8084 #[::fuchsia::test]
8085 async fn test_usercopy_growsdown_write_and_read() {
8086 spawn_kernel_and_run(async |current_task| {
8087 let mapped_addr = map_memory_growsdown(¤t_task, *PAGE_SIZE);
8088 let read_addr = (mapped_addr - 100usize).unwrap();
8089
8090 let mut read_buf = [std::mem::MaybeUninit::uninit(); 24];
8092 let read_data = current_task.read_memory(read_addr, &mut read_buf).unwrap();
8093 assert_eq!(read_data, &[0u8; 24]);
8094
8095 let write_addr = (read_addr - *PAGE_SIZE).unwrap();
8097 let test_data = b"hello growsdown usercopy";
8098 assert_matches!(
8099 current_task.write_memory(write_addr, test_data),
8100 Ok(len) if len == test_data.len()
8101 );
8102
8103 let mut read_buf = [std::mem::MaybeUninit::uninit(); 24];
8104 let read_data = current_task.read_memory(write_addr, &mut read_buf).unwrap();
8105 assert_eq!(read_data, test_data);
8106
8107 let mm = current_task.mm().unwrap();
8110 assert_matches!(
8111 mm.extend_growsdown_mapping_to_address(UserAddress::NULL, false),
8112 Ok(false)
8113 );
8114 assert_eq!(current_task.read_memory(UserAddress::NULL, &mut read_buf), error!(EFAULT));
8115 assert_eq!(current_task.write_memory(UserAddress::NULL, test_data), error!(EFAULT));
8116 assert_eq!(current_task.zero(UserAddress::NULL, 16), error!(EFAULT));
8117 })
8118 .await;
8119 }
8120
8121 #[::fuchsia::test]
8122 async fn test_syscall_growsdown_write_and_read() {
8123 spawn_kernel_and_run(async |current_task| {
8124 let task_ma: &Task = ¤t_task.task;
8125 let mapped_addr = map_memory_growsdown(¤t_task, *PAGE_SIZE);
8126 let read_addr = (mapped_addr - 100usize).unwrap();
8127
8128 let mut read_buf = [std::mem::MaybeUninit::uninit(); 24];
8130 let read_data = task_ma.read_memory(read_addr, &mut read_buf).unwrap();
8131 assert_eq!(read_data, &[0u8; 24]);
8132
8133 let write_addr = (read_addr - *PAGE_SIZE).unwrap();
8135 let test_data = b"hello growsdown syscall\0";
8136 assert_matches!(
8137 task_ma.write_memory(write_addr, test_data),
8138 Ok(len) if len == test_data.len()
8139 );
8140
8141 let mut read_buf = [std::mem::MaybeUninit::uninit(); 32];
8142 let read_cstr =
8143 task_ma.read_memory_partial_until_null_byte(write_addr, &mut read_buf).unwrap();
8144 assert_eq!(read_cstr, test_data);
8145
8146 let zero_addr = (write_addr - *PAGE_SIZE).unwrap();
8148 assert_eq!(task_ma.zero(zero_addr, 16), Ok(16));
8149
8150 assert_eq!(task_ma.read_memory(UserAddress::NULL, &mut read_buf), error!(EFAULT));
8153 assert_eq!(task_ma.write_memory(UserAddress::NULL, test_data), error!(EFAULT));
8154 assert_eq!(task_ma.zero(UserAddress::NULL, 16), error!(EFAULT));
8155 })
8156 .await;
8157 }
8158
8159 #[::fuchsia::test]
8160 async fn test_snapshot_paged_memory() {
8161 use zx::sys::zx_page_request_command_t::ZX_PAGER_VMO_READ;
8162
8163 spawn_kernel_and_run(async |current_task| {
8164 let mm = current_task.mm().unwrap();
8165
8166 let port = Arc::new(zx::Port::create());
8167 let port_clone = port.clone();
8168 let pager =
8169 Arc::new(zx::Pager::create(zx::PagerOptions::empty()).expect("create failed"));
8170 let pager_clone = pager.clone();
8171
8172 const VMO_SIZE: u64 = 128 * 1024;
8173 let vmo = Arc::new(
8174 pager
8175 .create_vmo(zx::VmoOptions::RESIZABLE, &port, 1, VMO_SIZE)
8176 .expect("create_vmo failed"),
8177 );
8178 let vmo_clone = vmo.clone();
8179
8180 let thread = std::thread::spawn(move || {
8182 loop {
8183 let packet =
8184 port_clone.wait(zx::MonotonicInstant::INFINITE).expect("wait failed");
8185 match packet.contents() {
8186 zx::PacketContents::Pager(contents) => {
8187 if contents.command() == ZX_PAGER_VMO_READ {
8188 let range = contents.range();
8189 let source_vmo = zx::Vmo::create(range.end - range.start)
8190 .expect("create failed");
8191 pager_clone
8192 .supply_pages(&vmo_clone, range, &source_vmo, 0)
8193 .expect("supply_pages failed");
8194 }
8195 }
8196 zx::PacketContents::User(_) => break,
8197 _ => {}
8198 }
8199 }
8200 });
8201
8202 let child_vmo = vmo
8203 .create_child(zx::VmoChildOptions::SNAPSHOT_AT_LEAST_ON_WRITE, 0, VMO_SIZE)
8204 .unwrap();
8205
8206 vmo.write(b"foo", 0).expect("write failed");
8208
8209 let prot_flags = ProtectionFlags::READ | ProtectionFlags::WRITE;
8210 let addr = mm
8211 .map_memory(
8212 DesiredAddress::Any,
8213 Arc::new(MemoryObject::from(child_vmo)),
8214 0,
8215 VMO_SIZE as usize,
8216 prot_flags,
8217 MappingOptions::empty(),
8218 MappingName::None,
8219 )
8220 .expect("map failed");
8221
8222 let target = current_task.clone_task_for_test(0, None);
8223
8224 let buf = target.read_memory_to_vec(addr, 3).expect("read_memory failed");
8226 assert_eq!(buf, b"foo");
8227
8228 let buf = current_task.deref().read_memory_to_vec(addr, 3).expect("read_memory failed");
8229 assert_eq!(buf, b"foo");
8230
8231 port.queue(&zx::Packet::from_user_packet(0, 0, zx::UserPacket::from_u8_array([0; 32])))
8232 .unwrap();
8233 thread.join().unwrap();
8234 })
8235 .await;
8236 }
8237
8238 #[::fuchsia::test]
8239 async fn test_remap_preserves_cow_modified() {
8240 spawn_kernel_and_run(async |current_task| {
8241 let mm = current_task.mm().unwrap();
8242 let page_size = *PAGE_SIZE as usize;
8243 let has_cow_modifications = |addr: UserAddress| {
8244 let state = mm.state.read();
8245 let (_, mapping) = state.mappings.get(addr).expect("mapping");
8246 mapping.has_cow_modifications()
8247 };
8248
8249 let file =
8251 new_memfd(¤t_task, b"test_memfd".into(), SealFlags::empty(), OpenFlags::RDWR)
8252 .unwrap();
8253 let vmo = zx::Vmo::create(4 * page_size as u64).expect("create VMO");
8254 let addr = mm
8255 .map_memory(
8256 DesiredAddress::Any,
8257 Arc::new(MemoryObject::from(vmo)),
8258 0,
8259 3 * page_size,
8260 ProtectionFlags::READ | ProtectionFlags::WRITE,
8261 MappingOptions::empty(),
8262 MappingName::File(file.to_mapping(None).expect("to_mapping")),
8263 )
8264 .expect("map failed");
8265 mm.unmap((addr + page_size).unwrap(), 2 * page_size).expect("unmap failed");
8266 assert!(!has_cow_modifications(addr));
8267
8268 {
8270 let mut state = mm.state.write();
8271 let (range, mapping) = state.mappings.get(addr).expect("mapping");
8272 let (range, mut mapping) = (range.clone(), mapping.clone());
8273 mapping.set_cow_modified();
8274 let _released = state.mappings.insert(range, mapping);
8275 }
8276 assert!(has_cow_modifications(addr));
8277
8278 let grown_addr = mm
8280 .remap(
8281 ¤t_task,
8282 addr,
8283 page_size,
8284 2 * page_size,
8285 MremapFlags::empty(),
8286 UserAddress::default(),
8287 )
8288 .expect("remap in place failed");
8289 assert_eq!(grown_addr, addr);
8290 assert!(has_cow_modifications(addr));
8291
8292 let dst_addr = map_memory(¤t_task, UserAddress::default(), 3 * page_size as u64);
8294 mm.unmap(dst_addr, 3 * page_size).expect("unmap failed");
8295 let moved_addr = mm
8296 .remap(
8297 ¤t_task,
8298 addr,
8299 2 * page_size,
8300 3 * page_size,
8301 MremapFlags::MAYMOVE | MremapFlags::FIXED,
8302 dst_addr,
8303 )
8304 .expect("remap move failed");
8305 assert_eq!(moved_addr, dst_addr);
8306 assert!(has_cow_modifications(dst_addr));
8307 })
8308 .await;
8309 }
8310
8311 #[::fuchsia::test]
8312 async fn test_set_vma_name() {
8313 spawn_kernel_and_run(async |mut current_task| {
8314 let name_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
8315
8316 let vma_name = "vma name";
8317 current_task.write_memory(name_addr, vma_name.as_bytes()).unwrap();
8318
8319 let mapping_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
8320
8321 sys_prctl(
8322 &mut current_task,
8323 PR_SET_VMA,
8324 PR_SET_VMA_ANON_NAME as u64,
8325 mapping_addr.ptr() as u64,
8326 *PAGE_SIZE,
8327 name_addr.ptr() as u64,
8328 )
8329 .unwrap();
8330
8331 assert_eq!(
8332 *current_task.mm().unwrap().get_mapping_name(mapping_addr).unwrap().unwrap(),
8333 vma_name
8334 );
8335 })
8336 .await;
8337 }
8338
8339 #[::fuchsia::test]
8340 async fn test_set_vma_name_adjacent_mappings() {
8341 spawn_kernel_and_run(async |mut current_task| {
8342 let name_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
8343 current_task
8344 .write_memory(name_addr, CString::new("foo").unwrap().as_bytes_with_nul())
8345 .unwrap();
8346
8347 let first_mapping_addr =
8348 map_memory(¤t_task, UserAddress::default(), 2 * *PAGE_SIZE);
8349 let second_mapping_addr = map_memory_with_flags(
8350 ¤t_task,
8351 (first_mapping_addr + *PAGE_SIZE).unwrap(),
8352 *PAGE_SIZE,
8353 MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
8354 );
8355
8356 assert_eq!((first_mapping_addr + *PAGE_SIZE).unwrap(), second_mapping_addr);
8357
8358 sys_prctl(
8359 &mut current_task,
8360 PR_SET_VMA,
8361 PR_SET_VMA_ANON_NAME as u64,
8362 first_mapping_addr.ptr() as u64,
8363 2 * *PAGE_SIZE,
8364 name_addr.ptr() as u64,
8365 )
8366 .unwrap();
8367
8368 {
8369 let mm = current_task.mm().unwrap();
8370 let state = mm.state.read();
8371
8372 let (_, mapping) = state.mappings.get(first_mapping_addr).unwrap();
8374 assert_eq!(mapping.name(), MappingName::Vma("foo".into()));
8375
8376 let (_, mapping) = state.mappings.get(second_mapping_addr).unwrap();
8377 assert_eq!(mapping.name(), MappingName::Vma("foo".into()));
8378 }
8379 })
8380 .await;
8381 }
8382
8383 #[::fuchsia::test]
8384 async fn test_set_vma_name_beyond_end() {
8385 spawn_kernel_and_run(async |mut current_task| {
8386 let name_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
8387 current_task
8388 .write_memory(name_addr, CString::new("foo").unwrap().as_bytes_with_nul())
8389 .unwrap();
8390
8391 let mapping_addr = map_memory(¤t_task, UserAddress::default(), 2 * *PAGE_SIZE);
8392
8393 let second_page = (mapping_addr + *PAGE_SIZE).unwrap();
8394 current_task.mm().unwrap().unmap(second_page, *PAGE_SIZE as usize).unwrap();
8395
8396 assert_eq!(
8398 sys_prctl(
8399 &mut current_task,
8400 PR_SET_VMA,
8401 PR_SET_VMA_ANON_NAME as u64,
8402 mapping_addr.ptr() as u64,
8403 2 * *PAGE_SIZE,
8404 name_addr.ptr() as u64,
8405 ),
8406 error!(ENOMEM)
8407 );
8408
8409 {
8411 let mm = current_task.mm().unwrap();
8412 let state = mm.state.read();
8413
8414 let (_, mapping) = state.mappings.get(mapping_addr).unwrap();
8415 assert_eq!(mapping.name(), MappingName::Vma("foo".into()));
8416 }
8417 })
8418 .await;
8419 }
8420
8421 #[::fuchsia::test]
8422 async fn test_set_vma_name_before_start() {
8423 spawn_kernel_and_run(async |mut current_task| {
8424 let name_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
8425 current_task
8426 .write_memory(name_addr, CString::new("foo").unwrap().as_bytes_with_nul())
8427 .unwrap();
8428
8429 let mapping_addr = map_memory(¤t_task, UserAddress::default(), 2 * *PAGE_SIZE);
8430
8431 let second_page = (mapping_addr + *PAGE_SIZE).unwrap();
8432 current_task.mm().unwrap().unmap(mapping_addr, *PAGE_SIZE as usize).unwrap();
8433
8434 assert_eq!(
8436 sys_prctl(
8437 &mut current_task,
8438 PR_SET_VMA,
8439 PR_SET_VMA_ANON_NAME as u64,
8440 mapping_addr.ptr() as u64,
8441 2 * *PAGE_SIZE,
8442 name_addr.ptr() as u64,
8443 ),
8444 error!(ENOMEM)
8445 );
8446
8447 {
8450 let mm = current_task.mm().unwrap();
8451 let state = mm.state.read();
8452
8453 let (_, mapping) = state.mappings.get(second_page).unwrap();
8454 assert_eq!(mapping.name(), MappingName::None);
8455 }
8456 })
8457 .await;
8458 }
8459
8460 #[::fuchsia::test]
8461 async fn test_set_vma_name_partial() {
8462 spawn_kernel_and_run(async |mut current_task| {
8463 let name_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
8464 current_task
8465 .write_memory(name_addr, CString::new("foo").unwrap().as_bytes_with_nul())
8466 .unwrap();
8467
8468 let mapping_addr = map_memory(¤t_task, UserAddress::default(), 3 * *PAGE_SIZE);
8469
8470 assert_eq!(
8471 sys_prctl(
8472 &mut current_task,
8473 PR_SET_VMA,
8474 PR_SET_VMA_ANON_NAME as u64,
8475 (mapping_addr + *PAGE_SIZE).unwrap().ptr() as u64,
8476 *PAGE_SIZE,
8477 name_addr.ptr() as u64,
8478 ),
8479 Ok(starnix_syscalls::SUCCESS)
8480 );
8481
8482 {
8484 let mm = current_task.mm().unwrap();
8485 let state = mm.state.read();
8486
8487 let (_, mapping) = state.mappings.get(mapping_addr).unwrap();
8488 assert_eq!(mapping.name(), MappingName::None);
8489
8490 let (_, mapping) =
8491 state.mappings.get((mapping_addr + *PAGE_SIZE).unwrap()).unwrap();
8492 assert_eq!(mapping.name(), MappingName::Vma("foo".into()));
8493
8494 let (_, mapping) =
8495 state.mappings.get((mapping_addr + (2 * *PAGE_SIZE)).unwrap()).unwrap();
8496 assert_eq!(mapping.name(), MappingName::None);
8497 }
8498 })
8499 .await;
8500 }
8501
8502 #[::fuchsia::test]
8503 async fn test_preserve_name_snapshot() {
8504 spawn_kernel_and_run(async |mut current_task| {
8505 let name_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
8506 current_task
8507 .write_memory(name_addr, CString::new("foo").unwrap().as_bytes_with_nul())
8508 .unwrap();
8509
8510 let mapping_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
8511
8512 assert_eq!(
8513 sys_prctl(
8514 &mut current_task,
8515 PR_SET_VMA,
8516 PR_SET_VMA_ANON_NAME as u64,
8517 mapping_addr.ptr() as u64,
8518 *PAGE_SIZE,
8519 name_addr.ptr() as u64,
8520 ),
8521 Ok(starnix_syscalls::SUCCESS)
8522 );
8523
8524 let target = current_task.clone_task_for_test(0, None);
8525
8526 {
8527 let mm = target.mm().unwrap();
8528 let state = mm.state.read();
8529
8530 let (_, mapping) = state.mappings.get(mapping_addr).unwrap();
8531 assert_eq!(mapping.name(), MappingName::Vma("foo".into()));
8532 }
8533 })
8534 .await;
8535 }
8536
8537 #[::fuchsia::test]
8538 fn test_fill_contiguous_entries_vectorized() {
8539 let mut slice = [0u64; 512];
8540 let flags = 0x8000_0000_0000_0000;
8541 let start_pfn = 0x1000;
8542 ProcPagemapFile::fill_contiguous_entries(&mut slice, flags, start_pfn, true);
8543 for (i, &entry) in slice.iter().enumerate() {
8544 assert_eq!(entry, flags | (start_pfn + i as u64));
8545 }
8546 }
8547
8548 #[::fuchsia::test]
8549 fn test_fill_contiguous_entries_overflow() {
8550 let mut slice = [0u64; 10];
8551 let flags = 0x8000_0000_0000_0000;
8552 let start_pfn = PAGEMAP_PFN_MASK - 5;
8553 ProcPagemapFile::fill_contiguous_entries(&mut slice, flags, start_pfn, true);
8554 for (i, &entry) in slice.iter().enumerate() {
8555 let expected_pfn = (start_pfn.wrapping_add(i as u64)) & PAGEMAP_PFN_MASK;
8556 assert_eq!(entry, flags | expected_pfn);
8557 }
8558 assert_eq!(slice[5], flags | PAGEMAP_PFN_MASK);
8559 assert_eq!(slice[6], flags | 0);
8560 }
8561
8562 #[::fuchsia::test]
8563 fn test_fill_contiguous_entries_unprivileged() {
8564 let mut slice = [0u64; 10];
8565 let flags = 0x8000_0000_0000_0000;
8566 let start_pfn = 0x1000;
8567 ProcPagemapFile::fill_contiguous_entries(&mut slice, flags, start_pfn, false);
8568 for &entry in slice.iter() {
8569 assert_eq!(entry, flags);
8570 }
8571 }
8572
8573 fn mapping_memory_koid(mm: &MemoryManager, addr: UserAddress) -> zx::Koid {
8575 let state = mm.state.read();
8576 let (_, mapping) = state.mappings.get(addr).expect("address should be mapped");
8577 let MappingBacking::Memory(backing) = mapping.get_backing_internal() else {
8578 panic!("mapping should have Memory backing");
8579 };
8580 backing.memory().get_koid()
8581 }
8582
8583 fn mlock_shadow_process_pinned_koids(kernel: &Kernel) -> Vec<zx::Koid> {
8585 let shadow_process =
8586 kernel.expando.peek::<MlockShadowProcess>().expect("shadow process should exist");
8587 shadow_process
8588 .0
8589 .vmar()
8590 .maps_vec()
8591 .unwrap()
8592 .iter()
8593 .filter_map(|map| match map.details() {
8594 zx::MapDetails::Mapping(details) => Some(details.vmo_koid),
8595 _ => None,
8596 })
8597 .collect()
8598 }
8599
8600 fn mlock_features(flavor: MlockPinFlavor) -> KernelFeatures {
8601 let mut features = KernelFeatures::default();
8602 features.mlock_pin_flavor = flavor;
8603 features
8604 }
8605
8606 #[::fuchsia::test]
8607 async fn test_force_write_memory_moves_shadow_process_mlock_pin() {
8608 spawn_kernel_with_features_and_run(
8609 async |current_task| {
8610 let page_size = *PAGE_SIZE as usize;
8611 let file = new_memfd(
8612 current_task,
8613 b"test_memfd".into(),
8614 SealFlags::empty(),
8615 OpenFlags::RDWR,
8616 )
8617 .unwrap();
8618 file.node().truncate(current_task, &file.name.mount, *PAGE_SIZE).unwrap();
8619 let fd = current_task.add_file(file, FdFlags::empty()).unwrap();
8620 let addr = do_mmap(
8621 current_task,
8622 UserAddress::default(),
8623 page_size,
8624 PROT_READ,
8625 MAP_PRIVATE,
8626 fd,
8627 0,
8628 )
8629 .expect("mmap failed");
8630 let mm = current_task.mm().unwrap();
8631
8632 mm.mlock(current_task, addr, page_size, false).expect("mlock failed");
8633 let original_koid = mapping_memory_koid(&mm, addr);
8634 assert_eq!(
8635 mlock_shadow_process_pinned_koids(current_task.kernel()),
8636 [original_koid]
8637 );
8638
8639 mm.force_write_memory(current_task.kernel(), addr, b"poke")
8642 .expect("force_write_memory failed");
8643 assert_eq!(¤t_task.read_memory_to_vec(addr, 4).unwrap(), b"poke");
8644
8645 let child_koid = mapping_memory_koid(&mm, addr);
8646 assert_ne!(child_koid, original_koid);
8647 assert_eq!(mlock_shadow_process_pinned_koids(current_task.kernel()), [child_koid]);
8648 },
8649 mlock_features(MlockPinFlavor::ShadowProcess),
8650 )
8651 .await;
8652 }
8653
8654 fn map_private_read_only_memfd(current_task: &CurrentTask) -> (FdNumber, UserAddress) {
8656 let file =
8657 new_memfd(current_task, b"test_memfd".into(), SealFlags::empty(), OpenFlags::RDWR)
8658 .unwrap();
8659 file.node().truncate(current_task, &file.name.mount, *PAGE_SIZE * 3).unwrap();
8660 let fd = current_task.add_file(file, FdFlags::empty()).unwrap();
8661 let addr = do_mmap(
8662 current_task,
8663 UserAddress::default(),
8664 *PAGE_SIZE as usize * 3,
8665 PROT_READ,
8666 MAP_PRIVATE,
8667 fd,
8668 0,
8669 )
8670 .expect("mmap failed");
8671 (fd, addr)
8672 }
8673
8674 fn check_file_unmodified(current_task: &CurrentTask, fd: FdNumber) {
8676 let addr = do_mmap(
8677 current_task,
8678 UserAddress::default(),
8679 *PAGE_SIZE as usize,
8680 PROT_READ,
8681 MAP_SHARED,
8682 fd,
8683 0,
8684 )
8685 .expect("shared mmap failed");
8686 check_page_eq(current_task, addr, '\0');
8687 }
8688
8689 #[::fuchsia::test]
8690 async fn test_private_read_only_file_mapping_mprotect_write_is_private() {
8691 spawn_kernel_and_run(async |current_task| {
8692 let page_size = *PAGE_SIZE as usize;
8693 let (fd, addr) = map_private_read_only_memfd(current_task);
8694 let middle_page = (addr + *PAGE_SIZE).unwrap();
8695 let last_page = (addr + *PAGE_SIZE * 2).unwrap();
8696 let mm = current_task.mm().unwrap();
8697
8698 mm.protect(
8700 current_task,
8701 middle_page,
8702 page_size,
8703 ProtectionFlags::READ | ProtectionFlags::WRITE,
8704 )
8705 .expect("mprotect(PROT_READ | PROT_WRITE) failed");
8706 fill_page(current_task, middle_page, 'b');
8707
8708 let end_addr = (addr + *PAGE_SIZE * 3).unwrap();
8711 mm.protect(current_task, middle_page, page_size, ProtectionFlags::READ).unwrap();
8712 assert_eq!(mm.state.read().mappings.get(addr).unwrap().0, &(addr..end_addr));
8713 mm.protect(
8714 current_task,
8715 middle_page,
8716 page_size,
8717 ProtectionFlags::READ | ProtectionFlags::WRITE,
8718 )
8719 .unwrap();
8720 check_page_eq(current_task, middle_page, 'b');
8721
8722 check_page_eq(current_task, addr, '\0');
8724 check_page_eq(current_task, last_page, '\0');
8725 check_file_unmodified(current_task, fd);
8726 })
8727 .await;
8728 }
8729
8730 #[::fuchsia::test]
8731 async fn test_private_read_only_file_mapping_force_write_is_private() {
8732 spawn_kernel_and_run(async |current_task| {
8733 let page_size = *PAGE_SIZE as usize;
8734 let (fd, addr) = map_private_read_only_memfd(current_task);
8735 let middle_page = (addr + *PAGE_SIZE).unwrap();
8736 let end_addr = (addr + *PAGE_SIZE * 3).unwrap();
8737 let mm = current_task.mm().unwrap();
8738
8739 mm.protect(current_task, middle_page, page_size, ProtectionFlags::empty()).unwrap();
8741 mm.force_write_memory(current_task.kernel(), addr, b"poke")
8742 .expect("force_write_memory failed");
8743 assert_eq!(¤t_task.read_memory_to_vec(addr, 4).unwrap(), b"poke");
8744 check_file_unmodified(current_task, fd);
8745
8746 mm.protect(current_task, middle_page, page_size, ProtectionFlags::READ).unwrap();
8748 let state = mm.state.read();
8749 let (range, _) = state.mappings.get(addr).unwrap();
8750 assert_eq!(range, &(addr..end_addr));
8751 })
8752 .await;
8753 }
8754
8755 #[::fuchsia::test]
8756 async fn test_private_read_only_file_mapping_without_exec_rights_mprotect_write_exec() {
8757 spawn_kernel_and_run_with_pkgfs(async |current_task| {
8758 let file =
8759 current_task.open_file("data/testfile.txt".into(), OpenFlags::RDONLY).unwrap();
8760 let fd = current_task.add_file(file, FdFlags::empty()).unwrap();
8761 let addr = do_mmap(
8762 current_task,
8763 UserAddress::default(),
8764 *PAGE_SIZE as usize,
8765 PROT_READ,
8766 MAP_PRIVATE,
8767 fd,
8768 0,
8769 )
8770 .expect("mmap failed");
8771
8772 current_task
8773 .mm()
8774 .unwrap()
8775 .protect(
8776 current_task,
8777 addr,
8778 *PAGE_SIZE as usize,
8779 ProtectionFlags::READ | ProtectionFlags::WRITE | ProtectionFlags::EXEC,
8780 )
8781 .expect("mprotect(PROT_WRITE | PROT_EXEC) failed");
8782
8783 let mm = current_task.mm().unwrap();
8786 let state = mm.state.read();
8787 let (_, mapping) = state.mappings.get(addr).expect("mapping");
8788 assert!(!mapping.flags().contains(MappingFlags::LAZY_PRIVATE_FILE));
8789 assert!(mapping.can_exec());
8790 let MappingBacking::Memory(backing) = mapping.get_backing_internal() else {
8791 panic!("mapping should be backed by memory");
8792 };
8793 assert!(backing.memory().get_rights().contains(zx::Rights::EXECUTE));
8794 })
8795 .await;
8796 }
8797
8798 #[::fuchsia::test]
8799 async fn test_private_read_only_file_mapping_write_after_fork_is_private() {
8800 spawn_kernel_and_run(async |current_task| {
8801 let page_size = *PAGE_SIZE as usize;
8802 let read_write = ProtectionFlags::READ | ProtectionFlags::WRITE;
8803 let (fd, addr) = map_private_read_only_memfd(current_task);
8804 let writing_child = current_task.clone_task_for_test(0, None);
8805 let idle_child = current_task.clone_task_for_test(0, None);
8806
8807 writing_child
8809 .mm()
8810 .unwrap()
8811 .protect(&writing_child, addr, page_size, read_write)
8812 .expect("child mprotect failed");
8813 Task::write_memory(&writing_child, addr, b"childmod").unwrap();
8814 assert_eq!(&Task::read_memory_to_vec(&writing_child, addr, 8).unwrap(), b"childmod");
8815
8816 check_page_eq(current_task, addr, '\0');
8818 check_file_unmodified(current_task, fd);
8819
8820 current_task
8822 .mm()
8823 .unwrap()
8824 .protect(current_task, addr, page_size, read_write)
8825 .expect("parent mprotect failed");
8826 current_task.write_memory(addr, b"parentmod").unwrap();
8827 assert_eq!(¤t_task.read_memory_to_vec(addr, 9).unwrap(), b"parentmod");
8828
8829 assert_eq!(&Task::read_memory_to_vec(&writing_child, addr, 8).unwrap(), b"childmod");
8831 assert_eq!(Task::read_memory_to_vec(&idle_child, addr, 9).unwrap(), vec![0u8; 9]);
8832 check_file_unmodified(current_task, fd);
8833 })
8834 .await;
8835 }
8836
8837 #[::fuchsia::test]
8838 async fn test_private_read_only_file_mapping_mprotect_partial_failure() {
8839 spawn_kernel_and_run(async |current_task| {
8840 let page_size = *PAGE_SIZE as usize;
8841 let (_fd, addr) = map_private_read_only_memfd(current_task);
8842 let middle_page = (addr + *PAGE_SIZE).unwrap();
8843 let last_page = (addr + *PAGE_SIZE * 2).unwrap();
8844 let mm = current_task.mm().unwrap();
8845
8846 mm.unmap(middle_page, page_size).expect("munmap failed");
8848
8849 assert_eq!(
8851 mm.protect(
8852 current_task,
8853 addr,
8854 page_size * 3,
8855 ProtectionFlags::READ | ProtectionFlags::WRITE,
8856 ),
8857 error!(ENOMEM)
8858 );
8859
8860 let state = mm.state.read();
8861 let (_, first) = state.mappings.get(addr).expect("first page should be mapped");
8862 assert!(first.flags().contains(MappingFlags::WRITE));
8863 assert!(!first.flags().contains(MappingFlags::LAZY_PRIVATE_FILE));
8864
8865 let (_, last) = state.mappings.get(last_page).expect("last page should be mapped");
8867 assert!(!last.flags().contains(MappingFlags::WRITE));
8868 assert!(last.flags().contains(MappingFlags::LAZY_PRIVATE_FILE));
8869 })
8870 .await;
8871 }
8872
8873 #[::fuchsia::test]
8874 async fn test_private_read_only_file_mapping_mprotect_partial_failure_after_fork() {
8875 spawn_kernel_and_run(async |current_task| {
8876 let page_size = *PAGE_SIZE as usize;
8877 let (_fd, addr) = map_private_read_only_memfd(current_task);
8878 let middle_page = (addr + *PAGE_SIZE).unwrap();
8879 let last_page = (addr + *PAGE_SIZE * 2).unwrap();
8880
8881 let child = current_task.clone_task_for_test(0, None);
8883 let mm = child.mm().unwrap();
8884 mm.unmap(middle_page, page_size).expect("munmap failed");
8885
8886 assert_eq!(
8887 mm.protect(
8888 &child,
8889 addr,
8890 page_size * 3,
8891 ProtectionFlags::READ | ProtectionFlags::WRITE,
8892 ),
8893 error!(ENOMEM)
8894 );
8895
8896 let state = mm.state.read();
8897 let (_, first) = state.mappings.get(addr).expect("first page should be mapped");
8898 assert!(first.flags().contains(MappingFlags::WRITE));
8899 assert!(!first.flags().contains(MappingFlags::LAZY_PRIVATE_FILE));
8900 assert_eq!(first.mapping_mode(), MappingMode::Eager);
8901
8902 let (_, last) = state.mappings.get(last_page).expect("last page should be mapped");
8905 assert!(!last.flags().contains(MappingFlags::WRITE));
8906 assert!(last.flags().contains(MappingFlags::LAZY_PRIVATE_FILE));
8907 assert_eq!(last.mapping_mode(), MappingMode::Lazy);
8908 })
8909 .await;
8910 }
8911
8912 #[::fuchsia::test]
8913 async fn test_private_read_only_file_mapping_force_write_after_fork_is_private() {
8914 spawn_kernel_and_run(async |current_task| {
8915 let page_size = *PAGE_SIZE as usize;
8916 let (fd, addr) = map_private_read_only_memfd(current_task);
8917 let middle_page = (addr + *PAGE_SIZE).unwrap();
8918 let end_addr = (addr + *PAGE_SIZE * 3).unwrap();
8919
8920 current_task
8922 .mm()
8923 .unwrap()
8924 .protect(current_task, middle_page, page_size, ProtectionFlags::empty())
8925 .unwrap();
8926
8927 let child = current_task.clone_task_for_test(0, None);
8929 let child_mm = child.mm().unwrap();
8930 child_mm
8931 .force_write_memory(child.kernel(), addr, b"poke")
8932 .expect("force_write_memory failed");
8933 assert_eq!(&Task::read_memory_to_vec(&child, addr, 4).unwrap(), b"poke");
8934
8935 check_page_eq(current_task, addr, '\0');
8937 check_file_unmodified(current_task, fd);
8938
8939 child_mm.protect(&child, middle_page, page_size, ProtectionFlags::READ).unwrap();
8942 let state = child_mm.state.read();
8943 let (range, _) = state.mappings.get(addr).unwrap();
8944 assert_eq!(range, &(addr..end_addr));
8945 })
8946 .await;
8947 }
8948
8949 #[::fuchsia::test]
8950 async fn test_private_read_only_file_mapping_mprotect_write_moves_shadow_process_pin() {
8951 spawn_kernel_with_features_and_run(
8952 async |current_task| {
8953 let page_size = *PAGE_SIZE as usize;
8954 let (_fd, addr) = map_private_read_only_memfd(current_task);
8955 let mm = current_task.mm().unwrap();
8956
8957 mm.mlock(current_task, addr, page_size, false).expect("mlock failed");
8958 let file_koid = mapping_memory_koid(&mm, addr);
8959 assert_eq!(mlock_shadow_process_pinned_koids(current_task.kernel()), [file_koid]);
8960
8961 mm.protect(
8962 current_task,
8963 addr,
8964 page_size,
8965 ProtectionFlags::READ | ProtectionFlags::WRITE,
8966 )
8967 .expect("mprotect failed");
8968
8969 let child_koid = mapping_memory_koid(&mm, addr);
8971 assert_ne!(child_koid, file_koid);
8972 assert!(
8973 mm.state
8974 .read()
8975 .mappings
8976 .get(addr)
8977 .unwrap()
8978 .1
8979 .flags()
8980 .contains(MappingFlags::LOCKED)
8981 );
8982 assert_eq!(mlock_shadow_process_pinned_koids(current_task.kernel()), [child_koid]);
8983 },
8984 mlock_features(MlockPinFlavor::ShadowProcess),
8985 )
8986 .await;
8987 }
8988
8989 #[::fuchsia::test]
8990 async fn test_private_read_only_file_mapping_mprotect_write_vmar_always_need_mlock() {
8991 spawn_kernel_with_features_and_run(
8992 async |current_task| {
8993 let page_size = *PAGE_SIZE as usize;
8994 let (_fd, addr) = map_private_read_only_memfd(current_task);
8995 let mm = current_task.mm().unwrap();
8996
8997 mm.mlock(current_task, addr, page_size, false).expect("mlock failed");
8998 mm.protect(
8999 current_task,
9000 addr,
9001 page_size,
9002 ProtectionFlags::READ | ProtectionFlags::WRITE,
9003 )
9004 .expect("mprotect failed");
9005 fill_page(current_task, addr, 'a');
9006 check_page_eq(current_task, addr, 'a');
9007
9008 let state = mm.state.read();
9009 let (_, mapping) = state.mappings.get(addr).unwrap();
9010 assert!(mapping.flags().contains(MappingFlags::LOCKED));
9011 assert!(!mapping.flags().contains(MappingFlags::LAZY_PRIVATE_FILE));
9012 },
9013 mlock_features(MlockPinFlavor::VmarAlwaysNeed),
9014 )
9015 .await;
9016 }
9017
9018 #[::fuchsia::test]
9019 async fn test_private_read_only_and_exec_file_mappings_fork() {
9020 spawn_kernel_and_run(async |current_task| {
9021 let page_size = *PAGE_SIZE as usize;
9022 let (fd, read_addr) = map_private_read_only_memfd(current_task);
9023
9024 let exec_addr = (read_addr + *PAGE_SIZE).unwrap();
9027 do_mmap(
9028 current_task,
9029 exec_addr,
9030 page_size,
9031 PROT_READ | PROT_EXEC,
9032 MAP_PRIVATE | MAP_FIXED,
9033 fd,
9034 *PAGE_SIZE,
9035 )
9036 .expect("exec mmap failed");
9037
9038 let child_task = current_task.clone_task_for_test(0, None);
9040 let child_mm = child_task.mm().unwrap();
9041 assert!(child_mm.ensure_range_mapped_in_user_vmar(read_addr, Some(page_size)).unwrap());
9042 assert!(child_mm.ensure_range_mapped_in_user_vmar(exec_addr, Some(page_size)).unwrap());
9043 })
9044 .await;
9045 }
9046
9047 struct PagerTestFile(Arc<MemoryObject>);
9048 impl FileOps for PagerTestFile {
9049 fileops_impl_memory!(self, &self.0);
9050 fileops_impl_noop_sync!();
9051 }
9052
9053 #[test_case(MAP_PRIVATE)]
9054 #[test_case(MAP_SHARED)]
9055 #[::fuchsia::test]
9056 async fn test_madvise_background_thread_pool(flags: u32) {
9057 spawn_kernel_and_run(async move |current_task| {
9058 let page_size = *PAGE_SIZE;
9059 let pager = zx::Pager::create(zx::PagerOptions::empty()).unwrap();
9060 let port = zx::Port::create();
9061 let vmo = pager.create_vmo(zx::VmoOptions::empty(), &port, 1, page_size).unwrap();
9062 let child_vmo = vmo.create_child(zx::VmoChildOptions::REFERENCE, 0, 0).unwrap();
9063 let memory = Arc::new(MemoryObject::from(child_vmo));
9064
9065 let file =
9066 anon_test_file(¤t_task, Box::new(PagerTestFile(memory)), OpenFlags::RDWR);
9067 let fd = current_task.add_file(file, FdFlags::empty()).unwrap();
9068 let addr = do_mmap(
9069 ¤t_task,
9070 UserAddress::default(),
9071 page_size as usize,
9072 PROT_READ | PROT_WRITE,
9073 flags,
9074 fd,
9075 0,
9076 )
9077 .unwrap();
9078
9079 assert_eq!(
9082 current_task.mm().unwrap().madvise(
9083 ¤t_task,
9084 addr,
9085 page_size as usize,
9086 MADV_WILLNEED
9087 ),
9088 Ok(())
9089 );
9090
9091 let packet = port.wait(zx::MonotonicInstant::INFINITE).unwrap();
9093 assert_eq!(packet.key(), 1);
9094
9095 let aux_vmo = zx::Vmo::create(page_size).unwrap();
9096 aux_vmo.write(&[0x42; 16], 0).unwrap();
9097 pager.supply_pages(&vmo, 0..page_size, &aux_vmo, 0).unwrap();
9098
9099 let read_buf: [u8; 16] = current_task.read_memory_to_array(addr).unwrap();
9100 assert_eq!(&read_buf, &[0x42; 16]);
9101 })
9102 .await;
9103 }
9104
9105 #[::fuchsia::test]
9106 async fn test_get_stats_linear_scan() {
9107 use crate::task::KernelFeatures;
9108 use crate::testing::spawn_kernel_with_features_and_run;
9109
9110 spawn_kernel_with_features_and_run(
9111 async |current_task| {
9112 let mm = current_task.mm().unwrap();
9113 let page_size = *PAGE_SIZE as usize;
9114 let stats_before = mm.get_stats(¤t_task, SelfStatsCacheMode::BypassCache);
9115
9116 let insert_lazy_mapping = |lazy_addr: UserAddress| {
9117 let lazy_memory = create_anonymous_mapping_memory(page_size as u64).unwrap();
9118 let lazy_flags = MappingFlags::from_access_flags_and_options(
9119 ProtectionFlags::empty(),
9120 MappingOptions::ANONYMOUS,
9121 );
9122 let lazy_mapping = Mapping::with_name(
9123 MappingBacking::Memory(Box::new(MappingBackingMemory::new(
9124 lazy_addr,
9125 lazy_memory,
9126 0,
9127 ))),
9128 lazy_flags,
9129 MappingName::None,
9130 MappingMode::Lazy,
9131 );
9132 let mut state = mm.state.write();
9133 state
9134 .mappings
9135 .insert(lazy_addr..(lazy_addr + page_size).unwrap(), lazy_mapping);
9136 };
9137
9138 insert_lazy_mapping((mm.base_addr + 4 * page_size).unwrap());
9140
9141 let addr_a = (mm.base_addr + 10 * page_size).unwrap();
9144 assert_eq!(map_memory(¤t_task, addr_a, 3 * *PAGE_SIZE), addr_a);
9145 current_task.write_memory(addr_a, &[1u8; 16]).unwrap();
9146 mm.protect(
9147 ¤t_task,
9148 (addr_a + page_size).unwrap(),
9149 page_size,
9150 ProtectionFlags::READ,
9151 )
9152 .unwrap();
9153
9154 insert_lazy_mapping((mm.base_addr + 14 * page_size).unwrap());
9156
9157 let addr_b = (mm.base_addr + 16 * page_size).unwrap();
9160 assert_eq!(map_memory(¤t_task, addr_b, 2 * *PAGE_SIZE), addr_b);
9161 current_task.write_memory((addr_b + page_size).unwrap(), &[2u8; 16]).unwrap();
9162 mm.set_mapping_name(addr_b, page_size, Some("first_half".into())).unwrap();
9163
9164 let addr_c = (mm.base_addr + 20 * page_size).unwrap();
9167 assert_eq!(map_memory(¤t_task, addr_c, 2 * *PAGE_SIZE), addr_c);
9168 current_task.write_memory(addr_c, &[3u8; 16]).unwrap();
9169 unsafe {
9171 mm.mapping_context.user_vmar.protect(
9172 addr_c.ptr(),
9173 page_size,
9174 zx::VmarFlags::PERM_READ,
9175 )
9176 }
9177 .unwrap();
9178
9179 insert_lazy_mapping((mm.base_addr + 24 * page_size).unwrap());
9181
9182 let stats_after = mm.get_stats(¤t_task, SelfStatsCacheMode::BypassCache);
9183 assert_eq!(stats_after.vm_size - stats_before.vm_size, 7 * page_size);
9184 assert_eq!(stats_after.vm_rss - stats_before.vm_rss, 3 * page_size);
9185 assert_eq!(stats_after.rss_anonymous - stats_before.rss_anonymous, 3 * page_size);
9186 },
9187 KernelFeatures { cached_zx_map_info_bytes: 4096, ..Default::default() },
9188 )
9189 .await;
9190 }
9191
9192 #[::fuchsia::test]
9193 async fn test_get_stats_caching() {
9194 use crate::task::KernelFeatures;
9195 use crate::testing::spawn_kernel_with_features_and_run;
9196
9197 spawn_kernel_with_features_and_run(
9198 async |current_task| {
9199 let page_size = *PAGE_SIZE as usize;
9200 let mm = current_task.mm().unwrap();
9201 let reader = current_task.clone_task_for_test(0, None);
9202 assert!(mm.cached_stats.lock().is_none());
9203
9204 let addr1 = map_memory(¤t_task, UserAddress::default(), 2 * *PAGE_SIZE);
9206 current_task.write_memory(addr1, &[42u8; 8]).unwrap();
9207
9208 let initial_stats = mm.get_stats(&reader, SelfStatsCacheMode::AllowCached);
9209 assert!(mm.cached_stats.lock().is_some());
9210 assert!(initial_stats.vm_size >= 2 * page_size);
9211 assert!(initial_stats.vm_rss >= page_size);
9212
9213 current_task.write_memory((addr1 + page_size).unwrap(), &[1u8; 8]).unwrap();
9216
9217 let cached_hit = mm.get_stats(&reader, SelfStatsCacheMode::AllowCached);
9218 assert_eq!(
9219 (cached_hit.vm_size, cached_hit.vm_rss),
9220 (initial_stats.vm_size, initial_stats.vm_rss)
9221 );
9222
9223 let gen1 = mm.state.read().mappings.generation;
9226 *mm.cached_stats.lock() = Some((
9227 zx::MonotonicInstant::get() - zx::MonotonicDuration::from_millis(2001),
9228 gen1,
9229 initial_stats,
9230 ));
9231 let expired_stats = mm.get_stats(&reader, SelfStatsCacheMode::AllowCached);
9232 assert_eq!(expired_stats.vm_size, initial_stats.vm_size);
9233 assert_eq!(expired_stats.vm_rss - initial_stats.vm_rss, page_size);
9234
9235 let addr2 = map_memory(¤t_task, UserAddress::default(), 2 * *PAGE_SIZE);
9236 current_task.write_memory(addr2, &[1u8; 8]).unwrap();
9237 current_task.write_memory((addr2 + page_size).unwrap(), &[2u8; 8]).unwrap();
9238
9239 let refreshed_stats = mm.get_stats(&reader, SelfStatsCacheMode::AllowCached);
9240 assert_eq!(refreshed_stats.vm_size - initial_stats.vm_size, 2 * page_size);
9241 assert_eq!(refreshed_stats.vm_rss - initial_stats.vm_rss, 3 * page_size);
9242
9243 let gen2 = mm.state.read().mappings.generation;
9247 *mm.cached_stats.lock() = Some((
9248 zx::MonotonicInstant::get(),
9249 gen2,
9250 MemoryStats { vm_size: 123_456, vm_rss: 654_321, ..Default::default() },
9251 ));
9252
9253 let (kthread_result_fn, req) =
9254 crate::task::dynamic_thread_spawner::SpawnRequestBuilder::new()
9255 .with_sync_closure({
9256 let mm = Arc::clone(&mm);
9257 move |kthread| {
9258 assert!(kthread.mm().is_err());
9259 mm.get_stats(kthread, SelfStatsCacheMode::BypassCache)
9260 }
9261 })
9262 .build_with_sync_result();
9263 current_task.kernel().kthreads.spawner().spawn_from_request(req);
9264 let kthread_stats = kthread_result_fn().expect("kthread get_stats");
9265 assert_eq!((kthread_stats.vm_size, kthread_stats.vm_rss), (123_456, 654_321));
9266
9267 let sibling = current_task.clone_task_for_test(
9268 (starnix_uapi::CLONE_THREAD
9269 | starnix_uapi::CLONE_VM
9270 | starnix_uapi::CLONE_SIGHAND) as u64,
9271 None,
9272 );
9273 assert!(Arc::ptr_eq(&sibling.mm().unwrap(), &mm));
9274 let sibling_cached = mm.get_stats(&sibling, SelfStatsCacheMode::AllowCached);
9275 assert_eq!((sibling_cached.vm_size, sibling_cached.vm_rss), (123_456, 654_321));
9276 let sibling_stats = mm.get_stats(&sibling, SelfStatsCacheMode::BypassCache);
9277 assert_eq!(
9278 (sibling_stats.vm_size, sibling_stats.vm_rss),
9279 (refreshed_stats.vm_size, refreshed_stats.vm_rss)
9280 );
9281
9282 mm.mrelease().unwrap();
9285 assert!(mm.cached_stats.lock().is_none());
9286 let post_release_stats = mm.get_stats(&reader, SelfStatsCacheMode::AllowCached);
9287 assert_eq!(post_release_stats.vm_size, refreshed_stats.vm_size);
9288 assert!(post_release_stats.vm_rss + 4 * page_size <= refreshed_stats.vm_rss);
9289 },
9290 KernelFeatures { cached_zx_map_info_bytes: 4096, ..Default::default() },
9291 )
9292 .await;
9293 }
9294}