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