Skip to main content

starnix_core/vfs/
namespace.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::security;
6use crate::task::{
7    CurrentTask, EventHandler, Kernel, MountsWriteToken, TaskContainer, WaitCanceler, Waiter,
8    register_delayed_call,
9};
10use crate::time::utc;
11use crate::vfs::fs_args::MountParams;
12use crate::vfs::fs_registry::FsRegistry;
13use crate::vfs::pseudo::dynamic_file::{DynamicFile, DynamicFileBuf, DynamicFileSource};
14use crate::vfs::pseudo::simple_file::SimpleFileNode;
15use crate::vfs::socket::{SocketAddress, SocketHandle, UnixSocket};
16use crate::vfs::{
17    AccessCheck, CreationStatus, DirEntry, DirEntryHandle, FileHandle, FileObject, FileOps,
18    FileSystem, FileSystemHandle, FileSystemOptions, FileWriteGuardMode, FsContext, FsNode,
19    FsNodeHandle, FsNodeOps, FsStr, FsString, OpenAccessCheck, PathBuilder, RenameFlags,
20    SymlinkTarget, UnlinkKind, fileops_impl_dataless, fileops_impl_delegate_read_write_and_seek,
21    fileops_impl_nonseekable, fileops_impl_noop_sync, fs_node_impl_not_dir,
22};
23use fuchsia_rcu::{RcuArc, RcuBox, RcuDroppable, RcuReadScope};
24use fuchsia_rcu_collections::rcu_raw_hash_map::RcuRawHashMap;
25use starnix_logging::log_warn;
26use starnix_sync::{LockDepMutex, MountSubmountsLock, MountsLock, NamespaceFlagsLock};
27use starnix_uapi::arc_key::{ArcKey, PtrKey, WeakKey};
28use starnix_uapi::auth::Credentials;
29use starnix_uapi::device_id::DeviceId;
30use starnix_uapi::errors::Errno;
31use starnix_uapi::file_mode::{Access, FileMode};
32use starnix_uapi::inotify_mask::InotifyMask;
33use starnix_uapi::mount_flags::{
34    AtomicMountpointFlags, FileSystemFlags, MountFlags, MountpointFlags,
35};
36use starnix_uapi::open_flags::OpenFlags;
37use starnix_uapi::unmount_flags::UnmountFlags;
38use starnix_uapi::vfs::{FdEvents, ResolveFlags};
39use starnix_uapi::{NAME_MAX, errno, error};
40use std::collections::{HashMap, HashSet};
41use std::fmt;
42use std::hash::{Hash, Hasher};
43use std::ops::{Deref, DerefMut};
44use std::sync::atomic::Ordering;
45use std::sync::{Arc, Weak};
46
47/// A mount namespace.
48///
49/// The namespace records at which entries filesystems are mounted.
50#[derive(Debug)]
51pub struct Namespace {
52    root_mount: MountHandle,
53
54    // Unique ID of this namespace.
55    pub id: u64,
56}
57
58impl Namespace {
59    pub fn new(fs: FileSystemHandle) -> Arc<Namespace> {
60        Self::new_with_flags(fs, MountpointFlags::empty())
61    }
62
63    pub fn new_with_flags(fs: FileSystemHandle, flags: MountpointFlags) -> Arc<Namespace> {
64        let kernel = fs.kernel.upgrade().expect("can't create namespace without a kernel");
65        let mounts_guard = kernel.mounts_lock();
66
67        let root_mount = Mount::new(&mounts_guard, WhatToMount::Fs(fs), flags)
68            .expect("creating root mount for new filesystem");
69        Arc::new(Self { root_mount, id: kernel.get_next_namespace_id() })
70    }
71
72    pub fn root(&self) -> NamespaceNode {
73        self.root_mount.root()
74    }
75
76    /// Consumes a bootstrap `Namespace`, panicking if any references to the namespace, its root
77    /// mount, or its underlying filesystem remain, or if any entries were created in its root.
78    pub(super) fn destroy_bootstrap(self: Arc<Self>) {
79        let ns = Arc::into_inner(self).expect("bootstrap namespace still referenced");
80        let root_mount =
81            Arc::into_inner(ns.root_mount).expect("bootstrap root mount still referenced");
82        assert_eq!(root_mount.active_clients(), 0);
83        assert_eq!(root_mount.relations.submounts_len(), 0);
84        assert_eq!(Arc::strong_count(&root_mount.fs), 1, "bootstrap filesystem still referenced");
85        // Both `root_mount.root` and `root_mount.fs.root` hold a strong reference to the root
86        // `DirEntry`. Any child `DirEntry` created under the root would also hold a parent
87        // reference, increasing the strong count above 2.
88        assert_eq!(
89            Arc::strong_count(&root_mount.root),
90            2,
91            "bootstrap root directory must not have children or external references"
92        );
93    }
94
95    pub fn kernel(&self) -> Arc<Kernel> {
96        self.root_mount.kernel()
97    }
98
99    pub fn clone_namespace(&self, mounts_guard: &MountsWriteToken) -> Arc<Namespace> {
100        Arc::new(Self {
101            root_mount: self.root_mount.clone_mount_recursive(mounts_guard),
102            id: self.kernel().get_next_namespace_id(),
103        })
104    }
105
106    /// Assuming new_ns is a clone of the namespace that node is from, return the equivalent of
107    /// node in new_ns. If this assumption is violated, returns None.
108    pub fn translate_node(
109        node: NamespaceNode,
110        new_ns: &Namespace,
111        mounts_guard: &MountsWriteToken,
112    ) -> Option<NamespaceNode> {
113        if node.mount.as_ref().is_some_and(|m| m.is_detached(mounts_guard)) {
114            return Some(node);
115        }
116        let mut node = mounts_guard.defer_drop(node);
117        // Collect the list of mountpoints that leads to this node's mount
118        let mut mountpoints = vec![];
119        let mut mount = node.mount.clone();
120        while let Some(mountpoint) = mount.as_ref().and_then(|m| m.mountpoint()) {
121            mountpoints.push(mountpoint.entry);
122            let prev = std::mem::replace(&mut mount, mountpoint.mount);
123            mounts_guard.defer_drop(prev);
124        }
125        mounts_guard.defer_drop(mount);
126        let mountpoints = mounts_guard.defer_drop(mountpoints);
127
128        // Follow the same path in the new namespace
129        let scope = RcuReadScope::new();
130        let mut mount = Arc::clone(&new_ns.root_mount);
131        for mountpoint in mountpoints.iter().rev() {
132            let next_mount = match mount.relations.get_submount(&scope, &PtrKey::from(mountpoint)) {
133                Some(m) => m,
134                None => {
135                    mounts_guard.defer_drop(mount);
136                    return None;
137                }
138            };
139            mounts_guard.defer_drop(std::mem::replace(&mut mount, next_mount));
140        }
141        mounts_guard.defer_drop(std::mem::replace(&mut node.mount, Some(mount).into()));
142        Some(scopeguard::ScopeGuard::into_inner(node))
143    }
144
145    pub fn pivot_root(
146        self: &Arc<Namespace>,
147        current_root: &NamespaceNode,
148        new_root: &NamespaceNode,
149        put_old: &NamespaceNode,
150    ) -> Result<(), Errno> {
151        debug_assert!(new_root.entry.node.is_dir());
152        debug_assert!(put_old.entry.node.is_dir());
153
154        let new_root_mount = new_root.mount.as_ref().ok_or_else(|| errno!(EINVAL))?;
155        let current_root_mount = current_root.mount.as_ref().ok_or_else(|| errno!(EINVAL))?;
156        let put_old_mount = put_old.mount.as_ref().ok_or_else(|| errno!(EINVAL))?;
157
158        if Arc::ptr_eq(new_root_mount, current_root_mount)
159            || Arc::ptr_eq(put_old_mount, current_root_mount)
160        {
161            return error!(EBUSY);
162        }
163
164        let current_root_mount = current_root.mount_if_root()?;
165        let new_root_mount = new_root.mount_if_root()?;
166
167        if !new_root.is_descendant_of(current_root) {
168            return error!(EINVAL);
169        }
170        if !put_old.is_descendant_of(new_root) {
171            return error!(EINVAL);
172        }
173
174        let kernel = self.kernel();
175        let mounts_guard = kernel.mounts_lock();
176
177        // Prevent a detached mount from being modified via chroot or lingering file descriptors.
178        // (`current_root_mount` and `new_root_mount` are checked via `mountpoint()` below.)
179        if put_old_mount.is_detached(&mounts_guard) {
180            return error!(EINVAL);
181        }
182
183        let current_root_mountpoint =
184            mounts_guard.defer_drop(current_root_mount.mountpoint().ok_or_else(|| errno!(EINVAL))?);
185        let new_root_mountpoint =
186            mounts_guard.defer_drop(new_root_mount.mountpoint().ok_or_else(|| errno!(EINVAL))?);
187
188        // Retain mounts and mountpoint entries so that any drops triggered by
189        // unlinking or reparenting under `mounts_guard` are deferred until after
190        // the spinlock is released, preventing blocking operations while holding
191        // the lock.
192        let new_root_parent = mounts_guard.retain(
193            new_root_mountpoint.mount.as_ref().expect("a mountpoint must be part of a mount"),
194        );
195        mounts_guard.retain(&new_root_mountpoint.entry);
196
197        if new_root_mount.peer_group().is_some() || new_root_parent.peer_group().is_some() {
198            return error!(EINVAL);
199        }
200
201        if put_old_mount.peer_group().is_some() {
202            return error!(EINVAL);
203        }
204
205        if current_root_mount.peer_group().is_some() {
206            return error!(EINVAL);
207        }
208
209        let current_root_parent = mounts_guard.retain(
210            current_root_mountpoint.mount.as_ref().expect("a mountpoint must be part of a mount"),
211        );
212        mounts_guard.retain(&current_root_mountpoint.entry);
213        if current_root_parent.peer_group().is_some() {
214            return error!(EINVAL);
215        }
216
217        // Retain the remaining mounts and entries involved in the pivot before
218        // detaching and attaching them below.
219        mounts_guard.retain(current_root_mount);
220        mounts_guard.retain(new_root_mount);
221        mounts_guard.retain(put_old_mount);
222        mounts_guard.retain(&put_old.entry);
223
224        // 1. Detach new_root_mount from its parent.
225        new_root_parent
226            .remove_submount_internal(&mounts_guard, &new_root_mountpoint.mount_hash_key())?;
227
228        // 2. Place new_root_mount where current_root_mount was.
229        current_root_parent
230            .remove_submount_internal(&mounts_guard, &current_root_mountpoint.mount_hash_key())?;
231        current_root_parent.create_submount(
232            &mounts_guard,
233            &current_root_mountpoint.entry,
234            WhatSubmount::Existing(Arc::clone(new_root_mount)),
235        )?;
236
237        // 3. Attach current_root_mount to put_old.
238        put_old_mount.create_submount(
239            &mounts_guard,
240            &put_old.entry,
241            WhatSubmount::Existing(Arc::clone(current_root_mount)),
242        )?;
243
244        Ok(())
245    }
246}
247
248impl FsNodeOps for Arc<Namespace> {
249    fs_node_impl_not_dir!();
250
251    fn create_file_ops(
252        &self,
253        _node: &FsNode,
254        _current_task: &CurrentTask,
255        _flags: OpenFlags,
256    ) -> Result<Box<dyn FileOps>, Errno> {
257        Ok(Box::new(MountNamespaceFile(self.clone())))
258    }
259}
260
261pub struct MountNamespaceFile(pub Arc<Namespace>);
262
263impl FileOps for MountNamespaceFile {
264    fileops_impl_nonseekable!();
265    fileops_impl_dataless!();
266    fileops_impl_noop_sync!();
267}
268
269/// An empty struct that we use to track the number of active clients for a mount.
270///
271/// Each active client takes a reference to this object. The unmount operation fails
272/// if there are any active clients of the mount.
273type MountClientMarker = Arc<()>;
274
275/// An instance of a filesystem mounted in a namespace.
276///
277/// At a mount, path traversal switches from one filesystem to another.
278/// The client sees a composed directory structure that glues together the
279/// directories from the underlying FsNodes from those filesystems.
280///
281/// The mounts in a namespace form a mount tree, with `mountpoint` pointing to the parent and
282/// `submounts` pointing to the children.
283pub struct Mount {
284    root: DirEntryHandle,
285    fs: FileSystemHandle,
286
287    /// Holds the flags specific to this mount of the underlying filesystem.
288    flags: AtomicMountpointFlags,
289
290    /// Lock used to serialize updates of `flags` to ensure consistency during remount operations.
291    flags_lock: LockDepMutex<(), NamespaceFlagsLock>,
292
293    /// A unique identifier for this mount reported in /proc/pid/mountinfo.
294    id: u64,
295
296    /// A count of the number of active clients.
297    active_client_counter: MountClientMarker,
298
299    /// The namespace node that this mount is mounted on. This is a tuple instead of a
300    /// NamespaceNode because the Mount pointer has to be weak because this is the pointer to the
301    /// parent mount, the parent has a pointer to the children too, and making both strong would be
302    /// a cycle.
303    /// Stores the relationships to other mounts (mountpoint and submounts).
304    /// Both require the `MountsWriteToken` to mutate.
305    relations: MountRelations,
306    // Mount used to contain a Weak<Namespace>. It no longer does because since the mount point
307    // hash was moved from Namespace to Mount, nothing actually uses it. Now that
308    // Namespace::clone_namespace() is implemented in terms of Mount::clone_mount_recursive, it
309    // won't be trivial to add it back. If you end up needing to find a Mount's Namespace, I
310    // recommend turning the mountpoint field into an enum of Mountpoint or Namespace, maybe called
311    // "parent", and then you can traverse up to the top of the tree.
312}
313
314type MountHandle = Arc<Mount>;
315
316/// Public representation of the mount options.
317#[derive(Clone, Debug)]
318pub struct MountInfo {
319    handle: Option<MountHandle>,
320}
321
322impl MountInfo {
323    /// `MountInfo` for a element that is not tied to a given mount. Mount flags will be considered
324    /// empty.
325    pub fn detached() -> Self {
326        None.into()
327    }
328
329    /// The mount flags of the represented mount.
330    pub fn flags(&self) -> MountFlags {
331        if let Some(handle) = &self.handle {
332            handle.flags()
333        } else {
334            // Consider not mounted node have the NOATIME flags.
335            MountFlags::NOATIME
336        }
337    }
338
339    /// Checks whether this `MountInfo` represents a writable file system mount.
340    pub fn check_readonly_filesystem(&self) -> Result<(), Errno> {
341        if self.flags().contains(MountFlags::RDONLY) {
342            return error!(EROFS);
343        }
344        Ok(())
345    }
346
347    /// Checks whether this `MountInfo` represents an executable file system mount.
348    pub fn check_noexec_filesystem(&self) -> Result<(), Errno> {
349        if self.flags().contains(MountFlags::NOEXEC) {
350            return error!(EACCES);
351        }
352        Ok(())
353    }
354}
355
356impl Deref for MountInfo {
357    type Target = Option<MountHandle>;
358
359    fn deref(&self) -> &Self::Target {
360        &self.handle
361    }
362}
363
364impl DerefMut for MountInfo {
365    fn deref_mut(&mut self) -> &mut Self::Target {
366        &mut self.handle
367    }
368}
369
370impl std::cmp::PartialEq for MountInfo {
371    fn eq(&self, other: &Self) -> bool {
372        self.handle.as_ref().map(Arc::as_ptr) == other.handle.as_ref().map(Arc::as_ptr)
373    }
374}
375
376impl std::cmp::Eq for MountInfo {}
377
378impl Into<MountInfo> for Option<MountHandle> {
379    fn into(self) -> MountInfo {
380        MountInfo { handle: self }
381    }
382}
383
384/// Attachment state of a [`Mount`] within a [`Namespace`]'s mount tree.
385#[derive(Clone, Debug, Default, RcuDroppable)]
386enum MountpointState {
387    /// Root [`Mount`] of a [`Namespace`], or a newly constructed [`Mount`] prior to attachment.
388    #[default]
389    Root,
390    /// Submount attached to a `parent` [`Mount`] at a mountpoint `entry`.
391    Attached { parent: Weak<Mount>, entry: Weak<DirEntry> },
392    /// Submount that has been unmounted and disconnected from the mount table.
393    Detached,
394}
395
396#[derive(Default)]
397struct MountRelations {
398    /// Attachment state of this [`Mount`] relative to its parent [`Mount`] in the [`Namespace`].
399    mountpoint: RcuBox<MountpointState>,
400    /// The active submounts, keyed by the directory entry in this mount where they are mounted.
401    submounts: LockDepMutex<HashMap<PtrKey<DirEntry>, Submount>, MountSubmountsLock>,
402    /// A lock-free RCU friendly view of [submounts].
403    submount_lookup: RcuRawHashMap<WeakKey<DirEntry>, Weak<Mount>>,
404    /// The membership of this mount in its peer group.
405    peer_group: RcuArc<PeerGroup>,
406    /// The membership of this mount in a PeerGroup's downstream.
407    upstream: RcuBox<Option<(Weak<PeerGroup>, PtrKey<Mount>)>>,
408}
409
410impl MountRelations {
411    fn get_submount(
412        &self,
413        scope: &starnix_rcu::RcuReadScope,
414        key: &PtrKey<DirEntry>,
415    ) -> Option<MountHandle> {
416        self.submount_lookup.get(scope, key).and_then(|weak| weak.upgrade())
417    }
418
419    fn insert_submount(
420        &self,
421        _guard: &MountsWriteToken,
422        key: WeakKey<DirEntry>,
423        value: Weak<Mount>,
424        submount: Submount,
425    ) -> Option<Submount> {
426        let ptr_key = PtrKey::from(key.0.as_ptr());
427        let old_submount = self.submounts.lock().insert(ptr_key, submount);
428        let scope = starnix_rcu::RcuReadScope::new();
429        // SAFETY: The MountsWriteToken proves we have exclusive write access.
430        unsafe { self.submount_lookup.insert(&scope, key, value) };
431        old_submount
432    }
433
434    fn remove_submount(
435        &self,
436        guard: &MountsWriteToken,
437        key: &PtrKey<DirEntry>,
438    ) -> Result<Submount, Errno> {
439        // SAFETY: The MountsWriteToken proves we have exclusive write access.
440        let _ = unsafe { self.submount_lookup.remove(key) };
441        let submount = self.submounts.lock().remove(key).ok_or_else(|| errno!(EINVAL))?;
442        submount.mount.relations.detach_mountpoint(guard);
443        Ok(submount)
444    }
445
446    /// Recursively disconnects all submounts of this [`Mount`] from each other and from the mount
447    /// table.
448    ///
449    /// Per `umount2(2)`, `MNT_DETACH` must "immediately disconnect the filesystem and all
450    /// filesystems mounted below it from each other and from the mount table".
451    fn detach_submounts_recursive(&self, guard: &MountsWriteToken) {
452        let submounts: Vec<_> =
453            self.submounts.lock().drain().map(|(_, submount)| submount).collect();
454        if submounts.is_empty() {
455            return;
456        }
457        for submount in &submounts {
458            let key = PtrKey::from(&submount.dir);
459            // SAFETY: The MountsWriteToken proves we have exclusive write access.
460            let _ = unsafe { self.submount_lookup.remove(&key) };
461            submount.mount.relations.detach_mountpoint(guard);
462            submount.mount.make_private(guard);
463            submount.mount.relations.detach_submounts_recursive(guard);
464        }
465        guard.defer_drop(submounts);
466    }
467
468    fn iter_submounts<'a>(
469        &'a self,
470        scope: &'a starnix_rcu::RcuReadScope,
471    ) -> impl Iterator<Item = (&'a WeakKey<DirEntry>, &'a Weak<Mount>)> {
472        let mut cursor = self.submount_lookup.cursor(scope);
473        std::iter::from_fn(move || {
474            let current = cursor.current();
475            if current.is_some() {
476                cursor.advance();
477            }
478            current
479        })
480    }
481
482    fn submounts_len(&self) -> usize {
483        self.submount_lookup.len()
484    }
485
486    fn set_mountpoint(
487        &self,
488        _guard: &MountsWriteToken,
489        parent: Weak<Mount>,
490        entry: Weak<DirEntry>,
491    ) {
492        self.mountpoint.update(MountpointState::Attached { parent, entry });
493    }
494
495    fn detach_mountpoint(&self, _guard: &MountsWriteToken) {
496        self.mountpoint.update(MountpointState::Detached);
497    }
498
499    fn mountpoint<'a>(&'a self, scope: &'a starnix_rcu::RcuReadScope) -> &'a MountpointState {
500        self.mountpoint.as_ref(scope)
501    }
502
503    fn take_peer_group(&self, _guard: &MountsWriteToken) -> Option<Arc<PeerGroup>> {
504        let peer_group = self.peer_group.upgrade();
505        self.peer_group.update(None);
506        peer_group
507    }
508
509    fn take_upstream(&self, _guard: &MountsWriteToken) -> Option<(Weak<PeerGroup>, PtrKey<Mount>)> {
510        let upstream = self.upstream.cloned();
511        self.upstream.update(None);
512        upstream
513    }
514}
515
516/// A group of mounts. Setting MS_SHARED on a mount puts it in its own peer group. Any bind mounts
517/// of a mount in the group are also added to the group. A mount created in any mount in a peer
518/// group will be automatically propagated (recreated) in every other mount in the group.
519#[derive(Default)]
520struct PeerGroup {
521    id: u64,
522    mounts: RcuRawHashMap<WeakKey<Mount>, ()>,
523    downstream: RcuRawHashMap<WeakKey<Mount>, ()>,
524}
525
526pub enum WhatToMount {
527    Fs(FileSystemHandle),
528    Bind(NamespaceNode),
529}
530
531enum WhatSubmount {
532    New(WhatToMount, MountpointFlags),
533    Existing(MountHandle),
534}
535
536impl Mount {
537    pub fn new(
538        mounts_guard: &MountsWriteToken,
539        what: WhatToMount,
540        mut flags: MountpointFlags,
541    ) -> Result<MountHandle, Errno> {
542        let what = mounts_guard.defer_drop(what);
543        match &*what {
544            WhatToMount::Fs(fs) => {
545                // If `flags` does not explicitly specify an access-time flag then default to `RELATIME`.
546                flags.default_atime_from(MountpointFlags::RELATIME);
547                Ok(Self::new_with_root(fs.root().clone(), flags))
548            }
549            WhatToMount::Bind(node) => {
550                // A target node may not have a mount point if it's an anonymous node. Modern Linux (6.15+)
551                // returns ENOENT in this case, rather than the more intuitive EINVAL.
552                let mount = node.mount.as_ref().ok_or_else(|| errno!(ENOENT))?;
553                // Prevent a detached mount from being cloned via lingering file descriptors.
554                if mount.is_detached(mounts_guard) {
555                    return error!(EINVAL);
556                }
557                Ok(mount.clone_mount(mounts_guard, &node.entry, flags.into()))
558            }
559        }
560    }
561
562    fn new_with_root(root: DirEntryHandle, flags: MountpointFlags) -> MountHandle {
563        let fs = root.node.fs();
564        let kernel = fs.kernel.upgrade().expect("can't create mount without kernel");
565        Arc::new(Self {
566            id: kernel.get_next_mount_id(),
567            flags: (flags & MountpointFlags::STORED_ON_MOUNT).into(),
568            flags_lock: Default::default(),
569            root,
570            active_client_counter: Default::default(),
571            fs,
572            relations: Default::default(),
573        })
574    }
575
576    /// A namespace node referring to the root of the mount.
577    pub fn root(self: &MountHandle) -> NamespaceNode {
578        NamespaceNode::new(Arc::clone(self), Arc::clone(&self.root))
579    }
580
581    fn kernel(&self) -> Arc<Kernel> {
582        self.fs.kernel.upgrade().expect("No Kernel")
583    }
584
585    /// Create the specified mount as a child. Also propagate it to the mount's peer group.
586    fn create_submount(
587        self: &MountHandle,
588        mounts_guard: &MountsWriteToken,
589        dir: &DirEntryHandle,
590        what: WhatSubmount,
591    ) -> Result<(), Errno> {
592        // Necessary to make a copy to prevent excess replication, see the comment on the
593        // following Mount::new call.
594        let peers = self.peer_group().map(|g| g.copy_propagation_targets()).unwrap_or_default();
595        let peers = mounts_guard.defer_drop(peers);
596
597        // Create the mount after copying the peer list, because in the case of creating a bind
598        // mount inside itself, the new mount would get added to our peer group during the
599        // Mount::new call, but we don't want to replicate into it already. For an example see
600        // MountTest.QuizBRecursion.
601        let mount = match what {
602            WhatSubmount::Existing(mount) => mount,
603            WhatSubmount::New(what, flags) => Mount::new(mounts_guard, what, flags)?,
604        };
605
606        if self.is_shared() {
607            mount.make_shared(mounts_guard);
608        }
609
610        for peer in &*peers {
611            if Arc::ptr_eq(self, peer) {
612                continue;
613            }
614            let clone = mount.clone_mount_recursive(mounts_guard);
615            peer.add_submount_internal(mounts_guard, dir, clone);
616        }
617
618        self.add_submount_internal(mounts_guard, dir, mount);
619        Ok(())
620    }
621
622    fn remove_submount(
623        self: &MountHandle,
624        mounts_guard: &MountsWriteToken,
625        mount_hash_key: &PtrKey<DirEntry>,
626    ) -> Result<(), Errno> {
627        // create_submount explains why we need to make a copy of peers.
628        let peers = self.peer_group().map(|g| g.copy_propagation_targets()).unwrap_or_default();
629        let peers = mounts_guard.defer_drop(peers);
630
631        for peer in &*peers {
632            if Arc::ptr_eq(self, peer) {
633                continue;
634            }
635            // mount_namespaces(7): If B is shared, then all most-recently-mounted mounts at b on
636            // mounts that receive propagation from mount B and do not have submounts under them are
637            // unmounted.
638            let submount = {
639                let scope = RcuReadScope::new();
640                peer.relations.get_submount(&scope, mount_hash_key)
641            };
642            if let Some(submount) = submount {
643                let submount = mounts_guard.defer_drop(submount);
644                if submount.relations.submounts_len() != 0 {
645                    continue;
646                }
647                submount.make_private(mounts_guard);
648            }
649            let _ = peer.remove_submount_internal(mounts_guard, mount_hash_key);
650        }
651
652        let submount = self.relations.remove_submount(mounts_guard, mount_hash_key)?;
653        submount.mount.make_private(mounts_guard);
654        submount.mount.relations.detach_submounts_recursive(mounts_guard);
655        mounts_guard.defer_drop(submount);
656        Ok(())
657    }
658
659    pub fn move_mount(
660        source_mount: &MountHandle,
661        target_mount: &MountHandle,
662        target_dir: &DirEntryHandle,
663    ) -> Result<(), Errno> {
664        let kernel = target_mount.kernel();
665        let mounts_guard = kernel.mounts_lock();
666        // Prevent a detached mount from being modified via any lingering file descriptors to it.
667        if source_mount.is_detached(&mounts_guard) || target_mount.is_detached(&mounts_guard) {
668            return error!(EINVAL);
669        }
670
671        let source_mountpoint = source_mount.mountpoint().ok_or_else(|| errno!(EIO))?;
672        let source_mountpoint = mounts_guard.defer_drop(source_mountpoint);
673        let source_parent = mounts_guard.retain(
674            source_mountpoint.mount.as_ref().expect("a mountpoint must be part of a mount"),
675        );
676
677        // First, disconnect the mount from its parent.
678        {
679            if source_parent.peer_group().is_some() {
680                // Sayeth mount(2):
681                // EINVAL A move operation (MS_MOVE) was attempted, but the parent mount of source
682                //        mount has propagation type MS_SHARED.
683                return error!(EINVAL);
684            }
685            source_parent
686                .remove_submount_internal(&mounts_guard, &source_mountpoint.mount_hash_key())?;
687        }
688
689        target_mount.create_submount(
690            &mounts_guard,
691            target_dir,
692            WhatSubmount::Existing(Arc::clone(source_mount)),
693        )?;
694        Ok(())
695    }
696
697    /// Create a new mount with the same filesystem, flags, and peer group. Used to implement bind
698    /// mounts.
699    fn clone_mount(
700        self: &MountHandle,
701        mounts_guard: &MountsWriteToken,
702        new_root: &DirEntryHandle,
703        flags: MountFlags,
704    ) -> MountHandle {
705        assert!(new_root.is_descendant_of(&self.root));
706        // According to mount(2) on bind mounts, all flags other than MS_REC are ignored when doing
707        // a bind mount.
708        let clone = Self::new_with_root(Arc::clone(new_root), self.mount_flags());
709
710        if flags.contains(MountFlags::REC) {
711            let submounts: Vec<_> = {
712                let scope = RcuReadScope::new();
713                self.relations
714                    .iter_submounts(&scope)
715                    .filter_map(|(dir, submount)| {
716                        let dir = dir.0.upgrade()?;
717                        if !dir.is_descendant_of(new_root) {
718                            return None;
719                        }
720                        Some((dir, submount.upgrade()?))
721                    })
722                    .collect()
723            };
724            if !submounts.is_empty() {
725                let submounts = mounts_guard.defer_drop(submounts);
726                for (dir, submount) in &*submounts {
727                    let submount = submount.clone_mount_recursive(mounts_guard);
728                    clone.add_submount_internal_unchecked(mounts_guard, dir, submount);
729                }
730            }
731        }
732
733        // Put the clone in the same peer group
734        let peer_group = self.peer_group();
735        if let Some(peer_group) = peer_group {
736            let peer_group = mounts_guard.defer_drop(peer_group);
737            clone.set_peer_group(mounts_guard, Arc::clone(&peer_group));
738        }
739
740        clone
741    }
742
743    /// Do a clone of the full mount hierarchy below this mount. Used for creating mount
744    /// namespaces and creating copies to use for propagation.
745    fn clone_mount_recursive(self: &MountHandle, mounts_guard: &MountsWriteToken) -> MountHandle {
746        self.clone_mount(mounts_guard, &self.root, MountFlags::REC)
747    }
748
749    pub fn change_propagation(
750        self: &MountHandle,
751        mounts_guard: &MountsWriteToken,
752        flag: MountFlags,
753        recursive: bool,
754    ) {
755        match flag {
756            MountFlags::SHARED => self.make_shared(mounts_guard),
757            MountFlags::PRIVATE => self.make_private(mounts_guard),
758            MountFlags::DOWNSTREAM => self.make_downstream(mounts_guard),
759            _ => {
760                log_warn!("mount propagation {:?}", flag);
761            }
762        }
763
764        if recursive {
765            let submounts: Vec<_> = {
766                let scope = starnix_rcu::RcuReadScope::new();
767                self.relations
768                    .iter_submounts(&scope)
769                    .filter_map(|(_, submount)| submount.upgrade())
770                    .collect()
771            };
772            let submounts = mounts_guard.defer_drop(submounts);
773            for submount in &*submounts {
774                submount.change_propagation(mounts_guard, flag, recursive);
775            }
776        }
777    }
778
779    /// Returns the effective flags for the `Mount`, calculated as the union of the mount flags
780    /// associated with the `FileSystem`, and with the `Mount` itself.
781    fn flags(&self) -> MountFlags {
782        MountFlags::from(self.mount_flags()) | self.fs_flags().into()
783    }
784
785    /// Returns the mount flags stored unique to this `Mount`.
786    fn mount_flags(&self) -> MountpointFlags {
787        self.flags.load(Ordering::Relaxed)
788    }
789
790    /// Returns the mount flags for the `FileSystem` of this `Mount`.
791    fn fs_flags(&self) -> FileSystemFlags {
792        self.fs.options.flags.load(Ordering::Relaxed)
793    }
794
795    /// Updates the `Mount` with the per-mount flags specified in `flags`, while preserving the
796    /// existing access-time flag if no access-time flag is set in `flags`.
797    pub fn update_flags(self: &MountHandle, mut flags: MountpointFlags) {
798        let _lock = self.flags_lock.lock();
799        // Since Linux 3.17, if none of MS_NOATIME, MS_NODIRATIME,
800        // MS_RELATIME, or MS_STRICTATIME is specified in mountflags, then
801        // the remount operation preserves the existing values of these
802        // flags (rather than defaulting to MS_RELATIME).
803        flags.default_atime_from(self.flags.load(Ordering::Relaxed));
804        flags &= MountpointFlags::STORED_ON_MOUNT;
805        self.flags.store(flags, Ordering::Relaxed);
806    }
807
808    /// The number of active clients of this mount.
809    ///
810    /// The mount cannot be unmounted if there are any active clients.
811    fn active_clients(&self) -> usize {
812        // We need to subtract one for our own reference. We are not a real client.
813        Arc::strong_count(&self.active_client_counter) - 1
814    }
815
816    pub fn unmount(
817        &self,
818        mounts_guard: &MountsWriteToken,
819        flags: UnmountFlags,
820    ) -> Result<(), Errno> {
821        // Prevent a detached mount from being unmounted again via lingering file descriptors
822        // (returning `EINVAL` rather than `EBUSY` even when open files keep it active).
823        if self.is_detached(mounts_guard) {
824            return error!(EINVAL);
825        }
826        if !flags.contains(UnmountFlags::DETACH) {
827            if self.active_clients() > 0 || self.relations.submounts_len() != 0 {
828                return error!(EBUSY);
829            }
830        }
831
832        let mountpoint = self.mountpoint().ok_or_else(|| errno!(EINVAL))?;
833        let mountpoint = mounts_guard.defer_drop(mountpoint);
834        let parent_mount = mountpoint.mount.as_ref().expect("a mountpoint must be part of a mount");
835        parent_mount.remove_submount(mounts_guard, &mountpoint.mount_hash_key())
836    }
837
838    /// Returns the security state of the fs.
839    pub fn security_state(&self) -> &security::FileSystemState {
840        &self.fs.security_state
841    }
842
843    /// Returns the name of the fs.
844    pub fn fs_name(&self) -> &'static FsStr {
845        self.fs.name()
846    }
847
848    /// Reconfigures the flags and mount parameters for the `FileSystem` backing this mount point.
849    pub fn reconfigure_fs(
850        &self,
851        current_task: &CurrentTask,
852        flags: FileSystemFlags,
853        params: &MountParams,
854    ) -> Result<(), Errno> {
855        self.fs.reconfigure(current_task, flags, params)
856    }
857
858    /// Returns true if there is a submount on top of `dir_entry`.
859    pub fn has_submount(&self, dir_entry: &DirEntryHandle) -> bool {
860        let scope = RcuReadScope::new();
861        self.relations.get_submount(&scope, &PtrKey::from(dir_entry)).is_some()
862    }
863
864    /// Whether this [`Mount`] has been unmounted from the mount table.
865    pub(super) fn is_detached(&self, _mounts_guard: &MountsWriteToken) -> bool {
866        // Distinguishes an unmounted submount (`MountpointState::Detached`) from a `Namespace`'s
867        // `root_mount` (`MountpointState::Root`). Because
868        // `MountRelations::detach_submounts_recursive` transitions all submounts beneath a lazily
869        // unmounted (`MNT_DETACH`) mount to `MountpointState::Detached`, checking this `Mount`'s
870        // own `MountpointState` is sufficient.
871        let scope = RcuReadScope::new();
872        matches!(self.relations.mountpoint(&scope), MountpointState::Detached)
873    }
874
875    /// [`NamespaceNode`] on which this [`Mount`] is mounted.
876    pub fn mountpoint(&self) -> Option<NamespaceNode> {
877        let scope = RcuReadScope::new();
878        match self.relations.mountpoint(&scope) {
879            MountpointState::Attached { parent, entry } => {
880                Some(NamespaceNode::new(parent.upgrade()?, entry.upgrade()?))
881            }
882            MountpointState::Root | MountpointState::Detached => None,
883        }
884    }
885
886    /// Add a child mount *without propagating it to the peer group*. For internal use only.
887    pub fn add_submount_internal(
888        self: &MountHandle,
889        guard: &MountsWriteToken,
890        dir: &DirEntryHandle,
891        mount: MountHandle,
892    ) {
893        if !dir.is_descendant_of(&self.root) {
894            guard.defer_drop(mount);
895            return;
896        }
897        self.add_submount_internal_unchecked(guard, dir, mount);
898    }
899
900    /// Caller must ensure `dir.is_descendant_of(&self.root)` holds.
901    fn add_submount_internal_unchecked(
902        self: &MountHandle,
903        guard: &MountsWriteToken,
904        dir: &DirEntryHandle,
905        mount: MountHandle,
906    ) {
907        debug_assert!(dir.is_descendant_of(&self.root));
908        let mount = guard.defer_drop(mount);
909
910        let submount = mount.kernel().mounts.register_mount(dir, Arc::clone(&mount));
911
912        // Accepts both newly constructed mounts (`MountpointState::Root`) and mounts transiently
913        // disconnected from their previous parent during `move_mount` or `pivot_root`
914        // (`MountpointState::Detached`).
915        assert!(
916            !matches!(
917                mount.relations.mountpoint(&RcuReadScope::new()),
918                MountpointState::Attached { .. }
919            ),
920            "add_submount can only take an unattached mount"
921        );
922        mount.relations.set_mountpoint(guard, Arc::downgrade(self), Arc::downgrade(dir));
923
924        let old_mount = self.relations.insert_submount(
925            guard,
926            WeakKey::from(dir),
927            Arc::downgrade(&mount),
928            submount,
929        );
930        if let Some(old_mount) = old_mount {
931            let old_mount = guard.defer_drop(old_mount);
932            old_mount.mount.relations.set_mountpoint(
933                guard,
934                Arc::downgrade(&mount),
935                Arc::downgrade(&mount.root),
936            );
937            let new_old_submount =
938                mount.kernel().mounts.register_mount(&mount.root, old_mount.mount.clone());
939            let replaced = mount.relations.insert_submount(
940                guard,
941                WeakKey::from(&mount.root),
942                Arc::downgrade(&old_mount.mount),
943                new_old_submount,
944            );
945            if let Some(replaced) = replaced {
946                guard.defer_drop(replaced);
947            }
948        }
949    }
950
951    pub fn remove_submount_internal(
952        self: &MountHandle,
953        guard: &MountsWriteToken,
954        mount_hash_key: &PtrKey<DirEntry>,
955    ) -> Result<(), Errno> {
956        let submount = self.relations.remove_submount(guard, mount_hash_key)?;
957        guard.defer_drop(submount);
958        Ok(())
959    }
960
961    /// Return this mount's current peer group.
962    fn peer_group(&self) -> Option<Arc<PeerGroup>> {
963        self.relations.peer_group.upgrade()
964    }
965
966    /// Handles unregistering from both peer group and upstream simultaneously.
967    /// This resolves forwarding the upstream to the next mount in the peer group if necessary.
968    fn unregister_from_peer_group_and_upstream(
969        guard: &MountsWriteToken,
970        peer_group: Option<Arc<PeerGroup>>,
971        upstream: Option<(Weak<PeerGroup>, PtrKey<Mount>)>,
972        mount_ptr: PtrKey<Mount>,
973    ) {
974        let peer_group = guard.defer_drop(peer_group);
975        let upstream_group = match upstream {
976            Some((weak_group, mount)) => {
977                if let Some(group) = weak_group.upgrade() {
978                    group.remove_downstream(guard, mount);
979                    Some(group)
980                } else {
981                    None
982                }
983            }
984            None => None,
985        };
986        let upstream_group = guard.defer_drop(upstream_group);
987
988        if let Some(group) = &*peer_group {
989            group.remove(guard, mount_ptr);
990
991            if let Some(upstream_group) = &*upstream_group {
992                let next_mount = {
993                    let scope = RcuReadScope::new();
994                    group.mounts.keys(&scope).next().and_then(|w| w.0.upgrade())
995                };
996                if let Some(next_mount) = next_mount {
997                    let next_mount = guard.defer_drop(next_mount);
998                    next_mount.set_upstream(guard, upstream_group);
999                }
1000            }
1001        }
1002    }
1003
1004    /// Remove this mount from its peer group.
1005    fn take_from_peer_group(&self, guard: &MountsWriteToken) -> Option<Arc<PeerGroup>> {
1006        let peer_group = self.relations.take_peer_group(guard);
1007        if peer_group.is_none() {
1008            return None;
1009        }
1010        let upstream = self.relations.take_upstream(guard);
1011        let return_group = peer_group.clone();
1012        Mount::unregister_from_peer_group_and_upstream(
1013            guard,
1014            peer_group,
1015            upstream,
1016            PtrKey::from(self),
1017        );
1018        return_group
1019    }
1020
1021    fn upstream(&self) -> Option<Arc<PeerGroup>> {
1022        let scope = RcuReadScope::new();
1023        let (group, _) = self.relations.upstream.as_ref(&scope).as_ref()?;
1024        group.upgrade()
1025    }
1026
1027    fn remove_from_upstream(&self, guard: &MountsWriteToken) {
1028        let upstream = self.relations.take_upstream(guard);
1029        if let Some((weak_group, mount)) = upstream {
1030            if let Some(group) = weak_group.upgrade() {
1031                group.remove_downstream(guard, mount);
1032                guard.defer_drop(group);
1033            }
1034        }
1035    }
1036
1037    /// Set this mount's peer group.
1038    fn set_peer_group(self: &Arc<Mount>, guard: &MountsWriteToken, group: Arc<PeerGroup>) {
1039        if let Some(prev) = self.take_from_peer_group(guard) {
1040            guard.defer_drop(prev);
1041        }
1042        group.add(guard, self);
1043        self.relations.peer_group.update(Some(group));
1044    }
1045
1046    fn set_upstream(self: &Arc<Mount>, guard: &MountsWriteToken, group: &Arc<PeerGroup>) {
1047        self.remove_from_upstream(guard);
1048        group.add_downstream(guard, self);
1049        self.relations.upstream.update(Some((Arc::downgrade(group), Arc::as_ptr(self).into())));
1050    }
1051
1052    /// Is the mount in a peer group? Corresponds to MS_SHARED.
1053    pub fn is_shared(&self) -> bool {
1054        self.relations.peer_group.is_some()
1055    }
1056
1057    /// Put the mount in a peer group. Implements MS_SHARED.
1058    fn make_shared(self: &Arc<Mount>, guard: &MountsWriteToken) {
1059        if self.is_shared() {
1060            return;
1061        }
1062        let kernel = self.kernel();
1063        self.set_peer_group(guard, PeerGroup::new(kernel.get_next_peer_group_id()))
1064    }
1065
1066    /// Take the mount out of its peer group, also remove upstream if any. Implements MS_PRIVATE.
1067    fn make_private(&self, guard: &MountsWriteToken) {
1068        let peer_group = self.relations.take_peer_group(guard);
1069        let upstream = self.relations.take_upstream(guard);
1070        Mount::unregister_from_peer_group_and_upstream(
1071            guard,
1072            peer_group,
1073            upstream,
1074            PtrKey::from(self),
1075        );
1076    }
1077
1078    /// Take the mount out of its peer group and make it downstream instead. Implements
1079    /// MountFlags::DOWNSTREAM (MS_SLAVE).
1080    fn make_downstream(self: &Arc<Mount>, guard: &MountsWriteToken) {
1081        if let Some(peer_group) = self.take_from_peer_group(guard) {
1082            let peer_group = guard.defer_drop(peer_group);
1083            self.set_upstream(guard, &peer_group);
1084        }
1085    }
1086}
1087
1088impl PeerGroup {
1089    fn new(id: u64) -> Arc<Self> {
1090        Arc::new(Self {
1091            id,
1092            mounts: RcuRawHashMap::default(),
1093            downstream: RcuRawHashMap::default(),
1094        })
1095    }
1096
1097    fn add(&self, _guard: &MountsWriteToken, mount: &Arc<Mount>) {
1098        // SAFETY: The MountsWriteToken proves we have exclusive write access.
1099        unsafe { self.mounts.insert(&starnix_rcu::RcuReadScope::new(), WeakKey::from(mount), ()) };
1100    }
1101
1102    fn remove(&self, _guard: &MountsWriteToken, mount: PtrKey<Mount>) {
1103        // SAFETY: The MountsWriteToken proves we have exclusive write access.
1104        unsafe { self.mounts.remove(&mount) };
1105    }
1106
1107    fn add_downstream(&self, _guard: &MountsWriteToken, mount: &Arc<Mount>) {
1108        // SAFETY: The MountsWriteToken proves we have exclusive write access.
1109        unsafe {
1110            self.downstream.insert(&starnix_rcu::RcuReadScope::new(), WeakKey::from(mount), ())
1111        };
1112    }
1113
1114    fn remove_downstream(&self, _guard: &MountsWriteToken, mount: PtrKey<Mount>) {
1115        // SAFETY: The MountsWriteToken proves we have exclusive write access.
1116        unsafe { self.downstream.remove(&mount) };
1117    }
1118
1119    fn copy_propagation_targets(&self) -> Vec<MountHandle> {
1120        let mut buf = vec![];
1121        self.collect_propagation_targets(&mut buf);
1122        buf
1123    }
1124
1125    fn collect_propagation_targets(&self, buf: &mut Vec<MountHandle>) {
1126        let downstream_mounts: Vec<_> = {
1127            let scope = RcuReadScope::new();
1128            buf.extend(self.mounts.keys(&scope).filter_map(|m| m.0.upgrade()));
1129            self.downstream.keys(&scope).filter_map(|m| m.0.upgrade()).collect()
1130        };
1131        for mount in downstream_mounts {
1132            let peer_group = mount.peer_group();
1133            match peer_group {
1134                Some(group) => group.collect_propagation_targets(buf),
1135                None => buf.push(mount),
1136            }
1137        }
1138    }
1139}
1140
1141impl Kernel {
1142    pub fn get_next_mount_id(&self) -> u64 {
1143        self.next_mount_id.next()
1144    }
1145
1146    pub fn get_next_peer_group_id(&self) -> u64 {
1147        self.next_peer_group_id.next()
1148    }
1149
1150    pub fn get_next_namespace_id(&self) -> u64 {
1151        self.next_namespace_id.next()
1152    }
1153}
1154
1155impl CurrentTask {
1156    pub fn create_filesystem(
1157        &self,
1158        fs_type: &FsStr,
1159        options: FileSystemOptions,
1160    ) -> Result<FileSystemHandle, Errno> {
1161        // Please register new file systems via //src/starnix/modules/lib.rs, even if the file
1162        // system is implemented inside starnix_core.
1163        //
1164        // Most file systems should be implemented as modules. The VFS provides various traits that
1165        // let starnix_core integrate file systems without needing to depend on the file systems
1166        // directly.
1167        self.kernel()
1168            .expando
1169            .get::<FsRegistry>()
1170            .create(self, fs_type, options)
1171            .ok_or_else(|| errno!(ENODEV, fs_type))?
1172    }
1173}
1174
1175struct ProcMountsFileSource {
1176    target: TaskContainer,
1177}
1178
1179impl DynamicFileSource for ProcMountsFileSource {
1180    fn generate(
1181        &self,
1182        _current_task: &CurrentTask,
1183        sink: &mut DynamicFileBuf,
1184    ) -> Result<(), Errno> {
1185        // TODO(tbodt): We should figure out a way to have a real iterator instead of grabbing the
1186        // entire list in one go. Should we have a BTreeMap<u64, Weak<Mount>> in the Namespace?
1187        // Also has the benefit of correct (i.e. chronological) ordering. But then we have to do
1188        // extra work to maintain it.
1189        let task = self.target.get_task()?;
1190        let task_fs = task.fs()?;
1191        let root = task_fs.root();
1192        let ns = task_fs.namespace();
1193        for_each_mount(&ns.root_mount, &mut |mount| {
1194            let mountpoint = mount.mountpoint().unwrap_or_else(|| mount.root());
1195            if !mountpoint.is_descendant_of(&root) {
1196                return Ok(());
1197            }
1198            write!(
1199                sink,
1200                "{} {} {} {}{}",
1201                mount.fs.options.source_for_display(),
1202                mountpoint.path(&task_fs),
1203                mount.fs.name(),
1204                // Report the union of the FileSystem and Mount flags, as well as any FileSystem-
1205                // or LSM-specific options.
1206                mount.flags(),
1207                mount.fs.format_options(&task.kernel())?,
1208            )?;
1209            writeln!(sink, " 0 0")?;
1210            Ok(())
1211        })?;
1212        Ok(())
1213    }
1214}
1215
1216pub struct ProcMountsFile {
1217    dynamic_file: DynamicFile<ProcMountsFileSource>,
1218}
1219
1220impl ProcMountsFile {
1221    pub fn new_node(target: TaskContainer) -> impl FsNodeOps {
1222        SimpleFileNode::new(move |_| {
1223            Ok(Self {
1224                dynamic_file: DynamicFile::new(ProcMountsFileSource { target: target.clone() }),
1225            })
1226        })
1227    }
1228}
1229
1230impl FileOps for ProcMountsFile {
1231    fileops_impl_delegate_read_write_and_seek!(self, self.dynamic_file);
1232    fileops_impl_noop_sync!();
1233
1234    fn wait_async(
1235        &self,
1236        _file: &FileObject,
1237        _current_task: &CurrentTask,
1238        waiter: &Waiter,
1239        _events: FdEvents,
1240        _handler: EventHandler,
1241    ) -> Option<WaitCanceler> {
1242        // Polling this file gives notifications when any change to mounts occurs. This is not
1243        // implemented yet, but stubbed for Android init.
1244        Some(waiter.fake_wait())
1245    }
1246
1247    fn query_events(
1248        &self,
1249        _file: &FileObject,
1250        _current_task: &CurrentTask,
1251    ) -> Result<FdEvents, Errno> {
1252        Ok(FdEvents::empty())
1253    }
1254}
1255
1256#[derive(Clone)]
1257pub struct ProcMountinfoFile {
1258    target: TaskContainer,
1259}
1260impl ProcMountinfoFile {
1261    pub fn new_node(target: TaskContainer) -> impl FsNodeOps {
1262        DynamicFile::new_node(Self { target })
1263    }
1264}
1265impl DynamicFileSource for ProcMountinfoFile {
1266    fn generate(
1267        &self,
1268        _current_task: &CurrentTask,
1269        sink: &mut DynamicFileBuf,
1270    ) -> Result<(), Errno> {
1271        // Returns path to the `dir` from the root of the file system.
1272        fn path_from_fs_root(dir: &DirEntryHandle) -> FsString {
1273            let mut path = PathBuilder::new();
1274            if dir.is_dead() {
1275                // Return `/foo/dir//deleted` if the dir was deleted.
1276                path.prepend_element("/deleted".into());
1277            }
1278            let scope = RcuReadScope::new();
1279            let mut current = dir.clone();
1280            while let Some(parent) = current.parent() {
1281                path.prepend_element(current.local_name(&scope));
1282                current = parent;
1283            }
1284            path.build_absolute()
1285        }
1286
1287        // TODO(tbodt): We should figure out a way to have a real iterator instead of grabbing the
1288        // entire list in one go. Should we have a BTreeMap<u64, Weak<Mount>> in the Namespace?
1289        // Also has the benefit of correct (i.e. chronological) ordering. But then we have to do
1290        // extra work to maintain it.
1291        let task = self.target.get_task()?;
1292        let task_fs = task.fs()?;
1293        let root = task_fs.root();
1294        let ns = task_fs.namespace();
1295        for_each_mount(&ns.root_mount, &mut |mount| {
1296            let mountpoint = mount.mountpoint().unwrap_or_else(|| mount.root());
1297            if !mountpoint.is_descendant_of(&root) {
1298                return Ok(());
1299            }
1300            // Can't fail, mountpoint() and root() can't return a NamespaceNode with no mount
1301            let parent = mountpoint.mount.as_ref().unwrap();
1302            write!(
1303                sink,
1304                "{} {} {} {} {} {}",
1305                mount.id,
1306                parent.id,
1307                mount.root.node.fs().dev_id,
1308                path_from_fs_root(&mount.root),
1309                mountpoint.path(&task_fs),
1310                mount.mount_flags(),
1311            )?;
1312            if let Some(peer_group) = mount.peer_group() {
1313                write!(sink, " shared:{}", peer_group.id)?;
1314            }
1315            if let Some(upstream) = mount.upstream() {
1316                write!(sink, " master:{}", upstream.id)?;
1317            }
1318            writeln!(
1319                sink,
1320                " - {} {} {}{}",
1321                mount.fs.name(),
1322                mount.fs.options.source_for_display(),
1323                mount.fs_flags(),
1324                // Options (including LSM options) are associated with the FileSystem rather than
1325                // the Mount.
1326                mount.fs.format_options(&task.kernel())?,
1327            )?;
1328            Ok(())
1329        })?;
1330        Ok(())
1331    }
1332}
1333
1334fn for_each_mount<E>(
1335    mount: &MountHandle,
1336    callback: &mut impl FnMut(&MountHandle) -> Result<(), E>,
1337) -> Result<(), E> {
1338    callback(mount)?;
1339    for (_, s) in mount.relations.iter_submounts(&RcuReadScope::new()) {
1340        if let Some(submount) = s.upgrade() {
1341            for_each_mount(&submount, callback)?;
1342        }
1343    }
1344    Ok(())
1345}
1346
1347/// The `SymlinkMode` enum encodes how symlinks are followed during path traversal.
1348#[derive(Default, PartialEq, Eq, Copy, Clone, Debug)]
1349pub enum SymlinkMode {
1350    /// Follow a symlink at the end of a path resolution.
1351    #[default]
1352    Follow,
1353
1354    /// Do not follow a symlink at the end of a path resolution.
1355    NoFollow,
1356}
1357
1358/// The `DirectoryMode` enum encodes whether a lookup requires the target to be a directory.
1359#[derive(Default, PartialEq, Eq, Copy, Clone, Debug)]
1360pub enum DirectoryMode {
1361    /// The target of the path resolution can be any file type.
1362    #[default]
1363    AllowAny,
1364
1365    /// The target of the path resolution must be a directory.
1366    MustBeDirectory,
1367}
1368
1369/// The maximum number of symlink traversals that can be made during path resolution.
1370pub const MAX_SYMLINK_FOLLOWS: u8 = 40;
1371
1372/// The context passed during namespace lookups.
1373///
1374/// Namespace lookups need to mutate a shared context in order to correctly
1375/// count the number of remaining symlink traversals.
1376pub struct LookupContext {
1377    /// The SymlinkMode for the lookup.
1378    ///
1379    /// As the lookup proceeds, the follow count is decremented each time the
1380    /// lookup traverses a symlink.
1381    pub symlink_mode: SymlinkMode,
1382
1383    /// The number of symlinks remaining the follow.
1384    ///
1385    /// Each time path resolution calls readlink, this value is decremented.
1386    pub remaining_follows: u8,
1387
1388    /// Whether the result of the lookup must be a directory.
1389    ///
1390    /// For example, if the path ends with a `/` or if userspace passes
1391    /// O_DIRECTORY. This flag can be set if the lookup encounters a
1392    /// symlink that ends with a `/`.
1393    pub directory_mode: DirectoryMode,
1394
1395    /// Resolve flags passed to `openat2`. Empty if the lookup originated in any other syscall.
1396    pub resolve_flags: ResolveFlags,
1397
1398    /// Base directory for the lookup. Set only when either `RESOLVE_BENEATH` or `RESOLVE_IN_ROOT`
1399    /// is passed to `openat2`.
1400    pub resolve_base: ResolveBase,
1401}
1402
1403/// Used to specify base directory in `LookupContext` for lookups originating in the `openat2`
1404/// syscall with either `RESOLVE_BENEATH` or `RESOLVE_IN_ROOT` flag.
1405#[derive(Clone, Eq, PartialEq)]
1406pub enum ResolveBase {
1407    None,
1408
1409    /// The lookup is not allowed to traverse any node that's not beneath the specified node.
1410    Beneath(NamespaceNode),
1411
1412    /// The lookup should be handled as if the root specified node is the file-system root.
1413    InRoot(NamespaceNode),
1414}
1415
1416impl LookupContext {
1417    pub fn new(symlink_mode: SymlinkMode) -> LookupContext {
1418        LookupContext {
1419            symlink_mode,
1420            remaining_follows: MAX_SYMLINK_FOLLOWS,
1421            directory_mode: DirectoryMode::default(),
1422            resolve_flags: ResolveFlags::empty(),
1423            resolve_base: ResolveBase::None,
1424        }
1425    }
1426
1427    pub fn with(&self, symlink_mode: SymlinkMode, directory_mode: DirectoryMode) -> LookupContext {
1428        LookupContext {
1429            symlink_mode,
1430            directory_mode,
1431            resolve_base: self.resolve_base.clone(),
1432            ..*self
1433        }
1434    }
1435
1436    pub fn update_for_path(&mut self, path: &FsStr) {
1437        if path.last() == Some(&b'/') {
1438            // The last path element must resolve to a directory. This is because a trailing slash
1439            // was found in the path.
1440            self.directory_mode = DirectoryMode::MustBeDirectory;
1441            // If the last path element is a symlink, we should follow it.
1442            // See https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap03.html#tag_21_03_00_75
1443            self.symlink_mode = SymlinkMode::Follow;
1444        }
1445    }
1446}
1447
1448impl Default for LookupContext {
1449    fn default() -> Self {
1450        LookupContext::new(SymlinkMode::Follow)
1451    }
1452}
1453
1454/// Whether the path is reachable from the given root.
1455pub enum PathWithReachability {
1456    /// The path is reachable from the given root.
1457    Reachable(FsString),
1458
1459    /// The path is not reachable from the given root.
1460    Unreachable(FsString),
1461}
1462
1463impl PathWithReachability {
1464    pub fn into_path(self) -> FsString {
1465        match self {
1466            PathWithReachability::Reachable(path) => path,
1467            PathWithReachability::Unreachable(path) => path,
1468        }
1469    }
1470}
1471
1472/// A node in a mount namespace.
1473///
1474/// This tree is a composite of the mount tree and the FsNode tree.
1475///
1476/// These nodes are used when traversing paths in a namespace in order to
1477/// present the client the directory structure that includes the mounted
1478/// filesystems.
1479#[derive(Clone)]
1480pub struct NamespaceNode {
1481    /// The mount where this namespace node is mounted.
1482    ///
1483    /// A given FsNode can be mounted in multiple places in a namespace. This
1484    /// field distinguishes between them.
1485    pub mount: MountInfo,
1486
1487    /// The FsNode that corresponds to this namespace entry.
1488    pub entry: DirEntryHandle,
1489}
1490
1491impl NamespaceNode {
1492    pub fn new(mount: MountHandle, entry: DirEntryHandle) -> Self {
1493        Self { mount: Some(mount).into(), entry }
1494    }
1495
1496    /// Create a namespace node that is not mounted in a namespace.
1497    pub fn new_anonymous(entry: DirEntryHandle) -> Self {
1498        Self { mount: None.into(), entry }
1499    }
1500
1501    /// Create a namespace node that is not mounted in a namespace and that refers to a node that
1502    /// is not rooted in a hierarchy and has no name.
1503    pub fn new_anonymous_unrooted(current_task: &CurrentTask, node: FsNodeHandle) -> Self {
1504        let dir_entry = DirEntry::new_unrooted(node);
1505        let _ = security::fs_node_init_with_dentry_no_xattr(current_task, &dir_entry);
1506        Self::new_anonymous(dir_entry)
1507    }
1508
1509    /// Create a FileObject corresponding to this namespace node.
1510    ///
1511    /// This function is the primary way of instantiating FileObjects. Each
1512    /// FileObject records the NamespaceNode that created it in order to
1513    /// remember its path in the Namespace.
1514    pub fn open(
1515        &self,
1516        current_task: &CurrentTask,
1517        open_check: impl Into<OpenAccessCheck>,
1518    ) -> Result<FileHandle, Errno> {
1519        let open_check = open_check.into();
1520        let ops = self.entry.node.open(current_task, self, open_check)?;
1521        FileObject::new(current_task, ops, self.clone(), open_check.open_flags())
1522    }
1523
1524    /// Create or open a node in the file system.
1525    ///
1526    /// Works for any type of node other than a symlink.
1527    ///
1528    /// Returns the existing node if there is one, and whether the node was created. The existence
1529    /// check and the creation happen atomically with respect to other VFS operations on this
1530    /// directory.
1531    pub fn open_create_node(
1532        &self,
1533        current_task: &CurrentTask,
1534        name: &FsStr,
1535        mode: FileMode,
1536        dev: DeviceId,
1537    ) -> Result<(NamespaceNode, CreationStatus), Errno> {
1538        let owner = current_task.current_fscred();
1539        let mode = current_task.fs().apply_umask(mode);
1540        let (entry, status) = self.entry.get_or_create_entry(
1541            current_task,
1542            &self.mount,
1543            name,
1544            |dir, mount, name| dir.create_node(current_task, mount, name, mode, dev, owner),
1545        )?;
1546        Ok((self.with_new_entry(entry), status))
1547    }
1548
1549    pub fn into_active(self) -> ActiveNamespaceNode {
1550        ActiveNamespaceNode::new(self)
1551    }
1552
1553    /// Create a node in the file system.
1554    ///
1555    /// Works for any type of node other than a symlink.
1556    ///
1557    /// Does not return an existing node.
1558    pub fn create_node(
1559        &self,
1560        current_task: &CurrentTask,
1561        name: &FsStr,
1562        mode: FileMode,
1563        dev: DeviceId,
1564    ) -> Result<NamespaceNode, Errno> {
1565        let owner = current_task.current_fscred();
1566        let mode = current_task.fs().apply_umask(mode);
1567        let entry =
1568            self.entry.create_entry(current_task, &self.mount, name, |dir, mount, name| {
1569                dir.create_node(current_task, mount, name, mode, dev, owner)
1570            })?;
1571        Ok(self.with_new_entry(entry))
1572    }
1573
1574    /// Create a symlink in the file system.
1575    ///
1576    /// To create another type of node, use `create_node`.
1577    pub fn create_symlink(
1578        &self,
1579        current_task: &CurrentTask,
1580        name: &FsStr,
1581        target: &FsStr,
1582    ) -> Result<NamespaceNode, Errno> {
1583        let owner = current_task.current_fscred();
1584        let entry =
1585            self.entry.create_entry(current_task, &self.mount, name, |dir, mount, name| {
1586                dir.create_symlink(current_task, mount, name, target, owner)
1587            })?;
1588        Ok(self.with_new_entry(entry))
1589    }
1590
1591    /// Creates an anonymous file.
1592    ///
1593    /// The FileMode::IFMT of the FileMode is always FileMode::IFREG.
1594    ///
1595    /// Used by O_TMPFILE.
1596    pub fn create_tmpfile(
1597        &self,
1598        current_task: &CurrentTask,
1599        mode: FileMode,
1600        flags: OpenFlags,
1601    ) -> Result<NamespaceNode, Errno> {
1602        let owner = current_task.current_fscred();
1603        let mode = current_task.fs().apply_umask(mode);
1604        Ok(self.with_new_entry(self.entry.create_tmpfile(
1605            current_task,
1606            &self.mount,
1607            mode,
1608            owner,
1609            flags,
1610        )?))
1611    }
1612
1613    pub fn link(
1614        &self,
1615        current_task: &CurrentTask,
1616        name: &FsStr,
1617        child: &FsNodeHandle,
1618    ) -> Result<NamespaceNode, Errno> {
1619        let dir_entry =
1620            self.entry.create_entry(current_task, &self.mount, name, |dir, mount, name| {
1621                dir.link(current_task, mount, name, child)
1622            })?;
1623        Ok(self.with_new_entry(dir_entry))
1624    }
1625
1626    /// Creates a socket node `name` bound to `socket`. The socket holds a strong reference to the
1627    /// node until `Socket::close()`, so callers must close it to avoid leaking both.
1628    pub fn bind_socket(
1629        &self,
1630        current_task: &CurrentTask,
1631        name: &FsStr,
1632        socket: SocketHandle,
1633        socket_address: SocketAddress,
1634        mode: FileMode,
1635    ) -> Result<NamespaceNode, Errno> {
1636        let dir_entry =
1637            self.entry.create_entry(current_task, &self.mount, name, |dir, mount, name| {
1638                let node = dir.create_node(
1639                    current_task,
1640                    mount,
1641                    name,
1642                    mode,
1643                    DeviceId::NONE,
1644                    current_task.current_fscred(),
1645                )?;
1646                if let Some(unix_socket) = socket.downcast_socket::<UnixSocket>() {
1647                    unix_socket.bind_socket_to_node(&socket, socket_address, &node)?;
1648                } else {
1649                    return error!(ENOTSUP);
1650                }
1651                Ok(node)
1652            })?;
1653        Ok(self.with_new_entry(dir_entry))
1654    }
1655
1656    pub fn unlink(
1657        &self,
1658        current_task: &CurrentTask,
1659        name: &FsStr,
1660        kind: UnlinkKind,
1661        directory_mode: DirectoryMode,
1662    ) -> Result<(), Errno> {
1663        if DirEntry::is_reserved_name(name) {
1664            match kind {
1665                UnlinkKind::Directory => {
1666                    if name == ".." {
1667                        error!(ENOTEMPTY)
1668                    } else if self.parent().is_none() {
1669                        // The client is attempting to remove the root.
1670                        error!(EBUSY)
1671                    } else {
1672                        error!(EINVAL)
1673                    }
1674                }
1675                UnlinkKind::NonDirectory => error!(ENOTDIR),
1676            }
1677        } else {
1678            self.entry.unlink(current_task, &self.mount, name, kind, directory_mode)
1679        }
1680    }
1681
1682    // Resolve the current node.
1683    //
1684    // Depending on context, this will resolve symlink and mount point.
1685    fn resolve(
1686        self,
1687        current_task: &CurrentTask,
1688        context: &mut LookupContext,
1689    ) -> Result<NamespaceNode, Errno> {
1690        let mut node = self;
1691
1692        loop {
1693            if !node.entry.node.is_lnk() || context.symlink_mode == SymlinkMode::NoFollow {
1694                break;
1695            }
1696            if context.remaining_follows == 0
1697                || context.resolve_flags.contains(ResolveFlags::NO_SYMLINKS)
1698            {
1699                return error!(ELOOP);
1700            }
1701            context.remaining_follows -= 1;
1702            node = match node.readlink(current_task)? {
1703                SymlinkTarget::Path(link_target) => {
1704                    let link_directory = if link_target[0] == b'/' {
1705                        // If the path is absolute, we'll resolve the root directory.
1706                        match &context.resolve_base {
1707                            ResolveBase::None => current_task.fs().root(),
1708                            ResolveBase::Beneath(_) => return error!(EXDEV),
1709                            ResolveBase::InRoot(root) => root.clone(),
1710                        }
1711                    } else {
1712                        // If the path is not absolute, it's a relative directory.
1713                        // Let's try to get the parent of the current node, or in the case that
1714                        // the node is the root we can just use that directly.
1715                        node.parent().unwrap_or(node)
1716                    };
1717                    current_task.lookup_path(context, link_directory, link_target.as_ref())?
1718                }
1719                SymlinkTarget::Node(node) => {
1720                    if context.resolve_flags.contains(ResolveFlags::NO_MAGICLINKS) {
1721                        return error!(ELOOP);
1722                    }
1723                    node
1724                }
1725            };
1726        }
1727        Ok(node.enter_mount())
1728    }
1729
1730    /// Traverse down a parent-to-child link in the namespace.
1731    pub fn lookup_child(
1732        &self,
1733        current_task: &CurrentTask,
1734        context: &mut LookupContext,
1735        basename: &FsStr,
1736    ) -> Result<NamespaceNode, Errno> {
1737        self.lookup_children(current_task, context, &[basename])
1738    }
1739
1740    /// Traverse down to `child`, a child of this node that was already looked up, e.g. with
1741    /// `DirEntry::component_lookup` or `open_create_node`.
1742    ///
1743    /// Follows a symlink and enters mounts as requested by `context`, and enforces
1744    /// `ResolveFlags::NO_XDEV` and `DirectoryMode::MustBeDirectory`.
1745    pub fn resolve_child(
1746        &self,
1747        current_task: &CurrentTask,
1748        context: &mut LookupContext,
1749        child: NamespaceNode,
1750    ) -> Result<NamespaceNode, Errno> {
1751        let child = child.resolve(current_task, context)?;
1752        if context.resolve_flags.contains(ResolveFlags::NO_XDEV) && child.mount != self.mount {
1753            return error!(EXDEV);
1754        }
1755        if context.directory_mode == DirectoryMode::MustBeDirectory && !child.entry.node.is_dir() {
1756            return error!(ENOTDIR);
1757        }
1758        Ok(child)
1759    }
1760
1761    /// Traverse down a parent-to-child link in the namespace.
1762    pub fn lookup_children(
1763        &self,
1764        current_task: &CurrentTask,
1765        context: &mut LookupContext,
1766        mut basenames: &[&FsStr],
1767    ) -> Result<NamespaceNode, Errno> {
1768        for name in basenames {
1769            if name.len() > NAME_MAX as usize {
1770                return error!(ENAMETOOLONG);
1771            }
1772        }
1773
1774        let mut current_namespace_node = self.clone();
1775
1776        while basenames.len() > 0 {
1777            if !current_namespace_node.entry.node.is_dir() {
1778                return error!(ENOTDIR);
1779            }
1780
1781            let basename = basenames[0];
1782            if basename.is_empty() {
1783                basenames = &basenames[1..];
1784                continue;
1785            }
1786            if basename == "." {
1787                current_namespace_node
1788                    .check_access(current_task, AccessCheck::for_internal(Access::EXEC))?;
1789                basenames = &basenames[1..];
1790                continue;
1791            }
1792            if basename == ".." {
1793                current_namespace_node
1794                    .check_access(current_task, AccessCheck::for_internal(Access::EXEC))?;
1795                let root = match &context.resolve_base {
1796                    ResolveBase::None => current_task.fs().root(),
1797                    ResolveBase::Beneath(node) => {
1798                        // Do not allow traversal out of the 'node'.
1799                        if current_namespace_node == *node {
1800                            return error!(EXDEV);
1801                        }
1802                        current_task.fs().root()
1803                    }
1804                    ResolveBase::InRoot(root) => root.clone(),
1805                };
1806
1807                // Make sure this can't escape a chroot.
1808                if current_namespace_node != root {
1809                    current_namespace_node =
1810                        current_namespace_node.parent().unwrap_or(current_namespace_node)
1811                }
1812                if context.resolve_flags.contains(ResolveFlags::NO_XDEV)
1813                    && current_namespace_node.mount != self.mount
1814                {
1815                    return error!(EXDEV);
1816                }
1817
1818                if context.directory_mode == DirectoryMode::MustBeDirectory
1819                    && !current_namespace_node.entry.node.is_dir()
1820                {
1821                    return error!(ENOTDIR);
1822                }
1823                basenames = &basenames[1..];
1824                continue;
1825            }
1826            if basenames.len() == 1
1827                || !current_namespace_node.entry.node.ops().has_lookup_pipelined()
1828            {
1829                let child = current_namespace_node.with_new_entry(
1830                    current_namespace_node.entry.component_lookup(
1831                        current_task,
1832                        &current_namespace_node.mount,
1833                        basename,
1834                    )?,
1835                );
1836                current_namespace_node =
1837                    current_namespace_node.resolve_child(current_task, context, child)?;
1838                basenames = &basenames[1..];
1839                continue;
1840            }
1841
1842            let pipelined_basenames = if let Some(pos) =
1843                basenames.iter().position(|&name| name.is_empty() || name == "." || name == "..")
1844            {
1845                &basenames[..pos]
1846            } else {
1847                basenames
1848            };
1849            let precomputed_entries = current_namespace_node.entry.get_children_pipelined(
1850                current_task,
1851                &current_namespace_node.mount,
1852                pipelined_basenames,
1853            );
1854            for entry in precomputed_entries {
1855                basenames = &basenames[1..];
1856                let child = current_namespace_node.with_new_entry(entry?);
1857                current_namespace_node =
1858                    current_namespace_node.resolve_child(current_task, context, child.clone())?;
1859                if current_namespace_node != child {
1860                    break;
1861                }
1862            }
1863        }
1864
1865        Ok(current_namespace_node)
1866    }
1867
1868    /// Traverse up a child-to-parent link in the namespace.
1869    ///
1870    /// This traversal matches the child-to-parent link in the underlying
1871    /// FsNode except at mountpoints, where the link switches from one
1872    /// filesystem to another.
1873    pub fn parent(&self) -> Option<NamespaceNode> {
1874        let mountpoint_or_self = self.escape_mount();
1875        let parent = mountpoint_or_self.entry.parent()?;
1876        Some(mountpoint_or_self.with_new_entry(parent))
1877    }
1878
1879    /// Returns the parent, but does not escape mounts i.e. returns None if this node
1880    /// is the root of a mount.
1881    pub fn parent_within_mount(&self) -> Option<DirEntryHandle> {
1882        if let Ok(_) = self.mount_if_root() {
1883            return None;
1884        }
1885        self.entry.parent()
1886    }
1887
1888    /// Whether this namespace node is a descendant of the given node.
1889    ///
1890    /// Walks up the namespace node tree looking for ancestor. If ancestor is
1891    /// found, returns true. Otherwise, returns false.
1892    pub fn is_descendant_of(&self, ancestor: &NamespaceNode) -> bool {
1893        let ancestor = ancestor.escape_mount();
1894        let mut current = self.escape_mount();
1895        while current != ancestor {
1896            if let Some(parent) = current.parent() {
1897                current = parent.escape_mount();
1898            } else {
1899                return false;
1900            }
1901        }
1902        true
1903    }
1904
1905    /// If this node is a mountpoint, returns the root of the submount.
1906    ///
1907    /// This only traverses one level of mount, even if the submount's root
1908    /// is itself a mountpoint for another mount.
1909    fn enter_one_mount(&self) -> Option<NamespaceNode> {
1910        if !self.entry.has_mounts() {
1911            return None;
1912        }
1913        if let Some(mount) = self.mount.deref() {
1914            if let Some(submount) =
1915                mount.relations.get_submount(&RcuReadScope::new(), &PtrKey::from(&self.entry))
1916            {
1917                return Some(submount.root());
1918            }
1919        }
1920        None
1921    }
1922
1923    /// If this is a mount point, return the root of the mount. Otherwise return self.
1924    ///
1925    /// This function traverses multiple mounts if there are mounts layered on top of each other.
1926    /// It handles its own synchronization by acquiring the mounts sequence lock for reading.
1927    fn enter_mount(self) -> NamespaceNode {
1928        // `Mounts::register_mount()` sets `HAS_MOUNTS` before a submount is published and
1929        // `Mounts::unregister_mount()` clears it only after the last mount on this `DirEntry` is
1930        // removed, so we can skip the slow path when it is clear. `DirEntry::destroy()` also lowers
1931        // `HAS_MOUNTS` before `Mounts::unmount()` detaches any remaining submounts, which is
1932        // harmless here because the entry has already been unlinked from its parent's children and
1933        // marked `IS_DEAD`.
1934        if !self.entry.has_mounts() {
1935            return self;
1936        }
1937        // While the child is a mountpoint, replace child with the mount's root.
1938        let kernel = self.entry.node.fs().kernel.upgrade().expect("kernel");
1939        kernel.mounts_lock.read_seq(|| {
1940            let mut inner = self.clone();
1941            while let Some(inner_root) = inner.enter_one_mount() {
1942                inner = inner_root;
1943            }
1944            inner
1945        })
1946    }
1947
1948    /// If this is a mount point, return the root of the mount. Otherwise return self.
1949    ///
1950    /// This function traverses multiple mounts if there are mounts layered on top of each other.
1951    /// It requires the caller to hold the mounts write lock (proved by `MountsWriteToken`),
1952    /// unlike `enter_mount` which uses a sequence lock for reading.
1953    fn enter_mount_locked(&self, _mounts_guard: &MountsWriteToken) -> NamespaceNode {
1954        // While the child is a mountpoint, replace child with the mount's root.
1955        let mut inner = self.clone();
1956        while let Some(inner_root) = inner.enter_one_mount() {
1957            inner = inner_root;
1958        }
1959        inner
1960    }
1961
1962    /// If this is the root of a mount, return the mount point. Otherwise return self.
1963    ///
1964    /// This is not exactly the same as parent(). If parent() is called on a root, it will escape
1965    /// the mount, but then return the parent of the mount point instead of the mount point.
1966    fn escape_mount(&self) -> NamespaceNode {
1967        let kernel = self.entry.node.fs().kernel.upgrade().expect("kernel");
1968        kernel.mounts_lock.read_seq(|| {
1969            let mut mountpoint_or_self = self.clone();
1970            while let Some(mountpoint) = mountpoint_or_self.mountpoint() {
1971                mountpoint_or_self = mountpoint;
1972            }
1973            mountpoint_or_self
1974        })
1975    }
1976
1977    /// If this node is the root of a mount, return it. Otherwise EINVAL.
1978    pub fn mount_if_root(&self) -> Result<&MountHandle, Errno> {
1979        if let Some(mount) = self.mount.deref() {
1980            if Arc::ptr_eq(&self.entry, &mount.root) {
1981                return Ok(mount);
1982            }
1983        }
1984        error!(EINVAL)
1985    }
1986
1987    /// Returns the mountpoint at this location in the namespace.
1988    ///
1989    /// If this node is mounted in another node, this function returns the node
1990    /// at which this node is mounted. Otherwise, returns None.
1991    fn mountpoint(&self) -> Option<NamespaceNode> {
1992        self.mount_if_root().ok()?.mountpoint()
1993    }
1994
1995    /// The path from the filesystem root to this node.
1996    pub fn path(&self, fs: &FsContext) -> FsString {
1997        self.path_from_root(Some(&fs.root())).into_path()
1998    }
1999
2000    /// The path from the root of the namespace to this node.
2001    pub fn path_escaping_chroot(&self) -> FsString {
2002        self.path_from_root(None).into_path()
2003    }
2004
2005    /// Returns the path to this node, accounting for a custom root.
2006    /// A task may have a custom root set by `chroot`.
2007    pub fn path_from_root(&self, root: Option<&NamespaceNode>) -> PathWithReachability {
2008        if self.mount.is_none() {
2009            return self.unrooted_path();
2010        }
2011
2012        let mut path = PathBuilder::new();
2013        let mut current = self.escape_mount();
2014        if let Some(root) = root {
2015            let scope = RcuReadScope::new();
2016            // The current node is expected to intersect with the custom root as we travel up the tree.
2017            let root = root.escape_mount();
2018            while current != root {
2019                if let Some(parent) = current.parent() {
2020                    path.prepend_element(current.entry.local_name(&scope));
2021                    current = parent.escape_mount();
2022                } else {
2023                    // This node hasn't intersected with the custom root and has reached the namespace root.
2024                    let mut absolute_path = path.build_absolute();
2025                    if self.entry.is_dead() {
2026                        absolute_path.extend_from_slice(b" (deleted)");
2027                    }
2028
2029                    return PathWithReachability::Unreachable(absolute_path);
2030                }
2031            }
2032        } else {
2033            // No custom root, so travel up the tree to the namespace root.
2034            let scope = RcuReadScope::new();
2035            while let Some(parent) = current.parent() {
2036                path.prepend_element(current.entry.local_name(&scope));
2037                current = parent.escape_mount();
2038            }
2039        }
2040
2041        let mut absolute_path = path.build_absolute();
2042        if self.entry.is_dead() {
2043            absolute_path.extend_from_slice(b" (deleted)");
2044        }
2045
2046        PathWithReachability::Reachable(absolute_path)
2047    }
2048
2049    fn unrooted_path(&self) -> PathWithReachability {
2050        let scope = RcuReadScope::new();
2051        let mode = self.entry.node.info().mode;
2052        let local_name = self.entry.local_name(&scope);
2053        let path = if !local_name.is_empty() {
2054            format!("anon_inode:{}", local_name)
2055        } else if mode.is_sock() {
2056            format!("socket:[{}]", self.entry.node.ino)
2057        } else if mode.is_fifo() {
2058            format!("pipe:[{}]", self.entry.node.ino)
2059        } else {
2060            format!("file:[{}]", self.entry.node.ino)
2061        };
2062        PathWithReachability::Reachable(path.into())
2063    }
2064
2065    pub fn mount(&self, what: WhatToMount, flags: MountpointFlags) -> Result<(), Errno> {
2066        let target = self.clone().enter_mount();
2067
2068        // A target node may not have a mount point if it's an anonymous node. Modern Linux (6.15+)
2069        // returns ENOENT in this case, rather than the more intuitive EINVAL.
2070        if target.mount.is_none() {
2071            return error!(ENOENT);
2072        }
2073
2074        let source_is_dir = match &what {
2075            WhatToMount::Fs(fs) => fs.root().node.is_dir(),
2076            WhatToMount::Bind(node) => node.entry.node.is_dir(),
2077        };
2078
2079        // The source and target need to both be identical types. In other words, if attempting to
2080        // mount a source file onto a target directory (or vice versa), we should err.
2081        if source_is_dir != target.entry.node.is_dir() {
2082            return error!(ENOTDIR);
2083        }
2084
2085        let kernel = self.entry.node.fs().kernel.upgrade().expect("can't mount without a kernel");
2086        let mounts_guard = kernel.mounts_lock();
2087        let what = mounts_guard.defer_drop(what);
2088        let mountpoint = self.enter_mount_locked(&mounts_guard);
2089        let mountpoint = mounts_guard.defer_drop(mountpoint);
2090
2091        let mount = mountpoint.mount.as_ref().ok_or_else(|| errno!(ENOENT))?;
2092        // Prevent a detached mount from being modified via any lingering file descriptors to it.
2093        if mount.is_detached(&mounts_guard) {
2094            return error!(EINVAL);
2095        }
2096        let writeable_mount = mounts_guard.retain(mount);
2097        let writeable_entry = mounts_guard.retain(&mountpoint.entry);
2098        writeable_mount.create_submount(
2099            &mounts_guard,
2100            &writeable_entry,
2101            WhatSubmount::New(scopeguard::ScopeGuard::into_inner(what), flags),
2102        )
2103    }
2104
2105    /// If this is the root of a filesystem, unmount. Otherwise return EINVAL.
2106    pub fn unmount(&self, flags: UnmountFlags) -> Result<(), Errno> {
2107        let kernel = self.entry.node.fs().kernel.upgrade().expect("can't mount without a kernel");
2108        let mounts_guard = kernel.mounts_lock();
2109
2110        let mountpoint = self.enter_mount_locked(&mounts_guard);
2111        let mountpoint = mounts_guard.defer_drop(mountpoint);
2112        let mount = mounts_guard.retain(mountpoint.mount_if_root()?);
2113        mount.unmount(&mounts_guard, flags)
2114    }
2115
2116    pub fn rename(
2117        current_task: &CurrentTask,
2118        old_parent: &NamespaceNode,
2119        old_name: &FsStr,
2120        new_parent: &NamespaceNode,
2121        new_name: &FsStr,
2122        flags: RenameFlags,
2123    ) -> Result<(), Errno> {
2124        DirEntry::rename(
2125            current_task,
2126            &old_parent.entry,
2127            &old_parent.mount,
2128            old_name,
2129            &new_parent.entry,
2130            &new_parent.mount,
2131            new_name,
2132            flags,
2133        )
2134    }
2135
2136    fn with_new_entry(&self, entry: DirEntryHandle) -> NamespaceNode {
2137        Self { mount: self.mount.clone(), entry }
2138    }
2139
2140    fn mount_hash_key(&self) -> PtrKey<DirEntry> {
2141        PtrKey::from(&self.entry)
2142    }
2143
2144    pub fn apply_suid_and_sgid(&self, creds: &mut Credentials) {
2145        // From <https://man7.org/linux/man-pages/man2/execve.2.html>:
2146        //
2147        //   The aforementioned transformations of the effective IDs are not
2148        //   performed ... if ... the underlying filesystem is mounted nosuid
2149        //   (the MS_NOSUID flag for mount(2)).
2150        if self.mount.flags().contains(MountFlags::NOSUID) {
2151            return;
2152        }
2153        self.entry.node.info().apply_suid_and_sgid(creds)
2154    }
2155
2156    pub fn update_atime(&self) {
2157        // Do not update the atime of this node if it is mounted with the NOATIME or RDONLY flag.
2158        if !self.mount.flags().intersects(MountFlags::NOATIME | MountFlags::RDONLY) {
2159            self.entry.node.update_info(|info| {
2160                let now = utc::utc_now();
2161                info.time_access = now;
2162                info.pending_time_access_update = true;
2163            });
2164        }
2165    }
2166
2167    pub fn readlink(&self, current_task: &CurrentTask) -> Result<SymlinkTarget, Errno> {
2168        self.update_atime();
2169        self.entry.node.readlink(current_task)
2170    }
2171
2172    pub fn notify(&self, event_mask: InotifyMask) {
2173        if self.mount.is_some() {
2174            self.entry.notify(event_mask);
2175        }
2176    }
2177
2178    /// Check whether the node can be accessed in the current context with the specified access
2179    /// flags (read, write, or exec). Accounts for capabilities and whether the current user is the
2180    /// owner or is in the file's group.
2181    pub fn check_access(
2182        &self,
2183        current_task: &CurrentTask,
2184        access_check: AccessCheck,
2185    ) -> Result<(), Errno> {
2186        self.entry.node.check_access(
2187            current_task,
2188            &self.mount,
2189            access_check.permission_flags(),
2190            access_check.reason(),
2191            self,
2192        )
2193    }
2194
2195    /// Checks if O_NOATIME is allowed,
2196    pub fn check_o_noatime_allowed(&self, current_task: &CurrentTask) -> Result<(), Errno> {
2197        self.entry.node.check_o_noatime_allowed(current_task)
2198    }
2199
2200    pub fn truncate(&self, current_task: &CurrentTask, length: u64) -> Result<(), Errno> {
2201        self.entry.node.truncate(current_task, &self.mount, length)?;
2202        self.entry.notify_ignoring_excl_unlink(InotifyMask::MODIFY);
2203        Ok(())
2204    }
2205}
2206
2207impl fmt::Debug for NamespaceNode {
2208    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2209        f.debug_struct("NamespaceNode")
2210            .field("path", &self.path_escaping_chroot())
2211            .field("mount", &self.mount)
2212            .field("entry", &self.entry)
2213            .finish()
2214    }
2215}
2216
2217// Eq/Hash impls intended for the MOUNT_POINTS hash
2218impl PartialEq for NamespaceNode {
2219    fn eq(&self, other: &Self) -> bool {
2220        self.mount.as_ref().map(Arc::as_ptr).eq(&other.mount.as_ref().map(Arc::as_ptr))
2221            && Arc::ptr_eq(&self.entry, &other.entry)
2222    }
2223}
2224impl Eq for NamespaceNode {}
2225impl Hash for NamespaceNode {
2226    fn hash<H: Hasher>(&self, state: &mut H) {
2227        self.mount.as_ref().map(Arc::as_ptr).hash(state);
2228        Arc::as_ptr(&self.entry).hash(state);
2229    }
2230}
2231
2232/// A namespace node that keeps the underly mount busy.
2233#[derive(Debug, Clone)]
2234pub struct ActiveNamespaceNode {
2235    /// The underlying namespace node.
2236    name: NamespaceNode,
2237
2238    /// Adds a reference to the mount client marker to prevent the mount from
2239    /// being removed while the NamespaceNode is active. Is None iff mount is
2240    /// None.
2241    _marker: Option<MountClientMarker>,
2242}
2243
2244impl ActiveNamespaceNode {
2245    pub fn new(name: NamespaceNode) -> Self {
2246        let marker = name.mount.as_ref().map(|mount| mount.active_client_counter.clone());
2247        Self { name, _marker: marker }
2248    }
2249
2250    pub fn to_passive(&self) -> NamespaceNode {
2251        self.deref().clone()
2252    }
2253}
2254
2255impl Deref for ActiveNamespaceNode {
2256    type Target = NamespaceNode;
2257
2258    fn deref(&self) -> &Self::Target {
2259        &self.name
2260    }
2261}
2262
2263impl PartialEq for ActiveNamespaceNode {
2264    fn eq(&self, other: &Self) -> bool {
2265        self.deref().eq(other.deref())
2266    }
2267}
2268impl Eq for ActiveNamespaceNode {}
2269impl Hash for ActiveNamespaceNode {
2270    fn hash<H: Hasher>(&self, state: &mut H) {
2271        self.deref().hash(state)
2272    }
2273}
2274
2275/// Mapping of a file into memory, holding a reference to the [`FileHandle`] and an optional
2276/// write guard on the underlying node.
2277#[derive(Debug, Clone)]
2278#[must_use]
2279pub struct FileMapping {
2280    file: FileHandle,
2281    mode: Option<FileWriteGuardMode>,
2282}
2283
2284impl FileMapping {
2285    /// Creates a new [`FileMapping`], acquiring the specified write guard mode on the node if any.
2286    pub fn new(file: FileHandle, mode: Option<FileWriteGuardMode>) -> Result<Arc<Self>, Errno> {
2287        if let Some(mode) = mode {
2288            file.name.entry.node.write_guard_state.lock().acquire(mode)?;
2289        }
2290        Ok(Arc::new(Self { file, mode }))
2291    }
2292
2293    /// File backing this mapping.
2294    pub fn file(&self) -> &FileHandle {
2295        &self.file
2296    }
2297
2298    /// Active namespace node associated with the underlying file.
2299    pub fn name(&self) -> &ActiveNamespaceNode {
2300        &self.file.name
2301    }
2302
2303    /// Filesystem node associated with the underlying file.
2304    pub fn node(&self) -> &FsNodeHandle {
2305        self.file.node()
2306    }
2307}
2308
2309impl PartialEq for FileMapping {
2310    fn eq(&self, other: &Self) -> bool {
2311        Arc::ptr_eq(&self.file, &other.file) && self.mode == other.mode
2312    }
2313}
2314
2315impl Eq for FileMapping {}
2316
2317impl Drop for FileMapping {
2318    fn drop(&mut self) {
2319        if let Some(mode) = self.mode {
2320            self.file.name.entry.node.write_guard_state.lock().release(mode);
2321        }
2322    }
2323}
2324
2325/// Tracks all mounts, keyed by mount point.
2326pub struct Mounts {
2327    mounts: LockDepMutex<HashMap<PtrKey<DirEntry>, Vec<Weak<Mount>>>, MountsLock>,
2328}
2329
2330impl Mounts {
2331    pub fn new() -> Self {
2332        Mounts { mounts: LockDepMutex::default() }
2333    }
2334
2335    /// Registers the mount in the global mounts map.
2336    fn register_mount(&self, dir_entry: &DirEntryHandle, mount: MountHandle) -> Submount {
2337        let mut mounts = self.mounts.lock();
2338        if let Some(vec) = mounts.get_mut(&PtrKey::from(dir_entry)) {
2339            vec.push(Arc::downgrade(&mount));
2340        } else {
2341            dir_entry.set_has_mounts(true);
2342            mounts.insert(PtrKey::from(dir_entry), vec![Arc::downgrade(&mount)]);
2343        }
2344        Submount { dir: dir_entry.clone(), mount }
2345    }
2346
2347    /// Unregisters the mount. This is called by `Submount::drop`.
2348    fn unregister_mount(&self, dir_entry: &DirEntryHandle, mount: &MountHandle) {
2349        let mut mounts = self.mounts.lock();
2350        let key = PtrKey::from(dir_entry);
2351        let mount_ptr = Arc::as_ptr(mount);
2352        let remove_entry = if let Some(vec) = mounts.get_mut(&key) {
2353            let index = vec.iter().position(|e| e.as_ptr() == mount_ptr).unwrap();
2354            vec.swap_remove(index);
2355            vec.is_empty()
2356        } else {
2357            false
2358        };
2359        if remove_entry {
2360            mounts.remove(&key);
2361            dir_entry.set_has_mounts(false);
2362        }
2363    }
2364
2365    /// Unmounts all mounts associated with `dir_entry`. This is called when `dir_entry` is
2366    /// unlinked (which would normally result in EBUSY, but not if it isn't mounted in the local
2367    /// namespace).
2368    pub fn unmount(&self, dir_entry: &DirEntry) {
2369        let Some(kernel) = dir_entry.node.fs().kernel.upgrade() else {
2370            return;
2371        };
2372        let mounts_guard = kernel.mounts_lock();
2373        let mounts = self.mounts.lock().remove(&PtrKey::from(dir_entry));
2374        if let Some(mounts) = mounts {
2375            let upgraded: Vec<_> = mounts.iter().filter_map(Weak::upgrade).collect();
2376            let mounts = mounts_guard.defer_drop(upgraded);
2377            for mount in &*mounts {
2378                // Ignore errors.
2379                let _ = mount.unmount(&mounts_guard, UnmountFlags::DETACH);
2380            }
2381        }
2382    }
2383
2384    /// Drain mounts. For each drained mount, force a FileSystem unmount.
2385    // TODO(https://fxbug.dev/295073633): Graceful shutdown should try to first unmount the mounts
2386    // and only force a FileSystem unmount on failure.
2387    pub fn clear(&self) {
2388        let drained = std::mem::take(&mut *self.mounts.lock());
2389        for (_dir_entry, mounts) in drained {
2390            for mount in mounts {
2391                if let Some(mount) = mount.upgrade() {
2392                    mount.fs.force_unmount_ops();
2393                }
2394            }
2395        }
2396    }
2397
2398    /// Returns the set of unique mounted filesystems, including any underlying filesystems
2399    /// wrapped by stacked filesystems such as OverlayFs.
2400    fn unique_filesystems(&self) -> HashSet<ArcKey<FileSystem>> {
2401        let mut filesystems = HashSet::new();
2402        let mut queue = Vec::new();
2403        let mounts: Vec<Weak<Mount>> = self.mounts.lock().values().flatten().cloned().collect();
2404        for m in mounts {
2405            if let Some(mount) = m.upgrade() {
2406                if filesystems.insert(ArcKey(mount.fs.clone())) {
2407                    queue.push(mount.fs.clone());
2408                }
2409            }
2410        }
2411        while let Some(fs) = queue.pop() {
2412            for sub_fs in fs.sub_filesystems() {
2413                if filesystems.insert(ArcKey(sub_fs.clone())) {
2414                    queue.push(sub_fs);
2415                }
2416            }
2417        }
2418        filesystems
2419    }
2420
2421    pub fn sync_all(&self, current_task: &CurrentTask) -> Result<(), Errno> {
2422        for fs in self.unique_filesystems() {
2423            if let Err(e) = fs.sync(current_task) {
2424                log_warn!("sync failed for filesystem {:?}: {:?}", fs.name(), e);
2425            }
2426        }
2427        Ok(())
2428    }
2429
2430    pub fn drop_caches(&self) {
2431        let filesystems = self.unique_filesystems();
2432        // First purge all directory entry caches so that stacked filesystems (like OverlayFs)
2433        // drop references to underlying DirEntries/FsNodes before backend caches are cleared.
2434        for fs in &filesystems {
2435            fs.purge_dcache();
2436        }
2437        for fs in &filesystems {
2438            fs.drop_backend_caches();
2439        }
2440    }
2441}
2442
2443impl Drop for Mount {
2444    fn drop(&mut self) {
2445        // Updating the RCU object without lock is acceptable because this Mount is not available
2446        // anymore by anything.
2447        let kernel = self.kernel();
2448        let peer_group = self.relations.peer_group.upgrade();
2449        let upstream = self.relations.upstream.cloned();
2450        self.relations.peer_group.update(None);
2451        self.relations.upstream.update(None);
2452        if peer_group.is_some() || upstream.is_some() {
2453            let mount_ptr = PtrKey::from(self as &Mount);
2454            register_delayed_call(move |_current_task| {
2455                let guard = kernel.mounts_lock();
2456                Mount::unregister_from_peer_group_and_upstream(
2457                    &guard, peer_group, upstream, mount_ptr,
2458                );
2459            });
2460        }
2461    }
2462}
2463
2464impl fmt::Debug for Mount {
2465    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2466        let scope = RcuReadScope::new();
2467        f.debug_struct("Mount")
2468            .field("id", &(self as *const Mount))
2469            .field("root", &self.root)
2470            .field("mountpoint", &self.relations.mountpoint(&scope))
2471            .field(
2472                "submounts",
2473                &self
2474                    .relations
2475                    .iter_submounts(&scope)
2476                    .filter_map(|(_, m)| m.upgrade())
2477                    .collect::<Vec<_>>(),
2478            )
2479            .finish()
2480    }
2481}
2482
2483/// A RAII object that unregisters a mount when dropped.
2484#[derive(Debug)]
2485struct Submount {
2486    dir: DirEntryHandle,
2487    mount: MountHandle,
2488}
2489
2490impl Drop for Submount {
2491    fn drop(&mut self) {
2492        self.mount.kernel().mounts.unregister_mount(&self.dir, &self.mount)
2493    }
2494}
2495
2496#[cfg(test)]
2497mod test {
2498    use crate::fs::tmpfs::TmpFs;
2499    use crate::testing::spawn_kernel_and_run;
2500    use crate::vfs::namespace::DeviceId;
2501    use crate::vfs::{
2502        CallbackSymlinkNode, DirectoryMode, FsNodeInfo, LookupContext, MountInfo, Namespace,
2503        NamespaceNode, RenameFlags, SymlinkMode, SymlinkTarget, UnlinkKind, WhatToMount,
2504    };
2505    use starnix_uapi::arc_key::PtrKey;
2506    use starnix_uapi::mount_flags::MountpointFlags;
2507    use starnix_uapi::unmount_flags::UnmountFlags;
2508    use starnix_uapi::{errno, mode};
2509    use std::sync::Arc;
2510
2511    #[::fuchsia::test]
2512    async fn test_namespace() {
2513        spawn_kernel_and_run(async |current_task| {
2514            let kernel = current_task.kernel();
2515            let root_fs = TmpFs::new_fs(&kernel);
2516            let root_node = Arc::clone(root_fs.root());
2517            let _dev_node =
2518                root_node.create_dir(&current_task, "dev".into()).expect("failed to mkdir dev");
2519            let dev_fs = TmpFs::new_fs(&kernel);
2520            let dev_root_node = Arc::clone(dev_fs.root());
2521            let _dev_pts_node =
2522                dev_root_node.create_dir(&current_task, "pts".into()).expect("failed to mkdir pts");
2523
2524            let ns = Namespace::new(root_fs);
2525            let mut context = LookupContext::default();
2526            let dev = ns
2527                .root()
2528                .lookup_child(&current_task, &mut context, "dev".into())
2529                .expect("failed to lookup dev");
2530            dev.mount(WhatToMount::Fs(dev_fs), MountpointFlags::empty())
2531                .expect("failed to mount dev root node");
2532
2533            let mut context = LookupContext::default();
2534            let dev = ns
2535                .root()
2536                .lookup_child(&current_task, &mut context, "dev".into())
2537                .expect("failed to lookup dev");
2538            let mut context = LookupContext::default();
2539            let pts = dev
2540                .lookup_child(&current_task, &mut context, "pts".into())
2541                .expect("failed to lookup pts");
2542            let pts_parent =
2543                pts.parent().ok_or_else(|| errno!(ENOENT)).expect("failed to get parent of pts");
2544            assert!(Arc::ptr_eq(&pts_parent.entry, &dev.entry));
2545
2546            let dev_parent =
2547                dev.parent().ok_or_else(|| errno!(ENOENT)).expect("failed to get parent of dev");
2548            assert!(Arc::ptr_eq(&dev_parent.entry, &ns.root().entry));
2549        })
2550        .await;
2551    }
2552
2553    #[::fuchsia::test]
2554    async fn test_mount_does_not_upgrade() {
2555        spawn_kernel_and_run(async |current_task| {
2556            let kernel = current_task.kernel();
2557            let root_fs = TmpFs::new_fs(&kernel);
2558            let root_node = Arc::clone(root_fs.root());
2559            let _dev_node =
2560                root_node.create_dir(&current_task, "dev".into()).expect("failed to mkdir dev");
2561            let dev_fs = TmpFs::new_fs(&kernel);
2562            let dev_root_node = Arc::clone(dev_fs.root());
2563            let _dev_pts_node =
2564                dev_root_node.create_dir(&current_task, "pts".into()).expect("failed to mkdir pts");
2565
2566            let ns = Namespace::new(root_fs);
2567            let mut context = LookupContext::default();
2568            let dev = ns
2569                .root()
2570                .lookup_child(&current_task, &mut context, "dev".into())
2571                .expect("failed to lookup dev");
2572            dev.mount(WhatToMount::Fs(dev_fs), MountpointFlags::empty())
2573                .expect("failed to mount dev root node");
2574            let mut context = LookupContext::default();
2575            let new_dev = ns
2576                .root()
2577                .lookup_child(&current_task, &mut context, "dev".into())
2578                .expect("failed to lookup dev again");
2579            assert!(!Arc::ptr_eq(&dev.entry, &new_dev.entry));
2580            assert_ne!(&dev, &new_dev);
2581
2582            let mut context = LookupContext::default();
2583            let _new_pts = new_dev
2584                .lookup_child(&current_task, &mut context, "pts".into())
2585                .expect("failed to lookup pts");
2586            let mut context = LookupContext::default();
2587            assert!(dev.lookup_child(&current_task, &mut context, "pts".into()).is_err());
2588        })
2589        .await;
2590    }
2591
2592    #[::fuchsia::test]
2593    async fn test_path() {
2594        spawn_kernel_and_run(async |current_task| {
2595            let kernel = current_task.kernel();
2596            let root_fs = TmpFs::new_fs(&kernel);
2597            let root_node = Arc::clone(root_fs.root());
2598            let _dev_node =
2599                root_node.create_dir(&current_task, "dev".into()).expect("failed to mkdir dev");
2600            let dev_fs = TmpFs::new_fs(&kernel);
2601            let dev_root_node = Arc::clone(dev_fs.root());
2602            let _dev_pts_node =
2603                dev_root_node.create_dir(&current_task, "pts".into()).expect("failed to mkdir pts");
2604
2605            let ns = Namespace::new(root_fs);
2606            let mut context = LookupContext::default();
2607            let dev = ns
2608                .root()
2609                .lookup_child(&current_task, &mut context, "dev".into())
2610                .expect("failed to lookup dev");
2611            dev.mount(WhatToMount::Fs(dev_fs), MountpointFlags::empty())
2612                .expect("failed to mount dev root node");
2613
2614            let mut context = LookupContext::default();
2615            let dev = ns
2616                .root()
2617                .lookup_child(&current_task, &mut context, "dev".into())
2618                .expect("failed to lookup dev");
2619            let mut context = LookupContext::default();
2620            let pts = dev
2621                .lookup_child(&current_task, &mut context, "pts".into())
2622                .expect("failed to lookup pts");
2623
2624            assert_eq!("/", ns.root().path_escaping_chroot());
2625            assert_eq!("/dev", dev.path_escaping_chroot());
2626            assert_eq!("/dev/pts", pts.path_escaping_chroot());
2627        })
2628        .await;
2629    }
2630
2631    #[::fuchsia::test]
2632    async fn test_shadowing() {
2633        spawn_kernel_and_run(async |current_task| {
2634            let kernel = current_task.kernel();
2635            let root_fs = TmpFs::new_fs(&kernel);
2636            let ns = Namespace::new(root_fs.clone());
2637            let _foo_node = root_fs.root().create_dir(&current_task, "foo".into()).unwrap();
2638            let mut context = LookupContext::default();
2639            let foo_dir =
2640                ns.root().lookup_child(&current_task, &mut context, "foo".into()).unwrap();
2641
2642            let foofs1 = TmpFs::new_fs(&kernel);
2643            foo_dir.mount(WhatToMount::Fs(foofs1.clone()), MountpointFlags::empty()).unwrap();
2644            let mut context = LookupContext::default();
2645            assert!(Arc::ptr_eq(
2646                &ns.root().lookup_child(&current_task, &mut context, "foo".into()).unwrap().entry,
2647                foofs1.root()
2648            ));
2649            let foo_dir =
2650                ns.root().lookup_child(&current_task, &mut context, "foo".into()).unwrap();
2651
2652            let ns_clone = ns.clone_namespace(&kernel.mounts_lock());
2653
2654            let foofs2 = TmpFs::new_fs(&kernel);
2655            foo_dir.mount(WhatToMount::Fs(foofs2.clone()), MountpointFlags::empty()).unwrap();
2656            let mut context = LookupContext::default();
2657            assert!(Arc::ptr_eq(
2658                &ns.root().lookup_child(&current_task, &mut context, "foo".into()).unwrap().entry,
2659                foofs2.root()
2660            ));
2661
2662            assert!(Arc::ptr_eq(
2663                &ns_clone
2664                    .root()
2665                    .lookup_child(&current_task, &mut LookupContext::default(), "foo".into())
2666                    .unwrap()
2667                    .entry,
2668                foofs1.root()
2669            ));
2670        })
2671        .await;
2672    }
2673
2674    #[::fuchsia::test]
2675    async fn test_unlink_mounted_directory() {
2676        spawn_kernel_and_run(async |current_task| {
2677            let kernel = current_task.kernel();
2678            let root_fs = TmpFs::new_fs(&kernel);
2679            let ns1 = Namespace::new(root_fs.clone());
2680            let ns2 = Namespace::new(root_fs.clone());
2681            let _foo_node = root_fs.root().create_dir(&current_task, "foo".into()).unwrap();
2682            let mut context = LookupContext::default();
2683            let foo_dir =
2684                ns1.root().lookup_child(&current_task, &mut context, "foo".into()).unwrap();
2685
2686            let foofs = TmpFs::new_fs(&kernel);
2687            foo_dir.mount(WhatToMount::Fs(foofs), MountpointFlags::empty()).unwrap();
2688
2689            // Trying to unlink from ns1 should fail.
2690            assert_eq!(
2691                ns1.root()
2692                    .unlink(
2693                        &current_task,
2694                        "foo".into(),
2695                        UnlinkKind::Directory,
2696                        DirectoryMode::AllowAny
2697                    )
2698                    .unwrap_err(),
2699                errno!(EBUSY),
2700            );
2701
2702            // But unlinking from ns2 should succeed.
2703            ns2.root()
2704                .unlink(&current_task, "foo".into(), UnlinkKind::Directory, DirectoryMode::AllowAny)
2705                .expect("unlink failed");
2706
2707            // And it should no longer show up in ns1.
2708            assert_eq!(
2709                ns1.root()
2710                    .unlink(
2711                        &current_task,
2712                        "foo".into(),
2713                        UnlinkKind::Directory,
2714                        DirectoryMode::AllowAny
2715                    )
2716                    .unwrap_err(),
2717                errno!(ENOENT),
2718            );
2719        })
2720        .await;
2721    }
2722
2723    #[::fuchsia::test]
2724    async fn test_rename_mounted_directory() {
2725        spawn_kernel_and_run(async |current_task| {
2726            let kernel = current_task.kernel();
2727            let root_fs = TmpFs::new_fs(&kernel);
2728            let ns1 = Namespace::new(root_fs.clone());
2729            let ns2 = Namespace::new(root_fs.clone());
2730            let _foo_node = root_fs.root().create_dir(&current_task, "foo".into()).unwrap();
2731            let _bar_node = root_fs.root().create_dir(&current_task, "bar".into()).unwrap();
2732            let _baz_node = root_fs.root().create_dir(&current_task, "baz".into()).unwrap();
2733            let mut context = LookupContext::default();
2734            let foo_dir =
2735                ns1.root().lookup_child(&current_task, &mut context, "foo".into()).unwrap();
2736
2737            let foofs = TmpFs::new_fs(&kernel);
2738            foo_dir.mount(WhatToMount::Fs(foofs), MountpointFlags::empty()).unwrap();
2739
2740            // Trying to rename over foo from ns1 should fail.
2741            let root = ns1.root();
2742            assert_eq!(
2743                NamespaceNode::rename(
2744                    &current_task,
2745                    &root,
2746                    "bar".into(),
2747                    &root,
2748                    "foo".into(),
2749                    RenameFlags::empty()
2750                )
2751                .unwrap_err(),
2752                errno!(EBUSY),
2753            );
2754            // Likewise the other way.
2755            assert_eq!(
2756                NamespaceNode::rename(
2757                    &current_task,
2758                    &root,
2759                    "foo".into(),
2760                    &root,
2761                    "bar".into(),
2762                    RenameFlags::empty()
2763                )
2764                .unwrap_err(),
2765                errno!(EBUSY),
2766            );
2767
2768            // But renaming from ns2 should succeed.
2769            let root = ns2.root();
2770
2771            // First rename the directory with the mount.
2772            NamespaceNode::rename(
2773                &current_task,
2774                &root,
2775                "foo".into(),
2776                &root,
2777                "bar".into(),
2778                RenameFlags::empty(),
2779            )
2780            .expect("rename failed");
2781
2782            // Renaming over a directory with a mount should also work.
2783            NamespaceNode::rename(
2784                &current_task,
2785                &root,
2786                "baz".into(),
2787                &root,
2788                "bar".into(),
2789                RenameFlags::empty(),
2790            )
2791            .expect("rename failed");
2792
2793            // "foo" and "baz" should no longer show up in ns1.
2794            assert_eq!(
2795                ns1.root().lookup_child(&current_task, &mut context, "foo".into()).unwrap_err(),
2796                errno!(ENOENT)
2797            );
2798            assert_eq!(
2799                ns1.root().lookup_child(&current_task, &mut context, "baz".into()).unwrap_err(),
2800                errno!(ENOENT)
2801            );
2802        })
2803        .await;
2804    }
2805
2806    /// Symlinks which need to be traversed across types (nodes and paths), as well as across
2807    /// owning directories, can be tricky to get right.
2808    #[::fuchsia::test]
2809    async fn test_lookup_with_symlink_chain() {
2810        spawn_kernel_and_run(async |current_task| {
2811            // Set up the root filesystem
2812            let kernel = current_task.kernel();
2813            let root_fs = TmpFs::new_fs(&kernel);
2814            let root_node = Arc::clone(root_fs.root());
2815            let _first_subdir_node = root_node
2816                .create_dir(&current_task, "first_subdir".into())
2817                .expect("failed to mkdir dev");
2818            let _second_subdir_node = root_node
2819                .create_dir(&current_task, "second_subdir".into())
2820                .expect("failed to mkdir dev");
2821
2822            // Set up two subdirectories under the root filesystem
2823            let first_subdir_fs = TmpFs::new_fs(&kernel);
2824            let second_subdir_fs = TmpFs::new_fs(&kernel);
2825
2826            let ns = Namespace::new(root_fs);
2827            let mut context = LookupContext::default();
2828            let first_subdir = ns
2829                .root()
2830                .lookup_child(&current_task, &mut context, "first_subdir".into())
2831                .expect("failed to lookup first_subdir");
2832            first_subdir
2833                .mount(WhatToMount::Fs(first_subdir_fs), MountpointFlags::empty())
2834                .expect("failed to mount first_subdir fs node");
2835            let second_subdir = ns
2836                .root()
2837                .lookup_child(&current_task, &mut context, "second_subdir".into())
2838                .expect("failed to lookup second_subdir");
2839            second_subdir
2840                .mount(WhatToMount::Fs(second_subdir_fs), MountpointFlags::empty())
2841                .expect("failed to mount second_subdir fs node");
2842
2843            // Create the symlink structure. To trigger potential symlink traversal bugs, we're going
2844            // for the following directory structure:
2845            // / (root)
2846            //     + first_subdir/
2847            //         - real_file
2848            //         - path_symlink (-> real_file)
2849            //     + second_subdir/
2850            //         - node_symlink (-> path_symlink)
2851            let real_file_node = first_subdir
2852                .create_node(&current_task, "real_file".into(), mode!(IFREG, 0o777), DeviceId::NONE)
2853                .expect("failed to create real_file");
2854            first_subdir
2855                .create_symlink(&current_task, "path_symlink".into(), "real_file".into())
2856                .expect("failed to create path_symlink");
2857
2858            let mut no_follow_lookup_context = LookupContext::new(SymlinkMode::NoFollow);
2859            let path_symlink_node = first_subdir
2860                .lookup_child(&current_task, &mut no_follow_lookup_context, "path_symlink".into())
2861                .expect("Failed to lookup path_symlink");
2862
2863            // The second symlink needs to be of type SymlinkTarget::Node in order to trip the sensitive
2864            // code path. There's no easy method for creating this type of symlink target, so we'll need
2865            // to construct a node from scratch and insert it into the directory manually.
2866            let node_symlink_node = second_subdir.entry.node.fs().create_node_and_allocate_node_id(
2867                CallbackSymlinkNode::new(move || {
2868                    let node = path_symlink_node.clone();
2869                    Ok(SymlinkTarget::Node(node))
2870                }),
2871                FsNodeInfo::new(mode!(IFLNK, 0o777), current_task.current_fscred()),
2872            );
2873            second_subdir
2874                .entry
2875                .create_entry(
2876                    &current_task,
2877                    &MountInfo::detached(),
2878                    "node_symlink".into(),
2879                    move |_dir, _mount, _name| Ok(node_symlink_node),
2880                )
2881                .expect("failed to create node_symlink entry");
2882
2883            // Finally, exercise the lookup under test.
2884            let mut follow_lookup_context = LookupContext::new(SymlinkMode::Follow);
2885            let node_symlink_resolution = second_subdir
2886                .lookup_child(&current_task, &mut follow_lookup_context, "node_symlink".into())
2887                .expect("lookup with symlink chain failed");
2888
2889            // The lookup resolution should have correctly followed the symlinks to the real_file node.
2890            assert!(node_symlink_resolution.entry.node.ino == real_file_node.entry.node.ino);
2891        })
2892        .await;
2893    }
2894
2895    #[::fuchsia::test]
2896    async fn test_mounts_registration_and_unmount_updates_has_mounts() {
2897        spawn_kernel_and_run(async |current_task| {
2898            let kernel = current_task.kernel();
2899            let root_fs = TmpFs::new_fs(&kernel);
2900            let ns1 = Namespace::new(root_fs.clone());
2901            let _foo_node = root_fs.root().create_dir(&current_task, "foo".into()).unwrap();
2902            let mut context = LookupContext::default();
2903            let foo_dir =
2904                ns1.root().lookup_child(&current_task, &mut context, "foo".into()).unwrap();
2905            let mountpoint_entry = Arc::clone(&foo_dir.entry);
2906            assert!(!mountpoint_entry.has_mounts());
2907
2908            let foofs = TmpFs::new_fs(&kernel);
2909            foo_dir.mount(WhatToMount::Fs(foofs), MountpointFlags::empty()).unwrap();
2910            assert!(mountpoint_entry.has_mounts());
2911
2912            // Cloning the namespace registers a second Submount on the same DirEntry.
2913            let ns1_clone = ns1.clone_namespace(&kernel.mounts_lock());
2914            assert!(mountpoint_entry.has_mounts());
2915
2916            // Dropping the cloned namespace unregisters its Submount, leaving ns1's Submount active.
2917            drop(ns1_clone);
2918            assert!(mountpoint_entry.has_mounts());
2919
2920            // Unmounting the remaining mount in ns1 calls `unregister_mount` for the last entry
2921            // and clears `has_mounts` without destroying the DirEntry.
2922            let mounted_foo = ns1
2923                .root()
2924                .lookup_child(&current_task, &mut LookupContext::default(), "foo".into())
2925                .unwrap();
2926            mounted_foo.unmount(UnmountFlags::empty()).unwrap();
2927            assert!(!mountpoint_entry.has_mounts());
2928
2929            // Also verify recursive (`REC`) bind mount of a subdirectory skips sibling mounts
2930            // outside the new root while cloning submounts under the subdirectory.
2931            let _sub_node = root_fs.root().create_dir(&current_task, "sub".into()).unwrap();
2932            let _dst_node = root_fs.root().create_dir(&current_task, "dst".into()).unwrap();
2933            let sub_dir = ns1
2934                .root()
2935                .lookup_child(&current_task, &mut LookupContext::default(), "sub".into())
2936                .unwrap();
2937            let _inner_node = sub_dir.entry.create_dir(&current_task, "inner".into()).unwrap();
2938            let inner_dir = sub_dir
2939                .lookup_child(&current_task, &mut LookupContext::default(), "inner".into())
2940                .unwrap();
2941            let inner_fs = TmpFs::new_fs(&kernel);
2942            let _inner_marker = inner_fs.root().create_dir(&current_task, "marker".into()).unwrap();
2943            inner_dir.mount(WhatToMount::Fs(inner_fs), MountpointFlags::empty()).unwrap();
2944
2945            let sibling_fs = TmpFs::new_fs(&kernel);
2946            foo_dir.mount(WhatToMount::Fs(sibling_fs), MountpointFlags::empty()).unwrap();
2947
2948            let dst_dir = ns1
2949                .root()
2950                .lookup_child(&current_task, &mut LookupContext::default(), "dst".into())
2951                .unwrap();
2952            dst_dir.mount(WhatToMount::Bind(sub_dir), MountpointFlags::REC).unwrap();
2953
2954            let dst_inner = ns1
2955                .root()
2956                .lookup_child(&current_task, &mut LookupContext::default(), "dst".into())
2957                .unwrap()
2958                .lookup_child(&current_task, &mut LookupContext::default(), "inner".into())
2959                .unwrap();
2960            assert!(
2961                dst_inner
2962                    .lookup_child(&current_task, &mut LookupContext::default(), "marker".into())
2963                    .is_ok()
2964            );
2965            assert_eq!(
2966                kernel.mounts.mounts.lock().get(&PtrKey::from(&foo_dir.entry)).unwrap().len(),
2967                1
2968            );
2969        })
2970        .await;
2971    }
2972
2973    #[::fuchsia::test]
2974    async fn test_enter_mount_has_mounts_lifecycle() {
2975        spawn_kernel_and_run(async |current_task| {
2976            let kernel = current_task.kernel();
2977            let root_fs = TmpFs::new_fs(&kernel);
2978            let ns1 = Namespace::new(root_fs.clone());
2979            let ns2 = Namespace::new(root_fs.clone());
2980            let foo_entry = root_fs.root().create_dir(&current_task, "foo".into()).unwrap();
2981            assert!(!foo_entry.has_mounts());
2982
2983            // Non-mountpoint lookup takes the !has_mounts() fast path and returns foo_entry.
2984            let foo_ns1 = ns1
2985                .root()
2986                .lookup_child(&current_task, &mut LookupContext::default(), "foo".into())
2987                .unwrap();
2988            assert!(Arc::ptr_eq(&foo_ns1.entry, &foo_entry));
2989
2990            // Mounting foofs1 in ns1 raises HAS_MOUNTS on foo_entry; ns1 enters foofs1, while ns2
2991            // (sharing foo_entry with HAS_MOUNTS set) still resolves to foo_entry.
2992            let foofs1 = TmpFs::new_fs(&kernel);
2993            foo_ns1.mount(WhatToMount::Fs(foofs1.clone()), MountpointFlags::empty()).unwrap();
2994            assert!(foo_entry.has_mounts());
2995            assert!(!foofs1.root().has_mounts());
2996
2997            let mounted1 = ns1
2998                .root()
2999                .lookup_child(&current_task, &mut LookupContext::default(), "foo".into())
3000                .unwrap();
3001            assert!(Arc::ptr_eq(&mounted1.entry, foofs1.root()));
3002            let foo_ns2 = ns2
3003                .root()
3004                .lookup_child(&current_task, &mut LookupContext::default(), "foo".into())
3005                .unwrap();
3006            assert!(Arc::ptr_eq(&foo_ns2.entry, &foo_entry));
3007
3008            // Stacking foofs2 on top of foofs1 in ns1 raises HAS_MOUNTS on foofs1.root().
3009            let foofs2 = TmpFs::new_fs(&kernel);
3010            mounted1.mount(WhatToMount::Fs(foofs2.clone()), MountpointFlags::empty()).unwrap();
3011            assert!(foofs1.root().has_mounts());
3012            assert!(!foofs2.root().has_mounts());
3013
3014            let mounted2 = ns1
3015                .root()
3016                .lookup_child(&current_task, &mut LookupContext::default(), "foo".into())
3017                .unwrap();
3018            assert!(Arc::ptr_eq(&mounted2.entry, foofs2.root()));
3019
3020            // Unmounting foofs2 lowers HAS_MOUNTS on foofs1.root() and exposes foofs1 again.
3021            mounted2.unmount(UnmountFlags::empty()).unwrap();
3022            assert!(!foofs1.root().has_mounts());
3023            assert!(foo_entry.has_mounts());
3024            let after_unmount2 = ns1
3025                .root()
3026                .lookup_child(&current_task, &mut LookupContext::default(), "foo".into())
3027                .unwrap();
3028            assert!(Arc::ptr_eq(&after_unmount2.entry, foofs1.root()));
3029
3030            // Unmounting foofs1 lowers HAS_MOUNTS on foo_entry and exposes the underlying dir.
3031            after_unmount2.unmount(UnmountFlags::empty()).unwrap();
3032            assert!(!foo_entry.has_mounts());
3033            let after_unmount1 = ns1
3034                .root()
3035                .lookup_child(&current_task, &mut LookupContext::default(), "foo".into())
3036                .unwrap();
3037            assert!(Arc::ptr_eq(&after_unmount1.entry, &foo_entry));
3038        })
3039        .await;
3040    }
3041}