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