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, FutexTable, InflightVmsplicedPayloads, MapInfoCache, Mapping,
11 MappingBacking, MappingFlags, MappingMode, MappingName, MappingNameRef, MlockPinFlavor,
12 PrivateFutexKey, ProtectionFlags, UserFault, VMEX_RESOURCE, VmsplicePayload,
13 VmsplicePayloadSegment,
14};
15use crate::security;
16use crate::signals::{SignalDetail, SignalInfo};
17use crate::task::{CurrentTask, ExceptionResult, PageFaultExceptionReport, Pid, Task};
18use crate::vfs::aio::AioContext;
19use crate::vfs::buffers::{InputBuffer, OutputBuffer};
20use crate::vfs::pseudo::dynamic_file::{
21 DynamicFile, DynamicFileBuf, DynamicFileSource, SequenceFileSource,
22};
23use crate::vfs::{
24 FileObject, FileOps, FsContext, FsString, NamespaceNode, fileops_impl_noop_sync,
25 fileops_impl_seekable,
26};
27use anyhow::{Error, anyhow};
28use bitflags::bitflags;
29use flyweights::FlyByteStr;
30use linux_uapi::BUS_ADRERR;
31use memory_pinning::PinnedMapping;
32use range_map::RangeMap;
33use smallvec::SmallVec;
34use starnix_ext::map_ext::EntryExt;
35use starnix_lifecycle::DropNotifier;
36use starnix_logging::{CATEGORY_STARNIX_MM, impossible_error, log_error, log_warn, track_stub};
37use starnix_sync::{LockDepMutex, MmDumpable, Mutex, RwLock, RwLockWriteGuard, ordered_write_lock};
38use starnix_types::arch::ArchWidth;
39use starnix_types::futex_address::FutexAddress;
40use starnix_types::math::{round_down_to_system_page_size, round_up_to_system_page_size};
41use starnix_types::user_buffer::{UserBuffer, UserBuffers};
42use starnix_uapi::auth::CAP_IPC_LOCK;
43use starnix_uapi::errors::Errno;
44use starnix_uapi::range_ext::RangeExt;
45use starnix_uapi::resource_limits::Resource;
46use starnix_uapi::restricted_aspace::{
47 RESTRICTED_ASPACE_BASE, RESTRICTED_ASPACE_HIGHEST_ADDRESS, RESTRICTED_ASPACE_RANGE,
48 RESTRICTED_ASPACE_SIZE,
49};
50use starnix_uapi::signals::{SIGBUS, SIGSEGV};
51use starnix_uapi::user_address::{ArchSpecific, UserAddress};
52use starnix_uapi::{
53 MADV_COLD, MADV_COLLAPSE, MADV_DODUMP, MADV_DOFORK, MADV_DONTDUMP, MADV_DONTFORK,
54 MADV_DONTNEED, MADV_DONTNEED_LOCKED, MADV_FREE, MADV_HUGEPAGE, MADV_HWPOISON, MADV_KEEPONFORK,
55 MADV_MERGEABLE, MADV_NOHUGEPAGE, MADV_NORMAL, MADV_PAGEOUT, MADV_POPULATE_READ, MADV_RANDOM,
56 MADV_REMOVE, MADV_SEQUENTIAL, MADV_SOFT_OFFLINE, MADV_UNMERGEABLE, MADV_WILLNEED,
57 MADV_WIPEONFORK, MREMAP_DONTUNMAP, MREMAP_FIXED, MREMAP_MAYMOVE, errno, error,
58 from_status_like_fdio,
59};
60use std::collections::HashMap;
61use std::hash::Hasher;
62use std::mem::MaybeUninit;
63use std::ops::{ControlFlow, Deref, DerefMut, Range, RangeBounds};
64use std::sync::{Arc, LazyLock, Weak};
65use zerocopy::IntoBytes;
66use zx::{Rights, VmoChildOptions};
67
68pub const ZX_VM_SPECIFIC_OVERWRITE: zx::VmarFlags =
69 zx::VmarFlags::from_bits_retain(zx::VmarFlagsExtended::SPECIFIC_OVERWRITE.bits());
70
71pub fn init_usercopy() {
78 let _ = usercopy();
80}
81
82thread_local! {
83 static LAST_SEEN_MAPPING_GENERATION: std::cell::Cell<u64> = const { std::cell::Cell::new(0) };
86}
87
88pub const GUARD_PAGE_COUNT_FOR_GROWSDOWN_MAPPINGS: usize = 256;
89
90#[cfg(target_arch = "x86_64")]
91const ASLR_RANDOM_BITS: usize = 27;
92
93#[cfg(target_arch = "aarch64")]
94const ASLR_RANDOM_BITS: usize = 28;
95
96#[cfg(target_arch = "riscv64")]
97const ASLR_RANDOM_BITS: usize = 18;
98
99const ASLR_32_RANDOM_BITS: usize = 8;
101
102const MAX_STACK_SIZE: usize = 512 * 1024 * 1024;
105
106const STUB_VM_RSS_HWM: usize = 2 * 1024 * 1024;
110
111fn usercopy() -> &'static usercopy::Usercopy {
112 static USERCOPY: LazyLock<usercopy::Usercopy> = LazyLock::new(|| {
113 usercopy::Usercopy::new(RESTRICTED_ASPACE_RANGE).unwrap()
116 });
117
118 LazyLock::force(&USERCOPY)
119}
120
121#[unsafe(no_mangle)]
133pub unsafe fn zxio_maybe_faultable_copy_impl(
134 dest: *mut u8,
135 src: *const u8,
136 count: usize,
137 ret_dest: bool,
138) -> bool {
139 let ret = unsafe { usercopy().raw_hermetic_copy(dest, src, count, ret_dest) };
142 ret == count
143}
144
145pub static PAGE_SIZE: LazyLock<u64> = LazyLock::new(|| zx::system_get_page_size() as u64);
146
147bitflags! {
148 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
149 pub struct MappingOptions: u16 {
150 const SHARED = 1 << 0;
151 const ANONYMOUS = 1 << 1;
152 const LOWER_32BIT = 1 << 2;
153 const GROWSDOWN = 1 << 3;
154 const ELF_BINARY = 1 << 4;
155 const DONTFORK = 1 << 5;
156 const WIPEONFORK = 1 << 6;
157 const DONT_SPLIT = 1 << 7;
158 const DONT_EXPAND = 1 << 8;
159 const POPULATE = 1 << 9;
160 }
161}
162
163bitflags! {
164 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
165 pub struct MremapFlags: u32 {
166 const MAYMOVE = MREMAP_MAYMOVE;
167 const FIXED = MREMAP_FIXED;
168 const DONTUNMAP = MREMAP_DONTUNMAP;
169 }
170}
171
172bitflags! {
173 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
174 pub struct MsyncFlags: u32 {
175 const ASYNC = starnix_uapi::MS_ASYNC;
176 const INVALIDATE = starnix_uapi::MS_INVALIDATE;
177 const SYNC = starnix_uapi::MS_SYNC;
178 }
179}
180
181const PROGRAM_BREAK_LIMIT: u64 = 64 * 1024 * 1024;
182
183#[derive(Debug, Clone, Eq, PartialEq)]
184struct ProgramBreak {
185 base: UserAddress,
187
188 current: UserAddress,
193}
194
195#[derive(Debug, Clone, Copy, Eq, PartialEq)]
197pub enum DumpPolicy {
198 Disable,
202
203 User,
207}
208
209pub enum MembarrierType {
211 Memory, SyncCore, }
214
215#[derive(Default, Clone)]
217struct MembarrierRegistrations {
218 memory: bool,
219 sync_core: bool,
220}
221
222#[derive(Default)]
223struct Mappings {
224 map: RangeMap<UserAddress, Mapping>,
226
227 generation: u64,
231
232 total_usage: usize,
234}
235
236impl Deref for Mappings {
237 type Target = RangeMap<UserAddress, Mapping>;
238
239 fn deref(&self) -> &Self::Target {
240 &self.map
241 }
242}
243
244impl Mappings {
245 pub fn insert(&mut self, range: std::ops::Range<UserAddress>, value: Mapping) -> Vec<Mapping> {
246 self.generation = self.generation.wrapping_add(1);
247 let range_len = range.end - range.start;
248 let removed_len: usize = self
249 .map
250 .range(range.clone())
251 .map(|(r, _)| {
252 let intersection = r.intersect(&range);
253 intersection.end - intersection.start
254 })
255 .sum();
256 let removed = self.map.insert(range, value);
257 self.total_usage = self.total_usage.saturating_add(range_len).saturating_sub(removed_len);
258 removed
259 }
260
261 pub fn remove(&mut self, range: std::ops::Range<UserAddress>) -> Vec<Mapping> {
262 self.generation = self.generation.wrapping_add(1);
263 let removed_len: usize = self
264 .map
265 .range(range.clone())
266 .map(|(r, _)| {
267 let intersection = r.intersect(&range);
268 intersection.end - intersection.start
269 })
270 .sum();
271 let removed = self.map.remove(range);
272 self.total_usage = self.total_usage.saturating_sub(removed_len);
273 removed
274 }
275
276 pub fn append_non_overlapping(
277 &mut self,
278 range: std::ops::Range<UserAddress>,
279 value: Mapping,
280 ) -> bool {
281 self.generation = self.generation.wrapping_add(1);
282 let range_len = range.end - range.start;
283 if self.map.append_non_overlapping(range, value) {
284 self.total_usage = self.total_usage.saturating_add(range_len);
285 true
286 } else {
287 false
288 }
289 }
290
291 pub fn update_exact<F, E>(
292 &mut self,
293 range: &std::ops::Range<UserAddress>,
294 f: F,
295 ) -> Result<bool, E>
296 where
297 F: FnOnce(&mut Mapping) -> Result<(), E>,
298 {
299 self.generation = self.generation.wrapping_add(1);
300 self.map.update_exact(range, f)
301 }
302}
303
304pub struct MemoryManagerState {
305 mappings: Mappings,
307
308 userfaultfds: Vec<Weak<UserFault>>,
310
311 shadow_mappings_for_mlock: RangeMap<UserAddress, Arc<PinnedMapping>>,
316
317 forkable_state: MemoryManagerForkableState,
318}
319
320const LOWER_4GB_LIMIT: UserAddress = UserAddress::const_from(0xffff_0000);
322
323#[derive(Default, Clone)]
324pub struct MemoryManagerForkableState {
325 brk: Option<ProgramBreak>,
327
328 executable_node: Option<NamespaceNode>,
330
331 pub stack_size: usize,
332 pub stack_start: UserAddress,
333 pub auxv_start: UserAddress,
334 pub auxv_end: UserAddress,
335 pub argv_start: UserAddress,
336 pub argv_end: UserAddress,
337 pub environ_start: UserAddress,
338 pub environ_end: UserAddress,
339
340 pub vdso_base: UserAddress,
342
343 pub mmap_top: UserAddress,
345 pub stack_origin: UserAddress,
346 pub brk_origin: UserAddress,
347
348 membarrier_registrations: MembarrierRegistrations,
350}
351
352impl Deref for MemoryManagerState {
353 type Target = MemoryManagerForkableState;
354 fn deref(&self) -> &Self::Target {
355 &self.forkable_state
356 }
357}
358
359impl DerefMut for MemoryManagerState {
360 fn deref_mut(&mut self) -> &mut Self::Target {
361 &mut self.forkable_state
362 }
363}
364
365#[derive(Debug, Default)]
366struct ReleasedMappings {
367 doomed: Vec<Mapping>,
368 doomed_pins: Vec<Arc<PinnedMapping>>,
369}
370
371impl ReleasedMappings {
372 fn extend(&mut self, mappings: impl IntoIterator<Item = Mapping>) {
373 self.doomed.extend(mappings);
374 }
375
376 fn extend_pins(&mut self, mappings: impl IntoIterator<Item = Arc<PinnedMapping>>) {
377 self.doomed_pins.extend(mappings);
378 }
379
380 fn is_empty(&self) -> bool {
381 self.doomed.is_empty() && self.doomed_pins.is_empty()
382 }
383
384 #[cfg(test)]
385 fn len(&self) -> usize {
386 self.doomed.len() + self.doomed_pins.len()
387 }
388
389 fn finalize(&mut self, mm_state: RwLockWriteGuard<'_, MemoryManagerState>) {
390 std::mem::drop(mm_state);
393 std::mem::take(&mut self.doomed);
394 std::mem::take(&mut self.doomed_pins);
395 }
396}
397
398impl Drop for ReleasedMappings {
399 fn drop(&mut self) {
400 assert!(self.is_empty(), "ReleasedMappings::finalize() must be called before drop");
401 }
402}
403
404fn map_in_vmar(
405 vmar: &zx::Vmar,
406 vmar_info: &zx::VmarInfo,
407 addr: SelectedAddress,
408 memory: &MemoryObject,
409 memory_offset: u64,
410 length: usize,
411 flags: MappingFlags,
412 populate: bool,
413) -> Result<(), Errno> {
414 let vmar_offset = addr.addr().checked_sub(vmar_info.base).ok_or_else(|| errno!(ENOMEM))?;
415 let vmar_extra_flags = match addr {
416 SelectedAddress::Fixed(_) => zx::VmarFlags::SPECIFIC,
417 SelectedAddress::FixedOverwrite(_) => ZX_VM_SPECIFIC_OVERWRITE,
418 };
419
420 if populate {
421 let op = if flags.contains(MappingFlags::WRITE) {
422 zx::VmoOp::COMMIT
424 } else {
425 zx::VmoOp::PREFETCH
428 };
429 fuchsia_trace::duration!(CATEGORY_STARNIX_MM, "MmapCommitPages");
430 let _ = memory.op_range(op, memory_offset, length as u64);
431 }
433
434 let vmar_maybe_map_range = if populate && !vmar_extra_flags.contains(ZX_VM_SPECIFIC_OVERWRITE) {
435 zx::VmarFlags::MAP_RANGE
436 } else {
437 zx::VmarFlags::empty()
438 };
439 let vmar_flags = flags.access_flags().to_vmar_flags()
440 | zx::VmarFlags::ALLOW_FAULTS
441 | vmar_extra_flags
442 | vmar_maybe_map_range;
443
444 let map_result = memory.map_in_vmar(vmar, vmar_offset.ptr(), memory_offset, length, vmar_flags);
445 let mapped_addr = map_result.map_err(MemoryManager::get_errno_for_map_err)?;
446
447 let expected_addr = addr.addr().ptr();
448 debug_assert_eq!(
449 mapped_addr, expected_addr,
450 "Zircon mapped to a different address than requested!"
451 );
452
453 Ok(())
454}
455
456impl MemoryManagerState {
457 fn get_occupied_address_ranges<'a>(
464 &'a self,
465 subrange: &'a Range<UserAddress>,
466 ) -> impl Iterator<Item = Range<UserAddress>> + 'a {
467 let query_range = subrange.start
468 ..(subrange
469 .end
470 .saturating_add(*PAGE_SIZE as usize * GUARD_PAGE_COUNT_FOR_GROWSDOWN_MAPPINGS));
471 self.mappings.range(query_range).filter_map(|(range, mapping)| {
472 let occupied_range = mapping.inflate_to_include_guard_pages(range);
473 if occupied_range.start < subrange.end && subrange.start < occupied_range.end {
474 Some(occupied_range)
475 } else {
476 None
477 }
478 })
479 }
480
481 fn count_possible_placements(
482 &self,
483 length: usize,
484 subrange: &Range<UserAddress>,
485 ) -> Option<usize> {
486 let mut occupied_ranges = self.get_occupied_address_ranges(subrange);
487 let mut possible_placements = 0;
488 let mut first_fill_end = subrange.start.checked_add(length)?;
491 while first_fill_end <= subrange.end {
492 let Some(mapping) = occupied_ranges.next() else {
493 possible_placements += (subrange.end - first_fill_end) / (*PAGE_SIZE as usize) + 1;
494 break;
495 };
496 if mapping.start >= first_fill_end {
497 possible_placements += (mapping.start - first_fill_end) / (*PAGE_SIZE as usize) + 1;
498 }
499 first_fill_end = mapping.end.checked_add(length)?;
500 }
501 Some(possible_placements)
502 }
503
504 fn pick_placement(
505 &self,
506 length: usize,
507 mut chosen_placement_idx: usize,
508 subrange: &Range<UserAddress>,
509 ) -> Option<UserAddress> {
510 let mut candidate =
511 Range { start: subrange.start, end: subrange.start.checked_add(length)? };
512 let mut occupied_ranges = self.get_occupied_address_ranges(subrange);
513 loop {
514 let Some(mapping) = occupied_ranges.next() else {
515 let res =
517 candidate.start.checked_add(chosen_placement_idx * *PAGE_SIZE as usize)?;
518 debug_assert!(res.checked_add(length)? <= subrange.end);
519 return Some(res);
520 };
521 if mapping.start < candidate.end {
522 candidate = Range { start: mapping.end, end: mapping.end.checked_add(length)? };
524 continue;
525 }
526 let unused_space =
527 (mapping.start.ptr() - candidate.end.ptr()) / (*PAGE_SIZE as usize) + 1;
528 if unused_space > chosen_placement_idx {
529 let res =
531 candidate.start.checked_add(chosen_placement_idx * *PAGE_SIZE as usize)?;
532 return Some(res);
533 }
534
535 chosen_placement_idx -= unused_space;
537 candidate = Range { start: mapping.end, end: mapping.end.checked_add(length)? };
538 }
539 }
540
541 fn find_random_unused_range(
542 &self,
543 length: usize,
544 subrange: &Range<UserAddress>,
545 ) -> Option<UserAddress> {
546 let possible_placements = self.count_possible_placements(length, subrange)?;
547 if possible_placements == 0 {
548 return None;
549 }
550 let chosen_placement_idx = rand::random_range(0..possible_placements);
551 self.pick_placement(length, chosen_placement_idx, subrange)
552 }
553
554 pub fn find_next_unused_range(&self, length: usize) -> Option<UserAddress> {
557 let gap_size = length as u64;
558 let mut upper_bound = self.mmap_top;
559
560 loop {
561 let gap_end = self.mappings.find_gap_end(gap_size, &upper_bound);
562 let candidate = gap_end.checked_sub(length)?;
563
564 let Some((occupied_range, mapping)) = self.mappings.get(gap_end) else {
566 return Some(candidate);
567 };
568 let occupied_range = mapping.inflate_to_include_guard_pages(occupied_range);
569 if occupied_range.start >= gap_end {
571 return Some(candidate);
572 }
573 upper_bound = occupied_range.start;
575 }
576 }
577
578 fn is_hint_acceptable(&self, hint_addr: UserAddress, length: usize) -> bool {
580 let Some(hint_end) = hint_addr.checked_add(length) else {
581 return false;
582 };
583 if !RESTRICTED_ASPACE_RANGE.contains(&hint_addr.ptr())
584 || !RESTRICTED_ASPACE_RANGE.contains(&hint_end.ptr())
585 {
586 return false;
587 };
588 self.get_occupied_address_ranges(&(hint_addr..hint_end)).next().is_none()
589 }
590
591 fn select_address(
592 &self,
593 addr: DesiredAddress,
594 length: usize,
595 flags: MappingFlags,
596 ) -> Result<SelectedAddress, Errno> {
597 let adjusted_length = round_up_to_system_page_size(length).or_else(|_| error!(ENOMEM))?;
598
599 let find_address = || -> Result<SelectedAddress, Errno> {
600 let new_addr = if flags.contains(MappingFlags::LOWER_32BIT) {
601 self.find_random_unused_range(
604 adjusted_length,
605 &(UserAddress::from_ptr(RESTRICTED_ASPACE_BASE)
606 ..UserAddress::from_ptr(0x80000000)),
607 )
608 .ok_or_else(|| errno!(ENOMEM))?
609 } else {
610 self.find_next_unused_range(adjusted_length).ok_or_else(|| errno!(ENOMEM))?
611 };
612
613 Ok(SelectedAddress::Fixed(new_addr))
614 };
615
616 Ok(match addr {
617 DesiredAddress::Any => find_address()?,
618 DesiredAddress::Hint(hint_addr) => {
619 let hint_addr =
621 UserAddress::from_ptr(hint_addr.ptr() - hint_addr.ptr() % *PAGE_SIZE as usize);
622 if self.is_hint_acceptable(hint_addr, adjusted_length) {
623 SelectedAddress::Fixed(hint_addr)
624 } else {
625 find_address()?
626 }
627 }
628 DesiredAddress::Fixed(addr) => SelectedAddress::Fixed(addr),
629 DesiredAddress::FixedOverwrite(addr) => SelectedAddress::FixedOverwrite(addr),
630 })
631 }
632
633 fn validate_addr(&self, addr: DesiredAddress, length: usize) -> Result<(), Errno> {
634 if length > RESTRICTED_ASPACE_SIZE {
635 return error!(ENOMEM);
636 }
637 match addr {
638 DesiredAddress::Fixed(a) | DesiredAddress::FixedOverwrite(a) => {
639 let end = a.checked_add(length).ok_or_else(|| errno!(ENOMEM))?;
640 if end > UserAddress::from_ptr(RESTRICTED_ASPACE_HIGHEST_ADDRESS as usize) {
641 return error!(ENOMEM);
642 }
643 if self.check_has_unauthorized_splits(a, length) {
644 return error!(ENOMEM);
645 }
646 }
647 _ => {}
648 }
649 Ok(())
650 }
651
652 fn add_memory_mapping(
653 &mut self,
654 mm: &Arc<MemoryManager>,
655 addr: DesiredAddress,
656 memory: Arc<MemoryObject>,
657 memory_offset: u64,
658 length: usize,
659 flags: MappingFlags,
660 populate: bool,
661 name: MappingName,
662 mapping_mode: MappingMode,
663 released_mappings: &mut ReleasedMappings,
664 ) -> Result<UserAddress, Errno> {
665 self.validate_addr(addr, length)?;
666
667 let selected_address = self.select_address(addr, length, flags)?;
668 let mapped_addr = selected_address.addr();
669 if mapping_mode == MappingMode::Eager {
670 mm.mapping_context.map_in_user_vmar(
671 selected_address,
672 &memory,
673 memory_offset,
674 length,
675 flags,
676 populate,
677 )?;
678 }
679
680 let end = (mapped_addr + length)?.round_up(*PAGE_SIZE)?;
681
682 if let DesiredAddress::FixedOverwrite(addr) = addr {
683 assert_eq!(addr, mapped_addr);
684 self.update_after_unmap(mm, addr, end - addr, released_mappings);
685 }
686
687 let mapping = Mapping::with_name(
688 self.create_memory_backing(mapped_addr, memory, memory_offset),
689 flags,
690 name,
691 mapping_mode,
692 );
693 released_mappings.extend(self.mappings.insert(mapped_addr..end, mapping));
694
695 Ok(mapped_addr)
696 }
697
698 fn map_private_anonymous(
699 &mut self,
700 mm: &Arc<MemoryManager>,
701 addr: DesiredAddress,
702 length: usize,
703 prot_flags: ProtectionFlags,
704 options: MappingOptions,
705 populate: bool,
706 name: MappingName,
707 released_mappings: &mut ReleasedMappings,
708 ) -> Result<UserAddress, Errno> {
709 self.validate_addr(addr, length)?;
710
711 let flags = MappingFlags::from_access_flags_and_options(prot_flags, options);
712 let selected_addr = self.select_address(addr, length, flags)?;
713 let mapped_addr = selected_addr.addr();
714 let backing_memory_offset = selected_addr.addr().ptr();
715
716 mm.mapping_context.map_in_user_vmar(
717 selected_addr,
718 &mm.mapping_context.private_anonymous.backing,
719 backing_memory_offset as u64,
720 length,
721 flags,
722 populate,
723 )?;
724
725 let end = (mapped_addr + length)?.round_up(*PAGE_SIZE)?;
726 if let DesiredAddress::FixedOverwrite(addr) = addr {
727 assert_eq!(addr, mapped_addr);
728 self.update_after_unmap(mm, addr, end - addr, released_mappings);
729 }
730
731 let mapping = Mapping::new_private_anonymous(flags, name, MappingMode::Eager);
732 released_mappings.extend(self.mappings.insert(mapped_addr..end, mapping));
733
734 Ok(mapped_addr)
735 }
736
737 fn map_anonymous(
738 &mut self,
739 mm: &Arc<MemoryManager>,
740 addr: DesiredAddress,
741 length: usize,
742 prot_flags: ProtectionFlags,
743 options: MappingOptions,
744 name: MappingName,
745 released_mappings: &mut ReleasedMappings,
746 ) -> Result<UserAddress, Errno> {
747 if !options.contains(MappingOptions::SHARED) {
748 return self.map_private_anonymous(
749 mm,
750 addr,
751 length,
752 prot_flags,
753 options,
754 options.contains(MappingOptions::POPULATE),
755 name,
756 released_mappings,
757 );
758 }
759 let memory = create_anonymous_mapping_memory(length as u64)?;
760 let flags = MappingFlags::from_access_flags_and_options(prot_flags, options);
761 self.add_memory_mapping(
762 mm,
763 addr,
764 memory,
765 0,
766 length,
767 flags,
768 options.contains(MappingOptions::POPULATE),
769 name,
770 MappingMode::Eager,
771 released_mappings,
772 )
773 }
774
775 fn any_ranges_lazy<I>(&self, ranges: I) -> bool
776 where
777 I: IntoIterator<Item = (UserAddress, Option<usize>)>,
778 {
779 for (addr, length) in ranges {
780 match length {
781 None => {
782 if let Some((_, mapping)) = self.mappings.get(addr) {
783 if mapping.mapping_mode() == MappingMode::Lazy {
784 return true;
785 }
786 }
787 }
788 Some(len) => {
789 assert!(len > 0);
790 let end = addr.checked_add(len).expect("address overflowed after validation");
791 if self
792 .mappings
793 .range(addr..end)
794 .any(|(_, mapping)| mapping.mapping_mode() == MappingMode::Lazy)
795 {
796 return true;
797 }
798 }
799 }
800 }
801 false
802 }
803
804 fn ensure_range_mapped_in_user_vmar(
805 &mut self,
806 addr: UserAddress,
807 length: Option<usize>,
808 context: &MappingContext,
809 ) -> Result<bool, Errno> {
810 self.ensure_ranges_mapped_in_user_vmar(std::iter::once((addr, length)), context)
811 }
812
813 fn ensure_ranges_mapped_in_user_vmar<I>(
814 &mut self,
815 ranges: I,
816 context: &MappingContext,
817 ) -> Result<bool, Errno>
818 where
819 I: IntoIterator<Item = (UserAddress, Option<usize>)>,
820 {
821 let mut ranges_to_update = SmallVec::<[std::ops::Range<UserAddress>; 1]>::new();
824 for (addr, length) in ranges {
825 match length {
826 None => {
827 if let Some((range, mapping)) = self.mappings.get(addr) {
828 if mapping.mapping_mode() == MappingMode::Lazy {
829 ranges_to_update.push(range.clone());
830 }
831 }
832 }
833 Some(len) => {
834 assert!(len > 0);
835 let end = addr.checked_add(len).expect("address overflowed after validation");
836 for (range, mapping) in self.mappings.range(addr..end) {
837 if mapping.mapping_mode() == MappingMode::Lazy {
838 ranges_to_update.push(range.clone());
839 }
840 }
841 }
842 }
843 }
844
845 if ranges_to_update.is_empty() {
846 return Ok(false);
847 }
848
849 for range in ranges_to_update {
850 let updated = self.mappings.update_exact(&range, |mapping| {
851 let addr = SelectedAddress::FixedOverwrite(range.start);
852 let flags = mapping.flags();
853 let (backing, backing_memory_offset) = match mapping.get_backing_internal() {
854 MappingBacking::Memory(backing) => {
855 (backing.memory(), backing.address_to_offset(addr.addr()))
856 }
857 MappingBacking::PrivateAnonymous => {
858 (&context.private_anonymous.backing, addr.addr().ptr() as u64)
859 }
860 };
861
862 let mapping_length = range.end - range.start;
863 context.map_in_user_vmar(
864 addr,
865 backing,
866 backing_memory_offset,
867 mapping_length,
868 flags,
869 false,
870 )?;
871
872 mapping.set_mapping_mode(MappingMode::Eager);
873 Ok(())
874 })?;
875 assert!(updated, "Expected to update exactly one mapping");
876 }
877
878 Ok(true)
879 }
880
881 fn remap(
882 &mut self,
883 _current_task: &CurrentTask,
884 mm: &Arc<MemoryManager>,
885 old_addr: UserAddress,
886 old_length: usize,
887 new_length: usize,
888 flags: MremapFlags,
889 new_addr: UserAddress,
890 released_mappings: &mut ReleasedMappings,
891 ) -> Result<UserAddress, Errno> {
892 if flags.contains(MremapFlags::FIXED) && !flags.contains(MremapFlags::MAYMOVE) {
894 return error!(EINVAL);
895 }
896
897 if flags.contains(MremapFlags::DONTUNMAP)
900 && (!flags.contains(MremapFlags::MAYMOVE) || old_length != new_length)
901 {
902 return error!(EINVAL);
903 }
904
905 if new_length == 0 {
906 return error!(EINVAL);
907 }
908
909 if !old_addr.is_aligned(*PAGE_SIZE) {
911 return error!(EINVAL);
912 }
913
914 let old_length = round_up_to_system_page_size(old_length)?;
915 let new_length = round_up_to_system_page_size(new_length)?;
916
917 if self.mappings.get(old_addr).is_none() {
919 return error!(EFAULT);
920 }
921
922 if !flags.contains(MremapFlags::MAYMOVE) && old_length == 0 {
924 return error!(ENOMEM);
925 }
926
927 if self.check_has_unauthorized_splits(old_addr, old_length) {
928 return error!(EINVAL);
929 }
930
931 if self.check_has_unauthorized_splits(new_addr, new_length) {
932 return error!(EINVAL);
933 }
934
935 if !flags.contains(MremapFlags::DONTUNMAP)
936 && !flags.contains(MremapFlags::FIXED)
937 && old_length != 0
938 {
939 if let Some(new_addr) =
942 self.try_remap_in_place(mm, old_addr, old_length, new_length, released_mappings)?
943 {
944 return Ok(new_addr);
945 }
946 }
947
948 if flags.contains(MremapFlags::MAYMOVE) {
950 let dst_address =
951 if flags.contains(MremapFlags::FIXED) { Some(new_addr) } else { None };
952 self.remap_move(
953 mm,
954 old_addr,
955 old_length,
956 dst_address,
957 new_length,
958 flags.contains(MremapFlags::DONTUNMAP),
959 released_mappings,
960 )
961 } else {
962 error!(ENOMEM)
963 }
964 }
965
966 fn try_remap_in_place(
969 &mut self,
970 mm: &Arc<MemoryManager>,
971 old_addr: UserAddress,
972 old_length: usize,
973 new_length: usize,
974 released_mappings: &mut ReleasedMappings,
975 ) -> Result<Option<UserAddress>, Errno> {
976 let old_range = old_addr..old_addr.checked_add(old_length).ok_or_else(|| errno!(EINVAL))?;
977 let new_range_in_place =
978 old_addr..old_addr.checked_add(new_length).ok_or_else(|| errno!(EINVAL))?;
979
980 if new_length <= old_length {
981 if new_length != old_length {
984 self.unmap(mm, new_range_in_place.end, old_length - new_length, released_mappings)?;
985 }
986 return Ok(Some(old_addr));
987 }
988
989 if self.mappings.range(old_range.end..new_range_in_place.end).next().is_some() {
990 return Ok(None);
992 }
993
994 let (original_range, mapping) =
996 self.mappings.get(old_addr).ok_or_else(|| errno!(EFAULT))?;
997
998 if old_range.end > original_range.end {
999 return error!(EFAULT);
1000 }
1001
1002 if mapping.flags().contains(MappingFlags::DONT_EXPAND) {
1003 return error!(EFAULT);
1004 }
1005
1006 let original_range = original_range.clone();
1007 let original_mapping = mapping.clone();
1008
1009 let final_length = (original_range.end - original_range.start) + (new_length - old_length);
1011
1012 match self.get_mapping_backing(&original_mapping) {
1013 MappingBacking::Memory(backing) => {
1014 Ok(Some(self.add_memory_mapping(
1016 mm,
1017 DesiredAddress::FixedOverwrite(original_range.start),
1018 backing.memory().clone(),
1019 backing.address_to_offset(original_range.start),
1020 final_length,
1021 original_mapping.flags(),
1022 false,
1023 original_mapping.name().to_owned(),
1024 original_mapping.mapping_mode(),
1025 released_mappings,
1026 )?))
1027 }
1028 MappingBacking::PrivateAnonymous => {
1029 let growth_start = original_range.end;
1030 let growth_length = new_length - old_length;
1031 let final_end = (original_range.start + final_length)?;
1032 mm.mapping_context.map_in_user_vmar(
1034 SelectedAddress::FixedOverwrite(growth_start),
1035 &mm.mapping_context.private_anonymous.backing,
1036 growth_start.ptr() as u64,
1037 growth_length,
1038 original_mapping.flags(),
1039 false,
1040 )?;
1041 released_mappings.extend(
1043 self.mappings.insert(original_range.start..final_end, original_mapping.clone()),
1044 );
1045 Ok(Some(original_range.start))
1046 }
1047 }
1048 }
1049
1050 fn remap_move(
1052 &mut self,
1053 mm: &Arc<MemoryManager>,
1054 src_addr: UserAddress,
1055 src_length: usize,
1056 dst_addr: Option<UserAddress>,
1057 dst_length: usize,
1058 keep_source: bool,
1059 released_mappings: &mut ReleasedMappings,
1060 ) -> Result<UserAddress, Errno> {
1061 let src_range = src_addr..src_addr.checked_add(src_length).ok_or_else(|| errno!(EINVAL))?;
1062 let (original_range, src_mapping) =
1063 self.mappings.get(src_addr).ok_or_else(|| errno!(EFAULT))?;
1064 let original_range = original_range.clone();
1065 let src_mapping = src_mapping.clone();
1066
1067 if src_length == 0 && !src_mapping.flags().contains(MappingFlags::SHARED) {
1068 return error!(EINVAL);
1071 }
1072
1073 if src_length != 0 && src_length > dst_length {
1077 self.unmap(mm, (src_addr + dst_length)?, src_length - dst_length, released_mappings)?;
1078 }
1079
1080 let dst_addr_for_map = match dst_addr {
1081 None => DesiredAddress::Any,
1082 Some(dst_addr) => {
1083 let dst_range =
1085 dst_addr..(dst_addr.checked_add(dst_length).ok_or_else(|| errno!(EINVAL))?);
1086 if !src_range.intersect(&dst_range).is_empty() {
1087 return error!(EINVAL);
1088 }
1089
1090 self.unmap(mm, dst_addr, dst_length, released_mappings)?;
1093
1094 DesiredAddress::Fixed(dst_addr)
1095 }
1096 };
1097
1098 if dst_length > src_length && src_mapping.flags().contains(MappingFlags::DONT_EXPAND) {
1101 return error!(EFAULT);
1102 }
1103
1104 if src_range.end > original_range.end {
1105 return error!(EFAULT);
1108 }
1109
1110 match self.get_mapping_backing(&src_mapping) {
1111 MappingBacking::PrivateAnonymous => {
1112 let dst_addr =
1113 self.select_address(dst_addr_for_map, dst_length, src_mapping.flags())?.addr();
1114 let dst_end = (dst_addr + dst_length)?;
1115
1116 let length_to_move = std::cmp::min(dst_length, src_length) as u64;
1117 let growth_start_addr = (dst_addr + length_to_move)?;
1118
1119 if dst_addr != src_addr {
1120 let src_move_end = (src_range.start + length_to_move)?;
1121 let range_to_move = src_range.start..src_move_end;
1122 mm.mapping_context.private_anonymous.move_pages(&range_to_move, dst_addr)?;
1124 }
1125
1126 let new_flags =
1128 src_mapping.flags().difference(MappingFlags::UFFD | MappingFlags::UFFD_MISSING);
1129 if src_mapping.mapping_mode() == MappingMode::Eager {
1130 mm.mapping_context.map_in_user_vmar(
1131 SelectedAddress::FixedOverwrite(dst_addr),
1132 &mm.mapping_context.private_anonymous.backing,
1133 dst_addr.ptr() as u64,
1134 dst_length,
1135 new_flags,
1136 false,
1137 )?;
1138
1139 if dst_length > src_length {
1140 let growth_length = dst_length - src_length;
1142
1143 self.map_private_anonymous(
1144 mm,
1145 DesiredAddress::FixedOverwrite(growth_start_addr),
1146 growth_length,
1147 new_flags.access_flags(),
1148 new_flags.options(),
1149 false,
1150 src_mapping.name().to_owned(),
1151 released_mappings,
1152 )?;
1153 }
1154 }
1155
1156 released_mappings.extend(self.mappings.insert(
1157 dst_addr..dst_end,
1158 Mapping::new_private_anonymous(
1159 new_flags,
1160 src_mapping.name().to_owned(),
1161 src_mapping.mapping_mode(),
1162 ),
1163 ));
1164
1165 if dst_addr != src_addr && src_length != 0 && !keep_source {
1166 self.unmap(mm, src_addr, src_length, released_mappings)?;
1167 }
1168
1169 return Ok(dst_addr);
1170 }
1171 MappingBacking::Memory(backing) => {
1172 let (dst_memory_offset, memory) =
1176 (backing.address_to_offset(src_addr), backing.memory().clone());
1177
1178 let new_address = self.add_memory_mapping(
1179 mm,
1180 dst_addr_for_map,
1181 memory,
1182 dst_memory_offset,
1183 dst_length,
1184 src_mapping.flags(),
1185 false,
1186 src_mapping.name().to_owned(),
1187 src_mapping.mapping_mode(),
1188 released_mappings,
1189 )?;
1190
1191 if src_length != 0 && !keep_source {
1192 self.unmap(mm, src_addr, src_length, released_mappings)?;
1196 }
1197
1198 return Ok(new_address);
1199 }
1200 };
1201 }
1202
1203 fn check_has_unauthorized_splits(&self, addr: UserAddress, length: usize) -> bool {
1209 let query_range = addr..addr.saturating_add(length);
1210 let mut intersection = self.mappings.range(query_range.clone());
1211
1212 let check_if_mapping_has_unauthorized_split =
1215 |mapping: Option<(&Range<UserAddress>, &Mapping)>| {
1216 mapping.is_some_and(|(mapping_range, mapping)| {
1217 mapping.flags().contains(MappingFlags::DONT_SPLIT)
1218 && (mapping_range.start < query_range.start
1219 || query_range.end < mapping_range.end)
1220 })
1221 };
1222
1223 check_if_mapping_has_unauthorized_split(intersection.next())
1227 || check_if_mapping_has_unauthorized_split(intersection.next_back())
1228 }
1229
1230 fn unmap(
1232 &mut self,
1233 mm: &Arc<MemoryManager>,
1234 addr: UserAddress,
1235 length: usize,
1236 released_mappings: &mut ReleasedMappings,
1237 ) -> Result<(), Errno> {
1238 if !addr.is_aligned(*PAGE_SIZE) {
1239 return error!(EINVAL);
1240 }
1241 let length = round_up_to_system_page_size(length)?;
1242 if length == 0 {
1243 return error!(EINVAL);
1244 }
1245
1246 if self.check_has_unauthorized_splits(addr, length) {
1247 return error!(EINVAL);
1248 }
1249
1250 #[allow(
1253 clippy::undocumented_unsafe_blocks,
1254 reason = "Force documented unsafe blocks in Starnix"
1255 )]
1256 match unsafe { mm.mapping_context.user_vmar.unmap(addr.ptr(), length) } {
1257 Ok(_) => (),
1258 Err(zx::Status::NOT_FOUND) => (),
1259 Err(zx::Status::INVALID_ARGS) => return error!(EINVAL),
1260 Err(status) => {
1261 impossible_error(status);
1262 }
1263 };
1264
1265 self.update_after_unmap(mm, addr, length, released_mappings);
1266
1267 Ok(())
1268 }
1269
1270 fn update_after_unmap(
1282 &mut self,
1283 mm: &Arc<MemoryManager>,
1284 addr: UserAddress,
1285 length: usize,
1286 released_mappings: &mut ReleasedMappings,
1287 ) {
1288 let end_addr = addr.checked_add(length).expect("address overflow during unmap");
1289 let unmap_range = addr..end_addr;
1290
1291 released_mappings.extend_pins(self.shadow_mappings_for_mlock.remove(unmap_range.clone()));
1293
1294 for (range, mapping) in self.mappings.range(unmap_range.clone()) {
1295 if let MappingBacking::PrivateAnonymous = self.get_mapping_backing(mapping) {
1297 let unmapped_range = &unmap_range.intersect(range);
1298
1299 if let Err(e) = mm
1300 .inflight_vmspliced_payloads
1301 .handle_unmapping(&mm.mapping_context.private_anonymous.backing, unmapped_range)
1302 {
1303 log_error!("Failed to handle vmsplice unmapping: {:?}", e);
1304 }
1305
1306 if let Err(e) = mm
1307 .mapping_context
1308 .private_anonymous
1309 .zero(unmapped_range.start, unmapped_range.end - unmapped_range.start)
1310 {
1311 log_error!("Failed to zero private anonymous memory: {:?}", e);
1312 }
1313 }
1314 }
1315 released_mappings.extend(self.mappings.remove(unmap_range));
1316 }
1317
1318 fn protect(
1319 &mut self,
1320 current_task: &CurrentTask,
1321 addr: UserAddress,
1322 length: usize,
1323 prot_flags: ProtectionFlags,
1324 released_mappings: &mut ReleasedMappings,
1325 ) -> Result<(), Errno> {
1326 let vmar_flags = prot_flags.to_vmar_flags();
1327 let page_size = *PAGE_SIZE;
1328 let end = addr.checked_add(length).ok_or_else(|| errno!(EINVAL))?.round_up(page_size)?;
1329
1330 if self.check_has_unauthorized_splits(addr, length) {
1331 return error!(EINVAL);
1332 }
1333
1334 let prot_range = if prot_flags.contains(ProtectionFlags::GROWSDOWN) {
1335 let mut start = addr;
1336 let Some((range, mapping)) = self.mappings.get(start) else {
1337 return error!(EINVAL);
1338 };
1339 if !mapping.flags().contains(MappingFlags::GROWSDOWN) {
1341 return error!(EINVAL);
1342 }
1343 let access_flags = mapping.flags().access_flags();
1344 start = range.start;
1352 while let Some((range, mapping)) =
1353 self.mappings.get(start.saturating_sub(page_size as usize))
1354 {
1355 if !mapping.flags().contains(MappingFlags::GROWSDOWN)
1356 || mapping.flags().access_flags() != access_flags
1357 {
1358 break;
1359 }
1360 start = range.start;
1361 }
1362 start..end
1363 } else {
1364 addr..end
1365 };
1366
1367 let mut range_list = vec![];
1368 let mapping_context = ¤t_task.mm()?.mapping_context;
1369 let length = prot_range.end - prot_range.start;
1370 self.ensure_range_mapped_in_user_vmar(prot_range.start, Some(length), mapping_context)?;
1371
1372 for (range, mapping) in self.mappings.range(prot_range.clone()) {
1373 range_list.push((range.clone(), mapping.clone()));
1374 }
1375
1376 let mut start_cursor = prot_range.start;
1377 let mut updates = vec![];
1378 let mut final_result = Ok(());
1379
1380 for (range, mapping) in range_list {
1381 if range.start > start_cursor {
1382 final_result = error!(ENOMEM);
1383 break;
1384 }
1385
1386 let intersection = range.intersect(&prot_range);
1387 if let Err(e) =
1388 security::file_mprotect(current_task, &intersection, &mapping, prot_flags)
1389 {
1390 final_result = Err(e);
1391 break;
1392 }
1393
1394 if mapping.flags().contains(MappingFlags::UFFD) {
1395 track_stub!(
1396 TODO("https://fxbug.dev/297375964"),
1397 "mprotect on uffd-registered range should not alter protections"
1398 );
1399 final_result = error!(EINVAL);
1400 break;
1401 }
1402
1403 let old_access_flags = mapping.flags().access_flags();
1404 if old_access_flags != prot_flags {
1405 let mapped_len = intersection.end - intersection.start;
1406
1407 let protect_result = unsafe {
1409 mapping_context.user_vmar.protect(
1410 intersection.start.ptr(),
1411 mapped_len,
1412 vmar_flags,
1413 )
1414 }
1415 .map_err(|s| match s {
1416 zx::Status::INVALID_ARGS => errno!(EINVAL),
1417 zx::Status::NOT_FOUND => errno!(ENOMEM),
1418 zx::Status::ACCESS_DENIED => errno!(EACCES),
1419 _ => impossible_error(s),
1420 });
1421
1422 if let Err(e) = protect_result {
1423 final_result = Err(e);
1424 break;
1425 }
1426
1427 let mut new_mapping = mapping;
1428 new_mapping.set_flags(new_mapping.flags().with_access_flags(prot_flags));
1429 let push_range = intersection.clone();
1430 updates.push((push_range, new_mapping));
1431 }
1432 start_cursor = intersection.end;
1433 }
1434
1435 if final_result.is_ok() && start_cursor < prot_range.end {
1436 final_result = error!(ENOMEM);
1437 }
1438
1439 for (r, m) in updates {
1440 released_mappings.extend(self.mappings.insert(r, m));
1441 }
1442
1443 final_result
1444 }
1445
1446 fn madvise(
1447 &mut self,
1448 context: &MappingContext,
1449 addr: UserAddress,
1450 length: usize,
1451 advice: u32,
1452 released_mappings: &mut ReleasedMappings,
1453 ) -> Result<(), Errno> {
1454 if !addr.is_aligned(*PAGE_SIZE) {
1455 return error!(EINVAL);
1456 }
1457
1458 let end_addr =
1459 addr.checked_add(length).ok_or_else(|| errno!(EINVAL))?.round_up(*PAGE_SIZE)?;
1460 if end_addr > context.max_address() {
1461 return error!(EFAULT);
1462 }
1463
1464 if advice == MADV_NORMAL {
1465 track_stub!(TODO("https://fxbug.dev/322874202"), "madvise undo hints for MADV_NORMAL");
1466 return Ok(());
1467 }
1468
1469 let mut updates = vec![];
1470 let range_for_op = addr..end_addr;
1471 for (range, mapping) in self.mappings.range(range_for_op.clone()) {
1472 let range_to_zero = range.intersect(&range_for_op);
1473 if range_to_zero.is_empty() {
1474 continue;
1475 }
1476 let start_offset = mapping.address_to_offset(range_to_zero.start);
1477 let end_offset = mapping.address_to_offset(range_to_zero.end);
1478 if advice == MADV_DONTFORK
1479 || advice == MADV_DOFORK
1480 || advice == MADV_WIPEONFORK
1481 || advice == MADV_KEEPONFORK
1482 || advice == MADV_DONTDUMP
1483 || advice == MADV_DODUMP
1484 || advice == MADV_MERGEABLE
1485 || advice == MADV_UNMERGEABLE
1486 {
1487 if advice == MADV_WIPEONFORK && !mapping.private_anonymous() {
1492 return error!(EINVAL);
1493 }
1494 let new_flags = match advice {
1495 MADV_DONTFORK => mapping.flags() | MappingFlags::DONTFORK,
1496 MADV_DOFORK => mapping.flags() & MappingFlags::DONTFORK.complement(),
1497 MADV_WIPEONFORK => mapping.flags() | MappingFlags::WIPEONFORK,
1498 MADV_KEEPONFORK => mapping.flags() & MappingFlags::WIPEONFORK.complement(),
1499 MADV_DONTDUMP => {
1500 track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_DONTDUMP");
1501 mapping.flags()
1502 }
1503 MADV_DODUMP => {
1504 track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_DODUMP");
1505 mapping.flags()
1506 }
1507 MADV_MERGEABLE => {
1508 track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_MERGEABLE");
1509 mapping.flags()
1510 }
1511 MADV_UNMERGEABLE => {
1512 track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_UNMERGEABLE");
1513 mapping.flags()
1514 }
1515 unknown_advice => unreachable!("unknown advice {unknown_advice}"),
1518 };
1519 let mut new_mapping = mapping.clone();
1520 new_mapping.set_flags(new_flags);
1521 updates.push((range_to_zero, new_mapping));
1522 } else {
1523 if mapping.flags().contains(MappingFlags::SHARED) {
1524 continue;
1525 }
1526 let op = match advice {
1527 MADV_DONTNEED if !mapping.flags().contains(MappingFlags::ANONYMOUS) => {
1528 track_stub!(
1532 TODO("https://fxbug.dev/322874496"),
1533 "MADV_DONTNEED with file-backed mapping"
1534 );
1535 return Ok(());
1536 }
1537 MADV_DONTNEED if mapping.flags().contains(MappingFlags::LOCKED) => {
1538 return error!(EINVAL);
1539 }
1540 MADV_DONTNEED => zx::VmoOp::ZERO,
1541 MADV_DONTNEED_LOCKED => {
1542 track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_DONTNEED_LOCKED");
1543 return error!(EINVAL);
1544 }
1545 MADV_WILLNEED => {
1546 if mapping.flags().contains(MappingFlags::WRITE) {
1547 zx::VmoOp::COMMIT
1548 } else {
1549 zx::VmoOp::PREFETCH
1550 }
1551 }
1552 MADV_COLD => {
1553 track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_COLD");
1554 return error!(EINVAL);
1555 }
1556 MADV_PAGEOUT => {
1557 track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_PAGEOUT");
1558 return error!(EINVAL);
1559 }
1560 MADV_POPULATE_READ => {
1561 track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_POPULATE_READ");
1562 return error!(EINVAL);
1563 }
1564 MADV_RANDOM => {
1565 track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_RANDOM");
1566 return error!(EINVAL);
1567 }
1568 MADV_SEQUENTIAL => {
1569 track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_SEQUENTIAL");
1570 return error!(EINVAL);
1571 }
1572 MADV_FREE if !mapping.flags().contains(MappingFlags::ANONYMOUS) => {
1573 track_stub!(
1574 TODO("https://fxbug.dev/411748419"),
1575 "MADV_FREE with file-backed mapping"
1576 );
1577 return error!(EINVAL);
1578 }
1579 MADV_FREE if mapping.flags().contains(MappingFlags::LOCKED) => {
1580 return error!(EINVAL);
1581 }
1582 MADV_FREE => {
1583 track_stub!(TODO("https://fxbug.dev/411748419"), "MADV_FREE");
1584 zx::VmoOp::ZERO
1587 }
1588 MADV_REMOVE => {
1589 track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_REMOVE");
1590 return error!(EINVAL);
1591 }
1592 MADV_HWPOISON => {
1593 track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_HWPOISON");
1594 return error!(EINVAL);
1595 }
1596 MADV_SOFT_OFFLINE => {
1597 track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_SOFT_OFFLINE");
1598 return error!(EINVAL);
1599 }
1600 MADV_HUGEPAGE => {
1601 track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_HUGEPAGE");
1602 return error!(EINVAL);
1603 }
1604 MADV_COLLAPSE => {
1605 track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_COLLAPSE");
1606 return error!(EINVAL);
1607 }
1608 MADV_NOHUGEPAGE => return Ok(()),
1609 advice => {
1610 track_stub!(TODO("https://fxbug.dev/322874202"), "madvise", advice);
1611 return error!(EINVAL);
1612 }
1613 };
1614
1615 let memory = match self.get_mapping_backing(mapping) {
1616 MappingBacking::Memory(backing) => backing.memory(),
1617 MappingBacking::PrivateAnonymous => &context.private_anonymous.backing,
1618 };
1619 memory.op_range(op, start_offset, end_offset - start_offset).map_err(
1620 |s| match s {
1621 zx::Status::OUT_OF_RANGE => errno!(EINVAL),
1622 zx::Status::NO_MEMORY => errno!(ENOMEM),
1623 zx::Status::INVALID_ARGS => errno!(EINVAL),
1624 zx::Status::ACCESS_DENIED => errno!(EACCES),
1625 _ => impossible_error(s),
1626 },
1627 )?;
1628 }
1629 }
1630 for (range, mapping) in updates {
1632 released_mappings.extend(self.mappings.insert(range, mapping));
1633 }
1634 Ok(())
1635 }
1636
1637 fn mlock(
1638 &mut self,
1639 context: &MappingContext,
1640 current_task: &CurrentTask,
1641 desired_addr: UserAddress,
1642 desired_length: usize,
1643 on_fault: bool,
1644 released_mappings: &mut ReleasedMappings,
1645 ) -> Result<(), Errno> {
1646 let desired_end_addr =
1647 desired_addr.checked_add(desired_length).ok_or_else(|| errno!(EINVAL))?;
1648 let start_addr = round_down_to_system_page_size(desired_addr)?;
1649 let end_addr = round_up_to_system_page_size(desired_end_addr)?;
1650
1651 let mut updates = vec![];
1652 let mut bytes_mapped_in_range = 0;
1653 let mut num_new_locked_bytes = 0;
1654 let mut failed_to_lock = false;
1655 for (range, mapping) in self.mappings.range(start_addr..end_addr) {
1656 let mut range = range.clone();
1657 let mut mapping = mapping.clone();
1658
1659 range.start = std::cmp::max(range.start, start_addr);
1661 range.end = std::cmp::min(range.end, end_addr);
1663
1664 bytes_mapped_in_range += (range.end - range.start) as u64;
1665
1666 if !mapping
1668 .flags()
1669 .intersects(MappingFlags::READ | MappingFlags::WRITE | MappingFlags::EXEC)
1670 {
1671 failed_to_lock = true;
1672 }
1673
1674 if !mapping.flags().contains(MappingFlags::LOCKED) {
1675 num_new_locked_bytes += (range.end - range.start) as u64;
1676 let shadow_mapping = match current_task.kernel().features.mlock_pin_flavor {
1677 MlockPinFlavor::ShadowProcess => {
1679 let shadow_process =
1680 current_task.kernel().expando.get_or_try_init(|| {
1681 memory_pinning::ShadowProcess::new(zx::Name::new_lossy(
1682 "starnix_mlock_pins",
1683 ))
1684 .map(MlockShadowProcess)
1685 .map_err(|_| errno!(EPERM))
1686 })?;
1687
1688 let (vmo, offset) = match self.get_mapping_backing(&mapping) {
1689 MappingBacking::Memory(m) => (
1690 m.memory().as_vmo().ok_or_else(|| errno!(ENOMEM))?,
1691 m.address_to_offset(range.start),
1692 ),
1693 MappingBacking::PrivateAnonymous => (
1694 context
1695 .private_anonymous
1696 .backing
1697 .as_vmo()
1698 .ok_or_else(|| errno!(ENOMEM))?,
1699 range.start.ptr() as u64,
1700 ),
1701 };
1702 Some(shadow_process.0.pin_pages(vmo, offset, range.end - range.start)?)
1703 }
1704
1705 MlockPinFlavor::Noop | MlockPinFlavor::VmarAlwaysNeed => None,
1707 };
1708 mapping.set_mlock();
1709 updates.push((range, mapping, shadow_mapping));
1710 }
1711 }
1712
1713 if bytes_mapped_in_range as usize != end_addr - start_addr {
1714 return error!(ENOMEM);
1715 }
1716
1717 let memlock_rlimit = current_task.thread_group().get_rlimit(Resource::MEMLOCK);
1718 let total_locked = self.num_locked_bytes(
1719 UserAddress::from(context.user_vmar_info.base as u64)
1720 ..UserAddress::from(
1721 (context.user_vmar_info.base + context.user_vmar_info.len) as u64,
1722 ),
1723 );
1724 if total_locked + num_new_locked_bytes > memlock_rlimit {
1725 if crate::security::check_task_capable(current_task, CAP_IPC_LOCK).is_err() {
1726 let code = if memlock_rlimit > 0 { errno!(ENOMEM) } else { errno!(EPERM) };
1727 return Err(code);
1728 }
1729 }
1730
1731 let op_range_status_to_errno = |e| match e {
1732 zx::Status::BAD_STATE | zx::Status::NOT_SUPPORTED => errno!(ENOMEM),
1733 zx::Status::INVALID_ARGS | zx::Status::OUT_OF_RANGE => errno!(EINVAL),
1734 zx::Status::ACCESS_DENIED => {
1735 unreachable!("user vmar should always have needed rights")
1736 }
1737 zx::Status::BAD_HANDLE => {
1738 unreachable!("user vmar should always be a valid handle")
1739 }
1740 zx::Status::WRONG_TYPE => unreachable!("user vmar handle should be a vmar"),
1741 _ => unreachable!("unknown error from op_range on user vmar for mlock: {e}"),
1742 };
1743
1744 self.ensure_range_mapped_in_user_vmar(start_addr, Some(end_addr - start_addr), context)?;
1745
1746 if !on_fault && !current_task.kernel().features.mlock_always_onfault {
1747 context
1748 .user_vmar
1749 .op_range(zx::VmarOp::PREFETCH, start_addr.ptr(), end_addr - start_addr)
1750 .map_err(op_range_status_to_errno)?;
1751 }
1752
1753 match current_task.kernel().features.mlock_pin_flavor {
1754 MlockPinFlavor::VmarAlwaysNeed => {
1755 context
1756 .user_vmar
1757 .op_range(zx::VmarOp::ALWAYS_NEED, start_addr.ptr(), end_addr - start_addr)
1758 .map_err(op_range_status_to_errno)?;
1759 }
1760 MlockPinFlavor::Noop | MlockPinFlavor::ShadowProcess => (),
1762 }
1763
1764 for (range, mapping, shadow_mapping) in updates {
1765 if let Some(shadow_mapping) = shadow_mapping {
1766 released_mappings.extend_pins(
1767 self.shadow_mappings_for_mlock.insert(range.clone(), shadow_mapping),
1768 );
1769 }
1770 released_mappings.extend(self.mappings.insert(range, mapping));
1771 }
1772
1773 if failed_to_lock { error!(ENOMEM) } else { Ok(()) }
1774 }
1775
1776 fn munlock(
1777 &mut self,
1778 _current_task: &CurrentTask,
1779 desired_addr: UserAddress,
1780 desired_length: usize,
1781 released_mappings: &mut ReleasedMappings,
1782 ) -> Result<(), Errno> {
1783 let desired_end_addr =
1784 desired_addr.checked_add(desired_length).ok_or_else(|| errno!(EINVAL))?;
1785 let start_addr = round_down_to_system_page_size(desired_addr)?;
1786 let end_addr = round_up_to_system_page_size(desired_end_addr)?;
1787
1788 let mut updates = vec![];
1789 let mut bytes_mapped_in_range = 0;
1790 for (range, mapping) in self.mappings.range(start_addr..end_addr) {
1791 let mut range = range.clone();
1792 let mut mapping = mapping.clone();
1793
1794 range.start = std::cmp::max(range.start, start_addr);
1796 range.end = std::cmp::min(range.end, end_addr);
1798
1799 bytes_mapped_in_range += (range.end - range.start) as u64;
1800
1801 if mapping.flags().contains(MappingFlags::LOCKED) {
1802 mapping.clear_mlock();
1806 updates.push((range, mapping));
1807 }
1808 }
1809
1810 if bytes_mapped_in_range as usize != end_addr - start_addr {
1811 return error!(ENOMEM);
1812 }
1813
1814 for (range, mapping) in updates {
1815 released_mappings.extend(self.mappings.insert(range.clone(), mapping));
1816 released_mappings.extend_pins(self.shadow_mappings_for_mlock.remove(range));
1817 }
1818
1819 Ok(())
1820 }
1821
1822 pub fn num_locked_bytes(&self, range: impl RangeBounds<UserAddress>) -> u64 {
1823 self.mappings
1824 .map
1825 .range(range)
1826 .filter(|(_, mapping)| mapping.flags().contains(MappingFlags::LOCKED))
1827 .map(|(range, _)| (range.end - range.start) as u64)
1828 .sum()
1829 }
1830
1831 fn get_mappings_for_vmsplice(
1832 &self,
1833 mm: &Arc<MemoryManager>,
1834 buffers: &UserBuffers,
1835 ) -> Result<Vec<Arc<VmsplicePayload>>, Errno> {
1836 let mut vmsplice_mappings = Vec::new();
1837
1838 for UserBuffer { mut address, length } in buffers.iter().copied() {
1839 let mappings = self.get_contiguous_mappings_at(address, length, &mm.mapping_context)?;
1840 for (mapping, length) in mappings {
1841 let vmsplice_payload = match self.get_mapping_backing(mapping) {
1842 MappingBacking::Memory(m) => VmsplicePayloadSegment {
1843 addr_offset: address,
1844 length,
1845 memory: m.memory().clone(),
1846 memory_offset: m.address_to_offset(address),
1847 should_snapshot_on_unmap: false,
1848 },
1849 MappingBacking::PrivateAnonymous => VmsplicePayloadSegment {
1850 addr_offset: address,
1851 length,
1852 memory: mm.mapping_context.private_anonymous.backing.clone(),
1853 memory_offset: address.ptr() as u64,
1854 should_snapshot_on_unmap: true,
1855 },
1856 };
1857 vmsplice_mappings.push(VmsplicePayload::new(Arc::downgrade(mm), vmsplice_payload));
1858
1859 address = (address + length)?;
1860 }
1861 }
1862
1863 Ok(vmsplice_mappings)
1864 }
1865
1866 fn get_contiguous_mappings_at(
1879 &self,
1880 addr: UserAddress,
1881 length: usize,
1882 context: &MappingContext,
1883 ) -> Result<impl Iterator<Item = (&Mapping, usize)>, Errno> {
1884 let end_addr = addr.checked_add(length).ok_or_else(|| errno!(EFAULT))?;
1885 if end_addr > context.max_address() {
1886 return error!(EFAULT);
1887 }
1888
1889 let mut mappings = self.mappings.range(addr..end_addr);
1891 let mut prev_range_end = None;
1892 let mut offset = 0;
1893 let result = std::iter::from_fn(move || {
1894 if offset != length {
1895 if let Some((range, mapping)) = mappings.next() {
1896 return match prev_range_end {
1897 None if range.start > addr => None,
1900
1901 Some(prev_range_end) if range.start != prev_range_end => None,
1903
1904 _ => {
1906 let mapping_length = std::cmp::min(length, range.end - addr) - offset;
1907 offset += mapping_length;
1908 prev_range_end = Some(range.end);
1909 Some((mapping, mapping_length))
1910 }
1911 };
1912 }
1913 }
1914
1915 None
1916 });
1917
1918 Ok(result)
1919 }
1920
1921 fn find_growsdown_mapping(&self, addr: UserAddress) -> Option<(UserAddress, &Mapping)> {
1929 match self.mappings.range(addr..).next() {
1930 Some((range, mapping)) => {
1931 if range.contains(&addr) {
1932 return None;
1934 } else if !mapping.flags().contains(MappingFlags::GROWSDOWN) {
1935 None
1938 } else {
1939 Some((range.start, mapping))
1940 }
1941 }
1942 None => None,
1943 }
1944 }
1945
1946 fn extend_growsdown_mapping_to_address(
1949 &mut self,
1950 mm: &Arc<MemoryManager>,
1951 addr: UserAddress,
1952 is_write: bool,
1953 ) -> Result<bool, Error> {
1954 let Some((mapping_low_addr, mapping_to_grow)) = self.find_growsdown_mapping(addr) else {
1955 return Ok(false);
1956 };
1957 if is_write && !mapping_to_grow.can_write() {
1958 return Ok(false);
1960 }
1961 if !mapping_to_grow.flags().contains(MappingFlags::ANONYMOUS) {
1962 return Ok(false);
1964 }
1965 let low_addr = (addr - (addr.ptr() as u64 % *PAGE_SIZE))?;
1966 let high_addr = mapping_low_addr;
1967
1968 let length = high_addr
1969 .ptr()
1970 .checked_sub(low_addr.ptr())
1971 .ok_or_else(|| anyhow!("Invalid growth range"))?;
1972
1973 let mut released_mappings = ReleasedMappings::default();
1974 self.map_anonymous(
1975 mm,
1976 DesiredAddress::FixedOverwrite(low_addr),
1977 length,
1978 mapping_to_grow.flags().access_flags(),
1979 mapping_to_grow.flags().options(),
1980 mapping_to_grow.name().to_owned(),
1981 &mut released_mappings,
1982 )?;
1983 assert!(
1986 released_mappings.is_empty(),
1987 "expected to not remove mappings by inserting, got {released_mappings:#?}"
1988 );
1989 Ok(true)
1990 }
1991
1992 fn read_memory<'a>(
1998 &self,
1999 addr: UserAddress,
2000 bytes: &'a mut [MaybeUninit<u8>],
2001 context: &MappingContext,
2002 ) -> Result<&'a mut [u8], Errno> {
2003 let mut bytes_read = 0;
2004 for (mapping, len) in self.get_contiguous_mappings_at(addr, bytes.len(), context)? {
2005 let next_offset = bytes_read + len;
2006 self.read_mapping_memory(
2007 (addr + bytes_read)?,
2008 mapping,
2009 &mut bytes[bytes_read..next_offset],
2010 context,
2011 )?;
2012 bytes_read = next_offset;
2013 }
2014
2015 if bytes_read != bytes.len() {
2016 error!(EFAULT)
2017 } else {
2018 let bytes = unsafe {
2023 std::slice::from_raw_parts_mut(bytes.as_mut_ptr() as *mut u8, bytes_read)
2024 };
2025 Ok(bytes)
2026 }
2027 }
2028
2029 fn read_mapping_memory<'a>(
2035 &self,
2036 addr: UserAddress,
2037 mapping: &Mapping,
2038 bytes: &'a mut [MaybeUninit<u8>],
2039 context: &MappingContext,
2040 ) -> Result<&'a mut [u8], Errno> {
2041 if !mapping.can_read() {
2042 return error!(EFAULT, "read_mapping_memory called on unreadable mapping");
2043 }
2044 match self.get_mapping_backing(mapping) {
2045 MappingBacking::Memory(backing) => backing.read_memory(addr, bytes),
2046 MappingBacking::PrivateAnonymous => context.private_anonymous.read_memory(addr, bytes),
2047 }
2048 }
2049
2050 fn read_memory_partial<'a>(
2060 &self,
2061 addr: UserAddress,
2062 bytes: &'a mut [MaybeUninit<u8>],
2063 context: &MappingContext,
2064 ) -> Result<&'a mut [u8], Errno> {
2065 let mut bytes_read = 0;
2066 for (mapping, len) in self.get_contiguous_mappings_at(addr, bytes.len(), context)? {
2067 let next_offset = bytes_read + len;
2068 if self
2069 .read_mapping_memory(
2070 (addr + bytes_read)?,
2071 mapping,
2072 &mut bytes[bytes_read..next_offset],
2073 context,
2074 )
2075 .is_err()
2076 {
2077 break;
2078 }
2079 bytes_read = next_offset;
2080 }
2081
2082 if !bytes.is_empty() && bytes_read == 0 {
2084 error!(EFAULT)
2085 } else {
2086 let bytes = unsafe {
2091 std::slice::from_raw_parts_mut(bytes.as_mut_ptr() as *mut u8, bytes_read)
2092 };
2093 Ok(bytes)
2094 }
2095 }
2096
2097 fn read_memory_partial_until_null_byte<'a>(
2100 &self,
2101 addr: UserAddress,
2102 bytes: &'a mut [MaybeUninit<u8>],
2103 context: &MappingContext,
2104 ) -> Result<&'a mut [u8], Errno> {
2105 let read_bytes = self.read_memory_partial(addr, bytes, context)?;
2106 let max_len = memchr::memchr(b'\0', read_bytes)
2107 .map_or_else(|| read_bytes.len(), |null_index| null_index + 1);
2108 Ok(&mut read_bytes[..max_len])
2109 }
2110
2111 fn write_memory(
2119 &self,
2120 addr: UserAddress,
2121 bytes: &[u8],
2122 context: &MappingContext,
2123 ) -> Result<usize, Errno> {
2124 let mut bytes_written = 0;
2125 for (mapping, len) in self.get_contiguous_mappings_at(addr, bytes.len(), context)? {
2126 let next_offset = bytes_written + len;
2127 self.write_mapping_memory(
2128 (addr + bytes_written)?,
2129 mapping,
2130 &bytes[bytes_written..next_offset],
2131 context,
2132 )?;
2133 bytes_written = next_offset;
2134 }
2135
2136 if bytes_written != bytes.len() { error!(EFAULT) } else { Ok(bytes.len()) }
2137 }
2138
2139 fn write_mapping_memory(
2145 &self,
2146 addr: UserAddress,
2147 mapping: &Mapping,
2148 bytes: &[u8],
2149 context: &MappingContext,
2150 ) -> Result<(), Errno> {
2151 if !mapping.can_write() {
2152 return error!(EFAULT, "write_mapping_memory called on unwritable memory");
2153 }
2154 match self.get_mapping_backing(mapping) {
2155 MappingBacking::Memory(backing) => backing.write_memory(addr, bytes),
2156 MappingBacking::PrivateAnonymous => context.private_anonymous.write_memory(addr, bytes),
2157 }
2158 }
2159
2160 fn write_memory_partial(
2167 &self,
2168 addr: UserAddress,
2169 bytes: &[u8],
2170 context: &MappingContext,
2171 ) -> Result<usize, Errno> {
2172 let mut bytes_written = 0;
2173 for (mapping, len) in self.get_contiguous_mappings_at(addr, bytes.len(), context)? {
2174 let next_offset = bytes_written + len;
2175 if self
2176 .write_mapping_memory(
2177 (addr + bytes_written)?,
2178 mapping,
2179 &bytes[bytes_written..next_offset],
2180 context,
2181 )
2182 .is_err()
2183 {
2184 break;
2185 }
2186 bytes_written = next_offset;
2187 }
2188
2189 if !bytes.is_empty() && bytes_written == 0 { error!(EFAULT) } else { Ok(bytes.len()) }
2190 }
2191
2192 fn zero(
2193 &self,
2194 addr: UserAddress,
2195 length: usize,
2196 context: &MappingContext,
2197 ) -> Result<usize, Errno> {
2198 let mut bytes_written = 0;
2199 for (mapping, len) in self.get_contiguous_mappings_at(addr, length, context)? {
2200 let next_offset = bytes_written + len;
2201 if self.zero_mapping((addr + bytes_written)?, mapping, len, context).is_err() {
2202 break;
2203 }
2204 bytes_written = next_offset;
2205 }
2206
2207 if length != bytes_written { error!(EFAULT) } else { Ok(length) }
2208 }
2209
2210 fn zero_mapping(
2211 &self,
2212 addr: UserAddress,
2213 mapping: &Mapping,
2214 length: usize,
2215 context: &MappingContext,
2216 ) -> Result<usize, Errno> {
2217 if !mapping.can_write() {
2218 return error!(EFAULT);
2219 }
2220
2221 match self.get_mapping_backing(mapping) {
2222 MappingBacking::Memory(backing) => backing.zero(addr, length),
2223 MappingBacking::PrivateAnonymous => context.private_anonymous.zero(addr, length),
2224 }
2225 }
2226
2227 pub fn create_memory_backing(
2228 &self,
2229 base: UserAddress,
2230 memory: Arc<MemoryObject>,
2231 memory_offset: u64,
2232 ) -> MappingBacking {
2233 MappingBacking::Memory(Box::new(MappingBackingMemory::new(base, memory, memory_offset)))
2234 }
2235
2236 pub fn get_mapping_backing<'a>(&self, mapping: &'a Mapping) -> &'a MappingBacking {
2237 mapping.get_backing_internal()
2238 }
2239
2240 fn get_aio_context(&self, addr: UserAddress) -> Option<(Range<UserAddress>, Arc<AioContext>)> {
2241 let Some((range, mapping)) = self.mappings.get(addr) else {
2242 return None;
2243 };
2244 let MappingNameRef::AioContext(ref aio_context) = mapping.name() else {
2245 return None;
2246 };
2247 if !mapping.can_read() {
2248 return None;
2249 }
2250 Some((range.clone(), Arc::clone(aio_context)))
2251 }
2252
2253 fn find_uffd(&self, addr: UserAddress) -> Option<Arc<UserFault>> {
2254 for userfault in self.userfaultfds.iter() {
2255 if let Some(userfault) = userfault.upgrade() {
2256 if userfault.contains_addr(addr) {
2257 return Some(userfault);
2258 }
2259 }
2260 }
2261 None
2262 }
2263
2264 fn cache_flush(
2265 &self,
2266 range: Range<UserAddress>,
2267 context: &MappingContext,
2268 ) -> Result<(), Errno> {
2269 let mut addr = range.start;
2270 let size = range.end - range.start;
2271 for (mapping, len) in self.get_contiguous_mappings_at(addr, size, context)? {
2272 if !mapping.can_read() {
2273 return error!(EFAULT);
2274 }
2275 if mapping.mapping_mode() == MappingMode::Lazy {
2276 addr = (addr + len)?;
2277 continue;
2278 }
2279 zx::Status::ok(unsafe {
2281 zx::sys::zx_cache_flush(
2282 addr.ptr() as *const u8,
2283 len,
2284 zx::sys::ZX_CACHE_FLUSH_DATA | zx::sys::ZX_CACHE_FLUSH_INSN,
2285 )
2286 })
2287 .map_err(impossible_error)?;
2288
2289 addr = (addr + len).unwrap(); }
2291 if addr != range.end { error!(EFAULT) } else { Ok(()) }
2293 }
2294
2295 pub fn register_membarrier_private_expedited(
2298 &mut self,
2299 mtype: MembarrierType,
2300 ) -> Result<(), Errno> {
2301 let registrations = &mut self.forkable_state.membarrier_registrations;
2302 match mtype {
2303 MembarrierType::Memory => {
2304 registrations.memory = true;
2305 }
2306 MembarrierType::SyncCore => {
2307 registrations.sync_core = true;
2308 }
2309 }
2310 Ok(())
2311 }
2312
2313 pub fn membarrier_private_expedited_registered(&self, mtype: MembarrierType) -> bool {
2316 let registrations = &self.forkable_state.membarrier_registrations;
2317 match mtype {
2318 MembarrierType::Memory => registrations.memory,
2319 MembarrierType::SyncCore => registrations.sync_core,
2320 }
2321 }
2322
2323 fn force_write_memory(
2324 &mut self,
2325 context: &MappingContext,
2326 addr: UserAddress,
2327 bytes: &[u8],
2328 released_mappings: &mut ReleasedMappings,
2329 ) -> Result<(), Errno> {
2330 let (range, mapping) = {
2331 let (r, m) = self.mappings.get(addr).ok_or_else(|| errno!(EFAULT))?;
2332 (r.clone(), m.clone())
2333 };
2334 if range.end < addr.saturating_add(bytes.len()) {
2335 track_stub!(
2336 TODO("https://fxbug.dev/445790710"),
2337 "ptrace poke across multiple mappings"
2338 );
2339 return error!(EFAULT);
2340 }
2341
2342 if mapping.flags().contains(MappingFlags::SHARED) {
2344 if !mapping.can_write() {
2345 return error!(EIO);
2347 }
2348 return self.write_mapping_memory(addr, &mapping, &bytes, context);
2349 }
2350
2351 let backing = match self.get_mapping_backing(&mapping) {
2352 MappingBacking::PrivateAnonymous => {
2353 return context.private_anonymous.write_memory(addr, &bytes);
2355 }
2356 MappingBacking::Memory(backing) => backing,
2357 };
2358
2359 let vmo = backing.memory().as_vmo().ok_or_else(|| errno!(EFAULT))?;
2360 let addr_offset = backing.address_to_offset(addr);
2361 let can_exec =
2362 vmo.basic_info().expect("get VMO handle info").rights.contains(Rights::EXECUTE);
2363
2364 match vmo.write(&bytes, addr_offset) {
2366 Ok(()) => {
2367 if can_exec {
2368 system_barrier(BarrierType::InstructionStream);
2370 }
2371 return Ok(());
2372 }
2373
2374 Err(zx::Status::ACCESS_DENIED) => { }
2375
2376 Err(status) => {
2377 return Err(MemoryManager::get_errno_for_vmo_err(status));
2378 }
2379 }
2380
2381 let mapping_offset = backing.address_to_offset(range.start);
2383 let len = range.end - range.start;
2384
2385 let size = vmo.get_size().map_err(MemoryManager::get_errno_for_vmo_err)?;
2387 let child_vmo = vmo
2388 .create_child(VmoChildOptions::SNAPSHOT_AT_LEAST_ON_WRITE, 0, size)
2389 .map_err(MemoryManager::get_errno_for_vmo_err)?;
2390
2391 child_vmo.write(&bytes, addr_offset).map_err(MemoryManager::get_errno_for_vmo_err)?;
2393
2394 let child_vmo = if can_exec {
2397 child_vmo
2398 .replace_as_executable(&VMEX_RESOURCE)
2399 .map_err(MemoryManager::get_errno_for_vmo_err)?
2400 } else {
2401 child_vmo
2402 };
2403
2404 self.ensure_range_mapped_in_user_vmar(addr, None, context)?;
2409
2410 let memory = Arc::new(MemoryObject::from(child_vmo));
2412 context.map_in_user_vmar(
2413 SelectedAddress::FixedOverwrite(range.start),
2414 &memory,
2415 mapping_offset,
2416 len,
2417 mapping.flags(),
2418 false,
2419 )?;
2420
2421 let new_backing = MappingBackingMemory::new(range.start, memory, mapping_offset);
2423
2424 let mut new_mapping = mapping.clone();
2425 new_mapping.set_backing_internal(MappingBacking::Memory(Box::new(new_backing)));
2426
2427 released_mappings.extend(self.mappings.insert(range, new_mapping));
2428
2429 Ok(())
2430 }
2431
2432 fn set_brk(
2433 &mut self,
2434 current_task: &CurrentTask,
2435 mm: &Arc<MemoryManager>,
2436 addr: UserAddress,
2437 released_mappings: &mut ReleasedMappings,
2438 ) -> Result<UserAddress, Errno> {
2439 let rlimit_data = std::cmp::min(
2440 PROGRAM_BREAK_LIMIT,
2441 current_task.thread_group().get_rlimit(Resource::DATA),
2442 );
2443
2444 let brk = match self.brk.clone() {
2445 None => {
2446 let brk = ProgramBreak { base: self.brk_origin, current: self.brk_origin };
2447 self.brk = Some(brk.clone());
2448 brk
2449 }
2450 Some(brk) => brk,
2451 };
2452
2453 let Ok(last_address) = brk.base + rlimit_data else {
2454 return Ok(brk.current);
2457 };
2458
2459 if addr < brk.base || addr > last_address {
2460 return Ok(brk.current);
2463 }
2464
2465 let old_end = brk.current.round_up(*PAGE_SIZE).unwrap();
2466 let new_end = addr.round_up(*PAGE_SIZE).unwrap();
2467
2468 match new_end.cmp(&old_end) {
2469 std::cmp::Ordering::Less => {
2470 let delta = old_end - new_end;
2474
2475 if self.unmap(mm, new_end, delta, released_mappings).is_err() {
2476 return Ok(brk.current);
2477 }
2478 }
2479 std::cmp::Ordering::Greater => {
2480 let range = old_end..new_end;
2481 let delta = new_end - old_end;
2482
2483 if self.mappings.range(range).next().is_some() {
2485 return Ok(brk.current);
2486 }
2487
2488 if self
2489 .map_anonymous(
2490 mm,
2491 DesiredAddress::FixedOverwrite(old_end),
2492 delta,
2493 ProtectionFlags::READ | ProtectionFlags::WRITE,
2494 MappingOptions::ANONYMOUS,
2495 MappingName::Heap,
2496 released_mappings,
2497 )
2498 .is_err()
2499 {
2500 return Ok(brk.current);
2501 }
2502 }
2503 _ => {}
2504 };
2505
2506 let mut new_brk = brk;
2508 new_brk.current = addr;
2509 self.brk = Some(new_brk);
2510
2511 Ok(addr)
2512 }
2513
2514 fn register_with_uffd(
2515 &mut self,
2516 mm: &MemoryManager,
2517 addr: UserAddress,
2518 length: usize,
2519 userfault: &Arc<UserFault>,
2520 mode: FaultRegisterMode,
2521 released_mappings: &mut ReleasedMappings,
2522 ) -> Result<(), Errno> {
2523 let end_addr = addr.checked_add(length).ok_or_else(|| errno!(EINVAL))?;
2524 let range_for_op = addr..end_addr;
2525 let mut updates = vec![];
2526
2527 for (range, mapping) in self.mappings.range(range_for_op.clone()) {
2528 if !mapping.private_anonymous() {
2529 track_stub!(TODO("https://fxbug.dev/391599171"), "uffd for shmem and hugetlbfs");
2530 return error!(EINVAL);
2531 }
2532 if mapping.flags().contains(MappingFlags::UFFD) {
2533 return error!(EBUSY);
2534 }
2535 let range = range.intersect(&range_for_op);
2536 let mut mapping = mapping.clone();
2537 mapping.set_uffd(mode);
2538 updates.push((range, mapping));
2539 }
2540 if updates.is_empty() {
2541 return error!(EINVAL);
2542 }
2543
2544 mm.protect_vmar_range(addr, length, ProtectionFlags::empty())
2545 .expect("Failed to remove protections on uffd-registered range");
2546
2547 for (range, mapping) in updates {
2549 released_mappings.extend(self.mappings.insert(range, mapping));
2550 }
2551
2552 userfault.insert_pages(range_for_op, false);
2553
2554 Ok(())
2555 }
2556
2557 fn unregister_range_from_uffd(
2558 &mut self,
2559 mm: &MemoryManager,
2560 userfault: &Arc<UserFault>,
2561 addr: UserAddress,
2562 length: usize,
2563 released_mappings: &mut ReleasedMappings,
2564 ) -> Result<(), Errno> {
2565 let end_addr = addr.checked_add(length).ok_or_else(|| errno!(EINVAL))?;
2566 let range_for_op = addr..end_addr;
2567 let mut updates = vec![];
2568
2569 for (range, mapping) in self.mappings.range(range_for_op.clone()) {
2570 if !mapping.private_anonymous() {
2571 track_stub!(TODO("https://fxbug.dev/391599171"), "uffd for shmem and hugetlbfs");
2572 return error!(EINVAL);
2573 }
2574 if mapping.flags().contains(MappingFlags::UFFD) {
2575 let range = range.intersect(&range_for_op);
2576 if userfault.remove_pages(range.clone()) {
2577 let mut mapping = mapping.clone();
2578 mapping.clear_uffd();
2579 updates.push((range, mapping));
2580 }
2581 }
2582 }
2583 for (range, mapping) in updates {
2584 let length = range.end - range.start;
2585 let restored_flags = mapping.flags().access_flags();
2586
2587 released_mappings.extend(self.mappings.insert(range.clone(), mapping));
2588
2589 mm.protect_vmar_range(range.start, length, restored_flags)
2590 .expect("Failed to restore original protection bits on uffd-registered range");
2591 }
2592 Ok(())
2593 }
2594
2595 fn unregister_uffd(
2596 &mut self,
2597 mm: &MemoryManager,
2598 userfault: &Arc<UserFault>,
2599 released_mappings: &mut ReleasedMappings,
2600 ) {
2601 let mut updates = vec![];
2602
2603 for (range, mapping) in self.mappings.iter() {
2604 if mapping.flags().contains(MappingFlags::UFFD) {
2605 for range in userfault.get_registered_pages_overlapping_range(range.clone()) {
2606 let mut mapping = mapping.clone();
2607 mapping.clear_uffd();
2608 updates.push((range, mapping));
2609 }
2610 }
2611 }
2612 for (range, mapping) in updates {
2614 let length = range.end - range.start;
2615 let restored_flags = mapping.flags().access_flags();
2616 released_mappings.extend(self.mappings.insert(range.clone(), mapping));
2617 mm.protect_vmar_range(range.start, length, restored_flags)
2619 .expect("Failed to restore original protection bits on uffd-registered range");
2620 }
2621
2622 userfault.remove_pages(
2623 UserAddress::from_ptr(RESTRICTED_ASPACE_BASE)
2624 ..UserAddress::from_ptr(RESTRICTED_ASPACE_HIGHEST_ADDRESS),
2625 );
2626
2627 let weak_userfault = Arc::downgrade(userfault);
2628 self.userfaultfds.retain(|uf| !Weak::ptr_eq(uf, &weak_userfault));
2629 }
2630
2631 fn set_mapping_name(
2632 &mut self,
2633 addr: UserAddress,
2634 length: usize,
2635 name: Option<FsString>,
2636 released_mappings: &mut ReleasedMappings,
2637 ) -> Result<(), Errno> {
2638 if addr.ptr() % *PAGE_SIZE as usize != 0 {
2639 return error!(EINVAL);
2640 }
2641 let end = match addr.checked_add(length) {
2642 Some(addr) => addr.round_up(*PAGE_SIZE).map_err(|_| errno!(ENOMEM))?,
2643 None => return error!(EINVAL),
2644 };
2645
2646 let mappings_in_range =
2647 self.mappings.range(addr..end).map(|(r, m)| (r.clone(), m.clone())).collect::<Vec<_>>();
2648
2649 if mappings_in_range.is_empty() {
2650 return error!(EINVAL);
2651 }
2652 if !mappings_in_range.first().unwrap().0.contains(&addr) {
2653 return error!(ENOMEM);
2654 }
2655
2656 let mut last_range_end = None;
2657 for (mut range, mut mapping) in mappings_in_range {
2661 if mapping.name().is_file() {
2662 return error!(EBADF);
2664 }
2665 range.start = std::cmp::max(range.start, addr);
2667 range.end = std::cmp::min(range.end, end);
2669
2670 if let Some(last_range_end) = last_range_end {
2671 if last_range_end != range.start {
2672 return error!(ENOMEM);
2674 }
2675 }
2676 last_range_end = Some(range.end.round_up(*PAGE_SIZE)?);
2677 if let MappingBacking::Memory(backing) = self.get_mapping_backing(&mapping) {
2680 match &name {
2681 Some(memory_name) => {
2682 backing.memory().set_zx_name(memory_name);
2683 }
2684 None => {
2685 backing.memory().set_zx_name(b"");
2686 }
2687 }
2688 }
2689 mapping.set_name(match &name {
2690 Some(name) => MappingName::Vma(FlyByteStr::new(name.as_bytes())),
2691 None => MappingName::None,
2692 });
2693 released_mappings.extend(self.mappings.insert(range, mapping));
2694 }
2695 if let Some(last_range_end) = last_range_end {
2696 if last_range_end < end {
2697 return error!(ENOMEM);
2699 }
2700 }
2701 Ok(())
2702 }
2703}
2704
2705pub struct MlockShadowProcess(memory_pinning::ShadowProcess);
2710
2711impl MemoryManager {
2712 pub fn ensure_range_mapped_in_user_vmar(
2717 &self,
2718 addr: UserAddress,
2719 length: Option<usize>,
2720 ) -> Result<bool, Errno> {
2721 if !self.state.read().any_ranges_lazy(std::iter::once((addr, length))) {
2722 return Ok(false);
2723 }
2724 self.state.write().ensure_ranges_mapped_in_user_vmar(
2725 std::iter::once((addr, length)),
2726 &self.mapping_context,
2727 )
2728 }
2729
2730 pub fn ensure_ranges_mapped_in_user_vmar<I>(&self, ranges: I) -> Result<bool, Errno>
2735 where
2736 I: IntoIterator<Item = (UserAddress, Option<usize>)>,
2737 {
2738 let ranges = ranges.into_iter().collect::<SmallVec<[_; 4]>>();
2741 if !self.state.read().any_ranges_lazy(ranges.iter().cloned()) {
2742 return Ok(false);
2743 }
2744 self.state.write().ensure_ranges_mapped_in_user_vmar(ranges, &self.mapping_context)
2745 }
2746
2747 pub fn mrelease(&self) -> Result<(), Errno> {
2748 self.mapping_context.private_anonymous.zero(
2749 UserAddress::from_ptr(self.mapping_context.user_vmar_info.base),
2750 self.mapping_context.user_vmar_info.len,
2751 )?;
2752 Ok(())
2753 }
2754
2755 pub fn summarize(&self, summary: &mut crate::mm::MappingSummary) {
2756 let state = self.state.read();
2757 for (_, mapping) in state.mappings.iter() {
2758 summary.add(&state, mapping);
2759 }
2760 }
2761
2762 pub fn get_mappings_for_vmsplice(
2763 self: &Arc<MemoryManager>,
2764 buffers: &UserBuffers,
2765 ) -> Result<Vec<Arc<VmsplicePayload>>, Errno> {
2766 self.state.read().get_mappings_for_vmsplice(self, buffers)
2767 }
2768
2769 pub fn has_same_address_space(&self, other: &Self) -> bool {
2770 std::ptr::eq(self, other)
2771 }
2772
2773 fn unified_transfer_loop<F>(
2774 &self,
2775 addr: UserAddress,
2776 len: usize,
2777 mut transfer_fn: F,
2778 ) -> Result<usize, Errno>
2779 where
2780 F: FnMut(UserAddress, usize) -> Result<ControlFlow<usize, usize>, Errno>,
2781 {
2782 let mut copied = 0;
2783 while copied < len {
2784 match transfer_fn((addr + copied)?, copied)? {
2785 ControlFlow::Continue(num_copied) => {
2786 if num_copied == 0 {
2787 let fault_addr = (addr + copied)?;
2788 if self.ensure_range_mapped_in_user_vmar(fault_addr, None)? {
2799 continue;
2800 } else {
2801 break;
2802 }
2803 }
2804 copied += num_copied;
2805 }
2806 ControlFlow::Break(num_copied) => {
2807 copied += num_copied;
2808 break;
2809 }
2810 }
2811 }
2812 Ok(copied)
2813 }
2814
2815 pub fn unified_read_memory<'a>(
2816 &self,
2817 current_task: &CurrentTask,
2818 addr: UserAddress,
2819 bytes: &'a mut [MaybeUninit<u8>],
2820 ) -> Result<&'a mut [u8], Errno> {
2821 debug_assert!(self.has_same_address_space(¤t_task.mm().unwrap()));
2822
2823 let buf_ptr = bytes.as_mut_ptr();
2824 let buf_len = bytes.len();
2825
2826 let copied = self.unified_transfer_loop(addr, buf_len, |cur_addr, offset| {
2827 let current_bytes =
2829 unsafe { std::slice::from_raw_parts_mut(buf_ptr.add(offset), buf_len - offset) };
2830 let (read_bytes, _unread_bytes) = usercopy().copyin(cur_addr.ptr(), current_bytes);
2831 Ok(ControlFlow::Continue(read_bytes.len()))
2832 })?;
2833 if copied < bytes.len() {
2834 error!(EFAULT)
2835 } else {
2836 Ok(unsafe { std::slice::from_raw_parts_mut(buf_ptr as *mut u8, buf_len) })
2838 }
2839 }
2840
2841 pub fn syscall_read_memory<'a>(
2842 &self,
2843 addr: UserAddress,
2844 bytes: &'a mut [MaybeUninit<u8>],
2845 ) -> Result<&'a mut [u8], Errno> {
2846 self.state.read().read_memory(addr, bytes, &self.mapping_context)
2847 }
2848
2849 pub fn unified_read_memory_partial_until_null_byte<'a>(
2850 &self,
2851 current_task: &CurrentTask,
2852 addr: UserAddress,
2853 bytes: &'a mut [MaybeUninit<u8>],
2854 ) -> Result<&'a mut [u8], Errno> {
2855 debug_assert!(self.has_same_address_space(¤t_task.mm().unwrap()));
2856
2857 let buf_ptr = bytes.as_mut_ptr();
2858 let buf_len = bytes.len();
2859
2860 let copied = self.unified_transfer_loop(addr, buf_len, |cur_addr, offset| {
2861 let current_bytes =
2863 unsafe { std::slice::from_raw_parts_mut(buf_ptr.add(offset), buf_len - offset) };
2864 let (read_bytes, _unread_bytes) =
2865 usercopy().copyin_until_null_byte(cur_addr.ptr(), current_bytes);
2866
2867 let num_copied = read_bytes.len();
2868 if read_bytes.last().map(|b| *b == 0).unwrap_or(false) {
2869 Ok(ControlFlow::Break(num_copied))
2870 } else {
2871 Ok(ControlFlow::Continue(num_copied))
2872 }
2873 })?;
2874 if copied == 0 && !bytes.is_empty() {
2875 error!(EFAULT)
2876 } else {
2877 Ok(unsafe { std::slice::from_raw_parts_mut(buf_ptr as *mut u8, copied) })
2879 }
2880 }
2881
2882 pub fn syscall_read_memory_partial_until_null_byte<'a>(
2883 &self,
2884 addr: UserAddress,
2885 bytes: &'a mut [MaybeUninit<u8>],
2886 ) -> Result<&'a mut [u8], Errno> {
2887 self.state.read().read_memory_partial_until_null_byte(addr, bytes, &self.mapping_context)
2888 }
2889
2890 pub fn unified_read_memory_partial<'a>(
2891 &self,
2892 current_task: &CurrentTask,
2893 addr: UserAddress,
2894 bytes: &'a mut [MaybeUninit<u8>],
2895 ) -> Result<&'a mut [u8], Errno> {
2896 debug_assert!(self.has_same_address_space(¤t_task.mm().unwrap()));
2897
2898 let buf_ptr = bytes.as_mut_ptr();
2899 let buf_len = bytes.len();
2900
2901 let copied = self.unified_transfer_loop(addr, buf_len, |cur_addr, offset| {
2902 let current_bytes =
2904 unsafe { std::slice::from_raw_parts_mut(buf_ptr.add(offset), buf_len - offset) };
2905 let (read_bytes, _unread_bytes) = usercopy().copyin(cur_addr.ptr(), current_bytes);
2906 Ok(ControlFlow::Continue(read_bytes.len()))
2907 })?;
2908 if copied == 0 && !bytes.is_empty() {
2909 error!(EFAULT)
2910 } else {
2911 Ok(unsafe { std::slice::from_raw_parts_mut(buf_ptr as *mut u8, copied) })
2913 }
2914 }
2915
2916 pub fn syscall_read_memory_partial<'a>(
2917 &self,
2918 addr: UserAddress,
2919 bytes: &'a mut [MaybeUninit<u8>],
2920 ) -> Result<&'a mut [u8], Errno> {
2921 self.state.read().read_memory_partial(addr, bytes, &self.mapping_context)
2922 }
2923
2924 pub fn unified_write_memory(
2925 &self,
2926 current_task: &CurrentTask,
2927 addr: UserAddress,
2928 bytes: &[u8],
2929 ) -> Result<usize, Errno> {
2930 debug_assert!(self.has_same_address_space(¤t_task.mm().unwrap()));
2931
2932 let len = bytes.len();
2933 let copied = self.unified_transfer_loop(addr, len, |cur_addr, offset| {
2934 Ok(ControlFlow::Continue(usercopy().copyout(&bytes[offset..], cur_addr.ptr())))
2935 })?;
2936 if copied < bytes.len() { error!(EFAULT) } else { Ok(copied) }
2937 }
2938
2939 pub fn force_write_memory(&self, addr: UserAddress, bytes: &[u8]) -> Result<(), Errno> {
2945 let mut state = self.state.write();
2946 let mut released_mappings = ReleasedMappings::default();
2947 let result =
2948 state.force_write_memory(&self.mapping_context, addr, bytes, &mut released_mappings);
2949 released_mappings.finalize(state);
2950 result
2951 }
2952
2953 pub fn syscall_write_memory(&self, addr: UserAddress, bytes: &[u8]) -> Result<usize, Errno> {
2954 self.state.read().write_memory(addr, bytes, &self.mapping_context)
2955 }
2956
2957 pub fn unified_write_memory_partial(
2958 &self,
2959 current_task: &CurrentTask,
2960 addr: UserAddress,
2961 bytes: &[u8],
2962 ) -> Result<usize, Errno> {
2963 debug_assert!(self.has_same_address_space(¤t_task.mm().unwrap()));
2964
2965 let len = bytes.len();
2966 let copied = self.unified_transfer_loop(addr, len, |cur_addr, offset| {
2967 Ok(ControlFlow::Continue(usercopy().copyout(&bytes[offset..], cur_addr.ptr())))
2968 })?;
2969 if copied == 0 && !bytes.is_empty() { error!(EFAULT) } else { Ok(copied) }
2970 }
2971
2972 pub fn syscall_write_memory_partial(
2973 &self,
2974 addr: UserAddress,
2975 bytes: &[u8],
2976 ) -> Result<usize, Errno> {
2977 self.state.read().write_memory_partial(addr, bytes, &self.mapping_context)
2978 }
2979
2980 pub fn unified_zero(
2981 &self,
2982 current_task: &CurrentTask,
2983 addr: UserAddress,
2984 length: usize,
2985 ) -> Result<usize, Errno> {
2986 debug_assert!(self.has_same_address_space(¤t_task.mm().unwrap()));
2987
2988 {
2989 let page_size = *PAGE_SIZE as usize;
2990 let next_page_boundary = round_up_to_system_page_size(addr.ptr())?;
2993 let length_with_atleast_one_full_page = page_size + (next_page_boundary - addr.ptr());
2996 if length >= length_with_atleast_one_full_page {
3003 return self.syscall_zero(addr, length);
3004 }
3005 }
3006
3007 let copied = self.unified_transfer_loop(addr, length, |cur_addr, offset| {
3008 Ok(ControlFlow::Continue(usercopy().zero(cur_addr.ptr(), length - offset)))
3009 })?;
3010 if copied == 0 && length > 0 { error!(EFAULT) } else { Ok(copied) }
3011 }
3012
3013 pub fn syscall_zero(&self, addr: UserAddress, length: usize) -> Result<usize, Errno> {
3014 self.state.read().zero(addr, length, &self.mapping_context)
3015 }
3016
3017 pub fn cache_flush(&self, range: Range<UserAddress>) -> Result<(), Errno> {
3019 self.state.read().cache_flush(range, &self.mapping_context)
3020 }
3021
3022 pub fn register_membarrier_private_expedited(
3025 &self,
3026 mtype: MembarrierType,
3027 ) -> Result<(), Errno> {
3028 self.state.write().register_membarrier_private_expedited(mtype)
3029 }
3030
3031 pub fn membarrier_private_expedited_registered(&self, mtype: MembarrierType) -> bool {
3034 self.state.read().membarrier_private_expedited_registered(mtype)
3035 }
3036}
3037
3038pub struct MappingContext {
3048 pub user_vmar: zx::Vmar,
3058
3059 pub user_vmar_info: zx::VmarInfo,
3061
3062 pub private_anonymous: PrivateAnonymousMemoryManager,
3064}
3065
3066impl MappingContext {
3067 fn map_in_user_vmar(
3068 &self,
3069 addr: SelectedAddress,
3070 memory: &MemoryObject,
3071 memory_offset: u64,
3072 length: usize,
3073 flags: MappingFlags,
3074 populate: bool,
3075 ) -> Result<(), Errno> {
3076 map_in_vmar(
3077 &self.user_vmar,
3078 &self.user_vmar_info,
3079 addr,
3080 memory,
3081 memory_offset,
3082 length,
3083 flags,
3084 populate,
3085 )
3086 }
3087
3088 pub fn max_address(&self) -> UserAddress {
3089 UserAddress::from_ptr(self.user_vmar_info.base + self.user_vmar_info.len)
3090 }
3091}
3092
3093pub struct MemoryManager {
3094 pub base_addr: UserAddress,
3096
3097 pub futex: Arc<FutexTable<PrivateFutexKey>>,
3099
3100 pub mapping_context: MappingContext,
3102
3103 pub state: RwLock<MemoryManagerState>,
3105
3106 pub dumpable: LockDepMutex<DumpPolicy, MmDumpable>,
3108
3109 pub maximum_valid_user_address: UserAddress,
3111
3112 pub inflight_vmspliced_payloads: InflightVmsplicedPayloads,
3121
3122 pub drop_notifier: DropNotifier,
3124
3125 pub arch_width: ArchWidth,
3127
3128 pub cached_stats: Mutex<Option<(zx::MonotonicInstant, MemoryStats)>>,
3130}
3131
3132impl ArchSpecific for MemoryManager {
3133 fn is_arch32(&self) -> bool {
3134 self.arch_width.is_arch32()
3135 }
3136}
3137
3138fn check_access_permissions_in_page_fault(
3139 decoded: &PageFaultExceptionReport,
3140 mapping: &Mapping,
3141) -> bool {
3142 let exec_denied = decoded.is_execute && !mapping.can_exec();
3143 let write_denied = decoded.is_write && !mapping.can_write();
3144 let read_denied = (!decoded.is_execute && !decoded.is_write) && !mapping.can_read();
3145 !exec_denied && !write_denied && !read_denied
3146}
3147
3148impl MemoryManager {
3149 pub fn new_for_test(root_vmar: zx::Unowned<'_, zx::Vmar>, arch_width: ArchWidth) -> Arc<Self> {
3151 Self::new(root_vmar, arch_width, None, None).expect("can create MemoryManager")
3152 }
3153
3154 fn with_zx_mappings<R>(
3157 &self,
3158 current_task: &CurrentTask,
3159 op: impl FnOnce(&[zx::MapInfo]) -> R,
3160 ) -> R {
3161 MapInfoCache::get_or_init(current_task)
3162 .expect("must be able to retrieve map info cache")
3163 .with_map_infos(&self.mapping_context.user_vmar, |infos| match infos {
3164 Ok(infos) => op(infos),
3165 Err(_) => op(&[]),
3166 })
3167 }
3168
3169 fn protect_vmar_range(
3170 &self,
3171 addr: UserAddress,
3172 length: usize,
3173 prot_flags: ProtectionFlags,
3174 ) -> Result<(), Errno> {
3175 let vmar_flags = prot_flags.to_vmar_flags();
3176 unsafe { self.mapping_context.user_vmar.protect(addr.ptr(), length, vmar_flags) }.map_err(
3178 |s| match s {
3179 zx::Status::INVALID_ARGS => errno!(EINVAL),
3180 zx::Status::NOT_FOUND => errno!(ENOMEM),
3181 zx::Status::ACCESS_DENIED => errno!(EACCES),
3182 _ => impossible_error(s),
3183 },
3184 )
3185 }
3186
3187 pub fn total_locked_bytes(&self) -> u64 {
3188 self.state.read().num_locked_bytes(
3189 UserAddress::from(self.mapping_context.user_vmar_info.base as u64)
3190 ..UserAddress::from(
3191 (self.mapping_context.user_vmar_info.base
3192 + self.mapping_context.user_vmar_info.len) as u64,
3193 ),
3194 )
3195 }
3196
3197 fn new(
3201 root_vmar: zx::Unowned<'_, zx::Vmar>,
3202 arch_width: ArchWidth,
3203 executable_node: Option<NamespaceNode>,
3204 private_anonymous: Option<PrivateAnonymousMemoryManager>,
3205 ) -> Result<Arc<Self>, Errno> {
3206 debug_assert!(!root_vmar.is_invalid());
3207
3208 let mut vmar_info = root_vmar.info().map_err(|status| from_status_like_fdio!(status))?;
3209 if arch_width.is_arch32() {
3210 vmar_info.len = (LOWER_4GB_LIMIT.ptr() - vmar_info.base) as usize;
3211 }
3212
3213 let (user_vmar, ptr) = root_vmar
3214 .allocate(
3215 0,
3216 vmar_info.len,
3217 zx::VmarFlags::SPECIFIC
3218 | zx::VmarFlags::CAN_MAP_SPECIFIC
3219 | zx::VmarFlags::CAN_MAP_READ
3220 | zx::VmarFlags::CAN_MAP_WRITE
3221 | zx::VmarFlags::CAN_MAP_EXECUTE,
3222 )
3223 .map_err(|status| from_status_like_fdio!(status))?;
3224 assert_eq!(ptr, vmar_info.base);
3225
3226 let user_vmar_info = user_vmar.info().map_err(|status| from_status_like_fdio!(status))?;
3227
3228 debug_assert_eq!(RESTRICTED_ASPACE_BASE, user_vmar_info.base);
3230 if arch_width.is_arch32() {
3231 debug_assert_eq!(LOWER_4GB_LIMIT.ptr() - user_vmar_info.base, user_vmar_info.len);
3232 } else {
3233 debug_assert_eq!(RESTRICTED_ASPACE_SIZE, user_vmar_info.len);
3234 }
3235
3236 let backing_size = (user_vmar_info.base + user_vmar_info.len) as u64;
3241
3242 let stack_origin = UserAddress::from_ptr(
3245 user_vmar_info.base + user_vmar_info.len - generate_random_offset_for_aslr(arch_width),
3246 )
3247 .round_up(*PAGE_SIZE)?;
3248
3249 let mmap_top = stack_origin
3252 .checked_sub(MAX_STACK_SIZE + generate_random_offset_for_aslr(arch_width))
3253 .ok_or_else(|| errno!(EINVAL))?;
3254
3255 Ok(Arc::new(MemoryManager {
3256 base_addr: UserAddress::from_ptr(user_vmar_info.base),
3257 futex: Arc::<FutexTable<PrivateFutexKey>>::default(),
3258 mapping_context: MappingContext {
3259 user_vmar,
3260 user_vmar_info,
3261 private_anonymous: private_anonymous
3262 .unwrap_or_else(|| PrivateAnonymousMemoryManager::new(backing_size)),
3263 },
3264 state: MemoryManagerState {
3265 mappings: Default::default(),
3266 userfaultfds: Default::default(),
3267 shadow_mappings_for_mlock: Default::default(),
3268 forkable_state: MemoryManagerForkableState {
3269 executable_node,
3270 stack_origin,
3271 mmap_top,
3272 ..Default::default()
3273 },
3274 }
3275 .into(),
3276 dumpable: LockDepMutex::new(DumpPolicy::User),
3279 maximum_valid_user_address: UserAddress::from_ptr(
3280 user_vmar_info.base + user_vmar_info.len,
3281 ),
3282 inflight_vmspliced_payloads: Default::default(),
3283 drop_notifier: DropNotifier::default(),
3284 arch_width,
3285 cached_stats: Mutex::default(),
3286 }))
3287 }
3288
3289 pub fn set_brk(
3290 self: &Arc<Self>,
3291 current_task: &CurrentTask,
3292 addr: UserAddress,
3293 ) -> Result<UserAddress, Errno> {
3294 let mut state = self.state.write();
3295 let mut released_mappings = ReleasedMappings::default();
3296 let result = state.set_brk(current_task, self, addr, &mut released_mappings);
3297 released_mappings.finalize(state);
3298 result
3299 }
3300
3301 pub fn register_uffd(&self, userfault: &Arc<UserFault>) {
3302 let mut state = self.state.write();
3303 state.userfaultfds.push(Arc::downgrade(userfault));
3304 }
3305
3306 pub fn register_with_uffd(
3308 self: &Arc<Self>,
3309 addr: UserAddress,
3310 length: usize,
3311 userfault: &Arc<UserFault>,
3312 mode: FaultRegisterMode,
3313 ) -> Result<(), Errno> {
3314 let mut state = self.state.write();
3315 let mut released_mappings = ReleasedMappings::default();
3316 let result =
3317 state.register_with_uffd(self, addr, length, userfault, mode, &mut released_mappings);
3318 released_mappings.finalize(state);
3319 result
3320 }
3321
3322 pub fn unregister_range_from_uffd(
3324 &self,
3325 userfault: &Arc<UserFault>,
3326 addr: UserAddress,
3327 length: usize,
3328 ) -> Result<(), Errno> {
3329 let mut state = self.state.write();
3330 let mut released_mappings = ReleasedMappings::default();
3331 let result =
3332 state.unregister_range_from_uffd(self, userfault, addr, length, &mut released_mappings);
3333 released_mappings.finalize(state);
3334 result
3335 }
3336
3337 pub fn unregister_uffd(&self, userfault: &Arc<UserFault>) {
3340 let mut state = self.state.write();
3341 let mut released_mappings = ReleasedMappings::default();
3342 state.unregister_uffd(self, userfault, &mut released_mappings);
3343 released_mappings.finalize(state);
3344 }
3345
3346 pub fn populate_from_uffd<F>(
3352 &self,
3353 addr: UserAddress,
3354 length: usize,
3355 userfault: &Arc<UserFault>,
3356 populate: F,
3357 ) -> Result<usize, Errno>
3358 where
3359 F: FnOnce(&MemoryManagerState, usize) -> Result<usize, Errno>,
3360 {
3361 let state = self.state.read();
3362 let mut bytes_registered_with_uffd = 0;
3365 for (mapping, len) in
3366 state.get_contiguous_mappings_at(addr, length, &self.mapping_context)?
3367 {
3368 if mapping.flags().contains(MappingFlags::UFFD) {
3369 if !userfault.contains_addr(addr) {
3372 track_stub!(
3373 TODO("https://fxbug.dev/391599171"),
3374 "operations across different uffds"
3375 );
3376 return error!(ENOTSUP);
3377 };
3378 } else {
3379 return error!(ENOENT);
3380 }
3381 bytes_registered_with_uffd += len;
3382 }
3383 if bytes_registered_with_uffd != length {
3384 return error!(ENOENT);
3385 }
3386
3387 let end_addr = addr.checked_add(length).ok_or_else(|| errno!(EINVAL))?;
3388
3389 let first_populated =
3391 userfault.get_first_populated_page_after(addr).ok_or_else(|| errno!(ENOENT))?;
3392 if first_populated == addr {
3394 return error!(EEXIST);
3395 }
3396 let trimmed_end = std::cmp::min(first_populated, end_addr);
3399 let effective_length = trimmed_end - addr;
3400
3401 populate(&state, effective_length)?;
3402 userfault.insert_pages(addr..trimmed_end, true);
3403
3404 for (range, mapping) in state.mappings.range(addr..trimmed_end) {
3409 let range_to_protect = range.intersect(&(addr..trimmed_end));
3410 let restored_flags = mapping.flags().access_flags();
3411 let length = range_to_protect.end - range_to_protect.start;
3412 self.protect_vmar_range(range_to_protect.start, length, restored_flags)
3413 .expect("Failed to restore original protection bits on uffd-registered range");
3414 }
3415 Ok(effective_length)
3418 }
3419
3420 pub fn zero_from_uffd(
3421 &self,
3422 addr: UserAddress,
3423 length: usize,
3424 userfault: &Arc<UserFault>,
3425 ) -> Result<usize, Errno> {
3426 self.populate_from_uffd(addr, length, userfault, |state, effective_length| {
3427 state.zero(addr, effective_length, &self.mapping_context)
3428 })
3429 }
3430
3431 pub fn fill_from_uffd(
3432 &self,
3433 addr: UserAddress,
3434 buf: &[u8],
3435 length: usize,
3436 userfault: &Arc<UserFault>,
3437 ) -> Result<usize, Errno> {
3438 self.populate_from_uffd(addr, length, userfault, |state, effective_length| {
3439 state.write_memory(addr, &buf[..effective_length], &self.mapping_context)
3440 })
3441 }
3442
3443 pub fn copy_from_uffd(
3444 &self,
3445 source_addr: UserAddress,
3446 dst_addr: UserAddress,
3447 length: usize,
3448 userfault: &Arc<UserFault>,
3449 ) -> Result<usize, Errno> {
3450 self.populate_from_uffd(dst_addr, length, userfault, |state, effective_length| {
3451 let mut buf = vec![std::mem::MaybeUninit::uninit(); effective_length];
3452 let buf = state.read_memory(source_addr, &mut buf, &self.mapping_context)?;
3453 state.write_memory(dst_addr, &buf[..effective_length], &self.mapping_context)
3454 })
3455 }
3456
3457 pub fn snapshot_of(
3461 source_mm: &Arc<MemoryManager>,
3462 root_vmar: zx::Unowned<'_, zx::Vmar>,
3463 arch_width: ArchWidth,
3464 ) -> Result<Arc<Self>, Errno> {
3465 fuchsia_trace::duration!(CATEGORY_STARNIX_MM, "snapshot_of");
3466 let backing_size = (source_mm.mapping_context.user_vmar_info.base
3467 + source_mm.mapping_context.user_vmar_info.len) as u64;
3468 let private_anonymous =
3469 source_mm.mapping_context.private_anonymous.snapshot(backing_size)?;
3470 let target = MemoryManager::new(
3471 root_vmar,
3472 arch_width,
3473 source_mm.executable_node(),
3474 Some(private_anonymous),
3475 )?;
3476
3477 {
3480 let (state, mut target_state) = ordered_write_lock(&source_mm.state, &target.state);
3481 debug_assert_eq!(
3482 source_mm.mapping_context.user_vmar_info,
3483 target.mapping_context.user_vmar_info
3484 );
3485
3486 let mut clone_cache = HashMap::<zx::Koid, Arc<MemoryObject>>::new();
3487
3488 for (range, mapping) in state.mappings.iter() {
3489 if mapping.flags().contains(MappingFlags::DONTFORK) {
3490 continue;
3491 }
3492 let target_mapping_flags = mapping.flags().difference(MappingFlags::LOCKED);
3494 match state.get_mapping_backing(mapping) {
3495 MappingBacking::Memory(backing) => {
3496 fuchsia_trace::duration!(CATEGORY_STARNIX_MM, "memory_backing_clone");
3497 let memory_offset = backing.address_to_offset(range.start);
3498
3499 let target_memory = if mapping.flags().contains(MappingFlags::SHARED)
3500 || mapping.name().is_vvar()
3501 {
3502 backing.memory().clone()
3505 } else {
3506 let memory_obj = backing.memory();
3507 let options = mapping.flags().options();
3508 let mut rights = memory_obj.get_rights();
3509 if mapping.flags().contains(MappingFlags::WRITE) {
3510 rights |= zx::Rights::WRITE;
3511 }
3512 let memory =
3513 clone_cache.entry(memory_obj.get_koid()).or_insert_with_fallible(
3514 || memory_obj.clone_memory(rights, options),
3515 )?;
3516 memory.clone()
3517 };
3518
3519 let mapping = Mapping::with_name(
3520 MappingBacking::Memory(Box::new(MappingBackingMemory::new(
3521 range.start,
3522 target_memory,
3523 memory_offset,
3524 ))),
3525 target_mapping_flags,
3526 mapping.name().to_owned(),
3527 MappingMode::Lazy,
3528 );
3529 assert!(
3530 target_state.mappings.append_non_overlapping(range.clone(), mapping)
3531 );
3532 }
3533 MappingBacking::PrivateAnonymous => {
3534 fuchsia_trace::duration!(
3535 CATEGORY_STARNIX_MM,
3536 "private_anonymous_backing_clone"
3537 );
3538 let length = range.end - range.start;
3539 if mapping.flags().contains(MappingFlags::WIPEONFORK) {
3540 target
3541 .mapping_context
3542 .private_anonymous
3543 .zero(range.start, length)
3544 .map_err(|_| errno!(ENOMEM))?;
3545 }
3546
3547 let mapping = Mapping::new_private_anonymous(
3548 target_mapping_flags,
3549 mapping.name().to_owned(),
3550 MappingMode::Lazy,
3551 );
3552 assert!(
3553 target_state.mappings.append_non_overlapping(range.clone(), mapping)
3554 );
3555 }
3556 };
3557 }
3558
3559 target_state.forkable_state = state.forkable_state.clone();
3560 }
3561
3562 let self_dumpable = *source_mm.dumpable.lock();
3563 *target.dumpable.lock() = self_dumpable;
3564
3565 Ok(target)
3566 }
3567
3568 pub fn exec(
3577 root_vmar: zx::Unowned<'_, zx::Vmar>,
3578 old_mm: Option<Arc<Self>>,
3579 exe_node: NamespaceNode,
3580 arch_width: ArchWidth,
3581 ) -> Result<Arc<Self>, Errno> {
3582 if let Some(old_mm) = old_mm {
3590 let _old_mappings = {
3591 let mut state = old_mm.state.write();
3592
3593 unsafe {
3596 old_mm
3597 .mapping_context
3598 .user_vmar
3599 .destroy()
3600 .map_err(|status| from_status_like_fdio!(status))?
3601 }
3602
3603 std::mem::replace(&mut state.mappings, Default::default())
3604 };
3605 }
3606
3607 Self::new(root_vmar, arch_width, Some(exe_node), None)
3608 }
3609
3610 pub fn initialize_brk_origin(
3611 &self,
3612 arch_width: ArchWidth,
3613 executable_end: UserAddress,
3614 ) -> Result<(), Errno> {
3615 self.state.write().brk_origin = executable_end
3616 .checked_add(generate_random_offset_for_aslr(arch_width))
3617 .ok_or_else(|| errno!(EINVAL))?;
3618 Ok(())
3619 }
3620
3621 pub fn get_random_base_for_executable(
3623 &self,
3624 arch_width: ArchWidth,
3625 length: usize,
3626 ) -> Result<UserAddress, Errno> {
3627 let state = self.state.read();
3628
3629 let base = round_up_to_system_page_size(2 * state.mmap_top.ptr() / 3).unwrap()
3631 + generate_random_offset_for_aslr(arch_width);
3632 if base.checked_add(length).ok_or_else(|| errno!(EINVAL))? <= state.mmap_top.ptr() {
3633 Ok(UserAddress::from_ptr(base))
3634 } else {
3635 error!(EINVAL)
3636 }
3637 }
3638 pub fn executable_node(&self) -> Option<NamespaceNode> {
3639 self.state.read().executable_node.clone()
3640 }
3641
3642 #[track_caller]
3643 pub fn get_errno_for_map_err(status: zx::Status) -> Errno {
3644 match status {
3645 zx::Status::INVALID_ARGS => errno!(EINVAL),
3646 zx::Status::ACCESS_DENIED => errno!(EPERM),
3647 zx::Status::NOT_SUPPORTED => errno!(ENODEV),
3648 zx::Status::NO_MEMORY => errno!(ENOMEM),
3649 zx::Status::NO_RESOURCES => errno!(ENOMEM),
3650 zx::Status::OUT_OF_RANGE => errno!(ENOMEM),
3651 zx::Status::ALREADY_EXISTS => errno!(EEXIST),
3652 zx::Status::BAD_STATE => errno!(EINVAL),
3653 _ => impossible_error(status),
3654 }
3655 }
3656
3657 #[track_caller]
3658 pub fn get_errno_for_vmo_err(status: zx::Status) -> Errno {
3659 match status {
3660 zx::Status::NO_MEMORY => errno!(ENOMEM),
3661 zx::Status::ACCESS_DENIED => errno!(EPERM),
3662 zx::Status::NOT_SUPPORTED => errno!(EIO),
3663 zx::Status::BAD_STATE => errno!(EIO),
3664 _ => return impossible_error(status),
3665 }
3666 }
3667
3668 pub fn map_memory(
3669 self: &Arc<Self>,
3670 addr: DesiredAddress,
3671 memory: Arc<MemoryObject>,
3672 memory_offset: u64,
3673 length: usize,
3674 prot_flags: ProtectionFlags,
3675 options: MappingOptions,
3676 name: MappingName,
3677 ) -> Result<UserAddress, Errno> {
3678 let flags = MappingFlags::from_access_flags_and_options(prot_flags, options);
3679
3680 let mut released_mappings = ReleasedMappings::default();
3682 let mut state = self.state.write();
3685 let result = state.add_memory_mapping(
3686 self,
3687 addr,
3688 memory,
3689 memory_offset,
3690 length,
3691 flags,
3692 options.contains(MappingOptions::POPULATE),
3693 name,
3694 MappingMode::Eager,
3695 &mut released_mappings,
3696 );
3697
3698 released_mappings.finalize(state);
3701
3702 result
3703 }
3704
3705 pub fn map_anonymous(
3706 self: &Arc<Self>,
3707 addr: DesiredAddress,
3708 length: usize,
3709 prot_flags: ProtectionFlags,
3710 options: MappingOptions,
3711 name: MappingName,
3712 ) -> Result<UserAddress, Errno> {
3713 let mut released_mappings = ReleasedMappings::default();
3714 let mut state = self.state.write();
3717 let result = state.map_anonymous(
3718 self,
3719 addr,
3720 length,
3721 prot_flags,
3722 options,
3723 name,
3724 &mut released_mappings,
3725 );
3726
3727 released_mappings.finalize(state);
3728
3729 result
3730 }
3731
3732 pub fn map_stack(
3734 self: &Arc<Self>,
3735 length: usize,
3736 prot_flags: ProtectionFlags,
3737 ) -> Result<UserAddress, Errno> {
3738 assert!(length <= MAX_STACK_SIZE);
3739 let addr = (self.state.read().stack_origin - length)?;
3740 let stack_addr = self.map_anonymous(
3747 DesiredAddress::Hint(addr),
3748 length,
3749 prot_flags,
3750 MappingOptions::ANONYMOUS | MappingOptions::GROWSDOWN,
3751 MappingName::Stack,
3752 )?;
3753 if stack_addr != addr {
3754 log_warn!(
3755 "An address designated for stack ({}) was unavailable, mapping at {} instead.",
3756 addr,
3757 stack_addr
3758 );
3759 }
3760 Ok(stack_addr)
3761 }
3762
3763 pub fn remap(
3764 self: &Arc<Self>,
3765 current_task: &CurrentTask,
3766 addr: UserAddress,
3767 old_length: usize,
3768 new_length: usize,
3769 flags: MremapFlags,
3770 new_addr: UserAddress,
3771 ) -> Result<UserAddress, Errno> {
3772 let mut released_mappings = ReleasedMappings::default();
3773 let mut state = self.state.write();
3776 let result = state.remap(
3777 current_task,
3778 self,
3779 addr,
3780 old_length,
3781 new_length,
3782 flags,
3783 new_addr,
3784 &mut released_mappings,
3785 );
3786
3787 released_mappings.finalize(state);
3788
3789 result
3790 }
3791
3792 pub fn unmap(self: &Arc<Self>, addr: UserAddress, length: usize) -> Result<(), Errno> {
3793 let mut released_mappings = ReleasedMappings::default();
3794 let mut state = self.state.write();
3797 let result = state.unmap(self, addr, length, &mut released_mappings);
3798
3799 released_mappings.finalize(state);
3800
3801 result
3802 }
3803
3804 pub fn protect(
3805 &self,
3806 current_task: &CurrentTask,
3807 addr: UserAddress,
3808 length: usize,
3809 prot_flags: ProtectionFlags,
3810 ) -> Result<(), Errno> {
3811 let page_size = *PAGE_SIZE;
3812 if !addr.is_aligned(page_size) {
3813 return error!(EINVAL);
3814 }
3815 if length == 0 {
3816 return Ok(());
3817 }
3818 let end = addr.checked_add(length).ok_or_else(|| errno!(ENOMEM))?.round_up(page_size)?;
3819 if end > self.maximum_valid_user_address {
3820 return error!(ENOMEM);
3821 }
3822
3823 let mut state = self.state.write();
3826 let mut released_mappings = ReleasedMappings::default();
3827 let result = state.protect(current_task, addr, length, prot_flags, &mut released_mappings);
3828 released_mappings.finalize(state);
3829 result
3830 }
3831
3832 pub fn msync(
3833 &self,
3834 current_task: &CurrentTask,
3835 addr: UserAddress,
3836 length: usize,
3837 flags: MsyncFlags,
3838 ) -> Result<(), Errno> {
3839 if flags.contains(MsyncFlags::ASYNC) && flags.contains(MsyncFlags::SYNC) {
3847 return error!(EINVAL);
3848 }
3849
3850 if !addr.is_aligned(*PAGE_SIZE) {
3851 return error!(EINVAL);
3852 }
3853
3854 let mut nodes_to_sync = {
3859 let mm_state = self.state.read();
3860
3861 let length_rounded = round_up_to_system_page_size(length)?;
3862 let end_addr = addr.checked_add(length_rounded).ok_or_else(|| errno!(EINVAL))?;
3863
3864 let mut last_end = addr;
3865 let mut nodes = vec![];
3866 for (range, mapping) in mm_state.mappings.range(addr..end_addr) {
3867 if range.start > last_end {
3870 return error!(ENOMEM);
3871 }
3872 last_end = range.end;
3873
3874 if flags.contains(MsyncFlags::INVALIDATE)
3875 && mapping.flags().contains(MappingFlags::LOCKED)
3876 {
3877 return error!(EBUSY);
3878 }
3879
3880 if flags.contains(MsyncFlags::SYNC) {
3881 if let MappingNameRef::File(file_mapping) = mapping.name() {
3882 nodes.push(file_mapping.node().clone());
3883 }
3884 }
3885 }
3886 if last_end < end_addr {
3887 return error!(ENOMEM);
3888 }
3889 nodes
3890 };
3891
3892 nodes_to_sync.sort_by_key(|n| Arc::as_ptr(n) as usize);
3894 nodes_to_sync.dedup_by(|a, b| Arc::ptr_eq(a, b));
3895
3896 for node in nodes_to_sync {
3897 node.ops().sync(&node, current_task)?;
3903 }
3904 Ok(())
3905 }
3906
3907 pub fn madvise(&self, addr: UserAddress, length: usize, advice: u32) -> Result<(), Errno> {
3908 let mut state = self.state.write();
3909 let mut released_mappings = ReleasedMappings::default();
3910 let result =
3911 state.madvise(&self.mapping_context, addr, length, advice, &mut released_mappings);
3912 released_mappings.finalize(state);
3913 result
3914 }
3915
3916 pub fn mlock(
3917 &self,
3918 current_task: &CurrentTask,
3919 desired_addr: UserAddress,
3920 desired_length: usize,
3921 on_fault: bool,
3922 ) -> Result<(), Errno> {
3923 let mut state = self.state.write();
3924 let mut released_mappings = ReleasedMappings::default();
3925 let result = state.mlock(
3926 &self.mapping_context,
3927 current_task,
3928 desired_addr,
3929 desired_length,
3930 on_fault,
3931 &mut released_mappings,
3932 );
3933 released_mappings.finalize(state);
3934 result
3935 }
3936
3937 pub fn munlock(
3938 &self,
3939 current_task: &CurrentTask,
3940 desired_addr: UserAddress,
3941 desired_length: usize,
3942 ) -> Result<(), Errno> {
3943 let mut state = self.state.write();
3944 let mut released_mappings = ReleasedMappings::default();
3945 let result =
3946 state.munlock(current_task, desired_addr, desired_length, &mut released_mappings);
3947 released_mappings.finalize(state);
3948 result
3949 }
3950
3951 pub fn log_memory_map(&self, task: &Task, fault_address: UserAddress) {
3952 let state = self.state.read();
3953 log_warn!("Memory map for pid={}:", task.pid);
3954 let mut last_end = UserAddress::from_ptr(0);
3955 for (range, map) in state.mappings.iter() {
3956 if fault_address >= last_end && fault_address < range.start {
3957 log_warn!("{:08x} <= FAULT", fault_address.ptr());
3958 }
3959
3960 let perms = format!(
3961 "{}{}{}{}",
3962 if map.can_read() { 'r' } else { '-' },
3963 if map.can_write() { 'w' } else { '-' },
3964 if map.can_exec() { 'x' } else { '-' },
3965 if map.flags().contains(MappingFlags::SHARED) { 's' } else { 'p' }
3966 );
3967
3968 let backing = match state.get_mapping_backing(map) {
3969 MappingBacking::Memory(backing) => backing.address_to_offset(range.start),
3970 MappingBacking::PrivateAnonymous => 0,
3971 };
3972
3973 let name_str = match &map.name() {
3974 MappingNameRef::File(file) => {
3975 let Ok(running_state) = task.running_state() else {
3976 log_warn!("Task {} is not running", task.get_tid());
3977 continue;
3978 };
3979 String::from_utf8_lossy(&file.name().path(&running_state.fs())).into_owned()
3980 }
3981 MappingNameRef::None | MappingNameRef::AioContext(_) => {
3982 if map.flags().contains(MappingFlags::SHARED)
3983 && map.flags().contains(MappingFlags::ANONYMOUS)
3984 {
3985 "/dev/zero (deleted)".to_string()
3986 } else {
3987 "".to_string()
3988 }
3989 }
3990 MappingNameRef::Stack => "[stack]".to_string(),
3991 MappingNameRef::Heap => "[heap]".to_string(),
3992 MappingNameRef::Vdso => "[vdso]".to_string(),
3993 MappingNameRef::Vvar => "[vvar]".to_string(),
3994 _ => format!("{:?}", map.name()),
3995 };
3996
3997 let fault_marker = if range.contains(&fault_address) { " <= FAULT" } else { "" };
3998
3999 log_warn!(
4000 "{:08x}-{:08x} {} {:08x} {}{}",
4001 range.start.ptr(),
4002 range.end.ptr(),
4003 perms,
4004 backing,
4005 name_str,
4006 fault_marker
4007 );
4008 last_end = range.end;
4009 }
4010
4011 if fault_address >= last_end {
4012 log_warn!("{:08x} <= FAULT", fault_address.ptr());
4013 }
4014 }
4015
4016 pub fn handle_page_fault(
4017 self: &Arc<Self>,
4018 decoded: PageFaultExceptionReport,
4019 error_code: zx::Status,
4020 ) -> ExceptionResult {
4021 #[cfg(target_arch = "aarch64")]
4022 let addr = if self.is_arch64() {
4025 UserAddress::from(decoded.faulting_address & 0x00FF_FFFF_FFFF_FFFF)
4026 } else {
4027 UserAddress::from(decoded.faulting_address)
4028 };
4029 #[cfg(not(target_arch = "aarch64"))]
4030 let addr = UserAddress::from(decoded.faulting_address);
4031
4032 if error_code == zx::Status::ACCESS_DENIED {
4034 let state = self.state.write();
4035 if let Some((_, mapping)) = state.mappings.get(addr) {
4036 if mapping.flags().contains(MappingFlags::UFFD) {
4037 assert!(mapping.flags().contains(MappingFlags::UFFD_MISSING));
4039
4040 if let Some(_uffd) = state.find_uffd(addr) {
4041 return ExceptionResult::Signal(SignalInfo::with_detail(
4047 SIGBUS,
4048 BUS_ADRERR as i32,
4049 SignalDetail::SigFault { addr: decoded.faulting_address },
4050 ));
4051 };
4052 }
4053 if check_access_permissions_in_page_fault(&decoded, mapping) {
4057 track_stub!(
4058 TODO("https://fxbug.dev/435171399"),
4059 "Inconsistent permission fault"
4060 );
4061 return ExceptionResult::Handled;
4062 }
4063 }
4064 std::mem::drop(state);
4065 }
4066
4067 if decoded.not_present {
4068 {
4069 let mut state = self.state.write();
4070 match state.ensure_range_mapped_in_user_vmar(addr, None, &self.mapping_context) {
4071 Ok(true) => return ExceptionResult::Handled,
4072 Ok(false) => {
4073 let current_gen = state.mappings.generation;
4079 let old_gen = LAST_SEEN_MAPPING_GENERATION.with(|c| c.replace(current_gen));
4080 if current_gen != old_gen {
4081 return ExceptionResult::Handled;
4082 }
4083 }
4084 Err(e) => {
4085 log_error!("Failed to map lazy memory: {e}")
4086 }
4087 }
4088 }
4089
4090 match self.extend_growsdown_mapping_to_address(
4096 UserAddress::from(decoded.faulting_address),
4097 decoded.is_write,
4098 ) {
4099 Ok(true) => {
4100 return ExceptionResult::Handled;
4101 }
4102 Err(e) => {
4103 log_warn!("Error handling page fault: {e}")
4104 }
4105 _ => {}
4106 }
4107 }
4108
4109 let (signo, si_code) = match error_code {
4117 zx::Status::OUT_OF_RANGE => (SIGBUS, linux_uapi::BUS_ADRERR as i32),
4118 _ => {
4119 let code = if self.state.read().mappings.get(addr).is_some() {
4120 linux_uapi::SEGV_ACCERR
4121 } else {
4122 linux_uapi::SEGV_MAPERR
4123 };
4124 (SIGSEGV, code as i32)
4125 }
4126 };
4127 ExceptionResult::Signal(SignalInfo::with_detail(
4128 signo,
4129 si_code,
4130 SignalDetail::SigFault { addr: decoded.faulting_address },
4131 ))
4132 }
4133
4134 pub fn set_mapping_name(
4135 &self,
4136 addr: UserAddress,
4137 length: usize,
4138 name: Option<FsString>,
4139 ) -> Result<(), Errno> {
4140 let mut state = self.state.write();
4141 let mut released_mappings = ReleasedMappings::default();
4142 let result = state.set_mapping_name(addr, length, name, &mut released_mappings);
4143 released_mappings.finalize(state);
4144 result
4145 }
4146
4147 pub fn ensure_mapped(&self, addr: UserAddress, length: usize) -> Result<(), Errno> {
4157 if !addr.is_aligned(*PAGE_SIZE) {
4158 return error!(EINVAL);
4159 }
4160
4161 let length = round_up_to_system_page_size(length)?;
4162 let end_addr = addr.checked_add(length).ok_or_else(|| errno!(EINVAL))?;
4163 let state = self.state.read();
4164 let mut last_end = addr;
4165 for (range, _) in state.mappings.range(addr..end_addr) {
4166 if range.start > last_end {
4167 return error!(ENOMEM);
4169 }
4170 last_end = range.end;
4171 }
4172 if last_end < end_addr {
4173 error!(ENOMEM)
4175 } else {
4176 Ok(())
4177 }
4178 }
4179
4180 pub fn get_mapping_memory(
4183 &self,
4184 addr: UserAddress,
4185 perms: ProtectionFlags,
4186 ) -> Result<(Arc<MemoryObject>, u64), Errno> {
4187 let state = self.state.read();
4188 let (_, mapping) = state.mappings.get(addr).ok_or_else(|| errno!(EFAULT))?;
4189 if !mapping.flags().access_flags().contains(perms) {
4190 return error!(EACCES);
4191 }
4192 match state.get_mapping_backing(mapping) {
4193 MappingBacking::Memory(backing) => {
4194 Ok((Arc::clone(backing.memory()), mapping.address_to_offset(addr)))
4195 }
4196 MappingBacking::PrivateAnonymous => {
4197 Ok((Arc::clone(&self.mapping_context.private_anonymous.backing), addr.ptr() as u64))
4198 }
4199 }
4200 }
4201
4202 pub fn check_plausible(&self, addr: UserAddress, buffer_size: usize) -> Result<(), Errno> {
4224 let state = self.state.read();
4225
4226 if let Some(range) = state.mappings.last_range() {
4227 if (range.end - buffer_size)? >= addr {
4228 return Ok(());
4229 }
4230 }
4231 error!(EFAULT)
4232 }
4233
4234 pub fn get_aio_context(&self, addr: UserAddress) -> Option<Arc<AioContext>> {
4235 let state = self.state.read();
4236 state.get_aio_context(addr).map(|(_, aio_context)| aio_context)
4237 }
4238
4239 pub fn destroy_aio_context(
4240 self: &Arc<Self>,
4241 addr: UserAddress,
4242 ) -> Result<Arc<AioContext>, Errno> {
4243 let mut released_mappings = ReleasedMappings::default();
4244
4245 let mut state = self.state.write();
4248
4249 let Some((range, aio_context)) = state.get_aio_context(addr) else {
4253 return error!(EINVAL);
4254 };
4255
4256 let length = range.end - range.start;
4257 let result = state.unmap(self, range.start, length, &mut released_mappings);
4258
4259 released_mappings.finalize(state);
4260
4261 result.map(|_| aio_context)
4262 }
4263
4264 #[cfg(test)]
4265 pub fn get_mapping_name(
4266 &self,
4267 addr: UserAddress,
4268 ) -> Result<Option<flyweights::FlyByteStr>, Errno> {
4269 let state = self.state.read();
4270 let (_, mapping) = state.mappings.get(addr).ok_or_else(|| errno!(EFAULT))?;
4271 if let MappingNameRef::Vma(name) = mapping.name() {
4272 Ok(Some(name.clone()))
4273 } else {
4274 Ok(None)
4275 }
4276 }
4277
4278 #[cfg(test)]
4279 pub fn get_mapping_count(&self) -> usize {
4280 let state = self.state.read();
4281 state.mappings.iter().count()
4282 }
4283
4284 pub fn extend_growsdown_mapping_to_address(
4285 self: &Arc<Self>,
4286 addr: UserAddress,
4287 is_write: bool,
4288 ) -> Result<bool, Error> {
4289 self.state.write().extend_growsdown_mapping_to_address(self, addr, is_write)
4290 }
4291
4292 pub fn get_total_usage(&self) -> usize {
4293 self.state.read().mappings.total_usage
4294 }
4295
4296 pub fn get_stats(&self, current_task: &CurrentTask) -> MemoryStats {
4297 let is_self_read =
4302 current_task.mm().map_or(false, |mm| std::ptr::eq(Arc::as_ptr(&mm), self));
4303 let now = zx::MonotonicInstant::get();
4304 if !is_self_read {
4305 const CACHE_TTL: zx::MonotonicDuration = zx::MonotonicDuration::from_millis(250);
4306 let cached = self.cached_stats.lock();
4307 if let Some((timestamp, stats)) = *cached {
4308 if now - timestamp < CACHE_TTL {
4309 return stats;
4310 }
4311 }
4312 }
4313
4314 let state = self.state.read();
4318
4319 let mut stats = MemoryStats::default();
4320 stats.vm_stack = state.stack_size;
4321
4322 self.with_zx_mappings(current_task, |zx_mappings| {
4323 for zx_mapping in zx_mappings {
4324 let zx_details = zx_mapping.details();
4326 let Some(zx_details) = zx_details.as_mapping() else { continue };
4327 let user_address = UserAddress::from(zx_mapping.base as u64);
4328 let (_, mm_mapping) = state
4329 .mappings
4330 .get(user_address)
4331 .unwrap_or_else(|| panic!("mapping bookkeeping must be consistent with zircon's: not found: {user_address:?}"));
4332 debug_assert_eq!(
4333 match state.get_mapping_backing(mm_mapping) {
4334 MappingBacking::Memory(m)=>m.memory().get_koid(),
4335 MappingBacking::PrivateAnonymous=>self.mapping_context.private_anonymous.backing.get_koid(),
4336 },
4337 zx_details.vmo_koid,
4338 "MemoryManager and Zircon must agree on which VMO is mapped in this range",
4339 );
4340
4341 stats.vm_size += zx_mapping.size;
4342
4343 stats.vm_rss += zx_details.committed_bytes;
4344 stats.vm_swap += zx_details.populated_bytes - zx_details.committed_bytes;
4345
4346 if mm_mapping.flags().contains(MappingFlags::SHARED) {
4347 stats.rss_shared += zx_details.committed_bytes;
4348 } else if mm_mapping.flags().contains(MappingFlags::ANONYMOUS) {
4349 stats.rss_anonymous += zx_details.committed_bytes;
4350 } else if mm_mapping.name().is_file() {
4351 stats.rss_file += zx_details.committed_bytes;
4352 }
4353
4354 if mm_mapping.flags().contains(MappingFlags::LOCKED) {
4355 stats.vm_lck += zx_details.committed_bytes;
4356 }
4357
4358 if mm_mapping.flags().contains(MappingFlags::ELF_BINARY)
4359 && mm_mapping.flags().contains(MappingFlags::WRITE)
4360 {
4361 stats.vm_data += zx_mapping.size;
4362 }
4363
4364 if mm_mapping.flags().contains(MappingFlags::ELF_BINARY)
4365 && mm_mapping.flags().contains(MappingFlags::EXEC)
4366 {
4367 stats.vm_exe += zx_mapping.size;
4368 }
4369 }
4370 });
4371
4372 stats.vm_rss_hwm = STUB_VM_RSS_HWM;
4375 *self.cached_stats.lock() = Some((now, stats));
4376 stats
4377 }
4378
4379 fn run_atomic_op<F, T>(&self, futex_addr: FutexAddress, mut op: F) -> Result<T, Errno>
4380 where
4381 F: FnMut(&usercopy::Usercopy) -> Result<T, ()>,
4382 {
4383 let uc = usercopy();
4384 if let Ok(val) = op(uc) {
4390 return Ok(val);
4391 }
4392 self.ensure_range_mapped_in_user_vmar(futex_addr.into(), None)?;
4393 op(uc).map_err(|_| errno!(EFAULT))
4394 }
4395
4396 pub fn atomic_load_u32_acquire(&self, futex_addr: FutexAddress) -> Result<u32, Errno> {
4397 self.run_atomic_op(futex_addr, |uc| uc.atomic_load_u32_acquire(futex_addr.ptr()))
4398 }
4399
4400 pub fn atomic_load_u32_relaxed(&self, futex_addr: FutexAddress) -> Result<u32, Errno> {
4401 self.run_atomic_op(futex_addr, |uc| uc.atomic_load_u32_relaxed(futex_addr.ptr()))
4402 }
4403
4404 pub fn atomic_store_u32_relaxed(
4405 &self,
4406 futex_addr: FutexAddress,
4407 value: u32,
4408 ) -> Result<(), Errno> {
4409 self.run_atomic_op(futex_addr, |uc| uc.atomic_store_u32_relaxed(futex_addr.ptr(), value))
4410 }
4411
4412 pub fn atomic_compare_exchange_u32_acq_rel(
4413 &self,
4414 futex_addr: FutexAddress,
4415 current: u32,
4416 new: u32,
4417 ) -> CompareExchangeResult<u32> {
4418 CompareExchangeResult::from_usercopy(self.run_atomic_op(futex_addr, |uc| {
4419 uc.atomic_compare_exchange_u32_acq_rel(futex_addr.ptr(), current, new)
4420 }))
4421 }
4422
4423 pub fn atomic_compare_exchange_weak_u32_acq_rel(
4424 &self,
4425 futex_addr: FutexAddress,
4426 current: u32,
4427 new: u32,
4428 ) -> CompareExchangeResult<u32> {
4429 CompareExchangeResult::from_usercopy(self.run_atomic_op(futex_addr, |uc| {
4430 uc.atomic_compare_exchange_weak_u32_acq_rel(futex_addr.ptr(), current, new)
4431 }))
4432 }
4433}
4434
4435#[derive(Debug, Clone)]
4437pub enum CompareExchangeResult<T> {
4438 Success,
4441 Stale { observed: T },
4443 Error(Errno),
4445}
4446
4447impl<T> CompareExchangeResult<T> {
4448 fn from_usercopy(res: Result<Result<T, T>, Errno>) -> Self {
4449 match res {
4450 Ok(Ok(_)) => Self::Success,
4451 Ok(Err(observed)) => Self::Stale { observed },
4452 Err(e) => Self::Error(e),
4453 }
4454 }
4455}
4456
4457impl<T> From<Errno> for CompareExchangeResult<T> {
4458 fn from(e: Errno) -> Self {
4459 Self::Error(e)
4460 }
4461}
4462
4463#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4465pub enum DesiredAddress {
4466 Any,
4468 Hint(UserAddress),
4471 Fixed(UserAddress),
4474 FixedOverwrite(UserAddress),
4477}
4478
4479#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4481enum SelectedAddress {
4482 Fixed(UserAddress),
4484 FixedOverwrite(UserAddress),
4486}
4487
4488impl SelectedAddress {
4489 fn addr(&self) -> UserAddress {
4490 match self {
4491 SelectedAddress::Fixed(addr) => *addr,
4492 SelectedAddress::FixedOverwrite(addr) => *addr,
4493 }
4494 }
4495}
4496
4497fn write_map(
4499 task: &Task,
4500 fs_context: Option<&FsContext>,
4501 sink: &mut DynamicFileBuf,
4502 state: &MemoryManagerState,
4503 range: &Range<UserAddress>,
4504 map: &Mapping,
4505) -> Result<(), Errno> {
4506 let line_length = write!(
4507 sink,
4508 "{:08x}-{:08x} {}{}{}{} {:08x} 00:00 {} ",
4509 range.start.ptr(),
4510 range.end.ptr(),
4511 if map.can_read() { 'r' } else { '-' },
4512 if map.can_write() { 'w' } else { '-' },
4513 if map.can_exec() { 'x' } else { '-' },
4514 if map.flags().contains(MappingFlags::SHARED) { 's' } else { 'p' },
4515 match state.get_mapping_backing(map) {
4516 MappingBacking::Memory(backing) => backing.address_to_offset(range.start),
4517 MappingBacking::PrivateAnonymous => 0,
4518 },
4519 if let MappingNameRef::File(file) = &map.name() { file.node().ino } else { 0 }
4520 )?;
4521 let fill_to_name = |sink: &mut DynamicFileBuf| {
4522 for _ in line_length..73 {
4524 sink.write(b" ");
4525 }
4526 };
4527 match &map.name() {
4528 MappingNameRef::None | MappingNameRef::AioContext(_) => {
4529 if map.flags().contains(MappingFlags::SHARED)
4530 && map.flags().contains(MappingFlags::ANONYMOUS)
4531 {
4532 fill_to_name(sink);
4534 sink.write(b"/dev/zero (deleted)");
4535 }
4536 }
4537 MappingNameRef::Stack => {
4538 fill_to_name(sink);
4539 sink.write(b"[stack]");
4540 }
4541 MappingNameRef::Heap => {
4542 fill_to_name(sink);
4543 sink.write(b"[heap]");
4544 }
4545 MappingNameRef::Vdso => {
4546 fill_to_name(sink);
4547 sink.write(b"[vdso]");
4548 }
4549 MappingNameRef::Vvar => {
4550 fill_to_name(sink);
4551 sink.write(b"[vvar]");
4552 }
4553 MappingNameRef::File(file) => {
4554 fill_to_name(sink);
4555 let path = if let Some(fs_context) = fs_context {
4559 file.name().path(fs_context)
4560 } else {
4561 file.name().path(&task.running_state()?.fs())
4562 };
4563 sink.write_iter(
4564 path.iter()
4565 .flat_map(|b| if *b == b'\n' { b"\\012" } else { std::slice::from_ref(b) })
4566 .copied(),
4567 );
4568 }
4569 MappingNameRef::Vma(name) => {
4570 fill_to_name(sink);
4571 sink.write(b"[anon:");
4572 sink.write(name.as_bytes());
4573 sink.write(b"]");
4574 }
4575 MappingNameRef::Ashmem(name) => {
4576 fill_to_name(sink);
4577 sink.write(b"/dev/ashmem/");
4578 sink.write(name.as_bytes());
4579 }
4580 }
4581 sink.write(b"\n");
4582 Ok(())
4583}
4584
4585#[derive(Clone, Copy, Debug, Default)]
4586pub struct MemoryStats {
4587 pub vm_size: usize,
4588 pub vm_rss: usize,
4589 pub vm_rss_hwm: usize,
4590 pub rss_anonymous: usize,
4591 pub rss_file: usize,
4592 pub rss_shared: usize,
4593 pub vm_data: usize,
4594 pub vm_stack: usize,
4595 pub vm_exe: usize,
4596 pub vm_swap: usize,
4597 pub vm_lck: usize,
4598}
4599
4600#[derive(Clone)]
4602pub struct ProcMapsFile {
4603 mm: Weak<MemoryManager>,
4604 task: Weak<Task>,
4605}
4606impl ProcMapsFile {
4607 pub fn new(task: Arc<Task>) -> DynamicFile<Self> {
4608 let mm = task.mm().map_or_else(|_| Weak::default(), |mm| Arc::downgrade(&mm));
4610 DynamicFile::new(Self { mm, task: Arc::downgrade(&task) })
4611 }
4612}
4613
4614impl SequenceFileSource for ProcMapsFile {
4615 type Cursor = UserAddress;
4616
4617 fn next(
4618 &self,
4619 _current_task: &CurrentTask,
4620 cursor: UserAddress,
4621 sink: &mut DynamicFileBuf,
4622 ) -> Result<Option<UserAddress>, Errno> {
4623 let task = Task::from_weak(&self.task)?;
4624 let Some(mm) = self.mm.upgrade() else {
4626 return Ok(None);
4627 };
4628 let state = mm.state.read();
4629 if let Some((range, map)) = state.mappings.find_at_or_after(cursor) {
4630 let fs_context = task.running_state().ok().map(|rs| rs.fs());
4631 write_map(&task, fs_context.as_deref(), sink, &state, range, map)?;
4632 return Ok(Some(range.end));
4633 }
4634 Ok(None)
4635 }
4636}
4637
4638#[derive(Clone)]
4639pub struct ProcSmapsFile {
4640 mm: Weak<MemoryManager>,
4641 task: Weak<Task>,
4642}
4643impl ProcSmapsFile {
4644 pub fn new(task: Arc<Task>) -> DynamicFile<Self> {
4645 let mm = task.mm().map_or_else(|_| Weak::default(), |mm| Arc::downgrade(&mm));
4647 DynamicFile::new(Self { mm, task: Arc::downgrade(&task) })
4648 }
4649}
4650
4651impl DynamicFileSource for ProcSmapsFile {
4652 fn generate(&self, current_task: &CurrentTask, sink: &mut DynamicFileBuf) -> Result<(), Errno> {
4653 let page_size_kb = *PAGE_SIZE / 1024;
4654 let task = Task::from_weak(&self.task)?;
4655 let Some(mm) = self.mm.upgrade() else {
4657 return Ok(());
4658 };
4659
4660 let lazy_ranges: SmallVec<[_; 4]> = {
4664 let state = mm.state.read();
4665 state
4666 .mappings
4667 .iter()
4668 .filter(|(_, m)| m.mapping_mode() == MappingMode::Lazy)
4669 .map(|(range, _)| (range.start, Some(range.end - range.start)))
4670 .collect()
4671 };
4672 if !lazy_ranges.is_empty() {
4673 mm.state.write().ensure_ranges_mapped_in_user_vmar(lazy_ranges, &mm.mapping_context)?;
4674 }
4675
4676 let state = mm.state.read();
4677 let committed_bytes_vec = mm.with_zx_mappings(current_task, |zx_mappings| {
4678 let mut zx_memory_info = RangeMap::<UserAddress, usize>::default();
4679 for idx in 0..zx_mappings.len() {
4680 let zx_mapping = zx_mappings[idx];
4681 let _ = zx_memory_info.insert(
4683 UserAddress::from_ptr(zx_mapping.base)
4684 ..UserAddress::from_ptr(zx_mapping.base + zx_mapping.size),
4685 idx,
4686 );
4687 }
4688
4689 let mut committed_bytes_vec = Vec::new();
4690 for (mm_range, mm_mapping) in state.mappings.iter() {
4691 let mut committed_bytes = 0;
4692
4693 for (zx_range, zx_mapping_idx) in zx_memory_info.range(mm_range.clone()) {
4694 let intersect_range = zx_range.intersect(mm_range);
4695 let zx_mapping = zx_mappings[*zx_mapping_idx];
4696 let zx_details = zx_mapping.details();
4697 let Some(zx_details) = zx_details.as_mapping() else { continue };
4698 let zx_committed_bytes = zx_details.committed_bytes;
4699
4700 committed_bytes += if intersect_range != *zx_range {
4706 let intersection_size =
4707 intersect_range.end.ptr() - intersect_range.start.ptr();
4708 let part = intersection_size as f32 / zx_mapping.size as f32;
4709 let prorated_committed_bytes: f32 = part * zx_committed_bytes as f32;
4710 prorated_committed_bytes as u64
4711 } else {
4712 zx_committed_bytes as u64
4713 };
4714 assert_eq!(
4715 match state.get_mapping_backing(mm_mapping) {
4716 MappingBacking::Memory(m) => m.memory().get_koid(),
4717 MappingBacking::PrivateAnonymous =>
4718 mm.mapping_context.private_anonymous.backing.get_koid(),
4719 },
4720 zx_details.vmo_koid,
4721 "MemoryManager and Zircon must agree on which VMO is mapped in this range",
4722 );
4723 }
4724 committed_bytes_vec.push(committed_bytes);
4725 }
4726 Ok(committed_bytes_vec)
4727 })?;
4728
4729 let fs_context = task.running_state().ok().map(|rs| rs.fs());
4730 let fs_context_ref = fs_context.as_deref();
4731 for ((mm_range, mm_mapping), committed_bytes) in
4732 state.mappings.iter().zip(committed_bytes_vec.into_iter())
4733 {
4734 write_map(&task, fs_context_ref, sink, &state, mm_range, mm_mapping)?;
4735
4736 let size_kb = (mm_range.end.ptr() - mm_range.start.ptr()) / 1024;
4737 writeln!(sink, "Size: {size_kb:>8} kB",)?;
4738 let share_count = match state.get_mapping_backing(mm_mapping) {
4739 MappingBacking::Memory(backing) => {
4740 let memory = backing.memory();
4741 if memory.is_clock() {
4742 1
4744 } else {
4745 let memory_info = backing.memory().info()?;
4746 memory_info.share_count as u64
4747 }
4748 }
4749 MappingBacking::PrivateAnonymous => {
4750 1 }
4752 };
4753
4754 let rss_kb = committed_bytes / 1024;
4755 writeln!(sink, "Rss: {rss_kb:>8} kB")?;
4756
4757 let pss_kb = if mm_mapping.flags().contains(MappingFlags::SHARED) {
4758 rss_kb / share_count
4759 } else {
4760 rss_kb
4761 };
4762 writeln!(sink, "Pss: {pss_kb:>8} kB")?;
4763
4764 track_stub!(TODO("https://fxbug.dev/322874967"), "smaps dirty pages");
4765 let (shared_dirty_kb, private_dirty_kb) = (0, 0);
4766
4767 let is_shared = share_count > 1;
4768 let shared_clean_kb = if is_shared { rss_kb } else { 0 };
4769 writeln!(sink, "Shared_Clean: {shared_clean_kb:>8} kB")?;
4770 writeln!(sink, "Shared_Dirty: {shared_dirty_kb:>8} kB")?;
4771
4772 let private_clean_kb = if is_shared { 0 } else { rss_kb };
4773 writeln!(sink, "Private_Clean: {private_clean_kb:>8} kB")?;
4774 writeln!(sink, "Private_Dirty: {private_dirty_kb:>8} kB")?;
4775
4776 let anonymous_kb = if mm_mapping.private_anonymous() { rss_kb } else { 0 };
4777 writeln!(sink, "Anonymous: {anonymous_kb:>8} kB")?;
4778 writeln!(sink, "KernelPageSize: {page_size_kb:>8} kB")?;
4779 writeln!(sink, "MMUPageSize: {page_size_kb:>8} kB")?;
4780
4781 let locked_kb =
4782 if mm_mapping.flags().contains(MappingFlags::LOCKED) { rss_kb } else { 0 };
4783 writeln!(sink, "Locked: {locked_kb:>8} kB")?;
4784 writeln!(sink, "VmFlags: {}", mm_mapping.vm_flags())?;
4785
4786 track_stub!(TODO("https://fxbug.dev/297444691"), "optional smaps fields");
4787 }
4788
4789 Ok(())
4790 }
4791}
4792
4793#[derive(Clone)]
4795pub struct ProcSmapsRollupFile {
4796 mm: Weak<MemoryManager>,
4797 task: Weak<Task>,
4798}
4799impl ProcSmapsRollupFile {
4800 pub fn new(task: Arc<Task>) -> DynamicFile<Self> {
4803 let mm = task.mm().map_or_else(|_| Weak::default(), |mm| Arc::downgrade(&mm));
4804 DynamicFile::new(Self { mm, task: Arc::downgrade(&task) })
4805 }
4806}
4807impl DynamicFileSource for ProcSmapsRollupFile {
4808 fn generate(&self, current_task: &CurrentTask, sink: &mut DynamicFileBuf) -> Result<(), Errno> {
4809 let _task = Task::from_weak(&self.task)?;
4810 let Some(mm) = self.mm.upgrade() else {
4811 return error!(ESRCH);
4812 };
4813
4814 let mem_stats = mm.get_stats(current_task);
4815 let rss_kb = mem_stats.vm_rss / 1024;
4816 let anon_kb = mem_stats.rss_anonymous / 1024;
4817 let file_kb = mem_stats.rss_file / 1024;
4818 let shmem_kb = mem_stats.rss_shared / 1024;
4819 let swap_kb = mem_stats.vm_swap / 1024;
4820 let locked_kb = mem_stats.vm_lck / 1024;
4821
4822 let private_dirty_kb = anon_kb;
4824 let shared_clean_kb = file_kb + shmem_kb;
4826 let private_clean_kb = 0;
4827 let pss_file_kb = file_kb / 5;
4830 let pss_shmem_kb = shmem_kb / 5;
4831 let pss_kb = anon_kb + pss_file_kb + pss_shmem_kb;
4832
4833 writeln!(sink, "00000000-ffffffffffffffff ---p 00000000 00:00 0 [rollup]")?;
4834 writeln!(sink, "Rss: {rss_kb:>8} kB")?;
4835 writeln!(sink, "Pss: {pss_kb:>8} kB")?;
4836 writeln!(sink, "Pss_Dirty: 0 kB")?;
4837 writeln!(sink, "Pss_Anon: {anon_kb:>8} kB")?;
4838 writeln!(sink, "Pss_File: {pss_file_kb:>8} kB")?;
4839 writeln!(sink, "Pss_Shmem: {pss_shmem_kb:>8} kB")?;
4840 writeln!(sink, "Shared_Clean: {shared_clean_kb:>8} kB")?;
4841 writeln!(sink, "Shared_Dirty: 0 kB")?;
4842 writeln!(sink, "Private_Clean: {private_clean_kb:>8} kB")?;
4843 writeln!(sink, "Private_Dirty: {private_dirty_kb:>8} kB")?;
4844 writeln!(sink, "Referenced: {rss_kb:>8} kB")?;
4845 writeln!(sink, "Anonymous: {anon_kb:>8} kB")?;
4846 writeln!(sink, "KSM: 0 kB")?;
4847 writeln!(sink, "LazyFree: 0 kB")?;
4848 writeln!(sink, "AnonHugePages: 0 kB")?;
4849 writeln!(sink, "ShmemPmdMapped: 0 kB")?;
4850 writeln!(sink, "FilePmdMapped: 0 kB")?;
4851 writeln!(sink, "Shared_Hugetlb: 0 kB")?;
4852 writeln!(sink, "Private_Hugetlb: 0 kB")?;
4853 writeln!(sink, "Swap: {swap_kb:>8} kB")?;
4854 writeln!(sink, "SwapPss: {swap_kb:>8} kB")?;
4855 writeln!(sink, "Locked: {locked_kb:>8} kB")?;
4856 Ok(())
4857 }
4858}
4859
4860const PAGEMAP_PFN_MASK: u64 = (1u64 << 55) - 1;
4861
4862fn compute_pseudo_pfn(koid: zx::Koid, vmo_page_idx: u64) -> u64 {
4884 let mut hasher = rustc_hash::FxHasher::default();
4885 hasher.write_u64(koid.raw_koid());
4886 hasher.finish().wrapping_add(vmo_page_idx) & PAGEMAP_PFN_MASK
4887}
4888
4889#[derive(Clone)]
4891pub struct ProcPagemapFile {
4892 pid: Pid,
4893}
4894
4895impl ProcPagemapFile {
4896 pub fn new(pid: Pid) -> Self {
4897 Self { pid }
4898 }
4899}
4900
4901impl FileOps for ProcPagemapFile {
4902 fileops_impl_seekable!();
4903 fileops_impl_noop_sync!();
4904
4905 fn read(
4906 &self,
4907 _file: &FileObject,
4908 current_task: &CurrentTask,
4909 offset: usize,
4910 dst: &mut dyn OutputBuffer,
4911 ) -> Result<usize, Errno> {
4912 let task = self.pid.get_task()?;
4913 let Ok(mm) = task.mm() else {
4914 return Ok(0);
4915 };
4916
4917 let to_read = std::cmp::min(dst.available(), 1024 * 1024);
4918 if to_read == 0 {
4919 return Ok(0);
4920 }
4921
4922 let entry_size = std::mem::size_of::<u64>();
4923 let page_size = *PAGE_SIZE as usize;
4924
4925 let unaligned_offset = offset % entry_size;
4926 let start_page_idx = offset / entry_size;
4927 let total_bytes_needed = unaligned_offset + to_read;
4928 let num_pages = (total_bytes_needed + entry_size - 1) / entry_size;
4929
4930 let state = mm.state.read();
4931 let can_read_pfn =
4932 security::is_task_capable_noaudit(current_task, starnix_uapi::auth::CAP_SYS_ADMIN);
4933
4934 let get_mapping_vmo_info = |mm_mapping: &Mapping, addr: UserAddress| -> (zx::Koid, u64) {
4935 match state.get_mapping_backing(mm_mapping) {
4936 MappingBacking::Memory(backing) => {
4937 (backing.memory().get_koid(), backing.address_to_offset(addr))
4938 }
4939 MappingBacking::PrivateAnonymous => {
4940 (mm.mapping_context.private_anonymous.backing.get_koid(), addr.ptr() as u64)
4941 }
4942 }
4943 };
4944
4945 let compute_entry_flags = |mm_mapping: &Mapping| -> u64 {
4954 let is_shared = mm_mapping.flags().contains(MappingFlags::SHARED);
4955 let is_file = matches!(mm_mapping.name(), MappingNameRef::File(_));
4956 (1u64 << 63) | if is_shared || is_file { 1u64 << 61 } else { 1u64 << 57 }
4957 };
4958
4959 if to_read == entry_size && unaligned_offset == 0 {
4961 let start_vaddr = match start_page_idx.checked_mul(page_size) {
4962 Some(addr) => UserAddress::from(addr as u64),
4963 None => return Ok(0),
4964 };
4965 let mut entry = 0u64;
4966 if let Some((_, mm_mapping)) = state.mappings.get(start_vaddr) {
4967 let flags = compute_entry_flags(mm_mapping);
4968 let pfn = if can_read_pfn {
4969 let (koid, vmo_offset) = get_mapping_vmo_info(mm_mapping, start_vaddr);
4970 compute_pseudo_pfn(koid, vmo_offset / page_size as u64)
4971 } else {
4972 0
4973 };
4974 entry = flags | pfn;
4975 }
4976 dst.write_all(&entry.to_ne_bytes())?;
4977 return Ok(entry_size);
4978 }
4979
4980 const CHUNK_PAGES: usize = 512;
4981 let mut chunk_buf = [0u64; CHUNK_PAGES];
4982
4983 let mut pages_processed = 0;
4984 let mut bytes_written_total = 0;
4985
4986 while pages_processed < num_pages && bytes_written_total < to_read {
4987 let chunk_start_page = start_page_idx + pages_processed;
4988 let current_chunk_pages = std::cmp::min(CHUNK_PAGES, num_pages - pages_processed);
4989 let chunk_slice = &mut chunk_buf[..current_chunk_pages];
4990
4991 let chunk_start_vaddr = match chunk_start_page.checked_mul(page_size) {
4992 Some(addr) => UserAddress::from(addr as u64),
4993 None => break,
4994 };
4995 let chunk_end_vaddr =
4996 match (chunk_start_page + current_chunk_pages).checked_mul(page_size) {
4997 Some(addr) => UserAddress::from(addr as u64),
4998 None => UserAddress::from(u64::MAX),
4999 };
5000
5001 if let Some((mm_range, mm_mapping)) = state.mappings.get(chunk_start_vaddr) {
5003 if mm_range.end >= chunk_end_vaddr {
5004 let flags = compute_entry_flags(mm_mapping);
5005
5006 let start_pfn = if can_read_pfn {
5007 let (koid, vmo_offset) =
5008 get_mapping_vmo_info(mm_mapping, chunk_start_vaddr);
5009 compute_pseudo_pfn(koid, vmo_offset / page_size as u64)
5010 } else {
5011 0
5012 };
5013
5014 for (i, entry) in chunk_slice.iter_mut().enumerate() {
5015 let pfn = if can_read_pfn {
5016 (start_pfn.wrapping_add(i as u64)) & PAGEMAP_PFN_MASK
5017 } else {
5018 0
5019 };
5020 *entry = flags | pfn;
5021 }
5022
5023 let byte_slice = chunk_slice.as_bytes();
5024 let chunk_byte_offset = if pages_processed == 0 { unaligned_offset } else { 0 };
5025 let chunk_available_bytes = byte_slice.len().saturating_sub(chunk_byte_offset);
5026 let chunk_write_len =
5027 std::cmp::min(to_read - bytes_written_total, chunk_available_bytes);
5028
5029 dst.write_all(
5030 &byte_slice[chunk_byte_offset..chunk_byte_offset + chunk_write_len],
5031 )?;
5032 bytes_written_total += chunk_write_len;
5033 pages_processed += current_chunk_pages;
5034 continue;
5035 }
5036 }
5037
5038 chunk_slice.fill(0);
5040
5041 for (mm_range, mm_mapping) in state.mappings.range(chunk_start_vaddr..chunk_end_vaddr) {
5042 let flags = compute_entry_flags(mm_mapping);
5043
5044 let map_start_page = (mm_range.start.ptr() as usize) / page_size;
5045 let map_end_page = (mm_range.end.ptr() as usize) / page_size;
5046
5047 let first_page = std::cmp::max(chunk_start_page, map_start_page);
5048 let last_page = std::cmp::min(chunk_start_page + current_chunk_pages, map_end_page);
5049
5050 let first_page_vaddr = UserAddress::from((first_page * page_size) as u64);
5051 let start_pfn = if can_read_pfn {
5052 let (koid, vmo_offset) = get_mapping_vmo_info(mm_mapping, first_page_vaddr);
5053 compute_pseudo_pfn(koid, vmo_offset / page_size as u64)
5054 } else {
5055 0
5056 };
5057
5058 for page_idx in first_page..last_page {
5059 let pfn = if can_read_pfn {
5060 (start_pfn.wrapping_add((page_idx - first_page) as u64)) & PAGEMAP_PFN_MASK
5061 } else {
5062 0
5063 };
5064 chunk_slice[page_idx - chunk_start_page] = flags | pfn;
5065 }
5066 }
5067
5068 let byte_slice = chunk_slice.as_bytes();
5069 let chunk_byte_offset = if pages_processed == 0 { unaligned_offset } else { 0 };
5070 let chunk_available_bytes = byte_slice.len().saturating_sub(chunk_byte_offset);
5071 let chunk_write_len =
5072 std::cmp::min(to_read - bytes_written_total, chunk_available_bytes);
5073
5074 dst.write_all(&byte_slice[chunk_byte_offset..chunk_byte_offset + chunk_write_len])?;
5075 bytes_written_total += chunk_write_len;
5076 pages_processed += current_chunk_pages;
5077 }
5078
5079 Ok(bytes_written_total)
5080 }
5081
5082 fn write(
5083 &self,
5084 _file: &FileObject,
5085 _current_task: &CurrentTask,
5086 _offset: usize,
5087 _data: &mut dyn InputBuffer,
5088 ) -> Result<usize, Errno> {
5089 starnix_uapi::error!(EPERM)
5090 }
5091}
5092
5093pub fn create_anonymous_mapping_memory(size: u64) -> Result<Arc<MemoryObject>, Errno> {
5095 let mut memory = MemoryObject::from(
5097 zx::Vmo::create_with_opts(zx::VmoOptions::RESIZABLE, size).map_err(|s| match s {
5098 zx::Status::NO_MEMORY => errno!(ENOMEM),
5099 zx::Status::OUT_OF_RANGE => errno!(ENOMEM),
5100 _ => impossible_error(s),
5101 })?,
5102 )
5103 .with_zx_name(b"starnix:memory_manager");
5104
5105 memory.set_zx_name(b"starnix-anon");
5106
5107 memory = memory.replace_as_executable(&VMEX_RESOURCE).map_err(impossible_error)?;
5109 Ok(Arc::new(memory))
5110}
5111
5112fn generate_random_offset_for_aslr(arch_width: ArchWidth) -> usize {
5113 let randomness = {
5115 let random_bits =
5116 if arch_width.is_arch32() { ASLR_32_RANDOM_BITS } else { ASLR_RANDOM_BITS };
5117 let mask = (1 << random_bits) - 1;
5118 let mut bytes = [0; std::mem::size_of::<usize>()];
5119 starnix_crypto::cprng_draw(&mut bytes);
5120 usize::from_le_bytes(bytes) & mask
5121 };
5122
5123 randomness * (*PAGE_SIZE as usize)
5125}
5126
5127#[cfg(test)]
5128mod tests {
5129 use super::*;
5130 use crate::mm::memory_accessor::{MemoryAccessor, MemoryAccessorExt};
5131 use crate::mm::syscalls::do_mmap;
5132 use crate::task::syscalls::sys_prctl;
5133 use crate::testing::*;
5134 use crate::vfs::FdNumber;
5135 use assert_matches::assert_matches;
5136 use itertools::assert_equal;
5137 use starnix_uapi::user_address::{UserCString, UserRef};
5138 use starnix_uapi::{
5139 MAP_ANONYMOUS, MAP_FIXED, MAP_GROWSDOWN, MAP_PRIVATE, MAP_SHARED, PR_SET_VMA,
5140 PR_SET_VMA_ANON_NAME, PROT_NONE, PROT_READ,
5141 };
5142 use std::ffi::CString;
5143 use zerocopy::{FromBytes, Immutable, KnownLayout};
5144
5145 #[::fuchsia::test]
5146 fn test_mapping_flags() {
5147 let options = MappingOptions::ANONYMOUS;
5148 let access_flags = ProtectionFlags::READ | ProtectionFlags::WRITE;
5149 let mapping_flags = MappingFlags::from_access_flags_and_options(access_flags, options);
5150 assert_eq!(mapping_flags.access_flags(), access_flags);
5151 assert_eq!(mapping_flags.options(), options);
5152
5153 let new_access_flags = ProtectionFlags::READ | ProtectionFlags::EXEC;
5154 let adusted_mapping_flags = mapping_flags.with_access_flags(new_access_flags);
5155 assert_eq!(adusted_mapping_flags.access_flags(), new_access_flags);
5156 assert_eq!(adusted_mapping_flags.options(), options);
5157 }
5158
5159 #[::fuchsia::test]
5160 async fn test_any_ranges_lazy() {
5161 spawn_kernel_and_run(async |current_task| {
5162 let mm = current_task.mm().unwrap();
5163 let page_size = *PAGE_SIZE as usize;
5164 let addr = (mm.base_addr + 10 * page_size).unwrap();
5165 let length = page_size;
5166
5167 let memory = create_anonymous_mapping_memory(length as u64).unwrap();
5168 let flags = MappingFlags::from_access_flags_and_options(
5169 ProtectionFlags::READ | ProtectionFlags::WRITE,
5170 MappingOptions::empty(),
5171 );
5172
5173 let mapping = Mapping::with_name(
5174 MappingBacking::Memory(Box::new(MappingBackingMemory::new(addr, memory, 0))),
5175 flags,
5176 MappingName::None,
5177 MappingMode::Lazy,
5178 );
5179
5180 {
5181 let mut state = mm.state.write();
5182 state.mappings.insert(addr..(addr + length).unwrap(), mapping);
5183 }
5184
5185 {
5186 let state = mm.state.read();
5187 assert!(state.any_ranges_lazy(std::iter::once((addr, Some(length)))));
5188 }
5189
5190 assert!(mm.ensure_range_mapped_in_user_vmar(addr, Some(length)).unwrap());
5191
5192 {
5193 let state = mm.state.read();
5194 assert!(!state.any_ranges_lazy(std::iter::once((addr, Some(length)))));
5195 }
5196 })
5197 .await;
5198 }
5199
5200 #[::fuchsia::test]
5201 async fn test_brk() {
5202 spawn_kernel_and_run(async |current_task| {
5203 let mm = current_task.mm().unwrap();
5204
5205 let get_range = |addr: UserAddress| {
5207 let state = mm.state.read();
5208 state
5209 .mappings
5210 .map
5211 .get(addr)
5212 .map(|(range, mapping)| (range.clone(), mapping.clone()))
5213 };
5214
5215 let base_addr = mm
5217 .set_brk(¤t_task, UserAddress::default())
5218 .expect("failed to set initial program break");
5219 assert!(base_addr > UserAddress::default());
5220
5221 assert_eq!(get_range(base_addr), None);
5223
5224 let addr0 =
5226 mm.set_brk(¤t_task, (base_addr + 1u64).unwrap()).expect("failed to grow brk");
5227 assert!(addr0 > base_addr);
5228 let (range0, _) = get_range(base_addr).expect("base_addr should be mapped");
5229 assert_eq!(range0.start, base_addr);
5230 assert_eq!(range0.end, (base_addr + *PAGE_SIZE).unwrap());
5231
5232 let addr1 =
5234 mm.set_brk(¤t_task, (base_addr + 2u64).unwrap()).expect("failed to grow brk");
5235 assert_eq!(addr1, (base_addr + 2u64).unwrap());
5236 let (range1, _) = get_range(base_addr).expect("base_addr should be mapped");
5237 assert_eq!(range1.start, range0.start);
5238 assert_eq!(range1.end, range0.end);
5239
5240 let addr2 = mm
5242 .set_brk(¤t_task, (base_addr + 24893u64).unwrap())
5243 .expect("failed to grow brk");
5244 assert_eq!(addr2, (base_addr + 24893u64).unwrap());
5245 let (range2, _) = get_range(base_addr).expect("base_addr should be mapped");
5246 assert_eq!(range2.start, base_addr);
5247 assert_eq!(range2.end, addr2.round_up(*PAGE_SIZE).unwrap());
5248
5249 let addr3 = mm
5251 .set_brk(¤t_task, (base_addr + 14832u64).unwrap())
5252 .expect("failed to shrink brk");
5253 assert_eq!(addr3, (base_addr + 14832u64).unwrap());
5254 let (range3, _) = get_range(base_addr).expect("base_addr should be mapped");
5255 assert_eq!(range3.start, base_addr);
5256 assert_eq!(range3.end, addr3.round_up(*PAGE_SIZE).unwrap());
5257
5258 let addr4 = mm
5260 .set_brk(¤t_task, (base_addr + 3u64).unwrap())
5261 .expect("failed to drastically shrink brk");
5262 assert_eq!(addr4, (base_addr + 3u64).unwrap());
5263 let (range4, _) = get_range(base_addr).expect("base_addr should be mapped");
5264 assert_eq!(range4.start, base_addr);
5265 assert_eq!(range4.end, addr4.round_up(*PAGE_SIZE).unwrap());
5266
5267 let addr5 = mm
5269 .set_brk(¤t_task, base_addr)
5270 .expect("failed to drastically shrink brk to zero");
5271 assert_eq!(addr5, base_addr);
5272 assert_eq!(get_range(base_addr), None);
5273 })
5274 .await;
5275 }
5276
5277 #[::fuchsia::test]
5278 async fn test_mm_exec() {
5279 spawn_kernel_and_run(async |current_task| {
5280 let mm = current_task.mm().unwrap();
5281
5282 let has = |addr: UserAddress| -> bool {
5283 let state = mm.state.read();
5284 state.mappings.get(addr).is_some()
5285 };
5286
5287 let brk_addr = mm
5288 .set_brk(¤t_task, UserAddress::default())
5289 .expect("failed to set initial program break");
5290 assert!(brk_addr > UserAddress::default());
5291
5292 let _ = mm
5294 .set_brk(¤t_task, (brk_addr + 1u64).unwrap())
5295 .expect("failed to grow program break");
5296 assert!(has(brk_addr));
5297
5298 let mapped_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
5299 assert!(mapped_addr > UserAddress::default());
5300 assert!(has(mapped_addr));
5301
5302 let node = current_task.lookup_path_from_root("/".into()).unwrap();
5303 let new_mm = MemoryManager::exec(
5304 current_task.thread_group().root_vmar.unowned(),
5305 current_task.running_state().mm.upgrade(),
5306 node,
5307 ArchWidth::Arch64,
5308 )
5309 .expect("failed to exec memory manager");
5310 current_task.running_state().mm.update(Some(new_mm));
5311
5312 assert!(!has(brk_addr));
5313 assert!(!has(mapped_addr));
5314
5315 let brk_addr2 = map_memory(¤t_task, brk_addr, *PAGE_SIZE);
5317 assert_eq!(brk_addr, brk_addr2);
5318 let mapped_addr2 = map_memory(¤t_task, mapped_addr, *PAGE_SIZE);
5319 assert_eq!(mapped_addr, mapped_addr2);
5320 })
5321 .await;
5322 }
5323
5324 #[::fuchsia::test]
5325 async fn test_get_contiguous_mappings_at() {
5326 spawn_kernel_and_run(async |current_task| {
5327 let mm = current_task.mm().unwrap();
5328 let context = &mm.mapping_context;
5329
5330 let page_size = *PAGE_SIZE as usize;
5332 let addr_a = (mm.base_addr + 10 * page_size).unwrap();
5333 let addr_b = (mm.base_addr + 11 * page_size).unwrap();
5334 let addr_c = (mm.base_addr + 12 * page_size).unwrap();
5335 let addr_d = (mm.base_addr + 14 * page_size).unwrap();
5336 assert_eq!(map_memory(¤t_task, addr_a, *PAGE_SIZE), addr_a);
5337 assert_eq!(map_memory(¤t_task, addr_b, *PAGE_SIZE), addr_b);
5338 assert_eq!(map_memory(¤t_task, addr_c, *PAGE_SIZE), addr_c);
5339 assert_eq!(map_memory(¤t_task, addr_d, *PAGE_SIZE), addr_d);
5340
5341 {
5342 let mm_state = mm.state.read();
5343 assert_equal(
5345 mm_state
5346 .get_contiguous_mappings_at((addr_a - 100u64).unwrap(), 50, &context)
5347 .unwrap(),
5348 vec![],
5349 );
5350 assert_equal(
5351 mm_state
5352 .get_contiguous_mappings_at((addr_a - 100u64).unwrap(), 200, &context)
5353 .unwrap(),
5354 vec![],
5355 );
5356
5357 assert_equal(
5359 mm_state.get_contiguous_mappings_at(addr_a, 0, &context).unwrap(),
5360 vec![],
5361 );
5362
5363 assert_eq!(
5365 mm_state
5366 .get_contiguous_mappings_at(UserAddress::from(100), usize::MAX, &context)
5367 .err()
5368 .unwrap(),
5369 errno!(EFAULT)
5370 );
5371 assert_eq!(
5372 mm_state
5373 .get_contiguous_mappings_at(
5374 (context.max_address() + 1u64).unwrap(),
5375 0,
5376 &context
5377 )
5378 .err()
5379 .unwrap(),
5380 errno!(EFAULT)
5381 );
5382 }
5383
5384 assert_eq!(mm.get_mapping_count(), 2);
5385 let mm_state = mm.state.read();
5386 let (map_a, map_b) = {
5387 let mut it = mm_state.mappings.iter();
5388 (it.next().unwrap().1, it.next().unwrap().1)
5389 };
5390
5391 assert_equal(
5392 mm_state.get_contiguous_mappings_at(addr_a, page_size, &context).unwrap(),
5393 vec![(map_a, page_size)],
5394 );
5395
5396 assert_equal(
5397 mm_state.get_contiguous_mappings_at(addr_a, page_size / 2, &context).unwrap(),
5398 vec![(map_a, page_size / 2)],
5399 );
5400
5401 assert_equal(
5402 mm_state.get_contiguous_mappings_at(addr_a, page_size * 3, &context).unwrap(),
5403 vec![(map_a, page_size * 3)],
5404 );
5405
5406 assert_equal(
5407 mm_state.get_contiguous_mappings_at(addr_b, page_size, &context).unwrap(),
5408 vec![(map_a, page_size)],
5409 );
5410
5411 assert_equal(
5412 mm_state.get_contiguous_mappings_at(addr_d, page_size, &context).unwrap(),
5413 vec![(map_b, page_size)],
5414 );
5415
5416 assert_equal(
5418 mm_state
5419 .get_contiguous_mappings_at(
5420 (addr_a + page_size / 2).unwrap(),
5421 page_size * 10,
5422 &context,
5423 )
5424 .unwrap(),
5425 vec![(map_a, page_size * 2 + page_size / 2)],
5426 );
5427
5428 assert_equal(
5430 mm_state.get_contiguous_mappings_at(addr_d, page_size * 10, &context).unwrap(),
5431 vec![(map_b, page_size)],
5432 );
5433 })
5434 .await;
5435 }
5436
5437 #[::fuchsia::test]
5438 async fn test_read_write_crossing_mappings() {
5439 spawn_kernel_and_run(async |current_task| {
5440 let mm = current_task.mm().unwrap();
5441 let ma = current_task.deref();
5442
5443 let page_size = *PAGE_SIZE;
5445 let addr = (mm.base_addr + 10 * page_size).unwrap();
5446 assert_eq!(map_memory(¤t_task, addr, page_size), addr);
5447 assert_eq!(
5448 map_memory(¤t_task, (addr + page_size).unwrap(), page_size),
5449 (addr + page_size).unwrap()
5450 );
5451 assert_eq!(mm.get_mapping_count(), 1);
5453
5454 let test_addr = (addr + page_size / 2).unwrap();
5456 let data: Vec<u8> = (0..page_size).map(|i| (i % 256) as u8).collect();
5457 ma.write_memory(test_addr, &data).expect("failed to write test data");
5458
5459 let data_readback =
5461 ma.read_memory_to_vec(test_addr, data.len()).expect("failed to read test data");
5462 assert_eq!(&data, &data_readback);
5463 })
5464 .await;
5465 }
5466
5467 #[::fuchsia::test]
5468 async fn test_read_write_errors() {
5469 spawn_kernel_and_run(async |current_task| {
5470 let ma = current_task.deref();
5471
5472 let page_size = *PAGE_SIZE;
5473 let addr = map_memory(¤t_task, UserAddress::default(), page_size);
5474 let buf = vec![0u8; page_size as usize];
5475
5476 let partial_addr_before = (addr - page_size / 2).unwrap();
5478 assert_eq!(ma.write_memory(partial_addr_before, &buf), error!(EFAULT));
5479 assert_eq!(ma.read_memory_to_vec(partial_addr_before, buf.len()), error!(EFAULT));
5480 let partial_addr_after = (addr + page_size / 2).unwrap();
5481 assert_eq!(ma.write_memory(partial_addr_after, &buf), error!(EFAULT));
5482 assert_eq!(ma.read_memory_to_vec(partial_addr_after, buf.len()), error!(EFAULT));
5483
5484 let unmapped_addr = (addr - 10 * page_size).unwrap();
5486 assert_eq!(ma.write_memory(unmapped_addr, &buf), error!(EFAULT));
5487 assert_eq!(ma.read_memory_to_vec(unmapped_addr, buf.len()), error!(EFAULT));
5488
5489 ma.write_memory(unmapped_addr, &[]).expect("failed to write no data");
5491 ma.read_memory_to_vec(unmapped_addr, 0).expect("failed to read no data");
5492 })
5493 .await;
5494 }
5495
5496 #[::fuchsia::test]
5497 async fn test_read_c_string_to_vec_large() {
5498 spawn_kernel_and_run(async |current_task| {
5499 let mm = current_task.mm().unwrap();
5500 let ma = current_task.deref();
5501
5502 let page_size = *PAGE_SIZE;
5503 let max_size = 4 * page_size as usize;
5504 let addr = (mm.base_addr + 10 * page_size).unwrap();
5505
5506 assert_eq!(map_memory(¤t_task, addr, max_size as u64), addr);
5507
5508 let mut random_data = vec![0; max_size];
5509 starnix_crypto::cprng_draw(&mut random_data);
5510 for i in 0..random_data.len() {
5512 if random_data[i] == 0 {
5513 random_data[i] = 1;
5514 }
5515 }
5516 random_data[max_size - 1] = 0;
5517
5518 ma.write_memory(addr, &random_data).expect("failed to write test string");
5519 assert_eq!(
5521 ma.read_c_string_to_vec(UserCString::new(current_task, addr), max_size).unwrap(),
5522 random_data[..max_size - 1]
5523 );
5524 })
5525 .await;
5526 }
5527
5528 #[::fuchsia::test]
5529 async fn test_read_c_string_to_vec() {
5530 spawn_kernel_and_run(async |current_task| {
5531 let mm = current_task.mm().unwrap();
5532 let ma = current_task.deref();
5533
5534 let page_size = *PAGE_SIZE;
5535 let max_size = 2 * page_size as usize;
5536 let addr = (mm.base_addr + 10 * page_size).unwrap();
5537
5538 assert_eq!(map_memory(¤t_task, addr, page_size), addr);
5540 let test_str = b"foo!";
5541 let test_addr =
5542 addr.checked_add(page_size as usize).unwrap().checked_sub(test_str.len()).unwrap();
5543 ma.write_memory(test_addr, test_str).expect("failed to write test string");
5544
5545 assert_eq!(
5547 ma.read_c_string_to_vec(UserCString::new(current_task, test_addr), max_size),
5548 error!(ENAMETOOLONG)
5549 );
5550
5551 ma.write_memory((addr + (page_size - 1)).unwrap(), b"\0").expect("failed to write nul");
5553 assert_eq!(
5554 ma.read_c_string_to_vec(UserCString::new(current_task, test_addr), max_size)
5555 .unwrap(),
5556 "foo"
5557 );
5558
5559 assert_eq!(
5561 map_memory(¤t_task, (addr + page_size).unwrap(), page_size),
5562 (addr + page_size).unwrap()
5563 );
5564 ma.write_memory((addr + (page_size - 1)).unwrap(), b"bar\0")
5568 .expect("failed to write extra chars");
5569 assert_eq!(
5570 ma.read_c_string_to_vec(UserCString::new(current_task, test_addr), max_size)
5571 .unwrap(),
5572 "foobar",
5573 );
5574
5575 assert_eq!(
5577 ma.read_c_string_to_vec(UserCString::new(current_task, test_addr), 2),
5578 error!(ENAMETOOLONG)
5579 );
5580
5581 assert_eq!(
5583 ma.read_c_string_to_vec(UserCString::null(current_task), max_size),
5584 error!(EFAULT)
5585 );
5586 })
5587 .await;
5588 }
5589
5590 #[::fuchsia::test]
5591 async fn can_read_argv_like_regions() {
5592 spawn_kernel_and_run(async |current_task| {
5593 let ma = current_task.deref();
5594
5595 let page_size = *PAGE_SIZE;
5597 let addr = map_memory_anywhere(¤t_task, page_size);
5598 assert!(!addr.is_null());
5599
5600 let mut payload = "first".as_bytes().to_vec();
5602 let mut expected_parses = vec![];
5603 ma.write_memory(addr, &payload).unwrap();
5604
5605 expected_parses.push(payload.clone());
5607 payload.push(0);
5608 ma.write_memory(addr, &payload).unwrap();
5609 assert_eq!(
5610 ma.read_nul_delimited_c_string_list(addr, payload.len()).unwrap(),
5611 expected_parses,
5612 );
5613
5614 let second = b"second";
5616 payload.extend(second);
5617 payload.push(0);
5618 expected_parses.push(second.to_vec());
5619
5620 let third = b"third";
5621 payload.extend(third);
5622 payload.push(0);
5623 expected_parses.push(third.to_vec());
5624
5625 ma.write_memory(addr, &payload).unwrap();
5626 assert_eq!(
5627 ma.read_nul_delimited_c_string_list(addr, payload.len()).unwrap(),
5628 expected_parses,
5629 );
5630 })
5631 .await;
5632 }
5633
5634 #[::fuchsia::test]
5635 async fn truncate_argv_like_regions() {
5636 spawn_kernel_and_run(async |current_task| {
5637 let ma = current_task.deref();
5638
5639 let page_size = *PAGE_SIZE;
5641 let addr = map_memory_anywhere(¤t_task, page_size);
5642 assert!(!addr.is_null());
5643
5644 let payload = b"first\0second\0third\0";
5645 ma.write_memory(addr, payload).unwrap();
5646 assert_eq!(
5647 ma.read_nul_delimited_c_string_list(addr, payload.len() - 3).unwrap(),
5648 vec![b"first".to_vec(), b"second".to_vec(), b"thi".to_vec()],
5649 "Skipping last three bytes of payload should skip last two bytes of 3rd string"
5650 );
5651 })
5652 .await;
5653 }
5654
5655 #[::fuchsia::test]
5656 async fn test_read_c_string() {
5657 spawn_kernel_and_run(async |current_task| {
5658 let mm = current_task.mm().unwrap();
5659 let ma = current_task.deref();
5660
5661 let page_size = *PAGE_SIZE;
5662 let buf_cap = 2 * page_size as usize;
5663 let mut buf = Vec::with_capacity(buf_cap);
5664 let buf = &mut buf.spare_capacity_mut()[..buf_cap];
5667 let addr = (mm.base_addr + 10 * page_size).unwrap();
5668
5669 assert_eq!(map_memory(¤t_task, addr, page_size), addr);
5671 let test_str = b"foo!";
5672 let test_addr = (addr + (page_size - test_str.len() as u64)).unwrap();
5673 ma.write_memory(test_addr, test_str).expect("failed to write test string");
5674
5675 assert_eq!(
5677 ma.read_c_string(UserCString::new(current_task, test_addr), buf),
5678 error!(ENAMETOOLONG)
5679 );
5680
5681 ma.write_memory((addr + (page_size - 1)).unwrap(), b"\0").expect("failed to write nul");
5683 assert_eq!(
5684 ma.read_c_string(UserCString::new(current_task, test_addr), buf).unwrap(),
5685 "foo"
5686 );
5687
5688 assert_eq!(
5690 map_memory(¤t_task, (addr + page_size).unwrap(), page_size),
5691 (addr + page_size).unwrap()
5692 );
5693 ma.write_memory((addr + (page_size - 1)).unwrap(), b"bar\0")
5697 .expect("failed to write extra chars");
5698 assert_eq!(
5699 ma.read_c_string(UserCString::new(current_task, test_addr), buf).unwrap(),
5700 "foobar"
5701 );
5702
5703 assert_eq!(
5705 ma.read_c_string(
5706 UserCString::new(current_task, test_addr),
5707 &mut [MaybeUninit::uninit(); 2]
5708 ),
5709 error!(ENAMETOOLONG)
5710 );
5711
5712 assert_eq!(ma.read_c_string(UserCString::null(current_task), buf), error!(EFAULT));
5714 })
5715 .await;
5716 }
5717
5718 #[::fuchsia::test]
5719 async fn test_find_next_unused_range() {
5720 spawn_kernel_and_run(async |current_task| {
5721 let mm = current_task.mm().unwrap();
5722
5723 let mmap_top = mm.state.read().find_next_unused_range(0).unwrap().ptr();
5724 let page_size = *PAGE_SIZE as usize;
5725 assert!(mmap_top <= RESTRICTED_ASPACE_HIGHEST_ADDRESS);
5726
5727 assert_eq!(
5729 mm.state.read().find_next_unused_range(page_size).unwrap(),
5730 UserAddress::from_ptr(mmap_top - page_size)
5731 );
5732
5733 let addr = UserAddress::from_ptr(mmap_top - page_size);
5735 assert_eq!(map_memory(¤t_task, addr, *PAGE_SIZE), addr);
5736
5737 assert_eq!(
5739 mm.state.read().find_next_unused_range(page_size).unwrap(),
5740 UserAddress::from_ptr(addr.ptr() - page_size)
5741 );
5742
5743 let addr2 = UserAddress::from_ptr(addr.ptr() - 2 * page_size);
5745 assert_eq!(map_memory(¤t_task, addr2, *PAGE_SIZE), addr2);
5746
5747 assert_eq!(
5749 mm.state.read().find_next_unused_range(page_size).unwrap(),
5750 UserAddress::from_ptr(addr.ptr() - page_size)
5751 );
5752
5753 assert_eq!(
5755 mm.state.read().find_next_unused_range(2 * page_size).unwrap(),
5756 UserAddress::from_ptr(addr2.ptr() - 2 * page_size)
5757 );
5758
5759 assert_eq!(mm.state.read().find_next_unused_range(mmap_top), None);
5761 })
5762 .await;
5763 }
5764
5765 #[::fuchsia::test]
5766 async fn test_count_placements() {
5767 spawn_kernel_and_run(async |current_task| {
5768 let mm = current_task.mm().unwrap();
5769
5770 let page_size = *PAGE_SIZE as usize;
5772 let subrange_ten = UserAddress::from_ptr(RESTRICTED_ASPACE_BASE)
5773 ..UserAddress::from_ptr(RESTRICTED_ASPACE_BASE + 10 * page_size);
5774
5775 assert_eq!(
5776 mm.state.read().count_possible_placements(11 * page_size, &subrange_ten),
5777 Some(0)
5778 );
5779 assert_eq!(
5780 mm.state.read().count_possible_placements(10 * page_size, &subrange_ten),
5781 Some(1)
5782 );
5783 assert_eq!(
5784 mm.state.read().count_possible_placements(9 * page_size, &subrange_ten),
5785 Some(2)
5786 );
5787 assert_eq!(
5788 mm.state.read().count_possible_placements(page_size, &subrange_ten),
5789 Some(10)
5790 );
5791
5792 let addr = UserAddress::from_ptr(RESTRICTED_ASPACE_BASE + 5 * page_size);
5794 assert_eq!(map_memory(¤t_task, addr, *PAGE_SIZE), addr);
5795
5796 assert_eq!(
5797 mm.state.read().count_possible_placements(10 * page_size, &subrange_ten),
5798 Some(0)
5799 );
5800 assert_eq!(
5801 mm.state.read().count_possible_placements(5 * page_size, &subrange_ten),
5802 Some(1)
5803 );
5804 assert_eq!(
5805 mm.state.read().count_possible_placements(4 * page_size, &subrange_ten),
5806 Some(3)
5807 );
5808 assert_eq!(
5809 mm.state.read().count_possible_placements(page_size, &subrange_ten),
5810 Some(9)
5811 );
5812 })
5813 .await;
5814 }
5815
5816 #[::fuchsia::test]
5817 async fn test_pick_placement() {
5818 spawn_kernel_and_run(async |current_task| {
5819 let mm = current_task.mm().unwrap();
5820
5821 let page_size = *PAGE_SIZE as usize;
5822 let subrange_ten = UserAddress::from_ptr(RESTRICTED_ASPACE_BASE)
5823 ..UserAddress::from_ptr(RESTRICTED_ASPACE_BASE + 10 * page_size);
5824
5825 let addr = UserAddress::from_ptr(RESTRICTED_ASPACE_BASE + 5 * page_size);
5826 assert_eq!(map_memory(¤t_task, addr, *PAGE_SIZE), addr);
5827 assert_eq!(
5828 mm.state.read().count_possible_placements(4 * page_size, &subrange_ten),
5829 Some(3)
5830 );
5831
5832 assert_eq!(
5833 mm.state.read().pick_placement(4 * page_size, 0, &subrange_ten),
5834 Some(UserAddress::from_ptr(RESTRICTED_ASPACE_BASE))
5835 );
5836 assert_eq!(
5837 mm.state.read().pick_placement(4 * page_size, 1, &subrange_ten),
5838 Some(UserAddress::from_ptr(RESTRICTED_ASPACE_BASE + page_size))
5839 );
5840 assert_eq!(
5841 mm.state.read().pick_placement(4 * page_size, 2, &subrange_ten),
5842 Some(UserAddress::from_ptr(RESTRICTED_ASPACE_BASE + 6 * page_size))
5843 );
5844 })
5845 .await;
5846 }
5847
5848 #[::fuchsia::test]
5849 async fn test_find_random_unused_range() {
5850 spawn_kernel_and_run(async |current_task| {
5851 let mm = current_task.mm().unwrap();
5852
5853 let page_size = *PAGE_SIZE as usize;
5855 let subrange_ten = UserAddress::from_ptr(RESTRICTED_ASPACE_BASE)
5856 ..UserAddress::from_ptr(RESTRICTED_ASPACE_BASE + 10 * page_size);
5857
5858 for _ in 0..10 {
5859 let addr = mm.state.read().find_random_unused_range(page_size, &subrange_ten);
5860 assert!(addr.is_some());
5861 assert_eq!(map_memory(¤t_task, addr.unwrap(), *PAGE_SIZE), addr.unwrap());
5862 }
5863 assert_eq!(mm.state.read().find_random_unused_range(page_size, &subrange_ten), None);
5864 })
5865 .await;
5866 }
5867
5868 #[::fuchsia::test]
5869 async fn test_grows_down_near_aspace_base() {
5870 spawn_kernel_and_run(async |current_task| {
5871 let mm = current_task.mm().unwrap();
5872
5873 let page_count = 10;
5874
5875 let page_size = *PAGE_SIZE as usize;
5876 let addr =
5877 (UserAddress::from_ptr(RESTRICTED_ASPACE_BASE) + page_count * page_size).unwrap();
5878 assert_eq!(
5879 map_memory_with_flags(
5880 ¤t_task,
5881 addr,
5882 page_size as u64,
5883 MAP_ANONYMOUS | MAP_PRIVATE | MAP_GROWSDOWN
5884 ),
5885 addr
5886 );
5887
5888 let subrange_ten = UserAddress::from_ptr(RESTRICTED_ASPACE_BASE)..addr;
5889 assert_eq!(mm.state.read().find_random_unused_range(page_size, &subrange_ten), None);
5890 })
5891 .await;
5892 }
5893
5894 #[::fuchsia::test]
5895 async fn test_unmap_returned_mappings() {
5896 spawn_kernel_and_run(async |current_task| {
5897 let mm = current_task.mm().unwrap();
5898
5899 let addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE * 2);
5900
5901 let mut released_mappings = ReleasedMappings::default();
5902 let mut mm_state = mm.state.write();
5903 let unmap_result =
5904 mm_state.unmap(&mm, addr, *PAGE_SIZE as usize, &mut released_mappings);
5905 assert!(unmap_result.is_ok());
5906 assert_eq!(released_mappings.len(), 1);
5907 released_mappings.finalize(mm_state);
5908 })
5909 .await;
5910 }
5911
5912 #[::fuchsia::test]
5913 async fn test_unmap_returns_multiple_mappings() {
5914 spawn_kernel_and_run(async |current_task| {
5915 let mm = current_task.mm().unwrap();
5916
5917 let addr = mm.state.read().find_next_unused_range(3 * *PAGE_SIZE as usize).unwrap();
5918 let addr = map_memory(¤t_task, addr, *PAGE_SIZE);
5919 let _ = map_memory(¤t_task, (addr + 2 * *PAGE_SIZE).unwrap(), *PAGE_SIZE);
5920
5921 let mut released_mappings = ReleasedMappings::default();
5922 let mut mm_state = mm.state.write();
5923 let unmap_result =
5924 mm_state.unmap(&mm, addr, (*PAGE_SIZE * 3) as usize, &mut released_mappings);
5925 assert!(unmap_result.is_ok());
5926 assert_eq!(released_mappings.len(), 2);
5927 released_mappings.finalize(mm_state);
5928 })
5929 .await;
5930 }
5931
5932 #[::fuchsia::test]
5935 async fn test_map_two_unmap_one() {
5936 spawn_kernel_and_run(async |current_task| {
5937 let mm = current_task.mm().unwrap();
5938
5939 let addr_reserve = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE * 2);
5941 let addr1 = do_mmap(
5942 ¤t_task,
5943 addr_reserve,
5944 *PAGE_SIZE as usize,
5945 PROT_READ, MAP_ANONYMOUS | MAP_SHARED | MAP_FIXED,
5947 FdNumber::from_raw(-1),
5948 0,
5949 )
5950 .expect("failed to mmap");
5951 let addr2 = map_memory_with_flags(
5952 ¤t_task,
5953 (addr_reserve + *PAGE_SIZE).unwrap(),
5954 *PAGE_SIZE,
5955 MAP_ANONYMOUS | MAP_SHARED | MAP_FIXED,
5956 );
5957 let state = mm.state.read();
5958 let (range1, _) = state.mappings.get(addr1).expect("mapping");
5959 assert_eq!(range1.start, addr1);
5960 assert_eq!(range1.end, (addr1 + *PAGE_SIZE).unwrap());
5961 let (range2, mapping2) = state.mappings.get(addr2).expect("mapping");
5962 assert_eq!(range2.start, addr2);
5963 assert_eq!(range2.end, (addr2 + *PAGE_SIZE).unwrap());
5964 let original_memory2 = {
5965 match state.get_mapping_backing(mapping2) {
5966 MappingBacking::Memory(backing) => {
5967 assert_eq!(backing.memory().get_size(), *PAGE_SIZE);
5968 backing.memory().clone()
5969 }
5970 MappingBacking::PrivateAnonymous => {
5971 panic!("Unexpected private anonymous mapping")
5972 }
5973 }
5974 };
5975 std::mem::drop(state);
5976
5977 assert_eq!(mm.unmap(addr1, *PAGE_SIZE as usize), Ok(()));
5978
5979 let state = mm.state.read();
5980
5981 assert!(state.mappings.get(addr1).is_none());
5983
5984 let (range2, mapping2) = state.mappings.get(addr2).expect("second page");
5986 assert_eq!(range2.start, addr2);
5987 assert_eq!(range2.end, (addr2 + *PAGE_SIZE).unwrap());
5988 match state.get_mapping_backing(mapping2) {
5989 MappingBacking::Memory(backing) => {
5990 assert_eq!(backing.memory().get_size(), *PAGE_SIZE);
5991 assert_eq!(original_memory2.get_koid(), backing.memory().get_koid());
5992 }
5993 MappingBacking::PrivateAnonymous => panic!("Unexpected private anonymous mapping"),
5994 }
5995 })
5996 .await;
5997 }
5998
5999 #[::fuchsia::test]
6000 async fn test_read_write_objects() {
6001 spawn_kernel_and_run(async |current_task| {
6002 let ma = current_task.deref();
6003 let addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
6004 let items_ref = UserRef::<i32>::new(addr);
6005
6006 let items_written = vec![0, 2, 3, 7, 1];
6007 ma.write_objects(items_ref, &items_written).expect("Failed to write object array.");
6008
6009 let items_read = ma
6010 .read_objects_to_vec(items_ref, items_written.len())
6011 .expect("Failed to read object array.");
6012
6013 assert_eq!(items_written, items_read);
6014 })
6015 .await;
6016 }
6017
6018 #[::fuchsia::test]
6019 async fn test_read_write_objects_null() {
6020 spawn_kernel_and_run(async |current_task| {
6021 let ma = current_task.deref();
6022 let items_ref = UserRef::<i32>::new(UserAddress::default());
6023
6024 let items_written = vec![];
6025 ma.write_objects(items_ref, &items_written)
6026 .expect("Failed to write empty object array.");
6027
6028 let items_read = ma
6029 .read_objects_to_vec(items_ref, items_written.len())
6030 .expect("Failed to read empty object array.");
6031
6032 assert_eq!(items_written, items_read);
6033 })
6034 .await;
6035 }
6036
6037 #[::fuchsia::test]
6038 async fn test_read_object_partial() {
6039 #[derive(Debug, Default, Copy, Clone, KnownLayout, FromBytes, Immutable, PartialEq)]
6040 struct Items {
6041 val: [i32; 4],
6042 }
6043
6044 spawn_kernel_and_run(async |current_task| {
6045 let ma = current_task.deref();
6046 let addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
6047 let items_array_ref = UserRef::<i32>::new(addr);
6048
6049 let items_written = vec![75, 23, 51, 98];
6051 ma.write_objects(items_array_ref, &items_written)
6052 .expect("Failed to write object array.");
6053
6054 let items_ref = UserRef::<Items>::new(addr);
6056 let items_read = ma
6057 .read_object_partial(items_ref, std::mem::size_of::<Items>())
6058 .expect("Failed to read object");
6059 assert_eq!(items_written, items_read.val);
6060
6061 let items_read = ma.read_object_partial(items_ref, 8).expect("Failed to read object");
6063 assert_eq!(vec![75, 23, 0, 0], items_read.val);
6064
6065 let items_read = ma.read_object_partial(items_ref, 0).expect("Failed to read object");
6068 assert_eq!(vec![0, 0, 0, 0], items_read.val);
6069
6070 assert_eq!(
6072 ma.read_object_partial(items_ref, std::mem::size_of::<Items>() + 8),
6073 error!(EINVAL)
6074 );
6075
6076 assert_eq!(
6078 ma.read_object_partial(UserRef::<Items>::new(UserAddress::from(1)), 16),
6079 error!(EFAULT)
6080 );
6081 })
6082 .await;
6083 }
6084
6085 #[::fuchsia::test]
6086 async fn test_partial_read() {
6087 spawn_kernel_and_run(async |current_task| {
6088 let mm = current_task.mm().unwrap();
6089 let ma = current_task.deref();
6090
6091 let addr = mm.state.read().find_next_unused_range(2 * *PAGE_SIZE as usize).unwrap();
6092 let addr = map_memory(¤t_task, addr, *PAGE_SIZE);
6093 let second_map = map_memory(¤t_task, (addr + *PAGE_SIZE).unwrap(), *PAGE_SIZE);
6094
6095 let bytes = vec![0xf; (*PAGE_SIZE * 2) as usize];
6096 assert!(ma.write_memory(addr, &bytes).is_ok());
6097 let mut state = mm.state.write();
6098 let mut released_mappings = ReleasedMappings::default();
6099 state
6100 .protect(
6101 ma,
6102 second_map,
6103 *PAGE_SIZE as usize,
6104 ProtectionFlags::empty(),
6105 &mut released_mappings,
6106 )
6107 .unwrap();
6108 released_mappings.finalize(state);
6109 assert_eq!(
6110 ma.read_memory_partial_to_vec(addr, bytes.len()).unwrap().len(),
6111 *PAGE_SIZE as usize,
6112 );
6113 })
6114 .await;
6115 }
6116
6117 fn map_memory_growsdown(current_task: &CurrentTask, length: u64) -> UserAddress {
6118 map_memory_with_flags(
6119 current_task,
6120 UserAddress::default(),
6121 length,
6122 MAP_ANONYMOUS | MAP_PRIVATE | MAP_GROWSDOWN,
6123 )
6124 }
6125
6126 #[::fuchsia::test]
6127 async fn test_grow_mapping_empty_mm() {
6128 spawn_kernel_and_run(async |current_task| {
6129 let mm = current_task.mm().unwrap();
6130
6131 let addr = UserAddress::from(0x100000);
6132
6133 assert_matches!(mm.extend_growsdown_mapping_to_address(addr, false), Ok(false));
6134 })
6135 .await;
6136 }
6137
6138 #[::fuchsia::test]
6139 async fn test_grow_inside_mapping() {
6140 spawn_kernel_and_run(async |current_task| {
6141 let mm = current_task.mm().unwrap();
6142
6143 let addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
6144
6145 assert_matches!(mm.extend_growsdown_mapping_to_address(addr, false), Ok(false));
6146 })
6147 .await;
6148 }
6149
6150 #[::fuchsia::test]
6151 async fn test_grow_write_fault_inside_read_only_mapping() {
6152 spawn_kernel_and_run(async |current_task| {
6153 let mm = current_task.mm().unwrap();
6154
6155 let addr = do_mmap(
6156 ¤t_task,
6157 UserAddress::default(),
6158 *PAGE_SIZE as usize,
6159 PROT_READ,
6160 MAP_ANONYMOUS | MAP_PRIVATE,
6161 FdNumber::from_raw(-1),
6162 0,
6163 )
6164 .expect("Could not map memory");
6165
6166 assert_matches!(mm.extend_growsdown_mapping_to_address(addr, false), Ok(false));
6167 assert_matches!(mm.extend_growsdown_mapping_to_address(addr, true), Ok(false));
6168 })
6169 .await;
6170 }
6171
6172 #[::fuchsia::test]
6173 async fn test_grow_fault_inside_prot_none_mapping() {
6174 spawn_kernel_and_run(async |current_task| {
6175 let mm = current_task.mm().unwrap();
6176
6177 let addr = do_mmap(
6178 ¤t_task,
6179 UserAddress::default(),
6180 *PAGE_SIZE as usize,
6181 PROT_NONE,
6182 MAP_ANONYMOUS | MAP_PRIVATE,
6183 FdNumber::from_raw(-1),
6184 0,
6185 )
6186 .expect("Could not map memory");
6187
6188 assert_matches!(mm.extend_growsdown_mapping_to_address(addr, false), Ok(false));
6189 assert_matches!(mm.extend_growsdown_mapping_to_address(addr, true), Ok(false));
6190 })
6191 .await;
6192 }
6193
6194 #[::fuchsia::test]
6195 async fn test_grow_below_mapping() {
6196 spawn_kernel_and_run(async |current_task| {
6197 let mm = current_task.mm().unwrap();
6198
6199 let addr = map_memory_growsdown(¤t_task, *PAGE_SIZE) - *PAGE_SIZE;
6200
6201 assert_matches!(mm.extend_growsdown_mapping_to_address(addr.unwrap(), false), Ok(true));
6202 })
6203 .await;
6204 }
6205
6206 #[::fuchsia::test]
6207 async fn test_grow_above_mapping() {
6208 spawn_kernel_and_run(async |current_task| {
6209 let mm = current_task.mm().unwrap();
6210
6211 let addr = map_memory_growsdown(¤t_task, *PAGE_SIZE) + *PAGE_SIZE;
6212
6213 assert_matches!(
6214 mm.extend_growsdown_mapping_to_address(addr.unwrap(), false),
6215 Ok(false)
6216 );
6217 })
6218 .await;
6219 }
6220
6221 #[::fuchsia::test]
6222 async fn test_grow_write_fault_below_read_only_mapping() {
6223 spawn_kernel_and_run(async |current_task| {
6224 let mm = current_task.mm().unwrap();
6225
6226 let mapped_addr = map_memory_growsdown(¤t_task, *PAGE_SIZE);
6227
6228 mm.protect(¤t_task, mapped_addr, *PAGE_SIZE as usize, ProtectionFlags::READ)
6229 .unwrap();
6230
6231 assert_matches!(
6232 mm.extend_growsdown_mapping_to_address((mapped_addr - *PAGE_SIZE).unwrap(), true),
6233 Ok(false)
6234 );
6235
6236 assert_eq!(mm.get_mapping_count(), 1);
6237 })
6238 .await;
6239 }
6240
6241 #[::fuchsia::test]
6242 async fn test_snapshot_paged_memory() {
6243 use zx::sys::zx_page_request_command_t::ZX_PAGER_VMO_READ;
6244
6245 spawn_kernel_and_run(async |current_task| {
6246 let mm = current_task.mm().unwrap();
6247
6248 let port = Arc::new(zx::Port::create());
6249 let port_clone = port.clone();
6250 let pager =
6251 Arc::new(zx::Pager::create(zx::PagerOptions::empty()).expect("create failed"));
6252 let pager_clone = pager.clone();
6253
6254 const VMO_SIZE: u64 = 128 * 1024;
6255 let vmo = Arc::new(
6256 pager
6257 .create_vmo(zx::VmoOptions::RESIZABLE, &port, 1, VMO_SIZE)
6258 .expect("create_vmo failed"),
6259 );
6260 let vmo_clone = vmo.clone();
6261
6262 let thread = std::thread::spawn(move || {
6264 loop {
6265 let packet =
6266 port_clone.wait(zx::MonotonicInstant::INFINITE).expect("wait failed");
6267 match packet.contents() {
6268 zx::PacketContents::Pager(contents) => {
6269 if contents.command() == ZX_PAGER_VMO_READ {
6270 let range = contents.range();
6271 let source_vmo = zx::Vmo::create(range.end - range.start)
6272 .expect("create failed");
6273 pager_clone
6274 .supply_pages(&vmo_clone, range, &source_vmo, 0)
6275 .expect("supply_pages failed");
6276 }
6277 }
6278 zx::PacketContents::User(_) => break,
6279 _ => {}
6280 }
6281 }
6282 });
6283
6284 let child_vmo = vmo
6285 .create_child(zx::VmoChildOptions::SNAPSHOT_AT_LEAST_ON_WRITE, 0, VMO_SIZE)
6286 .unwrap();
6287
6288 vmo.write(b"foo", 0).expect("write failed");
6290
6291 let prot_flags = ProtectionFlags::READ | ProtectionFlags::WRITE;
6292 let addr = mm
6293 .map_memory(
6294 DesiredAddress::Any,
6295 Arc::new(MemoryObject::from(child_vmo)),
6296 0,
6297 VMO_SIZE as usize,
6298 prot_flags,
6299 MappingOptions::empty(),
6300 MappingName::None,
6301 )
6302 .expect("map failed");
6303
6304 let target = current_task.clone_task_for_test(0, None);
6305
6306 let buf = target.read_memory_to_vec(addr, 3).expect("read_memory failed");
6308 assert_eq!(buf, b"foo");
6309
6310 let buf = current_task.deref().read_memory_to_vec(addr, 3).expect("read_memory failed");
6311 assert_eq!(buf, b"foo");
6312
6313 port.queue(&zx::Packet::from_user_packet(0, 0, zx::UserPacket::from_u8_array([0; 32])))
6314 .unwrap();
6315 thread.join().unwrap();
6316 })
6317 .await;
6318 }
6319
6320 #[::fuchsia::test]
6321 async fn test_set_vma_name() {
6322 spawn_kernel_and_run(async |mut current_task| {
6323 let name_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
6324
6325 let vma_name = "vma name";
6326 current_task.write_memory(name_addr, vma_name.as_bytes()).unwrap();
6327
6328 let mapping_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
6329
6330 sys_prctl(
6331 &mut current_task,
6332 PR_SET_VMA,
6333 PR_SET_VMA_ANON_NAME as u64,
6334 mapping_addr.ptr() as u64,
6335 *PAGE_SIZE,
6336 name_addr.ptr() as u64,
6337 )
6338 .unwrap();
6339
6340 assert_eq!(
6341 *current_task.mm().unwrap().get_mapping_name(mapping_addr).unwrap().unwrap(),
6342 vma_name
6343 );
6344 })
6345 .await;
6346 }
6347
6348 #[::fuchsia::test]
6349 async fn test_set_vma_name_adjacent_mappings() {
6350 spawn_kernel_and_run(async |mut current_task| {
6351 let name_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
6352 current_task
6353 .write_memory(name_addr, CString::new("foo").unwrap().as_bytes_with_nul())
6354 .unwrap();
6355
6356 let first_mapping_addr =
6357 map_memory(¤t_task, UserAddress::default(), 2 * *PAGE_SIZE);
6358 let second_mapping_addr = map_memory_with_flags(
6359 ¤t_task,
6360 (first_mapping_addr + *PAGE_SIZE).unwrap(),
6361 *PAGE_SIZE,
6362 MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
6363 );
6364
6365 assert_eq!((first_mapping_addr + *PAGE_SIZE).unwrap(), second_mapping_addr);
6366
6367 sys_prctl(
6368 &mut current_task,
6369 PR_SET_VMA,
6370 PR_SET_VMA_ANON_NAME as u64,
6371 first_mapping_addr.ptr() as u64,
6372 2 * *PAGE_SIZE,
6373 name_addr.ptr() as u64,
6374 )
6375 .unwrap();
6376
6377 {
6378 let mm = current_task.mm().unwrap();
6379 let state = mm.state.read();
6380
6381 let (_, mapping) = state.mappings.get(first_mapping_addr).unwrap();
6383 assert_eq!(mapping.name(), MappingName::Vma("foo".into()));
6384
6385 let (_, mapping) = state.mappings.get(second_mapping_addr).unwrap();
6386 assert_eq!(mapping.name(), MappingName::Vma("foo".into()));
6387 }
6388 })
6389 .await;
6390 }
6391
6392 #[::fuchsia::test]
6393 async fn test_set_vma_name_beyond_end() {
6394 spawn_kernel_and_run(async |mut current_task| {
6395 let name_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
6396 current_task
6397 .write_memory(name_addr, CString::new("foo").unwrap().as_bytes_with_nul())
6398 .unwrap();
6399
6400 let mapping_addr = map_memory(¤t_task, UserAddress::default(), 2 * *PAGE_SIZE);
6401
6402 let second_page = (mapping_addr + *PAGE_SIZE).unwrap();
6403 current_task.mm().unwrap().unmap(second_page, *PAGE_SIZE as usize).unwrap();
6404
6405 assert_eq!(
6407 sys_prctl(
6408 &mut current_task,
6409 PR_SET_VMA,
6410 PR_SET_VMA_ANON_NAME as u64,
6411 mapping_addr.ptr() as u64,
6412 2 * *PAGE_SIZE,
6413 name_addr.ptr() as u64,
6414 ),
6415 error!(ENOMEM)
6416 );
6417
6418 {
6420 let mm = current_task.mm().unwrap();
6421 let state = mm.state.read();
6422
6423 let (_, mapping) = state.mappings.get(mapping_addr).unwrap();
6424 assert_eq!(mapping.name(), MappingName::Vma("foo".into()));
6425 }
6426 })
6427 .await;
6428 }
6429
6430 #[::fuchsia::test]
6431 async fn test_set_vma_name_before_start() {
6432 spawn_kernel_and_run(async |mut current_task| {
6433 let name_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
6434 current_task
6435 .write_memory(name_addr, CString::new("foo").unwrap().as_bytes_with_nul())
6436 .unwrap();
6437
6438 let mapping_addr = map_memory(¤t_task, UserAddress::default(), 2 * *PAGE_SIZE);
6439
6440 let second_page = (mapping_addr + *PAGE_SIZE).unwrap();
6441 current_task.mm().unwrap().unmap(mapping_addr, *PAGE_SIZE as usize).unwrap();
6442
6443 assert_eq!(
6445 sys_prctl(
6446 &mut current_task,
6447 PR_SET_VMA,
6448 PR_SET_VMA_ANON_NAME as u64,
6449 mapping_addr.ptr() as u64,
6450 2 * *PAGE_SIZE,
6451 name_addr.ptr() as u64,
6452 ),
6453 error!(ENOMEM)
6454 );
6455
6456 {
6459 let mm = current_task.mm().unwrap();
6460 let state = mm.state.read();
6461
6462 let (_, mapping) = state.mappings.get(second_page).unwrap();
6463 assert_eq!(mapping.name(), MappingName::None);
6464 }
6465 })
6466 .await;
6467 }
6468
6469 #[::fuchsia::test]
6470 async fn test_set_vma_name_partial() {
6471 spawn_kernel_and_run(async |mut current_task| {
6472 let name_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
6473 current_task
6474 .write_memory(name_addr, CString::new("foo").unwrap().as_bytes_with_nul())
6475 .unwrap();
6476
6477 let mapping_addr = map_memory(¤t_task, UserAddress::default(), 3 * *PAGE_SIZE);
6478
6479 assert_eq!(
6480 sys_prctl(
6481 &mut current_task,
6482 PR_SET_VMA,
6483 PR_SET_VMA_ANON_NAME as u64,
6484 (mapping_addr + *PAGE_SIZE).unwrap().ptr() as u64,
6485 *PAGE_SIZE,
6486 name_addr.ptr() as u64,
6487 ),
6488 Ok(starnix_syscalls::SUCCESS)
6489 );
6490
6491 {
6493 let mm = current_task.mm().unwrap();
6494 let state = mm.state.read();
6495
6496 let (_, mapping) = state.mappings.get(mapping_addr).unwrap();
6497 assert_eq!(mapping.name(), MappingName::None);
6498
6499 let (_, mapping) =
6500 state.mappings.get((mapping_addr + *PAGE_SIZE).unwrap()).unwrap();
6501 assert_eq!(mapping.name(), MappingName::Vma("foo".into()));
6502
6503 let (_, mapping) =
6504 state.mappings.get((mapping_addr + (2 * *PAGE_SIZE)).unwrap()).unwrap();
6505 assert_eq!(mapping.name(), MappingName::None);
6506 }
6507 })
6508 .await;
6509 }
6510
6511 #[::fuchsia::test]
6512 async fn test_preserve_name_snapshot() {
6513 spawn_kernel_and_run(async |mut current_task| {
6514 let name_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
6515 current_task
6516 .write_memory(name_addr, CString::new("foo").unwrap().as_bytes_with_nul())
6517 .unwrap();
6518
6519 let mapping_addr = map_memory(¤t_task, UserAddress::default(), *PAGE_SIZE);
6520
6521 assert_eq!(
6522 sys_prctl(
6523 &mut current_task,
6524 PR_SET_VMA,
6525 PR_SET_VMA_ANON_NAME as u64,
6526 mapping_addr.ptr() as u64,
6527 *PAGE_SIZE,
6528 name_addr.ptr() as u64,
6529 ),
6530 Ok(starnix_syscalls::SUCCESS)
6531 );
6532
6533 let target = current_task.clone_task_for_test(0, None);
6534
6535 {
6536 let mm = target.mm().unwrap();
6537 let state = mm.state.read();
6538
6539 let (_, mapping) = state.mappings.get(mapping_addr).unwrap();
6540 assert_eq!(mapping.name(), MappingName::Vma("foo".into()));
6541 }
6542 })
6543 .await;
6544 }
6545}