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