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