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, 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 pub ino: ino_t,
85
86 pub flags: FsNodeFlags,
88
89 ops: Box<dyn FsNodeOps>,
94
95 fs: Weak<FileSystem>,
97
98 pub append_lock: RwQueue<FsNodeAppend>,
104
105 info: DynamicLockDepRwLock<FsNodeInfo>,
109
110 rare_data: OnceLock<Box<FsNodeRareData>>,
112
113 pub write_guard_state: LockDepMutex<FileWriteGuardState, FsNodeWriteGuardStateLock>,
115
116 pub fsverity: LockDepMutex<FsVerityState, FsNodeFsVerityLock>,
118
119 pub security_state: security::FsNodeState,
122}
123
124#[derive(Default)]
125struct FsNodeRareData {
126 fifo: OnceLock<PipeHandle>,
130
131 bound_socket: OnceLock<SocketHandle>,
133
134 flock_info: LockDepMutex<FlockInfo, FsNodeFlockInfoLock>,
138
139 record_locks: RecordLocks,
141
142 link_behavior: OnceLock<FsNodeLinkBehavior>,
146
147 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 pub wrapping_key_id: Option<[u8; 16]>,
196
197 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 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 self.mode.intersects(FileMode::IXGRP) {
246 self.mode &= !FileMode::ISGID;
247 }
248 }
249
250 fn has_suid_or_sgid_bits(&self) -> bool {
251 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 if self.mode.contains(FileMode::ISGID | FileMode::IXGRP) {
277 creds.egid = self.gid;
278 }
279 }
280}
281
282#[derive(Default)]
283struct FlockInfo {
284 locked_exclusive: Option<bool>,
289 locking_handles: Vec<WeakFileHandle>,
291 wait_queue: WaitQueue,
293}
294
295impl FlockInfo {
296 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
313pub 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 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 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 if fd_has_lock {
384 if operation.is_lock_exclusive() == file_lock_is_exclusive {
385 return Ok(());
387 } else {
388 flock_info.retain(|fh| !std::ptr::eq(fh, self));
391 continue;
392 }
393 }
394
395 if !file_lock_is_exclusive && !operation.is_lock_exclusive() {
397 flock_info.locking_handles.push(self.weak_handle.clone());
399 return Ok(());
400 }
401
402 if !operation.is_blocking() {
404 return error!(EAGAIN);
405 }
406
407 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
417mod inner_flags {
420 #![allow(clippy::bad_bit_mask)] 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 Directory,
445
446 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,
459 Create,
461 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#[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 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 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 fn create_dir_entry_ops(&self) -> Box<dyn DirEntryOps> {
562 Box::new(DefaultDirEntryOps)
563 }
564
565 fn create_file_ops(
570 &self,
571 node: &FsNode,
572 _current_task: &CurrentTask,
573 flags: OpenFlags,
574 ) -> Result<Box<dyn FileOps>, Errno>;
575
576 fn lookup(
581 &self,
582 _node: &FsNode,
583 _current_task: &CurrentTask,
584 name: &FsStr,
585 ) -> Result<FsNodeHandle, Errno> {
586 error!(ENOENT, format!("looking for {name}"))
589 }
590
591 fn has_lookup_pipelined(&self) -> bool {
593 false
594 }
595
596 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 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 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 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 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 fn readlink(
662 &self,
663 _node: &FsNode,
664 _current_task: &CurrentTask,
665 ) -> Result<SymlinkTarget, Errno> {
666 error!(EINVAL)
667 }
668
669 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 fn unlink(
685 &self,
686 node: &FsNode,
687 _current_task: &CurrentTask,
688 _name: &FsStr,
689 _child: &FsNodeHandle,
690 ) -> Result<(), Errno>;
691
692 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 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 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 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 fn initial_info(&self, _info: &mut FsNodeInfo) {}
740
741 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 fn sync(&self, _node: &FsNode, _current_task: &CurrentTask) -> Result<(), Errno> {
762 Ok(())
763 }
764
765 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 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 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 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 fn forget(
829 self: Box<Self>,
830 _current_task: &CurrentTask,
831 _info: FsNodeInfo,
832 ) -> Result<(), Errno> {
833 Ok(())
834 }
835
836 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 fn get_fsverity_descriptor(&self, _log_blocksize: u8) -> Result<fsverity_descriptor, Errno> {
854 error!(ENOTSUP)
855 }
856
857 fn node_key(&self, node: &FsNode) -> ino_t {
862 node.ino
863 }
864
865 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#[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
984pub trait XattrStorage {
989 fn get_xattr(&self, name: &FsStr) -> Result<FsString, Errno>;
991
992 fn set_xattr(&self, name: &FsStr, value: &FsStr, op: XattrOp) -> Result<(), Errno>;
994
995 fn remove_xattr(&self, name: &FsStr) -> Result<(), Errno>;
997
998 fn list_xattrs(&self) -> Result<Vec<FsString>, Errno>;
1000}
1001
1002#[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#[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
1133pub 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 pub fn is_private(&self) -> bool {
1158 self.flags.contains(FsNodeFlags::IS_PRIVATE)
1159 }
1160
1161 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 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 #[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 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 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 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 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 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 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 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 security::check_fs_node_mkdir_access(current_task, self, mode, name)?;
1405 } else {
1406 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 self.update_metadata_for_child(current_task, &mut mode, &mut owner);
1429
1430 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 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 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 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 pub fn readlink(&self, current_task: &CurrentTask) -> Result<SymlinkTarget, Errno> {
1528 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 let (child_uid, mode) = {
1565 let info = child.info();
1566 (info.uid, info.mode)
1567 };
1568 if child_uid != current_task.current_creds().fsuid
1572 && !security::is_task_capable_noaudit(current_task, CAP_FOWNER)
1573 {
1574 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 if e == EACCES { errno!(EPERM) } else { e }
1588 })?;
1589 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 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 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 pub fn ftruncate(&self, current_task: &CurrentTask, length: u64) -> Result<(), Errno> {
1665 if self.is_dir() {
1666 return error!(EINVAL);
1671 }
1672
1673 let guard = self.ops().append_lock_write(self, current_task)?;
1689 self.truncate_locked(&guard, current_task, length)
1690 }
1691
1692 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 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 {
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 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 pub fn check_o_noatime_allowed(&self, current_task: &CurrentTask) -> Result<(), Errno> {
1787 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 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 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 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 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 pub fn set_bound_socket(&self, socket: SocketHandle) {
1902 assert!(self.ensure_rare_data().bound_socket.set(socket).is_ok());
1903 }
1904
1905 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 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 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 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 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 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 if info.uid == euid {
2025 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 if owner.is_some() || group.is_some() {
2037 return error!(EPERM);
2038 }
2039
2040 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 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 pub fn is_reg(&self) -> bool {
2072 self.info().mode.is_reg()
2073 }
2074
2075 pub fn is_dir(&self) -> bool {
2077 self.info().mode.is_dir()
2078 }
2079
2080 pub fn is_sock(&self) -> bool {
2082 self.info().mode.is_sock()
2083 }
2084
2085 pub fn is_fifo(&self) -> bool {
2087 self.info().mode.is_fifo()
2088 }
2089
2090 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 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 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 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 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 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 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 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 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 self.check_xattr_access(current_task, mount, name, Access::READ)?;
2282
2283 security::check_fs_node_getxattr_access(current_task, self, name)?;
2285
2286 if name.starts_with(XATTR_SECURITY_PREFIX.to_bytes()) {
2287 security::fs_node_getsecurity(current_task, self, name, max_size)
2290 } else {
2291 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 self.check_xattr_access(current_task, mount, name, Access::WRITE)?;
2306
2307 security::check_fs_node_setxattr_access(current_task, self, name, value, op)?;
2309
2310 if name.starts_with(XATTR_SECURITY_PREFIX.to_bytes()) {
2311 security::fs_node_setsecurity(current_task, self, name, value, op)
2314 } else {
2315 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 self.check_xattr_access(current_task, mount, name, Access::WRITE)?;
2328
2329 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 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 pub fn info(&self) -> LockDepReadGuard<'_, FsNodeInfo> {
2354 self.info.read()
2355 }
2356
2357 pub(super) fn info_lock(&self) -> &DynamicLockDepRwLock<FsNodeInfo> {
2362 &self.info
2363 }
2364
2365 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 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 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 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 pub fn update_atime_mtime(
2422 &self,
2423 current_task: &CurrentTask,
2424 mount: &MountInfo,
2425 atime: TimeUpdateType,
2426 mtime: TimeUpdateType,
2427 ) -> Result<(), Errno> {
2428 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 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 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 pub fn ensure_watchers(&self) -> &inotify_hook::InotifyWatchers {
2480 &self.ensure_rare_data().watchers
2481 }
2482
2483 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 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 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 let mut requested = access & !granted;
2563
2564 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 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 let mut dac_override_access = Access::READ | Access::WRITE;
2593 dac_override_access |= if mode.is_dir() {
2594 Access::EXEC
2595 } else {
2596 (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 current_task
2626 .fs()
2627 .root()
2628 .create_node(¤t_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 let device_file =
2636 current_task.open_file("zero".into(), OpenFlags::RDONLY).expect("open device file");
2637 device_file.read(¤t_task, &mut buffer).expect("read from zero");
2638
2639 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 let node = ¤t_task
2650 .fs()
2651 .root()
2652 .create_node(¤t_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(¤t_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 let node = ¤t_task
2719 .fs()
2720 .root()
2721 .create_node(¤t_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 ¤t_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 let node = ¤t_task
2792 .fs()
2793 .root()
2794 .create_node(¤t_task, "foo".into(), FileMode::IFREG, DeviceId::NONE)
2795 .expect("create_node")
2796 .entry
2797 .node;
2798
2799 node.update_info(|info| info.mode = mode!(IFREG, 0o777));
2801
2802 assert_eq!(
2805 node.set_xattr(
2806 ¤t_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 let node = ¤t_task
2827 .fs()
2828 .root()
2829 .create_node(¤t_task, "foo".into(), FileMode::IFREG, DeviceId::NONE)
2830 .expect("create_node")
2831 .entry
2832 .node;
2833
2834 node.update_info(|info| info.mode = mode!(IFREG, 0o777));
2836
2837 assert_eq!(
2840 node.set_xattr(
2841 ¤t_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 let node = ¤t_task
2862 .fs()
2863 .root()
2864 .create_node(¤t_task, "foo".into(), FileMode::IFREG, DeviceId::NONE)
2865 .expect("create_node")
2866 .entry
2867 .node;
2868
2869 node.update_info(|info| info.mode = mode!(IFREG, 0o100));
2871 current_task.set_creds(Credentials::with_ids(0, 0));
2872
2873 assert_eq!(
2875 node.set_xattr(
2876 ¤t_task,
2877 &MountInfo::detached(),
2878 "security.name".into(),
2879 "security_label".into(),
2880 XattrOp::Create,
2881 ),
2882 Ok(())
2883 );
2884
2885 current_task.set_creds(Credentials::with_ids(1, 1));
2887
2888 assert_eq!(
2890 node.get_xattr(¤t_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 = ¤t_task
2901 .fs()
2902 .root()
2903 .create_node(¤t_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(¤t_task, |info| {
2910 info.casefold = true;
2911 Ok(())
2912 }),
2913 error!(ENOTSUP)
2914 );
2915 assert_eq!(file_node.set_casefold(¤t_task, false), Ok(()));
2918 assert_eq!(file_node.set_casefold(¤t_task, true), error!(ENOTDIR));
2919
2920 let dir_entry = ¤t_task
2922 .fs()
2923 .root()
2924 .create_node(¤t_task, "dir".into(), FileMode::IFDIR, DeviceId::NONE)
2925 .expect("create_dir")
2926 .entry;
2927 assert_eq!(dir_entry.set_casefold(¤t_task, true), error!(ENOTSUP));
2928 assert_eq!(dir_entry.set_casefold(¤t_task, false), Ok(()));
2929 })
2930 .await;
2931 }
2932}