Skip to main content

starnix_core/vfs/
fs_node.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::device::DeviceMode;
6use crate::mm::PAGE_SIZE;
7use crate::security::{self, Auditable, PermissionFlags};
8use crate::signals::{SignalInfo, send_standard_signal};
9use crate::task::{CurrentTask, WaitQueue, Waiter, register_delayed_release};
10use crate::time::utc;
11use crate::vfs::fsverity::FsVerityState;
12use crate::vfs::pipe::{Pipe, PipeHandle};
13use crate::vfs::rw_queue::{RwQueue, RwQueueReadGuard, RwQueueWriteGuard};
14use crate::vfs::socket::SocketHandle;
15use crate::vfs::{
16    DefaultDirEntryOps, DirEntryOps, FileObject, FileObjectState, FileOps, FileSystem,
17    FileSystemHandle, FileWriteGuardState, FsLockDepType, FsStr, FsString, MAX_LFS_FILESIZE,
18    MountInfo, NamespaceNode, OPathOps, RecordLockCommand, RecordLockOwner, RecordLocks,
19    WeakFileHandle, checked_add_offset_and_length, inotify_hook,
20};
21use bitflags::bitflags;
22use fuchsia_runtime::UtcInstant;
23use linux_uapi::{XATTR_SECURITY_PREFIX, XATTR_SYSTEM_PREFIX, XATTR_TRUSTED_PREFIX};
24use once_cell::race::OnceBool;
25use smallvec::SmallVec;
26use starnix_crypt::EncryptionKeyId;
27use starnix_lifecycle::{ObjectReleaser, ReleaserAction};
28use starnix_logging::{log_error, track_stub};
29use starnix_sync::{
30    DynamicLockDepRwLock, FsNodeAppend, FsNodeFlockInfoLock, FsNodeFsVerityLock, FsNodeInfoLevel,
31    FsNodeInfoRecursiveLevel, FsNodeWriteGuardStateLock, FuseFsNodeInfoLevel, LockDepMutex,
32    LockDepReadGuard, allow_subclass,
33};
34use starnix_types::ownership::{Releasable, ReleaseGuard};
35use starnix_types::time::{NANOS_PER_SECOND, timespec_from_time};
36use starnix_uapi::as_any::AsAny;
37use starnix_uapi::auth::{
38    CAP_CHOWN, CAP_DAC_OVERRIDE, CAP_DAC_READ_SEARCH, CAP_FOWNER, CAP_FSETID, CAP_MKNOD,
39    CAP_SYS_ADMIN, CAP_SYS_RESOURCE, Credentials, FsCred,
40};
41use starnix_uapi::device_id::DeviceId;
42use starnix_uapi::errors::{EACCES, ENOTSUP, EPERM, Errno};
43use starnix_uapi::file_mode::{Access, AccessCheck, FileMode};
44use starnix_uapi::inotify_mask::InotifyMask;
45use starnix_uapi::mount_flags::MountFlags;
46use starnix_uapi::open_flags::OpenFlags;
47use starnix_uapi::resource_limits::Resource;
48use starnix_uapi::seal_flags::SealFlags;
49use starnix_uapi::signals::SIGXFSZ;
50use starnix_uapi::{
51    FALLOC_FL_COLLAPSE_RANGE, FALLOC_FL_INSERT_RANGE, FALLOC_FL_KEEP_SIZE, FALLOC_FL_PUNCH_HOLE,
52    FALLOC_FL_UNSHARE_RANGE, FALLOC_FL_ZERO_RANGE, LOCK_EX, LOCK_NB, LOCK_SH, LOCK_UN,
53    STATX__RESERVED, STATX_ATIME, STATX_ATTR_VERITY, STATX_BASIC_STATS, STATX_BLOCKS, STATX_CTIME,
54    STATX_GID, STATX_INO, STATX_MTIME, STATX_NLINK, STATX_SIZE, STATX_UID, XATTR_USER_PREFIX,
55    errno, error, fsverity_descriptor, gid_t, ino_t, statx, statx_timestamp, timespec, uapi, uid_t,
56};
57use std::sync::atomic::Ordering;
58use std::sync::{Arc, OnceLock, Weak};
59use syncio::zxio_node_attr_has_t;
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq)]
62pub enum FsNodeLinkBehavior {
63    Allowed,
64    Disallowed,
65}
66
67impl Default for FsNodeLinkBehavior {
68    fn default() -> Self {
69        FsNodeLinkBehavior::Allowed
70    }
71}
72
73pub type AppendLockGuard<'a> = RwQueueReadGuard<'a, FsNodeAppend>;
74pub type AppendLockWriteGuard<'a> = RwQueueWriteGuard<'a, FsNodeAppend>;
75
76bitflags! {
77    pub struct FsNodeFlags: u8 {
78        const IS_PRIVATE = 1 << 0;
79    }
80}
81
82pub struct FsNode {
83    /// The inode number for this FsNode.
84    pub ino: ino_t,
85
86    /// Flags for this node.
87    pub flags: FsNodeFlags,
88
89    /// The FsNodeOps for this FsNode.
90    ///
91    /// The FsNodeOps are implemented by the individual file systems to provide
92    /// specific behaviors for this FsNode.
93    ops: Box<dyn FsNodeOps>,
94
95    /// The FileSystem that owns this FsNode's tree.
96    fs: Weak<FileSystem>,
97
98    /// A RwLock to synchronize append operations for this node.
99    ///
100    /// FileObjects writing with O_APPEND should grab a write() lock on this
101    /// field to ensure they operate sequentially. FileObjects writing without
102    /// O_APPEND should grab read() lock so that they can operate in parallel.
103    pub append_lock: RwQueue<FsNodeAppend>,
104
105    /// Mutable information about this node.
106    ///
107    /// This data is used to populate the uapi::stat structure.
108    info: DynamicLockDepRwLock<FsNodeInfo>,
109
110    /// Data associated with an FsNode that is rarely needed.
111    rare_data: OnceLock<Box<FsNodeRareData>>,
112
113    /// Tracks lock state for this file.
114    pub write_guard_state: LockDepMutex<FileWriteGuardState, FsNodeWriteGuardStateLock>,
115
116    /// Cached FsVerity state associated with this node.
117    pub fsverity: LockDepMutex<FsVerityState, FsNodeFsVerityLock>,
118
119    /// The security state associated with this node. Must always be acquired last
120    /// relative to other `FsNode` locks.
121    pub security_state: security::FsNodeState,
122}
123
124#[derive(Default)]
125struct FsNodeRareData {
126    /// The pipe located at this node, if any.
127    ///
128    /// Used if, and only if, the node has a mode of FileMode::IFIFO.
129    fifo: OnceLock<PipeHandle>,
130
131    /// The UNIX domain socket bound to this node, if any.
132    bound_socket: OnceLock<SocketHandle>,
133
134    /// Information about the locking information on this node.
135    ///
136    /// No other lock on this object may be taken while this lock is held.
137    flock_info: LockDepMutex<FlockInfo, FsNodeFlockInfoLock>,
138
139    /// Records locks associated with this node.
140    record_locks: RecordLocks,
141
142    /// Whether this node can be linked into a directory.
143    ///
144    /// Only set for nodes created with `O_TMPFILE`.
145    link_behavior: OnceLock<FsNodeLinkBehavior>,
146
147    /// Inotify watchers on this node. See inotify(7).
148    watchers: inotify_hook::InotifyWatchers,
149}
150
151impl FsNodeRareData {
152    fn ensure_fifo(&self, current_task: &CurrentTask) -> &PipeHandle {
153        self.fifo.get_or_init(|| {
154            let default_pipe_capacity = (*PAGE_SIZE * 16) as usize;
155            let kernel = current_task.kernel();
156            let max_size = kernel.system_limits.pipe_max_size.load(Ordering::Relaxed);
157            let capacity = if default_pipe_capacity <= max_size
158                || security::is_task_capable_noaudit(current_task, CAP_SYS_RESOURCE)
159            {
160                default_pipe_capacity
161            } else {
162                max_size
163            };
164            Pipe::new(capacity)
165        })
166    }
167}
168
169pub enum FsNodeReleaserAction {}
170impl ReleaserAction<FsNode> for FsNodeReleaserAction {
171    fn release(fs_node: ReleaseGuard<FsNode>) {
172        register_delayed_release(fs_node);
173    }
174}
175pub type FsNodeReleaser = ObjectReleaser<FsNode, FsNodeReleaserAction>;
176pub type FsNodeHandle = Arc<FsNodeReleaser>;
177pub type WeakFsNodeHandle = Weak<FsNodeReleaser>;
178
179#[derive(Debug, Default, Clone, PartialEq)]
180pub struct FsNodeInfo {
181    pub mode: FileMode,
182    pub link_count: usize,
183    pub uid: uid_t,
184    pub gid: gid_t,
185    pub rdev: DeviceId,
186    pub size: usize,
187    pub blksize: usize,
188    pub blocks: usize,
189    pub time_status_change: UtcInstant,
190    pub time_access: UtcInstant,
191    pub time_modify: UtcInstant,
192    pub casefold: bool,
193
194    // If this node is fscrypt encrypted, stores the id of the user wrapping key used to encrypt it.
195    pub wrapping_key_id: Option<[u8; 16]>,
196
197    // Used to indicate to filesystems that manage timestamps that an access has occurred and to
198    // update the node's atime.
199    // This only impacts accesses within Starnix. Most Fuchsia programs are not expected to maintain
200    // access times. If the file handle is transferred out of Starnix, there may be inconsistencies.
201    pub pending_time_access_update: bool,
202}
203
204impl FsNodeInfo {
205    pub fn new(mode: FileMode, owner: FsCred) -> Self {
206        let now = utc::utc_now();
207        Self {
208            mode,
209            link_count: if mode.is_dir() { 2 } else { 1 },
210            uid: owner.uid,
211            gid: owner.gid,
212            blksize: DEFAULT_BYTES_PER_BLOCK,
213            time_status_change: now,
214            time_access: now,
215            time_modify: now,
216            ..Default::default()
217        }
218    }
219
220    pub fn storage_size(&self) -> usize {
221        self.blksize.saturating_mul(self.blocks)
222    }
223
224    pub fn chmod(&mut self, mode: FileMode) {
225        self.mode = (self.mode & !FileMode::PERMISSIONS) | (mode & FileMode::PERMISSIONS);
226    }
227
228    pub fn chown(&mut self, owner: Option<uid_t>, group: Option<gid_t>) {
229        if let Some(owner) = owner {
230            self.uid = owner;
231        }
232        if let Some(group) = group {
233            self.gid = group;
234        }
235        // Clear the setuid and setgid bits if the file is executable and a regular file.
236        if self.mode.is_reg() {
237            self.mode &= !FileMode::ISUID;
238            self.clear_sgid_bit();
239        }
240    }
241
242    fn clear_sgid_bit(&mut self) {
243        // If the group execute bit is not set, the setgid bit actually indicates mandatory
244        // locking and should not be cleared.
245        if self.mode.intersects(FileMode::IXGRP) {
246            self.mode &= !FileMode::ISGID;
247        }
248    }
249
250    fn has_suid_or_sgid_bits(&self) -> bool {
251        // ISGID is only considered as setgid bit if IXGRP is present.
252        self.mode.contains(FileMode::ISUID) || self.mode.contains(FileMode::ISGID | FileMode::IXGRP)
253    }
254
255    fn clear_suid_and_sgid_bits(&mut self) {
256        self.mode &= !FileMode::ISUID;
257        self.clear_sgid_bit();
258    }
259
260    pub fn cred(&self) -> FsCred {
261        FsCred { uid: self.uid, gid: self.gid }
262    }
263
264    pub fn apply_suid_and_sgid(&self, creds: &mut Credentials) {
265        if self.mode.contains(FileMode::ISUID) {
266            creds.euid = self.uid;
267        }
268
269        // See <https://man7.org/linux/man-pages/man7/inode.7.html>:
270        //
271        //   For an executable file, the set-group-ID bit causes the
272        //   effective group ID of a process that executes the file to change
273        //   as described in execve(2).  For a file that does not have the
274        //   group execution bit (S_IXGRP) set, the set-group-ID bit indicates
275        //   mandatory file/record locking.
276        if self.mode.contains(FileMode::ISGID | FileMode::IXGRP) {
277            creds.egid = self.gid;
278        }
279    }
280}
281
282#[derive(Default)]
283struct FlockInfo {
284    /// Whether the node is currently locked. The meaning of the different values are:
285    /// - `None`: The node is not locked.
286    /// - `Some(false)`: The node is locked non exclusively.
287    /// - `Some(true)`: The node is locked exclusively.
288    locked_exclusive: Option<bool>,
289    /// The FileObject that hold the lock.
290    locking_handles: Vec<WeakFileHandle>,
291    /// The queue to notify process waiting on the lock.
292    wait_queue: WaitQueue,
293}
294
295impl FlockInfo {
296    /// Removes all file handle not holding `predicate` from the list of object holding the lock. If
297    /// this empties the list, unlocks the node and notifies all waiting processes.
298    pub fn retain<F>(&mut self, predicate: F)
299    where
300        F: Fn(&FileObject) -> bool,
301    {
302        if !self.locking_handles.is_empty() {
303            self.locking_handles
304                .retain(|w| if let Some(fh) = w.upgrade() { predicate(&fh) } else { false });
305            if self.locking_handles.is_empty() {
306                self.locked_exclusive = None;
307                self.wait_queue.notify_all();
308            }
309        }
310    }
311}
312
313/// `st_blksize` is measured in units of 512 bytes.
314pub const DEFAULT_BYTES_PER_BLOCK: usize = 512;
315
316pub struct FlockOperation {
317    operation: u32,
318}
319
320impl FlockOperation {
321    pub fn from_flags(operation: u32) -> Result<Self, Errno> {
322        if operation & !(LOCK_SH | LOCK_EX | LOCK_UN | LOCK_NB) != 0 {
323            return error!(EINVAL);
324        }
325        if [LOCK_SH, LOCK_EX, LOCK_UN].iter().filter(|&&o| operation & o == o).count() != 1 {
326            return error!(EINVAL);
327        }
328        Ok(Self { operation })
329    }
330
331    pub fn is_unlock(&self) -> bool {
332        self.operation & LOCK_UN > 0
333    }
334
335    pub fn is_lock_exclusive(&self) -> bool {
336        self.operation & LOCK_EX > 0
337    }
338
339    pub fn is_blocking(&self) -> bool {
340        self.operation & LOCK_NB == 0
341    }
342}
343
344impl FileObject {
345    /// Advisory locking.
346    ///
347    /// See flock(2).
348    pub fn flock(
349        &self,
350        current_task: &CurrentTask,
351        operation: FlockOperation,
352    ) -> Result<(), Errno> {
353        if self.flags().contains(OpenFlags::PATH) {
354            return error!(EBADF);
355        }
356        security::check_file_lock_access(current_task, self)?;
357        loop {
358            let mut flock_info = self.name.entry.node.ensure_rare_data().flock_info.lock();
359            if operation.is_unlock() {
360                flock_info.retain(|fh| !std::ptr::eq(fh, self));
361                return Ok(());
362            }
363            // Operation is a locking operation.
364            // 1. File is not locked
365            if flock_info.locked_exclusive.is_none() {
366                flock_info.locked_exclusive = Some(operation.is_lock_exclusive());
367                flock_info.locking_handles.push(self.weak_handle.clone());
368                return Ok(());
369            }
370
371            let file_lock_is_exclusive = flock_info.locked_exclusive == Some(true);
372            let fd_has_lock = flock_info
373                .locking_handles
374                .iter()
375                .find_map(|w| {
376                    w.upgrade().and_then(|fh| {
377                        if std::ptr::eq(&fh as &FileObject, self) { Some(()) } else { None }
378                    })
379                })
380                .is_some();
381
382            // 2. File is locked, but fd already have a lock
383            if fd_has_lock {
384                if operation.is_lock_exclusive() == file_lock_is_exclusive {
385                    // Correct lock is already held, return.
386                    return Ok(());
387                } else {
388                    // Incorrect lock is held. Release the lock and loop back to try to reacquire
389                    // it. flock doesn't guarantee atomic lock type switching.
390                    flock_info.retain(|fh| !std::ptr::eq(fh, self));
391                    continue;
392                }
393            }
394
395            // 3. File is locked, and fd doesn't have a lock.
396            if !file_lock_is_exclusive && !operation.is_lock_exclusive() {
397                // The lock is not exclusive, let's grab it.
398                flock_info.locking_handles.push(self.weak_handle.clone());
399                return Ok(());
400            }
401
402            // 4. The operation cannot be done at this time.
403            if !operation.is_blocking() {
404                return error!(EAGAIN);
405            }
406
407            // Register a waiter to be notified when the lock is released. Release the lock on
408            // FlockInfo, and wait.
409            let waiter = Waiter::new();
410            flock_info.wait_queue.wait_async(&waiter);
411            std::mem::drop(flock_info);
412            waiter.wait(current_task)?;
413        }
414    }
415}
416
417// The inner mod is required because bitflags cannot pass the attribute through to the single
418// variant, and attributes cannot be applied to macro invocations.
419mod inner_flags {
420    // Part of the code for the AT_STATX_SYNC_AS_STAT case that's produced by the macro triggers the
421    // lint, but as a whole, the produced code is still correct.
422    #![allow(clippy::bad_bit_mask)] // TODO(b/303500202) Remove once addressed in bitflags.
423    use super::{bitflags, uapi};
424
425    bitflags! {
426        #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
427        pub struct StatxFlags: u32 {
428            const AT_SYMLINK_NOFOLLOW = uapi::AT_SYMLINK_NOFOLLOW;
429            const AT_EMPTY_PATH = uapi::AT_EMPTY_PATH;
430            const AT_NO_AUTOMOUNT = uapi::AT_NO_AUTOMOUNT;
431            const AT_STATX_SYNC_AS_STAT = uapi::AT_STATX_SYNC_AS_STAT;
432            const AT_STATX_FORCE_SYNC = uapi::AT_STATX_FORCE_SYNC;
433            const AT_STATX_DONT_SYNC = uapi::AT_STATX_DONT_SYNC;
434            const STATX_ATTR_VERITY = uapi::STATX_ATTR_VERITY;
435        }
436    }
437}
438
439pub use inner_flags::StatxFlags;
440
441#[derive(Copy, Clone, Debug, PartialEq, Eq)]
442pub enum UnlinkKind {
443    /// Unlink a directory.
444    Directory,
445
446    /// Unlink a non-directory.
447    NonDirectory,
448}
449
450pub enum SymlinkTarget {
451    Path(FsString),
452    Node(NamespaceNode),
453}
454
455#[derive(Clone, Copy, PartialEq, Eq)]
456pub enum XattrOp {
457    /// Set the value of the extended attribute regardless of whether it exists.
458    Set,
459    /// Create a new extended attribute. Fail if it already exists.
460    Create,
461    /// Replace the value of the extended attribute. Fail if it doesn't exist.
462    Replace,
463}
464
465impl XattrOp {
466    pub fn into_flags(self) -> u32 {
467        match self {
468            Self::Set => 0,
469            Self::Create => uapi::XATTR_CREATE,
470            Self::Replace => uapi::XATTR_REPLACE,
471        }
472    }
473}
474
475/// Returns a value, or the size required to contains it.
476#[derive(Clone, Debug, PartialEq)]
477pub enum ValueOrSize<T> {
478    Value(T),
479    Size(usize),
480}
481
482impl<T> ValueOrSize<T> {
483    pub fn map<F, U>(self, f: F) -> ValueOrSize<U>
484    where
485        F: FnOnce(T) -> U,
486    {
487        match self {
488            Self::Size(s) => ValueOrSize::Size(s),
489            Self::Value(v) => ValueOrSize::Value(f(v)),
490        }
491    }
492
493    #[cfg(test)]
494    pub fn unwrap(self) -> T {
495        match self {
496            Self::Size(_) => panic!("Unwrap ValueOrSize that is a Size"),
497            Self::Value(v) => v,
498        }
499    }
500}
501
502impl<T> From<T> for ValueOrSize<T> {
503    fn from(t: T) -> Self {
504        Self::Value(t)
505    }
506}
507
508#[derive(Copy, Clone, Eq, PartialEq, Debug)]
509pub enum FallocMode {
510    Allocate { keep_size: bool },
511    PunchHole,
512    Collapse,
513    Zero { keep_size: bool },
514    InsertRange,
515    UnshareRange,
516}
517
518impl FallocMode {
519    pub fn from_bits(mode: u32) -> Option<Self> {
520        // `fallocate()` allows only the following values for `mode`.
521        if mode == 0 {
522            Some(Self::Allocate { keep_size: false })
523        } else if mode == FALLOC_FL_KEEP_SIZE {
524            Some(Self::Allocate { keep_size: true })
525        } else if mode == FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE {
526            Some(Self::PunchHole)
527        } else if mode == FALLOC_FL_COLLAPSE_RANGE {
528            Some(Self::Collapse)
529        } else if mode == FALLOC_FL_ZERO_RANGE {
530            Some(Self::Zero { keep_size: false })
531        } else if mode == FALLOC_FL_ZERO_RANGE | FALLOC_FL_KEEP_SIZE {
532            Some(Self::Zero { keep_size: true })
533        } else if mode == FALLOC_FL_INSERT_RANGE {
534            Some(Self::InsertRange)
535        } else if mode == FALLOC_FL_UNSHARE_RANGE {
536            Some(Self::UnshareRange)
537        } else {
538            None
539        }
540    }
541}
542
543#[derive(Debug, Copy, Clone, PartialEq)]
544pub enum CheckAccessReason {
545    Access,
546    Chdir,
547    Chroot,
548    Exec,
549    ChangeTimestamps { now: bool },
550    InternalPermissionChecks,
551}
552
553pub type LookupVec<T> = SmallVec<[T; 8]>;
554
555pub trait FsNodeOps: Send + Sync + AsAny + 'static {
556    /// Delegate the access check to the node.
557    fn check_access(
558        &self,
559        node: &FsNode,
560        current_task: &CurrentTask,
561        access: security::PermissionFlags,
562        info: &DynamicLockDepRwLock<FsNodeInfo>,
563        reason: CheckAccessReason,
564        audit_context: security::Auditable<'_>,
565    ) -> Result<(), Errno> {
566        node.default_check_access_impl(current_task, access, reason, info.read(), audit_context)
567    }
568
569    /// Build the [`DirEntryOps`] for a new [`DirEntry`] that will be associated
570    /// to this node.
571    fn create_dir_entry_ops(&self) -> Box<dyn DirEntryOps> {
572        Box::new(DefaultDirEntryOps)
573    }
574
575    /// Build the `FileOps` for the file associated to this node.
576    ///
577    /// The returned FileOps will be used to create a FileObject, which might
578    /// be assigned an FdNumber.
579    fn create_file_ops(
580        &self,
581        node: &FsNode,
582        _current_task: &CurrentTask,
583        flags: OpenFlags,
584    ) -> Result<Box<dyn FileOps>, Errno>;
585
586    /// Find an existing child node and populate the child parameter. Return the node.
587    ///
588    /// The child parameter is an empty node. Operations other than initialize may panic before
589    /// initialize is called.
590    fn lookup(
591        &self,
592        _node: &FsNode,
593        _current_task: &CurrentTask,
594        name: &FsStr,
595    ) -> Result<FsNodeHandle, Errno> {
596        // The default implementation here is suitable for filesystems that have permanent entries;
597        // entries that already exist will get found in the cache and shouldn't get this far.
598        error!(ENOENT, format!("looking for {name}"))
599    }
600
601    /// Returns whether this node supports pipelined lookups.
602    fn has_lookup_pipelined(&self) -> bool {
603        false
604    }
605
606    /// Find multiple children nodes in sequence.
607    ///
608    /// This can be used to pipeline lookups in filesystems that support it.
609    fn lookup_pipelined(
610        &self,
611        _node: &FsNode,
612        _current_task: &CurrentTask,
613        _names: &[&FsStr],
614    ) -> LookupVec<Result<FsNodeHandle, Errno>> {
615        panic!("has_lookup_pipelined should be false");
616    }
617
618    /// Returns whether this node supports casefolded filenames.
619    fn has_casefold_support(&self, _node: &FsNode) -> bool {
620        false
621    }
622
623    /// Create and return the given child node.
624    ///
625    /// The mode field of the FsNodeInfo indicates what kind of child to
626    /// create.
627    ///
628    /// This function is never called with FileMode::IFDIR. The mkdir function
629    /// is used to create directories instead.
630    fn mknod(
631        &self,
632        node: &FsNode,
633        _current_task: &CurrentTask,
634        _name: &FsStr,
635        _mode: FileMode,
636        _dev: DeviceId,
637        _owner: FsCred,
638    ) -> Result<FsNodeHandle, Errno>;
639
640    /// Create and return the given child node as a subdirectory.
641    fn mkdir(
642        &self,
643        node: &FsNode,
644        _current_task: &CurrentTask,
645        _name: &FsStr,
646        _mode: FileMode,
647        _owner: FsCred,
648    ) -> Result<FsNodeHandle, Errno>;
649
650    /// Creates a symlink with the given `target` path.
651    fn create_symlink(
652        &self,
653        node: &FsNode,
654        _current_task: &CurrentTask,
655        _name: &FsStr,
656        _target: &FsStr,
657        _owner: FsCred,
658    ) -> Result<FsNodeHandle, Errno>;
659
660    /// Creates an anonymous file.
661    ///
662    /// The FileMode::IFMT of the FileMode is always FileMode::IFREG.
663    ///
664    /// Used by O_TMPFILE.
665    fn create_tmpfile(
666        &self,
667        _node: &FsNode,
668        _current_task: &CurrentTask,
669        _mode: FileMode,
670        _owner: FsCred,
671    ) -> Result<FsNodeHandle, Errno> {
672        error!(EOPNOTSUPP)
673    }
674
675    /// Reads the symlink from this node.
676    fn readlink(
677        &self,
678        _node: &FsNode,
679        _current_task: &CurrentTask,
680    ) -> Result<SymlinkTarget, Errno> {
681        error!(EINVAL)
682    }
683
684    /// Create a hard link with the given name to the given child.
685    fn link(
686        &self,
687        _node: &FsNode,
688        _current_task: &CurrentTask,
689        _name: &FsStr,
690        _child: &FsNodeHandle,
691    ) -> Result<(), Errno> {
692        error!(EPERM)
693    }
694
695    /// Remove the child with the given name, if the child exists.
696    ///
697    /// The UnlinkKind parameter indicates whether the caller intends to unlink
698    /// a directory or a non-directory child.
699    fn unlink(
700        &self,
701        node: &FsNode,
702        _current_task: &CurrentTask,
703        _name: &FsStr,
704        _child: &FsNodeHandle,
705    ) -> Result<(), Errno>;
706
707    /// Acquire the necessary append lock for the operations that depend on them.
708    /// Should be done before calling `allocate` or `truncate` to avoid lock ordering issues.
709    fn append_lock_read<'a>(
710        &'a self,
711        node: &'a FsNode,
712        current_task: &CurrentTask,
713    ) -> Result<AppendLockGuard<'a>, Errno> {
714        return node.append_lock.read(current_task);
715    }
716
717    /// Acquire the necessary append lock for operations that need exclusive access (e.g., write append).
718    fn append_lock_write<'a>(
719        &'a self,
720        node: &'a FsNode,
721        current_task: &CurrentTask,
722    ) -> Result<AppendLockWriteGuard<'a>, Errno> {
723        return node.append_lock.write(current_task);
724    }
725
726    /// Change the length of the file.
727    fn truncate(
728        &self,
729        _guard: &AppendLockWriteGuard<'_>,
730        _node: &FsNode,
731        _current_task: &CurrentTask,
732        _length: u64,
733    ) -> Result<(), Errno> {
734        error!(EINVAL)
735    }
736
737    /// Manipulate allocated disk space for the file.
738    fn allocate(
739        &self,
740        _guard: &AppendLockWriteGuard<'_>,
741        _node: &FsNode,
742        _current_task: &CurrentTask,
743        _mode: FallocMode,
744        _offset: u64,
745        _length: u64,
746    ) -> Result<(), Errno> {
747        error!(EINVAL)
748    }
749
750    /// Update the supplied info with initial state (e.g. size) for the node.
751    ///
752    /// FsNode calls this method when created, to allow the FsNodeOps to
753    /// set appropriate initial values in the FsNodeInfo.
754    fn initial_info(&self, _info: &mut FsNodeInfo) {}
755
756    /// Update node.info as needed.
757    ///
758    /// FsNode calls this method before converting the FsNodeInfo struct into
759    /// the uapi::stat struct to give the file system a chance to update this data
760    /// before it is used by clients.
761    ///
762    /// File systems that keep the FsNodeInfo up-to-date do not need to
763    /// override this function.
764    ///
765    /// Return a read guard for the updated information.
766    fn fetch_and_refresh_info<'a>(
767        &self,
768        _node: &FsNode,
769        _current_task: &CurrentTask,
770        info: &'a DynamicLockDepRwLock<FsNodeInfo>,
771    ) -> Result<LockDepReadGuard<'a, FsNodeInfo>, Errno> {
772        Ok(info.read())
773    }
774
775    /// Syncs cached data to persistent storage.
776    fn sync(&self, _node: &FsNode, _current_task: &CurrentTask) -> Result<(), Errno> {
777        Ok(())
778    }
779
780    /// Update node attributes persistently.
781    fn update_attributes(
782        &self,
783        _node: &FsNode,
784        _current_task: &CurrentTask,
785        _info: &FsNodeInfo,
786        _has: zxio_node_attr_has_t,
787    ) -> Result<(), Errno> {
788        Ok(())
789    }
790
791    /// Get an extended attribute on the node.
792    ///
793    /// An implementation can systematically return a value. Otherwise, if `max_size` is 0, it can
794    /// instead return the size of the attribute, and can return an ERANGE error if max_size is not
795    /// 0, and lesser than the required size.
796    fn get_xattr(
797        &self,
798        _node: &FsNode,
799        _current_task: &CurrentTask,
800        _name: &FsStr,
801        _max_size: usize,
802    ) -> Result<ValueOrSize<FsString>, Errno> {
803        error!(ENOTSUP)
804    }
805
806    /// Set an extended attribute on the node.
807    fn set_xattr(
808        &self,
809        _node: &FsNode,
810        _current_task: &CurrentTask,
811        _name: &FsStr,
812        _value: &FsStr,
813        _op: XattrOp,
814    ) -> Result<(), Errno> {
815        error!(ENOTSUP)
816    }
817
818    fn remove_xattr(
819        &self,
820        _node: &FsNode,
821        _current_task: &CurrentTask,
822        _name: &FsStr,
823    ) -> Result<(), Errno> {
824        error!(ENOTSUP)
825    }
826
827    /// An implementation can systematically return a value. Otherwise, if `max_size` is 0, it can
828    /// instead return the size of the 0 separated string needed to represent the value, and can
829    /// return an ERANGE error if max_size is not 0, and lesser than the required size.
830    fn list_xattrs(
831        &self,
832        _node: &FsNode,
833        _current_task: &CurrentTask,
834        _max_size: usize,
835    ) -> Result<ValueOrSize<Vec<FsString>>, Errno> {
836        error!(ENOTSUP)
837    }
838
839    /// Called when the FsNode is freed by the Kernel.
840    fn forget(
841        self: Box<Self>,
842        _current_task: &CurrentTask,
843        _info: FsNodeInfo,
844    ) -> Result<(), Errno> {
845        Ok(())
846    }
847
848    ////////////////////
849    // FS-Verity operations
850
851    /// Marks that FS-Verity is being built. Writes fsverity descriptor and merkle tree, the latter
852    /// computed by the filesystem.
853    /// This should ensure there are no writable file handles. Returns EEXIST if the file was
854    /// already fsverity-enabled. Returns EBUSY if this ioctl was already running on this file.
855    fn enable_fsverity(
856        &self,
857        _node: &FsNode,
858        _current_task: &CurrentTask,
859        _descriptor: &fsverity_descriptor,
860    ) -> Result<(), Errno> {
861        error!(ENOTSUP)
862    }
863
864    /// Read fsverity descriptor, if the node is fsverity-enabled. Else returns ENODATA.
865    fn get_fsverity_descriptor(&self, _log_blocksize: u8) -> Result<fsverity_descriptor, Errno> {
866        error!(ENOTSUP)
867    }
868
869    /// The key used to identify this node in the file system's node cache.
870    ///
871    /// For many file systems, this will be the same as the inode number. However, some file
872    /// systems, such as FUSE, sometimes use different `node_key` and inode numbers.
873    fn node_key(&self, node: &FsNode) -> ino_t {
874        node.ino
875    }
876
877    /// Returns the size of the file.
878    fn get_size(&self, node: &FsNode, current_task: &CurrentTask) -> Result<usize, Errno> {
879        let info = node.fetch_and_refresh_info(current_task)?;
880        Ok(info.size.try_into().map_err(|_| errno!(EINVAL))?)
881    }
882}
883
884impl<T> From<T> for Box<dyn FsNodeOps>
885where
886    T: FsNodeOps,
887{
888    fn from(ops: T) -> Box<dyn FsNodeOps> {
889        Box::new(ops)
890    }
891}
892
893/// Implements [`FsNodeOps`] methods in a way that makes sense for symlinks.
894/// You must implement [`FsNodeOps::readlink`].
895#[macro_export]
896macro_rules! fs_node_impl_symlink {
897    () => {
898        $crate::vfs::fs_node_impl_not_dir!();
899
900        fn create_file_ops(
901            &self,
902            node: &$crate::vfs::FsNode,
903            _current_task: &CurrentTask,
904            _flags: starnix_uapi::open_flags::OpenFlags,
905        ) -> Result<Box<dyn $crate::vfs::FileOps>, starnix_uapi::errors::Errno> {
906            assert!(node.is_lnk());
907            unreachable!("Symlink nodes cannot be opened.");
908        }
909    };
910}
911
912#[macro_export]
913macro_rules! fs_node_impl_dir_readonly {
914    () => {
915        fn check_access(
916            &self,
917            node: &$crate::vfs::FsNode,
918            current_task: &$crate::task::CurrentTask,
919            permission_flags: $crate::security::PermissionFlags,
920            info: &starnix_sync::DynamicLockDepRwLock<$crate::vfs::FsNodeInfo>,
921            reason: $crate::vfs::CheckAccessReason,
922            audit_context: $crate::security::Auditable<'_>,
923        ) -> Result<(), starnix_uapi::errors::Errno> {
924            let access = permission_flags.as_access();
925            if access.contains(starnix_uapi::file_mode::Access::WRITE) {
926                return starnix_uapi::error!(
927                    EROFS,
928                    format!("check_access failed: read-only directory")
929                );
930            }
931            node.default_check_access_impl(
932                current_task,
933                permission_flags,
934                reason,
935                info.read(),
936                audit_context,
937            )
938        }
939
940        fn mkdir(
941            &self,
942            _node: &$crate::vfs::FsNode,
943            _current_task: &$crate::task::CurrentTask,
944            name: &$crate::vfs::FsStr,
945            _mode: starnix_uapi::file_mode::FileMode,
946            _owner: starnix_uapi::auth::FsCred,
947        ) -> Result<$crate::vfs::FsNodeHandle, starnix_uapi::errors::Errno> {
948            starnix_uapi::error!(EROFS, format!("mkdir failed: {:?}", name))
949        }
950
951        fn mknod(
952            &self,
953            _node: &$crate::vfs::FsNode,
954            _current_task: &$crate::task::CurrentTask,
955            name: &$crate::vfs::FsStr,
956            _mode: starnix_uapi::file_mode::FileMode,
957            _dev: starnix_uapi::device_id::DeviceId,
958            _owner: starnix_uapi::auth::FsCred,
959        ) -> Result<$crate::vfs::FsNodeHandle, starnix_uapi::errors::Errno> {
960            starnix_uapi::error!(EROFS, format!("mknod failed: {:?}", name))
961        }
962
963        fn create_symlink(
964            &self,
965            _node: &$crate::vfs::FsNode,
966            _current_task: &$crate::task::CurrentTask,
967            name: &$crate::vfs::FsStr,
968            _target: &$crate::vfs::FsStr,
969            _owner: starnix_uapi::auth::FsCred,
970        ) -> Result<$crate::vfs::FsNodeHandle, starnix_uapi::errors::Errno> {
971            starnix_uapi::error!(EROFS, format!("symlink failed: {:?}", name))
972        }
973
974        fn link(
975            &self,
976            _node: &$crate::vfs::FsNode,
977            _current_task: &$crate::task::CurrentTask,
978            name: &$crate::vfs::FsStr,
979            _child: &$crate::vfs::FsNodeHandle,
980        ) -> Result<(), starnix_uapi::errors::Errno> {
981            starnix_uapi::error!(EROFS, format!("link failed: {:?}", name))
982        }
983
984        fn unlink(
985            &self,
986            _node: &$crate::vfs::FsNode,
987            _current_task: &$crate::task::CurrentTask,
988            name: &$crate::vfs::FsStr,
989            _child: &$crate::vfs::FsNodeHandle,
990        ) -> Result<(), starnix_uapi::errors::Errno> {
991            starnix_uapi::error!(EROFS, format!("unlink failed: {:?}", name))
992        }
993    };
994}
995
996/// Trait that objects can implement if they need to handle extended attribute storage. Allows
997/// delegating extended attribute operations in [`FsNodeOps`] to another object.
998///
999/// See [`fs_node_impl_xattr_delegate`] for usage details.
1000pub trait XattrStorage {
1001    /// Delegate for [`FsNodeOps::get_xattr`].
1002    fn get_xattr(&self, name: &FsStr) -> Result<FsString, Errno>;
1003
1004    /// Delegate for [`FsNodeOps::set_xattr`].
1005    fn set_xattr(&self, name: &FsStr, value: &FsStr, op: XattrOp) -> Result<(), Errno>;
1006
1007    /// Delegate for [`FsNodeOps::remove_xattr`].
1008    fn remove_xattr(&self, name: &FsStr) -> Result<(), Errno>;
1009
1010    /// Delegate for [`FsNodeOps::list_xattrs`].
1011    fn list_xattrs(&self) -> Result<Vec<FsString>, Errno>;
1012}
1013
1014/// Implements extended attribute ops for [`FsNodeOps`] by delegating to another object which
1015/// implements the [`XattrStorage`] trait or a similar interface. For example:
1016///
1017/// ```
1018/// struct Xattrs {}
1019///
1020/// impl XattrStorage for Xattrs {
1021///     // implement XattrStorage
1022/// }
1023///
1024/// struct Node {
1025///     xattrs: Xattrs
1026/// }
1027///
1028/// impl FsNodeOps for Node {
1029///     // Delegate extended attribute ops in FsNodeOps to self.xattrs
1030///     fs_node_impl_xattr_delegate!(self, self.xattrs);
1031///
1032///     // add other FsNodeOps impls here
1033/// }
1034/// ```
1035#[macro_export]
1036macro_rules! fs_node_impl_xattr_delegate {
1037    ($self:ident, $delegate:expr) => {
1038        fn get_xattr(
1039            &$self,
1040            _node: &FsNode,
1041            _current_task: &CurrentTask,
1042            name: &$crate::vfs::FsStr,
1043            _size: usize,
1044        ) -> Result<$crate::vfs::ValueOrSize<$crate::vfs::FsString>, starnix_uapi::errors::Errno> {
1045            Ok($delegate.get_xattr(name)?.into())
1046        }
1047
1048        fn set_xattr(
1049            &$self,
1050            _node: &FsNode,
1051            _current_task: &CurrentTask,
1052            name: &$crate::vfs::FsStr,
1053            value: &$crate::vfs::FsStr,
1054            op: $crate::vfs::XattrOp,
1055        ) -> Result<(), starnix_uapi::errors::Errno> {
1056            $delegate.set_xattr(name, value, op)
1057        }
1058
1059        fn remove_xattr(
1060            &$self,
1061            _node: &FsNode,
1062            _current_task: &CurrentTask,
1063            name: &$crate::vfs::FsStr,
1064        ) -> Result<(), starnix_uapi::errors::Errno> {
1065            $delegate.remove_xattr(name)
1066        }
1067
1068        fn list_xattrs(
1069            &$self,
1070            _node: &FsNode,
1071            _current_task: &CurrentTask,
1072            _size: usize,
1073        ) -> Result<$crate::vfs::ValueOrSize<Vec<$crate::vfs::FsString>>, starnix_uapi::errors::Errno> {
1074            Ok($delegate.list_xattrs()?.into())
1075        }
1076    };
1077}
1078
1079/// Stubs out [`FsNodeOps`] methods that only apply to directories.
1080#[macro_export]
1081macro_rules! fs_node_impl_not_dir {
1082    () => {
1083        fn lookup(
1084            &self,
1085            _node: &$crate::vfs::FsNode,
1086            _current_task: &$crate::task::CurrentTask,
1087            _name: &$crate::vfs::FsStr,
1088        ) -> Result<$crate::vfs::FsNodeHandle, starnix_uapi::errors::Errno> {
1089            starnix_uapi::error!(ENOTDIR)
1090        }
1091
1092        fn mknod(
1093            &self,
1094            _node: &$crate::vfs::FsNode,
1095            _current_task: &$crate::task::CurrentTask,
1096            _name: &$crate::vfs::FsStr,
1097            _mode: starnix_uapi::file_mode::FileMode,
1098            _dev: starnix_uapi::device_id::DeviceId,
1099            _owner: starnix_uapi::auth::FsCred,
1100        ) -> Result<$crate::vfs::FsNodeHandle, starnix_uapi::errors::Errno> {
1101            starnix_uapi::error!(ENOTDIR)
1102        }
1103
1104        fn mkdir(
1105            &self,
1106            _node: &$crate::vfs::FsNode,
1107            _current_task: &$crate::task::CurrentTask,
1108            _name: &$crate::vfs::FsStr,
1109            _mode: starnix_uapi::file_mode::FileMode,
1110            _owner: starnix_uapi::auth::FsCred,
1111        ) -> Result<$crate::vfs::FsNodeHandle, starnix_uapi::errors::Errno> {
1112            starnix_uapi::error!(ENOTDIR)
1113        }
1114
1115        fn create_symlink(
1116            &self,
1117            _node: &$crate::vfs::FsNode,
1118            _current_task: &$crate::task::CurrentTask,
1119            _name: &$crate::vfs::FsStr,
1120            _target: &$crate::vfs::FsStr,
1121            _owner: starnix_uapi::auth::FsCred,
1122        ) -> Result<$crate::vfs::FsNodeHandle, starnix_uapi::errors::Errno> {
1123            starnix_uapi::error!(ENOTDIR)
1124        }
1125
1126        fn unlink(
1127            &self,
1128            _node: &$crate::vfs::FsNode,
1129            _current_task: &$crate::task::CurrentTask,
1130            _name: &$crate::vfs::FsStr,
1131            _child: &$crate::vfs::FsNodeHandle,
1132        ) -> Result<(), starnix_uapi::errors::Errno> {
1133            starnix_uapi::error!(ENOTDIR)
1134        }
1135    };
1136}
1137
1138#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1139pub enum TimeUpdateType {
1140    Now,
1141    Omit,
1142    Time(UtcInstant),
1143}
1144
1145// Public re-export of macros allows them to be used like regular rust items.
1146pub use fs_node_impl_dir_readonly;
1147pub use fs_node_impl_not_dir;
1148pub use fs_node_impl_symlink;
1149pub use fs_node_impl_xattr_delegate;
1150
1151pub struct SpecialNode;
1152
1153impl FsNodeOps for SpecialNode {
1154    fs_node_impl_not_dir!();
1155
1156    fn create_file_ops(
1157        &self,
1158        _node: &FsNode,
1159        _current_task: &CurrentTask,
1160        _flags: OpenFlags,
1161    ) -> Result<Box<dyn FileOps>, Errno> {
1162        unreachable!("Special nodes cannot be opened.");
1163    }
1164}
1165
1166impl FsNode {
1167    /// Returns true if the `fs_node` is private to the `Kernel`/`FileSystem`, in which
1168    /// case both MAC and DAC checks should be skipped.
1169    pub fn is_private(&self) -> bool {
1170        self.flags.contains(FsNodeFlags::IS_PRIVATE)
1171    }
1172
1173    /// Create a node without inserting it into the FileSystem node cache.
1174    ///
1175    /// This is usually not what you want!
1176    /// Only use if you're also using get_or_create_node, like ext4.
1177    pub fn new_uncached(
1178        ino: ino_t,
1179        ops: impl Into<Box<dyn FsNodeOps>>,
1180        fs: &FileSystemHandle,
1181        info: FsNodeInfo,
1182        flags: FsNodeFlags,
1183    ) -> FsNodeHandle {
1184        let ops = ops.into();
1185        FsNodeHandle::new(Self::new_internal(ino, ops, Arc::downgrade(fs), info, flags).into())
1186    }
1187
1188    fn new_internal(
1189        ino: ino_t,
1190        ops: Box<dyn FsNodeOps>,
1191        fs: Weak<FileSystem>,
1192        info: FsNodeInfo,
1193        flags: FsNodeFlags,
1194    ) -> Self {
1195        // Allow the FsNodeOps to populate initial info.
1196        let mut info = info;
1197        ops.initial_info(&mut info);
1198
1199        let fs_lockdep_type =
1200            fs.upgrade().map(|fs| fs.fs_lockdep_type()).unwrap_or(FsLockDepType::Normal);
1201        let info_lock = match fs_lockdep_type {
1202            FsLockDepType::Normal => DynamicLockDepRwLock::new::<FsNodeInfoLevel>(info),
1203            FsLockDepType::Fuse => DynamicLockDepRwLock::new::<FuseFsNodeInfoLevel>(info),
1204            FsLockDepType::Recursive => DynamicLockDepRwLock::new::<FsNodeInfoRecursiveLevel>(info),
1205        };
1206
1207        // The linter will fail in non test mode as it will not see the lock check.
1208        #[allow(clippy::let_and_return)]
1209        {
1210            let result = Self {
1211                ino,
1212                flags,
1213                ops,
1214                fs,
1215                info: info_lock,
1216                append_lock: Default::default(),
1217                rare_data: Default::default(),
1218                write_guard_state: Default::default(),
1219                fsverity: Default::default(),
1220                security_state: Default::default(),
1221            };
1222            #[cfg(any(test, debug_assertions))]
1223            {
1224                let _l1 = result.append_lock.read_for_lock_ordering();
1225                let _l2 = result.info.read();
1226                let _l3 = result.write_guard_state.lock();
1227                let _l4 = result.fsverity.lock();
1228            }
1229            result
1230        }
1231    }
1232
1233    pub fn fs(&self) -> FileSystemHandle {
1234        self.fs.upgrade().expect("FileSystem did not live long enough")
1235    }
1236
1237    pub fn ops(&self) -> &dyn FsNodeOps {
1238        self.ops.as_ref()
1239    }
1240
1241    /// Returns an error if this node is encrypted and locked. Does not require
1242    /// fetch_and_refresh_info because FS_IOC_SET_ENCRYPTION_POLICY updates info and once a node is
1243    /// encrypted, it remains encrypted forever.
1244    pub fn fail_if_locked(
1245        &self,
1246        _current_task: &CurrentTask,
1247        node_info: &FsNodeInfo,
1248    ) -> Result<(), Errno> {
1249        if let Some(wrapping_key_id) = node_info.wrapping_key_id {
1250            let crypt_service = self.fs().crypt_service().ok_or_else(|| errno!(ENOKEY))?;
1251            if !crypt_service.contains_key(EncryptionKeyId::from(wrapping_key_id)) {
1252                return error!(ENOKEY);
1253            }
1254        }
1255        Ok(())
1256    }
1257
1258    /// Returns the `FsNode`'s `FsNodeOps` as a `&T`, or `None` if the downcast fails.
1259    pub fn downcast_ops<T>(&self) -> Option<&T>
1260    where
1261        T: 'static,
1262    {
1263        self.ops().as_any().downcast_ref::<T>()
1264    }
1265
1266    pub fn on_file_closed(&self, file: &FileObjectState) {
1267        if let Some(rare_data) = self.rare_data.get() {
1268            let mut flock_info = rare_data.flock_info.lock();
1269            // This function will drop the flock from `file` because the `WeakFileHandle` for
1270            // `file` will no longer upgrade to an `FileHandle`.
1271            flock_info.retain(|_| true);
1272        }
1273        self.record_lock_release(RecordLockOwner::FileObject(file.id));
1274    }
1275
1276    pub fn record_lock(
1277        &self,
1278        current_task: &CurrentTask,
1279        file: &FileObject,
1280        cmd: RecordLockCommand,
1281        flock: uapi::flock,
1282    ) -> Result<Option<uapi::flock>, Errno> {
1283        self.ensure_rare_data().record_locks.lock(current_task, file, cmd, flock)
1284    }
1285
1286    /// Release all record locks acquired by the given owner.
1287    pub fn record_lock_release(&self, owner: RecordLockOwner) {
1288        if let Some(rare_data) = self.rare_data.get() {
1289            rare_data.record_locks.release_locks(owner);
1290        }
1291    }
1292
1293    pub fn create_dir_entry_ops(&self) -> Box<dyn DirEntryOps> {
1294        self.ops().create_dir_entry_ops()
1295    }
1296
1297    pub fn create_file_ops(
1298        &self,
1299        current_task: &CurrentTask,
1300        flags: OpenFlags,
1301    ) -> Result<Box<dyn FileOps>, Errno> {
1302        self.ops().create_file_ops(self, current_task, flags)
1303    }
1304
1305    pub fn open(
1306        &self,
1307        current_task: &CurrentTask,
1308        namespace_node: &NamespaceNode,
1309        flags: OpenFlags,
1310        access_check: AccessCheck,
1311    ) -> Result<Box<dyn FileOps>, Errno> {
1312        // If O_PATH is set, there is no need to create a real FileOps because
1313        // most file operations are disabled.
1314        if flags.contains(OpenFlags::PATH) {
1315            return Ok(Box::new(OPathOps::new()));
1316        }
1317
1318        let access = access_check.resolve(flags);
1319        if access.is_nontrivial() {
1320            if flags.contains(OpenFlags::NOATIME) {
1321                self.check_o_noatime_allowed(current_task)?;
1322            }
1323
1324            // `flags` doesn't contain any information about the EXEC permission. Instead the syscalls
1325            // used to execute a file (`sys_execve` and `sys_execveat`) call `open()` with the EXEC
1326            // permission request in `access`.
1327            let mut permission_flags = PermissionFlags::from(access);
1328
1329            // The `APPEND` flag exists only in `flags`, to modify the behaviour of
1330            // `PermissionFlags::WRITE`
1331            if flags.contains(OpenFlags::APPEND) {
1332                permission_flags |= security::PermissionFlags::APPEND;
1333            }
1334
1335            self.check_access(
1336                current_task,
1337                &namespace_node.mount,
1338                permission_flags,
1339                CheckAccessReason::InternalPermissionChecks,
1340                namespace_node,
1341            )?;
1342        }
1343
1344        let (mode, rdev) = {
1345            // Don't hold the info lock while calling into open_device or self.ops().
1346            // TODO: The mode and rdev are immutable and shouldn't require a lock to read.
1347            let info = self.info();
1348            (info.mode, info.rdev)
1349        };
1350
1351        match mode & FileMode::IFMT {
1352            FileMode::IFCHR => {
1353                if namespace_node.mount.flags().contains(MountFlags::NODEV) {
1354                    return error!(EACCES);
1355                }
1356                current_task.kernel().open_device(
1357                    current_task,
1358                    namespace_node,
1359                    flags,
1360                    rdev,
1361                    DeviceMode::Char,
1362                )
1363            }
1364            FileMode::IFBLK => {
1365                if namespace_node.mount.flags().contains(MountFlags::NODEV) {
1366                    return error!(EACCES);
1367                }
1368                current_task.kernel().open_device(
1369                    current_task,
1370                    namespace_node,
1371                    flags,
1372                    rdev,
1373                    DeviceMode::Block,
1374                )
1375            }
1376            FileMode::IFIFO => Pipe::open(current_task, self.fifo(current_task), flags),
1377            // UNIX domain sockets can't be opened.
1378            FileMode::IFSOCK => error!(ENXIO),
1379            _ => self.create_file_ops(current_task, flags),
1380        }
1381    }
1382
1383    pub fn lookup(
1384        &self,
1385        current_task: &CurrentTask,
1386        mount: &MountInfo,
1387        name: &FsStr,
1388    ) -> Result<FsNodeHandle, Errno> {
1389        self.check_access(
1390            current_task,
1391            mount,
1392            Access::EXEC,
1393            CheckAccessReason::InternalPermissionChecks,
1394            &[Auditable::Name(name), std::panic::Location::caller().into()],
1395        )?;
1396        self.ops().lookup(self, current_task, name)
1397    }
1398
1399    pub fn create_node(
1400        &self,
1401        current_task: &CurrentTask,
1402        mount: &MountInfo,
1403        name: &FsStr,
1404        mut mode: FileMode,
1405        dev: DeviceId,
1406        mut owner: FsCred,
1407    ) -> Result<FsNodeHandle, Errno> {
1408        assert!(
1409            !matches!(mode.fmt(), FileMode::EMPTY | FileMode::IFLNK),
1410            "create_node with missing or symlink node type"
1411        );
1412
1413        self.check_access(
1414            current_task,
1415            mount,
1416            Access::WRITE,
1417            CheckAccessReason::InternalPermissionChecks,
1418            security::Auditable::Name(name),
1419        )?;
1420
1421        if mode.is_dir() {
1422            // Even though the man page for mknod(2) says that mknod "cannot be used to create
1423            // directories" in starnix the mkdir syscall (`sys_mkdirat`) ends up calling
1424            // create_node.
1425            security::check_fs_node_mkdir_access(current_task, self, mode, name)?;
1426        } else {
1427            // https://man7.org/linux/man-pages/man2/mknod.2.html says on error EPERM:
1428            //
1429            //   mode requested creation of something other than a regular
1430            //   file, FIFO (named pipe), or UNIX domain socket, and the
1431            //   caller is not privileged (Linux: does not have the
1432            //   CAP_MKNOD capability); also returned if the filesystem
1433            //   containing pathname does not support the type of node
1434            //   requested.
1435            match mode.fmt() {
1436                FileMode::IFREG | FileMode::IFIFO | FileMode::IFSOCK => (),
1437                FileMode::IFCHR if dev == DeviceId::NONE => (),
1438                _ => security::check_task_capable(current_task, CAP_MKNOD)?,
1439            }
1440
1441            if mode.is_reg() {
1442                security::check_fs_node_create_access(current_task, self, mode, name)?;
1443            } else {
1444                security::check_fs_node_mknod_access(current_task, self, mode, name, dev)?;
1445            }
1446        }
1447
1448        // Propagate sticky bit(s) from parent directory to the child.
1449        self.update_metadata_for_child(current_task, &mut mode, &mut owner);
1450
1451        // Delegate to the `ops` implementation to actually create the node.
1452        let new_node = if mode.is_dir() {
1453            self.ops().mkdir(self, current_task, name, mode, owner)?
1454        } else {
1455            self.ops().mknod(self, current_task, name, mode, dev, owner)?
1456        };
1457
1458        // Allow the LSM to apply a security label to the new node.
1459        self.init_new_node_security_on_create(current_task, &new_node, name)?;
1460
1461        Ok(new_node)
1462    }
1463
1464    pub fn create_symlink(
1465        &self,
1466        current_task: &CurrentTask,
1467        mount: &MountInfo,
1468        name: &FsStr,
1469        target: &FsStr,
1470        owner: FsCred,
1471    ) -> Result<FsNodeHandle, Errno> {
1472        self.check_access(
1473            current_task,
1474            mount,
1475            Access::WRITE,
1476            CheckAccessReason::InternalPermissionChecks,
1477            security::Auditable::Name(name),
1478        )?;
1479        security::check_fs_node_symlink_access(current_task, self, name, target)?;
1480
1481        let new_node = self.ops().create_symlink(self, current_task, name, target, owner)?;
1482
1483        self.init_new_node_security_on_create(current_task, &new_node, name)?;
1484
1485        Ok(new_node)
1486    }
1487
1488    /// Requests that the LSM initialise a security label for the `new_node`, and optionally provide
1489    /// an extended attribute to write to the file to persist it.  If no LSM is enabled, no extended
1490    /// attribute returned, or if the filesystem does not support extended attributes, then the call
1491    /// returns success. All other failure modes return an `Errno` that should be early-returned.
1492    fn init_new_node_security_on_create(
1493        &self,
1494        current_task: &CurrentTask,
1495        new_node: &FsNode,
1496        name: &FsStr,
1497    ) -> Result<(), Errno> {
1498        security::fs_node_init_on_create(current_task, &new_node, self, name)?
1499            .map(|xattr| {
1500                match new_node.ops().set_xattr(
1501                    &new_node,
1502                    current_task,
1503                    xattr.name,
1504                    xattr.value.as_slice().into(),
1505                    XattrOp::Create,
1506                ) {
1507                    Err(e) => {
1508                        if e.code == ENOTSUP {
1509                            // This should only occur if a task has an "fscreate" context set, and
1510                            // creates a new file in a filesystem that does not support xattrs.
1511                            Ok(())
1512                        } else {
1513                            Err(e)
1514                        }
1515                    }
1516                    result => result,
1517                }
1518            })
1519            .unwrap_or_else(|| Ok(()))
1520    }
1521
1522    pub fn create_tmpfile(
1523        &self,
1524        current_task: &CurrentTask,
1525        mount: &MountInfo,
1526        mut mode: FileMode,
1527        mut owner: FsCred,
1528        link_behavior: FsNodeLinkBehavior,
1529    ) -> Result<FsNodeHandle, Errno> {
1530        self.check_access(
1531            current_task,
1532            mount,
1533            Access::WRITE,
1534            CheckAccessReason::InternalPermissionChecks,
1535            security::Auditable::Location(std::panic::Location::caller()),
1536        )?;
1537        self.update_metadata_for_child(current_task, &mut mode, &mut owner);
1538        let node = self.ops().create_tmpfile(self, current_task, mode, owner)?;
1539        self.init_new_node_security_on_create(current_task, &node, "".into())?;
1540        if link_behavior == FsNodeLinkBehavior::Disallowed {
1541            node.ensure_rare_data().link_behavior.set(link_behavior).unwrap();
1542        }
1543        Ok(node)
1544    }
1545
1546    // This method does not attempt to update the atime of the node.
1547    // Use `NamespaceNode::readlink` which checks the mount flags and updates the atime accordingly.
1548    pub fn readlink(&self, current_task: &CurrentTask) -> Result<SymlinkTarget, Errno> {
1549        // TODO: 378864856 - Is there a permission check here other than security checks?
1550        security::check_fs_node_read_link_access(current_task, self)?;
1551        self.ops().readlink(self, current_task)
1552    }
1553
1554    pub fn link(
1555        &self,
1556        current_task: &CurrentTask,
1557        mount: &MountInfo,
1558        name: &FsStr,
1559        child: &FsNodeHandle,
1560    ) -> Result<FsNodeHandle, Errno> {
1561        self.check_access(
1562            current_task,
1563            mount,
1564            Access::WRITE,
1565            CheckAccessReason::InternalPermissionChecks,
1566            security::Auditable::Location(std::panic::Location::caller()),
1567        )?;
1568
1569        if child.is_dir() {
1570            return error!(EPERM);
1571        }
1572
1573        if let Some(child_rare_data) = child.rare_data.get() {
1574            if matches!(child_rare_data.link_behavior.get(), Some(FsNodeLinkBehavior::Disallowed)) {
1575                return error!(ENOENT);
1576            }
1577        }
1578
1579        // Check that `current_task` has permission to create the hard link.
1580        //
1581        // See description of /proc/sys/fs/protected_hardlinks in
1582        // https://man7.org/linux/man-pages/man5/proc.5.html for details of the security
1583        // vulnerabilities.
1584        //
1585        let (child_uid, mode) = {
1586            let info = child.info();
1587            (info.uid, info.mode)
1588        };
1589        // Check that the the filesystem UID of the calling process (`current_task`) is the same as
1590        // the UID of the existing file. The check can be bypassed if the calling process has
1591        // `CAP_FOWNER` capability.
1592        if child_uid != current_task.current_creds().fsuid
1593            && !security::is_task_capable_noaudit(current_task, CAP_FOWNER)
1594        {
1595            // If current_task is not the user of the existing file, it needs to have read and write
1596            // access to the existing file.
1597            child
1598                .check_access(
1599                    current_task,
1600                    mount,
1601                    Access::READ | Access::WRITE,
1602                    CheckAccessReason::InternalPermissionChecks,
1603                    security::Auditable::Name(name),
1604                )
1605                .map_err(|e| {
1606                    // `check_access(..)` returns EACCES when the access rights doesn't match - change
1607                    // it to EPERM to match Linux standards.
1608                    if e == EACCES { errno!(EPERM) } else { e }
1609                })?;
1610            // There are also security issues that may arise when users link to setuid, setgid, or
1611            // special files.
1612            if mode.contains(FileMode::ISGID | FileMode::IXGRP) {
1613                return error!(EPERM);
1614            };
1615            if mode.contains(FileMode::ISUID) {
1616                return error!(EPERM);
1617            };
1618            if !mode.contains(FileMode::IFREG) {
1619                return error!(EPERM);
1620            };
1621        }
1622
1623        security::check_fs_node_link_access(current_task, self, child)?;
1624
1625        self.ops().link(self, current_task, name, child)?;
1626        Ok(child.clone())
1627    }
1628
1629    pub fn unlink(
1630        &self,
1631        current_task: &CurrentTask,
1632        mount: &MountInfo,
1633        name: &FsStr,
1634        child: &FsNodeHandle,
1635    ) -> Result<(), Errno> {
1636        // The user must be able to search and write to the directory.
1637        self.check_access(
1638            current_task,
1639            mount,
1640            Access::EXEC | Access::WRITE,
1641            CheckAccessReason::InternalPermissionChecks,
1642            security::Auditable::Name(name),
1643        )?;
1644        {
1645            let parent_info = self.info();
1646            // Safe because we acquire the parent directory lock first, and then the child lock
1647            // inside check_sticky_bit. This parent -> child acquisition follows the
1648            // hierarchical lock ordering.
1649            let _token = allow_subclass();
1650            self.check_sticky_bit(current_task, child, &parent_info)?;
1651        }
1652        if child.is_dir() {
1653            security::check_fs_node_rmdir_access(current_task, self, child, name)?;
1654        } else {
1655            security::check_fs_node_unlink_access(current_task, self, child, name)?;
1656        }
1657        self.ops().unlink(self, current_task, name, child)?;
1658        self.update_ctime_mtime();
1659        Ok(())
1660    }
1661
1662    pub fn truncate(
1663        &self,
1664        current_task: &CurrentTask,
1665        mount: &MountInfo,
1666        length: u64,
1667    ) -> Result<(), Errno> {
1668        if self.is_dir() {
1669            return error!(EISDIR);
1670        }
1671        self.check_access(
1672            current_task,
1673            mount,
1674            Access::WRITE,
1675            CheckAccessReason::InternalPermissionChecks,
1676            security::Auditable::Location(std::panic::Location::caller()),
1677        )?;
1678
1679        let guard = self.ops().append_lock_write(self, current_task)?;
1680        self.truncate_locked(&guard, current_task, length)
1681    }
1682
1683    /// Avoid calling this method directly. You probably want to call `FileObject::ftruncate()`
1684    /// which will also perform all file-descriptor based verifications.
1685    pub fn ftruncate(&self, current_task: &CurrentTask, length: u64) -> Result<(), Errno> {
1686        if self.is_dir() {
1687            // When truncating a file descriptor, if the descriptor references a directory,
1688            // return EINVAL. This is different from the truncate() syscall which returns EISDIR.
1689            //
1690            // See https://man7.org/linux/man-pages/man2/ftruncate.2.html#ERRORS
1691            return error!(EINVAL);
1692        }
1693
1694        // For ftruncate, we do not need to check that the file node is writable.
1695        //
1696        // The file object that calls this method must verify that the file was opened
1697        // with write permissions.
1698        //
1699        // This matters because a file could be opened with O_CREAT + O_RDWR + 0444 mode.
1700        // The file descriptor returned from such an operation can be truncated, even
1701        // though the file was created with a read-only mode.
1702        //
1703        // See https://man7.org/linux/man-pages/man2/ftruncate.2.html#DESCRIPTION
1704        // which says:
1705        //
1706        // "With ftruncate(), the file must be open for writing; with truncate(),
1707        // the file must be writable."
1708
1709        let guard = self.ops().append_lock_write(self, current_task)?;
1710        self.truncate_locked(&guard, current_task, length)
1711    }
1712
1713    // Called by `truncate` and `ftruncate` above.
1714    pub fn truncate_locked(
1715        &self,
1716        guard: &AppendLockWriteGuard<'_>,
1717        current_task: &CurrentTask,
1718        length: u64,
1719    ) -> Result<(), Errno> {
1720        if length > MAX_LFS_FILESIZE as u64 {
1721            return error!(EINVAL);
1722        }
1723        if length > current_task.thread_group().get_rlimit(Resource::FSIZE) {
1724            send_standard_signal(current_task, SignalInfo::kernel(SIGXFSZ));
1725            return error!(EFBIG);
1726        }
1727        self.clear_suid_and_sgid_bits(current_task)?;
1728
1729        self.ops().truncate(guard, self, current_task, length)?;
1730        self.update_ctime_mtime();
1731        Ok(())
1732    }
1733
1734    /// Avoid calling this method directly. You probably want to call `FileObject::fallocate()`
1735    /// which will also perform additional verifications.
1736    pub fn fallocate(
1737        &self,
1738        current_task: &CurrentTask,
1739        mode: FallocMode,
1740        offset: u64,
1741        length: u64,
1742    ) -> Result<(), Errno> {
1743        let guard = self.ops().append_lock_write(self, current_task)?;
1744        self.fallocate_locked(&guard, current_task, mode, offset, length)
1745    }
1746
1747    pub fn fallocate_locked(
1748        &self,
1749        guard: &AppendLockWriteGuard<'_>,
1750        current_task: &CurrentTask,
1751        mode: FallocMode,
1752        offset: u64,
1753        length: u64,
1754    ) -> Result<(), Errno> {
1755        let allocate_size = checked_add_offset_and_length(offset as usize, length as usize)
1756            .map_err(|_| errno!(EFBIG))? as u64;
1757        if allocate_size > current_task.thread_group().get_rlimit(Resource::FSIZE) {
1758            send_standard_signal(current_task, SignalInfo::kernel(SIGXFSZ));
1759            return error!(EFBIG);
1760        }
1761
1762        self.clear_suid_and_sgid_bits(current_task)?;
1763
1764        self.ops().allocate(guard, self, current_task, mode, offset, length)?;
1765        self.update_ctime_mtime();
1766        Ok(())
1767    }
1768
1769    fn update_metadata_for_child(
1770        &self,
1771        current_task: &CurrentTask,
1772        mode: &mut FileMode,
1773        owner: &mut FsCred,
1774    ) {
1775        // The setgid bit on a directory causes the gid to be inherited by new children and the
1776        // setgid bit to be inherited by new child directories. See SetgidDirTest in gvisor.
1777        {
1778            let self_info = self.info();
1779            if self_info.mode.contains(FileMode::ISGID) {
1780                owner.gid = self_info.gid;
1781                if mode.is_dir() {
1782                    *mode |= FileMode::ISGID;
1783                }
1784            }
1785        }
1786
1787        if !mode.is_dir() {
1788            // https://man7.org/linux/man-pages/man7/inode.7.html says:
1789            //
1790            //   For an executable file, the set-group-ID bit causes the
1791            //   effective group ID of a process that executes the file to change
1792            //   as described in execve(2).
1793            //
1794            // We need to check whether the current task has permission to create such a file.
1795            // See a similar check in `FsNode::chmod`.
1796            let current_creds = current_task.current_creds();
1797            if owner.gid != current_creds.fsgid
1798                && !current_creds.is_in_group(owner.gid)
1799                && !security::is_task_capable_noaudit(current_task, CAP_FOWNER)
1800            {
1801                *mode &= !FileMode::ISGID;
1802            }
1803        }
1804    }
1805
1806    /// Checks if O_NOATIME is allowed,
1807    pub fn check_o_noatime_allowed(&self, current_task: &CurrentTask) -> Result<(), Errno> {
1808        // Per open(2),
1809        //
1810        //   O_NOATIME (since Linux 2.6.8)
1811        //      ...
1812        //
1813        //      This flag can be employed only if one of the following
1814        //      conditions is true:
1815        //
1816        //      *  The effective UID of the process matches the owner UID
1817        //         of the file.
1818        //
1819        //      *  The calling process has the CAP_FOWNER capability in
1820        //         its user namespace and the owner UID of the file has a
1821        //         mapping in the namespace.
1822        if current_task.current_creds().fsuid != self.info().uid {
1823            security::check_task_capable(current_task, CAP_FOWNER)?;
1824        }
1825        Ok(())
1826    }
1827
1828    pub fn default_check_access_impl(
1829        &self,
1830        current_task: &CurrentTask,
1831        permission_flags: security::PermissionFlags,
1832        reason: CheckAccessReason,
1833        info: LockDepReadGuard<'_, FsNodeInfo>,
1834        audit_context: Auditable<'_>,
1835    ) -> Result<(), Errno> {
1836        let (node_uid, node_gid, mode) = (info.uid, info.gid, info.mode);
1837        std::mem::drop(info);
1838        if let CheckAccessReason::ChangeTimestamps { now } = reason {
1839            // To set the timestamps to the current time the caller must either have write access to
1840            // the file, be the file owner, or hold the CAP_DAC_OVERRIDE or CAP_FOWNER capability.
1841            // To set the timestamps to other values the caller must either be the file owner or hold
1842            // the CAP_FOWNER capability.
1843            if current_task.current_creds().fsuid == node_uid {
1844                return Ok(());
1845            }
1846            if now {
1847                if security::is_task_capable_noaudit(current_task, CAP_FOWNER) {
1848                    return Ok(());
1849                }
1850            } else {
1851                security::check_task_capable(current_task, CAP_FOWNER)?;
1852                return Ok(());
1853            }
1854        }
1855        check_access(self, current_task, permission_flags, node_uid, node_gid, mode)?;
1856        security::fs_node_permission(current_task, self, permission_flags, audit_context)
1857    }
1858
1859    /// Check whether the node can be accessed in the current context with the specified access
1860    /// flags (read, write, or exec). Accounts for capabilities and whether the current user is the
1861    /// owner or is in the file's group.
1862    pub fn check_access<'a>(
1863        &self,
1864        current_task: &CurrentTask,
1865        mount: &MountInfo,
1866        access: impl Into<security::PermissionFlags>,
1867        reason: CheckAccessReason,
1868        audit_context: impl Into<security::Auditable<'a>>,
1869    ) -> Result<(), Errno> {
1870        let mut permission_flags = access.into();
1871        if permission_flags.contains(security::PermissionFlags::WRITE)
1872            && !self.info().mode.is_special()
1873        {
1874            mount.check_readonly_filesystem()?;
1875        }
1876        if permission_flags.contains(security::PermissionFlags::EXEC) && !self.is_dir() {
1877            mount.check_noexec_filesystem()?;
1878        }
1879        if reason == CheckAccessReason::Access {
1880            permission_flags |= PermissionFlags::ACCESS;
1881        }
1882        self.ops().check_access(
1883            self,
1884            current_task,
1885            permission_flags,
1886            &self.info,
1887            reason,
1888            audit_context.into(),
1889        )
1890    }
1891
1892    /// Check whether the stick bit, `S_ISVTX`, forbids the `current_task` from removing the given
1893    /// `child`. If this node has `S_ISVTX`, then either the child must be owned by the `fsuid` of
1894    /// `current_task` or `current_task` must have `CAP_FOWNER`.
1895    pub fn check_sticky_bit(
1896        &self,
1897        current_task: &CurrentTask,
1898        child: &FsNodeHandle,
1899        self_info: &FsNodeInfo,
1900    ) -> Result<(), Errno> {
1901        if self_info.mode.contains(FileMode::ISVTX)
1902            && child.info().uid != current_task.current_creds().fsuid
1903        {
1904            security::check_task_capable(current_task, CAP_FOWNER)?;
1905        }
1906        Ok(())
1907    }
1908
1909    pub fn fifo(&self, current_task: &CurrentTask) -> &PipeHandle {
1910        assert!(self.is_fifo());
1911        self.ensure_rare_data().ensure_fifo(current_task)
1912    }
1913
1914    /// Returns the UNIX domain socket bound to this node, if any.
1915    pub fn bound_socket(&self) -> Option<&SocketHandle> {
1916        if let Some(rare_data) = self.rare_data.get() { rare_data.bound_socket.get() } else { None }
1917    }
1918
1919    /// Register the provided socket as the UNIX domain socket bound to this node.
1920    ///
1921    /// It is a fatal error to call this method again if it has already been called on this node.
1922    pub fn set_bound_socket(&self, socket: SocketHandle) {
1923        assert!(self.ensure_rare_data().bound_socket.set(socket).is_ok());
1924    }
1925
1926    pub fn update_attributes<F>(&self, current_task: &CurrentTask, mutator: F) -> Result<(), Errno>
1927    where
1928        F: FnOnce(&mut FsNodeInfo) -> Result<(), Errno>,
1929    {
1930        let mut info = self.info.write();
1931        let mut new_info = info.clone();
1932        mutator(&mut new_info)?;
1933
1934        let new_access = new_info.mode.user_access()
1935            | new_info.mode.group_access()
1936            | new_info.mode.other_access();
1937
1938        if new_access.intersects(Access::EXEC) {
1939            let write_guard_state = self.write_guard_state.lock();
1940            if let Ok(seals) = write_guard_state.get_seals() {
1941                if seals.contains(SealFlags::NO_EXEC) {
1942                    return error!(EPERM);
1943                }
1944            }
1945        }
1946
1947        // `mutator`s should not update the attribute change time, which is managed by this API.
1948        assert_eq!(info.time_status_change, new_info.time_status_change);
1949        if *info == new_info {
1950            return Ok(());
1951        }
1952        new_info.time_status_change = utc::utc_now();
1953
1954        let mut has = zxio_node_attr_has_t { ..Default::default() };
1955        has.modification_time = info.time_modify != new_info.time_modify;
1956        has.access_time = info.time_access != new_info.time_access;
1957        has.mode = info.mode != new_info.mode;
1958        has.uid = info.uid != new_info.uid;
1959        has.gid = info.gid != new_info.gid;
1960        has.rdev = info.rdev != new_info.rdev;
1961        has.casefold = info.casefold != new_info.casefold;
1962        has.wrapping_key_id = info.wrapping_key_id != new_info.wrapping_key_id;
1963
1964        if has.casefold && !self.ops().has_casefold_support(self) {
1965            return error!(ENOTSUP);
1966        }
1967        security::check_fs_node_setattr_access(current_task, &self, &has)?;
1968
1969        // Call `update_attributes(..)` to persist the changes for the following fields.
1970        if has.modification_time
1971            || has.access_time
1972            || has.mode
1973            || has.uid
1974            || has.gid
1975            || has.rdev
1976            || has.casefold
1977            || has.wrapping_key_id
1978        {
1979            self.ops().update_attributes(self, current_task, &new_info, has)?;
1980        }
1981
1982        *info = new_info;
1983        Ok(())
1984    }
1985
1986    /// Set the permissions on this FsNode to the given values.
1987    ///
1988    /// Does not change the IFMT of the node.
1989    pub fn chmod(
1990        &self,
1991        current_task: &CurrentTask,
1992        mount: &MountInfo,
1993        mut mode: FileMode,
1994    ) -> Result<(), Errno> {
1995        mount.check_readonly_filesystem()?;
1996        self.update_attributes(current_task, |info| {
1997            let current_creds = current_task.current_creds();
1998            if info.uid != current_creds.euid {
1999                security::check_task_capable(current_task, CAP_FOWNER)?;
2000            } else if info.gid != current_creds.egid
2001                && !current_creds.is_in_group(info.gid)
2002                && mode.intersects(FileMode::ISGID)
2003                && !security::is_task_capable_noaudit(current_task, CAP_FOWNER)
2004            {
2005                mode &= !FileMode::ISGID;
2006            }
2007            info.chmod(mode);
2008            Ok(())
2009        })
2010    }
2011
2012    /// Sets the owner and/or group on this FsNode.
2013    pub fn chown(
2014        &self,
2015        current_task: &CurrentTask,
2016        mount: &MountInfo,
2017        owner: Option<uid_t>,
2018        group: Option<gid_t>,
2019    ) -> Result<(), Errno> {
2020        mount.check_readonly_filesystem()?;
2021        self.update_attributes(current_task, |info| {
2022            if security::is_task_capable_noaudit(current_task, CAP_CHOWN) {
2023                info.chown(owner, group);
2024                return Ok(());
2025            }
2026
2027            // Nobody can change the owner.
2028            if let Some(uid) = owner {
2029                if info.uid != uid {
2030                    return error!(EPERM);
2031                }
2032            }
2033
2034            let (euid, is_in_group) = {
2035                let current_creds = current_task.current_creds();
2036                (current_creds.euid, group.map(|gid| current_creds.is_in_group(gid)))
2037            };
2038
2039            // The owner can change the group.
2040            if info.uid == euid {
2041                // To a group that it belongs.
2042                if let Some(is_in_group) = is_in_group {
2043                    if !is_in_group {
2044                        return error!(EPERM);
2045                    }
2046                }
2047                info.chown(None, group);
2048                return Ok(());
2049            }
2050
2051            // Any other user can call chown(file, -1, -1)
2052            if owner.is_some() || group.is_some() {
2053                return error!(EPERM);
2054            }
2055
2056            // But not on set-user-ID or set-group-ID files.
2057            // If we were to chown them, they would drop the set-ID bit.
2058            if info.mode.is_reg()
2059                && (info.mode.contains(FileMode::ISUID)
2060                    || info.mode.contains(FileMode::ISGID | FileMode::IXGRP))
2061            {
2062                return error!(EPERM);
2063            }
2064
2065            info.chown(None, None);
2066            Ok(())
2067        })
2068    }
2069
2070    /// Forcefully change the owner and group of this node.
2071    ///
2072    /// # Safety
2073    ///
2074    /// This function skips all the security checks and just updates the owner and group. Also, does
2075    /// not check if the filesystem is read-only and does not update the attribute change time.
2076    ///
2077    /// This function is used to set the owner and group of /proc/pid to the credentials of the
2078    /// current task. Please consider carefully whether you want to use this function for another
2079    /// purpose.
2080    pub unsafe fn force_chown(&self, creds: FsCred) {
2081        self.update_info(|info| {
2082            info.chown(Some(creds.uid), Some(creds.gid));
2083        });
2084    }
2085
2086    /// Whether this node is a regular file.
2087    pub fn is_reg(&self) -> bool {
2088        self.info().mode.is_reg()
2089    }
2090
2091    /// Whether this node is a directory.
2092    pub fn is_dir(&self) -> bool {
2093        self.info().mode.is_dir()
2094    }
2095
2096    /// Whether this node is a socket.
2097    pub fn is_sock(&self) -> bool {
2098        self.info().mode.is_sock()
2099    }
2100
2101    /// Whether this node is a FIFO.
2102    pub fn is_fifo(&self) -> bool {
2103        self.info().mode.is_fifo()
2104    }
2105
2106    /// Whether this node is a symbolic link.
2107    pub fn is_lnk(&self) -> bool {
2108        self.info().mode.is_lnk()
2109    }
2110
2111    pub fn dev(&self) -> DeviceId {
2112        self.fs().dev_id
2113    }
2114
2115    pub fn stat(&self, current_task: &CurrentTask) -> Result<uapi::stat, Errno> {
2116        security::check_fs_node_getattr_access(current_task, self)?;
2117
2118        let info = self.fetch_and_refresh_info(current_task)?;
2119
2120        let time_to_kernel_timespec_pair = |t| {
2121            let timespec { tv_sec, tv_nsec } = timespec_from_time(t);
2122            let time = tv_sec.try_into().map_err(|_| errno!(EINVAL))?;
2123            let time_nsec = tv_nsec.try_into().map_err(|_| errno!(EINVAL))?;
2124            Ok((time, time_nsec))
2125        };
2126
2127        let (st_atime, st_atime_nsec) = time_to_kernel_timespec_pair(info.time_access)?;
2128        let (st_mtime, st_mtime_nsec) = time_to_kernel_timespec_pair(info.time_modify)?;
2129        let (st_ctime, st_ctime_nsec) = time_to_kernel_timespec_pair(info.time_status_change)?;
2130
2131        Ok(uapi::stat {
2132            st_dev: self.dev().bits(),
2133            st_ino: self.ino,
2134            st_nlink: info.link_count.try_into().map_err(|_| errno!(EINVAL))?,
2135            st_mode: info.mode.bits(),
2136            st_uid: info.uid,
2137            st_gid: info.gid,
2138            st_rdev: info.rdev.bits(),
2139            st_size: info.size.try_into().map_err(|_| errno!(EINVAL))?,
2140            st_blksize: info.blksize.try_into().map_err(|_| errno!(EINVAL))?,
2141            st_blocks: info.blocks.try_into().map_err(|_| errno!(EINVAL))?,
2142            st_atime,
2143            st_atime_nsec,
2144            st_mtime,
2145            st_mtime_nsec,
2146            st_ctime,
2147            st_ctime_nsec,
2148            ..Default::default()
2149        })
2150    }
2151
2152    /// Returns the current size of the file.  This is inherently racy, so any caller that
2153    /// might want to use the value returned should hold their own locks if necessary.  For
2154    /// example, if using the value here to implement append (which is the case at the time
2155    /// of writing this comment), locks must be held to prevent the file size being changed
2156    /// concurrently.
2157    // TODO(https://fxbug.dev/454730248): This is probably the wrong way to implement O_APPEND.
2158    pub fn get_size(&self, current_task: &CurrentTask) -> Result<usize, Errno> {
2159        self.ops().get_size(self, current_task)
2160    }
2161
2162    fn statx_timestamp_from_time(time: UtcInstant) -> statx_timestamp {
2163        let nanos = time.into_nanos();
2164        statx_timestamp {
2165            tv_sec: nanos / NANOS_PER_SECOND,
2166            tv_nsec: (nanos % NANOS_PER_SECOND) as u32,
2167            ..Default::default()
2168        }
2169    }
2170
2171    pub fn statx(
2172        &self,
2173        current_task: &CurrentTask,
2174        flags: StatxFlags,
2175        mask: u32,
2176    ) -> Result<statx, Errno> {
2177        security::check_fs_node_getattr_access(current_task, self)?;
2178
2179        // Ignore mask for now and fill in all of the fields.
2180        let info = if flags.contains(StatxFlags::AT_STATX_DONT_SYNC) {
2181            self.info()
2182        } else {
2183            self.fetch_and_refresh_info(current_task)?
2184        };
2185        if mask & STATX__RESERVED == STATX__RESERVED {
2186            return error!(EINVAL);
2187        }
2188
2189        track_stub!(TODO("https://fxbug.dev/302594110"), "statx attributes");
2190        let stx_mnt_id = 0;
2191        let mut stx_attributes = 0;
2192        let stx_attributes_mask = STATX_ATTR_VERITY as u64;
2193
2194        if matches!(*self.fsverity.lock(), FsVerityState::FsVerity) {
2195            stx_attributes |= STATX_ATTR_VERITY as u64;
2196        }
2197
2198        Ok(statx {
2199            stx_mask: STATX_NLINK
2200                | STATX_UID
2201                | STATX_GID
2202                | STATX_ATIME
2203                | STATX_MTIME
2204                | STATX_CTIME
2205                | STATX_INO
2206                | STATX_SIZE
2207                | STATX_BLOCKS
2208                | STATX_BASIC_STATS,
2209            stx_blksize: info.blksize.try_into().map_err(|_| errno!(EINVAL))?,
2210            stx_attributes,
2211            stx_nlink: info.link_count.try_into().map_err(|_| errno!(EINVAL))?,
2212            stx_uid: info.uid,
2213            stx_gid: info.gid,
2214            stx_mode: info.mode.bits().try_into().map_err(|_| errno!(EINVAL))?,
2215            stx_ino: self.ino,
2216            stx_size: info.size.try_into().map_err(|_| errno!(EINVAL))?,
2217            stx_blocks: info.blocks.try_into().map_err(|_| errno!(EINVAL))?,
2218            stx_attributes_mask,
2219            stx_ctime: Self::statx_timestamp_from_time(info.time_status_change),
2220            stx_mtime: Self::statx_timestamp_from_time(info.time_modify),
2221            stx_atime: Self::statx_timestamp_from_time(info.time_access),
2222
2223            stx_rdev_major: info.rdev.major(),
2224            stx_rdev_minor: info.rdev.minor(),
2225
2226            stx_dev_major: self.fs().dev_id.major(),
2227            stx_dev_minor: self.fs().dev_id.minor(),
2228            stx_mnt_id,
2229            ..Default::default()
2230        })
2231    }
2232
2233    /// Checks whether `current_task` has capabilities required for the specified `access` to the
2234    /// extended attribute `name`.
2235    fn check_xattr_access(
2236        &self,
2237        current_task: &CurrentTask,
2238        mount: &MountInfo,
2239        name: &FsStr,
2240        access: Access,
2241    ) -> Result<(), Errno> {
2242        assert!(access == Access::READ || access == Access::WRITE);
2243
2244        let enodata_if_read =
2245            |e: Errno| if access == Access::READ && e.code == EPERM { errno!(ENODATA) } else { e };
2246
2247        // man xattr(7) describes the different access checks applied to each extended attribute
2248        // namespace.
2249        if name.starts_with(XATTR_USER_PREFIX.to_bytes()) {
2250            {
2251                let info = self.info();
2252                if !info.mode.is_reg() && !info.mode.is_dir() {
2253                    return Err(enodata_if_read(errno!(EPERM)));
2254                }
2255            }
2256
2257            // TODO: https://fxbug.dev/460734830 - Perform capability check(s) if file has sticky
2258            // bit set.
2259
2260            self.check_access(
2261                current_task,
2262                mount,
2263                access,
2264                CheckAccessReason::InternalPermissionChecks,
2265                security::Auditable::Name(name),
2266            )?;
2267        } else if name.starts_with(XATTR_TRUSTED_PREFIX.to_bytes()) {
2268            // Trusted extended attributes require `CAP_SYS_ADMIN` to read or write.
2269            security::check_task_capable(current_task, CAP_SYS_ADMIN).map_err(enodata_if_read)?;
2270        } else if name.starts_with(XATTR_SYSTEM_PREFIX.to_bytes()) {
2271            // System extended attributes have attribute-specific access policy.
2272            // TODO: https://fxbug.dev/460734830 -  Revise how system extended attributes are
2273            // access-controlled.
2274            security::check_task_capable(current_task, CAP_SYS_ADMIN).map_err(enodata_if_read)?;
2275        } else if name.starts_with(XATTR_SECURITY_PREFIX.to_bytes()) {
2276            if access == Access::WRITE {
2277                // Writes require `CAP_SYS_ADMIN`, unless the LSM owning `name` specifies to skip.
2278                if !security::fs_node_xattr_skipcap(name) {
2279                    security::check_task_capable(current_task, CAP_SYS_ADMIN)
2280                        .map_err(enodata_if_read)?;
2281                }
2282            }
2283        } else {
2284            panic!("Unknown extended attribute prefix: {}", name);
2285        }
2286        Ok(())
2287    }
2288
2289    pub fn get_xattr(
2290        &self,
2291        current_task: &CurrentTask,
2292        mount: &MountInfo,
2293        name: &FsStr,
2294        max_size: usize,
2295    ) -> Result<ValueOrSize<FsString>, Errno> {
2296        // Perform discretionary capability & access checks appropriate to the xattr prefix.
2297        self.check_xattr_access(current_task, mount, name, Access::READ)?;
2298
2299        // LSM access checks must be performed after discretionary checks.
2300        security::check_fs_node_getxattr_access(current_task, self, name)?;
2301
2302        if name.starts_with(XATTR_SECURITY_PREFIX.to_bytes()) {
2303            // If the attribute is in the security.* domain then allow the LSM to handle the
2304            // request, or to delegate to `FsNodeOps::get_xattr()`.
2305            security::fs_node_getsecurity(current_task, self, name, max_size)
2306        } else {
2307            // If the attribute is outside security.*, delegate the read to the `FsNodeOps`.
2308            self.ops().get_xattr(self, current_task, name, max_size)
2309        }
2310    }
2311
2312    pub fn set_xattr(
2313        &self,
2314        current_task: &CurrentTask,
2315        mount: &MountInfo,
2316        name: &FsStr,
2317        value: &FsStr,
2318        op: XattrOp,
2319    ) -> Result<(), Errno> {
2320        // Perform discretionary capability & access checks appropriate to the xattr prefix.
2321        self.check_xattr_access(current_task, mount, name, Access::WRITE)?;
2322
2323        // LSM access checks must be performed after discretionary checks.
2324        security::check_fs_node_setxattr_access(current_task, self, name, value, op)?;
2325
2326        if name.starts_with(XATTR_SECURITY_PREFIX.to_bytes()) {
2327            // If the attribute is in the security.* domain then allow the LSM to handle the
2328            // request, or to delegate to `FsNodeOps::set_xattr()`.
2329            security::fs_node_setsecurity(current_task, self, name, value, op)
2330        } else {
2331            // If the attribute is outside security.*, delegate the read to the `FsNodeOps`.
2332            self.ops().set_xattr(self, current_task, name, value, op)
2333        }
2334    }
2335
2336    pub fn remove_xattr(
2337        &self,
2338        current_task: &CurrentTask,
2339        mount: &MountInfo,
2340        name: &FsStr,
2341    ) -> Result<(), Errno> {
2342        // Perform discretionary capability & access checks appropriate to the xattr prefix.
2343        self.check_xattr_access(current_task, mount, name, Access::WRITE)?;
2344
2345        // LSM access checks must be performed after discretionary checks.
2346        security::check_fs_node_removexattr_access(current_task, self, name)?;
2347        self.ops().remove_xattr(self, current_task, name)
2348    }
2349
2350    pub fn list_xattrs(
2351        &self,
2352        current_task: &CurrentTask,
2353        max_size: usize,
2354    ) -> Result<ValueOrSize<Vec<FsString>>, Errno> {
2355        security::check_fs_node_listxattr_access(current_task, self)?;
2356        Ok(self.ops().list_xattrs(self, current_task, max_size)?.map(|mut v| {
2357            // Extended attributes may be listed even if the caller would not be able to read
2358            // (or modify) the attribute's value.
2359            // trusted.* attributes are only accessible with CAP_SYS_ADMIN and are omitted by
2360            // `listxattr()` unless the caller holds CAP_SYS_ADMIN.
2361            if !security::is_task_capable_noaudit(current_task, CAP_SYS_ADMIN) {
2362                v.retain(|name| !name.starts_with(XATTR_TRUSTED_PREFIX.to_bytes()));
2363            }
2364            v
2365        }))
2366    }
2367
2368    /// Returns current `FsNodeInfo`.
2369    pub fn info(&self) -> LockDepReadGuard<'_, FsNodeInfo> {
2370        self.info.read()
2371    }
2372
2373    /// Returns a reference to the `info` lock itself.
2374    ///
2375    /// This should ONLY be used by `RenameGuard` to perform ordered write locking on independent
2376    /// nodes.
2377    pub(super) fn info_lock(&self) -> &DynamicLockDepRwLock<FsNodeInfo> {
2378        &self.info
2379    }
2380
2381    /// Refreshes the `FsNodeInfo` if necessary and returns a read guard.
2382    pub fn fetch_and_refresh_info(
2383        &self,
2384        current_task: &CurrentTask,
2385    ) -> Result<LockDepReadGuard<'_, FsNodeInfo>, Errno> {
2386        self.ops().fetch_and_refresh_info(self, current_task, &self.info)
2387    }
2388
2389    pub fn update_info<F, T>(&self, mutator: F) -> T
2390    where
2391        F: FnOnce(&mut FsNodeInfo) -> T,
2392    {
2393        let mut info = self.info.write();
2394        mutator(&mut info)
2395    }
2396
2397    /// Clear the SUID and SGID bits unless the `current_task` has `CAP_FSETID`
2398    pub fn clear_suid_and_sgid_bits(&self, current_task: &CurrentTask) -> Result<(), Errno> {
2399        if !self.info().has_suid_or_sgid_bits() {
2400            return Ok(());
2401        }
2402        self.update_attributes(current_task, |info| {
2403            if info.has_suid_or_sgid_bits()
2404                && !security::is_task_capable_noaudit(current_task, CAP_FSETID)
2405            {
2406                info.clear_suid_and_sgid_bits();
2407            }
2408            Ok(())
2409        })
2410    }
2411
2412    /// Update the ctime and mtime of a file to now.
2413    pub fn update_ctime_mtime(&self) {
2414        if self.fs().manages_timestamps() {
2415            return;
2416        }
2417        self.update_info(|info| {
2418            let now = utc::utc_now();
2419            info.time_status_change = now;
2420            info.time_modify = now;
2421        });
2422    }
2423
2424    /// Update the ctime of a file to now.
2425    pub fn update_ctime(&self) {
2426        if self.fs().manages_timestamps() {
2427            return;
2428        }
2429        self.update_info(|info| {
2430            let now = utc::utc_now();
2431            info.time_status_change = now;
2432        });
2433    }
2434
2435    /// Update the atime and mtime if the `current_task` has write access, is the file owner, or
2436    /// holds either the CAP_DAC_OVERRIDE or CAP_FOWNER capability.
2437    pub fn update_atime_mtime(
2438        &self,
2439        current_task: &CurrentTask,
2440        mount: &MountInfo,
2441        atime: TimeUpdateType,
2442        mtime: TimeUpdateType,
2443    ) -> Result<(), Errno> {
2444        // If the filesystem is read-only, this always fail.
2445        mount.check_readonly_filesystem()?;
2446
2447        let now = matches!((atime, mtime), (TimeUpdateType::Now, TimeUpdateType::Now));
2448        self.check_access(
2449            current_task,
2450            mount,
2451            Access::WRITE,
2452            CheckAccessReason::ChangeTimestamps { now },
2453            security::Auditable::Location(std::panic::Location::caller()),
2454        )?;
2455
2456        if !matches!((atime, mtime), (TimeUpdateType::Omit, TimeUpdateType::Omit)) {
2457            // This function is called by `utimes(..)` which will update the access and
2458            // modification time. We need to call `update_attributes()` to update the mtime of
2459            // filesystems that manages file timestamps.
2460            self.update_attributes(current_task, |info| {
2461                let now = utc::utc_now();
2462                let get_time = |time: TimeUpdateType| match time {
2463                    TimeUpdateType::Now => Some(now),
2464                    TimeUpdateType::Time(t) => Some(t),
2465                    TimeUpdateType::Omit => None,
2466                };
2467                if let Some(time) = get_time(atime) {
2468                    info.time_access = time;
2469                }
2470                if let Some(time) = get_time(mtime) {
2471                    info.time_modify = time;
2472                }
2473                Ok(())
2474            })?;
2475        }
2476        Ok(())
2477    }
2478
2479    /// The key used to identify this node in the file system's node cache.
2480    ///
2481    /// For many file systems, this will be the same as the inode number. However, some file
2482    /// systems, such as FUSE, sometimes use different `node_key` and inode numbers.
2483    pub fn node_key(&self) -> ino_t {
2484        self.ops().node_key(self)
2485    }
2486
2487    fn ensure_rare_data(&self) -> &FsNodeRareData {
2488        self.rare_data.get_or_init(|| Box::new(FsNodeRareData::default()))
2489    }
2490
2491    /// Returns the set of watchers for this node.
2492    ///
2493    /// Only call this function if you require this node to actually store a list of watchers. If
2494    /// you just wish to notify any watchers that might exist, please use `notify` instead.
2495    pub fn ensure_watchers(&self) -> &inotify_hook::InotifyWatchers {
2496        &self.ensure_rare_data().watchers
2497    }
2498
2499    /// Notify the watchers of the given event.
2500    pub fn notify(
2501        &self,
2502        event_mask: InotifyMask,
2503        cookie: u32,
2504        name: &FsStr,
2505        mode: FileMode,
2506        is_dead: bool,
2507    ) {
2508        if let Some(rare_data) = self.rare_data.get() {
2509            let kernel = self.fs().kernel.upgrade().expect("kernel is dead");
2510            if let Some(hook) = kernel.expando.peek::<Arc<dyn inotify_hook::NotifyHook>>() {
2511                hook.notify(&rare_data.watchers, event_mask, cookie, name, mode, is_dead);
2512            }
2513        }
2514    }
2515
2516    /// Calls through to the filesystem to enable fs-verity on this file.
2517    pub fn enable_fsverity(
2518        &self,
2519        current_task: &CurrentTask,
2520        descriptor: &fsverity_descriptor,
2521    ) -> Result<(), Errno> {
2522        self.ops().enable_fsverity(self, current_task, descriptor)
2523    }
2524}
2525
2526impl std::fmt::Debug for FsNode {
2527    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2528        f.debug_struct("FsNode")
2529            .field("fs", &self.fs().name())
2530            .field("info", &*self.info())
2531            .field("ops_ty", &self.ops().type_name())
2532            .finish()
2533    }
2534}
2535
2536impl Releasable for FsNode {
2537    type Context<'a> = &'a CurrentTask;
2538
2539    fn release<'a>(self, context: &'a CurrentTask) {
2540        let current_task = context;
2541        if let Some(fs) = self.fs.upgrade() {
2542            fs.remove_node(&self);
2543        }
2544        if let Err(err) = self.ops.forget(current_task, self.info.into_inner()) {
2545            log_error!("Error on FsNodeOps::forget: {err:?}");
2546        }
2547    }
2548}
2549
2550fn check_access(
2551    fs_node: &FsNode,
2552    current_task: &CurrentTask,
2553    permission_flags: security::PermissionFlags,
2554    node_uid: uid_t,
2555    node_gid: gid_t,
2556    mode: FileMode,
2557) -> Result<(), Errno> {
2558    // Determine which of the access bits apply to the `current_task`.
2559    let (fsuid, is_in_group) = {
2560        let current_creds = current_task.current_creds();
2561        (current_creds.fsuid, current_creds.is_in_group(node_gid))
2562    };
2563    let granted = if fsuid == node_uid {
2564        mode.user_access()
2565    } else if is_in_group {
2566        mode.group_access()
2567    } else {
2568        mode.other_access()
2569    };
2570
2571    let access = permission_flags.as_access();
2572    if granted.contains(access) {
2573        return Ok(());
2574    }
2575
2576    // Callers with CAP_DAC_READ_SEARCH override can read files & directories, and traverse
2577    // directories to which they lack permission.
2578    let mut requested = access & !granted;
2579
2580    // If this check was triggered by `access()`, or a variant, then check for a `dontaudit`
2581    // statement for the `audit_access` permission for this caller & file.
2582    let have_dont_audit = OnceBool::new();
2583    let has_capability = move |current_task, capability| {
2584        let dont_audit = have_dont_audit.get_or_init(|| {
2585            permission_flags.contains(PermissionFlags::ACCESS)
2586                && security::has_dontaudit_access(current_task, fs_node)
2587        });
2588        if dont_audit {
2589            security::is_task_capable_noaudit(current_task, capability)
2590        } else {
2591            security::check_task_capable(current_task, capability).is_ok()
2592        }
2593    };
2594
2595    // CAP_DAC_READ_SEARCH allows bypass of read checks, and directory traverse (eXecute) checks.
2596    let dac_read_search_access =
2597        if mode.is_dir() { Access::READ | Access::EXEC } else { Access::READ };
2598    if dac_read_search_access.intersects(requested)
2599        && has_capability(current_task, CAP_DAC_READ_SEARCH)
2600    {
2601        requested.remove(dac_read_search_access);
2602    }
2603    if requested.is_empty() {
2604        return Ok(());
2605    }
2606
2607    // CAP_DAC_OVERRIDE allows bypass of all checks (though see the comment for file-execute).
2608    let mut dac_override_access = Access::READ | Access::WRITE;
2609    dac_override_access |= if mode.is_dir() {
2610        Access::EXEC
2611    } else {
2612        // File execute access checks may not be bypassed unless at least one executable bit is set.
2613        (mode.user_access() | mode.group_access() | mode.other_access()) & Access::EXEC
2614    };
2615    if dac_override_access.intersects(requested) && has_capability(current_task, CAP_DAC_OVERRIDE) {
2616        requested.remove(dac_override_access);
2617    }
2618    if requested.is_empty() {
2619        return Ok(());
2620    }
2621
2622    return error!(EACCES);
2623}
2624
2625#[cfg(test)]
2626mod tests {
2627    use super::*;
2628    use crate::device::mem::mem_device_init;
2629    use crate::testing::*;
2630    use crate::vfs::buffers::VecOutputBuffer;
2631    use starnix_uapi::auth::Credentials;
2632    use starnix_uapi::file_mode::mode;
2633
2634    #[::fuchsia::test]
2635    async fn open_device_file() {
2636        spawn_kernel_and_run(async |current_task| {
2637            mem_device_init(current_task.kernel()).expect("mem_device_init");
2638
2639            // Create a device file that points to the `zero` device (which is automatically
2640            // registered in the kernel).
2641            current_task
2642                .fs()
2643                .root()
2644                .create_node(&current_task, "zero".into(), mode!(IFCHR, 0o666), DeviceId::ZERO)
2645                .expect("create_node");
2646
2647            const CONTENT_LEN: usize = 10;
2648            let mut buffer = VecOutputBuffer::new(CONTENT_LEN);
2649
2650            // Read from the zero device.
2651            let device_file =
2652                current_task.open_file("zero".into(), OpenFlags::RDONLY).expect("open device file");
2653            device_file.read(&current_task, &mut buffer).expect("read from zero");
2654
2655            // Assert the contents.
2656            assert_eq!(&[0; CONTENT_LEN], buffer.data());
2657        })
2658        .await;
2659    }
2660
2661    #[::fuchsia::test]
2662    async fn node_info_is_reflected_in_stat() {
2663        spawn_kernel_and_run(async |current_task| {
2664            // Create a node.
2665            let node = &current_task
2666                .fs()
2667                .root()
2668                .create_node(&current_task, "zero".into(), FileMode::IFCHR, DeviceId::ZERO)
2669                .expect("create_node")
2670                .entry
2671                .node;
2672            node.update_info(|info| {
2673                info.mode = FileMode::IFSOCK;
2674                info.size = 1;
2675                info.blocks = 2;
2676                info.blksize = 4;
2677                info.uid = 9;
2678                info.gid = 10;
2679                info.link_count = 11;
2680                info.time_status_change = UtcInstant::from_nanos(1);
2681                info.time_access = UtcInstant::from_nanos(2);
2682                info.time_modify = UtcInstant::from_nanos(3);
2683                info.rdev = DeviceId::new(13, 13);
2684            });
2685            let stat = node.stat(&current_task).expect("stat");
2686
2687            assert_eq!(stat.st_mode, FileMode::IFSOCK.bits());
2688            assert_eq!(stat.st_size, 1);
2689            assert_eq!(stat.st_blksize, 4);
2690            assert_eq!(stat.st_blocks, 2);
2691            assert_eq!(stat.st_uid, 9);
2692            assert_eq!(stat.st_gid, 10);
2693            assert_eq!(stat.st_nlink, 11);
2694            assert_eq!(stat.st_ctime, 0);
2695            assert_eq!(stat.st_ctime_nsec, 1);
2696            assert_eq!(stat.st_atime, 0);
2697            assert_eq!(stat.st_atime_nsec, 2);
2698            assert_eq!(stat.st_mtime, 0);
2699            assert_eq!(stat.st_mtime_nsec, 3);
2700            assert_eq!(stat.st_rdev, DeviceId::new(13, 13).bits());
2701        })
2702        .await;
2703    }
2704
2705    #[::fuchsia::test]
2706    fn test_flock_operation() {
2707        assert!(FlockOperation::from_flags(0).is_err());
2708        assert!(FlockOperation::from_flags(u32::MAX).is_err());
2709
2710        let operation1 = FlockOperation::from_flags(LOCK_SH).expect("from_flags");
2711        assert!(!operation1.is_unlock());
2712        assert!(!operation1.is_lock_exclusive());
2713        assert!(operation1.is_blocking());
2714
2715        let operation2 = FlockOperation::from_flags(LOCK_EX | LOCK_NB).expect("from_flags");
2716        assert!(!operation2.is_unlock());
2717        assert!(operation2.is_lock_exclusive());
2718        assert!(!operation2.is_blocking());
2719
2720        let operation3 = FlockOperation::from_flags(LOCK_UN).expect("from_flags");
2721        assert!(operation3.is_unlock());
2722        assert!(!operation3.is_lock_exclusive());
2723        assert!(operation3.is_blocking());
2724    }
2725
2726    #[::fuchsia::test]
2727    async fn test_check_access() {
2728        spawn_kernel_and_run(async |current_task| {
2729            let mut creds = Credentials::with_ids(1, 2);
2730            creds.groups = vec![3, 4];
2731            current_task.set_creds(creds);
2732
2733            // Create a node.
2734            let node = &current_task
2735                .fs()
2736                .root()
2737                .create_node(&current_task, "foo".into(), FileMode::IFREG, DeviceId::NONE)
2738                .expect("create_node")
2739                .entry
2740                .node;
2741            let check_access = |uid: uid_t, gid: gid_t, perm: u32, access: Access| {
2742                node.update_info(|info| {
2743                    info.mode = mode!(IFREG, perm);
2744                    info.uid = uid;
2745                    info.gid = gid;
2746                });
2747                node.check_access(
2748                    &current_task,
2749                    &MountInfo::detached(),
2750                    access,
2751                    CheckAccessReason::InternalPermissionChecks,
2752                    security::Auditable::Location(std::panic::Location::caller()),
2753                )
2754            };
2755
2756            assert_eq!(check_access(0, 0, 0o700, Access::EXEC), error!(EACCES));
2757            assert_eq!(check_access(0, 0, 0o700, Access::READ), error!(EACCES));
2758            assert_eq!(check_access(0, 0, 0o700, Access::WRITE), error!(EACCES));
2759
2760            assert_eq!(check_access(0, 0, 0o070, Access::EXEC), error!(EACCES));
2761            assert_eq!(check_access(0, 0, 0o070, Access::READ), error!(EACCES));
2762            assert_eq!(check_access(0, 0, 0o070, Access::WRITE), error!(EACCES));
2763
2764            assert_eq!(check_access(0, 0, 0o007, Access::EXEC), Ok(()));
2765            assert_eq!(check_access(0, 0, 0o007, Access::READ), Ok(()));
2766            assert_eq!(check_access(0, 0, 0o007, Access::WRITE), Ok(()));
2767
2768            assert_eq!(check_access(1, 0, 0o700, Access::EXEC), Ok(()));
2769            assert_eq!(check_access(1, 0, 0o700, Access::READ), Ok(()));
2770            assert_eq!(check_access(1, 0, 0o700, Access::WRITE), Ok(()));
2771
2772            assert_eq!(check_access(1, 0, 0o100, Access::EXEC), Ok(()));
2773            assert_eq!(check_access(1, 0, 0o100, Access::READ), error!(EACCES));
2774            assert_eq!(check_access(1, 0, 0o100, Access::WRITE), error!(EACCES));
2775
2776            assert_eq!(check_access(1, 0, 0o200, Access::EXEC), error!(EACCES));
2777            assert_eq!(check_access(1, 0, 0o200, Access::READ), error!(EACCES));
2778            assert_eq!(check_access(1, 0, 0o200, Access::WRITE), Ok(()));
2779
2780            assert_eq!(check_access(1, 0, 0o400, Access::EXEC), error!(EACCES));
2781            assert_eq!(check_access(1, 0, 0o400, Access::READ), Ok(()));
2782            assert_eq!(check_access(1, 0, 0o400, Access::WRITE), error!(EACCES));
2783
2784            assert_eq!(check_access(0, 2, 0o700, Access::EXEC), error!(EACCES));
2785            assert_eq!(check_access(0, 2, 0o700, Access::READ), error!(EACCES));
2786            assert_eq!(check_access(0, 2, 0o700, Access::WRITE), error!(EACCES));
2787
2788            assert_eq!(check_access(0, 2, 0o070, Access::EXEC), Ok(()));
2789            assert_eq!(check_access(0, 2, 0o070, Access::READ), Ok(()));
2790            assert_eq!(check_access(0, 2, 0o070, Access::WRITE), Ok(()));
2791
2792            assert_eq!(check_access(0, 3, 0o070, Access::EXEC), Ok(()));
2793            assert_eq!(check_access(0, 3, 0o070, Access::READ), Ok(()));
2794            assert_eq!(check_access(0, 3, 0o070, Access::WRITE), Ok(()));
2795        })
2796        .await;
2797    }
2798
2799    #[::fuchsia::test]
2800    async fn set_security_xattr_fails_without_security_module_or_root() {
2801        spawn_kernel_and_run(async |current_task| {
2802            let mut creds = Credentials::with_ids(1, 2);
2803            creds.groups = vec![3, 4];
2804            current_task.set_creds(creds);
2805
2806            // Create a node.
2807            let node = &current_task
2808                .fs()
2809                .root()
2810                .create_node(&current_task, "foo".into(), FileMode::IFREG, DeviceId::NONE)
2811                .expect("create_node")
2812                .entry
2813                .node;
2814
2815            // Give read-write-execute access.
2816            node.update_info(|info| info.mode = mode!(IFREG, 0o777));
2817
2818            // Without a security module, and without CAP_SYS_ADMIN capabilities, setting the xattr
2819            // should fail.
2820            assert_eq!(
2821                node.set_xattr(
2822                    &current_task,
2823                    &MountInfo::detached(),
2824                    "security.name".into(),
2825                    "security_label".into(),
2826                    XattrOp::Create,
2827                ),
2828                error!(EPERM)
2829            );
2830        })
2831        .await;
2832    }
2833
2834    #[::fuchsia::test]
2835    async fn set_non_user_xattr_fails_without_security_module_or_root() {
2836        spawn_kernel_and_run(async |current_task| {
2837            let mut creds = Credentials::with_ids(1, 2);
2838            creds.groups = vec![3, 4];
2839            current_task.set_creds(creds);
2840
2841            // Create a node.
2842            let node = &current_task
2843                .fs()
2844                .root()
2845                .create_node(&current_task, "foo".into(), FileMode::IFREG, DeviceId::NONE)
2846                .expect("create_node")
2847                .entry
2848                .node;
2849
2850            // Give read-write-execute access.
2851            node.update_info(|info| info.mode = mode!(IFREG, 0o777));
2852
2853            // Without a security module, and without CAP_SYS_ADMIN capabilities, setting the xattr
2854            // should fail.
2855            assert_eq!(
2856                node.set_xattr(
2857                    &current_task,
2858                    &MountInfo::detached(),
2859                    "trusted.name".into(),
2860                    "some data".into(),
2861                    XattrOp::Create,
2862                ),
2863                error!(EPERM)
2864            );
2865        })
2866        .await;
2867    }
2868
2869    #[::fuchsia::test]
2870    async fn get_security_xattr_succeeds_without_read_access() {
2871        spawn_kernel_and_run(async |current_task| {
2872            let mut creds = Credentials::with_ids(1, 2);
2873            creds.groups = vec![3, 4];
2874            current_task.set_creds(creds);
2875
2876            // Create a node.
2877            let node = &current_task
2878                .fs()
2879                .root()
2880                .create_node(&current_task, "foo".into(), FileMode::IFREG, DeviceId::NONE)
2881                .expect("create_node")
2882                .entry
2883                .node;
2884
2885            // Only give read access to the root and give root access to the current task.
2886            node.update_info(|info| info.mode = mode!(IFREG, 0o100));
2887            current_task.set_creds(Credentials::with_ids(0, 0));
2888
2889            // Setting the label should succeed even without write access to the file.
2890            assert_eq!(
2891                node.set_xattr(
2892                    &current_task,
2893                    &MountInfo::detached(),
2894                    "security.name".into(),
2895                    "security_label".into(),
2896                    XattrOp::Create,
2897                ),
2898                Ok(())
2899            );
2900
2901            // Remove root access from the current task.
2902            current_task.set_creds(Credentials::with_ids(1, 1));
2903
2904            // Getting the label should succeed even without read access to the file.
2905            assert_eq!(
2906                node.get_xattr(&current_task, &MountInfo::detached(), "security.name".into(), 4096),
2907                Ok(ValueOrSize::Value("security_label".into()))
2908            );
2909        })
2910        .await;
2911    }
2912
2913    #[fuchsia::test]
2914    async fn test_casefold_not_supported_by_default() {
2915        spawn_kernel_and_run(async |current_task| {
2916            let node = &current_task
2917                .fs()
2918                .root()
2919                .create_node(&current_task, "foo".into(), FileMode::IFREG, DeviceId::NONE)
2920                .expect("create_node")
2921                .entry
2922                .node;
2923
2924            assert!(!node.ops().has_casefold_support(node));
2925            assert_eq!(
2926                node.update_attributes(&current_task, |info| {
2927                    info.casefold = true;
2928                    Ok(())
2929                }),
2930                error!(ENOTSUP)
2931            );
2932        })
2933        .await;
2934    }
2935}