1use crate::device::DeviceMode;
6use crate::mm::PAGE_SIZE;
7use crate::security::{self, Auditable, PermissionFlags};
8use crate::signals::{SignalInfo, send_standard_signal};
9use crate::task::{CurrentTask, WaitQueue, Waiter, register_delayed_release};
10use crate::time::utc;
11use crate::vfs::fsverity::FsVerityState;
12use crate::vfs::pipe::{Pipe, PipeHandle};
13use crate::vfs::rw_queue::{RwQueue, RwQueueReadGuard, RwQueueWriteGuard};
14use crate::vfs::socket::SocketHandle;
15use crate::vfs::{
16 CheckAccessReason, DefaultDirEntryOps, DirEntry, DirEntryOps, FileObject, FileObjectState,
17 FileOps, FileSystem, FileSystemHandle, FileWriteGuardMode, FileWriteGuardRef,
18 FileWriteGuardState, FsLockDepType, FsStr, FsString, MAX_LFS_FILESIZE, MountInfo,
19 NamespaceNode, OPathOps, OpenAccessCheck, RecordLockCommand, RecordLockOwner, RecordLocks,
20 WeakFileHandle, checked_add_offset_and_length, inotify_hook,
21};
22use bitflags::bitflags;
23use fuchsia_runtime::UtcInstant;
24use linux_uapi::{XATTR_SECURITY_PREFIX, XATTR_SYSTEM_PREFIX, XATTR_TRUSTED_PREFIX};
25use once_cell::race::OnceBool;
26use smallvec::SmallVec;
27use starnix_crypt::EncryptionKeyId;
28use starnix_lifecycle::{ObjectReleaser, ReleaserAction};
29use starnix_logging::{log_error, track_stub};
30use starnix_sync::{
31 DynamicLockDepRwLock, FsNodeAppend, FsNodeFlockInfoLock, FsNodeFsVerityLock, FsNodeInfoLevel,
32 FsNodeInfoRecursiveLevel, FsNodeWriteGuardStateLock, FuseFsNodeInfoLevel, LockDepMutex,
33 LockDepReadGuard, allow_subclass,
34};
35use starnix_types::ownership::{Releasable, ReleaseGuard};
36use starnix_types::time::{NANOS_PER_SECOND, timespec_from_time};
37use starnix_uapi::as_any::AsAny;
38use starnix_uapi::auth::{
39 CAP_CHOWN, CAP_DAC_OVERRIDE, CAP_DAC_READ_SEARCH, CAP_FOWNER, CAP_FSETID, CAP_MKNOD,
40 CAP_SYS_ADMIN, CAP_SYS_RESOURCE, Credentials, FsCred,
41};
42use starnix_uapi::device_id::DeviceId;
43use starnix_uapi::errors::{EACCES, ENOTSUP, EPERM, Errno};
44use starnix_uapi::file_mode::{Access, FileMode};
45use starnix_uapi::inotify_mask::InotifyMask;
46use starnix_uapi::mount_flags::MountFlags;
47use starnix_uapi::open_flags::OpenFlags;
48use starnix_uapi::resource_limits::Resource;
49use starnix_uapi::seal_flags::SealFlags;
50use starnix_uapi::signals::SIGXFSZ;
51use starnix_uapi::{
52 FALLOC_FL_COLLAPSE_RANGE, FALLOC_FL_INSERT_RANGE, FALLOC_FL_KEEP_SIZE, FALLOC_FL_PUNCH_HOLE,
53 FALLOC_FL_UNSHARE_RANGE, FALLOC_FL_ZERO_RANGE, LOCK_EX, LOCK_NB, LOCK_SH, LOCK_UN,
54 STATX__RESERVED, STATX_ATIME, STATX_ATTR_VERITY, STATX_BASIC_STATS, STATX_BLOCKS, STATX_CTIME,
55 STATX_GID, STATX_INO, STATX_MTIME, STATX_NLINK, STATX_SIZE, STATX_UID, XATTR_USER_PREFIX,
56 errno, error, fsverity_descriptor, gid_t, ino_t, statx, statx_timestamp, timespec, uapi, uid_t,
57};
58use std::sync::atomic::Ordering;
59use std::sync::{Arc, OnceLock, Weak};
60use syncio::zxio_node_attr_has_t;
61
62#[derive(Debug, Clone, Copy, PartialEq, Eq)]
63pub enum FsNodeLinkBehavior {
64 Allowed,
65 Disallowed,
66}
67
68impl Default for FsNodeLinkBehavior {
69 fn default() -> Self {
70 FsNodeLinkBehavior::Allowed
71 }
72}
73
74pub type AppendLockGuard<'a> = RwQueueReadGuard<'a, FsNodeAppend>;
75pub type AppendLockWriteGuard<'a> = RwQueueWriteGuard<'a, FsNodeAppend>;
76
77bitflags! {
78 pub struct FsNodeFlags: u8 {
79 const IS_PRIVATE = 1 << 0;
80 }
81}
82
83pub struct FsNode {
84 pub ino: ino_t,
86
87 pub flags: FsNodeFlags,
89
90 ops: Box<dyn FsNodeOps>,
95
96 fs: Weak<FileSystem>,
98
99 pub append_lock: RwQueue<FsNodeAppend>,
105
106 info: DynamicLockDepRwLock<FsNodeInfo>,
110
111 rare_data: OnceLock<Box<FsNodeRareData>>,
113
114 pub write_guard_state: LockDepMutex<FileWriteGuardState, FsNodeWriteGuardStateLock>,
116
117 pub fsverity: LockDepMutex<FsVerityState, FsNodeFsVerityLock>,
119
120 pub security_state: security::FsNodeState,
123}
124
125#[derive(Default)]
126struct FsNodeRareData {
127 fifo: OnceLock<PipeHandle>,
131
132 bound_socket: OnceLock<SocketHandle>,
134
135 flock_info: LockDepMutex<FlockInfo, FsNodeFlockInfoLock>,
139
140 record_locks: RecordLocks,
142
143 link_behavior: OnceLock<FsNodeLinkBehavior>,
147
148 watchers: inotify_hook::InotifyWatchers,
150}
151
152impl FsNodeRareData {
153 fn ensure_fifo(&self, current_task: &CurrentTask) -> &PipeHandle {
154 self.fifo.get_or_init(|| {
155 let default_pipe_capacity = (*PAGE_SIZE * 16) as usize;
156 let kernel = current_task.kernel();
157 let max_size = kernel.system_limits.pipe_max_size.load(Ordering::Relaxed);
158 let capacity = if default_pipe_capacity <= max_size
159 || security::is_task_capable_noaudit(current_task, CAP_SYS_RESOURCE)
160 {
161 default_pipe_capacity
162 } else {
163 max_size
164 };
165 Pipe::new(capacity)
166 })
167 }
168}
169
170pub enum FsNodeReleaserAction {}
171impl ReleaserAction<FsNode> for FsNodeReleaserAction {
172 fn release(fs_node: ReleaseGuard<FsNode>) {
173 register_delayed_release(fs_node);
174 }
175}
176pub type FsNodeReleaser = ObjectReleaser<FsNode, FsNodeReleaserAction>;
177pub type FsNodeHandle = Arc<FsNodeReleaser>;
178pub type WeakFsNodeHandle = Weak<FsNodeReleaser>;
179
180bitflags! {
181 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
183 pub struct FscryptPolicyFlags: u8 {
184 const PAD_8 = uapi::FSCRYPT_POLICY_FLAGS_PAD_8 as u8;
185 const PAD_16 = uapi::FSCRYPT_POLICY_FLAGS_PAD_16 as u8;
186 const DIRECT_KEY = uapi::FSCRYPT_POLICY_FLAG_DIRECT_KEY as u8;
187 const IV_INO_LBLK_64 = uapi::FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64 as u8;
188 const IV_INO_LBLK_32 = uapi::FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32 as u8;
189 }
190}
191
192#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
193pub struct FscryptNodePolicy {
194 pub key_identifier: [u8; 16],
195 pub flags: FscryptPolicyFlags,
196}
197
198#[derive(Debug, Default, Clone, PartialEq)]
199pub struct FsNodeInfo {
200 pub mode: FileMode,
201 pub link_count: usize,
202 pub uid: uid_t,
203 pub gid: gid_t,
204 pub rdev: DeviceId,
205 pub size: usize,
206 pub blksize: usize,
207 pub blocks: usize,
208 pub time_status_change: UtcInstant,
209 pub time_access: UtcInstant,
210 pub time_modify: UtcInstant,
211 pub casefold: bool,
212
213 pub encryption_policy: Option<FscryptNodePolicy>,
216
217 pub pending_time_access_update: bool,
222}
223
224impl FsNodeInfo {
225 pub fn new(mode: FileMode, owner: FsCred) -> Self {
226 let now = utc::utc_now();
227 Self {
228 mode,
229 link_count: if mode.is_dir() { 2 } else { 1 },
230 uid: owner.uid,
231 gid: owner.gid,
232 blksize: DEFAULT_BYTES_PER_BLOCK,
233 time_status_change: now,
234 time_access: now,
235 time_modify: now,
236 ..Default::default()
237 }
238 }
239
240 pub fn storage_size(&self) -> usize {
241 self.blksize.saturating_mul(self.blocks)
242 }
243
244 pub fn chmod(&mut self, mode: FileMode) {
245 self.mode = (self.mode & !FileMode::PERMISSIONS) | (mode & FileMode::PERMISSIONS);
246 }
247
248 pub fn chown(&mut self, owner: Option<uid_t>, group: Option<gid_t>) {
249 if let Some(owner) = owner {
250 self.uid = owner;
251 }
252 if let Some(group) = group {
253 self.gid = group;
254 }
255 self.clear_suid_and_sgid_bits();
256 }
257
258 fn clear_sgid_bit(&mut self) {
259 if self.mode.intersects(FileMode::IXGRP) {
262 self.mode &= !FileMode::ISGID;
263 }
264 }
265
266 fn has_suid_or_sgid_bits(&self) -> bool {
267 self.mode.is_reg()
269 && (self.mode.contains(FileMode::ISUID)
270 || self.mode.contains(FileMode::ISGID | FileMode::IXGRP))
271 }
272
273 fn clear_suid_and_sgid_bits(&mut self) {
274 if self.mode.is_reg() {
276 self.mode &= !FileMode::ISUID;
277 self.clear_sgid_bit();
278 }
279 }
280
281 pub fn cred(&self) -> FsCred {
282 FsCred { uid: self.uid, gid: self.gid }
283 }
284
285 pub fn apply_suid_and_sgid(&self, creds: &mut Credentials) {
286 if self.mode.contains(FileMode::ISUID) {
287 creds.euid = self.uid;
288 }
289
290 if self.mode.contains(FileMode::ISGID | FileMode::IXGRP) {
298 creds.egid = self.gid;
299 }
300 }
301}
302
303#[derive(Default)]
304struct FlockInfo {
305 locked_exclusive: Option<bool>,
310 locking_handles: Vec<WeakFileHandle>,
312 wait_queue: WaitQueue,
314}
315
316impl FlockInfo {
317 pub fn retain<F>(&mut self, predicate: F)
320 where
321 F: Fn(&FileObject) -> bool,
322 {
323 if !self.locking_handles.is_empty() {
324 self.locking_handles
325 .retain(|w| if let Some(fh) = w.upgrade() { predicate(&fh) } else { false });
326 if self.locking_handles.is_empty() {
327 self.locked_exclusive = None;
328 self.wait_queue.notify_all();
329 }
330 }
331 }
332}
333
334pub const DEFAULT_BYTES_PER_BLOCK: usize = 512;
336
337pub struct FlockOperation {
338 operation: u32,
339}
340
341impl FlockOperation {
342 pub fn from_flags(operation: u32) -> Result<Self, Errno> {
343 if operation & !(LOCK_SH | LOCK_EX | LOCK_UN | LOCK_NB) != 0 {
344 return error!(EINVAL);
345 }
346 if [LOCK_SH, LOCK_EX, LOCK_UN].iter().filter(|&&o| operation & o == o).count() != 1 {
347 return error!(EINVAL);
348 }
349 Ok(Self { operation })
350 }
351
352 pub fn is_unlock(&self) -> bool {
353 self.operation & LOCK_UN > 0
354 }
355
356 pub fn is_lock_exclusive(&self) -> bool {
357 self.operation & LOCK_EX > 0
358 }
359
360 pub fn is_blocking(&self) -> bool {
361 self.operation & LOCK_NB == 0
362 }
363}
364
365impl FileObject {
366 pub fn flock(
370 &self,
371 current_task: &CurrentTask,
372 operation: FlockOperation,
373 ) -> Result<(), Errno> {
374 if self.flags().contains(OpenFlags::PATH) {
375 return error!(EBADF);
376 }
377 security::check_file_lock_access(current_task, self)?;
378 loop {
379 let mut flock_info = self.name.entry.node.ensure_rare_data().flock_info.lock();
380 if operation.is_unlock() {
381 flock_info.retain(|fh| !std::ptr::eq(fh, self));
382 return Ok(());
383 }
384 if flock_info.locked_exclusive.is_none() {
387 flock_info.locked_exclusive = Some(operation.is_lock_exclusive());
388 flock_info.locking_handles.push(self.weak_handle.clone());
389 return Ok(());
390 }
391
392 let file_lock_is_exclusive = flock_info.locked_exclusive == Some(true);
393 let fd_has_lock = flock_info
394 .locking_handles
395 .iter()
396 .find_map(|w| {
397 w.upgrade().and_then(|fh| {
398 if std::ptr::eq(&fh as &FileObject, self) { Some(()) } else { None }
399 })
400 })
401 .is_some();
402
403 if fd_has_lock {
405 if operation.is_lock_exclusive() == file_lock_is_exclusive {
406 return Ok(());
408 } else {
409 flock_info.retain(|fh| !std::ptr::eq(fh, self));
412 continue;
413 }
414 }
415
416 if !file_lock_is_exclusive && !operation.is_lock_exclusive() {
418 flock_info.locking_handles.push(self.weak_handle.clone());
420 return Ok(());
421 }
422
423 if !operation.is_blocking() {
425 return error!(EAGAIN);
426 }
427
428 let waiter = Waiter::new();
431 flock_info.wait_queue.wait_async(&waiter);
432 std::mem::drop(flock_info);
433 waiter.wait(current_task)?;
434 }
435 }
436}
437
438mod inner_flags {
441 #![allow(clippy::bad_bit_mask)] use super::{bitflags, uapi};
445
446 bitflags! {
447 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
448 pub struct StatxFlags: u32 {
449 const AT_SYMLINK_NOFOLLOW = uapi::AT_SYMLINK_NOFOLLOW;
450 const AT_EMPTY_PATH = uapi::AT_EMPTY_PATH;
451 const AT_NO_AUTOMOUNT = uapi::AT_NO_AUTOMOUNT;
452 const AT_STATX_SYNC_AS_STAT = uapi::AT_STATX_SYNC_AS_STAT;
453 const AT_STATX_FORCE_SYNC = uapi::AT_STATX_FORCE_SYNC;
454 const AT_STATX_DONT_SYNC = uapi::AT_STATX_DONT_SYNC;
455 const STATX_ATTR_VERITY = uapi::STATX_ATTR_VERITY;
456 }
457 }
458}
459
460pub use inner_flags::StatxFlags;
461
462#[derive(Copy, Clone, Debug, PartialEq, Eq)]
463pub enum UnlinkKind {
464 Directory,
466
467 NonDirectory,
469}
470
471pub enum SymlinkTarget {
472 Path(FsString),
473 Node(NamespaceNode),
474}
475
476#[derive(Clone, Copy, PartialEq, Eq)]
477pub enum XattrOp {
478 Set,
480 Create,
482 Replace,
484}
485
486impl XattrOp {
487 pub fn into_flags(self) -> u32 {
488 match self {
489 Self::Set => 0,
490 Self::Create => uapi::XATTR_CREATE,
491 Self::Replace => uapi::XATTR_REPLACE,
492 }
493 }
494}
495
496#[derive(Clone, Debug, PartialEq)]
498pub enum ValueOrSize<T> {
499 Value(T),
500 Size(usize),
501}
502
503impl<T> ValueOrSize<T> {
504 pub fn map<F, U>(self, f: F) -> ValueOrSize<U>
505 where
506 F: FnOnce(T) -> U,
507 {
508 match self {
509 Self::Size(s) => ValueOrSize::Size(s),
510 Self::Value(v) => ValueOrSize::Value(f(v)),
511 }
512 }
513
514 #[cfg(test)]
515 pub fn unwrap(self) -> T {
516 match self {
517 Self::Size(_) => panic!("Unwrap ValueOrSize that is a Size"),
518 Self::Value(v) => v,
519 }
520 }
521}
522
523impl<T> From<T> for ValueOrSize<T> {
524 fn from(t: T) -> Self {
525 Self::Value(t)
526 }
527}
528
529#[derive(Copy, Clone, Eq, PartialEq, Debug)]
530pub enum FallocMode {
531 Allocate { keep_size: bool },
532 PunchHole,
533 Collapse,
534 Zero { keep_size: bool },
535 InsertRange,
536 UnshareRange,
537}
538
539impl FallocMode {
540 pub fn from_bits(mode: u32) -> Option<Self> {
541 if mode == 0 {
543 Some(Self::Allocate { keep_size: false })
544 } else if mode == FALLOC_FL_KEEP_SIZE {
545 Some(Self::Allocate { keep_size: true })
546 } else if mode == FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE {
547 Some(Self::PunchHole)
548 } else if mode == FALLOC_FL_COLLAPSE_RANGE {
549 Some(Self::Collapse)
550 } else if mode == FALLOC_FL_ZERO_RANGE {
551 Some(Self::Zero { keep_size: false })
552 } else if mode == FALLOC_FL_ZERO_RANGE | FALLOC_FL_KEEP_SIZE {
553 Some(Self::Zero { keep_size: true })
554 } else if mode == FALLOC_FL_INSERT_RANGE {
555 Some(Self::InsertRange)
556 } else if mode == FALLOC_FL_UNSHARE_RANGE {
557 Some(Self::UnshareRange)
558 } else {
559 None
560 }
561 }
562}
563
564pub type LookupVec<T> = SmallVec<[T; 8]>;
565
566pub trait FsNodeOps: Send + Sync + AsAny + 'static {
567 fn check_access(
569 &self,
570 node: &FsNode,
571 current_task: &CurrentTask,
572 access: security::PermissionFlags,
573 info: &DynamicLockDepRwLock<FsNodeInfo>,
574 reason: CheckAccessReason,
575 audit_context: security::Auditable<'_>,
576 ) -> Result<(), Errno> {
577 node.default_check_access_impl(current_task, access, reason, info.read(), audit_context)
578 }
579
580 fn create_dir_entry_ops(&self) -> Box<dyn DirEntryOps> {
583 Box::new(DefaultDirEntryOps)
584 }
585
586 fn create_child_dir_entry_ops(&self) -> Option<Box<dyn DirEntryOps>> {
592 None
593 }
594
595 fn create_file_ops(
600 &self,
601 node: &FsNode,
602 _current_task: &CurrentTask,
603 flags: OpenFlags,
604 ) -> Result<Box<dyn FileOps>, Errno>;
605
606 fn lookup(
608 &self,
609 _entry: &DirEntry,
610 _current_task: &CurrentTask,
611 name: &FsStr,
612 ) -> Result<FsNodeHandle, Errno> {
613 error!(ENOENT, format!("looking for {name}"))
616 }
617
618 fn has_lookup_pipelined(&self) -> bool {
620 false
621 }
622
623 fn lookup_pipelined(
632 &self,
633 _entry: &DirEntry,
634 _current_task: &CurrentTask,
635 _names: &[&FsStr],
636 ) -> LookupVec<Result<FsNodeHandle, Errno>> {
637 panic!("has_lookup_pipelined should be false");
638 }
639
640 fn mknod(
648 &self,
649 node: &FsNode,
650 _current_task: &CurrentTask,
651 _name: &FsStr,
652 _mode: FileMode,
653 _dev: DeviceId,
654 _owner: FsCred,
655 ) -> Result<FsNodeHandle, Errno>;
656
657 fn mkdir(
659 &self,
660 node: &FsNode,
661 _current_task: &CurrentTask,
662 _name: &FsStr,
663 _mode: FileMode,
664 _owner: FsCred,
665 ) -> Result<FsNodeHandle, Errno>;
666
667 fn create_symlink(
669 &self,
670 node: &FsNode,
671 _current_task: &CurrentTask,
672 _name: &FsStr,
673 _target: &FsStr,
674 _owner: FsCred,
675 ) -> Result<FsNodeHandle, Errno>;
676
677 fn create_tmpfile(
683 &self,
684 _node: &FsNode,
685 _current_task: &CurrentTask,
686 _mode: FileMode,
687 _owner: FsCred,
688 ) -> Result<FsNodeHandle, Errno> {
689 error!(EOPNOTSUPP)
690 }
691
692 fn readlink(
694 &self,
695 _node: &FsNode,
696 _current_task: &CurrentTask,
697 ) -> Result<SymlinkTarget, Errno> {
698 error!(EINVAL)
699 }
700
701 fn link(
703 &self,
704 _node: &FsNode,
705 _current_task: &CurrentTask,
706 _name: &FsStr,
707 _child: &FsNodeHandle,
708 ) -> Result<(), Errno> {
709 error!(EPERM)
710 }
711
712 fn unlink(
717 &self,
718 node: &FsNode,
719 _current_task: &CurrentTask,
720 _name: &FsStr,
721 _child: &FsNodeHandle,
722 ) -> Result<(), Errno>;
723
724 fn append_lock_read<'a>(
727 &'a self,
728 node: &'a FsNode,
729 current_task: &CurrentTask,
730 ) -> Result<AppendLockGuard<'a>, Errno> {
731 return node.append_lock.read(current_task);
732 }
733
734 fn append_lock_write<'a>(
736 &'a self,
737 node: &'a FsNode,
738 current_task: &CurrentTask,
739 ) -> Result<AppendLockWriteGuard<'a>, Errno> {
740 return node.append_lock.write(current_task);
741 }
742
743 fn truncate(
745 &self,
746 _guard: &AppendLockWriteGuard<'_>,
747 _node: &FsNode,
748 _current_task: &CurrentTask,
749 _length: u64,
750 ) -> Result<(), Errno> {
751 error!(EINVAL)
752 }
753
754 fn allocate(
756 &self,
757 _guard: &AppendLockWriteGuard<'_>,
758 _node: &FsNode,
759 _current_task: &CurrentTask,
760 _mode: FallocMode,
761 _offset: u64,
762 _length: u64,
763 ) -> Result<(), Errno> {
764 error!(EINVAL)
765 }
766
767 fn initial_info(&self, _info: &mut FsNodeInfo) {}
772
773 fn fetch_and_refresh_info<'a>(
784 &self,
785 _node: &FsNode,
786 _current_task: &CurrentTask,
787 info: &'a DynamicLockDepRwLock<FsNodeInfo>,
788 _flags: StatxFlags,
789 ) -> Result<LockDepReadGuard<'a, FsNodeInfo>, Errno> {
790 Ok(info.read())
791 }
792
793 fn sync(&self, _node: &FsNode, _current_task: &CurrentTask) -> Result<(), Errno> {
795 Ok(())
796 }
797
798 fn update_attributes(
803 &self,
804 _node: &FsNode,
805 _current_task: &CurrentTask,
806 _info: &FsNodeInfo,
807 _has: zxio_node_attr_has_t,
808 ) -> Result<(), Errno> {
809 Ok(())
810 }
811
812 fn get_xattr(
818 &self,
819 _node: &FsNode,
820 _current_task: &CurrentTask,
821 _name: &FsStr,
822 _max_size: usize,
823 ) -> Result<ValueOrSize<Box<[u8]>>, Errno> {
824 error!(ENOTSUP)
825 }
826
827 fn set_xattr(
829 &self,
830 _node: &FsNode,
831 _current_task: &CurrentTask,
832 _name: &FsStr,
833 _value: &[u8],
834 _op: XattrOp,
835 ) -> Result<(), Errno> {
836 error!(ENOTSUP)
837 }
838
839 fn remove_xattr(
840 &self,
841 _node: &FsNode,
842 _current_task: &CurrentTask,
843 _name: &FsStr,
844 ) -> Result<(), Errno> {
845 error!(ENOTSUP)
846 }
847
848 fn list_xattrs(
852 &self,
853 _node: &FsNode,
854 _current_task: &CurrentTask,
855 _max_size: usize,
856 ) -> Result<ValueOrSize<Vec<FsString>>, Errno> {
857 error!(ENOTSUP)
858 }
859
860 fn forget(
862 self: Box<Self>,
863 _current_task: &CurrentTask,
864 _info: FsNodeInfo,
865 ) -> Result<(), Errno> {
866 Ok(())
867 }
868
869 fn enable_fsverity(
877 &self,
878 _node: &FsNode,
879 _current_task: &CurrentTask,
880 _descriptor: &fsverity_descriptor,
881 ) -> Result<(), Errno> {
882 error!(ENOTSUP)
883 }
884
885 fn get_fsverity_descriptor(&self, _log_blocksize: u8) -> Result<fsverity_descriptor, Errno> {
887 error!(ENOTSUP)
888 }
889
890 fn node_key(&self, node: &FsNode) -> ino_t {
895 node.ino
896 }
897
898 fn get_size(&self, node: &FsNode, current_task: &CurrentTask) -> Result<usize, Errno> {
900 let info = node.fetch_and_refresh_info(current_task)?;
901 Ok(info.size.try_into().map_err(|_| errno!(EINVAL))?)
902 }
903}
904
905impl<T> From<T> for Box<dyn FsNodeOps>
906where
907 T: FsNodeOps,
908{
909 fn from(ops: T) -> Box<dyn FsNodeOps> {
910 Box::new(ops)
911 }
912}
913
914#[macro_export]
917macro_rules! fs_node_impl_symlink {
918 () => {
919 $crate::vfs::fs_node_impl_not_dir!();
920
921 fn create_file_ops(
922 &self,
923 node: &$crate::vfs::FsNode,
924 _current_task: &CurrentTask,
925 _flags: starnix_uapi::open_flags::OpenFlags,
926 ) -> Result<Box<dyn $crate::vfs::FileOps>, starnix_uapi::errors::Errno> {
927 assert!(node.is_lnk());
928 unreachable!("Symlink nodes cannot be opened.");
929 }
930 };
931}
932
933#[macro_export]
934macro_rules! fs_node_impl_dir_readonly_ops {
935 () => {
936 fn mkdir(
937 &self,
938 _node: &$crate::vfs::FsNode,
939 _current_task: &$crate::task::CurrentTask,
940 name: &$crate::vfs::FsStr,
941 _mode: starnix_uapi::file_mode::FileMode,
942 _owner: starnix_uapi::auth::FsCred,
943 ) -> Result<$crate::vfs::FsNodeHandle, starnix_uapi::errors::Errno> {
944 starnix_uapi::error!(EROFS, format!("mkdir failed: {:?}", name))
945 }
946
947 fn mknod(
948 &self,
949 _node: &$crate::vfs::FsNode,
950 _current_task: &$crate::task::CurrentTask,
951 name: &$crate::vfs::FsStr,
952 _mode: starnix_uapi::file_mode::FileMode,
953 _dev: starnix_uapi::device_id::DeviceId,
954 _owner: starnix_uapi::auth::FsCred,
955 ) -> Result<$crate::vfs::FsNodeHandle, starnix_uapi::errors::Errno> {
956 starnix_uapi::error!(EROFS, format!("mknod failed: {:?}", name))
957 }
958
959 fn create_symlink(
960 &self,
961 _node: &$crate::vfs::FsNode,
962 _current_task: &$crate::task::CurrentTask,
963 name: &$crate::vfs::FsStr,
964 _target: &$crate::vfs::FsStr,
965 _owner: starnix_uapi::auth::FsCred,
966 ) -> Result<$crate::vfs::FsNodeHandle, starnix_uapi::errors::Errno> {
967 starnix_uapi::error!(EROFS, format!("symlink failed: {:?}", name))
968 }
969
970 fn link(
971 &self,
972 _node: &$crate::vfs::FsNode,
973 _current_task: &$crate::task::CurrentTask,
974 name: &$crate::vfs::FsStr,
975 _child: &$crate::vfs::FsNodeHandle,
976 ) -> Result<(), starnix_uapi::errors::Errno> {
977 starnix_uapi::error!(EROFS, format!("link failed: {:?}", name))
978 }
979
980 fn unlink(
981 &self,
982 _node: &$crate::vfs::FsNode,
983 _current_task: &$crate::task::CurrentTask,
984 name: &$crate::vfs::FsStr,
985 _child: &$crate::vfs::FsNodeHandle,
986 ) -> Result<(), starnix_uapi::errors::Errno> {
987 starnix_uapi::error!(EROFS, format!("unlink failed: {:?}", name))
988 }
989 };
990}
991
992#[macro_export]
993macro_rules! fs_node_impl_dir_readonly {
994 () => {
995 $crate::vfs::fs_node_impl_dir_readonly_ops!();
996
997 fn check_access(
998 &self,
999 node: &$crate::vfs::FsNode,
1000 current_task: &$crate::task::CurrentTask,
1001 permission_flags: $crate::security::PermissionFlags,
1002 info: &starnix_sync::DynamicLockDepRwLock<$crate::vfs::FsNodeInfo>,
1003 reason: $crate::vfs::CheckAccessReason,
1004 audit_context: $crate::security::Auditable<'_>,
1005 ) -> Result<(), starnix_uapi::errors::Errno> {
1006 let access = permission_flags.as_access();
1007 if access.contains(starnix_uapi::file_mode::Access::WRITE) {
1008 return starnix_uapi::error!(
1009 EROFS,
1010 format!("check_access failed: read-only directory")
1011 );
1012 }
1013 node.default_check_access_impl(
1014 current_task,
1015 permission_flags,
1016 reason,
1017 info.read(),
1018 audit_context,
1019 )
1020 }
1021 };
1022}
1023
1024pub trait XattrStorage {
1029 fn get_xattr(&self, name: &FsStr) -> Result<Box<[u8]>, Errno>;
1031
1032 fn set_xattr(&self, name: &FsStr, value: &[u8], op: XattrOp) -> Result<(), Errno>;
1034
1035 fn remove_xattr(&self, name: &FsStr) -> Result<(), Errno>;
1037
1038 fn list_xattrs(&self) -> Result<Vec<FsString>, Errno>;
1040}
1041
1042#[macro_export]
1064macro_rules! fs_node_impl_xattr_delegate {
1065 ($self:ident, $delegate:expr) => {
1066 fn get_xattr(
1067 &$self,
1068 _node: &FsNode,
1069 _current_task: &CurrentTask,
1070 name: &$crate::vfs::FsStr,
1071 _size: usize,
1072 ) -> Result<$crate::vfs::ValueOrSize<Box<[u8]>>, starnix_uapi::errors::Errno> {
1073 Ok($delegate.get_xattr(name)?.into())
1074 }
1075
1076 fn set_xattr(
1077 &$self,
1078 _node: &FsNode,
1079 _current_task: &CurrentTask,
1080 name: &$crate::vfs::FsStr,
1081 value: &[u8],
1082 op: $crate::vfs::XattrOp,
1083 ) -> Result<(), starnix_uapi::errors::Errno> {
1084 $delegate.set_xattr(name, value, op)
1085 }
1086
1087 fn remove_xattr(
1088 &$self,
1089 _node: &FsNode,
1090 _current_task: &CurrentTask,
1091 name: &$crate::vfs::FsStr,
1092 ) -> Result<(), starnix_uapi::errors::Errno> {
1093 $delegate.remove_xattr(name)
1094 }
1095
1096 fn list_xattrs(
1097 &$self,
1098 _node: &FsNode,
1099 _current_task: &CurrentTask,
1100 _size: usize,
1101 ) -> Result<$crate::vfs::ValueOrSize<Vec<$crate::vfs::FsString>>, starnix_uapi::errors::Errno> {
1102 Ok($delegate.list_xattrs()?.into())
1103 }
1104 };
1105}
1106
1107#[macro_export]
1109macro_rules! fs_node_impl_not_dir {
1110 () => {
1111 fn lookup(
1112 &self,
1113 _entry: &$crate::vfs::DirEntry,
1114 _current_task: &$crate::task::CurrentTask,
1115 _name: &$crate::vfs::FsStr,
1116 ) -> Result<$crate::vfs::FsNodeHandle, starnix_uapi::errors::Errno> {
1117 starnix_uapi::error!(ENOTDIR)
1118 }
1119
1120 fn mknod(
1121 &self,
1122 _node: &$crate::vfs::FsNode,
1123 _current_task: &$crate::task::CurrentTask,
1124 _name: &$crate::vfs::FsStr,
1125 _mode: starnix_uapi::file_mode::FileMode,
1126 _dev: starnix_uapi::device_id::DeviceId,
1127 _owner: starnix_uapi::auth::FsCred,
1128 ) -> Result<$crate::vfs::FsNodeHandle, starnix_uapi::errors::Errno> {
1129 starnix_uapi::error!(ENOTDIR)
1130 }
1131
1132 fn mkdir(
1133 &self,
1134 _node: &$crate::vfs::FsNode,
1135 _current_task: &$crate::task::CurrentTask,
1136 _name: &$crate::vfs::FsStr,
1137 _mode: starnix_uapi::file_mode::FileMode,
1138 _owner: starnix_uapi::auth::FsCred,
1139 ) -> Result<$crate::vfs::FsNodeHandle, starnix_uapi::errors::Errno> {
1140 starnix_uapi::error!(ENOTDIR)
1141 }
1142
1143 fn create_symlink(
1144 &self,
1145 _node: &$crate::vfs::FsNode,
1146 _current_task: &$crate::task::CurrentTask,
1147 _name: &$crate::vfs::FsStr,
1148 _target: &$crate::vfs::FsStr,
1149 _owner: starnix_uapi::auth::FsCred,
1150 ) -> Result<$crate::vfs::FsNodeHandle, starnix_uapi::errors::Errno> {
1151 starnix_uapi::error!(ENOTDIR)
1152 }
1153
1154 fn unlink(
1155 &self,
1156 _node: &$crate::vfs::FsNode,
1157 _current_task: &$crate::task::CurrentTask,
1158 _name: &$crate::vfs::FsStr,
1159 _child: &$crate::vfs::FsNodeHandle,
1160 ) -> Result<(), starnix_uapi::errors::Errno> {
1161 starnix_uapi::error!(ENOTDIR)
1162 }
1163 };
1164}
1165
1166#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1167pub enum TimeUpdateType {
1168 Now,
1169 Omit,
1170 Time(UtcInstant),
1171}
1172
1173pub use fs_node_impl_dir_readonly;
1175pub use fs_node_impl_dir_readonly_ops;
1176pub use fs_node_impl_not_dir;
1177pub use fs_node_impl_symlink;
1178pub use fs_node_impl_xattr_delegate;
1179
1180pub struct SpecialNode;
1181
1182impl FsNodeOps for SpecialNode {
1183 fs_node_impl_not_dir!();
1184
1185 fn create_file_ops(
1186 &self,
1187 _node: &FsNode,
1188 _current_task: &CurrentTask,
1189 _flags: OpenFlags,
1190 ) -> Result<Box<dyn FileOps>, Errno> {
1191 unreachable!("Special nodes cannot be opened.");
1192 }
1193}
1194
1195impl FsNode {
1196 pub fn is_private(&self) -> bool {
1199 self.flags.contains(FsNodeFlags::IS_PRIVATE)
1200 }
1201
1202 pub fn new_uncached(
1207 ino: ino_t,
1208 ops: impl Into<Box<dyn FsNodeOps>>,
1209 fs: &FileSystemHandle,
1210 info: FsNodeInfo,
1211 flags: FsNodeFlags,
1212 ) -> FsNodeHandle {
1213 let ops = ops.into();
1214 FsNodeHandle::new(Self::new_internal(ino, ops, Arc::downgrade(fs), info, flags).into())
1215 }
1216
1217 fn new_internal(
1218 ino: ino_t,
1219 ops: Box<dyn FsNodeOps>,
1220 fs: Weak<FileSystem>,
1221 info: FsNodeInfo,
1222 flags: FsNodeFlags,
1223 ) -> Self {
1224 let mut info = info;
1226 ops.initial_info(&mut info);
1227
1228 let fs_lockdep_type =
1229 fs.upgrade().map(|fs| fs.fs_lockdep_type()).unwrap_or(FsLockDepType::Normal);
1230 let info_lock = match fs_lockdep_type {
1231 FsLockDepType::Normal => DynamicLockDepRwLock::new::<FsNodeInfoLevel>(info),
1232 FsLockDepType::Fuse => DynamicLockDepRwLock::new::<FuseFsNodeInfoLevel>(info),
1233 FsLockDepType::Recursive => DynamicLockDepRwLock::new::<FsNodeInfoRecursiveLevel>(info),
1234 };
1235
1236 #[allow(clippy::let_and_return)]
1238 {
1239 let result = Self {
1240 ino,
1241 flags,
1242 ops,
1243 fs,
1244 info: info_lock,
1245 append_lock: Default::default(),
1246 rare_data: Default::default(),
1247 write_guard_state: Default::default(),
1248 fsverity: Default::default(),
1249 security_state: Default::default(),
1250 };
1251 #[cfg(any(test, debug_assertions))]
1252 {
1253 let _l1 = result.append_lock.read_for_lock_ordering();
1254 let _l2 = result.info.read();
1255 let _l3 = result.write_guard_state.lock();
1256 let _l4 = result.fsverity.lock();
1257 }
1258 result
1259 }
1260 }
1261
1262 pub fn fs(&self) -> FileSystemHandle {
1263 self.fs.upgrade().expect("FileSystem did not live long enough")
1264 }
1265
1266 pub fn try_fs(&self) -> Option<FileSystemHandle> {
1267 self.fs.upgrade()
1268 }
1269
1270 pub fn ops(&self) -> &dyn FsNodeOps {
1271 self.ops.as_ref()
1272 }
1273
1274 pub fn fail_if_locked(
1278 &self,
1279 _current_task: &CurrentTask,
1280 node_info: &FsNodeInfo,
1281 ) -> Result<(), Errno> {
1282 if let Some(policy) = node_info.encryption_policy {
1283 let crypt_service = self.fs().crypt_service().ok_or_else(|| errno!(ENOKEY))?;
1284 if !crypt_service.contains_key(EncryptionKeyId::from(policy.key_identifier)) {
1285 return error!(ENOKEY);
1286 }
1287 }
1288 Ok(())
1289 }
1290
1291 pub fn downcast_ops<T>(&self) -> Option<&T>
1293 where
1294 T: 'static,
1295 {
1296 self.ops().as_any().downcast_ref::<T>()
1297 }
1298
1299 pub fn on_file_closed(&self, file: &FileObjectState) {
1300 if let Some(rare_data) = self.rare_data.get() {
1301 let mut flock_info = rare_data.flock_info.lock();
1302 flock_info.retain(|_| true);
1305 }
1306 self.record_lock_release(RecordLockOwner::FileObject(file.id));
1307 }
1308
1309 pub fn record_lock(
1310 &self,
1311 current_task: &CurrentTask,
1312 file: &FileObject,
1313 cmd: RecordLockCommand,
1314 flock: uapi::flock,
1315 ) -> Result<Option<uapi::flock>, Errno> {
1316 self.ensure_rare_data().record_locks.lock(current_task, file, cmd, flock)
1317 }
1318
1319 pub fn record_lock_release(&self, owner: RecordLockOwner) {
1321 if let Some(rare_data) = self.rare_data.get() {
1322 rare_data.record_locks.release_locks(owner);
1323 }
1324 }
1325
1326 pub fn create_dir_entry_ops(&self) -> Box<dyn DirEntryOps> {
1327 self.ops().create_dir_entry_ops()
1328 }
1329
1330 pub fn create_child_dir_entry_ops(&self) -> Option<Box<dyn DirEntryOps>> {
1331 self.ops().create_child_dir_entry_ops()
1332 }
1333
1334 pub fn create_file_ops(
1335 &self,
1336 current_task: &CurrentTask,
1337 flags: OpenFlags,
1338 ) -> Result<Box<dyn FileOps>, Errno> {
1339 self.ops().create_file_ops(self, current_task, flags)
1340 }
1341
1342 pub fn open(
1343 &self,
1344 current_task: &CurrentTask,
1345 namespace_node: &NamespaceNode,
1346 open_check: impl Into<OpenAccessCheck>,
1347 ) -> Result<Box<dyn FileOps>, Errno> {
1348 let open_check = open_check.into();
1349 let flags = open_check.open_flags();
1350 if flags.contains(OpenFlags::PATH) {
1353 return Ok(Box::new(OPathOps::new()));
1354 }
1355
1356 let access_check = open_check.access_check();
1357 let permission_flags = access_check.permission_flags();
1358 if !permission_flags.is_empty() {
1359 if flags.contains(OpenFlags::NOATIME) {
1360 self.check_o_noatime_allowed(current_task)?;
1361 }
1362
1363 self.check_access(
1364 current_task,
1365 &namespace_node.mount,
1366 permission_flags,
1367 access_check.reason(),
1368 namespace_node,
1369 )?;
1370 }
1371
1372 let (mode, rdev) = {
1373 let info = self.info();
1376 (info.mode, info.rdev)
1377 };
1378
1379 match mode & FileMode::IFMT {
1380 FileMode::IFCHR => {
1381 if namespace_node.mount.flags().contains(MountFlags::NODEV) {
1382 return error!(EACCES);
1383 }
1384 current_task.kernel().open_device(
1385 current_task,
1386 namespace_node,
1387 flags,
1388 rdev,
1389 DeviceMode::Char,
1390 )
1391 }
1392 FileMode::IFBLK => {
1393 if namespace_node.mount.flags().contains(MountFlags::NODEV) {
1394 return error!(EACCES);
1395 }
1396 current_task.kernel().open_device(
1397 current_task,
1398 namespace_node,
1399 flags,
1400 rdev,
1401 DeviceMode::Block,
1402 )
1403 }
1404 FileMode::IFIFO => Pipe::open(current_task, self.fifo(current_task), flags),
1405 FileMode::IFSOCK => error!(ENXIO),
1407 _ => self.create_file_ops(current_task, flags),
1408 }
1409 }
1410
1411 pub fn create_node(
1412 &self,
1413 current_task: &CurrentTask,
1414 mount: &MountInfo,
1415 name: &FsStr,
1416 mut mode: FileMode,
1417 dev: DeviceId,
1418 mut owner: FsCred,
1419 ) -> Result<FsNodeHandle, Errno> {
1420 assert!(
1421 !matches!(mode.fmt(), FileMode::EMPTY | FileMode::IFLNK),
1422 "create_node with missing or symlink node type"
1423 );
1424
1425 self.check_access(
1426 current_task,
1427 mount,
1428 Access::WRITE,
1429 CheckAccessReason::InternalPermissionChecks,
1430 security::Auditable::Name(name),
1431 )?;
1432
1433 if mode.is_dir() {
1434 security::check_fs_node_mkdir_access(current_task, self, mode, name)?;
1438 } else {
1439 match mode.fmt() {
1448 FileMode::IFREG | FileMode::IFIFO | FileMode::IFSOCK => (),
1449 FileMode::IFCHR if dev == DeviceId::NONE => (),
1450 _ => security::check_task_capable(current_task, CAP_MKNOD)?,
1451 }
1452
1453 if mode.is_reg() {
1454 security::check_fs_node_create_access(current_task, self, mode, name)?;
1455 } else {
1456 security::check_fs_node_mknod_access(current_task, self, mode, name, dev)?;
1457 }
1458 }
1459
1460 self.update_metadata_for_child(current_task, &mut mode, &mut owner);
1462
1463 let new_node = if mode.is_dir() {
1465 self.ops().mkdir(self, current_task, name, mode, owner)?
1466 } else {
1467 self.ops().mknod(self, current_task, name, mode, dev, owner)?
1468 };
1469
1470 self.init_new_node_security_on_create(current_task, &new_node, name)?;
1472
1473 Ok(new_node)
1474 }
1475
1476 pub fn create_symlink(
1477 &self,
1478 current_task: &CurrentTask,
1479 mount: &MountInfo,
1480 name: &FsStr,
1481 target: &FsStr,
1482 owner: FsCred,
1483 ) -> Result<FsNodeHandle, Errno> {
1484 self.check_access(
1485 current_task,
1486 mount,
1487 Access::WRITE,
1488 CheckAccessReason::InternalPermissionChecks,
1489 security::Auditable::Name(name),
1490 )?;
1491 security::check_fs_node_symlink_access(current_task, self, name, target)?;
1492
1493 let new_node = self.ops().create_symlink(self, current_task, name, target, owner)?;
1494
1495 self.init_new_node_security_on_create(current_task, &new_node, name)?;
1496
1497 Ok(new_node)
1498 }
1499
1500 fn init_new_node_security_on_create(
1505 &self,
1506 current_task: &CurrentTask,
1507 new_node: &FsNode,
1508 name: &FsStr,
1509 ) -> Result<(), Errno> {
1510 if new_node.fs().name() == "overlay" {
1511 return Ok(());
1515 }
1516 security::fs_node_init_on_create(current_task, &new_node, self, name)?
1517 .map(|xattr| {
1518 match new_node.ops().set_xattr(
1519 &new_node,
1520 current_task,
1521 xattr.name,
1522 &xattr.value,
1523 XattrOp::Create,
1524 ) {
1525 Err(e) => {
1526 if e.code == ENOTSUP {
1527 Ok(())
1530 } else {
1531 Err(e)
1532 }
1533 }
1534 result => result,
1535 }
1536 })
1537 .unwrap_or_else(|| Ok(()))
1538 }
1539
1540 pub fn create_tmpfile(
1541 &self,
1542 current_task: &CurrentTask,
1543 mount: &MountInfo,
1544 mut mode: FileMode,
1545 mut owner: FsCred,
1546 link_behavior: FsNodeLinkBehavior,
1547 ) -> Result<FsNodeHandle, Errno> {
1548 self.check_access(
1549 current_task,
1550 mount,
1551 Access::WRITE,
1552 CheckAccessReason::InternalPermissionChecks,
1553 security::Auditable::Location(std::panic::Location::caller()),
1554 )?;
1555 self.update_metadata_for_child(current_task, &mut mode, &mut owner);
1556 let node = self.ops().create_tmpfile(self, current_task, mode, owner)?;
1557 self.init_new_node_security_on_create(current_task, &node, "".into())?;
1558 if link_behavior == FsNodeLinkBehavior::Disallowed {
1559 node.ensure_rare_data().link_behavior.set(link_behavior).unwrap();
1560 }
1561 Ok(node)
1562 }
1563
1564 pub fn readlink(&self, current_task: &CurrentTask) -> Result<SymlinkTarget, Errno> {
1567 if !self.is_lnk() {
1569 return error!(EINVAL);
1570 }
1571 security::check_fs_node_read_link_access(current_task, self)?;
1573 self.ops().readlink(self, current_task)
1574 }
1575
1576 pub fn link(
1577 &self,
1578 current_task: &CurrentTask,
1579 mount: &MountInfo,
1580 name: &FsStr,
1581 child: &FsNodeHandle,
1582 ) -> Result<FsNodeHandle, Errno> {
1583 self.check_access(
1584 current_task,
1585 mount,
1586 Access::WRITE,
1587 CheckAccessReason::InternalPermissionChecks,
1588 security::Auditable::Location(std::panic::Location::caller()),
1589 )?;
1590
1591 if child.is_dir() {
1592 return error!(EPERM);
1593 }
1594
1595 if let Some(child_rare_data) = child.rare_data.get() {
1596 if matches!(child_rare_data.link_behavior.get(), Some(FsNodeLinkBehavior::Disallowed)) {
1597 return error!(ENOENT);
1598 }
1599 }
1600
1601 let (child_uid, mode) = {
1608 let info = child.info();
1609 (info.uid, info.mode)
1610 };
1611 if child_uid != current_task.current_creds().fsuid
1615 && !security::is_task_capable_noaudit(current_task, CAP_FOWNER)
1616 {
1617 child
1620 .check_access(
1621 current_task,
1622 mount,
1623 Access::READ | Access::WRITE,
1624 CheckAccessReason::InternalPermissionChecks,
1625 security::Auditable::Name(name),
1626 )
1627 .map_err(|e| {
1628 if e == EACCES { errno!(EPERM) } else { e }
1631 })?;
1632 if mode.contains(FileMode::ISGID | FileMode::IXGRP) {
1635 return error!(EPERM);
1636 };
1637 if mode.contains(FileMode::ISUID) {
1638 return error!(EPERM);
1639 };
1640 if !mode.contains(FileMode::IFREG) {
1641 return error!(EPERM);
1642 };
1643 }
1644
1645 security::check_fs_node_link_access(current_task, self, child)?;
1646
1647 self.ops().link(self, current_task, name, child)?;
1648 Ok(child.clone())
1649 }
1650
1651 pub fn unlink(
1652 &self,
1653 current_task: &CurrentTask,
1654 mount: &MountInfo,
1655 name: &FsStr,
1656 child: &FsNodeHandle,
1657 ) -> Result<(), Errno> {
1658 self.check_access(
1661 current_task,
1662 mount,
1663 Access::WRITE,
1664 CheckAccessReason::InternalPermissionChecks,
1665 security::Auditable::Name(name),
1666 )?;
1667 {
1668 let parent_info = self.info();
1669 let _token = allow_subclass();
1673 self.check_sticky_bit(current_task, child, &parent_info)?;
1674 }
1675 if child.is_dir() {
1676 security::check_fs_node_rmdir_access(current_task, self, child, name)?;
1677 } else {
1678 security::check_fs_node_unlink_access(current_task, self, child, name)?;
1679 }
1680 self.ops().unlink(self, current_task, name, child)?;
1681 self.update_ctime_mtime();
1682 Ok(())
1683 }
1684
1685 pub fn create_write_guard(
1691 &self,
1692 mode: FileWriteGuardMode,
1693 ) -> Result<FileWriteGuardRef<'_>, Errno> {
1694 FileWriteGuardRef::new(self, mode)
1695 }
1696
1697 pub fn truncate(
1698 &self,
1699 current_task: &CurrentTask,
1700 mount: &MountInfo,
1701 length: u64,
1702 ) -> Result<(), Errno> {
1703 if self.is_dir() {
1704 return error!(EISDIR);
1705 }
1706 self.check_access(
1707 current_task,
1708 mount,
1709 Access::WRITE,
1710 CheckAccessReason::InternalPermissionChecks,
1711 security::Auditable::Location(std::panic::Location::caller()),
1712 )?;
1713
1714 let _write_guard = self.create_write_guard(FileWriteGuardMode::WriteFile)?;
1729
1730 let guard = self.ops().append_lock_write(self, current_task)?;
1731 self.truncate_locked(&guard, current_task, length)
1732 }
1733
1734 pub fn ftruncate(&self, current_task: &CurrentTask, length: u64) -> Result<(), Errno> {
1737 if self.is_dir() {
1738 return error!(EINVAL);
1743 }
1744
1745 let guard = self.ops().append_lock_write(self, current_task)?;
1761 self.truncate_locked(&guard, current_task, length)
1762 }
1763
1764 pub fn truncate_locked(
1766 &self,
1767 guard: &AppendLockWriteGuard<'_>,
1768 current_task: &CurrentTask,
1769 length: u64,
1770 ) -> Result<(), Errno> {
1771 if length > MAX_LFS_FILESIZE as u64 {
1772 return error!(EINVAL);
1773 }
1774 if length > current_task.thread_group().get_rlimit(Resource::FSIZE) {
1775 send_standard_signal(current_task, SignalInfo::kernel(SIGXFSZ));
1776 return error!(EFBIG);
1777 }
1778 self.clear_suid_and_sgid_bits(current_task)?;
1779
1780 self.ops().truncate(guard, self, current_task, length)?;
1781 self.update_ctime_mtime();
1782 Ok(())
1783 }
1784
1785 pub fn fallocate(
1788 &self,
1789 current_task: &CurrentTask,
1790 mode: FallocMode,
1791 offset: u64,
1792 length: u64,
1793 ) -> Result<(), Errno> {
1794 let guard = self.ops().append_lock_write(self, current_task)?;
1795 self.fallocate_locked(&guard, current_task, mode, offset, length)
1796 }
1797
1798 pub fn fallocate_locked(
1799 &self,
1800 guard: &AppendLockWriteGuard<'_>,
1801 current_task: &CurrentTask,
1802 mode: FallocMode,
1803 offset: u64,
1804 length: u64,
1805 ) -> Result<(), Errno> {
1806 let allocate_size = checked_add_offset_and_length(offset as usize, length as usize)
1807 .map_err(|_| errno!(EFBIG))? as u64;
1808 if allocate_size > current_task.thread_group().get_rlimit(Resource::FSIZE) {
1809 send_standard_signal(current_task, SignalInfo::kernel(SIGXFSZ));
1810 return error!(EFBIG);
1811 }
1812
1813 self.clear_suid_and_sgid_bits(current_task)?;
1814
1815 self.ops().allocate(guard, self, current_task, mode, offset, length)?;
1816 self.update_ctime_mtime();
1817 Ok(())
1818 }
1819
1820 fn update_metadata_for_child(
1821 &self,
1822 current_task: &CurrentTask,
1823 mode: &mut FileMode,
1824 owner: &mut FsCred,
1825 ) {
1826 {
1829 let self_info = self.info();
1830 if self_info.mode.contains(FileMode::ISGID) {
1831 owner.gid = self_info.gid;
1832 if mode.is_dir() {
1833 *mode |= FileMode::ISGID;
1834 }
1835 }
1836 }
1837
1838 if !mode.is_dir() && mode.contains(FileMode::ISGID | FileMode::IXGRP) {
1839 if !can_retain_sgid(current_task, owner.gid) {
1848 *mode &= !FileMode::ISGID;
1849 }
1850 }
1851 }
1852
1853 pub fn check_o_noatime_allowed(&self, current_task: &CurrentTask) -> Result<(), Errno> {
1855 if current_task.current_creds().fsuid != self.info().uid {
1870 security::check_task_capable(current_task, CAP_FOWNER)?;
1871 }
1872 Ok(())
1873 }
1874
1875 pub fn default_check_access_impl(
1876 &self,
1877 current_task: &CurrentTask,
1878 permission_flags: security::PermissionFlags,
1879 reason: CheckAccessReason,
1880 info: LockDepReadGuard<'_, FsNodeInfo>,
1881 audit_context: Auditable<'_>,
1882 ) -> Result<(), Errno> {
1883 let (node_uid, node_gid, mode) = (info.uid, info.gid, info.mode);
1884 std::mem::drop(info);
1885 if let CheckAccessReason::ChangeTimestamps { now } = reason {
1886 if current_task.current_creds().fsuid == node_uid {
1891 return Ok(());
1892 }
1893 if now {
1894 if security::is_task_capable_noaudit(current_task, CAP_FOWNER) {
1895 return Ok(());
1896 }
1897 } else {
1898 security::check_task_capable(current_task, CAP_FOWNER)?;
1899 return Ok(());
1900 }
1901 }
1902 check_access(self, current_task, permission_flags, node_uid, node_gid, mode)?;
1903 security::fs_node_permission(current_task, self, permission_flags, audit_context)
1904 }
1905
1906 pub fn check_access<'a>(
1910 &self,
1911 current_task: &CurrentTask,
1912 mount: &MountInfo,
1913 access: impl Into<security::PermissionFlags>,
1914 reason: CheckAccessReason,
1915 audit_context: impl Into<security::Auditable<'a>>,
1916 ) -> Result<(), Errno> {
1917 let mut permission_flags = access.into();
1918 if permission_flags.contains(security::PermissionFlags::WRITE)
1919 && !self.info().mode.is_special()
1920 {
1921 mount.check_readonly_filesystem()?;
1922 }
1923 if permission_flags.contains(security::PermissionFlags::EXEC) && !self.is_dir() {
1924 mount.check_noexec_filesystem()?;
1925 }
1926 if reason == CheckAccessReason::Access {
1927 permission_flags |= PermissionFlags::ACCESS;
1928 }
1929 self.ops().check_access(
1930 self,
1931 current_task,
1932 permission_flags,
1933 &self.info,
1934 reason,
1935 audit_context.into(),
1936 )
1937 }
1938
1939 pub fn check_sticky_bit(
1943 &self,
1944 current_task: &CurrentTask,
1945 child: &FsNodeHandle,
1946 self_info: &FsNodeInfo,
1947 ) -> Result<(), Errno> {
1948 if self_info.mode.contains(FileMode::ISVTX)
1949 && child.info().uid != current_task.current_creds().fsuid
1950 {
1951 security::check_task_capable(current_task, CAP_FOWNER)?;
1952 }
1953 Ok(())
1954 }
1955
1956 pub fn fifo(&self, current_task: &CurrentTask) -> &PipeHandle {
1957 assert!(self.is_fifo());
1958 self.ensure_rare_data().ensure_fifo(current_task)
1959 }
1960
1961 pub fn bound_socket(&self) -> Option<&SocketHandle> {
1963 if let Some(rare_data) = self.rare_data.get() { rare_data.bound_socket.get() } else { None }
1964 }
1965
1966 pub fn set_bound_socket(&self, socket: SocketHandle) {
1970 assert!(self.ensure_rare_data().bound_socket.set(socket).is_ok());
1971 }
1972
1973 pub fn update_attributes<F>(&self, current_task: &CurrentTask, mutator: F) -> Result<(), Errno>
1979 where
1980 F: FnOnce(&mut FsNodeInfo) -> Result<(), Errno>,
1981 {
1982 let mut info = self.info.write();
1983 let mut new_info = info.clone();
1984 mutator(&mut new_info)?;
1985
1986 let new_access = new_info.mode.user_access()
1987 | new_info.mode.group_access()
1988 | new_info.mode.other_access();
1989
1990 if new_access.intersects(Access::EXEC) {
1991 let write_guard_state = self.write_guard_state.lock();
1992 if let Ok(seals) = write_guard_state.get_seals() {
1993 if seals.contains(SealFlags::NO_EXEC) {
1994 return error!(EPERM);
1995 }
1996 }
1997 }
1998
1999 assert_eq!(info.time_status_change, new_info.time_status_change);
2001 if *info == new_info {
2002 return Ok(());
2003 }
2004 new_info.time_status_change = utc::utc_now();
2005
2006 let mut has = zxio_node_attr_has_t { ..Default::default() };
2007 has.modification_time = info.time_modify != new_info.time_modify;
2008 has.access_time = info.time_access != new_info.time_access;
2009 has.mode = info.mode != new_info.mode;
2010 has.uid = info.uid != new_info.uid;
2011 has.gid = info.gid != new_info.gid;
2012 has.rdev = info.rdev != new_info.rdev;
2013 has.casefold = info.casefold != new_info.casefold;
2014 has.encryption_policy = info.encryption_policy != new_info.encryption_policy;
2015
2016 if has.casefold && !self.fs().has_casefold_support() {
2017 return error!(ENOTSUP);
2018 }
2019 security::check_fs_node_setattr_access(current_task, &self, &has)?;
2020
2021 if has.modification_time
2023 || has.access_time
2024 || has.mode
2025 || has.uid
2026 || has.gid
2027 || has.rdev
2028 || has.casefold
2029 || has.encryption_policy
2030 {
2031 self.ops().update_attributes(self, current_task, &new_info, has)?;
2032 }
2033
2034 *info = new_info;
2035 Ok(())
2036 }
2037
2038 pub fn chmod(
2042 &self,
2043 current_task: &CurrentTask,
2044 mount: &MountInfo,
2045 mut mode: FileMode,
2046 ) -> Result<(), Errno> {
2047 mount.check_readonly_filesystem()?;
2048 self.update_attributes(current_task, |info| {
2049 if info.uid != current_task.current_creds().fsuid {
2050 security::check_task_capable(current_task, CAP_FOWNER)?;
2051 }
2052 if mode.intersects(FileMode::ISGID) && !can_retain_sgid(current_task, info.gid) {
2053 mode &= !FileMode::ISGID;
2054 }
2055 info.chmod(mode);
2056 Ok(())
2057 })
2058 }
2059
2060 pub fn chown(
2062 &self,
2063 current_task: &CurrentTask,
2064 mount: &MountInfo,
2065 owner: Option<uid_t>,
2066 group: Option<gid_t>,
2067 ) -> Result<(), Errno> {
2068 mount.check_readonly_filesystem()?;
2069 self.update_attributes(current_task, |info| {
2070 if security::is_task_capable_noaudit(current_task, CAP_CHOWN) {
2071 info.chown(owner, group);
2072 return Ok(());
2073 }
2074
2075 if let Some(uid) = owner {
2077 if info.uid != uid {
2078 return error!(EPERM);
2079 }
2080 }
2081
2082 let (euid, is_in_group) = {
2083 let current_creds = current_task.current_creds();
2084 (current_creds.euid, group.map(|gid| current_creds.is_in_group(gid)))
2085 };
2086
2087 if info.uid == euid {
2089 if let Some(is_in_group) = is_in_group {
2091 if !is_in_group {
2092 return error!(EPERM);
2093 }
2094 }
2095 info.chown(None, group);
2096 return Ok(());
2097 }
2098
2099 if owner.is_some() || group.is_some() {
2101 return error!(EPERM);
2102 }
2103
2104 if info.has_suid_or_sgid_bits() {
2107 return error!(EPERM);
2108 }
2109
2110 info.chown(None, None);
2111 Ok(())
2112 })?;
2113 self.clear_suid_and_sgid_bits(current_task)
2124 }
2125
2126 pub unsafe fn force_chown(&self, creds: FsCred) {
2137 self.update_info(|info| {
2138 info.chown(Some(creds.uid), Some(creds.gid));
2139 });
2140 }
2141
2142 pub fn is_reg(&self) -> bool {
2144 self.info().mode.is_reg()
2145 }
2146
2147 pub fn is_dir(&self) -> bool {
2149 self.info().mode.is_dir()
2150 }
2151
2152 pub fn is_sock(&self) -> bool {
2154 self.info().mode.is_sock()
2155 }
2156
2157 pub fn is_fifo(&self) -> bool {
2159 self.info().mode.is_fifo()
2160 }
2161
2162 pub fn is_lnk(&self) -> bool {
2164 self.info().mode.is_lnk()
2165 }
2166
2167 pub fn dev(&self) -> DeviceId {
2168 self.fs().dev_id
2169 }
2170
2171 pub fn stat(&self, current_task: &CurrentTask) -> Result<uapi::stat, Errno> {
2172 security::check_fs_node_getattr_access(current_task, self)?;
2173
2174 let info = self.fetch_and_refresh_info(current_task)?;
2175
2176 let time_to_kernel_timespec_pair = |t| {
2177 let timespec { tv_sec, tv_nsec } = timespec_from_time(t);
2178 let time = tv_sec.try_into().map_err(|_| errno!(EINVAL))?;
2179 let time_nsec = tv_nsec.try_into().map_err(|_| errno!(EINVAL))?;
2180 Ok((time, time_nsec))
2181 };
2182
2183 let (st_atime, st_atime_nsec) = time_to_kernel_timespec_pair(info.time_access)?;
2184 let (st_mtime, st_mtime_nsec) = time_to_kernel_timespec_pair(info.time_modify)?;
2185 let (st_ctime, st_ctime_nsec) = time_to_kernel_timespec_pair(info.time_status_change)?;
2186
2187 Ok(uapi::stat {
2188 st_dev: self.dev().bits(),
2189 st_ino: self.ino,
2190 st_nlink: info.link_count.try_into().map_err(|_| errno!(EINVAL))?,
2191 st_mode: info.mode.bits(),
2192 st_uid: info.uid,
2193 st_gid: info.gid,
2194 st_rdev: info.rdev.bits(),
2195 st_size: info.size.try_into().map_err(|_| errno!(EINVAL))?,
2196 st_blksize: info.blksize.try_into().map_err(|_| errno!(EINVAL))?,
2197 st_blocks: info.blocks.try_into().map_err(|_| errno!(EINVAL))?,
2198 st_atime,
2199 st_atime_nsec,
2200 st_mtime,
2201 st_mtime_nsec,
2202 st_ctime,
2203 st_ctime_nsec,
2204 ..Default::default()
2205 })
2206 }
2207
2208 pub fn get_size(&self, current_task: &CurrentTask) -> Result<usize, Errno> {
2215 self.ops().get_size(self, current_task)
2216 }
2217
2218 fn statx_timestamp_from_time(time: UtcInstant) -> statx_timestamp {
2219 let nanos = time.into_nanos();
2220 statx_timestamp {
2221 tv_sec: nanos / NANOS_PER_SECOND,
2222 tv_nsec: (nanos % NANOS_PER_SECOND) as u32,
2223 ..Default::default()
2224 }
2225 }
2226
2227 pub fn statx(
2228 &self,
2229 current_task: &CurrentTask,
2230 flags: StatxFlags,
2231 mask: u32,
2232 ) -> Result<statx, Errno> {
2233 security::check_fs_node_getattr_access(current_task, self)?;
2234
2235 let info = self.fetch_and_refresh_info_with_flags(current_task, flags)?;
2237 if mask & STATX__RESERVED == STATX__RESERVED {
2238 return error!(EINVAL);
2239 }
2240
2241 track_stub!(TODO("https://fxbug.dev/302594110"), "statx attributes");
2242 let stx_mnt_id = 0;
2243 let mut stx_attributes = 0;
2244 let stx_attributes_mask = STATX_ATTR_VERITY as u64;
2245
2246 if matches!(*self.fsverity.lock(), FsVerityState::FsVerity) {
2247 stx_attributes |= STATX_ATTR_VERITY as u64;
2248 }
2249
2250 Ok(statx {
2251 stx_mask: STATX_NLINK
2252 | STATX_UID
2253 | STATX_GID
2254 | STATX_ATIME
2255 | STATX_MTIME
2256 | STATX_CTIME
2257 | STATX_INO
2258 | STATX_SIZE
2259 | STATX_BLOCKS
2260 | STATX_BASIC_STATS,
2261 stx_blksize: info.blksize.try_into().map_err(|_| errno!(EINVAL))?,
2262 stx_attributes,
2263 stx_nlink: info.link_count.try_into().map_err(|_| errno!(EINVAL))?,
2264 stx_uid: info.uid,
2265 stx_gid: info.gid,
2266 stx_mode: info.mode.bits().try_into().map_err(|_| errno!(EINVAL))?,
2267 stx_ino: self.ino,
2268 stx_size: info.size.try_into().map_err(|_| errno!(EINVAL))?,
2269 stx_blocks: info.blocks.try_into().map_err(|_| errno!(EINVAL))?,
2270 stx_attributes_mask,
2271 stx_ctime: Self::statx_timestamp_from_time(info.time_status_change),
2272 stx_mtime: Self::statx_timestamp_from_time(info.time_modify),
2273 stx_atime: Self::statx_timestamp_from_time(info.time_access),
2274
2275 stx_rdev_major: info.rdev.major(),
2276 stx_rdev_minor: info.rdev.minor(),
2277
2278 stx_dev_major: self.fs().dev_id.major(),
2279 stx_dev_minor: self.fs().dev_id.minor(),
2280 stx_mnt_id,
2281 ..Default::default()
2282 })
2283 }
2284
2285 fn check_xattr_access(
2288 &self,
2289 current_task: &CurrentTask,
2290 mount: &MountInfo,
2291 name: &FsStr,
2292 access: Access,
2293 ) -> Result<(), Errno> {
2294 assert!(access == Access::READ || access == Access::WRITE);
2295
2296 let enodata_if_read =
2297 |e: Errno| if access == Access::READ && e.code == EPERM { errno!(ENODATA) } else { e };
2298
2299 if name.starts_with(XATTR_USER_PREFIX.to_bytes()) {
2302 {
2303 let info = self.info();
2304 if !info.mode.is_reg() && !info.mode.is_dir() {
2305 return Err(enodata_if_read(errno!(EPERM)));
2306 }
2307 }
2308
2309 self.check_access(
2313 current_task,
2314 mount,
2315 access,
2316 CheckAccessReason::InternalPermissionChecks,
2317 security::Auditable::Name(name),
2318 )?;
2319 } else if name.starts_with(XATTR_TRUSTED_PREFIX.to_bytes()) {
2320 security::check_task_capable(current_task, CAP_SYS_ADMIN).map_err(enodata_if_read)?;
2322 } else if name.starts_with(XATTR_SYSTEM_PREFIX.to_bytes()) {
2323 security::check_task_capable(current_task, CAP_SYS_ADMIN).map_err(enodata_if_read)?;
2327 } else if name.starts_with(XATTR_SECURITY_PREFIX.to_bytes()) {
2328 if access == Access::WRITE {
2329 if !security::fs_node_xattr_skipcap(current_task, name) {
2331 security::check_task_capable(current_task, CAP_SYS_ADMIN)
2332 .map_err(enodata_if_read)?;
2333 }
2334 }
2335 } else {
2336 panic!("Unknown extended attribute prefix: {}", name);
2337 }
2338 Ok(())
2339 }
2340
2341 pub fn get_xattr(
2342 &self,
2343 current_task: &CurrentTask,
2344 mount: &MountInfo,
2345 name: &FsStr,
2346 max_size: usize,
2347 ) -> Result<ValueOrSize<Box<[u8]>>, Errno> {
2348 self.check_xattr_access(current_task, mount, name, Access::READ)?;
2350
2351 security::check_fs_node_getxattr_access(current_task, self, name)?;
2353
2354 if name.starts_with(XATTR_SECURITY_PREFIX.to_bytes()) {
2355 security::fs_node_getsecurity(current_task, self, name, max_size)
2358 } else {
2359 self.ops().get_xattr(self, current_task, name, max_size)
2361 }
2362 }
2363
2364 pub fn set_xattr(
2365 &self,
2366 current_task: &CurrentTask,
2367 mount: &MountInfo,
2368 name: &FsStr,
2369 value: &[u8],
2370 op: XattrOp,
2371 ) -> Result<(), Errno> {
2372 self.check_xattr_access(current_task, mount, name, Access::WRITE)?;
2374
2375 security::check_fs_node_setxattr_access(current_task, self, name, value, op)?;
2377
2378 if name.starts_with(XATTR_SECURITY_PREFIX.to_bytes()) {
2379 security::fs_node_setsecurity(current_task, self, name, value, op)
2382 } else {
2383 self.ops().set_xattr(self, current_task, name, value, op)
2385 }
2386 }
2387
2388 pub fn remove_xattr(
2389 &self,
2390 current_task: &CurrentTask,
2391 mount: &MountInfo,
2392 name: &FsStr,
2393 ) -> Result<(), Errno> {
2394 self.check_xattr_access(current_task, mount, name, Access::WRITE)?;
2396
2397 security::check_fs_node_removexattr_access(current_task, self, name)?;
2399 self.ops().remove_xattr(self, current_task, name)
2400 }
2401
2402 pub fn list_xattrs(
2403 &self,
2404 current_task: &CurrentTask,
2405 max_size: usize,
2406 ) -> Result<ValueOrSize<Vec<FsString>>, Errno> {
2407 security::check_fs_node_listxattr_access(current_task, self)?;
2408 Ok(self.ops().list_xattrs(self, current_task, max_size)?.map(|mut v| {
2409 if !security::is_task_capable_noaudit(current_task, CAP_SYS_ADMIN) {
2414 v.retain(|name| !name.starts_with(XATTR_TRUSTED_PREFIX.to_bytes()));
2415 }
2416 v
2417 }))
2418 }
2419
2420 pub fn info(&self) -> LockDepReadGuard<'_, FsNodeInfo> {
2422 self.info.read()
2423 }
2424
2425 pub(super) fn info_lock(&self) -> &DynamicLockDepRwLock<FsNodeInfo> {
2430 &self.info
2431 }
2432
2433 pub fn fetch_and_refresh_info(
2435 &self,
2436 current_task: &CurrentTask,
2437 ) -> Result<LockDepReadGuard<'_, FsNodeInfo>, Errno> {
2438 self.fetch_and_refresh_info_with_flags(current_task, StatxFlags::empty())
2439 }
2440
2441 pub fn fetch_and_refresh_info_with_flags(
2442 &self,
2443 current_task: &CurrentTask,
2444 flags: StatxFlags,
2445 ) -> Result<LockDepReadGuard<'_, FsNodeInfo>, Errno> {
2446 self.ops().fetch_and_refresh_info(self, current_task, &self.info, flags)
2447 }
2448
2449 pub fn update_info<F, T>(&self, mutator: F) -> T
2450 where
2451 F: FnOnce(&mut FsNodeInfo) -> T,
2452 {
2453 let mut info = self.info.write();
2454 mutator(&mut info)
2455 }
2456
2457 pub fn clear_suid_and_sgid_bits(&self, current_task: &CurrentTask) -> Result<(), Errno> {
2460 if self.info().has_suid_or_sgid_bits()
2470 && !security::is_task_capable_noaudit(current_task, CAP_FSETID)
2471 {
2472 self.update_attributes(current_task, |info| {
2473 info.clear_suid_and_sgid_bits();
2474 Ok(())
2475 })?;
2476 }
2477
2478 if security::fs_node_needs_killpriv(current_task, self)? {
2481 security::fs_node_killpriv(current_task, self)?;
2482 }
2483 Ok(())
2484 }
2485
2486 pub fn update_ctime_mtime(&self) {
2488 if self.fs().manages_timestamps() {
2489 return;
2490 }
2491 self.update_info(|info| {
2492 let now = utc::utc_now();
2493 info.time_status_change = now;
2494 info.time_modify = now;
2495 });
2496 }
2497
2498 pub fn update_ctime(&self) {
2500 if self.fs().manages_timestamps() {
2501 return;
2502 }
2503 self.update_info(|info| {
2504 let now = utc::utc_now();
2505 info.time_status_change = now;
2506 });
2507 }
2508
2509 pub fn update_atime_mtime(
2512 &self,
2513 current_task: &CurrentTask,
2514 mount: &MountInfo,
2515 atime: TimeUpdateType,
2516 mtime: TimeUpdateType,
2517 ) -> Result<(), Errno> {
2518 mount.check_readonly_filesystem()?;
2520
2521 let now = matches!((atime, mtime), (TimeUpdateType::Now, TimeUpdateType::Now));
2522 self.check_access(
2523 current_task,
2524 mount,
2525 Access::WRITE,
2526 CheckAccessReason::ChangeTimestamps { now },
2527 security::Auditable::Location(std::panic::Location::caller()),
2528 )?;
2529
2530 if !matches!((atime, mtime), (TimeUpdateType::Omit, TimeUpdateType::Omit)) {
2531 self.update_attributes(current_task, |info| {
2535 let now = utc::utc_now();
2536 let get_time = |time: TimeUpdateType| match time {
2537 TimeUpdateType::Now => Some(now),
2538 TimeUpdateType::Time(t) => Some(t),
2539 TimeUpdateType::Omit => None,
2540 };
2541 if let Some(time) = get_time(atime) {
2542 info.time_access = time;
2543 }
2544 if let Some(time) = get_time(mtime) {
2545 info.time_modify = time;
2546 }
2547 Ok(())
2548 })?;
2549 }
2550 Ok(())
2551 }
2552
2553 pub fn node_key(&self) -> ino_t {
2558 self.ops().node_key(self)
2559 }
2560
2561 fn ensure_rare_data(&self) -> &FsNodeRareData {
2562 self.rare_data.get_or_init(|| Box::new(FsNodeRareData::default()))
2563 }
2564
2565 pub fn ensure_watchers(&self) -> &inotify_hook::InotifyWatchers {
2570 &self.ensure_rare_data().watchers
2571 }
2572
2573 pub fn notify(
2575 &self,
2576 event_mask: InotifyMask,
2577 cookie: u32,
2578 name: &FsStr,
2579 mode: FileMode,
2580 is_dead: bool,
2581 ) {
2582 if let Some(rare_data) = self.rare_data.get() {
2583 let kernel = self.fs().kernel.upgrade().expect("kernel is dead");
2584 if let Some(hook) = kernel.expando.peek::<Arc<dyn inotify_hook::NotifyHook>>() {
2585 hook.notify(&rare_data.watchers, event_mask, cookie, name, mode, is_dead);
2586 }
2587 }
2588 }
2589
2590 pub fn enable_fsverity(
2592 &self,
2593 current_task: &CurrentTask,
2594 descriptor: &fsverity_descriptor,
2595 ) -> Result<(), Errno> {
2596 self.ops().enable_fsverity(self, current_task, descriptor)
2597 }
2598}
2599
2600impl std::fmt::Debug for FsNode {
2601 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2602 f.debug_struct("FsNode")
2603 .field("fs", &self.fs().name())
2604 .field("info", &*self.info())
2605 .field("ops_ty", &self.ops().type_name())
2606 .finish()
2607 }
2608}
2609
2610impl Releasable for FsNode {
2611 type Context<'a> = &'a CurrentTask;
2612
2613 fn release<'a>(self, context: &'a CurrentTask) {
2614 let current_task = context;
2615 if let Some(fs) = self.fs.upgrade() {
2616 fs.remove_node(&self);
2617 }
2618 if let Err(err) = self.ops.forget(current_task, self.info.into_inner()) {
2619 log_error!("Error on FsNodeOps::forget: {err:?}");
2620 }
2621 }
2622}
2623
2624fn can_retain_sgid(current_task: &CurrentTask, gid: gid_t) -> bool {
2629 let in_group = {
2630 let current_creds = current_task.current_creds();
2631 gid == current_creds.fsgid || current_creds.groups.contains(&gid)
2632 };
2633 in_group || security::check_task_capable(current_task, CAP_FSETID).is_ok()
2634}
2635
2636fn check_access(
2637 fs_node: &FsNode,
2638 current_task: &CurrentTask,
2639 permission_flags: security::PermissionFlags,
2640 node_uid: uid_t,
2641 node_gid: gid_t,
2642 mode: FileMode,
2643) -> Result<(), Errno> {
2644 let (fsuid, is_in_group) = {
2646 let current_creds = current_task.current_creds();
2647 (current_creds.fsuid, current_creds.is_in_group(node_gid))
2648 };
2649 let granted = if fsuid == node_uid {
2650 mode.user_access()
2651 } else if is_in_group {
2652 mode.group_access()
2653 } else {
2654 mode.other_access()
2655 };
2656
2657 let access = permission_flags.as_access();
2658 if granted.contains(access) {
2659 return Ok(());
2660 }
2661
2662 let mut requested = access & !granted;
2665
2666 let have_dont_audit = OnceBool::new();
2669 let has_capability = move |current_task, capability| {
2670 let dont_audit = have_dont_audit.get_or_init(|| {
2671 permission_flags.contains(PermissionFlags::ACCESS)
2672 && security::has_dontaudit_access(current_task, fs_node)
2673 });
2674 if dont_audit {
2675 security::is_task_capable_noaudit(current_task, capability)
2676 } else {
2677 security::check_task_capable(current_task, capability).is_ok()
2678 }
2679 };
2680
2681 let dac_read_search_access =
2683 if mode.is_dir() { Access::READ | Access::EXEC } else { Access::READ };
2684 if dac_read_search_access.intersects(requested)
2685 && has_capability(current_task, CAP_DAC_READ_SEARCH)
2686 {
2687 requested.remove(dac_read_search_access);
2688 }
2689 if requested.is_empty() {
2690 return Ok(());
2691 }
2692
2693 let mut dac_override_access = Access::READ | Access::WRITE;
2695 dac_override_access |= if mode.is_dir() {
2696 Access::EXEC
2697 } else {
2698 (mode.user_access() | mode.group_access() | mode.other_access()) & Access::EXEC
2700 };
2701 if dac_override_access.intersects(requested) && has_capability(current_task, CAP_DAC_OVERRIDE) {
2702 requested.remove(dac_override_access);
2703 }
2704 if requested.is_empty() {
2705 return Ok(());
2706 }
2707
2708 return error!(EACCES);
2709}
2710
2711#[cfg(test)]
2712mod tests {
2713 use super::*;
2714 use crate::device::mem::mem_device_init;
2715 use crate::testing::*;
2716 use crate::vfs::buffers::VecOutputBuffer;
2717 use starnix_uapi::auth::Credentials;
2718 use starnix_uapi::file_mode::mode;
2719
2720 #[::fuchsia::test]
2721 async fn open_device_file() {
2722 spawn_kernel_and_run(async |current_task| {
2723 mem_device_init(current_task.kernel()).expect("mem_device_init");
2724
2725 current_task
2728 .fs()
2729 .root()
2730 .create_node(¤t_task, "zero".into(), mode!(IFCHR, 0o666), DeviceId::ZERO)
2731 .expect("create_node");
2732
2733 const CONTENT_LEN: usize = 10;
2734 let mut buffer = VecOutputBuffer::new(CONTENT_LEN);
2735
2736 let device_file =
2738 current_task.open_file("zero".into(), OpenFlags::RDONLY).expect("open device file");
2739 device_file.read(¤t_task, &mut buffer).expect("read from zero");
2740
2741 assert_eq!(&[0; CONTENT_LEN], buffer.data());
2743 })
2744 .await;
2745 }
2746
2747 #[::fuchsia::test]
2748 async fn node_info_is_reflected_in_stat() {
2749 spawn_kernel_and_run(async |current_task| {
2750 let node = ¤t_task
2752 .fs()
2753 .root()
2754 .create_node(¤t_task, "zero".into(), FileMode::IFCHR, DeviceId::ZERO)
2755 .expect("create_node")
2756 .entry
2757 .node;
2758 node.update_info(|info| {
2759 info.mode = FileMode::IFSOCK;
2760 info.size = 1;
2761 info.blocks = 2;
2762 info.blksize = 4;
2763 info.uid = 9;
2764 info.gid = 10;
2765 info.link_count = 11;
2766 info.time_status_change = UtcInstant::from_nanos(1);
2767 info.time_access = UtcInstant::from_nanos(2);
2768 info.time_modify = UtcInstant::from_nanos(3);
2769 info.rdev = DeviceId::new(13, 13);
2770 });
2771 let stat = node.stat(¤t_task).expect("stat");
2772
2773 assert_eq!(stat.st_mode, FileMode::IFSOCK.bits());
2774 assert_eq!(stat.st_size, 1);
2775 assert_eq!(stat.st_blksize, 4);
2776 assert_eq!(stat.st_blocks, 2);
2777 assert_eq!(stat.st_uid, 9);
2778 assert_eq!(stat.st_gid, 10);
2779 assert_eq!(stat.st_nlink, 11);
2780 assert_eq!(stat.st_ctime, 0);
2781 assert_eq!(stat.st_ctime_nsec, 1);
2782 assert_eq!(stat.st_atime, 0);
2783 assert_eq!(stat.st_atime_nsec, 2);
2784 assert_eq!(stat.st_mtime, 0);
2785 assert_eq!(stat.st_mtime_nsec, 3);
2786 assert_eq!(stat.st_rdev, DeviceId::new(13, 13).bits());
2787 })
2788 .await;
2789 }
2790
2791 #[::fuchsia::test]
2792 fn test_flock_operation() {
2793 assert!(FlockOperation::from_flags(0).is_err());
2794 assert!(FlockOperation::from_flags(u32::MAX).is_err());
2795
2796 let operation1 = FlockOperation::from_flags(LOCK_SH).expect("from_flags");
2797 assert!(!operation1.is_unlock());
2798 assert!(!operation1.is_lock_exclusive());
2799 assert!(operation1.is_blocking());
2800
2801 let operation2 = FlockOperation::from_flags(LOCK_EX | LOCK_NB).expect("from_flags");
2802 assert!(!operation2.is_unlock());
2803 assert!(operation2.is_lock_exclusive());
2804 assert!(!operation2.is_blocking());
2805
2806 let operation3 = FlockOperation::from_flags(LOCK_UN).expect("from_flags");
2807 assert!(operation3.is_unlock());
2808 assert!(!operation3.is_lock_exclusive());
2809 assert!(operation3.is_blocking());
2810 }
2811
2812 #[::fuchsia::test]
2813 async fn test_check_access() {
2814 spawn_kernel_and_run(async |current_task| {
2815 let mut creds = Credentials::with_ids(1, 2);
2816 creds.groups = vec![3, 4];
2817 current_task.set_creds(creds);
2818
2819 let node = ¤t_task
2821 .fs()
2822 .root()
2823 .create_node(¤t_task, "foo".into(), FileMode::IFREG, DeviceId::NONE)
2824 .expect("create_node")
2825 .entry
2826 .node;
2827 let check_access = |uid: uid_t, gid: gid_t, perm: u32, access: Access| {
2828 node.update_info(|info| {
2829 info.mode = mode!(IFREG, perm);
2830 info.uid = uid;
2831 info.gid = gid;
2832 });
2833 node.check_access(
2834 ¤t_task,
2835 &MountInfo::detached(),
2836 access,
2837 CheckAccessReason::InternalPermissionChecks,
2838 security::Auditable::Location(std::panic::Location::caller()),
2839 )
2840 };
2841
2842 assert_eq!(check_access(0, 0, 0o700, Access::EXEC), error!(EACCES));
2843 assert_eq!(check_access(0, 0, 0o700, Access::READ), error!(EACCES));
2844 assert_eq!(check_access(0, 0, 0o700, Access::WRITE), error!(EACCES));
2845
2846 assert_eq!(check_access(0, 0, 0o070, Access::EXEC), error!(EACCES));
2847 assert_eq!(check_access(0, 0, 0o070, Access::READ), error!(EACCES));
2848 assert_eq!(check_access(0, 0, 0o070, Access::WRITE), error!(EACCES));
2849
2850 assert_eq!(check_access(0, 0, 0o007, Access::EXEC), Ok(()));
2851 assert_eq!(check_access(0, 0, 0o007, Access::READ), Ok(()));
2852 assert_eq!(check_access(0, 0, 0o007, Access::WRITE), Ok(()));
2853
2854 assert_eq!(check_access(1, 0, 0o700, Access::EXEC), Ok(()));
2855 assert_eq!(check_access(1, 0, 0o700, Access::READ), Ok(()));
2856 assert_eq!(check_access(1, 0, 0o700, Access::WRITE), Ok(()));
2857
2858 assert_eq!(check_access(1, 0, 0o100, Access::EXEC), Ok(()));
2859 assert_eq!(check_access(1, 0, 0o100, Access::READ), error!(EACCES));
2860 assert_eq!(check_access(1, 0, 0o100, Access::WRITE), error!(EACCES));
2861
2862 assert_eq!(check_access(1, 0, 0o200, Access::EXEC), error!(EACCES));
2863 assert_eq!(check_access(1, 0, 0o200, Access::READ), error!(EACCES));
2864 assert_eq!(check_access(1, 0, 0o200, Access::WRITE), Ok(()));
2865
2866 assert_eq!(check_access(1, 0, 0o400, Access::EXEC), error!(EACCES));
2867 assert_eq!(check_access(1, 0, 0o400, Access::READ), Ok(()));
2868 assert_eq!(check_access(1, 0, 0o400, Access::WRITE), error!(EACCES));
2869
2870 assert_eq!(check_access(0, 2, 0o700, Access::EXEC), error!(EACCES));
2871 assert_eq!(check_access(0, 2, 0o700, Access::READ), error!(EACCES));
2872 assert_eq!(check_access(0, 2, 0o700, Access::WRITE), error!(EACCES));
2873
2874 assert_eq!(check_access(0, 2, 0o070, Access::EXEC), Ok(()));
2875 assert_eq!(check_access(0, 2, 0o070, Access::READ), Ok(()));
2876 assert_eq!(check_access(0, 2, 0o070, Access::WRITE), Ok(()));
2877
2878 assert_eq!(check_access(0, 3, 0o070, Access::EXEC), Ok(()));
2879 assert_eq!(check_access(0, 3, 0o070, Access::READ), Ok(()));
2880 assert_eq!(check_access(0, 3, 0o070, Access::WRITE), Ok(()));
2881 })
2882 .await;
2883 }
2884
2885 #[::fuchsia::test]
2886 async fn set_security_xattr_fails_without_security_module_or_root() {
2887 spawn_kernel_and_run(async |current_task| {
2888 let mut creds = Credentials::with_ids(1, 2);
2889 creds.groups = vec![3, 4];
2890 current_task.set_creds(creds);
2891
2892 let node = ¤t_task
2894 .fs()
2895 .root()
2896 .create_node(¤t_task, "foo".into(), FileMode::IFREG, DeviceId::NONE)
2897 .expect("create_node")
2898 .entry
2899 .node;
2900
2901 node.update_info(|info| info.mode = mode!(IFREG, 0o777));
2903
2904 assert_eq!(
2907 node.set_xattr(
2908 ¤t_task,
2909 &MountInfo::detached(),
2910 "security.name".into(),
2911 b"security_label",
2912 XattrOp::Create,
2913 ),
2914 error!(EPERM)
2915 );
2916 })
2917 .await;
2918 }
2919
2920 #[::fuchsia::test]
2921 async fn set_non_user_xattr_fails_without_security_module_or_root() {
2922 spawn_kernel_and_run(async |current_task| {
2923 let mut creds = Credentials::with_ids(1, 2);
2924 creds.groups = vec![3, 4];
2925 current_task.set_creds(creds);
2926
2927 let node = ¤t_task
2929 .fs()
2930 .root()
2931 .create_node(¤t_task, "foo".into(), FileMode::IFREG, DeviceId::NONE)
2932 .expect("create_node")
2933 .entry
2934 .node;
2935
2936 node.update_info(|info| info.mode = mode!(IFREG, 0o777));
2938
2939 assert_eq!(
2942 node.set_xattr(
2943 ¤t_task,
2944 &MountInfo::detached(),
2945 "trusted.name".into(),
2946 b"some data",
2947 XattrOp::Create,
2948 ),
2949 error!(EPERM)
2950 );
2951 })
2952 .await;
2953 }
2954
2955 #[::fuchsia::test]
2956 async fn get_security_xattr_succeeds_without_read_access() {
2957 spawn_kernel_and_run(async |current_task| {
2958 let mut creds = Credentials::with_ids(1, 2);
2959 creds.groups = vec![3, 4];
2960 current_task.set_creds(creds);
2961
2962 let node = ¤t_task
2964 .fs()
2965 .root()
2966 .create_node(¤t_task, "foo".into(), FileMode::IFREG, DeviceId::NONE)
2967 .expect("create_node")
2968 .entry
2969 .node;
2970
2971 node.update_info(|info| info.mode = mode!(IFREG, 0o100));
2973 current_task.set_creds(Credentials::with_ids(0, 0));
2974
2975 assert_eq!(
2977 node.set_xattr(
2978 ¤t_task,
2979 &MountInfo::detached(),
2980 "security.name".into(),
2981 b"security_label",
2982 XattrOp::Create,
2983 ),
2984 Ok(())
2985 );
2986
2987 current_task.set_creds(Credentials::with_ids(1, 1));
2989
2990 assert_eq!(
2992 node.get_xattr(¤t_task, &MountInfo::detached(), "security.name".into(), 4096),
2993 Ok(ValueOrSize::Value(b"security_label"[..].into()))
2994 );
2995 })
2996 .await;
2997 }
2998
2999 #[fuchsia::test]
3000 async fn test_casefold_not_supported_by_default() {
3001 spawn_kernel_and_run(async |current_task| {
3002 let file_node = ¤t_task
3003 .fs()
3004 .root()
3005 .create_node(¤t_task, "foo".into(), FileMode::IFREG, DeviceId::NONE)
3006 .expect("create_node")
3007 .entry;
3008
3009 assert!(!file_node.node.fs().has_casefold_support());
3010 assert_eq!(
3011 file_node.node.update_attributes(¤t_task, |info| {
3012 info.casefold = true;
3013 Ok(())
3014 }),
3015 error!(ENOTSUP)
3016 );
3017 assert_eq!(file_node.set_casefold(¤t_task, false), Ok(()));
3020 assert_eq!(file_node.set_casefold(¤t_task, true), error!(ENOTDIR));
3021
3022 let dir_entry = ¤t_task
3024 .fs()
3025 .root()
3026 .create_node(¤t_task, "dir".into(), FileMode::IFDIR, DeviceId::NONE)
3027 .expect("create_dir")
3028 .entry;
3029 assert_eq!(dir_entry.set_casefold(¤t_task, true), error!(ENOTSUP));
3030 assert_eq!(dir_entry.set_casefold(¤t_task, false), Ok(()));
3031 })
3032 .await;
3033 }
3034}