Skip to main content

starnix_core/mm/
memory_manager.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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, read_to_array,
14};
15use crate::security;
16use crate::signals::{SignalDetail, SignalInfo};
17use crate::task::{CurrentTask, ExceptionResult, PageFaultExceptionReport, Task};
18use crate::vfs::aio::AioContext;
19use crate::vfs::pseudo::dynamic_file::{
20    DynamicFile, DynamicFileBuf, DynamicFileSource, SequenceFileSource,
21};
22use crate::vfs::{FsString, NamespaceNode};
23use anyhow::{Error, anyhow};
24use bitflags::bitflags;
25use flyweights::FlyByteStr;
26use linux_uapi::BUS_ADRERR;
27use memory_pinning::PinnedMapping;
28use range_map::RangeMap;
29use smallvec::SmallVec;
30use starnix_ext::map_ext::EntryExt;
31use starnix_lifecycle::DropNotifier;
32use starnix_logging::{CATEGORY_STARNIX_MM, impossible_error, log_error, log_warn, track_stub};
33use starnix_sync::{LockDepMutex, MmDumpable, RwLock, RwLockWriteGuard, ordered_write_lock};
34use starnix_types::arch::ArchWidth;
35use starnix_types::futex_address::FutexAddress;
36use starnix_types::math::{round_down_to_system_page_size, round_up_to_system_page_size};
37use starnix_types::user_buffer::{UserBuffer, UserBuffers};
38use starnix_uapi::auth::CAP_IPC_LOCK;
39use starnix_uapi::errors::Errno;
40use starnix_uapi::file_mode::Access;
41use starnix_uapi::range_ext::RangeExt;
42use starnix_uapi::resource_limits::Resource;
43use starnix_uapi::restricted_aspace::{
44    RESTRICTED_ASPACE_BASE, RESTRICTED_ASPACE_HIGHEST_ADDRESS, RESTRICTED_ASPACE_RANGE,
45    RESTRICTED_ASPACE_SIZE,
46};
47use starnix_uapi::signals::{SIGBUS, SIGSEGV};
48use starnix_uapi::user_address::{ArchSpecific, UserAddress};
49use starnix_uapi::{
50    MADV_COLD, MADV_COLLAPSE, MADV_DODUMP, MADV_DOFORK, MADV_DONTDUMP, MADV_DONTFORK,
51    MADV_DONTNEED, MADV_DONTNEED_LOCKED, MADV_FREE, MADV_HUGEPAGE, MADV_HWPOISON, MADV_KEEPONFORK,
52    MADV_MERGEABLE, MADV_NOHUGEPAGE, MADV_NORMAL, MADV_PAGEOUT, MADV_POPULATE_READ, MADV_RANDOM,
53    MADV_REMOVE, MADV_SEQUENTIAL, MADV_SOFT_OFFLINE, MADV_UNMERGEABLE, MADV_WILLNEED,
54    MADV_WIPEONFORK, MREMAP_DONTUNMAP, MREMAP_FIXED, MREMAP_MAYMOVE, errno, error,
55    from_status_like_fdio,
56};
57use std::collections::HashMap;
58use std::mem::MaybeUninit;
59use std::ops::{ControlFlow, Deref, DerefMut, Range, RangeBounds};
60use std::sync::{Arc, LazyLock, Weak};
61use syncio::zxio::zxio_default_maybe_faultable_copy;
62use zerocopy::IntoBytes;
63use zx::{Rights, VmoChildOptions};
64
65pub const ZX_VM_SPECIFIC_OVERWRITE: zx::VmarFlags =
66    zx::VmarFlags::from_bits_retain(zx::VmarFlagsExtended::SPECIFIC_OVERWRITE.bits());
67
68// We do not create shared processes in unit tests.
69pub(crate) const UNIFIED_ASPACES_ENABLED: bool = cfg!(not(test));
70
71/// Initializes the usercopy utilities.
72///
73/// It is useful to explicitly call this so that the usercopy is initialized
74/// at a known instant. For example, Starnix may want to make sure the usercopy
75/// thread created to support user copying is associated to the Starnix process
76/// and not a restricted-mode process.
77pub fn init_usercopy() {
78    // This call lazily initializes the `Usercopy` instance.
79    let _ = usercopy();
80}
81
82thread_local! {
83    /// The last mapping generation seen by this thread.
84    /// Used to prevent infinite loops in page fault handling.
85    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
99/// Number of bits of entropy for processes running in 32 bits mode.
100const ASLR_32_RANDOM_BITS: usize = 8;
101
102// The biggest we expect stack to be; increase as needed
103// TODO(https://fxbug.dev/322874791): Once setting RLIMIT_STACK is implemented, we should use it.
104const MAX_STACK_SIZE: usize = 512 * 1024 * 1024;
105
106// Value to report temporarily as the VM RSS HWM.
107// TODO(https://fxbug.dev/396221597): Need support from the kernel to track the committed bytes high
108// water mark.
109const STUB_VM_RSS_HWM: usize = 2 * 1024 * 1024;
110
111fn usercopy() -> Option<&'static usercopy::Usercopy> {
112    static USERCOPY: LazyLock<Option<usercopy::Usercopy>> = LazyLock::new(|| {
113        // We do not create shared processes in unit tests.
114        if UNIFIED_ASPACES_ENABLED {
115            // ASUMPTION: All Starnix managed Linux processes have the same
116            // restricted mode address range.
117            Some(usercopy::Usercopy::new(RESTRICTED_ASPACE_RANGE).unwrap())
118        } else {
119            None
120        }
121    });
122
123    LazyLock::force(&USERCOPY).as_ref()
124}
125
126/// Provides an implementation for zxio's `zxio_maybe_faultable_copy` that supports
127/// catching faults.
128///
129/// See zxio's `zxio_maybe_faultable_copy` documentation for more details.
130///
131/// # Safety
132///
133/// Only one of `src`/`dest` may be an address to a buffer owned by user/restricted-mode
134/// (`ret_dest` indicates whether the user-owned buffer is `dest` when `true`).
135/// The other must be a valid Starnix/normal-mode buffer that will never cause a fault
136/// when the first `count` bytes are read/written.
137#[unsafe(no_mangle)]
138pub unsafe fn zxio_maybe_faultable_copy_impl(
139    dest: *mut u8,
140    src: *const u8,
141    count: usize,
142    ret_dest: bool,
143) -> bool {
144    if let Some(usercopy) = usercopy() {
145        #[allow(clippy::undocumented_unsafe_blocks, reason = "2024 edition migration")]
146        let ret = unsafe { usercopy.raw_hermetic_copy(dest, src, count, ret_dest) };
147        ret == count
148    } else {
149        #[allow(clippy::undocumented_unsafe_blocks, reason = "2024 edition migration")]
150        unsafe {
151            zxio_default_maybe_faultable_copy(dest, src, count, ret_dest)
152        }
153    }
154}
155
156pub static PAGE_SIZE: LazyLock<u64> = LazyLock::new(|| zx::system_get_page_size() as u64);
157
158bitflags! {
159    #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
160    pub struct MappingOptions: u16 {
161      const SHARED      = 1 << 0;
162      const ANONYMOUS   = 1 << 1;
163      const LOWER_32BIT = 1 << 2;
164      const GROWSDOWN   = 1 << 3;
165      const ELF_BINARY  = 1 << 4;
166      const DONTFORK    = 1 << 5;
167      const WIPEONFORK  = 1 << 6;
168      const DONT_SPLIT  = 1 << 7;
169      const DONT_EXPAND = 1 << 8;
170      const POPULATE    = 1 << 9;
171    }
172}
173
174bitflags! {
175    #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
176    pub struct MremapFlags: u32 {
177        const MAYMOVE = MREMAP_MAYMOVE;
178        const FIXED = MREMAP_FIXED;
179        const DONTUNMAP = MREMAP_DONTUNMAP;
180    }
181}
182
183bitflags! {
184    #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
185    pub struct MsyncFlags: u32 {
186        const ASYNC = starnix_uapi::MS_ASYNC;
187        const INVALIDATE = starnix_uapi::MS_INVALIDATE;
188        const SYNC = starnix_uapi::MS_SYNC;
189    }
190}
191
192const PROGRAM_BREAK_LIMIT: u64 = 64 * 1024 * 1024;
193
194#[derive(Debug, Clone, Eq, PartialEq)]
195struct ProgramBreak {
196    // These base address at which the data segment is mapped.
197    base: UserAddress,
198
199    // The current program break.
200    //
201    // The addresses from [base, current.round_up(*PAGE_SIZE)) are mapped into the
202    // client address space from the underlying |memory|.
203    current: UserAddress,
204}
205
206/// The policy about whether the address space can be dumped.
207#[derive(Debug, Clone, Copy, Eq, PartialEq)]
208pub enum DumpPolicy {
209    /// The address space cannot be dumped.
210    ///
211    /// Corresponds to SUID_DUMP_DISABLE.
212    Disable,
213
214    /// The address space can be dumped.
215    ///
216    /// Corresponds to SUID_DUMP_USER.
217    User,
218}
219
220// Supported types of membarriers.
221pub enum MembarrierType {
222    Memory,   // MEMBARRIER_CMD_GLOBAL, etc
223    SyncCore, // MEMBARRIER_CMD_..._SYNC_CORE
224}
225
226// Tracks the types of membarriers this address space is registered to receive.
227#[derive(Default, Clone)]
228struct MembarrierRegistrations {
229    memory: bool,
230    sync_core: bool,
231}
232
233#[derive(Default)]
234struct Mappings {
235    /// The mappings record which object backs each address.
236    map: RangeMap<UserAddress, Mapping>,
237
238    /// Generation counter for mappings. Incremented on any modification to `mappings`.
239    ///
240    /// This is used to detect stale mappings in `handle_page_fault`.
241    generation: u64,
242
243    /// The cached sum of the lengths of all mapped ranges.
244    total_usage: usize,
245}
246
247impl Deref for Mappings {
248    type Target = RangeMap<UserAddress, Mapping>;
249
250    fn deref(&self) -> &Self::Target {
251        &self.map
252    }
253}
254
255impl Mappings {
256    pub fn insert(&mut self, range: std::ops::Range<UserAddress>, value: Mapping) -> Vec<Mapping> {
257        self.generation = self.generation.wrapping_add(1);
258        let range_len = range.end - range.start;
259        let removed_len: usize = self
260            .map
261            .range(range.clone())
262            .map(|(r, _)| {
263                let intersection = r.intersect(&range);
264                intersection.end - intersection.start
265            })
266            .sum();
267        let removed = self.map.insert(range, value);
268        self.total_usage = self.total_usage.saturating_add(range_len).saturating_sub(removed_len);
269        removed
270    }
271
272    pub fn remove(&mut self, range: std::ops::Range<UserAddress>) -> Vec<Mapping> {
273        self.generation = self.generation.wrapping_add(1);
274        let removed_len: usize = self
275            .map
276            .range(range.clone())
277            .map(|(r, _)| {
278                let intersection = r.intersect(&range);
279                intersection.end - intersection.start
280            })
281            .sum();
282        let removed = self.map.remove(range);
283        self.total_usage = self.total_usage.saturating_sub(removed_len);
284        removed
285    }
286
287    pub fn append_non_overlapping(
288        &mut self,
289        range: std::ops::Range<UserAddress>,
290        value: Mapping,
291    ) -> bool {
292        self.generation = self.generation.wrapping_add(1);
293        let range_len = range.end - range.start;
294        if self.map.append_non_overlapping(range, value) {
295            self.total_usage = self.total_usage.saturating_add(range_len);
296            true
297        } else {
298            false
299        }
300    }
301
302    pub fn update_exact<F, E>(
303        &mut self,
304        range: &std::ops::Range<UserAddress>,
305        f: F,
306    ) -> Result<bool, E>
307    where
308        F: FnOnce(&mut Mapping) -> Result<(), E>,
309    {
310        self.generation = self.generation.wrapping_add(1);
311        self.map.update_exact(range, f)
312    }
313}
314
315pub struct MemoryManagerState {
316    /// The memory mappings currently used by this address space.
317    mappings: Mappings,
318
319    /// UserFaults registered with this memory manager.
320    userfaultfds: Vec<Weak<UserFault>>,
321
322    /// Shadow mappings for mlock()'d pages.
323    ///
324    /// Used for MlockPinFlavor::ShadowProcess to keep track of when we need to unmap
325    /// memory from the shadow process.
326    shadow_mappings_for_mlock: RangeMap<UserAddress, Arc<PinnedMapping>>,
327
328    forkable_state: MemoryManagerForkableState,
329}
330
331// 64k under the 4GB
332const LOWER_4GB_LIMIT: UserAddress = UserAddress::const_from(0xffff_0000);
333
334#[derive(Default, Clone)]
335pub struct MemoryManagerForkableState {
336    /// State for the brk and sbrk syscalls.
337    brk: Option<ProgramBreak>,
338
339    /// The namespace node that represents the executable associated with this task.
340    executable_node: Option<NamespaceNode>,
341
342    pub stack_size: usize,
343    pub stack_start: UserAddress,
344    pub auxv_start: UserAddress,
345    pub auxv_end: UserAddress,
346    pub argv_start: UserAddress,
347    pub argv_end: UserAddress,
348    pub environ_start: UserAddress,
349    pub environ_end: UserAddress,
350
351    /// vDSO location
352    pub vdso_base: UserAddress,
353
354    /// Randomized regions:
355    pub mmap_top: UserAddress,
356    pub stack_origin: UserAddress,
357    pub brk_origin: UserAddress,
358
359    // Membarrier registrations
360    membarrier_registrations: MembarrierRegistrations,
361}
362
363impl Deref for MemoryManagerState {
364    type Target = MemoryManagerForkableState;
365    fn deref(&self) -> &Self::Target {
366        &self.forkable_state
367    }
368}
369
370impl DerefMut for MemoryManagerState {
371    fn deref_mut(&mut self) -> &mut Self::Target {
372        &mut self.forkable_state
373    }
374}
375
376#[derive(Debug, Default)]
377struct ReleasedMappings {
378    doomed: Vec<Mapping>,
379    doomed_pins: Vec<Arc<PinnedMapping>>,
380}
381
382impl ReleasedMappings {
383    fn extend(&mut self, mappings: impl IntoIterator<Item = Mapping>) {
384        self.doomed.extend(mappings);
385    }
386
387    fn extend_pins(&mut self, mappings: impl IntoIterator<Item = Arc<PinnedMapping>>) {
388        self.doomed_pins.extend(mappings);
389    }
390
391    fn is_empty(&self) -> bool {
392        self.doomed.is_empty() && self.doomed_pins.is_empty()
393    }
394
395    #[cfg(test)]
396    fn len(&self) -> usize {
397        self.doomed.len() + self.doomed_pins.len()
398    }
399
400    fn finalize(&mut self, mm_state: RwLockWriteGuard<'_, MemoryManagerState>) {
401        // Drop the state before the unmapped mappings, since dropping a mapping may acquire a lock
402        // in `DirEntry`'s `drop`.
403        std::mem::drop(mm_state);
404        std::mem::take(&mut self.doomed);
405        std::mem::take(&mut self.doomed_pins);
406    }
407}
408
409impl Drop for ReleasedMappings {
410    fn drop(&mut self) {
411        assert!(self.is_empty(), "ReleasedMappings::finalize() must be called before drop");
412    }
413}
414
415fn map_in_vmar(
416    vmar: &zx::Vmar,
417    vmar_info: &zx::VmarInfo,
418    addr: SelectedAddress,
419    memory: &MemoryObject,
420    memory_offset: u64,
421    length: usize,
422    flags: MappingFlags,
423    populate: bool,
424) -> Result<(), Errno> {
425    let vmar_offset = addr.addr().checked_sub(vmar_info.base).ok_or_else(|| errno!(ENOMEM))?;
426    let vmar_extra_flags = match addr {
427        SelectedAddress::Fixed(_) => zx::VmarFlags::SPECIFIC,
428        SelectedAddress::FixedOverwrite(_) => ZX_VM_SPECIFIC_OVERWRITE,
429    };
430
431    if populate {
432        let op = if flags.contains(MappingFlags::WRITE) {
433            // Requires ZX_RIGHT_WRITEABLE which we should expect when the mapping is writeable.
434            zx::VmoOp::COMMIT
435        } else {
436            // When we don't expect to have ZX_RIGHT_WRITEABLE, fall back to a VMO op that doesn't
437            // need it.
438            zx::VmoOp::PREFETCH
439        };
440        fuchsia_trace::duration!(CATEGORY_STARNIX_MM, "MmapCommitPages");
441        let _ = memory.op_range(op, memory_offset, length as u64);
442        // "The mmap() call doesn't fail if the mapping cannot be populated."
443    }
444
445    let vmar_maybe_map_range = if populate && !vmar_extra_flags.contains(ZX_VM_SPECIFIC_OVERWRITE) {
446        zx::VmarFlags::MAP_RANGE
447    } else {
448        zx::VmarFlags::empty()
449    };
450    let vmar_flags = flags.access_flags().to_vmar_flags()
451        | zx::VmarFlags::ALLOW_FAULTS
452        | vmar_extra_flags
453        | vmar_maybe_map_range;
454
455    let map_result = memory.map_in_vmar(vmar, vmar_offset.ptr(), memory_offset, length, vmar_flags);
456    let mapped_addr = map_result.map_err(MemoryManager::get_errno_for_map_err)?;
457
458    let expected_addr = addr.addr().ptr();
459    debug_assert_eq!(
460        mapped_addr, expected_addr,
461        "Zircon mapped to a different address than requested!"
462    );
463
464    Ok(())
465}
466
467impl MemoryManagerState {
468    /// Returns occupied address ranges that intersect with the given range.
469    ///
470    /// An address range is "occupied" if (a) there is already a mapping in that range or (b) there
471    /// is a GROWSDOWN mapping <= 256 pages above that range. The 256 pages below a GROWSDOWN
472    /// mapping is the "guard region." The memory manager avoids mapping memory in the guard region
473    /// in some circumstances to preserve space for the GROWSDOWN mapping to grow down.
474    fn get_occupied_address_ranges<'a>(
475        &'a self,
476        subrange: &'a Range<UserAddress>,
477    ) -> impl Iterator<Item = Range<UserAddress>> + 'a {
478        let query_range = subrange.start
479            ..(subrange
480                .end
481                .saturating_add(*PAGE_SIZE as usize * GUARD_PAGE_COUNT_FOR_GROWSDOWN_MAPPINGS));
482        self.mappings.range(query_range).filter_map(|(range, mapping)| {
483            let occupied_range = mapping.inflate_to_include_guard_pages(range);
484            if occupied_range.start < subrange.end && subrange.start < occupied_range.end {
485                Some(occupied_range)
486            } else {
487                None
488            }
489        })
490    }
491
492    fn count_possible_placements(
493        &self,
494        length: usize,
495        subrange: &Range<UserAddress>,
496    ) -> Option<usize> {
497        let mut occupied_ranges = self.get_occupied_address_ranges(subrange);
498        let mut possible_placements = 0;
499        // If the allocation is placed at the first available address, every page that is left
500        // before the next mapping or the end of subrange is +1 potential placement.
501        let mut first_fill_end = subrange.start.checked_add(length)?;
502        while first_fill_end <= subrange.end {
503            let Some(mapping) = occupied_ranges.next() else {
504                possible_placements += (subrange.end - first_fill_end) / (*PAGE_SIZE as usize) + 1;
505                break;
506            };
507            if mapping.start >= first_fill_end {
508                possible_placements += (mapping.start - first_fill_end) / (*PAGE_SIZE as usize) + 1;
509            }
510            first_fill_end = mapping.end.checked_add(length)?;
511        }
512        Some(possible_placements)
513    }
514
515    fn pick_placement(
516        &self,
517        length: usize,
518        mut chosen_placement_idx: usize,
519        subrange: &Range<UserAddress>,
520    ) -> Option<UserAddress> {
521        let mut candidate =
522            Range { start: subrange.start, end: subrange.start.checked_add(length)? };
523        let mut occupied_ranges = self.get_occupied_address_ranges(subrange);
524        loop {
525            let Some(mapping) = occupied_ranges.next() else {
526                // No more mappings: treat the rest of the index as an offset.
527                let res =
528                    candidate.start.checked_add(chosen_placement_idx * *PAGE_SIZE as usize)?;
529                debug_assert!(res.checked_add(length)? <= subrange.end);
530                return Some(res);
531            };
532            if mapping.start < candidate.end {
533                // doesn't fit, skip
534                candidate = Range { start: mapping.end, end: mapping.end.checked_add(length)? };
535                continue;
536            }
537            let unused_space =
538                (mapping.start.ptr() - candidate.end.ptr()) / (*PAGE_SIZE as usize) + 1;
539            if unused_space > chosen_placement_idx {
540                // Chosen placement is within the range; treat the rest of the index as an offset.
541                let res =
542                    candidate.start.checked_add(chosen_placement_idx * *PAGE_SIZE as usize)?;
543                return Some(res);
544            }
545
546            // chosen address is further up, skip
547            chosen_placement_idx -= unused_space;
548            candidate = Range { start: mapping.end, end: mapping.end.checked_add(length)? };
549        }
550    }
551
552    fn find_random_unused_range(
553        &self,
554        length: usize,
555        subrange: &Range<UserAddress>,
556    ) -> Option<UserAddress> {
557        let possible_placements = self.count_possible_placements(length, subrange)?;
558        if possible_placements == 0 {
559            return None;
560        }
561        let chosen_placement_idx = rand::random_range(0..possible_placements);
562        self.pick_placement(length, chosen_placement_idx, subrange)
563    }
564
565    // Find the first unused range of addresses that fits a mapping of `length` bytes, searching
566    // from `mmap_top` downwards.
567    pub fn find_next_unused_range(&self, length: usize) -> Option<UserAddress> {
568        let gap_size = length as u64;
569        let mut upper_bound = self.mmap_top;
570
571        loop {
572            let gap_end = self.mappings.find_gap_end(gap_size, &upper_bound);
573            let candidate = gap_end.checked_sub(length)?;
574
575            // Is there a next mapping? If not, the candidate is already good.
576            let Some((occupied_range, mapping)) = self.mappings.get(gap_end) else {
577                return Some(candidate);
578            };
579            let occupied_range = mapping.inflate_to_include_guard_pages(occupied_range);
580            // If it doesn't overlap, the gap is big enough to fit.
581            if occupied_range.start >= gap_end {
582                return Some(candidate);
583            }
584            // If there was a mapping in the way, use the start of that range as the upper bound.
585            upper_bound = occupied_range.start;
586        }
587    }
588
589    // Accept the hint if the range is unused and within the range available for mapping.
590    fn is_hint_acceptable(&self, hint_addr: UserAddress, length: usize) -> bool {
591        let Some(hint_end) = hint_addr.checked_add(length) else {
592            return false;
593        };
594        if !RESTRICTED_ASPACE_RANGE.contains(&hint_addr.ptr())
595            || !RESTRICTED_ASPACE_RANGE.contains(&hint_end.ptr())
596        {
597            return false;
598        };
599        self.get_occupied_address_ranges(&(hint_addr..hint_end)).next().is_none()
600    }
601
602    fn select_address(
603        &self,
604        addr: DesiredAddress,
605        length: usize,
606        flags: MappingFlags,
607    ) -> Result<SelectedAddress, Errno> {
608        let adjusted_length = round_up_to_system_page_size(length).or_else(|_| error!(ENOMEM))?;
609
610        let find_address = || -> Result<SelectedAddress, Errno> {
611            let new_addr = if flags.contains(MappingFlags::LOWER_32BIT) {
612                // MAP_32BIT specifies that the memory allocated will
613                // be within the first 2 GB of the process address space.
614                self.find_random_unused_range(
615                    adjusted_length,
616                    &(UserAddress::from_ptr(RESTRICTED_ASPACE_BASE)
617                        ..UserAddress::from_ptr(0x80000000)),
618                )
619                .ok_or_else(|| errno!(ENOMEM))?
620            } else {
621                self.find_next_unused_range(adjusted_length).ok_or_else(|| errno!(ENOMEM))?
622            };
623
624            Ok(SelectedAddress::Fixed(new_addr))
625        };
626
627        Ok(match addr {
628            DesiredAddress::Any => find_address()?,
629            DesiredAddress::Hint(hint_addr) => {
630                // Round down to page size
631                let hint_addr =
632                    UserAddress::from_ptr(hint_addr.ptr() - hint_addr.ptr() % *PAGE_SIZE as usize);
633                if self.is_hint_acceptable(hint_addr, adjusted_length) {
634                    SelectedAddress::Fixed(hint_addr)
635                } else {
636                    find_address()?
637                }
638            }
639            DesiredAddress::Fixed(addr) => SelectedAddress::Fixed(addr),
640            DesiredAddress::FixedOverwrite(addr) => SelectedAddress::FixedOverwrite(addr),
641        })
642    }
643
644    fn validate_addr(&self, addr: DesiredAddress, length: usize) -> Result<(), Errno> {
645        if length > RESTRICTED_ASPACE_SIZE {
646            return error!(ENOMEM);
647        }
648        match addr {
649            DesiredAddress::Fixed(a) | DesiredAddress::FixedOverwrite(a) => {
650                let end = a.checked_add(length).ok_or_else(|| errno!(ENOMEM))?;
651                if end > UserAddress::from_ptr(RESTRICTED_ASPACE_HIGHEST_ADDRESS as usize) {
652                    return error!(ENOMEM);
653                }
654                if self.check_has_unauthorized_splits(a, length) {
655                    return error!(ENOMEM);
656                }
657            }
658            _ => {}
659        }
660        Ok(())
661    }
662
663    fn add_memory_mapping(
664        &mut self,
665        mm: &Arc<MemoryManager>,
666        addr: DesiredAddress,
667        memory: Arc<MemoryObject>,
668        memory_offset: u64,
669        length: usize,
670        flags: MappingFlags,
671        max_access: Access,
672        populate: bool,
673        name: MappingName,
674        mapping_mode: MappingMode,
675        released_mappings: &mut ReleasedMappings,
676    ) -> Result<UserAddress, Errno> {
677        self.validate_addr(addr, length)?;
678
679        let selected_address = self.select_address(addr, length, flags)?;
680        let mapped_addr = selected_address.addr();
681        if mapping_mode == MappingMode::Eager {
682            mm.mapping_context.map_in_user_vmar(
683                selected_address,
684                &memory,
685                memory_offset,
686                length,
687                flags,
688                populate,
689            )?;
690        }
691
692        let end = (mapped_addr + length)?.round_up(*PAGE_SIZE)?;
693
694        if let DesiredAddress::FixedOverwrite(addr) = addr {
695            assert_eq!(addr, mapped_addr);
696            self.update_after_unmap(mm, addr, end - addr, released_mappings);
697        }
698
699        let mapping = Mapping::with_name(
700            self.create_memory_backing(mapped_addr, memory, memory_offset),
701            flags,
702            max_access,
703            name,
704            mapping_mode,
705        );
706        released_mappings.extend(self.mappings.insert(mapped_addr..end, mapping));
707
708        Ok(mapped_addr)
709    }
710
711    fn map_private_anonymous(
712        &mut self,
713        mm: &Arc<MemoryManager>,
714        addr: DesiredAddress,
715        length: usize,
716        prot_flags: ProtectionFlags,
717        options: MappingOptions,
718        populate: bool,
719        name: MappingName,
720        released_mappings: &mut ReleasedMappings,
721    ) -> Result<UserAddress, Errno> {
722        self.validate_addr(addr, length)?;
723
724        let flags = MappingFlags::from_access_flags_and_options(prot_flags, options);
725        let selected_addr = self.select_address(addr, length, flags)?;
726        let mapped_addr = selected_addr.addr();
727        let backing_memory_offset = selected_addr.addr().ptr();
728
729        mm.mapping_context.map_in_user_vmar(
730            selected_addr,
731            &mm.mapping_context.private_anonymous.backing,
732            backing_memory_offset as u64,
733            length,
734            flags,
735            populate,
736        )?;
737
738        let end = (mapped_addr + length)?.round_up(*PAGE_SIZE)?;
739        if let DesiredAddress::FixedOverwrite(addr) = addr {
740            assert_eq!(addr, mapped_addr);
741            self.update_after_unmap(mm, addr, end - addr, released_mappings);
742        }
743
744        let mapping = Mapping::new_private_anonymous(flags, name, MappingMode::Eager);
745        released_mappings.extend(self.mappings.insert(mapped_addr..end, mapping));
746
747        Ok(mapped_addr)
748    }
749
750    fn map_anonymous(
751        &mut self,
752        mm: &Arc<MemoryManager>,
753        addr: DesiredAddress,
754        length: usize,
755        prot_flags: ProtectionFlags,
756        options: MappingOptions,
757        name: MappingName,
758        released_mappings: &mut ReleasedMappings,
759    ) -> Result<UserAddress, Errno> {
760        if !options.contains(MappingOptions::SHARED) {
761            return self.map_private_anonymous(
762                mm,
763                addr,
764                length,
765                prot_flags,
766                options,
767                options.contains(MappingOptions::POPULATE),
768                name,
769                released_mappings,
770            );
771        }
772        let memory = create_anonymous_mapping_memory(length as u64)?;
773        let flags = MappingFlags::from_access_flags_and_options(prot_flags, options);
774        self.add_memory_mapping(
775            mm,
776            addr,
777            memory,
778            0,
779            length,
780            flags,
781            Access::rwx(),
782            options.contains(MappingOptions::POPULATE),
783            name,
784            MappingMode::Eager,
785            released_mappings,
786        )
787    }
788
789    fn any_ranges_lazy<I>(&self, ranges: I) -> bool
790    where
791        I: IntoIterator<Item = (UserAddress, Option<usize>)>,
792    {
793        for (addr, length) in ranges {
794            match length {
795                None => {
796                    if let Some((_, mapping)) = self.mappings.get(addr) {
797                        if mapping.mapping_mode() == MappingMode::Lazy {
798                            return true;
799                        }
800                    }
801                }
802                Some(len) => {
803                    assert!(len > 0);
804                    let end = addr.checked_add(len).expect("address overflowed after validation");
805                    if self
806                        .mappings
807                        .range(addr..end)
808                        .any(|(_, mapping)| mapping.mapping_mode() == MappingMode::Lazy)
809                    {
810                        return true;
811                    }
812                }
813            }
814        }
815        false
816    }
817
818    fn ensure_range_mapped_in_user_vmar(
819        &mut self,
820        addr: UserAddress,
821        length: Option<usize>,
822        context: &MappingContext,
823    ) -> Result<bool, Errno> {
824        self.ensure_ranges_mapped_in_user_vmar(std::iter::once((addr, length)), context)
825    }
826
827    fn ensure_ranges_mapped_in_user_vmar<I>(
828        &mut self,
829        ranges: I,
830        context: &MappingContext,
831    ) -> Result<bool, Errno>
832    where
833        I: IntoIterator<Item = (UserAddress, Option<usize>)>,
834    {
835        // This is most likely to contain one range, so use `SmallVec` to avoid
836        // heap allocation and better performance in the common case.
837        let mut ranges_to_update = SmallVec::<[std::ops::Range<UserAddress>; 1]>::new();
838        for (addr, length) in ranges {
839            match length {
840                None => {
841                    if let Some((range, mapping)) = self.mappings.get(addr) {
842                        if mapping.mapping_mode() == MappingMode::Lazy {
843                            ranges_to_update.push(range.clone());
844                        }
845                    }
846                }
847                Some(len) => {
848                    assert!(len > 0);
849                    let end = addr.checked_add(len).expect("address overflowed after validation");
850                    for (range, mapping) in self.mappings.range(addr..end) {
851                        if mapping.mapping_mode() == MappingMode::Lazy {
852                            ranges_to_update.push(range.clone());
853                        }
854                    }
855                }
856            }
857        }
858
859        if ranges_to_update.is_empty() {
860            return Ok(false);
861        }
862
863        for range in ranges_to_update {
864            let updated = self.mappings.update_exact(&range, |mapping| {
865                let addr = SelectedAddress::FixedOverwrite(range.start);
866                let flags = mapping.flags();
867                let (backing, backing_memory_offset) = match mapping.get_backing_internal() {
868                    MappingBacking::Memory(backing) => {
869                        (backing.memory(), backing.address_to_offset(addr.addr()))
870                    }
871                    MappingBacking::PrivateAnonymous => {
872                        (&context.private_anonymous.backing, addr.addr().ptr() as u64)
873                    }
874                };
875
876                let mapping_length = range.end - range.start;
877                context.map_in_user_vmar(
878                    addr,
879                    backing,
880                    backing_memory_offset,
881                    mapping_length,
882                    flags,
883                    false,
884                )?;
885
886                mapping.set_mapping_mode(MappingMode::Eager);
887                Ok(())
888            })?;
889            assert!(updated, "Expected to update exactly one mapping");
890        }
891
892        Ok(true)
893    }
894
895    fn remap(
896        &mut self,
897        _current_task: &CurrentTask,
898        mm: &Arc<MemoryManager>,
899        old_addr: UserAddress,
900        old_length: usize,
901        new_length: usize,
902        flags: MremapFlags,
903        new_addr: UserAddress,
904        released_mappings: &mut ReleasedMappings,
905    ) -> Result<UserAddress, Errno> {
906        // MREMAP_FIXED moves a mapping, which requires MREMAP_MAYMOVE.
907        if flags.contains(MremapFlags::FIXED) && !flags.contains(MremapFlags::MAYMOVE) {
908            return error!(EINVAL);
909        }
910
911        // MREMAP_DONTUNMAP is always a move, so it requires MREMAP_MAYMOVE.
912        // There is no resizing allowed either.
913        if flags.contains(MremapFlags::DONTUNMAP)
914            && (!flags.contains(MremapFlags::MAYMOVE) || old_length != new_length)
915        {
916            return error!(EINVAL);
917        }
918
919        // In-place copies are invalid.
920        if !flags.contains(MremapFlags::MAYMOVE) && old_length == 0 {
921            return error!(ENOMEM);
922        }
923
924        if new_length == 0 {
925            return error!(EINVAL);
926        }
927
928        // Make sure old_addr is page-aligned.
929        if !old_addr.is_aligned(*PAGE_SIZE) {
930            return error!(EINVAL);
931        }
932
933        let old_length = round_up_to_system_page_size(old_length)?;
934        let new_length = round_up_to_system_page_size(new_length)?;
935
936        if self.check_has_unauthorized_splits(old_addr, old_length) {
937            return error!(EINVAL);
938        }
939
940        if self.check_has_unauthorized_splits(new_addr, new_length) {
941            return error!(EINVAL);
942        }
943
944        if !flags.contains(MremapFlags::DONTUNMAP)
945            && !flags.contains(MremapFlags::FIXED)
946            && old_length != 0
947        {
948            // We are not requested to remap to a specific address, so first we see if we can remap
949            // in-place. In-place copies (old_length == 0) are not allowed.
950            if let Some(new_addr) =
951                self.try_remap_in_place(mm, old_addr, old_length, new_length, released_mappings)?
952            {
953                return Ok(new_addr);
954            }
955        }
956
957        // There is no space to grow in place, or there is an explicit request to move.
958        if flags.contains(MremapFlags::MAYMOVE) {
959            let dst_address =
960                if flags.contains(MremapFlags::FIXED) { Some(new_addr) } else { None };
961            self.remap_move(
962                mm,
963                old_addr,
964                old_length,
965                dst_address,
966                new_length,
967                flags.contains(MremapFlags::DONTUNMAP),
968                released_mappings,
969            )
970        } else {
971            error!(ENOMEM)
972        }
973    }
974
975    /// Attempts to grow or shrink the mapping in-place. Returns `Ok(Some(addr))` if the remap was
976    /// successful. Returns `Ok(None)` if there was no space to grow.
977    fn try_remap_in_place(
978        &mut self,
979        mm: &Arc<MemoryManager>,
980        old_addr: UserAddress,
981        old_length: usize,
982        new_length: usize,
983        released_mappings: &mut ReleasedMappings,
984    ) -> Result<Option<UserAddress>, Errno> {
985        let old_range = old_addr..old_addr.checked_add(old_length).ok_or_else(|| errno!(EINVAL))?;
986        let new_range_in_place =
987            old_addr..old_addr.checked_add(new_length).ok_or_else(|| errno!(EINVAL))?;
988
989        if new_length <= old_length {
990            // Shrink the mapping in-place, which should always succeed.
991            // This is done by unmapping the extraneous region.
992            if new_length != old_length {
993                self.unmap(mm, new_range_in_place.end, old_length - new_length, released_mappings)?;
994            }
995            return Ok(Some(old_addr));
996        }
997
998        if self.mappings.range(old_range.end..new_range_in_place.end).next().is_some() {
999            // There is some mapping in the growth range prevening an in-place growth.
1000            return Ok(None);
1001        }
1002
1003        // There is space to grow in-place. The old range must be one contiguous mapping.
1004        let (original_range, mapping) =
1005            self.mappings.get(old_addr).ok_or_else(|| errno!(EINVAL))?;
1006
1007        if old_range.end > original_range.end {
1008            return error!(EFAULT);
1009        }
1010        let original_range = original_range.clone();
1011        let original_mapping = mapping.clone();
1012
1013        // Compute the new length of the entire mapping once it has grown.
1014        let final_length = (original_range.end - original_range.start) + (new_length - old_length);
1015
1016        match self.get_mapping_backing(&original_mapping) {
1017            MappingBacking::Memory(backing) => {
1018                // Re-map the original range, which may include pages before the requested range.
1019                Ok(Some(self.add_memory_mapping(
1020                    mm,
1021                    DesiredAddress::FixedOverwrite(original_range.start),
1022                    backing.memory().clone(),
1023                    backing.address_to_offset(original_range.start),
1024                    final_length,
1025                    original_mapping.flags(),
1026                    original_mapping.max_access(),
1027                    false,
1028                    original_mapping.name().to_owned(),
1029                    original_mapping.mapping_mode(),
1030                    released_mappings,
1031                )?))
1032            }
1033            MappingBacking::PrivateAnonymous => {
1034                let growth_start = original_range.end;
1035                let growth_length = new_length - old_length;
1036                let final_end = (original_range.start + final_length)?;
1037                // Map new pages to back the growth.
1038                mm.mapping_context.map_in_user_vmar(
1039                    SelectedAddress::FixedOverwrite(growth_start),
1040                    &mm.mapping_context.private_anonymous.backing,
1041                    growth_start.ptr() as u64,
1042                    growth_length,
1043                    original_mapping.flags(),
1044                    false,
1045                )?;
1046                // Overwrite the mapping entry with the new larger size.
1047                released_mappings.extend(
1048                    self.mappings.insert(original_range.start..final_end, original_mapping.clone()),
1049                );
1050                Ok(Some(original_range.start))
1051            }
1052        }
1053    }
1054
1055    /// Grows or shrinks the mapping while moving it to a new destination.
1056    fn remap_move(
1057        &mut self,
1058        mm: &Arc<MemoryManager>,
1059        src_addr: UserAddress,
1060        src_length: usize,
1061        dst_addr: Option<UserAddress>,
1062        dst_length: usize,
1063        keep_source: bool,
1064        released_mappings: &mut ReleasedMappings,
1065    ) -> Result<UserAddress, Errno> {
1066        let src_range = src_addr..src_addr.checked_add(src_length).ok_or_else(|| errno!(EINVAL))?;
1067        let (original_range, src_mapping) =
1068            self.mappings.get(src_addr).ok_or_else(|| errno!(EINVAL))?;
1069        let original_range = original_range.clone();
1070        let src_mapping = src_mapping.clone();
1071
1072        if src_length == 0 && !src_mapping.flags().contains(MappingFlags::SHARED) {
1073            // src_length == 0 means that the mapping is to be copied. This behavior is only valid
1074            // with MAP_SHARED mappings.
1075            return error!(EINVAL);
1076        }
1077
1078        // If the destination range is smaller than the source range, we must first shrink
1079        // the source range in place. This must be done now and visible to processes, even if
1080        // a later failure causes the remap operation to fail.
1081        if src_length != 0 && src_length > dst_length {
1082            self.unmap(mm, (src_addr + dst_length)?, src_length - dst_length, released_mappings)?;
1083        }
1084
1085        let dst_addr_for_map = match dst_addr {
1086            None => DesiredAddress::Any,
1087            Some(dst_addr) => {
1088                // The mapping is being moved to a specific address.
1089                let dst_range =
1090                    dst_addr..(dst_addr.checked_add(dst_length).ok_or_else(|| errno!(EINVAL))?);
1091                if !src_range.intersect(&dst_range).is_empty() {
1092                    return error!(EINVAL);
1093                }
1094
1095                // The destination range must be unmapped. This must be done now and visible to
1096                // processes, even if a later failure causes the remap operation to fail.
1097                self.unmap(mm, dst_addr, dst_length, released_mappings)?;
1098
1099                DesiredAddress::Fixed(dst_addr)
1100            }
1101        };
1102
1103        // According to gVisor's aio_test, Linux checks for DONT_EXPAND after unmapping the dst
1104        // range.
1105        if dst_length > src_length && src_mapping.flags().contains(MappingFlags::DONT_EXPAND) {
1106            return error!(EFAULT);
1107        }
1108
1109        if src_range.end > original_range.end {
1110            // The source range is not one contiguous mapping. This check must be done only after
1111            // the source range is shrunk and the destination unmapped.
1112            return error!(EFAULT);
1113        }
1114
1115        match self.get_mapping_backing(&src_mapping) {
1116            MappingBacking::PrivateAnonymous => {
1117                let dst_addr =
1118                    self.select_address(dst_addr_for_map, dst_length, src_mapping.flags())?.addr();
1119                let dst_end = (dst_addr + dst_length)?;
1120
1121                let length_to_move = std::cmp::min(dst_length, src_length) as u64;
1122                let growth_start_addr = (dst_addr + length_to_move)?;
1123
1124                if dst_addr != src_addr {
1125                    let src_move_end = (src_range.start + length_to_move)?;
1126                    let range_to_move = src_range.start..src_move_end;
1127                    // Move the previously mapped pages into their new location.
1128                    mm.mapping_context.private_anonymous.move_pages(&range_to_move, dst_addr)?;
1129                }
1130
1131                // Userfault registration is not preserved by remap
1132                let new_flags =
1133                    src_mapping.flags().difference(MappingFlags::UFFD | MappingFlags::UFFD_MISSING);
1134                if src_mapping.mapping_mode() == MappingMode::Eager {
1135                    mm.mapping_context.map_in_user_vmar(
1136                        SelectedAddress::FixedOverwrite(dst_addr),
1137                        &mm.mapping_context.private_anonymous.backing,
1138                        dst_addr.ptr() as u64,
1139                        dst_length,
1140                        new_flags,
1141                        false,
1142                    )?;
1143
1144                    if dst_length > src_length {
1145                        // The mapping has grown, map new pages in to cover the growth.
1146                        let growth_length = dst_length - src_length;
1147
1148                        self.map_private_anonymous(
1149                            mm,
1150                            DesiredAddress::FixedOverwrite(growth_start_addr),
1151                            growth_length,
1152                            new_flags.access_flags(),
1153                            new_flags.options(),
1154                            false,
1155                            src_mapping.name().to_owned(),
1156                            released_mappings,
1157                        )?;
1158                    }
1159                }
1160
1161                released_mappings.extend(self.mappings.insert(
1162                    dst_addr..dst_end,
1163                    Mapping::new_private_anonymous(
1164                        new_flags,
1165                        src_mapping.name().to_owned(),
1166                        src_mapping.mapping_mode(),
1167                    ),
1168                ));
1169
1170                if dst_addr != src_addr && src_length != 0 && !keep_source {
1171                    self.unmap(mm, src_addr, src_length, released_mappings)?;
1172                }
1173
1174                return Ok(dst_addr);
1175            }
1176            MappingBacking::Memory(backing) => {
1177                // This mapping is backed by an FD or is a shared anonymous mapping. Just map the
1178                // range of the memory object covering the moved pages. If the memory object already
1179                // had COW semantics, this preserves them.
1180                let (dst_memory_offset, memory) =
1181                    (backing.address_to_offset(src_addr), backing.memory().clone());
1182
1183                let new_address = self.add_memory_mapping(
1184                    mm,
1185                    dst_addr_for_map,
1186                    memory,
1187                    dst_memory_offset,
1188                    dst_length,
1189                    src_mapping.flags(),
1190                    src_mapping.max_access(),
1191                    false,
1192                    src_mapping.name().to_owned(),
1193                    src_mapping.mapping_mode(),
1194                    released_mappings,
1195                )?;
1196
1197                if src_length != 0 && !keep_source {
1198                    // Only unmap the source range if this is not a copy and if there was not a specific
1199                    // request to not unmap. It was checked earlier that in case of src_length == 0
1200                    // this mapping is MAP_SHARED.
1201                    self.unmap(mm, src_addr, src_length, released_mappings)?;
1202                }
1203
1204                return Ok(new_address);
1205            }
1206        };
1207    }
1208
1209    // Checks if an operation may be performed over the target mapping that may
1210    // result in a split mapping.
1211    //
1212    // An operation may be forbidden if the target mapping only partially covers
1213    // an existing mapping with the `MappingOptions::DONT_SPLIT` flag set.
1214    fn check_has_unauthorized_splits(&self, addr: UserAddress, length: usize) -> bool {
1215        let query_range = addr..addr.saturating_add(length);
1216        let mut intersection = self.mappings.range(query_range.clone());
1217
1218        // A mapping is not OK if it disallows splitting and the target range
1219        // does not fully cover the mapping range.
1220        let check_if_mapping_has_unauthorized_split =
1221            |mapping: Option<(&Range<UserAddress>, &Mapping)>| {
1222                mapping.is_some_and(|(mapping_range, mapping)| {
1223                    mapping.flags().contains(MappingFlags::DONT_SPLIT)
1224                        && (mapping_range.start < query_range.start
1225                            || query_range.end < mapping_range.end)
1226                })
1227            };
1228
1229        // We only check the first and last mappings in the range because naturally,
1230        // the mappings in the middle are fully covered by the target mapping and
1231        // won't be split.
1232        check_if_mapping_has_unauthorized_split(intersection.next())
1233            || check_if_mapping_has_unauthorized_split(intersection.next_back())
1234    }
1235
1236    /// Unmaps the specified range. Unmapped mappings are placed in `released_mappings`.
1237    fn unmap(
1238        &mut self,
1239        mm: &Arc<MemoryManager>,
1240        addr: UserAddress,
1241        length: usize,
1242        released_mappings: &mut ReleasedMappings,
1243    ) -> Result<(), Errno> {
1244        if !addr.is_aligned(*PAGE_SIZE) {
1245            return error!(EINVAL);
1246        }
1247        let length = round_up_to_system_page_size(length)?;
1248        if length == 0 {
1249            return error!(EINVAL);
1250        }
1251
1252        if self.check_has_unauthorized_splits(addr, length) {
1253            return error!(EINVAL);
1254        }
1255
1256        // Unmap the range, including the the tail of any range that would have been split. This
1257        // operation is safe because we're operating on another process.
1258        #[allow(
1259            clippy::undocumented_unsafe_blocks,
1260            reason = "Force documented unsafe blocks in Starnix"
1261        )]
1262        match unsafe { mm.mapping_context.user_vmar.unmap(addr.ptr(), length) } {
1263            Ok(_) => (),
1264            Err(zx::Status::NOT_FOUND) => (),
1265            Err(zx::Status::INVALID_ARGS) => return error!(EINVAL),
1266            Err(status) => {
1267                impossible_error(status);
1268            }
1269        };
1270
1271        self.update_after_unmap(mm, addr, length, released_mappings);
1272
1273        Ok(())
1274    }
1275
1276    // Updates `self.mappings` after the specified range was unmaped.
1277    //
1278    // The range to unmap can span multiple mappings, and can split mappings if
1279    // the range start or end falls in the middle of a mapping.
1280    //
1281    // Private anonymous memory is contained in the same memory object; The pages of that object
1282    // that are no longer reachable should be released.
1283    //
1284    // File-backed mappings don't need to have their memory object modified.
1285    //
1286    // Unmapped mappings are placed in `released_mappings`.
1287    fn update_after_unmap(
1288        &mut self,
1289        mm: &Arc<MemoryManager>,
1290        addr: UserAddress,
1291        length: usize,
1292        released_mappings: &mut ReleasedMappings,
1293    ) {
1294        let end_addr = addr.checked_add(length).expect("address overflow during unmap");
1295        let unmap_range = addr..end_addr;
1296
1297        // Remove any shadow mappings for mlock()'d pages that are now unmapped.
1298        released_mappings.extend_pins(self.shadow_mappings_for_mlock.remove(unmap_range.clone()));
1299
1300        for (range, mapping) in self.mappings.range(unmap_range.clone()) {
1301            // Deallocate any pages in the private, anonymous backing that are now unreachable.
1302            if let MappingBacking::PrivateAnonymous = self.get_mapping_backing(mapping) {
1303                let unmapped_range = &unmap_range.intersect(range);
1304
1305                if let Err(e) = mm
1306                    .inflight_vmspliced_payloads
1307                    .handle_unmapping(&mm.mapping_context.private_anonymous.backing, unmapped_range)
1308                {
1309                    log_error!("Failed to handle vmsplice unmapping: {:?}", e);
1310                }
1311
1312                if let Err(e) = mm
1313                    .mapping_context
1314                    .private_anonymous
1315                    .zero(unmapped_range.start, unmapped_range.end - unmapped_range.start)
1316                {
1317                    log_error!("Failed to zero private anonymous memory: {:?}", e);
1318                }
1319            }
1320        }
1321        released_mappings.extend(self.mappings.remove(unmap_range));
1322    }
1323
1324    fn protect(
1325        &mut self,
1326        current_task: &CurrentTask,
1327        addr: UserAddress,
1328        length: usize,
1329        prot_flags: ProtectionFlags,
1330        released_mappings: &mut ReleasedMappings,
1331    ) -> Result<(), Errno> {
1332        let vmar_flags = prot_flags.to_vmar_flags();
1333        let page_size = *PAGE_SIZE;
1334        let end = addr.checked_add(length).ok_or_else(|| errno!(EINVAL))?.round_up(page_size)?;
1335
1336        if self.check_has_unauthorized_splits(addr, length) {
1337            return error!(EINVAL);
1338        }
1339
1340        let prot_range = if prot_flags.contains(ProtectionFlags::GROWSDOWN) {
1341            let mut start = addr;
1342            let Some((range, mapping)) = self.mappings.get(start) else {
1343                return error!(EINVAL);
1344            };
1345            // Ensure that the mapping has GROWSDOWN if PROT_GROWSDOWN was specified.
1346            if !mapping.flags().contains(MappingFlags::GROWSDOWN) {
1347                return error!(EINVAL);
1348            }
1349            let access_flags = mapping.flags().access_flags();
1350            // From <https://man7.org/linux/man-pages/man2/mprotect.2.html>:
1351            //
1352            //   PROT_GROWSDOWN
1353            //     Apply the protection mode down to the beginning of a
1354            //     mapping that grows downward (which should be a stack
1355            //     segment or a segment mapped with the MAP_GROWSDOWN flag
1356            //     set).
1357            start = range.start;
1358            while let Some((range, mapping)) =
1359                self.mappings.get(start.saturating_sub(page_size as usize))
1360            {
1361                if !mapping.flags().contains(MappingFlags::GROWSDOWN)
1362                    || mapping.flags().access_flags() != access_flags
1363                {
1364                    break;
1365                }
1366                start = range.start;
1367            }
1368            start..end
1369        } else {
1370            addr..end
1371        };
1372
1373        let mut range_list = vec![];
1374        let mapping_context = &current_task.mm()?.mapping_context;
1375        let length = prot_range.end - prot_range.start;
1376        self.ensure_range_mapped_in_user_vmar(prot_range.start, Some(length), mapping_context)?;
1377
1378        for (range, mapping) in self.mappings.range(prot_range.clone()) {
1379            range_list.push((range.clone(), mapping.clone()));
1380        }
1381
1382        let mut start_cursor = prot_range.start;
1383        let mut updates = vec![];
1384        let mut final_result = Ok(());
1385
1386        for (range, mapping) in range_list {
1387            if range.start > start_cursor {
1388                final_result = error!(ENOMEM);
1389                break;
1390            }
1391
1392            let intersection = range.intersect(&prot_range);
1393            if let Err(e) =
1394                security::file_mprotect(current_task, &intersection, &mapping, prot_flags)
1395            {
1396                final_result = Err(e);
1397                break;
1398            }
1399
1400            if mapping.flags().contains(MappingFlags::UFFD) {
1401                track_stub!(
1402                    TODO("https://fxbug.dev/297375964"),
1403                    "mprotect on uffd-registered range should not alter protections"
1404                );
1405                final_result = error!(EINVAL);
1406                break;
1407            }
1408
1409            let mapped_len = intersection.end - intersection.start;
1410
1411            // SAFETY: This is safe because the vmar belongs to a different process.
1412            let protect_result = unsafe {
1413                mapping_context.user_vmar.protect(intersection.start.ptr(), mapped_len, vmar_flags)
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.clone();
1428            new_mapping.set_flags(new_mapping.flags().with_access_flags(prot_flags));
1429            let push_range = intersection.clone();
1430            start_cursor = intersection.end;
1431            updates.push((push_range, new_mapping));
1432        }
1433
1434        if final_result.is_ok() && start_cursor < prot_range.end {
1435            final_result = error!(ENOMEM);
1436        }
1437
1438        for (r, m) in updates {
1439            released_mappings.extend(self.mappings.insert(r, m));
1440        }
1441
1442        final_result
1443    }
1444
1445    fn madvise(
1446        &mut self,
1447        context: &MappingContext,
1448        addr: UserAddress,
1449        length: usize,
1450        advice: u32,
1451        released_mappings: &mut ReleasedMappings,
1452    ) -> Result<(), Errno> {
1453        if !addr.is_aligned(*PAGE_SIZE) {
1454            return error!(EINVAL);
1455        }
1456
1457        let end_addr =
1458            addr.checked_add(length).ok_or_else(|| errno!(EINVAL))?.round_up(*PAGE_SIZE)?;
1459        if end_addr > context.max_address() {
1460            return error!(EFAULT);
1461        }
1462
1463        if advice == MADV_NORMAL {
1464            track_stub!(TODO("https://fxbug.dev/322874202"), "madvise undo hints for MADV_NORMAL");
1465            return Ok(());
1466        }
1467
1468        let mut updates = vec![];
1469        let range_for_op = addr..end_addr;
1470        for (range, mapping) in self.mappings.range(range_for_op.clone()) {
1471            let range_to_zero = range.intersect(&range_for_op);
1472            if range_to_zero.is_empty() {
1473                continue;
1474            }
1475            let start_offset = mapping.address_to_offset(range_to_zero.start);
1476            let end_offset = mapping.address_to_offset(range_to_zero.end);
1477            if advice == MADV_DONTFORK
1478                || advice == MADV_DOFORK
1479                || advice == MADV_WIPEONFORK
1480                || advice == MADV_KEEPONFORK
1481                || advice == MADV_DONTDUMP
1482                || advice == MADV_DODUMP
1483                || advice == MADV_MERGEABLE
1484                || advice == MADV_UNMERGEABLE
1485            {
1486                // WIPEONFORK is only supported on private anonymous mappings per madvise(2).
1487                // KEEPONFORK can be specified on ranges that cover other sorts of mappings. It should
1488                // have no effect on mappings that are not private and anonymous as such mappings cannot
1489                // have the WIPEONFORK option set.
1490                if advice == MADV_WIPEONFORK && !mapping.private_anonymous() {
1491                    return error!(EINVAL);
1492                }
1493                let new_flags = match advice {
1494                    MADV_DONTFORK => mapping.flags() | MappingFlags::DONTFORK,
1495                    MADV_DOFORK => mapping.flags() & MappingFlags::DONTFORK.complement(),
1496                    MADV_WIPEONFORK => mapping.flags() | MappingFlags::WIPEONFORK,
1497                    MADV_KEEPONFORK => mapping.flags() & MappingFlags::WIPEONFORK.complement(),
1498                    MADV_DONTDUMP => {
1499                        track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_DONTDUMP");
1500                        mapping.flags()
1501                    }
1502                    MADV_DODUMP => {
1503                        track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_DODUMP");
1504                        mapping.flags()
1505                    }
1506                    MADV_MERGEABLE => {
1507                        track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_MERGEABLE");
1508                        mapping.flags()
1509                    }
1510                    MADV_UNMERGEABLE => {
1511                        track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_UNMERGEABLE");
1512                        mapping.flags()
1513                    }
1514                    // Only the variants in this match should be reachable given the condition for
1515                    // the containing branch.
1516                    unknown_advice => unreachable!("unknown advice {unknown_advice}"),
1517                };
1518                let mut new_mapping = mapping.clone();
1519                new_mapping.set_flags(new_flags);
1520                updates.push((range_to_zero, new_mapping));
1521            } else {
1522                if mapping.flags().contains(MappingFlags::SHARED) {
1523                    continue;
1524                }
1525                let op = match advice {
1526                    MADV_DONTNEED if !mapping.flags().contains(MappingFlags::ANONYMOUS) => {
1527                        // Note, we cannot simply implemented MADV_DONTNEED with
1528                        // zx::VmoOp::DONT_NEED because they have different
1529                        // semantics.
1530                        track_stub!(
1531                            TODO("https://fxbug.dev/322874496"),
1532                            "MADV_DONTNEED with file-backed mapping"
1533                        );
1534                        return error!(EINVAL);
1535                    }
1536                    MADV_DONTNEED if mapping.flags().contains(MappingFlags::LOCKED) => {
1537                        return error!(EINVAL);
1538                    }
1539                    MADV_DONTNEED => zx::VmoOp::ZERO,
1540                    MADV_DONTNEED_LOCKED => {
1541                        track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_DONTNEED_LOCKED");
1542                        return error!(EINVAL);
1543                    }
1544                    MADV_WILLNEED => {
1545                        if mapping.flags().contains(MappingFlags::WRITE) {
1546                            zx::VmoOp::COMMIT
1547                        } else {
1548                            zx::VmoOp::PREFETCH
1549                        }
1550                    }
1551                    MADV_COLD => {
1552                        track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_COLD");
1553                        return error!(EINVAL);
1554                    }
1555                    MADV_PAGEOUT => {
1556                        track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_PAGEOUT");
1557                        return error!(EINVAL);
1558                    }
1559                    MADV_POPULATE_READ => {
1560                        track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_POPULATE_READ");
1561                        return error!(EINVAL);
1562                    }
1563                    MADV_RANDOM => {
1564                        track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_RANDOM");
1565                        return error!(EINVAL);
1566                    }
1567                    MADV_SEQUENTIAL => {
1568                        track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_SEQUENTIAL");
1569                        return error!(EINVAL);
1570                    }
1571                    MADV_FREE if !mapping.flags().contains(MappingFlags::ANONYMOUS) => {
1572                        track_stub!(
1573                            TODO("https://fxbug.dev/411748419"),
1574                            "MADV_FREE with file-backed mapping"
1575                        );
1576                        return error!(EINVAL);
1577                    }
1578                    MADV_FREE if mapping.flags().contains(MappingFlags::LOCKED) => {
1579                        return error!(EINVAL);
1580                    }
1581                    MADV_FREE => {
1582                        track_stub!(TODO("https://fxbug.dev/411748419"), "MADV_FREE");
1583                        // TODO(https://fxbug.dev/411748419) For now, treat MADV_FREE like
1584                        // MADV_DONTNEED as a stopgap until we have proper support.
1585                        zx::VmoOp::ZERO
1586                    }
1587                    MADV_REMOVE => {
1588                        track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_REMOVE");
1589                        return error!(EINVAL);
1590                    }
1591                    MADV_HWPOISON => {
1592                        track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_HWPOISON");
1593                        return error!(EINVAL);
1594                    }
1595                    MADV_SOFT_OFFLINE => {
1596                        track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_SOFT_OFFLINE");
1597                        return error!(EINVAL);
1598                    }
1599                    MADV_HUGEPAGE => {
1600                        track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_HUGEPAGE");
1601                        return error!(EINVAL);
1602                    }
1603                    MADV_COLLAPSE => {
1604                        track_stub!(TODO("https://fxbug.dev/322874202"), "MADV_COLLAPSE");
1605                        return error!(EINVAL);
1606                    }
1607                    MADV_NOHUGEPAGE => return Ok(()),
1608                    advice => {
1609                        track_stub!(TODO("https://fxbug.dev/322874202"), "madvise", advice);
1610                        return error!(EINVAL);
1611                    }
1612                };
1613
1614                let memory = match self.get_mapping_backing(mapping) {
1615                    MappingBacking::Memory(backing) => backing.memory(),
1616                    MappingBacking::PrivateAnonymous => &context.private_anonymous.backing,
1617                };
1618                memory.op_range(op, start_offset, end_offset - start_offset).map_err(
1619                    |s| match s {
1620                        zx::Status::OUT_OF_RANGE => errno!(EINVAL),
1621                        zx::Status::NO_MEMORY => errno!(ENOMEM),
1622                        zx::Status::INVALID_ARGS => errno!(EINVAL),
1623                        zx::Status::ACCESS_DENIED => errno!(EACCES),
1624                        _ => impossible_error(s),
1625                    },
1626                )?;
1627            }
1628        }
1629        // Use a separate loop to avoid mutating the mappings structure while iterating over it.
1630        for (range, mapping) in updates {
1631            released_mappings.extend(self.mappings.insert(range, mapping));
1632        }
1633        Ok(())
1634    }
1635
1636    fn mlock(
1637        &mut self,
1638        context: &MappingContext,
1639        current_task: &CurrentTask,
1640        desired_addr: UserAddress,
1641        desired_length: usize,
1642        on_fault: bool,
1643        released_mappings: &mut ReleasedMappings,
1644    ) -> Result<(), Errno> {
1645        let desired_end_addr =
1646            desired_addr.checked_add(desired_length).ok_or_else(|| errno!(EINVAL))?;
1647        let start_addr = round_down_to_system_page_size(desired_addr)?;
1648        let end_addr = round_up_to_system_page_size(desired_end_addr)?;
1649
1650        let mut updates = vec![];
1651        let mut bytes_mapped_in_range = 0;
1652        let mut num_new_locked_bytes = 0;
1653        let mut failed_to_lock = false;
1654        for (range, mapping) in self.mappings.range(start_addr..end_addr) {
1655            let mut range = range.clone();
1656            let mut mapping = mapping.clone();
1657
1658            // Handle mappings that start before the region to be locked.
1659            range.start = std::cmp::max(range.start, start_addr);
1660            // Handle mappings that extend past the region to be locked.
1661            range.end = std::cmp::min(range.end, end_addr);
1662
1663            bytes_mapped_in_range += (range.end - range.start) as u64;
1664
1665            // PROT_NONE mappings generate ENOMEM but are left locked.
1666            if !mapping
1667                .flags()
1668                .intersects(MappingFlags::READ | MappingFlags::WRITE | MappingFlags::EXEC)
1669            {
1670                failed_to_lock = true;
1671            }
1672
1673            if !mapping.flags().contains(MappingFlags::LOCKED) {
1674                num_new_locked_bytes += (range.end - range.start) as u64;
1675                let shadow_mapping = match current_task.kernel().features.mlock_pin_flavor {
1676                    // Pin the memory by mapping the backing memory into the high priority vmar.
1677                    MlockPinFlavor::ShadowProcess => {
1678                        let shadow_process =
1679                            current_task.kernel().expando.get_or_try_init(|| {
1680                                memory_pinning::ShadowProcess::new(zx::Name::new_lossy(
1681                                    "starnix_mlock_pins",
1682                                ))
1683                                .map(MlockShadowProcess)
1684                                .map_err(|_| errno!(EPERM))
1685                            })?;
1686
1687                        let (vmo, offset) = match self.get_mapping_backing(&mapping) {
1688                            MappingBacking::Memory(m) => (
1689                                m.memory().as_vmo().ok_or_else(|| errno!(ENOMEM))?,
1690                                m.address_to_offset(range.start),
1691                            ),
1692                            MappingBacking::PrivateAnonymous => (
1693                                context
1694                                    .private_anonymous
1695                                    .backing
1696                                    .as_vmo()
1697                                    .ok_or_else(|| errno!(ENOMEM))?,
1698                                range.start.ptr() as u64,
1699                            ),
1700                        };
1701                        Some(shadow_process.0.pin_pages(vmo, offset, range.end - range.start)?)
1702                    }
1703
1704                    // Relying on VMAR-level operations means just flags are set per-mapping.
1705                    MlockPinFlavor::Noop | MlockPinFlavor::VmarAlwaysNeed => None,
1706                };
1707                mapping.set_mlock();
1708                updates.push((range, mapping, shadow_mapping));
1709            }
1710        }
1711
1712        if bytes_mapped_in_range as usize != end_addr - start_addr {
1713            return error!(ENOMEM);
1714        }
1715
1716        let memlock_rlimit = current_task.thread_group().get_rlimit(Resource::MEMLOCK);
1717        let total_locked = self.num_locked_bytes(
1718            UserAddress::from(context.user_vmar_info.base as u64)
1719                ..UserAddress::from(
1720                    (context.user_vmar_info.base + context.user_vmar_info.len) as u64,
1721                ),
1722        );
1723        if total_locked + num_new_locked_bytes > memlock_rlimit {
1724            if crate::security::check_task_capable(current_task, CAP_IPC_LOCK).is_err() {
1725                let code = if memlock_rlimit > 0 { errno!(ENOMEM) } else { errno!(EPERM) };
1726                return Err(code);
1727            }
1728        }
1729
1730        let op_range_status_to_errno = |e| match e {
1731            zx::Status::BAD_STATE | zx::Status::NOT_SUPPORTED => errno!(ENOMEM),
1732            zx::Status::INVALID_ARGS | zx::Status::OUT_OF_RANGE => errno!(EINVAL),
1733            zx::Status::ACCESS_DENIED => {
1734                unreachable!("user vmar should always have needed rights")
1735            }
1736            zx::Status::BAD_HANDLE => {
1737                unreachable!("user vmar should always be a valid handle")
1738            }
1739            zx::Status::WRONG_TYPE => unreachable!("user vmar handle should be a vmar"),
1740            _ => unreachable!("unknown error from op_range on user vmar for mlock: {e}"),
1741        };
1742
1743        self.ensure_range_mapped_in_user_vmar(start_addr, Some(end_addr - start_addr), context)?;
1744
1745        if !on_fault && !current_task.kernel().features.mlock_always_onfault {
1746            context
1747                .user_vmar
1748                .op_range(zx::VmarOp::PREFETCH, start_addr.ptr(), end_addr - start_addr)
1749                .map_err(op_range_status_to_errno)?;
1750        }
1751
1752        match current_task.kernel().features.mlock_pin_flavor {
1753            MlockPinFlavor::VmarAlwaysNeed => {
1754                context
1755                    .user_vmar
1756                    .op_range(zx::VmarOp::ALWAYS_NEED, start_addr.ptr(), end_addr - start_addr)
1757                    .map_err(op_range_status_to_errno)?;
1758            }
1759            // The shadow process doesn't use any vmar-level operations to pin memory.
1760            MlockPinFlavor::Noop | MlockPinFlavor::ShadowProcess => (),
1761        }
1762
1763        for (range, mapping, shadow_mapping) in updates {
1764            if let Some(shadow_mapping) = shadow_mapping {
1765                released_mappings.extend_pins(
1766                    self.shadow_mappings_for_mlock.insert(range.clone(), shadow_mapping),
1767                );
1768            }
1769            released_mappings.extend(self.mappings.insert(range, mapping));
1770        }
1771
1772        if failed_to_lock { error!(ENOMEM) } else { Ok(()) }
1773    }
1774
1775    fn munlock(
1776        &mut self,
1777        _current_task: &CurrentTask,
1778        desired_addr: UserAddress,
1779        desired_length: usize,
1780        released_mappings: &mut ReleasedMappings,
1781    ) -> Result<(), Errno> {
1782        let desired_end_addr =
1783            desired_addr.checked_add(desired_length).ok_or_else(|| errno!(EINVAL))?;
1784        let start_addr = round_down_to_system_page_size(desired_addr)?;
1785        let end_addr = round_up_to_system_page_size(desired_end_addr)?;
1786
1787        let mut updates = vec![];
1788        let mut bytes_mapped_in_range = 0;
1789        for (range, mapping) in self.mappings.range(start_addr..end_addr) {
1790            let mut range = range.clone();
1791            let mut mapping = mapping.clone();
1792
1793            // Handle mappings that start before the region to be locked.
1794            range.start = std::cmp::max(range.start, start_addr);
1795            // Handle mappings that extend past the region to be locked.
1796            range.end = std::cmp::min(range.end, end_addr);
1797
1798            bytes_mapped_in_range += (range.end - range.start) as u64;
1799
1800            if mapping.flags().contains(MappingFlags::LOCKED) {
1801                // This clears the locking for the shadow process pin flavor. It's not currently
1802                // possible to actually unlock pages that were locked with the
1803                // ZX_VMAR_OP_ALWAYS_NEED pin flavor.
1804                mapping.clear_mlock();
1805                updates.push((range, mapping));
1806            }
1807        }
1808
1809        if bytes_mapped_in_range as usize != end_addr - start_addr {
1810            return error!(ENOMEM);
1811        }
1812
1813        for (range, mapping) in updates {
1814            released_mappings.extend(self.mappings.insert(range.clone(), mapping));
1815            released_mappings.extend_pins(self.shadow_mappings_for_mlock.remove(range));
1816        }
1817
1818        Ok(())
1819    }
1820
1821    pub fn num_locked_bytes(&self, range: impl RangeBounds<UserAddress>) -> u64 {
1822        self.mappings
1823            .map
1824            .range(range)
1825            .filter(|(_, mapping)| mapping.flags().contains(MappingFlags::LOCKED))
1826            .map(|(range, _)| (range.end - range.start) as u64)
1827            .sum()
1828    }
1829
1830    fn get_mappings_for_vmsplice(
1831        &self,
1832        mm: &Arc<MemoryManager>,
1833        buffers: &UserBuffers,
1834    ) -> Result<Vec<Arc<VmsplicePayload>>, Errno> {
1835        let mut vmsplice_mappings = Vec::new();
1836
1837        for UserBuffer { mut address, length } in buffers.iter().copied() {
1838            let mappings = self.get_contiguous_mappings_at(address, length, &mm.mapping_context)?;
1839            for (mapping, length) in mappings {
1840                let vmsplice_payload = match self.get_mapping_backing(mapping) {
1841                    MappingBacking::Memory(m) => VmsplicePayloadSegment {
1842                        addr_offset: address,
1843                        length,
1844                        memory: m.memory().clone(),
1845                        memory_offset: m.address_to_offset(address),
1846                        should_snapshot_on_unmap: false,
1847                    },
1848                    MappingBacking::PrivateAnonymous => VmsplicePayloadSegment {
1849                        addr_offset: address,
1850                        length,
1851                        memory: mm.mapping_context.private_anonymous.backing.clone(),
1852                        memory_offset: address.ptr() as u64,
1853                        should_snapshot_on_unmap: true,
1854                    },
1855                };
1856                vmsplice_mappings.push(VmsplicePayload::new(Arc::downgrade(mm), vmsplice_payload));
1857
1858                address = (address + length)?;
1859            }
1860        }
1861
1862        Ok(vmsplice_mappings)
1863    }
1864
1865    /// Returns all the mappings starting at `addr`, and continuing until either `length` bytes have
1866    /// been covered or an unmapped page is reached.
1867    ///
1868    /// Mappings are returned in ascending order along with the number of bytes that intersect the
1869    /// requested range. The returned mappings are guaranteed to be contiguous and the total length
1870    /// corresponds to the number of contiguous mapped bytes starting from `addr`, i.e.:
1871    /// - 0 (empty iterator) if `addr` is not mapped.
1872    /// - exactly `length` if the requested range is fully mapped.
1873    /// - the offset of the first unmapped page (between 0 and `length`) if the requested range is
1874    ///   only partially mapped.
1875    ///
1876    /// Returns EFAULT if the requested range overflows or extends past the end of the vmar.
1877    fn get_contiguous_mappings_at(
1878        &self,
1879        addr: UserAddress,
1880        length: usize,
1881        context: &MappingContext,
1882    ) -> Result<impl Iterator<Item = (&Mapping, usize)>, Errno> {
1883        let end_addr = addr.checked_add(length).ok_or_else(|| errno!(EFAULT))?;
1884        if end_addr > context.max_address() {
1885            return error!(EFAULT);
1886        }
1887
1888        // Iterate over all contiguous mappings intersecting the requested range.
1889        let mut mappings = self.mappings.range(addr..end_addr);
1890        let mut prev_range_end = None;
1891        let mut offset = 0;
1892        let result = std::iter::from_fn(move || {
1893            if offset != length {
1894                if let Some((range, mapping)) = mappings.next() {
1895                    return match prev_range_end {
1896                        // If this is the first mapping that we are considering, it may not actually
1897                        // contain `addr` at all.
1898                        None if range.start > addr => None,
1899
1900                        // Subsequent mappings may not be contiguous.
1901                        Some(prev_range_end) if range.start != prev_range_end => None,
1902
1903                        // This mapping can be returned.
1904                        _ => {
1905                            let mapping_length = std::cmp::min(length, range.end - addr) - offset;
1906                            offset += mapping_length;
1907                            prev_range_end = Some(range.end);
1908                            Some((mapping, mapping_length))
1909                        }
1910                    };
1911                }
1912            }
1913
1914            None
1915        });
1916
1917        Ok(result)
1918    }
1919
1920    /// Determines whether a fault at the given address could be covered by extending a growsdown
1921    /// mapping.
1922    ///
1923    /// If the address already belongs to a mapping, this function returns `None`. If the next
1924    /// mapping above the given address has the `MappingFlags::GROWSDOWN` flag, this function
1925    /// returns the address at which that mapping starts and the mapping itself. Otherwise, this
1926    /// function returns `None`.
1927    fn find_growsdown_mapping(&self, addr: UserAddress) -> Option<(UserAddress, &Mapping)> {
1928        match self.mappings.range(addr..).next() {
1929            Some((range, mapping)) => {
1930                if range.contains(&addr) {
1931                    // |addr| is already contained within a mapping, nothing to grow.
1932                    return None;
1933                } else if !mapping.flags().contains(MappingFlags::GROWSDOWN) {
1934                    // The next mapping above the given address does not have the
1935                    // `MappingFlags::GROWSDOWN` flag.
1936                    None
1937                } else {
1938                    Some((range.start, mapping))
1939                }
1940            }
1941            None => None,
1942        }
1943    }
1944
1945    /// Determines if an access at a given address could be covered by extending a growsdown mapping
1946    /// and extends it if possible. Returns true if the given address is covered by a mapping.
1947    fn extend_growsdown_mapping_to_address(
1948        &mut self,
1949        mm: &Arc<MemoryManager>,
1950        addr: UserAddress,
1951        is_write: bool,
1952    ) -> Result<bool, Error> {
1953        let Some((mapping_low_addr, mapping_to_grow)) = self.find_growsdown_mapping(addr) else {
1954            return Ok(false);
1955        };
1956        if is_write && !mapping_to_grow.can_write() {
1957            // Don't grow a read-only GROWSDOWN mapping for a write fault, it won't work.
1958            return Ok(false);
1959        }
1960        if !mapping_to_grow.flags().contains(MappingFlags::ANONYMOUS) {
1961            // Currently, we only grow anonymous mappings.
1962            return Ok(false);
1963        }
1964        let low_addr = (addr - (addr.ptr() as u64 % *PAGE_SIZE))?;
1965        let high_addr = mapping_low_addr;
1966
1967        let length = high_addr
1968            .ptr()
1969            .checked_sub(low_addr.ptr())
1970            .ok_or_else(|| anyhow!("Invalid growth range"))?;
1971
1972        let mut released_mappings = ReleasedMappings::default();
1973        self.map_anonymous(
1974            mm,
1975            DesiredAddress::FixedOverwrite(low_addr),
1976            length,
1977            mapping_to_grow.flags().access_flags(),
1978            mapping_to_grow.flags().options(),
1979            mapping_to_grow.name().to_owned(),
1980            &mut released_mappings,
1981        )?;
1982        // We can't have any released mappings because `find_growsdown_mapping` will return None if
1983        // the mapping already exists in this range.
1984        assert!(
1985            released_mappings.is_empty(),
1986            "expected to not remove mappings by inserting, got {released_mappings:#?}"
1987        );
1988        Ok(true)
1989    }
1990
1991    /// Reads exactly `bytes.len()` bytes of memory.
1992    ///
1993    /// # Parameters
1994    /// - `addr`: The address to read data from.
1995    /// - `bytes`: The byte array to read into.
1996    fn read_memory<'a>(
1997        &self,
1998        addr: UserAddress,
1999        bytes: &'a mut [MaybeUninit<u8>],
2000        context: &MappingContext,
2001    ) -> Result<&'a mut [u8], Errno> {
2002        let mut bytes_read = 0;
2003        for (mapping, len) in self.get_contiguous_mappings_at(addr, bytes.len(), context)? {
2004            let next_offset = bytes_read + len;
2005            self.read_mapping_memory(
2006                (addr + bytes_read)?,
2007                mapping,
2008                &mut bytes[bytes_read..next_offset],
2009                context,
2010            )?;
2011            bytes_read = next_offset;
2012        }
2013
2014        if bytes_read != bytes.len() {
2015            error!(EFAULT)
2016        } else {
2017            // SAFETY: The created slice is properly aligned/sized since it
2018            // is a subset of the `bytes` slice. Note that `MaybeUninit<T>` has
2019            // the same layout as `T`. Also note that `bytes_read` bytes have
2020            // been properly initialized.
2021            let bytes = unsafe {
2022                std::slice::from_raw_parts_mut(bytes.as_mut_ptr() as *mut u8, bytes_read)
2023            };
2024            Ok(bytes)
2025        }
2026    }
2027
2028    /// Reads exactly `bytes.len()` bytes of memory from `addr`.
2029    ///
2030    /// # Parameters
2031    /// - `addr`: The address to read data from.
2032    /// - `bytes`: The byte array to read into.
2033    fn read_mapping_memory<'a>(
2034        &self,
2035        addr: UserAddress,
2036        mapping: &Mapping,
2037        bytes: &'a mut [MaybeUninit<u8>],
2038        context: &MappingContext,
2039    ) -> Result<&'a mut [u8], Errno> {
2040        if !mapping.can_read() {
2041            return error!(EFAULT, "read_mapping_memory called on unreadable mapping");
2042        }
2043        match self.get_mapping_backing(mapping) {
2044            MappingBacking::Memory(backing) => backing.read_memory(addr, bytes),
2045            MappingBacking::PrivateAnonymous => context.private_anonymous.read_memory(addr, bytes),
2046        }
2047    }
2048
2049    /// Reads bytes starting at `addr`, continuing until either `bytes.len()` bytes have been read
2050    /// or no more bytes can be read.
2051    ///
2052    /// This is used, for example, to read null-terminated strings where the exact length is not
2053    /// known, only the maximum length is.
2054    ///
2055    /// # Parameters
2056    /// - `addr`: The address to read data from.
2057    /// - `bytes`: The byte array to read into.
2058    fn read_memory_partial<'a>(
2059        &self,
2060        addr: UserAddress,
2061        bytes: &'a mut [MaybeUninit<u8>],
2062        context: &MappingContext,
2063    ) -> Result<&'a mut [u8], Errno> {
2064        let mut bytes_read = 0;
2065        for (mapping, len) in self.get_contiguous_mappings_at(addr, bytes.len(), context)? {
2066            let next_offset = bytes_read + len;
2067            if self
2068                .read_mapping_memory(
2069                    (addr + bytes_read)?,
2070                    mapping,
2071                    &mut bytes[bytes_read..next_offset],
2072                    context,
2073                )
2074                .is_err()
2075            {
2076                break;
2077            }
2078            bytes_read = next_offset;
2079        }
2080
2081        // If at least one byte was requested but we got none, it means that `addr` was invalid.
2082        if !bytes.is_empty() && bytes_read == 0 {
2083            error!(EFAULT)
2084        } else {
2085            // SAFETY: The created slice is properly aligned/sized since it
2086            // is a subset of the `bytes` slice. Note that `MaybeUninit<T>` has
2087            // the same layout as `T`. Also note that `bytes_read` bytes have
2088            // been properly initialized.
2089            let bytes = unsafe {
2090                std::slice::from_raw_parts_mut(bytes.as_mut_ptr() as *mut u8, bytes_read)
2091            };
2092            Ok(bytes)
2093        }
2094    }
2095
2096    /// Like `read_memory_partial` but only returns the bytes up to and including
2097    /// a null (zero) byte.
2098    fn read_memory_partial_until_null_byte<'a>(
2099        &self,
2100        addr: UserAddress,
2101        bytes: &'a mut [MaybeUninit<u8>],
2102        context: &MappingContext,
2103    ) -> Result<&'a mut [u8], Errno> {
2104        let read_bytes = self.read_memory_partial(addr, bytes, context)?;
2105        let max_len = memchr::memchr(b'\0', read_bytes)
2106            .map_or_else(|| read_bytes.len(), |null_index| null_index + 1);
2107        Ok(&mut read_bytes[..max_len])
2108    }
2109
2110    /// Writes the provided bytes.
2111    ///
2112    /// In case of success, the number of bytes written will always be `bytes.len()`.
2113    ///
2114    /// # Parameters
2115    /// - `addr`: The address to write to.
2116    /// - `bytes`: The bytes to write.
2117    fn write_memory(
2118        &self,
2119        addr: UserAddress,
2120        bytes: &[u8],
2121        context: &MappingContext,
2122    ) -> Result<usize, Errno> {
2123        let mut bytes_written = 0;
2124        for (mapping, len) in self.get_contiguous_mappings_at(addr, bytes.len(), context)? {
2125            let next_offset = bytes_written + len;
2126            self.write_mapping_memory(
2127                (addr + bytes_written)?,
2128                mapping,
2129                &bytes[bytes_written..next_offset],
2130                context,
2131            )?;
2132            bytes_written = next_offset;
2133        }
2134
2135        if bytes_written != bytes.len() { error!(EFAULT) } else { Ok(bytes.len()) }
2136    }
2137
2138    /// Writes the provided bytes to `addr`.
2139    ///
2140    /// # Parameters
2141    /// - `addr`: The address to write to.
2142    /// - `bytes`: The bytes to write to the memory object.
2143    fn write_mapping_memory(
2144        &self,
2145        addr: UserAddress,
2146        mapping: &Mapping,
2147        bytes: &[u8],
2148        context: &MappingContext,
2149    ) -> Result<(), Errno> {
2150        if !mapping.can_write() {
2151            return error!(EFAULT, "write_mapping_memory called on unwritable memory");
2152        }
2153        match self.get_mapping_backing(mapping) {
2154            MappingBacking::Memory(backing) => backing.write_memory(addr, bytes),
2155            MappingBacking::PrivateAnonymous => context.private_anonymous.write_memory(addr, bytes),
2156        }
2157    }
2158
2159    /// Writes bytes starting at `addr`, continuing until either `bytes.len()` bytes have been
2160    /// written or no more bytes can be written.
2161    ///
2162    /// # Parameters
2163    /// - `addr`: The address to read data from.
2164    /// - `bytes`: The byte array to write from.
2165    fn write_memory_partial(
2166        &self,
2167        addr: UserAddress,
2168        bytes: &[u8],
2169        context: &MappingContext,
2170    ) -> Result<usize, Errno> {
2171        let mut bytes_written = 0;
2172        for (mapping, len) in self.get_contiguous_mappings_at(addr, bytes.len(), context)? {
2173            let next_offset = bytes_written + len;
2174            if self
2175                .write_mapping_memory(
2176                    (addr + bytes_written)?,
2177                    mapping,
2178                    &bytes[bytes_written..next_offset],
2179                    context,
2180                )
2181                .is_err()
2182            {
2183                break;
2184            }
2185            bytes_written = next_offset;
2186        }
2187
2188        if !bytes.is_empty() && bytes_written == 0 { error!(EFAULT) } else { Ok(bytes.len()) }
2189    }
2190
2191    fn zero(
2192        &self,
2193        addr: UserAddress,
2194        length: usize,
2195        context: &MappingContext,
2196    ) -> Result<usize, Errno> {
2197        let mut bytes_written = 0;
2198        for (mapping, len) in self.get_contiguous_mappings_at(addr, length, context)? {
2199            let next_offset = bytes_written + len;
2200            if self.zero_mapping((addr + bytes_written)?, mapping, len, context).is_err() {
2201                break;
2202            }
2203            bytes_written = next_offset;
2204        }
2205
2206        if length != bytes_written { error!(EFAULT) } else { Ok(length) }
2207    }
2208
2209    fn zero_mapping(
2210        &self,
2211        addr: UserAddress,
2212        mapping: &Mapping,
2213        length: usize,
2214        context: &MappingContext,
2215    ) -> Result<usize, Errno> {
2216        if !mapping.can_write() {
2217            return error!(EFAULT);
2218        }
2219
2220        match self.get_mapping_backing(mapping) {
2221            MappingBacking::Memory(backing) => backing.zero(addr, length),
2222            MappingBacking::PrivateAnonymous => context.private_anonymous.zero(addr, length),
2223        }
2224    }
2225
2226    pub fn create_memory_backing(
2227        &self,
2228        base: UserAddress,
2229        memory: Arc<MemoryObject>,
2230        memory_offset: u64,
2231    ) -> MappingBacking {
2232        MappingBacking::Memory(Box::new(MappingBackingMemory::new(base, memory, memory_offset)))
2233    }
2234
2235    pub fn get_mapping_backing<'a>(&self, mapping: &'a Mapping) -> &'a MappingBacking {
2236        mapping.get_backing_internal()
2237    }
2238
2239    fn get_aio_context(&self, addr: UserAddress) -> Option<(Range<UserAddress>, Arc<AioContext>)> {
2240        let Some((range, mapping)) = self.mappings.get(addr) else {
2241            return None;
2242        };
2243        let MappingNameRef::AioContext(ref aio_context) = mapping.name() else {
2244            return None;
2245        };
2246        if !mapping.can_read() {
2247            return None;
2248        }
2249        Some((range.clone(), Arc::clone(aio_context)))
2250    }
2251
2252    fn find_uffd(&self, addr: UserAddress) -> Option<Arc<UserFault>> {
2253        for userfault in self.userfaultfds.iter() {
2254            if let Some(userfault) = userfault.upgrade() {
2255                if userfault.contains_addr(addr) {
2256                    return Some(userfault);
2257                }
2258            }
2259        }
2260        None
2261    }
2262
2263    fn cache_flush(
2264        &self,
2265        range: Range<UserAddress>,
2266        context: &MappingContext,
2267    ) -> Result<(), Errno> {
2268        let mut addr = range.start;
2269        let size = range.end - range.start;
2270        for (mapping, len) in self.get_contiguous_mappings_at(addr, size, context)? {
2271            if !mapping.can_read() {
2272                return error!(EFAULT);
2273            }
2274            if mapping.mapping_mode() == MappingMode::Lazy {
2275                addr = (addr + len)?;
2276                continue;
2277            }
2278            // SAFETY: This is operating on a readable restricted mode mapping and will not fault.
2279            zx::Status::ok(unsafe {
2280                zx::sys::zx_cache_flush(
2281                    addr.ptr() as *const u8,
2282                    len,
2283                    zx::sys::ZX_CACHE_FLUSH_DATA | zx::sys::ZX_CACHE_FLUSH_INSN,
2284                )
2285            })
2286            .map_err(impossible_error)?;
2287
2288            addr = (addr + len).unwrap(); // unwrap since we're iterating within the address space.
2289        }
2290        // Did we flush the entire range?
2291        if addr != range.end { error!(EFAULT) } else { Ok(()) }
2292    }
2293
2294    /// Register the address space managed by this memory manager for interest in
2295    /// receiving private expedited memory barriers of the given kind.
2296    pub fn register_membarrier_private_expedited(
2297        &mut self,
2298        mtype: MembarrierType,
2299    ) -> Result<(), Errno> {
2300        let registrations = &mut self.forkable_state.membarrier_registrations;
2301        match mtype {
2302            MembarrierType::Memory => {
2303                registrations.memory = true;
2304            }
2305            MembarrierType::SyncCore => {
2306                registrations.sync_core = true;
2307            }
2308        }
2309        Ok(())
2310    }
2311
2312    /// Checks if the address space managed by this memory manager is registered
2313    /// for interest in private expedited barriers of the given kind.
2314    pub fn membarrier_private_expedited_registered(&self, mtype: MembarrierType) -> bool {
2315        let registrations = &self.forkable_state.membarrier_registrations;
2316        match mtype {
2317            MembarrierType::Memory => registrations.memory,
2318            MembarrierType::SyncCore => registrations.sync_core,
2319        }
2320    }
2321
2322    fn force_write_memory(
2323        &mut self,
2324        context: &MappingContext,
2325        addr: UserAddress,
2326        bytes: &[u8],
2327        released_mappings: &mut ReleasedMappings,
2328    ) -> Result<(), Errno> {
2329        let (range, mapping) = {
2330            let (r, m) = self.mappings.get(addr).ok_or_else(|| errno!(EFAULT))?;
2331            (r.clone(), m.clone())
2332        };
2333        if range.end < addr.saturating_add(bytes.len()) {
2334            track_stub!(
2335                TODO("https://fxbug.dev/445790710"),
2336                "ptrace poke across multiple mappings"
2337            );
2338            return error!(EFAULT);
2339        }
2340
2341        // Don't create CoW copy of shared memory, go through regular syscall writing.
2342        if mapping.flags().contains(MappingFlags::SHARED) {
2343            if !mapping.can_write() {
2344                // Linux returns EIO here instead of EFAULT.
2345                return error!(EIO);
2346            }
2347            return self.write_mapping_memory(addr, &mapping, &bytes, context);
2348        }
2349
2350        let backing = match self.get_mapping_backing(&mapping) {
2351            MappingBacking::PrivateAnonymous => {
2352                // Starnix has a writable handle to private anonymous memory.
2353                return context.private_anonymous.write_memory(addr, &bytes);
2354            }
2355            MappingBacking::Memory(backing) => backing,
2356        };
2357
2358        let vmo = backing.memory().as_vmo().ok_or_else(|| errno!(EFAULT))?;
2359        let addr_offset = backing.address_to_offset(addr);
2360        let can_exec =
2361            vmo.basic_info().expect("get VMO handle info").rights.contains(Rights::EXECUTE);
2362
2363        // Attempt to write to existing VMO
2364        match vmo.write(&bytes, addr_offset) {
2365            Ok(()) => {
2366                if can_exec {
2367                    // Issue a barrier to avoid executing stale instructions.
2368                    system_barrier(BarrierType::InstructionStream);
2369                }
2370                return Ok(());
2371            }
2372
2373            Err(zx::Status::ACCESS_DENIED) => { /* Fall through */ }
2374
2375            Err(status) => {
2376                return Err(MemoryManager::get_errno_for_vmo_err(status));
2377            }
2378        }
2379
2380        // Create a CoW child of the entire VMO and swap with the backing.
2381        let mapping_offset = backing.address_to_offset(range.start);
2382        let len = range.end - range.start;
2383
2384        // 1. Obtain a writable child of the VMO.
2385        let size = vmo.get_size().map_err(MemoryManager::get_errno_for_vmo_err)?;
2386        let child_vmo = vmo
2387            .create_child(VmoChildOptions::SNAPSHOT_AT_LEAST_ON_WRITE, 0, size)
2388            .map_err(MemoryManager::get_errno_for_vmo_err)?;
2389
2390        // 2. Modify the memory.
2391        child_vmo.write(&bytes, addr_offset).map_err(MemoryManager::get_errno_for_vmo_err)?;
2392
2393        // 3. If needed, remint the VMO as executable. Zircon flushes instruction caches when
2394        // mapping executable memory below, so a barrier isn't necessary here.
2395        let child_vmo = if can_exec {
2396            child_vmo
2397                .replace_as_executable(&VMEX_RESOURCE)
2398                .map_err(MemoryManager::get_errno_for_vmo_err)?
2399        } else {
2400            child_vmo
2401        };
2402
2403        // Ensure that the mapping that `addr` falls into is mapped in the user VMAR.
2404        // This ensures that the mapping's mode becomes `Eager` (if it was `Lazy`),
2405        // otherwise, we might clone a `Lazy` mapping but map it unconditionally below,
2406        // leading to state drift where a mapping is mapped in Zircon but marked as lazy in Starnix.
2407        self.ensure_range_mapped_in_user_vmar(addr, None, context)?;
2408
2409        // 4. Map the new VMO into user VMAR
2410        let memory = Arc::new(MemoryObject::from(child_vmo));
2411        context.map_in_user_vmar(
2412            SelectedAddress::FixedOverwrite(range.start),
2413            &memory,
2414            mapping_offset,
2415            len,
2416            mapping.flags(),
2417            false,
2418        )?;
2419
2420        // 5. Update mappings
2421        let new_backing = MappingBackingMemory::new(range.start, memory, mapping_offset);
2422
2423        let mut new_mapping = mapping.clone();
2424        new_mapping.set_backing_internal(MappingBacking::Memory(Box::new(new_backing)));
2425
2426        released_mappings.extend(self.mappings.insert(range, new_mapping));
2427
2428        Ok(())
2429    }
2430
2431    fn set_brk(
2432        &mut self,
2433        current_task: &CurrentTask,
2434        mm: &Arc<MemoryManager>,
2435        addr: UserAddress,
2436        released_mappings: &mut ReleasedMappings,
2437    ) -> Result<UserAddress, Errno> {
2438        let rlimit_data = std::cmp::min(
2439            PROGRAM_BREAK_LIMIT,
2440            current_task.thread_group().get_rlimit(Resource::DATA),
2441        );
2442
2443        let brk = match self.brk.clone() {
2444            None => {
2445                let brk = ProgramBreak { base: self.brk_origin, current: self.brk_origin };
2446                self.brk = Some(brk.clone());
2447                brk
2448            }
2449            Some(brk) => brk,
2450        };
2451
2452        let Ok(last_address) = brk.base + rlimit_data else {
2453            // The requested program break is out-of-range. We're supposed to simply
2454            // return the current program break.
2455            return Ok(brk.current);
2456        };
2457
2458        if addr < brk.base || addr > last_address {
2459            // The requested program break is out-of-range. We're supposed to simply
2460            // return the current program break.
2461            return Ok(brk.current);
2462        }
2463
2464        let old_end = brk.current.round_up(*PAGE_SIZE).unwrap();
2465        let new_end = addr.round_up(*PAGE_SIZE).unwrap();
2466
2467        match new_end.cmp(&old_end) {
2468            std::cmp::Ordering::Less => {
2469                // Shrinking the program break removes any mapped pages in the
2470                // affected range, regardless of whether they were actually program
2471                // break pages, or other mappings.
2472                let delta = old_end - new_end;
2473
2474                if self.unmap(mm, new_end, delta, released_mappings).is_err() {
2475                    return Ok(brk.current);
2476                }
2477            }
2478            std::cmp::Ordering::Greater => {
2479                let range = old_end..new_end;
2480                let delta = new_end - old_end;
2481
2482                // Check for mappings over the program break region.
2483                if self.mappings.range(range).next().is_some() {
2484                    return Ok(brk.current);
2485                }
2486
2487                if self
2488                    .map_anonymous(
2489                        mm,
2490                        DesiredAddress::FixedOverwrite(old_end),
2491                        delta,
2492                        ProtectionFlags::READ | ProtectionFlags::WRITE,
2493                        MappingOptions::ANONYMOUS,
2494                        MappingName::Heap,
2495                        released_mappings,
2496                    )
2497                    .is_err()
2498                {
2499                    return Ok(brk.current);
2500                }
2501            }
2502            _ => {}
2503        };
2504
2505        // Any required updates to the program break succeeded, so update internal state.
2506        let mut new_brk = brk;
2507        new_brk.current = addr;
2508        self.brk = Some(new_brk);
2509
2510        Ok(addr)
2511    }
2512
2513    fn register_with_uffd(
2514        &mut self,
2515        mm: &MemoryManager,
2516        addr: UserAddress,
2517        length: usize,
2518        userfault: &Arc<UserFault>,
2519        mode: FaultRegisterMode,
2520        released_mappings: &mut ReleasedMappings,
2521    ) -> Result<(), Errno> {
2522        let end_addr = addr.checked_add(length).ok_or_else(|| errno!(EINVAL))?;
2523        let range_for_op = addr..end_addr;
2524        let mut updates = vec![];
2525
2526        for (range, mapping) in self.mappings.range(range_for_op.clone()) {
2527            if !mapping.private_anonymous() {
2528                track_stub!(TODO("https://fxbug.dev/391599171"), "uffd for shmem and hugetlbfs");
2529                return error!(EINVAL);
2530            }
2531            if mapping.flags().contains(MappingFlags::UFFD) {
2532                return error!(EBUSY);
2533            }
2534            let range = range.intersect(&range_for_op);
2535            let mut mapping = mapping.clone();
2536            mapping.set_uffd(mode);
2537            updates.push((range, mapping));
2538        }
2539        if updates.is_empty() {
2540            return error!(EINVAL);
2541        }
2542
2543        mm.protect_vmar_range(addr, length, ProtectionFlags::empty())
2544            .expect("Failed to remove protections on uffd-registered range");
2545
2546        // Use a separate loop to avoid mutating the mappings structure while iterating over it.
2547        for (range, mapping) in updates {
2548            released_mappings.extend(self.mappings.insert(range, mapping));
2549        }
2550
2551        userfault.insert_pages(range_for_op, false);
2552
2553        Ok(())
2554    }
2555
2556    fn unregister_range_from_uffd(
2557        &mut self,
2558        mm: &MemoryManager,
2559        userfault: &Arc<UserFault>,
2560        addr: UserAddress,
2561        length: usize,
2562        released_mappings: &mut ReleasedMappings,
2563    ) -> Result<(), Errno> {
2564        let end_addr = addr.checked_add(length).ok_or_else(|| errno!(EINVAL))?;
2565        let range_for_op = addr..end_addr;
2566        let mut updates = vec![];
2567
2568        for (range, mapping) in self.mappings.range(range_for_op.clone()) {
2569            if !mapping.private_anonymous() {
2570                track_stub!(TODO("https://fxbug.dev/391599171"), "uffd for shmem and hugetlbfs");
2571                return error!(EINVAL);
2572            }
2573            if mapping.flags().contains(MappingFlags::UFFD) {
2574                let range = range.intersect(&range_for_op);
2575                if userfault.remove_pages(range.clone()) {
2576                    let mut mapping = mapping.clone();
2577                    mapping.clear_uffd();
2578                    updates.push((range, mapping));
2579                }
2580            }
2581        }
2582        for (range, mapping) in updates {
2583            let length = range.end - range.start;
2584            let restored_flags = mapping.flags().access_flags();
2585
2586            released_mappings.extend(self.mappings.insert(range.clone(), mapping));
2587
2588            mm.protect_vmar_range(range.start, length, restored_flags)
2589                .expect("Failed to restore original protection bits on uffd-registered range");
2590        }
2591        Ok(())
2592    }
2593
2594    fn unregister_uffd(
2595        &mut self,
2596        mm: &MemoryManager,
2597        userfault: &Arc<UserFault>,
2598        released_mappings: &mut ReleasedMappings,
2599    ) {
2600        let mut updates = vec![];
2601
2602        for (range, mapping) in self.mappings.iter() {
2603            if mapping.flags().contains(MappingFlags::UFFD) {
2604                for range in userfault.get_registered_pages_overlapping_range(range.clone()) {
2605                    let mut mapping = mapping.clone();
2606                    mapping.clear_uffd();
2607                    updates.push((range.clone(), mapping));
2608                }
2609            }
2610        }
2611        // Use a separate loop to avoid mutating the mappings structure while iterating over it.
2612        for (range, mapping) in updates {
2613            let length = range.end - range.start;
2614            let restored_flags = mapping.flags().access_flags();
2615            released_mappings.extend(self.mappings.insert(range.clone(), mapping));
2616            // We can't recover from an error here as this is run during the cleanup.
2617            mm.protect_vmar_range(range.start, length, restored_flags)
2618                .expect("Failed to restore original protection bits on uffd-registered range");
2619        }
2620
2621        userfault.remove_pages(
2622            UserAddress::from_ptr(RESTRICTED_ASPACE_BASE)
2623                ..UserAddress::from_ptr(RESTRICTED_ASPACE_HIGHEST_ADDRESS),
2624        );
2625
2626        let weak_userfault = Arc::downgrade(userfault);
2627        self.userfaultfds.retain(|uf| !Weak::ptr_eq(uf, &weak_userfault));
2628    }
2629
2630    fn set_mapping_name(
2631        &mut self,
2632        addr: UserAddress,
2633        length: usize,
2634        name: Option<FsString>,
2635        released_mappings: &mut ReleasedMappings,
2636    ) -> Result<(), Errno> {
2637        if addr.ptr() % *PAGE_SIZE as usize != 0 {
2638            return error!(EINVAL);
2639        }
2640        let end = match addr.checked_add(length) {
2641            Some(addr) => addr.round_up(*PAGE_SIZE).map_err(|_| errno!(ENOMEM))?,
2642            None => return error!(EINVAL),
2643        };
2644
2645        let mappings_in_range =
2646            self.mappings.range(addr..end).map(|(r, m)| (r.clone(), m.clone())).collect::<Vec<_>>();
2647
2648        if mappings_in_range.is_empty() {
2649            return error!(EINVAL);
2650        }
2651        if !mappings_in_range.first().unwrap().0.contains(&addr) {
2652            return error!(ENOMEM);
2653        }
2654
2655        let mut last_range_end = None;
2656        // There's no get_mut on RangeMap, because it would be hard to implement correctly in
2657        // combination with merging of adjacent mappings. Instead, make a copy, change the copy,
2658        // and insert the copy.
2659        for (mut range, mut mapping) in mappings_in_range {
2660            if mapping.name().is_file() {
2661                // It's invalid to assign a name to a file-backed mapping.
2662                return error!(EBADF);
2663            }
2664            // Handle mappings that start before the region to be named.
2665            range.start = std::cmp::max(range.start, addr);
2666            // Handle mappings that extend past the region to be named.
2667            range.end = std::cmp::min(range.end, end);
2668
2669            if let Some(last_range_end) = last_range_end {
2670                if last_range_end != range.start {
2671                    // The name must apply to a contiguous range of mapped pages.
2672                    return error!(ENOMEM);
2673                }
2674            }
2675            last_range_end = Some(range.end.round_up(*PAGE_SIZE)?);
2676            // TODO(b/310255065): We have no place to store names in a way visible to programs outside of Starnix
2677            // such as memory analysis tools.
2678            if let MappingBacking::Memory(backing) = self.get_mapping_backing(&mapping) {
2679                match &name {
2680                    Some(memory_name) => {
2681                        backing.memory().set_zx_name(memory_name);
2682                    }
2683                    None => {
2684                        backing.memory().set_zx_name(b"");
2685                    }
2686                }
2687            }
2688            mapping.set_name(match &name {
2689                Some(name) => MappingName::Vma(FlyByteStr::new(name.as_bytes())),
2690                None => MappingName::None,
2691            });
2692            released_mappings.extend(self.mappings.insert(range, mapping));
2693        }
2694        if let Some(last_range_end) = last_range_end {
2695            if last_range_end < end {
2696                // The name must apply to a contiguous range of mapped pages.
2697                return error!(ENOMEM);
2698            }
2699        }
2700        Ok(())
2701    }
2702}
2703
2704/// The memory pinning shadow process used for mlock().
2705///
2706/// Uses its own distinct shadow process so that it doesn't interfere with other uses of memory
2707/// pinning.
2708pub struct MlockShadowProcess(memory_pinning::ShadowProcess);
2709
2710impl MemoryManager {
2711    /// Ensures that any mapping at `addr` is actually mapped at in the user vmar.
2712    ///
2713    /// If `length` is `None`, it will ensure the mapping only on the page `addr` falls into.
2714    /// Returns `true` if any lazy mappings are mapped.
2715    pub fn ensure_range_mapped_in_user_vmar(
2716        &self,
2717        addr: UserAddress,
2718        length: Option<usize>,
2719    ) -> Result<bool, Errno> {
2720        if !self.state.read().any_ranges_lazy(std::iter::once((addr, length))) {
2721            return Ok(false);
2722        }
2723        self.state.write().ensure_ranges_mapped_in_user_vmar(
2724            std::iter::once((addr, length)),
2725            &self.mapping_context,
2726        )
2727    }
2728
2729    /// Ensures that any mappings in the specified ranges are actually mapped in the user vmar.
2730    ///
2731    /// If `length` is `None`, it will ensure the mapping only on the page `addr` falls into.
2732    /// Returns `true` if any lazy mappings are mapped.
2733    pub fn ensure_ranges_mapped_in_user_vmar<I>(&self, ranges: I) -> Result<bool, Errno>
2734    where
2735        I: IntoIterator<Item = (UserAddress, Option<usize>)>,
2736    {
2737        // Collect ranges into a SmallVec with capacity 4 to avoid heap allocations in the common
2738        // case where there are only a few ranges (e.g., socket read/write buffers).
2739        let ranges = ranges.into_iter().collect::<SmallVec<[_; 4]>>();
2740        if !self.state.read().any_ranges_lazy(ranges.iter().cloned()) {
2741            return Ok(false);
2742        }
2743        self.state.write().ensure_ranges_mapped_in_user_vmar(ranges, &self.mapping_context)
2744    }
2745
2746    pub fn mrelease(&self) -> Result<(), Errno> {
2747        self.mapping_context.private_anonymous.zero(
2748            UserAddress::from_ptr(self.mapping_context.user_vmar_info.base),
2749            self.mapping_context.user_vmar_info.len,
2750        )?;
2751        Ok(())
2752    }
2753
2754    pub fn summarize(&self, summary: &mut crate::mm::MappingSummary) {
2755        let state = self.state.read();
2756        for (_, mapping) in state.mappings.iter() {
2757            summary.add(&state, mapping);
2758        }
2759    }
2760
2761    pub fn get_mappings_for_vmsplice(
2762        self: &Arc<MemoryManager>,
2763        buffers: &UserBuffers,
2764    ) -> Result<Vec<Arc<VmsplicePayload>>, Errno> {
2765        self.state.read().get_mappings_for_vmsplice(self, buffers)
2766    }
2767
2768    pub fn has_same_address_space(&self, other: &Self) -> bool {
2769        std::ptr::eq(self, other)
2770    }
2771
2772    fn unified_transfer_loop<F>(
2773        &self,
2774        addr: UserAddress,
2775        len: usize,
2776        mut transfer_fn: F,
2777    ) -> Result<usize, Errno>
2778    where
2779        F: FnMut(UserAddress, usize) -> Result<ControlFlow<usize, usize>, Errno>,
2780    {
2781        let mut copied = 0;
2782        while copied < len {
2783            match transfer_fn((addr + copied)?, copied)? {
2784                ControlFlow::Continue(num_copied) => {
2785                    if num_copied == 0 {
2786                        let fault_addr = (addr + copied)?;
2787                        // If we successfully mapped a lazy mapping, retry the copy.
2788                        // Otherwise, this might be a permission fault or invalid address, so we
2789                        // stop and return the partial result.
2790                        //
2791                        // NOTE: We lazily materialize mappings one page at a time here.
2792                        // An alternative approach would be to materialize the entire range
2793                        // or the first mapping up front. That might avoid bouncing between
2794                        // threads on faults, but adds overhead (locks and range lookups)
2795                        // if the memory is already mapped. We use the reactive approach
2796                        // for now, but this could be tuned in the future.
2797                        if self.ensure_range_mapped_in_user_vmar(fault_addr, None)? {
2798                            continue;
2799                        } else {
2800                            break;
2801                        }
2802                    }
2803                    copied += num_copied;
2804                }
2805                ControlFlow::Break(num_copied) => {
2806                    copied += num_copied;
2807                    break;
2808                }
2809            }
2810        }
2811        Ok(copied)
2812    }
2813
2814    pub fn unified_read_memory<'a>(
2815        &self,
2816        current_task: &CurrentTask,
2817        addr: UserAddress,
2818        bytes: &'a mut [MaybeUninit<u8>],
2819    ) -> Result<&'a mut [u8], Errno> {
2820        debug_assert!(self.has_same_address_space(&current_task.mm().unwrap()));
2821
2822        if let Some(usercopy) = usercopy() {
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                // SAFETY: Exclusive access to `bytes` for the lifetime of this function.
2828                let current_bytes = unsafe {
2829                    std::slice::from_raw_parts_mut(buf_ptr.add(offset), buf_len - offset)
2830                };
2831                let (read_bytes, _unread_bytes) = usercopy.copyin(cur_addr.ptr(), current_bytes);
2832                Ok(ControlFlow::Continue(read_bytes.len()))
2833            })?;
2834            if copied < bytes.len() {
2835                error!(EFAULT)
2836            } else {
2837                // SAFETY: All bytes up to `buf_len` have been initialized.
2838                Ok(unsafe { std::slice::from_raw_parts_mut(buf_ptr as *mut u8, buf_len) })
2839            }
2840        } else {
2841            self.syscall_read_memory(addr, bytes)
2842        }
2843    }
2844
2845    pub fn syscall_read_memory<'a>(
2846        &self,
2847        addr: UserAddress,
2848        bytes: &'a mut [MaybeUninit<u8>],
2849    ) -> Result<&'a mut [u8], Errno> {
2850        self.state.read().read_memory(addr, bytes, &self.mapping_context)
2851    }
2852
2853    pub fn unified_read_memory_partial_until_null_byte<'a>(
2854        &self,
2855        current_task: &CurrentTask,
2856        addr: UserAddress,
2857        bytes: &'a mut [MaybeUninit<u8>],
2858    ) -> Result<&'a mut [u8], Errno> {
2859        debug_assert!(self.has_same_address_space(&current_task.mm().unwrap()));
2860
2861        if let Some(usercopy) = usercopy() {
2862            let buf_ptr = bytes.as_mut_ptr();
2863            let buf_len = bytes.len();
2864
2865            let copied = self.unified_transfer_loop(addr, buf_len, |cur_addr, offset| {
2866                // SAFETY: Exclusive access to `bytes` for the lifetime of this function.
2867                let current_bytes = unsafe {
2868                    std::slice::from_raw_parts_mut(buf_ptr.add(offset), buf_len - offset)
2869                };
2870                let (read_bytes, _unread_bytes) =
2871                    usercopy.copyin_until_null_byte(cur_addr.ptr(), current_bytes);
2872
2873                let num_copied = read_bytes.len();
2874                if read_bytes.last().map(|b| *b == 0).unwrap_or(false) {
2875                    Ok(ControlFlow::Break(num_copied))
2876                } else {
2877                    Ok(ControlFlow::Continue(num_copied))
2878                }
2879            })?;
2880            if copied == 0 && !bytes.is_empty() {
2881                error!(EFAULT)
2882            } else {
2883                // SAFETY: Bytes up to `copied` have been initialized.
2884                Ok(unsafe { std::slice::from_raw_parts_mut(buf_ptr as *mut u8, copied) })
2885            }
2886        } else {
2887            self.syscall_read_memory_partial_until_null_byte(addr, bytes)
2888        }
2889    }
2890
2891    pub fn syscall_read_memory_partial_until_null_byte<'a>(
2892        &self,
2893        addr: UserAddress,
2894        bytes: &'a mut [MaybeUninit<u8>],
2895    ) -> Result<&'a mut [u8], Errno> {
2896        self.state.read().read_memory_partial_until_null_byte(addr, bytes, &self.mapping_context)
2897    }
2898
2899    pub fn unified_read_memory_partial<'a>(
2900        &self,
2901        current_task: &CurrentTask,
2902        addr: UserAddress,
2903        bytes: &'a mut [MaybeUninit<u8>],
2904    ) -> Result<&'a mut [u8], Errno> {
2905        debug_assert!(self.has_same_address_space(&current_task.mm().unwrap()));
2906
2907        if let Some(usercopy) = usercopy() {
2908            let buf_ptr = bytes.as_mut_ptr();
2909            let buf_len = bytes.len();
2910
2911            let copied = self.unified_transfer_loop(addr, buf_len, |cur_addr, offset| {
2912                // SAFETY: Exclusive access to `bytes` for the lifetime of this function.
2913                let current_bytes = unsafe {
2914                    std::slice::from_raw_parts_mut(buf_ptr.add(offset), buf_len - offset)
2915                };
2916                let (read_bytes, _unread_bytes) = usercopy.copyin(cur_addr.ptr(), current_bytes);
2917                Ok(ControlFlow::Continue(read_bytes.len()))
2918            })?;
2919            if copied == 0 && !bytes.is_empty() {
2920                error!(EFAULT)
2921            } else {
2922                // SAFETY: Bytes up to `copied` have been initialized.
2923                Ok(unsafe { std::slice::from_raw_parts_mut(buf_ptr as *mut u8, copied) })
2924            }
2925        } else {
2926            self.syscall_read_memory_partial(addr, bytes)
2927        }
2928    }
2929
2930    pub fn syscall_read_memory_partial<'a>(
2931        &self,
2932        addr: UserAddress,
2933        bytes: &'a mut [MaybeUninit<u8>],
2934    ) -> Result<&'a mut [u8], Errno> {
2935        self.state.read().read_memory_partial(addr, bytes, &self.mapping_context)
2936    }
2937
2938    pub fn unified_write_memory(
2939        &self,
2940        current_task: &CurrentTask,
2941        addr: UserAddress,
2942        bytes: &[u8],
2943    ) -> Result<usize, Errno> {
2944        debug_assert!(self.has_same_address_space(&current_task.mm().unwrap()));
2945
2946        if let Some(usercopy) = usercopy() {
2947            let len = bytes.len();
2948            let copied = self.unified_transfer_loop(addr, len, |cur_addr, offset| {
2949                Ok(ControlFlow::Continue(usercopy.copyout(&bytes[offset..], cur_addr.ptr())))
2950            })?;
2951            if copied < bytes.len() { error!(EFAULT) } else { Ok(copied) }
2952        } else {
2953            self.syscall_write_memory(addr, bytes)
2954        }
2955    }
2956
2957    /// Write `bytes` to memory address `addr`, making a copy-on-write child of the VMO backing and
2958    /// replacing the mapping if necessary.
2959    ///
2960    /// NOTE: this bypasses userspace's memory protection configuration and should only be called
2961    /// by codepaths like ptrace which bypass memory protection.
2962    pub fn force_write_memory(&self, addr: UserAddress, bytes: &[u8]) -> Result<(), Errno> {
2963        let mut state = self.state.write();
2964        let mut released_mappings = ReleasedMappings::default();
2965        let result =
2966            state.force_write_memory(&self.mapping_context, addr, bytes, &mut released_mappings);
2967        released_mappings.finalize(state);
2968        result
2969    }
2970
2971    pub fn syscall_write_memory(&self, addr: UserAddress, bytes: &[u8]) -> Result<usize, Errno> {
2972        self.state.read().write_memory(addr, bytes, &self.mapping_context)
2973    }
2974
2975    pub fn unified_write_memory_partial(
2976        &self,
2977        current_task: &CurrentTask,
2978        addr: UserAddress,
2979        bytes: &[u8],
2980    ) -> Result<usize, Errno> {
2981        debug_assert!(self.has_same_address_space(&current_task.mm().unwrap()));
2982
2983        if let Some(usercopy) = usercopy() {
2984            let len = bytes.len();
2985            let copied = self.unified_transfer_loop(addr, len, |cur_addr, offset| {
2986                Ok(ControlFlow::Continue(usercopy.copyout(&bytes[offset..], cur_addr.ptr())))
2987            })?;
2988            if copied == 0 && !bytes.is_empty() { error!(EFAULT) } else { Ok(copied) }
2989        } else {
2990            self.syscall_write_memory_partial(addr, bytes)
2991        }
2992    }
2993
2994    pub fn syscall_write_memory_partial(
2995        &self,
2996        addr: UserAddress,
2997        bytes: &[u8],
2998    ) -> Result<usize, Errno> {
2999        self.state.read().write_memory_partial(addr, bytes, &self.mapping_context)
3000    }
3001
3002    pub fn unified_zero(
3003        &self,
3004        current_task: &CurrentTask,
3005        addr: UserAddress,
3006        length: usize,
3007    ) -> Result<usize, Errno> {
3008        debug_assert!(self.has_same_address_space(&current_task.mm().unwrap()));
3009
3010        {
3011            let page_size = *PAGE_SIZE as usize;
3012            // Get the page boundary immediately following `addr` if `addr` is
3013            // not page aligned.
3014            let next_page_boundary = round_up_to_system_page_size(addr.ptr())?;
3015            // The number of bytes needed to zero at least a full page (not just
3016            // a pages worth of bytes) starting at `addr`.
3017            let length_with_atleast_one_full_page = page_size + (next_page_boundary - addr.ptr());
3018            // If at least one full page is being zeroed, go through the memory object since Zircon
3019            // can swap the mapped pages with the zero page which should be cheaper than zeroing
3020            // out a pages worth of bytes manually.
3021            //
3022            // If we are not zeroing out a full page, then go through usercopy
3023            // if unified aspaces is enabled.
3024            if length >= length_with_atleast_one_full_page {
3025                return self.syscall_zero(addr, length);
3026            }
3027        }
3028
3029        if let Some(usercopy) = usercopy() {
3030            let copied = self.unified_transfer_loop(addr, length, |cur_addr, offset| {
3031                Ok(ControlFlow::Continue(usercopy.zero(cur_addr.ptr(), length - offset)))
3032            })?;
3033            if copied == 0 && length > 0 { error!(EFAULT) } else { Ok(copied) }
3034        } else {
3035            self.syscall_zero(addr, length)
3036        }
3037    }
3038
3039    pub fn syscall_zero(&self, addr: UserAddress, length: usize) -> Result<usize, Errno> {
3040        self.state.read().zero(addr, length, &self.mapping_context)
3041    }
3042
3043    /// Performs a data and instruction cache flush over the given address range.
3044    pub fn cache_flush(&self, range: Range<UserAddress>) -> Result<(), Errno> {
3045        self.state.read().cache_flush(range, &self.mapping_context)
3046    }
3047
3048    /// Register the address space managed by this memory manager for interest in
3049    /// receiving private expedited memory barriers of the given type.
3050    pub fn register_membarrier_private_expedited(
3051        &self,
3052        mtype: MembarrierType,
3053    ) -> Result<(), Errno> {
3054        self.state.write().register_membarrier_private_expedited(mtype)
3055    }
3056
3057    /// Checks if the address space managed by this memory manager is registered
3058    /// for interest in private expedited barriers of the given kind.
3059    pub fn membarrier_private_expedited_registered(&self, mtype: MembarrierType) -> bool {
3060        self.state.read().membarrier_private_expedited_registered(mtype)
3061    }
3062}
3063
3064/// State and resources of the `MemoryManager` that are either immutable after creation
3065/// or handle their own interior mutability (e.g., `private_anonymous`).
3066///
3067/// This is distinct from `MemoryManagerState` in that the fields here do not require
3068/// acquisition of the `MemoryManager`'s main lock for access. This allows concurrent
3069/// access to these resources without lock contention.
3070///
3071/// This structure primarily holds the Zircon VMAR handle and the manager for private
3072/// anonymous memory, which are the core primitives used to manipulate the address space.
3073pub struct MappingContext {
3074    /// The VMAR in which userspace mappings occur.
3075    ///
3076    /// We map userspace memory in this child VMAR so that we can destroy the
3077    /// entire VMAR during exec.
3078    /// For 32-bit tasks, we limit the user_vmar to correspond to the available memory.
3079    ///
3080    /// This field is set to `ZX_HANDLE_INVALID` when the address-space has been destroyed (e.g. on
3081    /// `exec()`), allowing the value to be pro-actively checked for, or the `ZX_ERR_BAD_HANDLE`
3082    /// status return from Zircon operations handled, to suit the call-site.
3083    pub user_vmar: zx::Vmar,
3084
3085    /// Cached VmarInfo for user_vmar.
3086    pub user_vmar_info: zx::VmarInfo,
3087
3088    /// Memory object backing private, anonymous memory allocations in this address space.
3089    pub private_anonymous: PrivateAnonymousMemoryManager,
3090}
3091
3092impl MappingContext {
3093    fn map_in_user_vmar(
3094        &self,
3095        addr: SelectedAddress,
3096        memory: &MemoryObject,
3097        memory_offset: u64,
3098        length: usize,
3099        flags: MappingFlags,
3100        populate: bool,
3101    ) -> Result<(), Errno> {
3102        map_in_vmar(
3103            &self.user_vmar,
3104            &self.user_vmar_info,
3105            addr,
3106            memory,
3107            memory_offset,
3108            length,
3109            flags,
3110            populate,
3111        )
3112    }
3113
3114    pub fn max_address(&self) -> UserAddress {
3115        UserAddress::from_ptr(self.user_vmar_info.base + self.user_vmar_info.len)
3116    }
3117}
3118
3119pub struct MemoryManager {
3120    /// The base address of the root_vmar.
3121    pub base_addr: UserAddress,
3122
3123    /// The futexes in this address space.
3124    pub futex: Arc<FutexTable<PrivateFutexKey>>,
3125
3126    /// The mapping context for this address space.
3127    pub mapping_context: MappingContext,
3128
3129    /// Mutable state for the memory manager.
3130    pub state: RwLock<MemoryManagerState>,
3131
3132    /// Whether this address space is dumpable.
3133    pub dumpable: LockDepMutex<DumpPolicy, MmDumpable>,
3134
3135    /// Maximum valid user address for this vmar.
3136    pub maximum_valid_user_address: UserAddress,
3137
3138    /// In-flight payloads enqueued to a pipe as a consequence of a `vmsplice(2)`
3139    /// operation.
3140    ///
3141    /// For details on why we need to keep track of in-flight vmspliced payloads,
3142    /// see [`VmsplicePayload`].
3143    ///
3144    /// For details on why this isn't under the `LockDepRwLock` protected `MemoryManagerState`,
3145    /// See [`InflightVmsplicedPayloads::payloads`].
3146    pub inflight_vmspliced_payloads: InflightVmsplicedPayloads,
3147
3148    /// A mechanism to be notified when this `MemoryManager` is destroyed.
3149    pub drop_notifier: DropNotifier,
3150
3151    /// The architecture width of the process.
3152    pub arch_width: ArchWidth,
3153}
3154
3155impl ArchSpecific for MemoryManager {
3156    fn is_arch32(&self) -> bool {
3157        self.arch_width.is_arch32()
3158    }
3159}
3160
3161fn check_access_permissions_in_page_fault(
3162    decoded: &PageFaultExceptionReport,
3163    mapping: &Mapping,
3164) -> bool {
3165    let exec_denied = decoded.is_execute && !mapping.can_exec();
3166    let write_denied = decoded.is_write && !mapping.can_write();
3167    let read_denied = (!decoded.is_execute && !decoded.is_write) && !mapping.can_read();
3168    !exec_denied && !write_denied && !read_denied
3169}
3170
3171impl MemoryManager {
3172    /// Returns a new `MemoryManager` suitable for use in tests.
3173    pub fn new_for_test(root_vmar: zx::Unowned<'_, zx::Vmar>, arch_width: ArchWidth) -> Arc<Self> {
3174        Self::new(root_vmar, arch_width, None, None).expect("can create MemoryManager")
3175    }
3176
3177    // Returns details of mappings in the `user_vmar`, or an empty vector if the `user_vmar` has
3178    // been destroyed.
3179    fn with_zx_mappings<R>(
3180        &self,
3181        current_task: &CurrentTask,
3182        op: impl FnOnce(&[zx::MapInfo]) -> R,
3183    ) -> R {
3184        MapInfoCache::get_or_init(current_task)
3185            .expect("must be able to retrieve map info cache")
3186            .with_map_infos(&self.mapping_context.user_vmar, |infos| match infos {
3187                Ok(infos) => op(infos),
3188                Err(_) => op(&[]),
3189            })
3190    }
3191
3192    fn protect_vmar_range(
3193        &self,
3194        addr: UserAddress,
3195        length: usize,
3196        prot_flags: ProtectionFlags,
3197    ) -> Result<(), Errno> {
3198        let vmar_flags = prot_flags.to_vmar_flags();
3199        // SAFETY: Modifying user vmar
3200        unsafe { self.mapping_context.user_vmar.protect(addr.ptr(), length, vmar_flags) }.map_err(
3201            |s| match s {
3202                zx::Status::INVALID_ARGS => errno!(EINVAL),
3203                zx::Status::NOT_FOUND => errno!(ENOMEM),
3204                zx::Status::ACCESS_DENIED => errno!(EACCES),
3205                _ => impossible_error(s),
3206            },
3207        )
3208    }
3209
3210    pub fn total_locked_bytes(&self) -> u64 {
3211        self.state.read().num_locked_bytes(
3212            UserAddress::from(self.mapping_context.user_vmar_info.base as u64)
3213                ..UserAddress::from(
3214                    (self.mapping_context.user_vmar_info.base
3215                        + self.mapping_context.user_vmar_info.len) as u64,
3216                ),
3217        )
3218    }
3219
3220    /// Returns a new `MemoryManager` initialized with a new userspace VMAR matching the specified
3221    /// `arch_width`, under the specified restricted-mode `root_vmar`.  The `executable_node` that
3222    /// the new address-space will execute may optionally be supplied.
3223    fn new(
3224        root_vmar: zx::Unowned<'_, zx::Vmar>,
3225        arch_width: ArchWidth,
3226        executable_node: Option<NamespaceNode>,
3227        private_anonymous: Option<PrivateAnonymousMemoryManager>,
3228    ) -> Result<Arc<Self>, Errno> {
3229        debug_assert!(!root_vmar.is_invalid());
3230
3231        let mut vmar_info = root_vmar.info().map_err(|status| from_status_like_fdio!(status))?;
3232        if arch_width.is_arch32() {
3233            vmar_info.len = (LOWER_4GB_LIMIT.ptr() - vmar_info.base) as usize;
3234        }
3235
3236        let (user_vmar, ptr) = root_vmar
3237            .allocate(
3238                0,
3239                vmar_info.len,
3240                zx::VmarFlags::SPECIFIC
3241                    | zx::VmarFlags::CAN_MAP_SPECIFIC
3242                    | zx::VmarFlags::CAN_MAP_READ
3243                    | zx::VmarFlags::CAN_MAP_WRITE
3244                    | zx::VmarFlags::CAN_MAP_EXECUTE,
3245            )
3246            .map_err(|status| from_status_like_fdio!(status))?;
3247        assert_eq!(ptr, vmar_info.base);
3248
3249        let user_vmar_info = user_vmar.info().map_err(|status| from_status_like_fdio!(status))?;
3250
3251        // Ensure that the `user_vmar_info` matches assumptions for the requested layout.
3252        debug_assert_eq!(RESTRICTED_ASPACE_BASE, user_vmar_info.base);
3253        if arch_width.is_arch32() {
3254            debug_assert_eq!(LOWER_4GB_LIMIT.ptr() - user_vmar_info.base, user_vmar_info.len);
3255        } else {
3256            debug_assert_eq!(RESTRICTED_ASPACE_SIZE, user_vmar_info.len);
3257        }
3258
3259        // The private anonymous backing memory object extend from the user address 0 up to the
3260        // highest mappable address. The pages below `user_vmar_info.base` are never mapped, but
3261        // including them in the memory object makes the math for mapping address to memory object
3262        // offsets simpler.
3263        let backing_size = (user_vmar_info.base + user_vmar_info.len) as u64;
3264
3265        // Place the stack at the end of the address space, subject to ASLR adjustment. The stack
3266        // grows down, so the origin corresponds to the top of the initial stack.
3267        let stack_origin = UserAddress::from_ptr(
3268            user_vmar_info.base + user_vmar_info.len - generate_random_offset_for_aslr(arch_width),
3269        )
3270        .round_up(*PAGE_SIZE)?;
3271
3272        // Set the highest address that `mmap` will assign to the allocations that don't ask for a
3273        // specific address, subject to ASLR adjustment.
3274        let mmap_top = stack_origin
3275            .checked_sub(MAX_STACK_SIZE + generate_random_offset_for_aslr(arch_width))
3276            .ok_or_else(|| errno!(EINVAL))?;
3277
3278        Ok(Arc::new(MemoryManager {
3279            base_addr: UserAddress::from_ptr(user_vmar_info.base),
3280            futex: Arc::<FutexTable<PrivateFutexKey>>::default(),
3281            mapping_context: MappingContext {
3282                user_vmar,
3283                user_vmar_info,
3284                private_anonymous: private_anonymous
3285                    .unwrap_or_else(|| PrivateAnonymousMemoryManager::new(backing_size)),
3286            },
3287            state: MemoryManagerState {
3288                mappings: Default::default(),
3289                userfaultfds: Default::default(),
3290                shadow_mappings_for_mlock: Default::default(),
3291                forkable_state: MemoryManagerForkableState {
3292                    executable_node,
3293                    stack_origin,
3294                    mmap_top,
3295                    ..Default::default()
3296                },
3297            }
3298            .into(),
3299            // TODO(security): Reset to DISABLE, or the value in the fs.suid_dumpable sysctl, under
3300            // certain conditions as specified in the prctl(2) man page.
3301            dumpable: LockDepMutex::new(DumpPolicy::User),
3302            maximum_valid_user_address: UserAddress::from_ptr(
3303                user_vmar_info.base + user_vmar_info.len,
3304            ),
3305            inflight_vmspliced_payloads: Default::default(),
3306            drop_notifier: DropNotifier::default(),
3307            arch_width,
3308        }))
3309    }
3310
3311    pub fn set_brk(
3312        self: &Arc<Self>,
3313        current_task: &CurrentTask,
3314        addr: UserAddress,
3315    ) -> Result<UserAddress, Errno> {
3316        let mut state = self.state.write();
3317        let mut released_mappings = ReleasedMappings::default();
3318        let result = state.set_brk(current_task, self, addr, &mut released_mappings);
3319        released_mappings.finalize(state);
3320        result
3321    }
3322
3323    pub fn register_uffd(&self, userfault: &Arc<UserFault>) {
3324        let mut state = self.state.write();
3325        state.userfaultfds.push(Arc::downgrade(userfault));
3326    }
3327
3328    /// Register a given memory range with a userfault object.
3329    pub fn register_with_uffd(
3330        self: &Arc<Self>,
3331        addr: UserAddress,
3332        length: usize,
3333        userfault: &Arc<UserFault>,
3334        mode: FaultRegisterMode,
3335    ) -> Result<(), Errno> {
3336        let mut state = self.state.write();
3337        let mut released_mappings = ReleasedMappings::default();
3338        let result =
3339            state.register_with_uffd(self, addr, length, userfault, mode, &mut released_mappings);
3340        released_mappings.finalize(state);
3341        result
3342    }
3343
3344    /// Unregister a given range from any userfault objects associated with it.
3345    pub fn unregister_range_from_uffd(
3346        &self,
3347        userfault: &Arc<UserFault>,
3348        addr: UserAddress,
3349        length: usize,
3350    ) -> Result<(), Errno> {
3351        let mut state = self.state.write();
3352        let mut released_mappings = ReleasedMappings::default();
3353        let result =
3354            state.unregister_range_from_uffd(self, userfault, addr, length, &mut released_mappings);
3355        released_mappings.finalize(state);
3356        result
3357    }
3358
3359    /// Unregister any mappings registered with a given userfault object. Used when closing the last
3360    /// file descriptor associated to it.
3361    pub fn unregister_uffd(&self, userfault: &Arc<UserFault>) {
3362        let mut state = self.state.write();
3363        let mut released_mappings = ReleasedMappings::default();
3364        state.unregister_uffd(self, userfault, &mut released_mappings);
3365        released_mappings.finalize(state);
3366    }
3367
3368    /// Populate a range of pages registered with an userfaulfd according to a `populate` function.
3369    /// This will fail if the pages were not registered with userfaultfd, or if the page at `addr`
3370    /// was already populated. If any page other than the first one was populated, the `length`
3371    /// is adjusted to only include the first N unpopulated pages, and this adjusted length
3372    /// is then passed to `populate`. On success, returns the number of populated bytes.
3373    pub fn populate_from_uffd<F>(
3374        &self,
3375        addr: UserAddress,
3376        length: usize,
3377        userfault: &Arc<UserFault>,
3378        populate: F,
3379    ) -> Result<usize, Errno>
3380    where
3381        F: FnOnce(&MemoryManagerState, usize) -> Result<usize, Errno>,
3382    {
3383        let state = self.state.read();
3384        // Check that the addr..length range is a contiguous range of mappings which are all
3385        // registered with an userfault object.
3386        let mut bytes_registered_with_uffd = 0;
3387        for (mapping, len) in
3388            state.get_contiguous_mappings_at(addr, length, &self.mapping_context)?
3389        {
3390            if mapping.flags().contains(MappingFlags::UFFD) {
3391                // Check that the mapping is registered with the same uffd. This is not required,
3392                // but we don't support cross-uffd operations yet.
3393                if !userfault.contains_addr(addr) {
3394                    track_stub!(
3395                        TODO("https://fxbug.dev/391599171"),
3396                        "operations across different uffds"
3397                    );
3398                    return error!(ENOTSUP);
3399                };
3400            } else {
3401                return error!(ENOENT);
3402            }
3403            bytes_registered_with_uffd += len;
3404        }
3405        if bytes_registered_with_uffd != length {
3406            return error!(ENOENT);
3407        }
3408
3409        let end_addr = addr.checked_add(length).ok_or_else(|| errno!(EINVAL))?;
3410
3411        // Determine how many pages in the requested range are already populated
3412        let first_populated =
3413            userfault.get_first_populated_page_after(addr).ok_or_else(|| errno!(ENOENT))?;
3414        // If the very first page is already populated, uffd operations should just return EEXIST
3415        if first_populated == addr {
3416            return error!(EEXIST);
3417        }
3418        // Otherwise it is possible to do an incomplete operation by only populating pages until
3419        // the first populated one.
3420        let trimmed_end = std::cmp::min(first_populated, end_addr);
3421        let effective_length = trimmed_end - addr;
3422
3423        populate(&state, effective_length)?;
3424        userfault.insert_pages(addr..trimmed_end, true);
3425
3426        // Since we used protection bits to force pagefaults, we now need to reverse this change by
3427        // restoring the protections on the underlying Zircon mappings to the "real" protection bits
3428        // that were kept in the Starnix mappings. This will prevent new pagefaults from being
3429        // generated. Only do this on the pages that were populated by this operation.
3430        for (range, mapping) in state.mappings.range(addr..trimmed_end) {
3431            let range_to_protect = range.intersect(&(addr..trimmed_end));
3432            let restored_flags = mapping.flags().access_flags();
3433            let length = range_to_protect.end - range_to_protect.start;
3434            self.protect_vmar_range(range_to_protect.start, length, restored_flags)
3435                .expect("Failed to restore original protection bits on uffd-registered range");
3436        }
3437        // Return the number of effectively populated bytes, which might be smaller than the
3438        // requested number.
3439        Ok(effective_length)
3440    }
3441
3442    pub fn zero_from_uffd(
3443        &self,
3444        addr: UserAddress,
3445        length: usize,
3446        userfault: &Arc<UserFault>,
3447    ) -> Result<usize, Errno> {
3448        self.populate_from_uffd(addr, length, userfault, |state, effective_length| {
3449            state.zero(addr, effective_length, &self.mapping_context)
3450        })
3451    }
3452
3453    pub fn fill_from_uffd(
3454        &self,
3455        addr: UserAddress,
3456        buf: &[u8],
3457        length: usize,
3458        userfault: &Arc<UserFault>,
3459    ) -> Result<usize, Errno> {
3460        self.populate_from_uffd(addr, length, userfault, |state, effective_length| {
3461            state.write_memory(addr, &buf[..effective_length], &self.mapping_context)
3462        })
3463    }
3464
3465    pub fn copy_from_uffd(
3466        &self,
3467        source_addr: UserAddress,
3468        dst_addr: UserAddress,
3469        length: usize,
3470        userfault: &Arc<UserFault>,
3471    ) -> Result<usize, Errno> {
3472        self.populate_from_uffd(dst_addr, length, userfault, |state, effective_length| {
3473            let mut buf = vec![std::mem::MaybeUninit::uninit(); effective_length];
3474            let buf = state.read_memory(source_addr, &mut buf, &self.mapping_context)?;
3475            state.write_memory(dst_addr, &buf[..effective_length], &self.mapping_context)
3476        })
3477    }
3478
3479    /// Returns the new `MemoryManager` for a process, pre-populated with a snapshot of the layout
3480    /// and mappings of `source_mm`.  This is used during `CurrentTask::clone()` operations to
3481    /// create the initial address-space for the cloned child process.
3482    pub fn snapshot_of(
3483        source_mm: &Arc<MemoryManager>,
3484        root_vmar: zx::Unowned<'_, zx::Vmar>,
3485        arch_width: ArchWidth,
3486    ) -> Result<Arc<Self>, Errno> {
3487        fuchsia_trace::duration!(CATEGORY_STARNIX_MM, "snapshot_of");
3488        let backing_size = (source_mm.mapping_context.user_vmar_info.base
3489            + source_mm.mapping_context.user_vmar_info.len) as u64;
3490        let private_anonymous =
3491            source_mm.mapping_context.private_anonymous.snapshot(backing_size)?;
3492        let target = MemoryManager::new(
3493            root_vmar,
3494            arch_width,
3495            source_mm.executable_node(),
3496            Some(private_anonymous),
3497        )?;
3498
3499        // Hold the lock throughout the operation to uphold memory manager's invariants.
3500        // See mm/README.md.
3501        {
3502            let (state, mut target_state) = ordered_write_lock(&source_mm.state, &target.state);
3503            debug_assert_eq!(
3504                source_mm.mapping_context.user_vmar_info,
3505                target.mapping_context.user_vmar_info
3506            );
3507
3508            let mut clone_cache = HashMap::<zx::Koid, Arc<MemoryObject>>::new();
3509
3510            for (range, mapping) in state.mappings.iter() {
3511                if mapping.flags().contains(MappingFlags::DONTFORK) {
3512                    continue;
3513                }
3514                // Locking is not inherited when forking.
3515                let target_mapping_flags = mapping.flags().difference(MappingFlags::LOCKED);
3516                match state.get_mapping_backing(mapping) {
3517                    MappingBacking::Memory(backing) => {
3518                        fuchsia_trace::duration!(CATEGORY_STARNIX_MM, "memory_backing_clone");
3519                        let memory_offset = backing.address_to_offset(range.start);
3520
3521                        let target_memory = if mapping.flags().contains(MappingFlags::SHARED)
3522                            || mapping.name().is_vvar()
3523                        {
3524                            // Note that the Vvar is a special mapping that behaves like a shared mapping but
3525                            // is private to each process.
3526                            backing.memory().clone()
3527                        } else {
3528                            let memory_obj = backing.memory();
3529                            let options = mapping.flags().options();
3530                            let memory =
3531                                clone_cache.entry(memory_obj.get_koid()).or_insert_with_fallible(
3532                                    || memory_obj.clone_memory(memory_obj.get_rights(), options),
3533                                )?;
3534                            memory.clone()
3535                        };
3536
3537                        let mapping = Mapping::with_name(
3538                            MappingBacking::Memory(Box::new(MappingBackingMemory::new(
3539                                range.start,
3540                                target_memory,
3541                                memory_offset,
3542                            ))),
3543                            target_mapping_flags,
3544                            mapping.max_access(),
3545                            mapping.name().to_owned(),
3546                            MappingMode::Lazy,
3547                        );
3548                        assert!(
3549                            target_state.mappings.append_non_overlapping(range.clone(), mapping)
3550                        );
3551                    }
3552                    MappingBacking::PrivateAnonymous => {
3553                        fuchsia_trace::duration!(
3554                            CATEGORY_STARNIX_MM,
3555                            "private_anonymous_backing_clone"
3556                        );
3557                        let length = range.end - range.start;
3558                        if mapping.flags().contains(MappingFlags::WIPEONFORK) {
3559                            target
3560                                .mapping_context
3561                                .private_anonymous
3562                                .zero(range.start, length)
3563                                .map_err(|_| errno!(ENOMEM))?;
3564                        }
3565
3566                        let mapping = Mapping::new_private_anonymous(
3567                            target_mapping_flags,
3568                            mapping.name().to_owned(),
3569                            MappingMode::Lazy,
3570                        );
3571                        assert!(
3572                            target_state.mappings.append_non_overlapping(range.clone(), mapping)
3573                        );
3574                    }
3575                };
3576            }
3577
3578            target_state.forkable_state = state.forkable_state.clone();
3579        }
3580
3581        let self_dumpable = *source_mm.dumpable.lock();
3582        *target.dumpable.lock() = self_dumpable;
3583
3584        Ok(target)
3585    }
3586
3587    /// Returns the replacement `MemoryManager` to be used by the `exec()`ing task.
3588    ///
3589    /// POSIX requires that "a call to any exec function from a process with more than one thread
3590    /// shall result in all threads being terminated and the new executable being loaded and
3591    /// executed. No destructor functions or cleanup handlers shall be called".
3592    /// The caller is responsible for having ensured that this is the only `Task` in the
3593    /// `ThreadGroup`, and thereby the `zx::process`, such that it is safe to tear-down the Zircon
3594    /// userspace VMAR for the current address-space.
3595    pub fn exec(
3596        root_vmar: zx::Unowned<'_, zx::Vmar>,
3597        old_mm: Option<Arc<Self>>,
3598        exe_node: NamespaceNode,
3599        arch_width: ArchWidth,
3600    ) -> Result<Arc<Self>, Errno> {
3601        // To safeguard against concurrent accesses by other tasks through this `MemoryManager`, the
3602        // following steps are performed while holding the write lock on the old MM, if any:
3603        //
3604        // 1. All `mappings` are removed, so that remote `MemoryAccessor` calls will fail.
3605        // 2. The `user_vmar` is `destroy()`ed to free-up the user address-space.
3606        //
3607        // Once these steps are complete it is safe for the old mappings to be dropped.
3608        if let Some(old_mm) = old_mm {
3609            let _old_mappings = {
3610                let mut state = old_mm.state.write();
3611
3612                // SAFETY: This operation is safe because this is the only `Task` active in the address-
3613                // space, and accesses by remote tasks will use syscalls on the `root_vmar`.
3614                unsafe {
3615                    old_mm
3616                        .mapping_context
3617                        .user_vmar
3618                        .destroy()
3619                        .map_err(|status| from_status_like_fdio!(status))?
3620                }
3621
3622                std::mem::replace(&mut state.mappings, Default::default())
3623            };
3624        }
3625
3626        Self::new(root_vmar, arch_width, Some(exe_node), None)
3627    }
3628
3629    pub fn initialize_brk_origin(
3630        &self,
3631        arch_width: ArchWidth,
3632        executable_end: UserAddress,
3633    ) -> Result<(), Errno> {
3634        self.state.write().brk_origin = executable_end
3635            .checked_add(generate_random_offset_for_aslr(arch_width))
3636            .ok_or_else(|| errno!(EINVAL))?;
3637        Ok(())
3638    }
3639
3640    // Get a randomised address for loading a position-independent executable.
3641    pub fn get_random_base_for_executable(
3642        &self,
3643        arch_width: ArchWidth,
3644        length: usize,
3645    ) -> Result<UserAddress, Errno> {
3646        let state = self.state.read();
3647
3648        // Place it at approx. 2/3 of the available mmap space, subject to ASLR adjustment.
3649        let base = round_up_to_system_page_size(2 * state.mmap_top.ptr() / 3).unwrap()
3650            + generate_random_offset_for_aslr(arch_width);
3651        if base.checked_add(length).ok_or_else(|| errno!(EINVAL))? <= state.mmap_top.ptr() {
3652            Ok(UserAddress::from_ptr(base))
3653        } else {
3654            error!(EINVAL)
3655        }
3656    }
3657    pub fn executable_node(&self) -> Option<NamespaceNode> {
3658        self.state.read().executable_node.clone()
3659    }
3660
3661    #[track_caller]
3662    pub fn get_errno_for_map_err(status: zx::Status) -> Errno {
3663        match status {
3664            zx::Status::INVALID_ARGS => errno!(EINVAL),
3665            zx::Status::ACCESS_DENIED => errno!(EPERM),
3666            zx::Status::NOT_SUPPORTED => errno!(ENODEV),
3667            zx::Status::NO_MEMORY => errno!(ENOMEM),
3668            zx::Status::NO_RESOURCES => errno!(ENOMEM),
3669            zx::Status::OUT_OF_RANGE => errno!(ENOMEM),
3670            zx::Status::ALREADY_EXISTS => errno!(EEXIST),
3671            zx::Status::BAD_STATE => errno!(EINVAL),
3672            _ => impossible_error(status),
3673        }
3674    }
3675
3676    #[track_caller]
3677    pub fn get_errno_for_vmo_err(status: zx::Status) -> Errno {
3678        match status {
3679            zx::Status::NO_MEMORY => errno!(ENOMEM),
3680            zx::Status::ACCESS_DENIED => errno!(EPERM),
3681            zx::Status::NOT_SUPPORTED => errno!(EIO),
3682            zx::Status::BAD_STATE => errno!(EIO),
3683            _ => return impossible_error(status),
3684        }
3685    }
3686
3687    pub fn map_memory(
3688        self: &Arc<Self>,
3689        addr: DesiredAddress,
3690        memory: Arc<MemoryObject>,
3691        memory_offset: u64,
3692        length: usize,
3693        prot_flags: ProtectionFlags,
3694        max_access: Access,
3695        options: MappingOptions,
3696        name: MappingName,
3697    ) -> Result<UserAddress, Errno> {
3698        let flags = MappingFlags::from_access_flags_and_options(prot_flags, options);
3699
3700        // Unmapped mappings must be released after the state is unlocked.
3701        let mut released_mappings = ReleasedMappings::default();
3702        // Hold the lock throughout the operation to uphold memory manager's invariants.
3703        // See mm/README.md.
3704        let mut state = self.state.write();
3705        let result = state.add_memory_mapping(
3706            self,
3707            addr,
3708            memory,
3709            memory_offset,
3710            length,
3711            flags,
3712            max_access,
3713            options.contains(MappingOptions::POPULATE),
3714            name,
3715            MappingMode::Eager,
3716            &mut released_mappings,
3717        );
3718
3719        // Drop the state before the unmapped mappings, since dropping a mapping may acquire a lock
3720        // in `DirEntry`'s `drop`.
3721        released_mappings.finalize(state);
3722
3723        result
3724    }
3725
3726    pub fn map_anonymous(
3727        self: &Arc<Self>,
3728        addr: DesiredAddress,
3729        length: usize,
3730        prot_flags: ProtectionFlags,
3731        options: MappingOptions,
3732        name: MappingName,
3733    ) -> Result<UserAddress, Errno> {
3734        let mut released_mappings = ReleasedMappings::default();
3735        // Hold the lock throughout the operation to uphold memory manager's invariants.
3736        // See mm/README.md.
3737        let mut state = self.state.write();
3738        let result = state.map_anonymous(
3739            self,
3740            addr,
3741            length,
3742            prot_flags,
3743            options,
3744            name,
3745            &mut released_mappings,
3746        );
3747
3748        released_mappings.finalize(state);
3749
3750        result
3751    }
3752
3753    /// Map the stack into a pre-selected address region
3754    pub fn map_stack(
3755        self: &Arc<Self>,
3756        length: usize,
3757        prot_flags: ProtectionFlags,
3758    ) -> Result<UserAddress, Errno> {
3759        assert!(length <= MAX_STACK_SIZE);
3760        let addr = (self.state.read().stack_origin - length)?;
3761        // The address range containing stack_origin should normally be available: it's above the
3762        // mmap_top, and this method is called early enough in the process lifetime that only the
3763        // main ELF and the interpreter are already loaded. However, in the rare case that the
3764        // static position-independent executable is overlapping the chosen address, mapping as Hint
3765        // will make mmap choose a new place for it.
3766        // TODO(https://fxbug.dev/370027241): Consider a more robust approach
3767        let stack_addr = self.map_anonymous(
3768            DesiredAddress::Hint(addr),
3769            length,
3770            prot_flags,
3771            MappingOptions::ANONYMOUS | MappingOptions::GROWSDOWN,
3772            MappingName::Stack,
3773        )?;
3774        if stack_addr != addr {
3775            log_warn!(
3776                "An address designated for stack ({}) was unavailable, mapping at {} instead.",
3777                addr,
3778                stack_addr
3779            );
3780        }
3781        Ok(stack_addr)
3782    }
3783
3784    pub fn remap(
3785        self: &Arc<Self>,
3786        current_task: &CurrentTask,
3787        addr: UserAddress,
3788        old_length: usize,
3789        new_length: usize,
3790        flags: MremapFlags,
3791        new_addr: UserAddress,
3792    ) -> Result<UserAddress, Errno> {
3793        let mut released_mappings = ReleasedMappings::default();
3794        // Hold the lock throughout the operation to uphold memory manager's invariants.
3795        // See mm/README.md.
3796        let mut state = self.state.write();
3797        let result = state.remap(
3798            current_task,
3799            self,
3800            addr,
3801            old_length,
3802            new_length,
3803            flags,
3804            new_addr,
3805            &mut released_mappings,
3806        );
3807
3808        released_mappings.finalize(state);
3809
3810        result
3811    }
3812
3813    pub fn unmap(self: &Arc<Self>, addr: UserAddress, length: usize) -> Result<(), Errno> {
3814        let mut released_mappings = ReleasedMappings::default();
3815        // Hold the lock throughout the operation to uphold memory manager's invariants.
3816        // See mm/README.md.
3817        let mut state = self.state.write();
3818        let result = state.unmap(self, addr, length, &mut released_mappings);
3819
3820        released_mappings.finalize(state);
3821
3822        result
3823    }
3824
3825    pub fn protect(
3826        &self,
3827        current_task: &CurrentTask,
3828        addr: UserAddress,
3829        length: usize,
3830        prot_flags: ProtectionFlags,
3831    ) -> Result<(), Errno> {
3832        let page_size = *PAGE_SIZE;
3833        if !addr.is_aligned(page_size) {
3834            return error!(EINVAL);
3835        }
3836        if length == 0 {
3837            return Ok(());
3838        }
3839        let end = addr.checked_add(length).ok_or_else(|| errno!(ENOMEM))?.round_up(page_size)?;
3840        if end > self.maximum_valid_user_address {
3841            return error!(ENOMEM);
3842        }
3843
3844        // Hold the lock throughout the operation to uphold memory manager's invariants.
3845        // See mm/README.md.
3846        let mut state = self.state.write();
3847        let mut released_mappings = ReleasedMappings::default();
3848        let result = state.protect(current_task, addr, length, prot_flags, &mut released_mappings);
3849        released_mappings.finalize(state);
3850        result
3851    }
3852
3853    pub fn msync(
3854        &self,
3855        current_task: &CurrentTask,
3856        addr: UserAddress,
3857        length: usize,
3858        flags: MsyncFlags,
3859    ) -> Result<(), Errno> {
3860        // According to POSIX, either MS_SYNC or MS_ASYNC must be specified in flags,
3861        // and indeed failure to include one of these flags will cause msync() to fail
3862        // on some systems.  However, Linux permits a call to msync() that specifies
3863        // neither of these flags, with semantics that are (currently) equivalent to
3864        // specifying MS_ASYNC.
3865
3866        // Both MS_SYNC and MS_ASYNC are set in flags
3867        if flags.contains(MsyncFlags::ASYNC) && flags.contains(MsyncFlags::SYNC) {
3868            return error!(EINVAL);
3869        }
3870
3871        if !addr.is_aligned(*PAGE_SIZE) {
3872            return error!(EINVAL);
3873        }
3874
3875        // We collect the nodes to sync first, release the memory manager lock, and then sync them.
3876        // This avoids holding the lock during blocking I/O operations (sync), which prevents
3877        // stalling other memory operations and avoids potential deadlocks.
3878        // It also allows us to deduplicate nodes, avoiding redundant sync calls for the same file.
3879        let mut nodes_to_sync = {
3880            let mm_state = self.state.read();
3881
3882            let length_rounded = round_up_to_system_page_size(length)?;
3883            let end_addr = addr.checked_add(length_rounded).ok_or_else(|| errno!(EINVAL))?;
3884
3885            let mut last_end = addr;
3886            let mut nodes = vec![];
3887            for (range, mapping) in mm_state.mappings.range(addr..end_addr) {
3888                // Check if there is a gap between the last mapped address and the current mapping.
3889                // msync requires the entire range to be mapped, so any gap results in ENOMEM.
3890                if range.start > last_end {
3891                    return error!(ENOMEM);
3892                }
3893                last_end = range.end;
3894
3895                if flags.contains(MsyncFlags::INVALIDATE)
3896                    && mapping.flags().contains(MappingFlags::LOCKED)
3897                {
3898                    return error!(EBUSY);
3899                }
3900
3901                if flags.contains(MsyncFlags::SYNC) {
3902                    if let MappingNameRef::File(file_mapping) = mapping.name() {
3903                        nodes.push(file_mapping.name.entry.node.clone());
3904                    }
3905                }
3906            }
3907            if last_end < end_addr {
3908                return error!(ENOMEM);
3909            }
3910            nodes
3911        };
3912
3913        // Deduplicate nodes to avoid redundant sync calls.
3914        nodes_to_sync.sort_by_key(|n| Arc::as_ptr(n) as usize);
3915        nodes_to_sync.dedup_by(|a, b| Arc::ptr_eq(a, b));
3916
3917        for node in nodes_to_sync {
3918            // Range-based sync is non-trivial for Fxfs to support due to its complicated
3919            // reservation system (b/322874588#comment5). Naive range-based sync could exhaust
3920            // space reservations if called page-by-page, as transaction costs are based on the
3921            // number of dirty pages rather than file ranges. We use whole-file sync for now
3922            // to ensure data durability without adding excessive complexity.
3923            node.ops().sync(&node, current_task)?;
3924        }
3925        Ok(())
3926    }
3927
3928    pub fn madvise(&self, addr: UserAddress, length: usize, advice: u32) -> Result<(), Errno> {
3929        let mut state = self.state.write();
3930        let mut released_mappings = ReleasedMappings::default();
3931        let result =
3932            state.madvise(&self.mapping_context, addr, length, advice, &mut released_mappings);
3933        released_mappings.finalize(state);
3934        result
3935    }
3936
3937    pub fn mlock(
3938        &self,
3939        current_task: &CurrentTask,
3940        desired_addr: UserAddress,
3941        desired_length: usize,
3942        on_fault: bool,
3943    ) -> Result<(), Errno> {
3944        let mut state = self.state.write();
3945        let mut released_mappings = ReleasedMappings::default();
3946        let result = state.mlock(
3947            &self.mapping_context,
3948            current_task,
3949            desired_addr,
3950            desired_length,
3951            on_fault,
3952            &mut released_mappings,
3953        );
3954        released_mappings.finalize(state);
3955        result
3956    }
3957
3958    pub fn munlock(
3959        &self,
3960        current_task: &CurrentTask,
3961        desired_addr: UserAddress,
3962        desired_length: usize,
3963    ) -> Result<(), Errno> {
3964        let mut state = self.state.write();
3965        let mut released_mappings = ReleasedMappings::default();
3966        let result =
3967            state.munlock(current_task, desired_addr, desired_length, &mut released_mappings);
3968        released_mappings.finalize(state);
3969        result
3970    }
3971
3972    pub fn log_memory_map(&self, task: &Task, fault_address: UserAddress) {
3973        let state = self.state.read();
3974        log_warn!("Memory map for pid={}:", task.thread_group.leader);
3975        let mut last_end = UserAddress::from_ptr(0);
3976        for (range, map) in state.mappings.iter() {
3977            if fault_address >= last_end && fault_address < range.start {
3978                log_warn!("{:08x} <= FAULT", fault_address.ptr());
3979            }
3980
3981            let perms = format!(
3982                "{}{}{}{}",
3983                if map.can_read() { 'r' } else { '-' },
3984                if map.can_write() { 'w' } else { '-' },
3985                if map.can_exec() { 'x' } else { '-' },
3986                if map.flags().contains(MappingFlags::SHARED) { 's' } else { 'p' }
3987            );
3988
3989            let backing = match state.get_mapping_backing(map) {
3990                MappingBacking::Memory(backing) => backing.address_to_offset(range.start),
3991                MappingBacking::PrivateAnonymous => 0,
3992            };
3993
3994            let name_str = match &map.name() {
3995                MappingNameRef::File(file) => {
3996                    let Ok(running_state) = task.running_state() else {
3997                        log_warn!("Task {} is not running", task.get_tid());
3998                        continue;
3999                    };
4000                    String::from_utf8_lossy(&file.name.path(&running_state.fs())).into_owned()
4001                }
4002                MappingNameRef::None | MappingNameRef::AioContext(_) => {
4003                    if map.flags().contains(MappingFlags::SHARED)
4004                        && map.flags().contains(MappingFlags::ANONYMOUS)
4005                    {
4006                        "/dev/zero (deleted)".to_string()
4007                    } else {
4008                        "".to_string()
4009                    }
4010                }
4011                MappingNameRef::Stack => "[stack]".to_string(),
4012                MappingNameRef::Heap => "[heap]".to_string(),
4013                MappingNameRef::Vdso => "[vdso]".to_string(),
4014                MappingNameRef::Vvar => "[vvar]".to_string(),
4015                _ => format!("{:?}", map.name()),
4016            };
4017
4018            let fault_marker = if range.contains(&fault_address) { " <= FAULT" } else { "" };
4019
4020            log_warn!(
4021                "{:08x}-{:08x} {} {:08x} {}{}",
4022                range.start.ptr(),
4023                range.end.ptr(),
4024                perms,
4025                backing,
4026                name_str,
4027                fault_marker
4028            );
4029            last_end = range.end;
4030        }
4031
4032        if fault_address >= last_end {
4033            log_warn!("{:08x} <= FAULT", fault_address.ptr());
4034        }
4035    }
4036
4037    pub fn handle_page_fault(
4038        self: &Arc<Self>,
4039        decoded: PageFaultExceptionReport,
4040        error_code: zx::Status,
4041    ) -> ExceptionResult {
4042        #[cfg(target_arch = "aarch64")]
4043        // On aarch64, 64-bit processes can use Top Byte Ignore (TBI). We need to mask out the
4044        // top byte of the faulting address to get the actual userspace address.
4045        let addr = if self.is_arch64() {
4046            UserAddress::from(decoded.faulting_address & 0x00FF_FFFF_FFFF_FFFF)
4047        } else {
4048            UserAddress::from(decoded.faulting_address)
4049        };
4050        #[cfg(not(target_arch = "aarch64"))]
4051        let addr = UserAddress::from(decoded.faulting_address);
4052
4053        // On uffd-registered range, handle according to the uffd rules
4054        if error_code == zx::Status::ACCESS_DENIED {
4055            let state = self.state.write();
4056            if let Some((_, mapping)) = state.mappings.get(addr) {
4057                if mapping.flags().contains(MappingFlags::UFFD) {
4058                    // TODO(https://fxbug.dev/391599171): Support other modes
4059                    assert!(mapping.flags().contains(MappingFlags::UFFD_MISSING));
4060
4061                    if let Some(_uffd) = state.find_uffd(addr) {
4062                        // If the SIGBUS feature was set, no event will be sent to the file.
4063                        // Instead, SIGBUS is delivered to the process that triggered the fault.
4064                        // TODO(https://fxbug.dev/391599171): For now we only support this feature,
4065                        // so we assume it is set.
4066                        // Check for the SIGBUS feature when we start supporting running without it.
4067                        return ExceptionResult::Signal(SignalInfo::with_detail(
4068                            SIGBUS,
4069                            BUS_ADRERR as i32,
4070                            SignalDetail::SigFault { addr: decoded.faulting_address },
4071                        ));
4072                    };
4073                }
4074                // There is a data race resulting from uffd unregistration and page fault happening
4075                // at the same time. To detect it, we check if the access was meant to be rejected
4076                // according to Starnix own information about the mapping.
4077                if check_access_permissions_in_page_fault(&decoded, mapping) {
4078                    track_stub!(
4079                        TODO("https://fxbug.dev/435171399"),
4080                        "Inconsistent permission fault"
4081                    );
4082                    return ExceptionResult::Handled;
4083                }
4084            }
4085            std::mem::drop(state);
4086        }
4087
4088        if decoded.not_present {
4089            {
4090                let mut state = self.state.write();
4091                match state.ensure_range_mapped_in_user_vmar(addr, None, &self.mapping_context) {
4092                    Ok(true) => return ExceptionResult::Handled,
4093                    Ok(false) => {
4094                        // If the mapping generation has changed since the last time this thread
4095                        // saw it, we return `Handled` to retry the faulting instruction.
4096                        // This handles cases where the fault was spurious due to a concurrent
4097                        // mapping operation. We update the counter here to ensure we converge and
4098                        // don't loop infinitely.
4099                        let current_gen = state.mappings.generation;
4100                        let old_gen = LAST_SEEN_MAPPING_GENERATION.with(|c| c.replace(current_gen));
4101                        if current_gen != old_gen {
4102                            return ExceptionResult::Handled;
4103                        }
4104                    }
4105                    Err(e) => {
4106                        log_error!("Failed to map lazy memory: {e}")
4107                    }
4108                }
4109            }
4110
4111            // A page fault may be resolved by extending a growsdown mapping to cover the faulting
4112            // address. Mark the exception handled if so. Otherwise let the regular handling proceed.
4113
4114            // We should only attempt growth on a not-present fault and we should only extend if the
4115            // access type matches the protection on the GROWSDOWN mapping.
4116            match self.extend_growsdown_mapping_to_address(
4117                UserAddress::from(decoded.faulting_address),
4118                decoded.is_write,
4119            ) {
4120                Ok(true) => {
4121                    return ExceptionResult::Handled;
4122                }
4123                Err(e) => {
4124                    log_warn!("Error handling page fault: {e}")
4125                }
4126                _ => {}
4127            }
4128        }
4129
4130        // For this exception type, the synth_code field in the exception report's context is the
4131        // error generated by the page fault handler. For us this is used to distinguish between a
4132        // segmentation violation and a bus error. Unfortunately this detail is not documented in
4133        // Zircon's public documentation and is only described in the architecture-specific
4134        // exception definitions such as:
4135        // zircon/kernel/arch/x86/include/arch/x86.h
4136        // zircon/kernel/arch/arm64/include/arch/arm64.h
4137        let (signo, si_code) = match error_code {
4138            zx::Status::OUT_OF_RANGE => (SIGBUS, linux_uapi::BUS_ADRERR as i32),
4139            _ => {
4140                let code = if self.state.read().mappings.get(addr).is_some() {
4141                    linux_uapi::SEGV_ACCERR
4142                } else {
4143                    linux_uapi::SEGV_MAPERR
4144                };
4145                (SIGSEGV, code as i32)
4146            }
4147        };
4148        ExceptionResult::Signal(SignalInfo::with_detail(
4149            signo,
4150            si_code,
4151            SignalDetail::SigFault { addr: decoded.faulting_address },
4152        ))
4153    }
4154
4155    pub fn set_mapping_name(
4156        &self,
4157        addr: UserAddress,
4158        length: usize,
4159        name: Option<FsString>,
4160    ) -> Result<(), Errno> {
4161        let mut state = self.state.write();
4162        let mut released_mappings = ReleasedMappings::default();
4163        let result = state.set_mapping_name(addr, length, name, &mut released_mappings);
4164        released_mappings.finalize(state);
4165        result
4166    }
4167
4168    /// Returns [`Ok`] if the entire range specified by `addr..(addr+length)` contains valid
4169    /// mappings.
4170    ///
4171    /// # Errors
4172    ///
4173    /// Returns [`Err(errno)`] where `errno` is:
4174    ///
4175    ///   - `EINVAL`: `addr` is not page-aligned, or the range is too large,
4176    ///   - `ENOMEM`: one or more pages in the range are not mapped.
4177    pub fn ensure_mapped(&self, addr: UserAddress, length: usize) -> Result<(), Errno> {
4178        if !addr.is_aligned(*PAGE_SIZE) {
4179            return error!(EINVAL);
4180        }
4181
4182        let length = round_up_to_system_page_size(length)?;
4183        let end_addr = addr.checked_add(length).ok_or_else(|| errno!(EINVAL))?;
4184        let state = self.state.read();
4185        let mut last_end = addr;
4186        for (range, _) in state.mappings.range(addr..end_addr) {
4187            if range.start > last_end {
4188                // This mapping does not start immediately after the last.
4189                return error!(ENOMEM);
4190            }
4191            last_end = range.end;
4192        }
4193        if last_end < end_addr {
4194            // There is a gap of no mappings at the end of the range.
4195            error!(ENOMEM)
4196        } else {
4197            Ok(())
4198        }
4199    }
4200
4201    /// Returns the memory object mapped at the address and the offset into the memory object of
4202    /// the address. Intended for implementing futexes.
4203    pub fn get_mapping_memory(
4204        &self,
4205        addr: UserAddress,
4206        perms: ProtectionFlags,
4207    ) -> Result<(Arc<MemoryObject>, u64), Errno> {
4208        let state = self.state.read();
4209        let (_, mapping) = state.mappings.get(addr).ok_or_else(|| errno!(EFAULT))?;
4210        if !mapping.flags().access_flags().contains(perms) {
4211            return error!(EACCES);
4212        }
4213        match state.get_mapping_backing(mapping) {
4214            MappingBacking::Memory(backing) => {
4215                Ok((Arc::clone(backing.memory()), mapping.address_to_offset(addr)))
4216            }
4217            MappingBacking::PrivateAnonymous => {
4218                Ok((Arc::clone(&self.mapping_context.private_anonymous.backing), addr.ptr() as u64))
4219            }
4220        }
4221    }
4222
4223    /// Does a rough check that the given address is plausibly in the address space of the
4224    /// application. This does not mean the pointer is valid for any particular purpose or that
4225    /// it will remain so!
4226    ///
4227    /// In some syscalls, Linux seems to do some initial validation of the pointer up front to
4228    /// tell the caller early if it's invalid. For example, in epoll_wait() it's returning a vector
4229    /// of events. If the caller passes an invalid pointer, it wants to fail without dropping any
4230    /// events. Failing later when actually copying the required events to userspace would mean
4231    /// those events will be lost. But holding a lock on the memory manager for an asynchronous
4232    /// wait is not desirable.
4233    ///
4234    /// Testing shows that Linux seems to do some initial plausibility checking of the pointer to
4235    /// be able to report common usage errors before doing any (possibly unreversable) work. This
4236    /// checking is easy to get around if you try, so this function is also not required to
4237    /// be particularly robust. Certainly the more advanced cases of races (the memory could be
4238    /// unmapped after this call but before it's used) are not handled.
4239    ///
4240    /// The buffer_size variable is the size of the data structure that needs to fit
4241    /// in the given memory.
4242    ///
4243    /// Returns the error EFAULT if invalid.
4244    pub fn check_plausible(&self, addr: UserAddress, buffer_size: usize) -> Result<(), Errno> {
4245        let state = self.state.read();
4246
4247        if let Some(range) = state.mappings.last_range() {
4248            if (range.end - buffer_size)? >= addr {
4249                return Ok(());
4250            }
4251        }
4252        error!(EFAULT)
4253    }
4254
4255    pub fn get_aio_context(&self, addr: UserAddress) -> Option<Arc<AioContext>> {
4256        let state = self.state.read();
4257        state.get_aio_context(addr).map(|(_, aio_context)| aio_context)
4258    }
4259
4260    pub fn destroy_aio_context(
4261        self: &Arc<Self>,
4262        addr: UserAddress,
4263    ) -> Result<Arc<AioContext>, Errno> {
4264        let mut released_mappings = ReleasedMappings::default();
4265
4266        // Hold the lock throughout the operation to uphold memory manager's invariants.
4267        // See mm/README.md.
4268        let mut state = self.state.write();
4269
4270        // Validate that this address actually has an AioContext. We need to hold the state lock
4271        // until we actually remove the mappings to ensure that another thread does not manipulate
4272        // the mappings after we've validated that they contain an AioContext.
4273        let Some((range, aio_context)) = state.get_aio_context(addr) else {
4274            return error!(EINVAL);
4275        };
4276
4277        let length = range.end - range.start;
4278        let result = state.unmap(self, range.start, length, &mut released_mappings);
4279
4280        released_mappings.finalize(state);
4281
4282        result.map(|_| aio_context)
4283    }
4284
4285    #[cfg(test)]
4286    pub fn get_mapping_name(
4287        &self,
4288        addr: UserAddress,
4289    ) -> Result<Option<flyweights::FlyByteStr>, Errno> {
4290        let state = self.state.read();
4291        let (_, mapping) = state.mappings.get(addr).ok_or_else(|| errno!(EFAULT))?;
4292        if let MappingNameRef::Vma(name) = mapping.name() {
4293            Ok(Some(name.clone()))
4294        } else {
4295            Ok(None)
4296        }
4297    }
4298
4299    #[cfg(test)]
4300    pub fn get_mapping_count(&self) -> usize {
4301        let state = self.state.read();
4302        state.mappings.iter().count()
4303    }
4304
4305    pub fn extend_growsdown_mapping_to_address(
4306        self: &Arc<Self>,
4307        addr: UserAddress,
4308        is_write: bool,
4309    ) -> Result<bool, Error> {
4310        self.state.write().extend_growsdown_mapping_to_address(self, addr, is_write)
4311    }
4312
4313    pub fn get_total_usage(&self) -> usize {
4314        self.state.read().mappings.total_usage
4315    }
4316
4317    pub fn get_stats(&self, current_task: &CurrentTask) -> MemoryStats {
4318        // Grab our state lock before reading zircon mappings so that the two are consistent.
4319        // Other Starnix threads should not make any changes to the Zircon mappings while we hold
4320        // a read lock to the memory manager state.
4321        let state = self.state.read();
4322
4323        let mut stats = MemoryStats::default();
4324        stats.vm_stack = state.stack_size;
4325
4326        self.with_zx_mappings(current_task, |zx_mappings| {
4327            for zx_mapping in zx_mappings {
4328                // We only care about map info for actual mappings.
4329                let zx_details = zx_mapping.details();
4330                let Some(zx_details) = zx_details.as_mapping() else { continue };
4331                let user_address = UserAddress::from(zx_mapping.base as u64);
4332                let (_, mm_mapping) = state
4333                    .mappings
4334                    .get(user_address)
4335                    .unwrap_or_else(|| panic!("mapping bookkeeping must be consistent with zircon's: not found: {user_address:?}"));
4336                debug_assert_eq!(
4337                    match state.get_mapping_backing(mm_mapping) {
4338                        MappingBacking::Memory(m)=>m.memory().get_koid(),
4339                        MappingBacking::PrivateAnonymous=>self.mapping_context.private_anonymous.backing.get_koid(),
4340                    },
4341                    zx_details.vmo_koid,
4342                    "MemoryManager and Zircon must agree on which VMO is mapped in this range",
4343                );
4344
4345                stats.vm_size += zx_mapping.size;
4346
4347                stats.vm_rss += zx_details.committed_bytes;
4348                stats.vm_swap += zx_details.populated_bytes - zx_details.committed_bytes;
4349
4350                if mm_mapping.flags().contains(MappingFlags::SHARED) {
4351                    stats.rss_shared += zx_details.committed_bytes;
4352                } else if mm_mapping.flags().contains(MappingFlags::ANONYMOUS) {
4353                    stats.rss_anonymous += zx_details.committed_bytes;
4354                } else if mm_mapping.name().is_file() {
4355                    stats.rss_file += zx_details.committed_bytes;
4356                }
4357
4358                if mm_mapping.flags().contains(MappingFlags::LOCKED) {
4359                    stats.vm_lck += zx_details.committed_bytes;
4360                }
4361
4362                if mm_mapping.flags().contains(MappingFlags::ELF_BINARY)
4363                    && mm_mapping.flags().contains(MappingFlags::WRITE)
4364                {
4365                    stats.vm_data += zx_mapping.size;
4366                }
4367
4368                if mm_mapping.flags().contains(MappingFlags::ELF_BINARY)
4369                    && mm_mapping.flags().contains(MappingFlags::EXEC)
4370                {
4371                    stats.vm_exe += zx_mapping.size;
4372                }
4373            }
4374        });
4375
4376        // TODO(https://fxbug.dev/396221597): Placeholder for now. We need kernel support to track
4377        // the committed bytes high water mark.
4378        stats.vm_rss_hwm = STUB_VM_RSS_HWM;
4379        stats
4380    }
4381
4382    fn run_atomic_op<F, T>(&self, futex_addr: FutexAddress, mut op: F) -> Result<T, Errno>
4383    where
4384        F: FnMut(&usercopy::Usercopy) -> Result<T, ()>,
4385    {
4386        if let Some(usercopy) = usercopy() {
4387            // Try the lock-free fast path first.
4388            // Note: `op` returns `Err(())` strictly on memory access faults. For
4389            // compare-exchange operations, a logical mismatch is wrapped inside a
4390            // successful `Ok(value_or_error)`, meaning we will short-circuit here
4391            // and won't incorrectly retry on logical failures.
4392            if let Ok(val) = op(usercopy) {
4393                return Ok(val);
4394            }
4395            self.ensure_range_mapped_in_user_vmar(futex_addr.into(), None)?;
4396            op(usercopy).map_err(|_| errno!(EFAULT))
4397        } else {
4398            unreachable!("can only control memory ordering of atomics with usercopy");
4399        }
4400    }
4401
4402    pub fn atomic_load_u32_acquire(&self, futex_addr: FutexAddress) -> Result<u32, Errno> {
4403        self.run_atomic_op(futex_addr, |uc| uc.atomic_load_u32_acquire(futex_addr.ptr()))
4404    }
4405
4406    pub fn atomic_load_u32_relaxed(&self, futex_addr: FutexAddress) -> Result<u32, Errno> {
4407        if usercopy().is_some() {
4408            self.run_atomic_op(futex_addr, |uc| uc.atomic_load_u32_relaxed(futex_addr.ptr()))
4409        } else {
4410            // SAFETY: `self.state.read().read_memory` only returns `Ok` if all
4411            // bytes were read to.
4412            let buf = unsafe {
4413                read_to_array(|buf| {
4414                    self.state
4415                        .read()
4416                        .read_memory(futex_addr.into(), buf, &self.mapping_context)
4417                        .map(|bytes_read| {
4418                            debug_assert_eq!(bytes_read.len(), std::mem::size_of::<u32>())
4419                        })
4420                })
4421            }?;
4422            Ok(u32::from_ne_bytes(buf))
4423        }
4424    }
4425
4426    pub fn atomic_store_u32_relaxed(
4427        &self,
4428        futex_addr: FutexAddress,
4429        value: u32,
4430    ) -> Result<(), Errno> {
4431        if usercopy().is_some() {
4432            self.run_atomic_op(futex_addr, |uc| {
4433                uc.atomic_store_u32_relaxed(futex_addr.ptr(), value)
4434            })
4435        } else {
4436            self.state.read().write_memory(
4437                futex_addr.into(),
4438                value.as_bytes(),
4439                &self.mapping_context,
4440            )?;
4441            Ok(())
4442        }
4443    }
4444
4445    pub fn atomic_compare_exchange_u32_acq_rel(
4446        &self,
4447        futex_addr: FutexAddress,
4448        current: u32,
4449        new: u32,
4450    ) -> CompareExchangeResult<u32> {
4451        CompareExchangeResult::from_usercopy(self.run_atomic_op(futex_addr, |uc| {
4452            uc.atomic_compare_exchange_u32_acq_rel(futex_addr.ptr(), current, new)
4453        }))
4454    }
4455
4456    pub fn atomic_compare_exchange_weak_u32_acq_rel(
4457        &self,
4458        futex_addr: FutexAddress,
4459        current: u32,
4460        new: u32,
4461    ) -> CompareExchangeResult<u32> {
4462        CompareExchangeResult::from_usercopy(self.run_atomic_op(futex_addr, |uc| {
4463            uc.atomic_compare_exchange_weak_u32_acq_rel(futex_addr.ptr(), current, new)
4464        }))
4465    }
4466}
4467
4468/// The result of an atomic compare/exchange operation on user memory.
4469#[derive(Debug, Clone)]
4470pub enum CompareExchangeResult<T> {
4471    /// The current value provided matched the one observed in memory and the new value provided
4472    /// was written.
4473    Success,
4474    /// The provided current value did not match the current value in memory.
4475    Stale { observed: T },
4476    /// There was a general error while accessing the requested memory.
4477    Error(Errno),
4478}
4479
4480impl<T> CompareExchangeResult<T> {
4481    fn from_usercopy(res: Result<Result<T, T>, Errno>) -> Self {
4482        match res {
4483            Ok(Ok(_)) => Self::Success,
4484            Ok(Err(observed)) => Self::Stale { observed },
4485            Err(e) => Self::Error(e),
4486        }
4487    }
4488}
4489
4490impl<T> From<Errno> for CompareExchangeResult<T> {
4491    fn from(e: Errno) -> Self {
4492        Self::Error(e)
4493    }
4494}
4495
4496/// The user-space address at which a mapping should be placed. Used by [`MemoryManager::map`].
4497#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4498pub enum DesiredAddress {
4499    /// Map at any address chosen by the kernel.
4500    Any,
4501    /// The address is a hint. If the address overlaps an existing mapping a different address may
4502    /// be chosen.
4503    Hint(UserAddress),
4504    /// The address is a requirement. If the address overlaps an existing mapping (and cannot
4505    /// overwrite it), mapping fails.
4506    Fixed(UserAddress),
4507    /// The address is a requirement. If the address overlaps an existing mapping (and cannot
4508    /// overwrite it), they should be unmapped.
4509    FixedOverwrite(UserAddress),
4510}
4511
4512/// The user-space address at which a mapping should be placed. Used by [`map_in_vmar`].
4513#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4514enum SelectedAddress {
4515    /// See DesiredAddress::Fixed.
4516    Fixed(UserAddress),
4517    /// See DesiredAddress::FixedOverwrite.
4518    FixedOverwrite(UserAddress),
4519}
4520
4521impl SelectedAddress {
4522    fn addr(&self) -> UserAddress {
4523        match self {
4524            SelectedAddress::Fixed(addr) => *addr,
4525            SelectedAddress::FixedOverwrite(addr) => *addr,
4526        }
4527    }
4528}
4529
4530/// Write one line of the memory map intended for adding to `/proc/self/maps`.
4531fn write_map(
4532    task: &Task,
4533    sink: &mut DynamicFileBuf,
4534    state: &MemoryManagerState,
4535    range: &Range<UserAddress>,
4536    map: &Mapping,
4537) -> Result<(), Errno> {
4538    let line_length = write!(
4539        sink,
4540        "{:08x}-{:08x} {}{}{}{} {:08x} 00:00 {} ",
4541        range.start.ptr(),
4542        range.end.ptr(),
4543        if map.can_read() { 'r' } else { '-' },
4544        if map.can_write() { 'w' } else { '-' },
4545        if map.can_exec() { 'x' } else { '-' },
4546        if map.flags().contains(MappingFlags::SHARED) { 's' } else { 'p' },
4547        match state.get_mapping_backing(map) {
4548            MappingBacking::Memory(backing) => backing.address_to_offset(range.start),
4549            MappingBacking::PrivateAnonymous => 0,
4550        },
4551        if let MappingNameRef::File(file) = &map.name() { file.name.entry.node.ino } else { 0 }
4552    )?;
4553    let fill_to_name = |sink: &mut DynamicFileBuf| {
4554        // The filename goes at >= the 74th column (73rd when zero indexed)
4555        for _ in line_length..73 {
4556            sink.write(b" ");
4557        }
4558    };
4559    match &map.name() {
4560        MappingNameRef::None | MappingNameRef::AioContext(_) => {
4561            if map.flags().contains(MappingFlags::SHARED)
4562                && map.flags().contains(MappingFlags::ANONYMOUS)
4563            {
4564                // See proc(5), "/proc/[pid]/map_files/"
4565                fill_to_name(sink);
4566                sink.write(b"/dev/zero (deleted)");
4567            }
4568        }
4569        MappingNameRef::Stack => {
4570            fill_to_name(sink);
4571            sink.write(b"[stack]");
4572        }
4573        MappingNameRef::Heap => {
4574            fill_to_name(sink);
4575            sink.write(b"[heap]");
4576        }
4577        MappingNameRef::Vdso => {
4578            fill_to_name(sink);
4579            sink.write(b"[vdso]");
4580        }
4581        MappingNameRef::Vvar => {
4582            fill_to_name(sink);
4583            sink.write(b"[vvar]");
4584        }
4585        MappingNameRef::File(file) => {
4586            fill_to_name(sink);
4587            // File names can have newlines that need to be escaped before printing.
4588            // According to https://man7.org/linux/man-pages/man5/proc.5.html the only
4589            // escaping applied to paths is replacing newlines with an octal sequence.
4590            let path = file.name.path(&task.running_state()?.fs());
4591            sink.write_iter(
4592                path.iter()
4593                    .flat_map(|b| if *b == b'\n' { b"\\012" } else { std::slice::from_ref(b) })
4594                    .copied(),
4595            );
4596        }
4597        MappingNameRef::Vma(name) => {
4598            fill_to_name(sink);
4599            sink.write(b"[anon:");
4600            sink.write(name.as_bytes());
4601            sink.write(b"]");
4602        }
4603        MappingNameRef::Ashmem(name) => {
4604            fill_to_name(sink);
4605            sink.write(b"/dev/ashmem/");
4606            sink.write(name.as_bytes());
4607        }
4608    }
4609    sink.write(b"\n");
4610    Ok(())
4611}
4612
4613#[derive(Default)]
4614pub struct MemoryStats {
4615    pub vm_size: usize,
4616    pub vm_rss: usize,
4617    pub vm_rss_hwm: usize,
4618    pub rss_anonymous: usize,
4619    pub rss_file: usize,
4620    pub rss_shared: usize,
4621    pub vm_data: usize,
4622    pub vm_stack: usize,
4623    pub vm_exe: usize,
4624    pub vm_swap: usize,
4625    pub vm_lck: usize,
4626}
4627
4628/// Implements `/proc/self/maps`.
4629#[derive(Clone)]
4630pub struct ProcMapsFile {
4631    mm: Weak<MemoryManager>,
4632    task: Weak<Task>,
4633}
4634impl ProcMapsFile {
4635    pub fn new(task: Arc<Task>) -> DynamicFile<Self> {
4636        // "maps" is empty for kthreads, rather than inaccessible.
4637        let mm = task.mm().map_or_else(|_| Weak::default(), |mm| Arc::downgrade(&mm));
4638        DynamicFile::new(Self { mm, task: Arc::downgrade(&task) })
4639    }
4640}
4641
4642impl SequenceFileSource for ProcMapsFile {
4643    type Cursor = UserAddress;
4644
4645    fn next(
4646        &self,
4647        _current_task: &CurrentTask,
4648        cursor: UserAddress,
4649        sink: &mut DynamicFileBuf,
4650    ) -> Result<Option<UserAddress>, Errno> {
4651        let task = Task::from_weak(&self.task)?;
4652        // /proc/<pid>/maps is empty for kthreads and tasks whose memory manager has changed.
4653        let Some(mm) = self.mm.upgrade() else {
4654            return Ok(None);
4655        };
4656        let state = mm.state.read();
4657        if let Some((range, map)) = state.mappings.find_at_or_after(cursor) {
4658            write_map(&task, sink, &state, range, map)?;
4659            return Ok(Some(range.end));
4660        }
4661        Ok(None)
4662    }
4663}
4664
4665#[derive(Clone)]
4666pub struct ProcSmapsFile {
4667    mm: Weak<MemoryManager>,
4668    task: Weak<Task>,
4669}
4670impl ProcSmapsFile {
4671    pub fn new(task: Arc<Task>) -> DynamicFile<Self> {
4672        // "smaps" is empty for kthreads, rather than inaccessible.
4673        let mm = task.mm().map_or_else(|_| Weak::default(), |mm| Arc::downgrade(&mm));
4674        DynamicFile::new(Self { mm, task: Arc::downgrade(&task) })
4675    }
4676}
4677
4678impl DynamicFileSource for ProcSmapsFile {
4679    fn generate(&self, current_task: &CurrentTask, sink: &mut DynamicFileBuf) -> Result<(), Errno> {
4680        let page_size_kb = *PAGE_SIZE / 1024;
4681        let task = Task::from_weak(&self.task)?;
4682        // /proc/<pid>/smaps is empty for kthreads and tasks whose memory manager has changed.
4683        let Some(mm) = self.mm.upgrade() else {
4684            return Ok(());
4685        };
4686
4687        // Ensure all mappings are mapped into the user vmar.
4688        let max_addr = mm.maximum_valid_user_address;
4689        mm.ensure_range_mapped_in_user_vmar(UserAddress::from(0), Some(max_addr.ptr()))?;
4690
4691        let state = mm.state.read();
4692        let committed_bytes_vec = mm.with_zx_mappings(current_task, |zx_mappings| {
4693            let mut zx_memory_info = RangeMap::<UserAddress, usize>::default();
4694            for idx in 0..zx_mappings.len() {
4695                let zx_mapping = zx_mappings[idx];
4696                // RangeMap uses #[must_use] for its default usecase but this drop is trivial.
4697                let _ = zx_memory_info.insert(
4698                    UserAddress::from_ptr(zx_mapping.base)
4699                        ..UserAddress::from_ptr(zx_mapping.base + zx_mapping.size),
4700                    idx,
4701                );
4702            }
4703
4704            let mut committed_bytes_vec = Vec::new();
4705            for (mm_range, mm_mapping) in state.mappings.iter() {
4706                let mut committed_bytes = 0;
4707
4708                for (zx_range, zx_mapping_idx) in zx_memory_info.range(mm_range.clone()) {
4709                    let intersect_range = zx_range.intersect(mm_range);
4710                    let zx_mapping = zx_mappings[*zx_mapping_idx];
4711                    let zx_details = zx_mapping.details();
4712                    let Some(zx_details) = zx_details.as_mapping() else { continue };
4713                    let zx_committed_bytes = zx_details.committed_bytes;
4714
4715                    // TODO(https://fxbug.dev/419882465): It can happen that the same Zircon mapping
4716                    // is covered by more than one Starnix mapping. In this case we don't have
4717                    // enough granularity to answer the question of how many committed bytes belong
4718                    // to one mapping or another. Make a best-effort approximation by dividing the
4719                    // committed bytes of a Zircon mapping proportionally.
4720                    committed_bytes += if intersect_range != *zx_range {
4721                        let intersection_size =
4722                            intersect_range.end.ptr() - intersect_range.start.ptr();
4723                        let part = intersection_size as f32 / zx_mapping.size as f32;
4724                        let prorated_committed_bytes: f32 = part * zx_committed_bytes as f32;
4725                        prorated_committed_bytes as u64
4726                    } else {
4727                        zx_committed_bytes as u64
4728                    };
4729                    assert_eq!(
4730                        match state.get_mapping_backing(mm_mapping) {
4731                            MappingBacking::Memory(m) => m.memory().get_koid(),
4732                            MappingBacking::PrivateAnonymous =>
4733                                mm.mapping_context.private_anonymous.backing.get_koid(),
4734                        },
4735                        zx_details.vmo_koid,
4736                        "MemoryManager and Zircon must agree on which VMO is mapped in this range",
4737                    );
4738                }
4739                committed_bytes_vec.push(committed_bytes);
4740            }
4741            Ok(committed_bytes_vec)
4742        })?;
4743
4744        for ((mm_range, mm_mapping), committed_bytes) in
4745            state.mappings.iter().zip(committed_bytes_vec.into_iter())
4746        {
4747            write_map(&task, sink, &state, mm_range, mm_mapping)?;
4748
4749            let size_kb = (mm_range.end.ptr() - mm_range.start.ptr()) / 1024;
4750            writeln!(sink, "Size:           {size_kb:>8} kB",)?;
4751            let share_count = match state.get_mapping_backing(mm_mapping) {
4752                MappingBacking::Memory(backing) => {
4753                    let memory = backing.memory();
4754                    if memory.is_clock() {
4755                        // Clock memory mappings are not shared in a meaningful way.
4756                        1
4757                    } else {
4758                        let memory_info = backing.memory().info()?;
4759                        memory_info.share_count as u64
4760                    }
4761                }
4762                MappingBacking::PrivateAnonymous => {
4763                    1 // Private mapping
4764                }
4765            };
4766
4767            let rss_kb = committed_bytes / 1024;
4768            writeln!(sink, "Rss:            {rss_kb:>8} kB")?;
4769
4770            let pss_kb = if mm_mapping.flags().contains(MappingFlags::SHARED) {
4771                rss_kb / share_count
4772            } else {
4773                rss_kb
4774            };
4775            writeln!(sink, "Pss:            {pss_kb:>8} kB")?;
4776
4777            track_stub!(TODO("https://fxbug.dev/322874967"), "smaps dirty pages");
4778            let (shared_dirty_kb, private_dirty_kb) = (0, 0);
4779
4780            let is_shared = share_count > 1;
4781            let shared_clean_kb = if is_shared { rss_kb } else { 0 };
4782            writeln!(sink, "Shared_Clean:   {shared_clean_kb:>8} kB")?;
4783            writeln!(sink, "Shared_Dirty:   {shared_dirty_kb:>8} kB")?;
4784
4785            let private_clean_kb = if is_shared { 0 } else { rss_kb };
4786            writeln!(sink, "Private_Clean:  {private_clean_kb:>8} kB")?;
4787            writeln!(sink, "Private_Dirty:  {private_dirty_kb:>8} kB")?;
4788
4789            let anonymous_kb = if mm_mapping.private_anonymous() { rss_kb } else { 0 };
4790            writeln!(sink, "Anonymous:      {anonymous_kb:>8} kB")?;
4791            writeln!(sink, "KernelPageSize: {page_size_kb:>8} kB")?;
4792            writeln!(sink, "MMUPageSize:    {page_size_kb:>8} kB")?;
4793
4794            let locked_kb =
4795                if mm_mapping.flags().contains(MappingFlags::LOCKED) { rss_kb } else { 0 };
4796            writeln!(sink, "Locked:         {locked_kb:>8} kB")?;
4797            writeln!(sink, "VmFlags: {}", mm_mapping.vm_flags())?;
4798
4799            track_stub!(TODO("https://fxbug.dev/297444691"), "optional smaps fields");
4800        }
4801
4802        Ok(())
4803    }
4804}
4805
4806/// Creates a memory object that can be used in an anonymous mapping for the `mmap` syscall.
4807pub fn create_anonymous_mapping_memory(size: u64) -> Result<Arc<MemoryObject>, Errno> {
4808    // mremap can grow memory regions, so make sure the memory object is resizable.
4809    let mut memory = MemoryObject::from(
4810        zx::Vmo::create_with_opts(zx::VmoOptions::RESIZABLE, size).map_err(|s| match s {
4811            zx::Status::NO_MEMORY => errno!(ENOMEM),
4812            zx::Status::OUT_OF_RANGE => errno!(ENOMEM),
4813            _ => impossible_error(s),
4814        })?,
4815    )
4816    .with_zx_name(b"starnix:memory_manager");
4817
4818    memory.set_zx_name(b"starnix-anon");
4819
4820    // TODO(https://fxbug.dev/42056890): Audit replace_as_executable usage
4821    memory = memory.replace_as_executable(&VMEX_RESOURCE).map_err(impossible_error)?;
4822    Ok(Arc::new(memory))
4823}
4824
4825fn generate_random_offset_for_aslr(arch_width: ArchWidth) -> usize {
4826    // Generate a number with ASLR_RANDOM_BITS.
4827    let randomness = {
4828        let random_bits =
4829            if arch_width.is_arch32() { ASLR_32_RANDOM_BITS } else { ASLR_RANDOM_BITS };
4830        let mask = (1 << random_bits) - 1;
4831        let mut bytes = [0; std::mem::size_of::<usize>()];
4832        starnix_crypto::cprng_draw(&mut bytes);
4833        usize::from_le_bytes(bytes) & mask
4834    };
4835
4836    // Transform it into a page-aligned offset.
4837    randomness * (*PAGE_SIZE as usize)
4838}
4839
4840#[cfg(test)]
4841mod tests {
4842    use super::*;
4843    use crate::mm::memory_accessor::{MemoryAccessor, MemoryAccessorExt};
4844    use crate::mm::syscalls::do_mmap;
4845    use crate::task::syscalls::sys_prctl;
4846    use crate::testing::*;
4847    use crate::vfs::FdNumber;
4848    use assert_matches::assert_matches;
4849    use itertools::assert_equal;
4850    use starnix_uapi::user_address::{UserCString, UserRef};
4851    use starnix_uapi::{
4852        MAP_ANONYMOUS, MAP_FIXED, MAP_GROWSDOWN, MAP_PRIVATE, MAP_SHARED, PR_SET_VMA,
4853        PR_SET_VMA_ANON_NAME, PROT_NONE, PROT_READ,
4854    };
4855    use std::ffi::CString;
4856    use zerocopy::{FromBytes, Immutable, KnownLayout};
4857
4858    #[::fuchsia::test]
4859    fn test_mapping_flags() {
4860        let options = MappingOptions::ANONYMOUS;
4861        let access_flags = ProtectionFlags::READ | ProtectionFlags::WRITE;
4862        let mapping_flags = MappingFlags::from_access_flags_and_options(access_flags, options);
4863        assert_eq!(mapping_flags.access_flags(), access_flags);
4864        assert_eq!(mapping_flags.options(), options);
4865
4866        let new_access_flags = ProtectionFlags::READ | ProtectionFlags::EXEC;
4867        let adusted_mapping_flags = mapping_flags.with_access_flags(new_access_flags);
4868        assert_eq!(adusted_mapping_flags.access_flags(), new_access_flags);
4869        assert_eq!(adusted_mapping_flags.options(), options);
4870    }
4871
4872    #[::fuchsia::test]
4873    async fn test_any_ranges_lazy() {
4874        spawn_kernel_and_run(async |current_task| {
4875            let mm = current_task.mm().unwrap();
4876            let page_size = *PAGE_SIZE as usize;
4877            let addr = (mm.base_addr + 10 * page_size).unwrap();
4878            let length = page_size;
4879
4880            let memory = create_anonymous_mapping_memory(length as u64).unwrap();
4881            let flags = MappingFlags::from_access_flags_and_options(
4882                ProtectionFlags::READ | ProtectionFlags::WRITE,
4883                MappingOptions::empty(),
4884            );
4885
4886            let mapping = Mapping::with_name(
4887                MappingBacking::Memory(Box::new(MappingBackingMemory::new(addr, memory, 0))),
4888                flags,
4889                Access::rwx(),
4890                MappingName::None,
4891                MappingMode::Lazy,
4892            );
4893
4894            {
4895                let mut state = mm.state.write();
4896                state.mappings.insert(addr..(addr + length).unwrap(), mapping);
4897            }
4898
4899            {
4900                let state = mm.state.read();
4901                assert!(state.any_ranges_lazy(std::iter::once((addr, Some(length)))));
4902            }
4903
4904            assert!(mm.ensure_range_mapped_in_user_vmar(addr, Some(length)).unwrap());
4905
4906            {
4907                let state = mm.state.read();
4908                assert!(!state.any_ranges_lazy(std::iter::once((addr, Some(length)))));
4909            }
4910        })
4911        .await;
4912    }
4913
4914    #[::fuchsia::test]
4915    async fn test_brk() {
4916        spawn_kernel_and_run(async |current_task| {
4917            let mm = current_task.mm().unwrap();
4918
4919            // Look up the given addr in the mappings table.
4920            let get_range = |addr: UserAddress| {
4921                let state = mm.state.read();
4922                state
4923                    .mappings
4924                    .map
4925                    .get(addr)
4926                    .map(|(range, mapping)| (range.clone(), mapping.clone()))
4927            };
4928
4929            // Initialize the program break.
4930            let base_addr = mm
4931                .set_brk(&current_task, UserAddress::default())
4932                .expect("failed to set initial program break");
4933            assert!(base_addr > UserAddress::default());
4934
4935            // Page containing the program break address should not be mapped.
4936            assert_eq!(get_range(base_addr), None);
4937
4938            // Growing it by a single byte results in that page becoming mapped.
4939            let addr0 =
4940                mm.set_brk(&current_task, (base_addr + 1u64).unwrap()).expect("failed to grow brk");
4941            assert!(addr0 > base_addr);
4942            let (range0, _) = get_range(base_addr).expect("base_addr should be mapped");
4943            assert_eq!(range0.start, base_addr);
4944            assert_eq!(range0.end, (base_addr + *PAGE_SIZE).unwrap());
4945
4946            // Grow the program break by another byte, which won't be enough to cause additional pages to be mapped.
4947            let addr1 =
4948                mm.set_brk(&current_task, (base_addr + 2u64).unwrap()).expect("failed to grow brk");
4949            assert_eq!(addr1, (base_addr + 2u64).unwrap());
4950            let (range1, _) = get_range(base_addr).expect("base_addr should be mapped");
4951            assert_eq!(range1.start, range0.start);
4952            assert_eq!(range1.end, range0.end);
4953
4954            // Grow the program break by a non-trival amount and observe the larger mapping.
4955            let addr2 = mm
4956                .set_brk(&current_task, (base_addr + 24893u64).unwrap())
4957                .expect("failed to grow brk");
4958            assert_eq!(addr2, (base_addr + 24893u64).unwrap());
4959            let (range2, _) = get_range(base_addr).expect("base_addr should be mapped");
4960            assert_eq!(range2.start, base_addr);
4961            assert_eq!(range2.end, addr2.round_up(*PAGE_SIZE).unwrap());
4962
4963            // Shrink the program break and observe the smaller mapping.
4964            let addr3 = mm
4965                .set_brk(&current_task, (base_addr + 14832u64).unwrap())
4966                .expect("failed to shrink brk");
4967            assert_eq!(addr3, (base_addr + 14832u64).unwrap());
4968            let (range3, _) = get_range(base_addr).expect("base_addr should be mapped");
4969            assert_eq!(range3.start, base_addr);
4970            assert_eq!(range3.end, addr3.round_up(*PAGE_SIZE).unwrap());
4971
4972            // Shrink the program break close to zero and observe the smaller mapping.
4973            let addr4 = mm
4974                .set_brk(&current_task, (base_addr + 3u64).unwrap())
4975                .expect("failed to drastically shrink brk");
4976            assert_eq!(addr4, (base_addr + 3u64).unwrap());
4977            let (range4, _) = get_range(base_addr).expect("base_addr should be mapped");
4978            assert_eq!(range4.start, base_addr);
4979            assert_eq!(range4.end, addr4.round_up(*PAGE_SIZE).unwrap());
4980
4981            // Shrink the program break to zero and observe that the mapping is entirely gone.
4982            let addr5 = mm
4983                .set_brk(&current_task, base_addr)
4984                .expect("failed to drastically shrink brk to zero");
4985            assert_eq!(addr5, base_addr);
4986            assert_eq!(get_range(base_addr), None);
4987        })
4988        .await;
4989    }
4990
4991    #[::fuchsia::test]
4992    async fn test_mm_exec() {
4993        spawn_kernel_and_run(async |current_task| {
4994            let mm = current_task.mm().unwrap();
4995
4996            let has = |addr: UserAddress| -> bool {
4997                let state = mm.state.read();
4998                state.mappings.get(addr).is_some()
4999            };
5000
5001            let brk_addr = mm
5002                .set_brk(&current_task, UserAddress::default())
5003                .expect("failed to set initial program break");
5004            assert!(brk_addr > UserAddress::default());
5005
5006            // Allocate a single page of BRK space, so that the break base address is mapped.
5007            let _ = mm
5008                .set_brk(&current_task, (brk_addr + 1u64).unwrap())
5009                .expect("failed to grow program break");
5010            assert!(has(brk_addr));
5011
5012            let mapped_addr = map_memory(&current_task, UserAddress::default(), *PAGE_SIZE);
5013            assert!(mapped_addr > UserAddress::default());
5014            assert!(has(mapped_addr));
5015
5016            let node = current_task.lookup_path_from_root("/".into()).unwrap();
5017            let new_mm = MemoryManager::exec(
5018                current_task.thread_group().root_vmar.unowned(),
5019                current_task.running_state().mm.to_option_arc(),
5020                node,
5021                ArchWidth::Arch64,
5022            )
5023            .expect("failed to exec memory manager");
5024            current_task.running_state().mm.update(Some(new_mm));
5025
5026            assert!(!has(brk_addr));
5027            assert!(!has(mapped_addr));
5028
5029            // Check that the old addresses are actually available for mapping.
5030            let brk_addr2 = map_memory(&current_task, brk_addr, *PAGE_SIZE);
5031            assert_eq!(brk_addr, brk_addr2);
5032            let mapped_addr2 = map_memory(&current_task, mapped_addr, *PAGE_SIZE);
5033            assert_eq!(mapped_addr, mapped_addr2);
5034        })
5035        .await;
5036    }
5037
5038    #[::fuchsia::test]
5039    async fn test_get_contiguous_mappings_at() {
5040        spawn_kernel_and_run(async |current_task| {
5041            let mm = current_task.mm().unwrap();
5042            let context = &mm.mapping_context;
5043
5044            // Create four one-page mappings with a hole between the third one and the fourth one.
5045            let page_size = *PAGE_SIZE as usize;
5046            let addr_a = (mm.base_addr + 10 * page_size).unwrap();
5047            let addr_b = (mm.base_addr + 11 * page_size).unwrap();
5048            let addr_c = (mm.base_addr + 12 * page_size).unwrap();
5049            let addr_d = (mm.base_addr + 14 * page_size).unwrap();
5050            assert_eq!(map_memory(&current_task, addr_a, *PAGE_SIZE), addr_a);
5051            assert_eq!(map_memory(&current_task, addr_b, *PAGE_SIZE), addr_b);
5052            assert_eq!(map_memory(&current_task, addr_c, *PAGE_SIZE), addr_c);
5053            assert_eq!(map_memory(&current_task, addr_d, *PAGE_SIZE), addr_d);
5054
5055            {
5056                let mm_state = mm.state.read();
5057                // Verify that requesting an unmapped address returns an empty iterator.
5058                assert_equal(
5059                    mm_state
5060                        .get_contiguous_mappings_at((addr_a - 100u64).unwrap(), 50, &context)
5061                        .unwrap(),
5062                    vec![],
5063                );
5064                assert_equal(
5065                    mm_state
5066                        .get_contiguous_mappings_at((addr_a - 100u64).unwrap(), 200, &context)
5067                        .unwrap(),
5068                    vec![],
5069                );
5070
5071                // Verify that requesting zero bytes returns an empty iterator.
5072                assert_equal(
5073                    mm_state.get_contiguous_mappings_at(addr_a, 0, &context).unwrap(),
5074                    vec![],
5075                );
5076
5077                // Verify errors.
5078                assert_eq!(
5079                    mm_state
5080                        .get_contiguous_mappings_at(UserAddress::from(100), usize::MAX, &context)
5081                        .err()
5082                        .unwrap(),
5083                    errno!(EFAULT)
5084                );
5085                assert_eq!(
5086                    mm_state
5087                        .get_contiguous_mappings_at(
5088                            (context.max_address() + 1u64).unwrap(),
5089                            0,
5090                            &context
5091                        )
5092                        .err()
5093                        .unwrap(),
5094                    errno!(EFAULT)
5095                );
5096            }
5097
5098            assert_eq!(mm.get_mapping_count(), 2);
5099            let mm_state = mm.state.read();
5100            let (map_a, map_b) = {
5101                let mut it = mm_state.mappings.iter();
5102                (it.next().unwrap().1, it.next().unwrap().1)
5103            };
5104
5105            assert_equal(
5106                mm_state.get_contiguous_mappings_at(addr_a, page_size, &context).unwrap(),
5107                vec![(map_a, page_size)],
5108            );
5109
5110            assert_equal(
5111                mm_state.get_contiguous_mappings_at(addr_a, page_size / 2, &context).unwrap(),
5112                vec![(map_a, page_size / 2)],
5113            );
5114
5115            assert_equal(
5116                mm_state.get_contiguous_mappings_at(addr_a, page_size * 3, &context).unwrap(),
5117                vec![(map_a, page_size * 3)],
5118            );
5119
5120            assert_equal(
5121                mm_state.get_contiguous_mappings_at(addr_b, page_size, &context).unwrap(),
5122                vec![(map_a, page_size)],
5123            );
5124
5125            assert_equal(
5126                mm_state.get_contiguous_mappings_at(addr_d, page_size, &context).unwrap(),
5127                vec![(map_b, page_size)],
5128            );
5129
5130            // Verify that results stop if there is a hole.
5131            assert_equal(
5132                mm_state
5133                    .get_contiguous_mappings_at(
5134                        (addr_a + page_size / 2).unwrap(),
5135                        page_size * 10,
5136                        &context,
5137                    )
5138                    .unwrap(),
5139                vec![(map_a, page_size * 2 + page_size / 2)],
5140            );
5141
5142            // Verify that results stop at the last mapped page.
5143            assert_equal(
5144                mm_state.get_contiguous_mappings_at(addr_d, page_size * 10, &context).unwrap(),
5145                vec![(map_b, page_size)],
5146            );
5147        })
5148        .await;
5149    }
5150
5151    #[::fuchsia::test]
5152    async fn test_read_write_crossing_mappings() {
5153        spawn_kernel_and_run(async |current_task| {
5154            let mm = current_task.mm().unwrap();
5155            let ma = current_task.deref();
5156
5157            // Map two contiguous pages at fixed addresses, but backed by distinct mappings.
5158            let page_size = *PAGE_SIZE;
5159            let addr = (mm.base_addr + 10 * page_size).unwrap();
5160            assert_eq!(map_memory(&current_task, addr, page_size), addr);
5161            assert_eq!(
5162                map_memory(&current_task, (addr + page_size).unwrap(), page_size),
5163                (addr + page_size).unwrap()
5164            );
5165            // Mappings get merged since they are baked by the same memory object
5166            assert_eq!(mm.get_mapping_count(), 1);
5167
5168            // Write a pattern crossing our two mappings.
5169            let test_addr = (addr + page_size / 2).unwrap();
5170            let data: Vec<u8> = (0..page_size).map(|i| (i % 256) as u8).collect();
5171            ma.write_memory(test_addr, &data).expect("failed to write test data");
5172
5173            // Read it back.
5174            let data_readback =
5175                ma.read_memory_to_vec(test_addr, data.len()).expect("failed to read test data");
5176            assert_eq!(&data, &data_readback);
5177        })
5178        .await;
5179    }
5180
5181    #[::fuchsia::test]
5182    async fn test_read_write_errors() {
5183        spawn_kernel_and_run(async |current_task| {
5184            let ma = current_task.deref();
5185
5186            let page_size = *PAGE_SIZE;
5187            let addr = map_memory(&current_task, UserAddress::default(), page_size);
5188            let buf = vec![0u8; page_size as usize];
5189
5190            // Verify that accessing data that is only partially mapped is an error.
5191            let partial_addr_before = (addr - page_size / 2).unwrap();
5192            assert_eq!(ma.write_memory(partial_addr_before, &buf), error!(EFAULT));
5193            assert_eq!(ma.read_memory_to_vec(partial_addr_before, buf.len()), error!(EFAULT));
5194            let partial_addr_after = (addr + page_size / 2).unwrap();
5195            assert_eq!(ma.write_memory(partial_addr_after, &buf), error!(EFAULT));
5196            assert_eq!(ma.read_memory_to_vec(partial_addr_after, buf.len()), error!(EFAULT));
5197
5198            // Verify that accessing unmapped memory is an error.
5199            let unmapped_addr = (addr - 10 * page_size).unwrap();
5200            assert_eq!(ma.write_memory(unmapped_addr, &buf), error!(EFAULT));
5201            assert_eq!(ma.read_memory_to_vec(unmapped_addr, buf.len()), error!(EFAULT));
5202
5203            // However, accessing zero bytes in unmapped memory is not an error.
5204            ma.write_memory(unmapped_addr, &[]).expect("failed to write no data");
5205            ma.read_memory_to_vec(unmapped_addr, 0).expect("failed to read no data");
5206        })
5207        .await;
5208    }
5209
5210    #[::fuchsia::test]
5211    async fn test_read_c_string_to_vec_large() {
5212        spawn_kernel_and_run(async |current_task| {
5213            let mm = current_task.mm().unwrap();
5214            let ma = current_task.deref();
5215
5216            let page_size = *PAGE_SIZE;
5217            let max_size = 4 * page_size as usize;
5218            let addr = (mm.base_addr + 10 * page_size).unwrap();
5219
5220            assert_eq!(map_memory(&current_task, addr, max_size as u64), addr);
5221
5222            let mut random_data = vec![0; max_size];
5223            starnix_crypto::cprng_draw(&mut random_data);
5224            // Remove all NUL bytes.
5225            for i in 0..random_data.len() {
5226                if random_data[i] == 0 {
5227                    random_data[i] = 1;
5228                }
5229            }
5230            random_data[max_size - 1] = 0;
5231
5232            ma.write_memory(addr, &random_data).expect("failed to write test string");
5233            // We should read the same value minus the last byte (NUL char).
5234            assert_eq!(
5235                ma.read_c_string_to_vec(UserCString::new(current_task, addr), max_size).unwrap(),
5236                random_data[..max_size - 1]
5237            );
5238        })
5239        .await;
5240    }
5241
5242    #[::fuchsia::test]
5243    async fn test_read_c_string_to_vec() {
5244        spawn_kernel_and_run(async |current_task| {
5245            let mm = current_task.mm().unwrap();
5246            let ma = current_task.deref();
5247
5248            let page_size = *PAGE_SIZE;
5249            let max_size = 2 * page_size as usize;
5250            let addr = (mm.base_addr + 10 * page_size).unwrap();
5251
5252            // Map a page at a fixed address and write an unterminated string at the end of it.
5253            assert_eq!(map_memory(&current_task, addr, page_size), addr);
5254            let test_str = b"foo!";
5255            let test_addr =
5256                addr.checked_add(page_size as usize).unwrap().checked_sub(test_str.len()).unwrap();
5257            ma.write_memory(test_addr, test_str).expect("failed to write test string");
5258
5259            // Expect error if the string is not terminated.
5260            assert_eq!(
5261                ma.read_c_string_to_vec(UserCString::new(current_task, test_addr), max_size),
5262                error!(ENAMETOOLONG)
5263            );
5264
5265            // Expect success if the string is terminated.
5266            ma.write_memory((addr + (page_size - 1)).unwrap(), b"\0").expect("failed to write nul");
5267            assert_eq!(
5268                ma.read_c_string_to_vec(UserCString::new(current_task, test_addr), max_size)
5269                    .unwrap(),
5270                "foo"
5271            );
5272
5273            // Expect success if the string spans over two mappings.
5274            assert_eq!(
5275                map_memory(&current_task, (addr + page_size).unwrap(), page_size),
5276                (addr + page_size).unwrap()
5277            );
5278            // TODO: Adjacent private anonymous mappings are collapsed. To test this case this test needs to
5279            // provide a backing for the second mapping.
5280            // assert_eq!(mm.get_mapping_count(), 2);
5281            ma.write_memory((addr + (page_size - 1)).unwrap(), b"bar\0")
5282                .expect("failed to write extra chars");
5283            assert_eq!(
5284                ma.read_c_string_to_vec(UserCString::new(current_task, test_addr), max_size)
5285                    .unwrap(),
5286                "foobar",
5287            );
5288
5289            // Expect error if the string exceeds max limit
5290            assert_eq!(
5291                ma.read_c_string_to_vec(UserCString::new(current_task, test_addr), 2),
5292                error!(ENAMETOOLONG)
5293            );
5294
5295            // Expect error if the address is invalid.
5296            assert_eq!(
5297                ma.read_c_string_to_vec(UserCString::null(current_task), max_size),
5298                error!(EFAULT)
5299            );
5300        })
5301        .await;
5302    }
5303
5304    #[::fuchsia::test]
5305    async fn can_read_argv_like_regions() {
5306        spawn_kernel_and_run(async |current_task| {
5307            let ma = current_task.deref();
5308
5309            // Map a page.
5310            let page_size = *PAGE_SIZE;
5311            let addr = map_memory_anywhere(&current_task, page_size);
5312            assert!(!addr.is_null());
5313
5314            // Write an unterminated string.
5315            let mut payload = "first".as_bytes().to_vec();
5316            let mut expected_parses = vec![];
5317            ma.write_memory(addr, &payload).unwrap();
5318
5319            // Expect success if the string is terminated.
5320            expected_parses.push(payload.clone());
5321            payload.push(0);
5322            ma.write_memory(addr, &payload).unwrap();
5323            assert_eq!(
5324                ma.read_nul_delimited_c_string_list(addr, payload.len()).unwrap(),
5325                expected_parses,
5326            );
5327
5328            // Make sure we can parse multiple strings from the same region.
5329            let second = b"second";
5330            payload.extend(second);
5331            payload.push(0);
5332            expected_parses.push(second.to_vec());
5333
5334            let third = b"third";
5335            payload.extend(third);
5336            payload.push(0);
5337            expected_parses.push(third.to_vec());
5338
5339            ma.write_memory(addr, &payload).unwrap();
5340            assert_eq!(
5341                ma.read_nul_delimited_c_string_list(addr, payload.len()).unwrap(),
5342                expected_parses,
5343            );
5344        })
5345        .await;
5346    }
5347
5348    #[::fuchsia::test]
5349    async fn truncate_argv_like_regions() {
5350        spawn_kernel_and_run(async |current_task| {
5351            let ma = current_task.deref();
5352
5353            // Map a page.
5354            let page_size = *PAGE_SIZE;
5355            let addr = map_memory_anywhere(&current_task, page_size);
5356            assert!(!addr.is_null());
5357
5358            let payload = b"first\0second\0third\0";
5359            ma.write_memory(addr, payload).unwrap();
5360            assert_eq!(
5361                ma.read_nul_delimited_c_string_list(addr, payload.len() - 3).unwrap(),
5362                vec![b"first".to_vec(), b"second".to_vec(), b"thi".to_vec()],
5363                "Skipping last three bytes of payload should skip last two bytes of 3rd string"
5364            );
5365        })
5366        .await;
5367    }
5368
5369    #[::fuchsia::test]
5370    async fn test_read_c_string() {
5371        spawn_kernel_and_run(async |current_task| {
5372            let mm = current_task.mm().unwrap();
5373            let ma = current_task.deref();
5374
5375            let page_size = *PAGE_SIZE;
5376            let buf_cap = 2 * page_size as usize;
5377            let mut buf = Vec::with_capacity(buf_cap);
5378            // We can't just use `spare_capacity_mut` because `Vec::with_capacity`
5379            // returns a `Vec` with _at least_ the requested capacity.
5380            let buf = &mut buf.spare_capacity_mut()[..buf_cap];
5381            let addr = (mm.base_addr + 10 * page_size).unwrap();
5382
5383            // Map a page at a fixed address and write an unterminated string at the end of it..
5384            assert_eq!(map_memory(&current_task, addr, page_size), addr);
5385            let test_str = b"foo!";
5386            let test_addr = (addr + (page_size - test_str.len() as u64)).unwrap();
5387            ma.write_memory(test_addr, test_str).expect("failed to write test string");
5388
5389            // Expect error if the string is not terminated.
5390            assert_eq!(
5391                ma.read_c_string(UserCString::new(current_task, test_addr), buf),
5392                error!(ENAMETOOLONG)
5393            );
5394
5395            // Expect success if the string is terminated.
5396            ma.write_memory((addr + (page_size - 1)).unwrap(), b"\0").expect("failed to write nul");
5397            assert_eq!(
5398                ma.read_c_string(UserCString::new(current_task, test_addr), buf).unwrap(),
5399                "foo"
5400            );
5401
5402            // Expect success if the string spans over two mappings.
5403            assert_eq!(
5404                map_memory(&current_task, (addr + page_size).unwrap(), page_size),
5405                (addr + page_size).unwrap()
5406            );
5407            // TODO: To be multiple mappings we need to provide a file backing for the next page or the
5408            // mappings will be collapsed.
5409            //assert_eq!(mm.get_mapping_count(), 2);
5410            ma.write_memory((addr + (page_size - 1)).unwrap(), b"bar\0")
5411                .expect("failed to write extra chars");
5412            assert_eq!(
5413                ma.read_c_string(UserCString::new(current_task, test_addr), buf).unwrap(),
5414                "foobar"
5415            );
5416
5417            // Expect error if the string does not fit in the provided buffer.
5418            assert_eq!(
5419                ma.read_c_string(
5420                    UserCString::new(current_task, test_addr),
5421                    &mut [MaybeUninit::uninit(); 2]
5422                ),
5423                error!(ENAMETOOLONG)
5424            );
5425
5426            // Expect error if the address is invalid.
5427            assert_eq!(ma.read_c_string(UserCString::null(current_task), buf), error!(EFAULT));
5428        })
5429        .await;
5430    }
5431
5432    #[::fuchsia::test]
5433    async fn test_find_next_unused_range() {
5434        spawn_kernel_and_run(async |current_task| {
5435            let mm = current_task.mm().unwrap();
5436
5437            let mmap_top = mm.state.read().find_next_unused_range(0).unwrap().ptr();
5438            let page_size = *PAGE_SIZE as usize;
5439            assert!(mmap_top <= RESTRICTED_ASPACE_HIGHEST_ADDRESS);
5440
5441            // No mappings - top address minus requested size is available
5442            assert_eq!(
5443                mm.state.read().find_next_unused_range(page_size).unwrap(),
5444                UserAddress::from_ptr(mmap_top - page_size)
5445            );
5446
5447            // Fill it.
5448            let addr = UserAddress::from_ptr(mmap_top - page_size);
5449            assert_eq!(map_memory(&current_task, addr, *PAGE_SIZE), addr);
5450
5451            // The next available range is right before the new mapping.
5452            assert_eq!(
5453                mm.state.read().find_next_unused_range(page_size).unwrap(),
5454                UserAddress::from_ptr(addr.ptr() - page_size)
5455            );
5456
5457            // Allocate an extra page before a one-page gap.
5458            let addr2 = UserAddress::from_ptr(addr.ptr() - 2 * page_size);
5459            assert_eq!(map_memory(&current_task, addr2, *PAGE_SIZE), addr2);
5460
5461            // Searching for one-page range still gives the same result
5462            assert_eq!(
5463                mm.state.read().find_next_unused_range(page_size).unwrap(),
5464                UserAddress::from_ptr(addr.ptr() - page_size)
5465            );
5466
5467            // Searching for a bigger range results in the area before the second mapping
5468            assert_eq!(
5469                mm.state.read().find_next_unused_range(2 * page_size).unwrap(),
5470                UserAddress::from_ptr(addr2.ptr() - 2 * page_size)
5471            );
5472
5473            // Searching for more memory than available should fail.
5474            assert_eq!(mm.state.read().find_next_unused_range(mmap_top), None);
5475        })
5476        .await;
5477    }
5478
5479    #[::fuchsia::test]
5480    async fn test_count_placements() {
5481        spawn_kernel_and_run(async |current_task| {
5482            let mm = current_task.mm().unwrap();
5483
5484            // ten-page range
5485            let page_size = *PAGE_SIZE as usize;
5486            let subrange_ten = UserAddress::from_ptr(RESTRICTED_ASPACE_BASE)
5487                ..UserAddress::from_ptr(RESTRICTED_ASPACE_BASE + 10 * page_size);
5488
5489            assert_eq!(
5490                mm.state.read().count_possible_placements(11 * page_size, &subrange_ten),
5491                Some(0)
5492            );
5493            assert_eq!(
5494                mm.state.read().count_possible_placements(10 * page_size, &subrange_ten),
5495                Some(1)
5496            );
5497            assert_eq!(
5498                mm.state.read().count_possible_placements(9 * page_size, &subrange_ten),
5499                Some(2)
5500            );
5501            assert_eq!(
5502                mm.state.read().count_possible_placements(page_size, &subrange_ten),
5503                Some(10)
5504            );
5505
5506            // map 6th page
5507            let addr = UserAddress::from_ptr(RESTRICTED_ASPACE_BASE + 5 * page_size);
5508            assert_eq!(map_memory(&current_task, addr, *PAGE_SIZE), addr);
5509
5510            assert_eq!(
5511                mm.state.read().count_possible_placements(10 * page_size, &subrange_ten),
5512                Some(0)
5513            );
5514            assert_eq!(
5515                mm.state.read().count_possible_placements(5 * page_size, &subrange_ten),
5516                Some(1)
5517            );
5518            assert_eq!(
5519                mm.state.read().count_possible_placements(4 * page_size, &subrange_ten),
5520                Some(3)
5521            );
5522            assert_eq!(
5523                mm.state.read().count_possible_placements(page_size, &subrange_ten),
5524                Some(9)
5525            );
5526        })
5527        .await;
5528    }
5529
5530    #[::fuchsia::test]
5531    async fn test_pick_placement() {
5532        spawn_kernel_and_run(async |current_task| {
5533            let mm = current_task.mm().unwrap();
5534
5535            let page_size = *PAGE_SIZE as usize;
5536            let subrange_ten = UserAddress::from_ptr(RESTRICTED_ASPACE_BASE)
5537                ..UserAddress::from_ptr(RESTRICTED_ASPACE_BASE + 10 * page_size);
5538
5539            let addr = UserAddress::from_ptr(RESTRICTED_ASPACE_BASE + 5 * page_size);
5540            assert_eq!(map_memory(&current_task, addr, *PAGE_SIZE), addr);
5541            assert_eq!(
5542                mm.state.read().count_possible_placements(4 * page_size, &subrange_ten),
5543                Some(3)
5544            );
5545
5546            assert_eq!(
5547                mm.state.read().pick_placement(4 * page_size, 0, &subrange_ten),
5548                Some(UserAddress::from_ptr(RESTRICTED_ASPACE_BASE))
5549            );
5550            assert_eq!(
5551                mm.state.read().pick_placement(4 * page_size, 1, &subrange_ten),
5552                Some(UserAddress::from_ptr(RESTRICTED_ASPACE_BASE + page_size))
5553            );
5554            assert_eq!(
5555                mm.state.read().pick_placement(4 * page_size, 2, &subrange_ten),
5556                Some(UserAddress::from_ptr(RESTRICTED_ASPACE_BASE + 6 * page_size))
5557            );
5558        })
5559        .await;
5560    }
5561
5562    #[::fuchsia::test]
5563    async fn test_find_random_unused_range() {
5564        spawn_kernel_and_run(async |current_task| {
5565            let mm = current_task.mm().unwrap();
5566
5567            // ten-page range
5568            let page_size = *PAGE_SIZE as usize;
5569            let subrange_ten = UserAddress::from_ptr(RESTRICTED_ASPACE_BASE)
5570                ..UserAddress::from_ptr(RESTRICTED_ASPACE_BASE + 10 * page_size);
5571
5572            for _ in 0..10 {
5573                let addr = mm.state.read().find_random_unused_range(page_size, &subrange_ten);
5574                assert!(addr.is_some());
5575                assert_eq!(map_memory(&current_task, addr.unwrap(), *PAGE_SIZE), addr.unwrap());
5576            }
5577            assert_eq!(mm.state.read().find_random_unused_range(page_size, &subrange_ten), None);
5578        })
5579        .await;
5580    }
5581
5582    #[::fuchsia::test]
5583    async fn test_grows_down_near_aspace_base() {
5584        spawn_kernel_and_run(async |current_task| {
5585            let mm = current_task.mm().unwrap();
5586
5587            let page_count = 10;
5588
5589            let page_size = *PAGE_SIZE as usize;
5590            let addr =
5591                (UserAddress::from_ptr(RESTRICTED_ASPACE_BASE) + page_count * page_size).unwrap();
5592            assert_eq!(
5593                map_memory_with_flags(
5594                    &current_task,
5595                    addr,
5596                    page_size as u64,
5597                    MAP_ANONYMOUS | MAP_PRIVATE | MAP_GROWSDOWN
5598                ),
5599                addr
5600            );
5601
5602            let subrange_ten = UserAddress::from_ptr(RESTRICTED_ASPACE_BASE)..addr;
5603            assert_eq!(mm.state.read().find_random_unused_range(page_size, &subrange_ten), None);
5604        })
5605        .await;
5606    }
5607
5608    #[::fuchsia::test]
5609    async fn test_unmap_returned_mappings() {
5610        spawn_kernel_and_run(async |current_task| {
5611            let mm = current_task.mm().unwrap();
5612
5613            let addr = map_memory(&current_task, UserAddress::default(), *PAGE_SIZE * 2);
5614
5615            let mut released_mappings = ReleasedMappings::default();
5616            let mut mm_state = mm.state.write();
5617            let unmap_result =
5618                mm_state.unmap(&mm, addr, *PAGE_SIZE as usize, &mut released_mappings);
5619            assert!(unmap_result.is_ok());
5620            assert_eq!(released_mappings.len(), 1);
5621            released_mappings.finalize(mm_state);
5622        })
5623        .await;
5624    }
5625
5626    #[::fuchsia::test]
5627    async fn test_unmap_returns_multiple_mappings() {
5628        spawn_kernel_and_run(async |current_task| {
5629            let mm = current_task.mm().unwrap();
5630
5631            let addr = mm.state.read().find_next_unused_range(3 * *PAGE_SIZE as usize).unwrap();
5632            let addr = map_memory(&current_task, addr, *PAGE_SIZE);
5633            let _ = map_memory(&current_task, (addr + 2 * *PAGE_SIZE).unwrap(), *PAGE_SIZE);
5634
5635            let mut released_mappings = ReleasedMappings::default();
5636            let mut mm_state = mm.state.write();
5637            let unmap_result =
5638                mm_state.unmap(&mm, addr, (*PAGE_SIZE * 3) as usize, &mut released_mappings);
5639            assert!(unmap_result.is_ok());
5640            assert_eq!(released_mappings.len(), 2);
5641            released_mappings.finalize(mm_state);
5642        })
5643        .await;
5644    }
5645
5646    /// Maps two pages in separate mappings next to each other, then unmaps the first page.
5647    /// The second page should not be modified.
5648    #[::fuchsia::test]
5649    async fn test_map_two_unmap_one() {
5650        spawn_kernel_and_run(async |current_task| {
5651            let mm = current_task.mm().unwrap();
5652
5653            // reserve memory for both pages
5654            let addr_reserve = map_memory(&current_task, UserAddress::default(), *PAGE_SIZE * 2);
5655            let addr1 = do_mmap(
5656                &current_task,
5657                addr_reserve,
5658                *PAGE_SIZE as usize,
5659                PROT_READ, // Map read-only to avoid merging of the two mappings
5660                MAP_ANONYMOUS | MAP_SHARED | MAP_FIXED,
5661                FdNumber::from_raw(-1),
5662                0,
5663            )
5664            .expect("failed to mmap");
5665            let addr2 = map_memory_with_flags(
5666                &current_task,
5667                (addr_reserve + *PAGE_SIZE).unwrap(),
5668                *PAGE_SIZE,
5669                MAP_ANONYMOUS | MAP_SHARED | MAP_FIXED,
5670            );
5671            let state = mm.state.read();
5672            let (range1, _) = state.mappings.get(addr1).expect("mapping");
5673            assert_eq!(range1.start, addr1);
5674            assert_eq!(range1.end, (addr1 + *PAGE_SIZE).unwrap());
5675            let (range2, mapping2) = state.mappings.get(addr2).expect("mapping");
5676            assert_eq!(range2.start, addr2);
5677            assert_eq!(range2.end, (addr2 + *PAGE_SIZE).unwrap());
5678            let original_memory2 = {
5679                match state.get_mapping_backing(mapping2) {
5680                    MappingBacking::Memory(backing) => {
5681                        assert_eq!(backing.memory().get_size(), *PAGE_SIZE);
5682                        backing.memory().clone()
5683                    }
5684                    MappingBacking::PrivateAnonymous => {
5685                        panic!("Unexpected private anonymous mapping")
5686                    }
5687                }
5688            };
5689            std::mem::drop(state);
5690
5691            assert_eq!(mm.unmap(addr1, *PAGE_SIZE as usize), Ok(()));
5692
5693            let state = mm.state.read();
5694
5695            // The first page should be unmapped.
5696            assert!(state.mappings.get(addr1).is_none());
5697
5698            // The second page should remain unchanged.
5699            let (range2, mapping2) = state.mappings.get(addr2).expect("second page");
5700            assert_eq!(range2.start, addr2);
5701            assert_eq!(range2.end, (addr2 + *PAGE_SIZE).unwrap());
5702            match state.get_mapping_backing(mapping2) {
5703                MappingBacking::Memory(backing) => {
5704                    assert_eq!(backing.memory().get_size(), *PAGE_SIZE);
5705                    assert_eq!(original_memory2.get_koid(), backing.memory().get_koid());
5706                }
5707                MappingBacking::PrivateAnonymous => panic!("Unexpected private anonymous mapping"),
5708            }
5709        })
5710        .await;
5711    }
5712
5713    #[::fuchsia::test]
5714    async fn test_read_write_objects() {
5715        spawn_kernel_and_run(async |current_task| {
5716            let ma = current_task.deref();
5717            let addr = map_memory(&current_task, UserAddress::default(), *PAGE_SIZE);
5718            let items_ref = UserRef::<i32>::new(addr);
5719
5720            let items_written = vec![0, 2, 3, 7, 1];
5721            ma.write_objects(items_ref, &items_written).expect("Failed to write object array.");
5722
5723            let items_read = ma
5724                .read_objects_to_vec(items_ref, items_written.len())
5725                .expect("Failed to read object array.");
5726
5727            assert_eq!(items_written, items_read);
5728        })
5729        .await;
5730    }
5731
5732    #[::fuchsia::test]
5733    async fn test_read_write_objects_null() {
5734        spawn_kernel_and_run(async |current_task| {
5735            let ma = current_task.deref();
5736            let items_ref = UserRef::<i32>::new(UserAddress::default());
5737
5738            let items_written = vec![];
5739            ma.write_objects(items_ref, &items_written)
5740                .expect("Failed to write empty object array.");
5741
5742            let items_read = ma
5743                .read_objects_to_vec(items_ref, items_written.len())
5744                .expect("Failed to read empty object array.");
5745
5746            assert_eq!(items_written, items_read);
5747        })
5748        .await;
5749    }
5750
5751    #[::fuchsia::test]
5752    async fn test_read_object_partial() {
5753        #[derive(Debug, Default, Copy, Clone, KnownLayout, FromBytes, Immutable, PartialEq)]
5754        struct Items {
5755            val: [i32; 4],
5756        }
5757
5758        spawn_kernel_and_run(async |current_task| {
5759            let ma = current_task.deref();
5760            let addr = map_memory(&current_task, UserAddress::default(), *PAGE_SIZE);
5761            let items_array_ref = UserRef::<i32>::new(addr);
5762
5763            // Populate some values.
5764            let items_written = vec![75, 23, 51, 98];
5765            ma.write_objects(items_array_ref, &items_written)
5766                .expect("Failed to write object array.");
5767
5768            // Full read of all 4 values.
5769            let items_ref = UserRef::<Items>::new(addr);
5770            let items_read = ma
5771                .read_object_partial(items_ref, std::mem::size_of::<Items>())
5772                .expect("Failed to read object");
5773            assert_eq!(items_written, items_read.val);
5774
5775            // Partial read of the first two.
5776            let items_read = ma.read_object_partial(items_ref, 8).expect("Failed to read object");
5777            assert_eq!(vec![75, 23, 0, 0], items_read.val);
5778
5779            // The API currently allows reading 0 bytes (this could be re-evaluated) so test that does
5780            // the right thing.
5781            let items_read = ma.read_object_partial(items_ref, 0).expect("Failed to read object");
5782            assert_eq!(vec![0, 0, 0, 0], items_read.val);
5783
5784            // Size bigger than the object.
5785            assert_eq!(
5786                ma.read_object_partial(items_ref, std::mem::size_of::<Items>() + 8),
5787                error!(EINVAL)
5788            );
5789
5790            // Bad pointer.
5791            assert_eq!(
5792                ma.read_object_partial(UserRef::<Items>::new(UserAddress::from(1)), 16),
5793                error!(EFAULT)
5794            );
5795        })
5796        .await;
5797    }
5798
5799    #[::fuchsia::test]
5800    async fn test_partial_read() {
5801        spawn_kernel_and_run(async |current_task| {
5802            let mm = current_task.mm().unwrap();
5803            let ma = current_task.deref();
5804
5805            let addr = mm.state.read().find_next_unused_range(2 * *PAGE_SIZE as usize).unwrap();
5806            let addr = map_memory(&current_task, addr, *PAGE_SIZE);
5807            let second_map = map_memory(&current_task, (addr + *PAGE_SIZE).unwrap(), *PAGE_SIZE);
5808
5809            let bytes = vec![0xf; (*PAGE_SIZE * 2) as usize];
5810            assert!(ma.write_memory(addr, &bytes).is_ok());
5811            let mut state = mm.state.write();
5812            let mut released_mappings = ReleasedMappings::default();
5813            state
5814                .protect(
5815                    ma,
5816                    second_map,
5817                    *PAGE_SIZE as usize,
5818                    ProtectionFlags::empty(),
5819                    &mut released_mappings,
5820                )
5821                .unwrap();
5822            released_mappings.finalize(state);
5823            assert_eq!(
5824                ma.read_memory_partial_to_vec(addr, bytes.len()).unwrap().len(),
5825                *PAGE_SIZE as usize,
5826            );
5827        })
5828        .await;
5829    }
5830
5831    fn map_memory_growsdown(current_task: &CurrentTask, length: u64) -> UserAddress {
5832        map_memory_with_flags(
5833            current_task,
5834            UserAddress::default(),
5835            length,
5836            MAP_ANONYMOUS | MAP_PRIVATE | MAP_GROWSDOWN,
5837        )
5838    }
5839
5840    #[::fuchsia::test]
5841    async fn test_grow_mapping_empty_mm() {
5842        spawn_kernel_and_run(async |current_task| {
5843            let mm = current_task.mm().unwrap();
5844
5845            let addr = UserAddress::from(0x100000);
5846
5847            assert_matches!(mm.extend_growsdown_mapping_to_address(addr, false), Ok(false));
5848        })
5849        .await;
5850    }
5851
5852    #[::fuchsia::test]
5853    async fn test_grow_inside_mapping() {
5854        spawn_kernel_and_run(async |current_task| {
5855            let mm = current_task.mm().unwrap();
5856
5857            let addr = map_memory(&current_task, UserAddress::default(), *PAGE_SIZE);
5858
5859            assert_matches!(mm.extend_growsdown_mapping_to_address(addr, false), Ok(false));
5860        })
5861        .await;
5862    }
5863
5864    #[::fuchsia::test]
5865    async fn test_grow_write_fault_inside_read_only_mapping() {
5866        spawn_kernel_and_run(async |current_task| {
5867            let mm = current_task.mm().unwrap();
5868
5869            let addr = do_mmap(
5870                &current_task,
5871                UserAddress::default(),
5872                *PAGE_SIZE as usize,
5873                PROT_READ,
5874                MAP_ANONYMOUS | MAP_PRIVATE,
5875                FdNumber::from_raw(-1),
5876                0,
5877            )
5878            .expect("Could not map memory");
5879
5880            assert_matches!(mm.extend_growsdown_mapping_to_address(addr, false), Ok(false));
5881            assert_matches!(mm.extend_growsdown_mapping_to_address(addr, true), Ok(false));
5882        })
5883        .await;
5884    }
5885
5886    #[::fuchsia::test]
5887    async fn test_grow_fault_inside_prot_none_mapping() {
5888        spawn_kernel_and_run(async |current_task| {
5889            let mm = current_task.mm().unwrap();
5890
5891            let addr = do_mmap(
5892                &current_task,
5893                UserAddress::default(),
5894                *PAGE_SIZE as usize,
5895                PROT_NONE,
5896                MAP_ANONYMOUS | MAP_PRIVATE,
5897                FdNumber::from_raw(-1),
5898                0,
5899            )
5900            .expect("Could not map memory");
5901
5902            assert_matches!(mm.extend_growsdown_mapping_to_address(addr, false), Ok(false));
5903            assert_matches!(mm.extend_growsdown_mapping_to_address(addr, true), Ok(false));
5904        })
5905        .await;
5906    }
5907
5908    #[::fuchsia::test]
5909    async fn test_grow_below_mapping() {
5910        spawn_kernel_and_run(async |current_task| {
5911            let mm = current_task.mm().unwrap();
5912
5913            let addr = map_memory_growsdown(&current_task, *PAGE_SIZE) - *PAGE_SIZE;
5914
5915            assert_matches!(mm.extend_growsdown_mapping_to_address(addr.unwrap(), false), Ok(true));
5916        })
5917        .await;
5918    }
5919
5920    #[::fuchsia::test]
5921    async fn test_grow_above_mapping() {
5922        spawn_kernel_and_run(async |current_task| {
5923            let mm = current_task.mm().unwrap();
5924
5925            let addr = map_memory_growsdown(&current_task, *PAGE_SIZE) + *PAGE_SIZE;
5926
5927            assert_matches!(
5928                mm.extend_growsdown_mapping_to_address(addr.unwrap(), false),
5929                Ok(false)
5930            );
5931        })
5932        .await;
5933    }
5934
5935    #[::fuchsia::test]
5936    async fn test_grow_write_fault_below_read_only_mapping() {
5937        spawn_kernel_and_run(async |current_task| {
5938            let mm = current_task.mm().unwrap();
5939
5940            let mapped_addr = map_memory_growsdown(&current_task, *PAGE_SIZE);
5941
5942            mm.protect(&current_task, mapped_addr, *PAGE_SIZE as usize, ProtectionFlags::READ)
5943                .unwrap();
5944
5945            assert_matches!(
5946                mm.extend_growsdown_mapping_to_address((mapped_addr - *PAGE_SIZE).unwrap(), true),
5947                Ok(false)
5948            );
5949
5950            assert_eq!(mm.get_mapping_count(), 1);
5951        })
5952        .await;
5953    }
5954
5955    #[::fuchsia::test]
5956    async fn test_snapshot_paged_memory() {
5957        use zx::sys::zx_page_request_command_t::ZX_PAGER_VMO_READ;
5958
5959        spawn_kernel_and_run(async |current_task| {
5960            let mm = current_task.mm().unwrap();
5961            let ma = current_task.deref();
5962
5963            let port = Arc::new(zx::Port::create());
5964            let port_clone = port.clone();
5965            let pager =
5966                Arc::new(zx::Pager::create(zx::PagerOptions::empty()).expect("create failed"));
5967            let pager_clone = pager.clone();
5968
5969            const VMO_SIZE: u64 = 128 * 1024;
5970            let vmo = Arc::new(
5971                pager
5972                    .create_vmo(zx::VmoOptions::RESIZABLE, &port, 1, VMO_SIZE)
5973                    .expect("create_vmo failed"),
5974            );
5975            let vmo_clone = vmo.clone();
5976
5977            // Create a thread to service the port where we will receive pager requests.
5978            let thread = std::thread::spawn(move || {
5979                loop {
5980                    let packet =
5981                        port_clone.wait(zx::MonotonicInstant::INFINITE).expect("wait failed");
5982                    match packet.contents() {
5983                        zx::PacketContents::Pager(contents) => {
5984                            if contents.command() == ZX_PAGER_VMO_READ {
5985                                let range = contents.range();
5986                                let source_vmo = zx::Vmo::create(range.end - range.start)
5987                                    .expect("create failed");
5988                                pager_clone
5989                                    .supply_pages(&vmo_clone, range, &source_vmo, 0)
5990                                    .expect("supply_pages failed");
5991                            }
5992                        }
5993                        zx::PacketContents::User(_) => break,
5994                        _ => {}
5995                    }
5996                }
5997            });
5998
5999            let child_vmo = vmo
6000                .create_child(zx::VmoChildOptions::SNAPSHOT_AT_LEAST_ON_WRITE, 0, VMO_SIZE)
6001                .unwrap();
6002
6003            // Write something to the source VMO.
6004            vmo.write(b"foo", 0).expect("write failed");
6005
6006            let prot_flags = ProtectionFlags::READ | ProtectionFlags::WRITE;
6007            let addr = mm
6008                .map_memory(
6009                    DesiredAddress::Any,
6010                    Arc::new(MemoryObject::from(child_vmo)),
6011                    0,
6012                    VMO_SIZE as usize,
6013                    prot_flags,
6014                    Access::rwx(),
6015                    MappingOptions::empty(),
6016                    MappingName::None,
6017                )
6018                .expect("map failed");
6019
6020            let target = current_task.clone_task_for_test(0, None);
6021
6022            // Make sure it has what we wrote.
6023            let buf = target.read_memory_to_vec(addr, 3).expect("read_memory failed");
6024            assert_eq!(buf, b"foo");
6025
6026            // Write something to both source and target and make sure they are forked.
6027            ma.write_memory(addr, b"bar").expect("write_memory failed");
6028
6029            let buf = target.read_memory_to_vec(addr, 3).expect("read_memory failed");
6030            assert_eq!(buf, b"foo");
6031
6032            target.write_memory(addr, b"baz").expect("write_memory failed");
6033            let buf = ma.read_memory_to_vec(addr, 3).expect("read_memory failed");
6034            assert_eq!(buf, b"bar");
6035
6036            let buf = target.read_memory_to_vec(addr, 3).expect("read_memory failed");
6037            assert_eq!(buf, b"baz");
6038
6039            port.queue(&zx::Packet::from_user_packet(0, 0, zx::UserPacket::from_u8_array([0; 32])))
6040                .unwrap();
6041            thread.join().unwrap();
6042        })
6043        .await;
6044    }
6045
6046    #[::fuchsia::test]
6047    async fn test_set_vma_name() {
6048        spawn_kernel_and_run(async |mut current_task| {
6049            let name_addr = map_memory(&current_task, UserAddress::default(), *PAGE_SIZE);
6050
6051            let vma_name = "vma name";
6052            current_task.write_memory(name_addr, vma_name.as_bytes()).unwrap();
6053
6054            let mapping_addr = map_memory(&current_task, UserAddress::default(), *PAGE_SIZE);
6055
6056            sys_prctl(
6057                &mut current_task,
6058                PR_SET_VMA,
6059                PR_SET_VMA_ANON_NAME as u64,
6060                mapping_addr.ptr() as u64,
6061                *PAGE_SIZE,
6062                name_addr.ptr() as u64,
6063            )
6064            .unwrap();
6065
6066            assert_eq!(
6067                *current_task.mm().unwrap().get_mapping_name(mapping_addr).unwrap().unwrap(),
6068                vma_name
6069            );
6070        })
6071        .await;
6072    }
6073
6074    #[::fuchsia::test]
6075    async fn test_set_vma_name_adjacent_mappings() {
6076        spawn_kernel_and_run(async |mut current_task| {
6077            let name_addr = map_memory(&current_task, UserAddress::default(), *PAGE_SIZE);
6078            current_task
6079                .write_memory(name_addr, CString::new("foo").unwrap().as_bytes_with_nul())
6080                .unwrap();
6081
6082            let first_mapping_addr =
6083                map_memory(&current_task, UserAddress::default(), 2 * *PAGE_SIZE);
6084            let second_mapping_addr = map_memory_with_flags(
6085                &current_task,
6086                (first_mapping_addr + *PAGE_SIZE).unwrap(),
6087                *PAGE_SIZE,
6088                MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
6089            );
6090
6091            assert_eq!((first_mapping_addr + *PAGE_SIZE).unwrap(), second_mapping_addr);
6092
6093            sys_prctl(
6094                &mut current_task,
6095                PR_SET_VMA,
6096                PR_SET_VMA_ANON_NAME as u64,
6097                first_mapping_addr.ptr() as u64,
6098                2 * *PAGE_SIZE,
6099                name_addr.ptr() as u64,
6100            )
6101            .unwrap();
6102
6103            {
6104                let mm = current_task.mm().unwrap();
6105                let state = mm.state.read();
6106
6107                // The name should apply to both mappings.
6108                let (_, mapping) = state.mappings.get(first_mapping_addr).unwrap();
6109                assert_eq!(mapping.name(), MappingName::Vma("foo".into()));
6110
6111                let (_, mapping) = state.mappings.get(second_mapping_addr).unwrap();
6112                assert_eq!(mapping.name(), MappingName::Vma("foo".into()));
6113            }
6114        })
6115        .await;
6116    }
6117
6118    #[::fuchsia::test]
6119    async fn test_set_vma_name_beyond_end() {
6120        spawn_kernel_and_run(async |mut current_task| {
6121            let name_addr = map_memory(&current_task, UserAddress::default(), *PAGE_SIZE);
6122            current_task
6123                .write_memory(name_addr, CString::new("foo").unwrap().as_bytes_with_nul())
6124                .unwrap();
6125
6126            let mapping_addr = map_memory(&current_task, UserAddress::default(), 2 * *PAGE_SIZE);
6127
6128            let second_page = (mapping_addr + *PAGE_SIZE).unwrap();
6129            current_task.mm().unwrap().unmap(second_page, *PAGE_SIZE as usize).unwrap();
6130
6131            // This should fail with ENOMEM since it extends past the end of the mapping into unmapped memory.
6132            assert_eq!(
6133                sys_prctl(
6134                    &mut current_task,
6135                    PR_SET_VMA,
6136                    PR_SET_VMA_ANON_NAME as u64,
6137                    mapping_addr.ptr() as u64,
6138                    2 * *PAGE_SIZE,
6139                    name_addr.ptr() as u64,
6140                ),
6141                error!(ENOMEM)
6142            );
6143
6144            // Despite returning an error, the prctl should still assign a name to the region at the start of the region.
6145            {
6146                let mm = current_task.mm().unwrap();
6147                let state = mm.state.read();
6148
6149                let (_, mapping) = state.mappings.get(mapping_addr).unwrap();
6150                assert_eq!(mapping.name(), MappingName::Vma("foo".into()));
6151            }
6152        })
6153        .await;
6154    }
6155
6156    #[::fuchsia::test]
6157    async fn test_set_vma_name_before_start() {
6158        spawn_kernel_and_run(async |mut current_task| {
6159            let name_addr = map_memory(&current_task, UserAddress::default(), *PAGE_SIZE);
6160            current_task
6161                .write_memory(name_addr, CString::new("foo").unwrap().as_bytes_with_nul())
6162                .unwrap();
6163
6164            let mapping_addr = map_memory(&current_task, UserAddress::default(), 2 * *PAGE_SIZE);
6165
6166            let second_page = (mapping_addr + *PAGE_SIZE).unwrap();
6167            current_task.mm().unwrap().unmap(mapping_addr, *PAGE_SIZE as usize).unwrap();
6168
6169            // This should fail with ENOMEM since the start of the range is in unmapped memory.
6170            assert_eq!(
6171                sys_prctl(
6172                    &mut current_task,
6173                    PR_SET_VMA,
6174                    PR_SET_VMA_ANON_NAME as u64,
6175                    mapping_addr.ptr() as u64,
6176                    2 * *PAGE_SIZE,
6177                    name_addr.ptr() as u64,
6178                ),
6179                error!(ENOMEM)
6180            );
6181
6182            // Unlike a range which starts within a mapping and extends past the end, this should not assign
6183            // a name to any mappings.
6184            {
6185                let mm = current_task.mm().unwrap();
6186                let state = mm.state.read();
6187
6188                let (_, mapping) = state.mappings.get(second_page).unwrap();
6189                assert_eq!(mapping.name(), MappingName::None);
6190            }
6191        })
6192        .await;
6193    }
6194
6195    #[::fuchsia::test]
6196    async fn test_set_vma_name_partial() {
6197        spawn_kernel_and_run(async |mut current_task| {
6198            let name_addr = map_memory(&current_task, UserAddress::default(), *PAGE_SIZE);
6199            current_task
6200                .write_memory(name_addr, CString::new("foo").unwrap().as_bytes_with_nul())
6201                .unwrap();
6202
6203            let mapping_addr = map_memory(&current_task, UserAddress::default(), 3 * *PAGE_SIZE);
6204
6205            assert_eq!(
6206                sys_prctl(
6207                    &mut current_task,
6208                    PR_SET_VMA,
6209                    PR_SET_VMA_ANON_NAME as u64,
6210                    (mapping_addr + *PAGE_SIZE).unwrap().ptr() as u64,
6211                    *PAGE_SIZE,
6212                    name_addr.ptr() as u64,
6213                ),
6214                Ok(starnix_syscalls::SUCCESS)
6215            );
6216
6217            // This should split the mapping into 3 pieces with the second piece having the name "foo"
6218            {
6219                let mm = current_task.mm().unwrap();
6220                let state = mm.state.read();
6221
6222                let (_, mapping) = state.mappings.get(mapping_addr).unwrap();
6223                assert_eq!(mapping.name(), MappingName::None);
6224
6225                let (_, mapping) =
6226                    state.mappings.get((mapping_addr + *PAGE_SIZE).unwrap()).unwrap();
6227                assert_eq!(mapping.name(), MappingName::Vma("foo".into()));
6228
6229                let (_, mapping) =
6230                    state.mappings.get((mapping_addr + (2 * *PAGE_SIZE)).unwrap()).unwrap();
6231                assert_eq!(mapping.name(), MappingName::None);
6232            }
6233        })
6234        .await;
6235    }
6236
6237    #[::fuchsia::test]
6238    async fn test_preserve_name_snapshot() {
6239        spawn_kernel_and_run(async |mut current_task| {
6240            let name_addr = map_memory(&current_task, UserAddress::default(), *PAGE_SIZE);
6241            current_task
6242                .write_memory(name_addr, CString::new("foo").unwrap().as_bytes_with_nul())
6243                .unwrap();
6244
6245            let mapping_addr = map_memory(&current_task, UserAddress::default(), *PAGE_SIZE);
6246
6247            assert_eq!(
6248                sys_prctl(
6249                    &mut current_task,
6250                    PR_SET_VMA,
6251                    PR_SET_VMA_ANON_NAME as u64,
6252                    mapping_addr.ptr() as u64,
6253                    *PAGE_SIZE,
6254                    name_addr.ptr() as u64,
6255                ),
6256                Ok(starnix_syscalls::SUCCESS)
6257            );
6258
6259            let target = current_task.clone_task_for_test(0, None);
6260
6261            {
6262                let mm = target.mm().unwrap();
6263                let state = mm.state.read();
6264
6265                let (_, mapping) = state.mappings.get(mapping_addr).unwrap();
6266                assert_eq!(mapping.name(), MappingName::Vma("foo".into()));
6267            }
6268        })
6269        .await;
6270    }
6271}