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 DefaultDirEntryOps, DirEntryOps, FileObject, FileObjectState, FileOps, FileSystem,
17 FileSystemHandle, FileWriteGuardState, FsLockDepType, FsStr, FsString, MAX_LFS_FILESIZE,
18 MountInfo, NamespaceNode, OPathOps, RecordLockCommand, RecordLockOwner, RecordLocks,
19 WeakFileHandle, checked_add_offset_and_length, inotify_hook,
20};
21use bitflags::bitflags;
22use fuchsia_runtime::UtcInstant;
23use linux_uapi::{XATTR_SECURITY_PREFIX, XATTR_SYSTEM_PREFIX, XATTR_TRUSTED_PREFIX};
24use once_cell::race::OnceBool;
25use smallvec::SmallVec;
26use starnix_crypt::EncryptionKeyId;
27use starnix_lifecycle::{ObjectReleaser, ReleaserAction};
28use starnix_logging::{log_error, track_stub};
29use starnix_sync::{
30 DynamicLockDepRwLock, FsNodeAppend, FsNodeFlockInfoLock, FsNodeFsVerityLock, FsNodeInfoLevel,
31 FsNodeInfoRecursiveLevel, FsNodeWriteGuardStateLock, FuseFsNodeInfoLevel, LockDepMutex,
32 LockDepReadGuard, allow_subclass,
33};
34use starnix_types::ownership::{Releasable, ReleaseGuard};
35use starnix_types::time::{NANOS_PER_SECOND, timespec_from_time};
36use starnix_uapi::as_any::AsAny;
37use starnix_uapi::auth::{
38 CAP_CHOWN, CAP_DAC_OVERRIDE, CAP_DAC_READ_SEARCH, CAP_FOWNER, CAP_FSETID, CAP_MKNOD,
39 CAP_SYS_ADMIN, CAP_SYS_RESOURCE, Credentials, FsCred,
40};
41use starnix_uapi::device_id::DeviceId;
42use starnix_uapi::errors::{EACCES, ENOTSUP, EPERM, Errno};
43use starnix_uapi::file_mode::{Access, AccessCheck, FileMode};
44use starnix_uapi::inotify_mask::InotifyMask;
45use starnix_uapi::mount_flags::MountFlags;
46use starnix_uapi::open_flags::OpenFlags;
47use starnix_uapi::resource_limits::Resource;
48use starnix_uapi::seal_flags::SealFlags;
49use starnix_uapi::signals::SIGXFSZ;
50use starnix_uapi::{
51 FALLOC_FL_COLLAPSE_RANGE, FALLOC_FL_INSERT_RANGE, FALLOC_FL_KEEP_SIZE, FALLOC_FL_PUNCH_HOLE,
52 FALLOC_FL_UNSHARE_RANGE, FALLOC_FL_ZERO_RANGE, LOCK_EX, LOCK_NB, LOCK_SH, LOCK_UN,
53 STATX__RESERVED, STATX_ATIME, STATX_ATTR_VERITY, STATX_BASIC_STATS, STATX_BLOCKS, STATX_CTIME,
54 STATX_GID, STATX_INO, STATX_MTIME, STATX_NLINK, STATX_SIZE, STATX_UID, XATTR_USER_PREFIX,
55 errno, error, fsverity_descriptor, gid_t, ino_t, statx, statx_timestamp, timespec, uapi, uid_t,
56};
57use std::sync::atomic::Ordering;
58use std::sync::{Arc, OnceLock, Weak};
59use syncio::zxio_node_attr_has_t;
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq)]
62pub enum FsNodeLinkBehavior {
63 Allowed,
64 Disallowed,
65}
66
67impl Default for FsNodeLinkBehavior {
68 fn default() -> Self {
69 FsNodeLinkBehavior::Allowed
70 }
71}
72
73pub type AppendLockGuard<'a> = RwQueueReadGuard<'a, FsNodeAppend>;
74pub type AppendLockWriteGuard<'a> = RwQueueWriteGuard<'a, FsNodeAppend>;
75
76bitflags! {
77 pub struct FsNodeFlags: u8 {
78 const IS_PRIVATE = 1 << 0;
79 }
80}
81
82pub struct FsNode {
83 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
543#[derive(Debug, Copy, Clone, PartialEq)]
544pub enum CheckAccessReason {
545 Access,
546 Chdir,
547 Chroot,
548 Exec,
549 ChangeTimestamps { now: bool },
550 InternalPermissionChecks,
551}
552
553pub type LookupVec<T> = SmallVec<[T; 8]>;
554
555pub trait FsNodeOps: Send + Sync + AsAny + 'static {
556 fn check_access(
558 &self,
559 node: &FsNode,
560 current_task: &CurrentTask,
561 access: security::PermissionFlags,
562 info: &DynamicLockDepRwLock<FsNodeInfo>,
563 reason: CheckAccessReason,
564 audit_context: security::Auditable<'_>,
565 ) -> Result<(), Errno> {
566 node.default_check_access_impl(current_task, access, reason, info.read(), audit_context)
567 }
568
569 fn create_dir_entry_ops(&self) -> Box<dyn DirEntryOps> {
572 Box::new(DefaultDirEntryOps)
573 }
574
575 fn create_file_ops(
580 &self,
581 node: &FsNode,
582 _current_task: &CurrentTask,
583 flags: OpenFlags,
584 ) -> Result<Box<dyn FileOps>, Errno>;
585
586 fn lookup(
591 &self,
592 _node: &FsNode,
593 _current_task: &CurrentTask,
594 name: &FsStr,
595 ) -> Result<FsNodeHandle, Errno> {
596 error!(ENOENT, format!("looking for {name}"))
599 }
600
601 fn has_lookup_pipelined(&self) -> bool {
603 false
604 }
605
606 fn lookup_pipelined(
610 &self,
611 _node: &FsNode,
612 _current_task: &CurrentTask,
613 _names: &[&FsStr],
614 ) -> LookupVec<Result<FsNodeHandle, Errno>> {
615 panic!("has_lookup_pipelined should be false");
616 }
617
618 fn has_casefold_support(&self, _node: &FsNode) -> bool {
620 false
621 }
622
623 fn mknod(
631 &self,
632 node: &FsNode,
633 _current_task: &CurrentTask,
634 _name: &FsStr,
635 _mode: FileMode,
636 _dev: DeviceId,
637 _owner: FsCred,
638 ) -> Result<FsNodeHandle, Errno>;
639
640 fn mkdir(
642 &self,
643 node: &FsNode,
644 _current_task: &CurrentTask,
645 _name: &FsStr,
646 _mode: FileMode,
647 _owner: FsCred,
648 ) -> Result<FsNodeHandle, Errno>;
649
650 fn create_symlink(
652 &self,
653 node: &FsNode,
654 _current_task: &CurrentTask,
655 _name: &FsStr,
656 _target: &FsStr,
657 _owner: FsCred,
658 ) -> Result<FsNodeHandle, Errno>;
659
660 fn create_tmpfile(
666 &self,
667 _node: &FsNode,
668 _current_task: &CurrentTask,
669 _mode: FileMode,
670 _owner: FsCred,
671 ) -> Result<FsNodeHandle, Errno> {
672 error!(EOPNOTSUPP)
673 }
674
675 fn readlink(
677 &self,
678 _node: &FsNode,
679 _current_task: &CurrentTask,
680 ) -> Result<SymlinkTarget, Errno> {
681 error!(EINVAL)
682 }
683
684 fn link(
686 &self,
687 _node: &FsNode,
688 _current_task: &CurrentTask,
689 _name: &FsStr,
690 _child: &FsNodeHandle,
691 ) -> Result<(), Errno> {
692 error!(EPERM)
693 }
694
695 fn unlink(
700 &self,
701 node: &FsNode,
702 _current_task: &CurrentTask,
703 _name: &FsStr,
704 _child: &FsNodeHandle,
705 ) -> Result<(), Errno>;
706
707 fn append_lock_read<'a>(
710 &'a self,
711 node: &'a FsNode,
712 current_task: &CurrentTask,
713 ) -> Result<AppendLockGuard<'a>, Errno> {
714 return node.append_lock.read(current_task);
715 }
716
717 fn append_lock_write<'a>(
719 &'a self,
720 node: &'a FsNode,
721 current_task: &CurrentTask,
722 ) -> Result<AppendLockWriteGuard<'a>, Errno> {
723 return node.append_lock.write(current_task);
724 }
725
726 fn truncate(
728 &self,
729 _guard: &AppendLockWriteGuard<'_>,
730 _node: &FsNode,
731 _current_task: &CurrentTask,
732 _length: u64,
733 ) -> Result<(), Errno> {
734 error!(EINVAL)
735 }
736
737 fn allocate(
739 &self,
740 _guard: &AppendLockWriteGuard<'_>,
741 _node: &FsNode,
742 _current_task: &CurrentTask,
743 _mode: FallocMode,
744 _offset: u64,
745 _length: u64,
746 ) -> Result<(), Errno> {
747 error!(EINVAL)
748 }
749
750 fn initial_info(&self, _info: &mut FsNodeInfo) {}
755
756 fn fetch_and_refresh_info<'a>(
767 &self,
768 _node: &FsNode,
769 _current_task: &CurrentTask,
770 info: &'a DynamicLockDepRwLock<FsNodeInfo>,
771 ) -> Result<LockDepReadGuard<'a, FsNodeInfo>, Errno> {
772 Ok(info.read())
773 }
774
775 fn sync(&self, _node: &FsNode, _current_task: &CurrentTask) -> Result<(), Errno> {
777 Ok(())
778 }
779
780 fn update_attributes(
782 &self,
783 _node: &FsNode,
784 _current_task: &CurrentTask,
785 _info: &FsNodeInfo,
786 _has: zxio_node_attr_has_t,
787 ) -> Result<(), Errno> {
788 Ok(())
789 }
790
791 fn get_xattr(
797 &self,
798 _node: &FsNode,
799 _current_task: &CurrentTask,
800 _name: &FsStr,
801 _max_size: usize,
802 ) -> Result<ValueOrSize<FsString>, Errno> {
803 error!(ENOTSUP)
804 }
805
806 fn set_xattr(
808 &self,
809 _node: &FsNode,
810 _current_task: &CurrentTask,
811 _name: &FsStr,
812 _value: &FsStr,
813 _op: XattrOp,
814 ) -> Result<(), Errno> {
815 error!(ENOTSUP)
816 }
817
818 fn remove_xattr(
819 &self,
820 _node: &FsNode,
821 _current_task: &CurrentTask,
822 _name: &FsStr,
823 ) -> Result<(), Errno> {
824 error!(ENOTSUP)
825 }
826
827 fn list_xattrs(
831 &self,
832 _node: &FsNode,
833 _current_task: &CurrentTask,
834 _max_size: usize,
835 ) -> Result<ValueOrSize<Vec<FsString>>, Errno> {
836 error!(ENOTSUP)
837 }
838
839 fn forget(
841 self: Box<Self>,
842 _current_task: &CurrentTask,
843 _info: FsNodeInfo,
844 ) -> Result<(), Errno> {
845 Ok(())
846 }
847
848 fn enable_fsverity(
856 &self,
857 _node: &FsNode,
858 _current_task: &CurrentTask,
859 _descriptor: &fsverity_descriptor,
860 ) -> Result<(), Errno> {
861 error!(ENOTSUP)
862 }
863
864 fn get_fsverity_descriptor(&self, _log_blocksize: u8) -> Result<fsverity_descriptor, Errno> {
866 error!(ENOTSUP)
867 }
868
869 fn node_key(&self, node: &FsNode) -> ino_t {
874 node.ino
875 }
876
877 fn get_size(&self, node: &FsNode, current_task: &CurrentTask) -> Result<usize, Errno> {
879 let info = node.fetch_and_refresh_info(current_task)?;
880 Ok(info.size.try_into().map_err(|_| errno!(EINVAL))?)
881 }
882}
883
884impl<T> From<T> for Box<dyn FsNodeOps>
885where
886 T: FsNodeOps,
887{
888 fn from(ops: T) -> Box<dyn FsNodeOps> {
889 Box::new(ops)
890 }
891}
892
893#[macro_export]
896macro_rules! fs_node_impl_symlink {
897 () => {
898 $crate::vfs::fs_node_impl_not_dir!();
899
900 fn create_file_ops(
901 &self,
902 node: &$crate::vfs::FsNode,
903 _current_task: &CurrentTask,
904 _flags: starnix_uapi::open_flags::OpenFlags,
905 ) -> Result<Box<dyn $crate::vfs::FileOps>, starnix_uapi::errors::Errno> {
906 assert!(node.is_lnk());
907 unreachable!("Symlink nodes cannot be opened.");
908 }
909 };
910}
911
912#[macro_export]
913macro_rules! fs_node_impl_dir_readonly {
914 () => {
915 fn check_access(
916 &self,
917 node: &$crate::vfs::FsNode,
918 current_task: &$crate::task::CurrentTask,
919 permission_flags: $crate::security::PermissionFlags,
920 info: &starnix_sync::DynamicLockDepRwLock<$crate::vfs::FsNodeInfo>,
921 reason: $crate::vfs::CheckAccessReason,
922 audit_context: $crate::security::Auditable<'_>,
923 ) -> Result<(), starnix_uapi::errors::Errno> {
924 let access = permission_flags.as_access();
925 if access.contains(starnix_uapi::file_mode::Access::WRITE) {
926 return starnix_uapi::error!(
927 EROFS,
928 format!("check_access failed: read-only directory")
929 );
930 }
931 node.default_check_access_impl(
932 current_task,
933 permission_flags,
934 reason,
935 info.read(),
936 audit_context,
937 )
938 }
939
940 fn mkdir(
941 &self,
942 _node: &$crate::vfs::FsNode,
943 _current_task: &$crate::task::CurrentTask,
944 name: &$crate::vfs::FsStr,
945 _mode: starnix_uapi::file_mode::FileMode,
946 _owner: starnix_uapi::auth::FsCred,
947 ) -> Result<$crate::vfs::FsNodeHandle, starnix_uapi::errors::Errno> {
948 starnix_uapi::error!(EROFS, format!("mkdir failed: {:?}", name))
949 }
950
951 fn mknod(
952 &self,
953 _node: &$crate::vfs::FsNode,
954 _current_task: &$crate::task::CurrentTask,
955 name: &$crate::vfs::FsStr,
956 _mode: starnix_uapi::file_mode::FileMode,
957 _dev: starnix_uapi::device_id::DeviceId,
958 _owner: starnix_uapi::auth::FsCred,
959 ) -> Result<$crate::vfs::FsNodeHandle, starnix_uapi::errors::Errno> {
960 starnix_uapi::error!(EROFS, format!("mknod failed: {:?}", name))
961 }
962
963 fn create_symlink(
964 &self,
965 _node: &$crate::vfs::FsNode,
966 _current_task: &$crate::task::CurrentTask,
967 name: &$crate::vfs::FsStr,
968 _target: &$crate::vfs::FsStr,
969 _owner: starnix_uapi::auth::FsCred,
970 ) -> Result<$crate::vfs::FsNodeHandle, starnix_uapi::errors::Errno> {
971 starnix_uapi::error!(EROFS, format!("symlink failed: {:?}", name))
972 }
973
974 fn link(
975 &self,
976 _node: &$crate::vfs::FsNode,
977 _current_task: &$crate::task::CurrentTask,
978 name: &$crate::vfs::FsStr,
979 _child: &$crate::vfs::FsNodeHandle,
980 ) -> Result<(), starnix_uapi::errors::Errno> {
981 starnix_uapi::error!(EROFS, format!("link failed: {:?}", name))
982 }
983
984 fn unlink(
985 &self,
986 _node: &$crate::vfs::FsNode,
987 _current_task: &$crate::task::CurrentTask,
988 name: &$crate::vfs::FsStr,
989 _child: &$crate::vfs::FsNodeHandle,
990 ) -> Result<(), starnix_uapi::errors::Errno> {
991 starnix_uapi::error!(EROFS, format!("unlink failed: {:?}", name))
992 }
993 };
994}
995
996pub trait XattrStorage {
1001 fn get_xattr(&self, name: &FsStr) -> Result<FsString, Errno>;
1003
1004 fn set_xattr(&self, name: &FsStr, value: &FsStr, op: XattrOp) -> Result<(), Errno>;
1006
1007 fn remove_xattr(&self, name: &FsStr) -> Result<(), Errno>;
1009
1010 fn list_xattrs(&self) -> Result<Vec<FsString>, Errno>;
1012}
1013
1014#[macro_export]
1036macro_rules! fs_node_impl_xattr_delegate {
1037 ($self:ident, $delegate:expr) => {
1038 fn get_xattr(
1039 &$self,
1040 _node: &FsNode,
1041 _current_task: &CurrentTask,
1042 name: &$crate::vfs::FsStr,
1043 _size: usize,
1044 ) -> Result<$crate::vfs::ValueOrSize<$crate::vfs::FsString>, starnix_uapi::errors::Errno> {
1045 Ok($delegate.get_xattr(name)?.into())
1046 }
1047
1048 fn set_xattr(
1049 &$self,
1050 _node: &FsNode,
1051 _current_task: &CurrentTask,
1052 name: &$crate::vfs::FsStr,
1053 value: &$crate::vfs::FsStr,
1054 op: $crate::vfs::XattrOp,
1055 ) -> Result<(), starnix_uapi::errors::Errno> {
1056 $delegate.set_xattr(name, value, op)
1057 }
1058
1059 fn remove_xattr(
1060 &$self,
1061 _node: &FsNode,
1062 _current_task: &CurrentTask,
1063 name: &$crate::vfs::FsStr,
1064 ) -> Result<(), starnix_uapi::errors::Errno> {
1065 $delegate.remove_xattr(name)
1066 }
1067
1068 fn list_xattrs(
1069 &$self,
1070 _node: &FsNode,
1071 _current_task: &CurrentTask,
1072 _size: usize,
1073 ) -> Result<$crate::vfs::ValueOrSize<Vec<$crate::vfs::FsString>>, starnix_uapi::errors::Errno> {
1074 Ok($delegate.list_xattrs()?.into())
1075 }
1076 };
1077}
1078
1079#[macro_export]
1081macro_rules! fs_node_impl_not_dir {
1082 () => {
1083 fn lookup(
1084 &self,
1085 _node: &$crate::vfs::FsNode,
1086 _current_task: &$crate::task::CurrentTask,
1087 _name: &$crate::vfs::FsStr,
1088 ) -> Result<$crate::vfs::FsNodeHandle, starnix_uapi::errors::Errno> {
1089 starnix_uapi::error!(ENOTDIR)
1090 }
1091
1092 fn mknod(
1093 &self,
1094 _node: &$crate::vfs::FsNode,
1095 _current_task: &$crate::task::CurrentTask,
1096 _name: &$crate::vfs::FsStr,
1097 _mode: starnix_uapi::file_mode::FileMode,
1098 _dev: starnix_uapi::device_id::DeviceId,
1099 _owner: starnix_uapi::auth::FsCred,
1100 ) -> Result<$crate::vfs::FsNodeHandle, starnix_uapi::errors::Errno> {
1101 starnix_uapi::error!(ENOTDIR)
1102 }
1103
1104 fn mkdir(
1105 &self,
1106 _node: &$crate::vfs::FsNode,
1107 _current_task: &$crate::task::CurrentTask,
1108 _name: &$crate::vfs::FsStr,
1109 _mode: starnix_uapi::file_mode::FileMode,
1110 _owner: starnix_uapi::auth::FsCred,
1111 ) -> Result<$crate::vfs::FsNodeHandle, starnix_uapi::errors::Errno> {
1112 starnix_uapi::error!(ENOTDIR)
1113 }
1114
1115 fn create_symlink(
1116 &self,
1117 _node: &$crate::vfs::FsNode,
1118 _current_task: &$crate::task::CurrentTask,
1119 _name: &$crate::vfs::FsStr,
1120 _target: &$crate::vfs::FsStr,
1121 _owner: starnix_uapi::auth::FsCred,
1122 ) -> Result<$crate::vfs::FsNodeHandle, starnix_uapi::errors::Errno> {
1123 starnix_uapi::error!(ENOTDIR)
1124 }
1125
1126 fn unlink(
1127 &self,
1128 _node: &$crate::vfs::FsNode,
1129 _current_task: &$crate::task::CurrentTask,
1130 _name: &$crate::vfs::FsStr,
1131 _child: &$crate::vfs::FsNodeHandle,
1132 ) -> Result<(), starnix_uapi::errors::Errno> {
1133 starnix_uapi::error!(ENOTDIR)
1134 }
1135 };
1136}
1137
1138#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1139pub enum TimeUpdateType {
1140 Now,
1141 Omit,
1142 Time(UtcInstant),
1143}
1144
1145pub use fs_node_impl_dir_readonly;
1147pub use fs_node_impl_not_dir;
1148pub use fs_node_impl_symlink;
1149pub use fs_node_impl_xattr_delegate;
1150
1151pub struct SpecialNode;
1152
1153impl FsNodeOps for SpecialNode {
1154 fs_node_impl_not_dir!();
1155
1156 fn create_file_ops(
1157 &self,
1158 _node: &FsNode,
1159 _current_task: &CurrentTask,
1160 _flags: OpenFlags,
1161 ) -> Result<Box<dyn FileOps>, Errno> {
1162 unreachable!("Special nodes cannot be opened.");
1163 }
1164}
1165
1166impl FsNode {
1167 pub fn is_private(&self) -> bool {
1170 self.flags.contains(FsNodeFlags::IS_PRIVATE)
1171 }
1172
1173 pub fn new_uncached(
1178 ino: ino_t,
1179 ops: impl Into<Box<dyn FsNodeOps>>,
1180 fs: &FileSystemHandle,
1181 info: FsNodeInfo,
1182 flags: FsNodeFlags,
1183 ) -> FsNodeHandle {
1184 let ops = ops.into();
1185 FsNodeHandle::new(Self::new_internal(ino, ops, Arc::downgrade(fs), info, flags).into())
1186 }
1187
1188 fn new_internal(
1189 ino: ino_t,
1190 ops: Box<dyn FsNodeOps>,
1191 fs: Weak<FileSystem>,
1192 info: FsNodeInfo,
1193 flags: FsNodeFlags,
1194 ) -> Self {
1195 let mut info = info;
1197 ops.initial_info(&mut info);
1198
1199 let fs_lockdep_type =
1200 fs.upgrade().map(|fs| fs.fs_lockdep_type()).unwrap_or(FsLockDepType::Normal);
1201 let info_lock = match fs_lockdep_type {
1202 FsLockDepType::Normal => DynamicLockDepRwLock::new::<FsNodeInfoLevel>(info),
1203 FsLockDepType::Fuse => DynamicLockDepRwLock::new::<FuseFsNodeInfoLevel>(info),
1204 FsLockDepType::Recursive => DynamicLockDepRwLock::new::<FsNodeInfoRecursiveLevel>(info),
1205 };
1206
1207 #[allow(clippy::let_and_return)]
1209 {
1210 let result = Self {
1211 ino,
1212 flags,
1213 ops,
1214 fs,
1215 info: info_lock,
1216 append_lock: Default::default(),
1217 rare_data: Default::default(),
1218 write_guard_state: Default::default(),
1219 fsverity: Default::default(),
1220 security_state: Default::default(),
1221 };
1222 #[cfg(any(test, debug_assertions))]
1223 {
1224 let _l1 = result.append_lock.read_for_lock_ordering();
1225 let _l2 = result.info.read();
1226 let _l3 = result.write_guard_state.lock();
1227 let _l4 = result.fsverity.lock();
1228 }
1229 result
1230 }
1231 }
1232
1233 pub fn fs(&self) -> FileSystemHandle {
1234 self.fs.upgrade().expect("FileSystem did not live long enough")
1235 }
1236
1237 pub fn ops(&self) -> &dyn FsNodeOps {
1238 self.ops.as_ref()
1239 }
1240
1241 pub fn fail_if_locked(
1245 &self,
1246 _current_task: &CurrentTask,
1247 node_info: &FsNodeInfo,
1248 ) -> Result<(), Errno> {
1249 if let Some(wrapping_key_id) = node_info.wrapping_key_id {
1250 let crypt_service = self.fs().crypt_service().ok_or_else(|| errno!(ENOKEY))?;
1251 if !crypt_service.contains_key(EncryptionKeyId::from(wrapping_key_id)) {
1252 return error!(ENOKEY);
1253 }
1254 }
1255 Ok(())
1256 }
1257
1258 pub fn downcast_ops<T>(&self) -> Option<&T>
1260 where
1261 T: 'static,
1262 {
1263 self.ops().as_any().downcast_ref::<T>()
1264 }
1265
1266 pub fn on_file_closed(&self, file: &FileObjectState) {
1267 if let Some(rare_data) = self.rare_data.get() {
1268 let mut flock_info = rare_data.flock_info.lock();
1269 flock_info.retain(|_| true);
1272 }
1273 self.record_lock_release(RecordLockOwner::FileObject(file.id));
1274 }
1275
1276 pub fn record_lock(
1277 &self,
1278 current_task: &CurrentTask,
1279 file: &FileObject,
1280 cmd: RecordLockCommand,
1281 flock: uapi::flock,
1282 ) -> Result<Option<uapi::flock>, Errno> {
1283 self.ensure_rare_data().record_locks.lock(current_task, file, cmd, flock)
1284 }
1285
1286 pub fn record_lock_release(&self, owner: RecordLockOwner) {
1288 if let Some(rare_data) = self.rare_data.get() {
1289 rare_data.record_locks.release_locks(owner);
1290 }
1291 }
1292
1293 pub fn create_dir_entry_ops(&self) -> Box<dyn DirEntryOps> {
1294 self.ops().create_dir_entry_ops()
1295 }
1296
1297 pub fn create_file_ops(
1298 &self,
1299 current_task: &CurrentTask,
1300 flags: OpenFlags,
1301 ) -> Result<Box<dyn FileOps>, Errno> {
1302 self.ops().create_file_ops(self, current_task, flags)
1303 }
1304
1305 pub fn open(
1306 &self,
1307 current_task: &CurrentTask,
1308 namespace_node: &NamespaceNode,
1309 flags: OpenFlags,
1310 access_check: AccessCheck,
1311 ) -> Result<Box<dyn FileOps>, Errno> {
1312 if flags.contains(OpenFlags::PATH) {
1315 return Ok(Box::new(OPathOps::new()));
1316 }
1317
1318 let access = access_check.resolve(flags);
1319 if access.is_nontrivial() {
1320 if flags.contains(OpenFlags::NOATIME) {
1321 self.check_o_noatime_allowed(current_task)?;
1322 }
1323
1324 let mut permission_flags = PermissionFlags::from(access);
1328
1329 if flags.contains(OpenFlags::APPEND) {
1332 permission_flags |= security::PermissionFlags::APPEND;
1333 }
1334
1335 self.check_access(
1336 current_task,
1337 &namespace_node.mount,
1338 permission_flags,
1339 CheckAccessReason::InternalPermissionChecks,
1340 namespace_node,
1341 )?;
1342 }
1343
1344 let (mode, rdev) = {
1345 let info = self.info();
1348 (info.mode, info.rdev)
1349 };
1350
1351 match mode & FileMode::IFMT {
1352 FileMode::IFCHR => {
1353 if namespace_node.mount.flags().contains(MountFlags::NODEV) {
1354 return error!(EACCES);
1355 }
1356 current_task.kernel().open_device(
1357 current_task,
1358 namespace_node,
1359 flags,
1360 rdev,
1361 DeviceMode::Char,
1362 )
1363 }
1364 FileMode::IFBLK => {
1365 if namespace_node.mount.flags().contains(MountFlags::NODEV) {
1366 return error!(EACCES);
1367 }
1368 current_task.kernel().open_device(
1369 current_task,
1370 namespace_node,
1371 flags,
1372 rdev,
1373 DeviceMode::Block,
1374 )
1375 }
1376 FileMode::IFIFO => Pipe::open(current_task, self.fifo(current_task), flags),
1377 FileMode::IFSOCK => error!(ENXIO),
1379 _ => self.create_file_ops(current_task, flags),
1380 }
1381 }
1382
1383 pub fn lookup(
1384 &self,
1385 current_task: &CurrentTask,
1386 mount: &MountInfo,
1387 name: &FsStr,
1388 ) -> Result<FsNodeHandle, Errno> {
1389 self.check_access(
1390 current_task,
1391 mount,
1392 Access::EXEC,
1393 CheckAccessReason::InternalPermissionChecks,
1394 &[Auditable::Name(name), std::panic::Location::caller().into()],
1395 )?;
1396 self.ops().lookup(self, current_task, name)
1397 }
1398
1399 pub fn create_node(
1400 &self,
1401 current_task: &CurrentTask,
1402 mount: &MountInfo,
1403 name: &FsStr,
1404 mut mode: FileMode,
1405 dev: DeviceId,
1406 mut owner: FsCred,
1407 ) -> Result<FsNodeHandle, Errno> {
1408 assert!(
1409 !matches!(mode.fmt(), FileMode::EMPTY | FileMode::IFLNK),
1410 "create_node with missing or symlink node type"
1411 );
1412
1413 self.check_access(
1414 current_task,
1415 mount,
1416 Access::WRITE,
1417 CheckAccessReason::InternalPermissionChecks,
1418 security::Auditable::Name(name),
1419 )?;
1420
1421 if mode.is_dir() {
1422 security::check_fs_node_mkdir_access(current_task, self, mode, name)?;
1426 } else {
1427 match mode.fmt() {
1436 FileMode::IFREG | FileMode::IFIFO | FileMode::IFSOCK => (),
1437 FileMode::IFCHR if dev == DeviceId::NONE => (),
1438 _ => security::check_task_capable(current_task, CAP_MKNOD)?,
1439 }
1440
1441 if mode.is_reg() {
1442 security::check_fs_node_create_access(current_task, self, mode, name)?;
1443 } else {
1444 security::check_fs_node_mknod_access(current_task, self, mode, name, dev)?;
1445 }
1446 }
1447
1448 self.update_metadata_for_child(current_task, &mut mode, &mut owner);
1450
1451 let new_node = if mode.is_dir() {
1453 self.ops().mkdir(self, current_task, name, mode, owner)?
1454 } else {
1455 self.ops().mknod(self, current_task, name, mode, dev, owner)?
1456 };
1457
1458 self.init_new_node_security_on_create(current_task, &new_node, name)?;
1460
1461 Ok(new_node)
1462 }
1463
1464 pub fn create_symlink(
1465 &self,
1466 current_task: &CurrentTask,
1467 mount: &MountInfo,
1468 name: &FsStr,
1469 target: &FsStr,
1470 owner: FsCred,
1471 ) -> Result<FsNodeHandle, Errno> {
1472 self.check_access(
1473 current_task,
1474 mount,
1475 Access::WRITE,
1476 CheckAccessReason::InternalPermissionChecks,
1477 security::Auditable::Name(name),
1478 )?;
1479 security::check_fs_node_symlink_access(current_task, self, name, target)?;
1480
1481 let new_node = self.ops().create_symlink(self, current_task, name, target, owner)?;
1482
1483 self.init_new_node_security_on_create(current_task, &new_node, name)?;
1484
1485 Ok(new_node)
1486 }
1487
1488 fn init_new_node_security_on_create(
1493 &self,
1494 current_task: &CurrentTask,
1495 new_node: &FsNode,
1496 name: &FsStr,
1497 ) -> Result<(), Errno> {
1498 security::fs_node_init_on_create(current_task, &new_node, self, name)?
1499 .map(|xattr| {
1500 match new_node.ops().set_xattr(
1501 &new_node,
1502 current_task,
1503 xattr.name,
1504 xattr.value.as_slice().into(),
1505 XattrOp::Create,
1506 ) {
1507 Err(e) => {
1508 if e.code == ENOTSUP {
1509 Ok(())
1512 } else {
1513 Err(e)
1514 }
1515 }
1516 result => result,
1517 }
1518 })
1519 .unwrap_or_else(|| Ok(()))
1520 }
1521
1522 pub fn create_tmpfile(
1523 &self,
1524 current_task: &CurrentTask,
1525 mount: &MountInfo,
1526 mut mode: FileMode,
1527 mut owner: FsCred,
1528 link_behavior: FsNodeLinkBehavior,
1529 ) -> Result<FsNodeHandle, Errno> {
1530 self.check_access(
1531 current_task,
1532 mount,
1533 Access::WRITE,
1534 CheckAccessReason::InternalPermissionChecks,
1535 security::Auditable::Location(std::panic::Location::caller()),
1536 )?;
1537 self.update_metadata_for_child(current_task, &mut mode, &mut owner);
1538 let node = self.ops().create_tmpfile(self, current_task, mode, owner)?;
1539 self.init_new_node_security_on_create(current_task, &node, "".into())?;
1540 if link_behavior == FsNodeLinkBehavior::Disallowed {
1541 node.ensure_rare_data().link_behavior.set(link_behavior).unwrap();
1542 }
1543 Ok(node)
1544 }
1545
1546 pub fn readlink(&self, current_task: &CurrentTask) -> Result<SymlinkTarget, Errno> {
1549 security::check_fs_node_read_link_access(current_task, self)?;
1551 self.ops().readlink(self, current_task)
1552 }
1553
1554 pub fn link(
1555 &self,
1556 current_task: &CurrentTask,
1557 mount: &MountInfo,
1558 name: &FsStr,
1559 child: &FsNodeHandle,
1560 ) -> Result<FsNodeHandle, Errno> {
1561 self.check_access(
1562 current_task,
1563 mount,
1564 Access::WRITE,
1565 CheckAccessReason::InternalPermissionChecks,
1566 security::Auditable::Location(std::panic::Location::caller()),
1567 )?;
1568
1569 if child.is_dir() {
1570 return error!(EPERM);
1571 }
1572
1573 if let Some(child_rare_data) = child.rare_data.get() {
1574 if matches!(child_rare_data.link_behavior.get(), Some(FsNodeLinkBehavior::Disallowed)) {
1575 return error!(ENOENT);
1576 }
1577 }
1578
1579 let (child_uid, mode) = {
1586 let info = child.info();
1587 (info.uid, info.mode)
1588 };
1589 if child_uid != current_task.current_creds().fsuid
1593 && !security::is_task_capable_noaudit(current_task, CAP_FOWNER)
1594 {
1595 child
1598 .check_access(
1599 current_task,
1600 mount,
1601 Access::READ | Access::WRITE,
1602 CheckAccessReason::InternalPermissionChecks,
1603 security::Auditable::Name(name),
1604 )
1605 .map_err(|e| {
1606 if e == EACCES { errno!(EPERM) } else { e }
1609 })?;
1610 if mode.contains(FileMode::ISGID | FileMode::IXGRP) {
1613 return error!(EPERM);
1614 };
1615 if mode.contains(FileMode::ISUID) {
1616 return error!(EPERM);
1617 };
1618 if !mode.contains(FileMode::IFREG) {
1619 return error!(EPERM);
1620 };
1621 }
1622
1623 security::check_fs_node_link_access(current_task, self, child)?;
1624
1625 self.ops().link(self, current_task, name, child)?;
1626 Ok(child.clone())
1627 }
1628
1629 pub fn unlink(
1630 &self,
1631 current_task: &CurrentTask,
1632 mount: &MountInfo,
1633 name: &FsStr,
1634 child: &FsNodeHandle,
1635 ) -> Result<(), Errno> {
1636 self.check_access(
1638 current_task,
1639 mount,
1640 Access::EXEC | Access::WRITE,
1641 CheckAccessReason::InternalPermissionChecks,
1642 security::Auditable::Name(name),
1643 )?;
1644 {
1645 let parent_info = self.info();
1646 let _token = allow_subclass();
1650 self.check_sticky_bit(current_task, child, &parent_info)?;
1651 }
1652 if child.is_dir() {
1653 security::check_fs_node_rmdir_access(current_task, self, child, name)?;
1654 } else {
1655 security::check_fs_node_unlink_access(current_task, self, child, name)?;
1656 }
1657 self.ops().unlink(self, current_task, name, child)?;
1658 self.update_ctime_mtime();
1659 Ok(())
1660 }
1661
1662 pub fn truncate(
1663 &self,
1664 current_task: &CurrentTask,
1665 mount: &MountInfo,
1666 length: u64,
1667 ) -> Result<(), Errno> {
1668 if self.is_dir() {
1669 return error!(EISDIR);
1670 }
1671 self.check_access(
1672 current_task,
1673 mount,
1674 Access::WRITE,
1675 CheckAccessReason::InternalPermissionChecks,
1676 security::Auditable::Location(std::panic::Location::caller()),
1677 )?;
1678
1679 let guard = self.ops().append_lock_write(self, current_task)?;
1680 self.truncate_locked(&guard, current_task, length)
1681 }
1682
1683 pub fn ftruncate(&self, current_task: &CurrentTask, length: u64) -> Result<(), Errno> {
1686 if self.is_dir() {
1687 return error!(EINVAL);
1692 }
1693
1694 let guard = self.ops().append_lock_write(self, current_task)?;
1710 self.truncate_locked(&guard, current_task, length)
1711 }
1712
1713 pub fn truncate_locked(
1715 &self,
1716 guard: &AppendLockWriteGuard<'_>,
1717 current_task: &CurrentTask,
1718 length: u64,
1719 ) -> Result<(), Errno> {
1720 if length > MAX_LFS_FILESIZE as u64 {
1721 return error!(EINVAL);
1722 }
1723 if length > current_task.thread_group().get_rlimit(Resource::FSIZE) {
1724 send_standard_signal(current_task, SignalInfo::kernel(SIGXFSZ));
1725 return error!(EFBIG);
1726 }
1727 self.clear_suid_and_sgid_bits(current_task)?;
1728
1729 self.ops().truncate(guard, self, current_task, length)?;
1730 self.update_ctime_mtime();
1731 Ok(())
1732 }
1733
1734 pub fn fallocate(
1737 &self,
1738 current_task: &CurrentTask,
1739 mode: FallocMode,
1740 offset: u64,
1741 length: u64,
1742 ) -> Result<(), Errno> {
1743 let guard = self.ops().append_lock_write(self, current_task)?;
1744 self.fallocate_locked(&guard, current_task, mode, offset, length)
1745 }
1746
1747 pub fn fallocate_locked(
1748 &self,
1749 guard: &AppendLockWriteGuard<'_>,
1750 current_task: &CurrentTask,
1751 mode: FallocMode,
1752 offset: u64,
1753 length: u64,
1754 ) -> Result<(), Errno> {
1755 let allocate_size = checked_add_offset_and_length(offset as usize, length as usize)
1756 .map_err(|_| errno!(EFBIG))? as u64;
1757 if allocate_size > current_task.thread_group().get_rlimit(Resource::FSIZE) {
1758 send_standard_signal(current_task, SignalInfo::kernel(SIGXFSZ));
1759 return error!(EFBIG);
1760 }
1761
1762 self.clear_suid_and_sgid_bits(current_task)?;
1763
1764 self.ops().allocate(guard, self, current_task, mode, offset, length)?;
1765 self.update_ctime_mtime();
1766 Ok(())
1767 }
1768
1769 fn update_metadata_for_child(
1770 &self,
1771 current_task: &CurrentTask,
1772 mode: &mut FileMode,
1773 owner: &mut FsCred,
1774 ) {
1775 {
1778 let self_info = self.info();
1779 if self_info.mode.contains(FileMode::ISGID) {
1780 owner.gid = self_info.gid;
1781 if mode.is_dir() {
1782 *mode |= FileMode::ISGID;
1783 }
1784 }
1785 }
1786
1787 if !mode.is_dir() {
1788 let current_creds = current_task.current_creds();
1797 if owner.gid != current_creds.fsgid
1798 && !current_creds.is_in_group(owner.gid)
1799 && !security::is_task_capable_noaudit(current_task, CAP_FOWNER)
1800 {
1801 *mode &= !FileMode::ISGID;
1802 }
1803 }
1804 }
1805
1806 pub fn check_o_noatime_allowed(&self, current_task: &CurrentTask) -> Result<(), Errno> {
1808 if current_task.current_creds().fsuid != self.info().uid {
1823 security::check_task_capable(current_task, CAP_FOWNER)?;
1824 }
1825 Ok(())
1826 }
1827
1828 pub fn default_check_access_impl(
1829 &self,
1830 current_task: &CurrentTask,
1831 permission_flags: security::PermissionFlags,
1832 reason: CheckAccessReason,
1833 info: LockDepReadGuard<'_, FsNodeInfo>,
1834 audit_context: Auditable<'_>,
1835 ) -> Result<(), Errno> {
1836 let (node_uid, node_gid, mode) = (info.uid, info.gid, info.mode);
1837 std::mem::drop(info);
1838 if let CheckAccessReason::ChangeTimestamps { now } = reason {
1839 if current_task.current_creds().fsuid == node_uid {
1844 return Ok(());
1845 }
1846 if now {
1847 if security::is_task_capable_noaudit(current_task, CAP_FOWNER) {
1848 return Ok(());
1849 }
1850 } else {
1851 security::check_task_capable(current_task, CAP_FOWNER)?;
1852 return Ok(());
1853 }
1854 }
1855 check_access(self, current_task, permission_flags, node_uid, node_gid, mode)?;
1856 security::fs_node_permission(current_task, self, permission_flags, audit_context)
1857 }
1858
1859 pub fn check_access<'a>(
1863 &self,
1864 current_task: &CurrentTask,
1865 mount: &MountInfo,
1866 access: impl Into<security::PermissionFlags>,
1867 reason: CheckAccessReason,
1868 audit_context: impl Into<security::Auditable<'a>>,
1869 ) -> Result<(), Errno> {
1870 let mut permission_flags = access.into();
1871 if permission_flags.contains(security::PermissionFlags::WRITE)
1872 && !self.info().mode.is_special()
1873 {
1874 mount.check_readonly_filesystem()?;
1875 }
1876 if permission_flags.contains(security::PermissionFlags::EXEC) && !self.is_dir() {
1877 mount.check_noexec_filesystem()?;
1878 }
1879 if reason == CheckAccessReason::Access {
1880 permission_flags |= PermissionFlags::ACCESS;
1881 }
1882 self.ops().check_access(
1883 self,
1884 current_task,
1885 permission_flags,
1886 &self.info,
1887 reason,
1888 audit_context.into(),
1889 )
1890 }
1891
1892 pub fn check_sticky_bit(
1896 &self,
1897 current_task: &CurrentTask,
1898 child: &FsNodeHandle,
1899 self_info: &FsNodeInfo,
1900 ) -> Result<(), Errno> {
1901 if self_info.mode.contains(FileMode::ISVTX)
1902 && child.info().uid != current_task.current_creds().fsuid
1903 {
1904 security::check_task_capable(current_task, CAP_FOWNER)?;
1905 }
1906 Ok(())
1907 }
1908
1909 pub fn fifo(&self, current_task: &CurrentTask) -> &PipeHandle {
1910 assert!(self.is_fifo());
1911 self.ensure_rare_data().ensure_fifo(current_task)
1912 }
1913
1914 pub fn bound_socket(&self) -> Option<&SocketHandle> {
1916 if let Some(rare_data) = self.rare_data.get() { rare_data.bound_socket.get() } else { None }
1917 }
1918
1919 pub fn set_bound_socket(&self, socket: SocketHandle) {
1923 assert!(self.ensure_rare_data().bound_socket.set(socket).is_ok());
1924 }
1925
1926 pub fn update_attributes<F>(&self, current_task: &CurrentTask, mutator: F) -> Result<(), Errno>
1927 where
1928 F: FnOnce(&mut FsNodeInfo) -> Result<(), Errno>,
1929 {
1930 let mut info = self.info.write();
1931 let mut new_info = info.clone();
1932 mutator(&mut new_info)?;
1933
1934 let new_access = new_info.mode.user_access()
1935 | new_info.mode.group_access()
1936 | new_info.mode.other_access();
1937
1938 if new_access.intersects(Access::EXEC) {
1939 let write_guard_state = self.write_guard_state.lock();
1940 if let Ok(seals) = write_guard_state.get_seals() {
1941 if seals.contains(SealFlags::NO_EXEC) {
1942 return error!(EPERM);
1943 }
1944 }
1945 }
1946
1947 assert_eq!(info.time_status_change, new_info.time_status_change);
1949 if *info == new_info {
1950 return Ok(());
1951 }
1952 new_info.time_status_change = utc::utc_now();
1953
1954 let mut has = zxio_node_attr_has_t { ..Default::default() };
1955 has.modification_time = info.time_modify != new_info.time_modify;
1956 has.access_time = info.time_access != new_info.time_access;
1957 has.mode = info.mode != new_info.mode;
1958 has.uid = info.uid != new_info.uid;
1959 has.gid = info.gid != new_info.gid;
1960 has.rdev = info.rdev != new_info.rdev;
1961 has.casefold = info.casefold != new_info.casefold;
1962 has.wrapping_key_id = info.wrapping_key_id != new_info.wrapping_key_id;
1963
1964 if has.casefold && !self.ops().has_casefold_support(self) {
1965 return error!(ENOTSUP);
1966 }
1967 security::check_fs_node_setattr_access(current_task, &self, &has)?;
1968
1969 if has.modification_time
1971 || has.access_time
1972 || has.mode
1973 || has.uid
1974 || has.gid
1975 || has.rdev
1976 || has.casefold
1977 || has.wrapping_key_id
1978 {
1979 self.ops().update_attributes(self, current_task, &new_info, has)?;
1980 }
1981
1982 *info = new_info;
1983 Ok(())
1984 }
1985
1986 pub fn chmod(
1990 &self,
1991 current_task: &CurrentTask,
1992 mount: &MountInfo,
1993 mut mode: FileMode,
1994 ) -> Result<(), Errno> {
1995 mount.check_readonly_filesystem()?;
1996 self.update_attributes(current_task, |info| {
1997 let current_creds = current_task.current_creds();
1998 if info.uid != current_creds.euid {
1999 security::check_task_capable(current_task, CAP_FOWNER)?;
2000 } else if info.gid != current_creds.egid
2001 && !current_creds.is_in_group(info.gid)
2002 && mode.intersects(FileMode::ISGID)
2003 && !security::is_task_capable_noaudit(current_task, CAP_FOWNER)
2004 {
2005 mode &= !FileMode::ISGID;
2006 }
2007 info.chmod(mode);
2008 Ok(())
2009 })
2010 }
2011
2012 pub fn chown(
2014 &self,
2015 current_task: &CurrentTask,
2016 mount: &MountInfo,
2017 owner: Option<uid_t>,
2018 group: Option<gid_t>,
2019 ) -> Result<(), Errno> {
2020 mount.check_readonly_filesystem()?;
2021 self.update_attributes(current_task, |info| {
2022 if security::is_task_capable_noaudit(current_task, CAP_CHOWN) {
2023 info.chown(owner, group);
2024 return Ok(());
2025 }
2026
2027 if let Some(uid) = owner {
2029 if info.uid != uid {
2030 return error!(EPERM);
2031 }
2032 }
2033
2034 let (euid, is_in_group) = {
2035 let current_creds = current_task.current_creds();
2036 (current_creds.euid, group.map(|gid| current_creds.is_in_group(gid)))
2037 };
2038
2039 if info.uid == euid {
2041 if let Some(is_in_group) = is_in_group {
2043 if !is_in_group {
2044 return error!(EPERM);
2045 }
2046 }
2047 info.chown(None, group);
2048 return Ok(());
2049 }
2050
2051 if owner.is_some() || group.is_some() {
2053 return error!(EPERM);
2054 }
2055
2056 if info.mode.is_reg()
2059 && (info.mode.contains(FileMode::ISUID)
2060 || info.mode.contains(FileMode::ISGID | FileMode::IXGRP))
2061 {
2062 return error!(EPERM);
2063 }
2064
2065 info.chown(None, None);
2066 Ok(())
2067 })
2068 }
2069
2070 pub unsafe fn force_chown(&self, creds: FsCred) {
2081 self.update_info(|info| {
2082 info.chown(Some(creds.uid), Some(creds.gid));
2083 });
2084 }
2085
2086 pub fn is_reg(&self) -> bool {
2088 self.info().mode.is_reg()
2089 }
2090
2091 pub fn is_dir(&self) -> bool {
2093 self.info().mode.is_dir()
2094 }
2095
2096 pub fn is_sock(&self) -> bool {
2098 self.info().mode.is_sock()
2099 }
2100
2101 pub fn is_fifo(&self) -> bool {
2103 self.info().mode.is_fifo()
2104 }
2105
2106 pub fn is_lnk(&self) -> bool {
2108 self.info().mode.is_lnk()
2109 }
2110
2111 pub fn dev(&self) -> DeviceId {
2112 self.fs().dev_id
2113 }
2114
2115 pub fn stat(&self, current_task: &CurrentTask) -> Result<uapi::stat, Errno> {
2116 security::check_fs_node_getattr_access(current_task, self)?;
2117
2118 let info = self.fetch_and_refresh_info(current_task)?;
2119
2120 let time_to_kernel_timespec_pair = |t| {
2121 let timespec { tv_sec, tv_nsec } = timespec_from_time(t);
2122 let time = tv_sec.try_into().map_err(|_| errno!(EINVAL))?;
2123 let time_nsec = tv_nsec.try_into().map_err(|_| errno!(EINVAL))?;
2124 Ok((time, time_nsec))
2125 };
2126
2127 let (st_atime, st_atime_nsec) = time_to_kernel_timespec_pair(info.time_access)?;
2128 let (st_mtime, st_mtime_nsec) = time_to_kernel_timespec_pair(info.time_modify)?;
2129 let (st_ctime, st_ctime_nsec) = time_to_kernel_timespec_pair(info.time_status_change)?;
2130
2131 Ok(uapi::stat {
2132 st_dev: self.dev().bits(),
2133 st_ino: self.ino,
2134 st_nlink: info.link_count.try_into().map_err(|_| errno!(EINVAL))?,
2135 st_mode: info.mode.bits(),
2136 st_uid: info.uid,
2137 st_gid: info.gid,
2138 st_rdev: info.rdev.bits(),
2139 st_size: info.size.try_into().map_err(|_| errno!(EINVAL))?,
2140 st_blksize: info.blksize.try_into().map_err(|_| errno!(EINVAL))?,
2141 st_blocks: info.blocks.try_into().map_err(|_| errno!(EINVAL))?,
2142 st_atime,
2143 st_atime_nsec,
2144 st_mtime,
2145 st_mtime_nsec,
2146 st_ctime,
2147 st_ctime_nsec,
2148 ..Default::default()
2149 })
2150 }
2151
2152 pub fn get_size(&self, current_task: &CurrentTask) -> Result<usize, Errno> {
2159 self.ops().get_size(self, current_task)
2160 }
2161
2162 fn statx_timestamp_from_time(time: UtcInstant) -> statx_timestamp {
2163 let nanos = time.into_nanos();
2164 statx_timestamp {
2165 tv_sec: nanos / NANOS_PER_SECOND,
2166 tv_nsec: (nanos % NANOS_PER_SECOND) as u32,
2167 ..Default::default()
2168 }
2169 }
2170
2171 pub fn statx(
2172 &self,
2173 current_task: &CurrentTask,
2174 flags: StatxFlags,
2175 mask: u32,
2176 ) -> Result<statx, Errno> {
2177 security::check_fs_node_getattr_access(current_task, self)?;
2178
2179 let info = if flags.contains(StatxFlags::AT_STATX_DONT_SYNC) {
2181 self.info()
2182 } else {
2183 self.fetch_and_refresh_info(current_task)?
2184 };
2185 if mask & STATX__RESERVED == STATX__RESERVED {
2186 return error!(EINVAL);
2187 }
2188
2189 track_stub!(TODO("https://fxbug.dev/302594110"), "statx attributes");
2190 let stx_mnt_id = 0;
2191 let mut stx_attributes = 0;
2192 let stx_attributes_mask = STATX_ATTR_VERITY as u64;
2193
2194 if matches!(*self.fsverity.lock(), FsVerityState::FsVerity) {
2195 stx_attributes |= STATX_ATTR_VERITY as u64;
2196 }
2197
2198 Ok(statx {
2199 stx_mask: STATX_NLINK
2200 | STATX_UID
2201 | STATX_GID
2202 | STATX_ATIME
2203 | STATX_MTIME
2204 | STATX_CTIME
2205 | STATX_INO
2206 | STATX_SIZE
2207 | STATX_BLOCKS
2208 | STATX_BASIC_STATS,
2209 stx_blksize: info.blksize.try_into().map_err(|_| errno!(EINVAL))?,
2210 stx_attributes,
2211 stx_nlink: info.link_count.try_into().map_err(|_| errno!(EINVAL))?,
2212 stx_uid: info.uid,
2213 stx_gid: info.gid,
2214 stx_mode: info.mode.bits().try_into().map_err(|_| errno!(EINVAL))?,
2215 stx_ino: self.ino,
2216 stx_size: info.size.try_into().map_err(|_| errno!(EINVAL))?,
2217 stx_blocks: info.blocks.try_into().map_err(|_| errno!(EINVAL))?,
2218 stx_attributes_mask,
2219 stx_ctime: Self::statx_timestamp_from_time(info.time_status_change),
2220 stx_mtime: Self::statx_timestamp_from_time(info.time_modify),
2221 stx_atime: Self::statx_timestamp_from_time(info.time_access),
2222
2223 stx_rdev_major: info.rdev.major(),
2224 stx_rdev_minor: info.rdev.minor(),
2225
2226 stx_dev_major: self.fs().dev_id.major(),
2227 stx_dev_minor: self.fs().dev_id.minor(),
2228 stx_mnt_id,
2229 ..Default::default()
2230 })
2231 }
2232
2233 fn check_xattr_access(
2236 &self,
2237 current_task: &CurrentTask,
2238 mount: &MountInfo,
2239 name: &FsStr,
2240 access: Access,
2241 ) -> Result<(), Errno> {
2242 assert!(access == Access::READ || access == Access::WRITE);
2243
2244 let enodata_if_read =
2245 |e: Errno| if access == Access::READ && e.code == EPERM { errno!(ENODATA) } else { e };
2246
2247 if name.starts_with(XATTR_USER_PREFIX.to_bytes()) {
2250 {
2251 let info = self.info();
2252 if !info.mode.is_reg() && !info.mode.is_dir() {
2253 return Err(enodata_if_read(errno!(EPERM)));
2254 }
2255 }
2256
2257 self.check_access(
2261 current_task,
2262 mount,
2263 access,
2264 CheckAccessReason::InternalPermissionChecks,
2265 security::Auditable::Name(name),
2266 )?;
2267 } else if name.starts_with(XATTR_TRUSTED_PREFIX.to_bytes()) {
2268 security::check_task_capable(current_task, CAP_SYS_ADMIN).map_err(enodata_if_read)?;
2270 } else if name.starts_with(XATTR_SYSTEM_PREFIX.to_bytes()) {
2271 security::check_task_capable(current_task, CAP_SYS_ADMIN).map_err(enodata_if_read)?;
2275 } else if name.starts_with(XATTR_SECURITY_PREFIX.to_bytes()) {
2276 if access == Access::WRITE {
2277 if !security::fs_node_xattr_skipcap(name) {
2279 security::check_task_capable(current_task, CAP_SYS_ADMIN)
2280 .map_err(enodata_if_read)?;
2281 }
2282 }
2283 } else {
2284 panic!("Unknown extended attribute prefix: {}", name);
2285 }
2286 Ok(())
2287 }
2288
2289 pub fn get_xattr(
2290 &self,
2291 current_task: &CurrentTask,
2292 mount: &MountInfo,
2293 name: &FsStr,
2294 max_size: usize,
2295 ) -> Result<ValueOrSize<FsString>, Errno> {
2296 self.check_xattr_access(current_task, mount, name, Access::READ)?;
2298
2299 security::check_fs_node_getxattr_access(current_task, self, name)?;
2301
2302 if name.starts_with(XATTR_SECURITY_PREFIX.to_bytes()) {
2303 security::fs_node_getsecurity(current_task, self, name, max_size)
2306 } else {
2307 self.ops().get_xattr(self, current_task, name, max_size)
2309 }
2310 }
2311
2312 pub fn set_xattr(
2313 &self,
2314 current_task: &CurrentTask,
2315 mount: &MountInfo,
2316 name: &FsStr,
2317 value: &FsStr,
2318 op: XattrOp,
2319 ) -> Result<(), Errno> {
2320 self.check_xattr_access(current_task, mount, name, Access::WRITE)?;
2322
2323 security::check_fs_node_setxattr_access(current_task, self, name, value, op)?;
2325
2326 if name.starts_with(XATTR_SECURITY_PREFIX.to_bytes()) {
2327 security::fs_node_setsecurity(current_task, self, name, value, op)
2330 } else {
2331 self.ops().set_xattr(self, current_task, name, value, op)
2333 }
2334 }
2335
2336 pub fn remove_xattr(
2337 &self,
2338 current_task: &CurrentTask,
2339 mount: &MountInfo,
2340 name: &FsStr,
2341 ) -> Result<(), Errno> {
2342 self.check_xattr_access(current_task, mount, name, Access::WRITE)?;
2344
2345 security::check_fs_node_removexattr_access(current_task, self, name)?;
2347 self.ops().remove_xattr(self, current_task, name)
2348 }
2349
2350 pub fn list_xattrs(
2351 &self,
2352 current_task: &CurrentTask,
2353 max_size: usize,
2354 ) -> Result<ValueOrSize<Vec<FsString>>, Errno> {
2355 security::check_fs_node_listxattr_access(current_task, self)?;
2356 Ok(self.ops().list_xattrs(self, current_task, max_size)?.map(|mut v| {
2357 if !security::is_task_capable_noaudit(current_task, CAP_SYS_ADMIN) {
2362 v.retain(|name| !name.starts_with(XATTR_TRUSTED_PREFIX.to_bytes()));
2363 }
2364 v
2365 }))
2366 }
2367
2368 pub fn info(&self) -> LockDepReadGuard<'_, FsNodeInfo> {
2370 self.info.read()
2371 }
2372
2373 pub(super) fn info_lock(&self) -> &DynamicLockDepRwLock<FsNodeInfo> {
2378 &self.info
2379 }
2380
2381 pub fn fetch_and_refresh_info(
2383 &self,
2384 current_task: &CurrentTask,
2385 ) -> Result<LockDepReadGuard<'_, FsNodeInfo>, Errno> {
2386 self.ops().fetch_and_refresh_info(self, current_task, &self.info)
2387 }
2388
2389 pub fn update_info<F, T>(&self, mutator: F) -> T
2390 where
2391 F: FnOnce(&mut FsNodeInfo) -> T,
2392 {
2393 let mut info = self.info.write();
2394 mutator(&mut info)
2395 }
2396
2397 pub fn clear_suid_and_sgid_bits(&self, current_task: &CurrentTask) -> Result<(), Errno> {
2399 if !self.info().has_suid_or_sgid_bits() {
2400 return Ok(());
2401 }
2402 self.update_attributes(current_task, |info| {
2403 if info.has_suid_or_sgid_bits()
2404 && !security::is_task_capable_noaudit(current_task, CAP_FSETID)
2405 {
2406 info.clear_suid_and_sgid_bits();
2407 }
2408 Ok(())
2409 })
2410 }
2411
2412 pub fn update_ctime_mtime(&self) {
2414 if self.fs().manages_timestamps() {
2415 return;
2416 }
2417 self.update_info(|info| {
2418 let now = utc::utc_now();
2419 info.time_status_change = now;
2420 info.time_modify = now;
2421 });
2422 }
2423
2424 pub fn update_ctime(&self) {
2426 if self.fs().manages_timestamps() {
2427 return;
2428 }
2429 self.update_info(|info| {
2430 let now = utc::utc_now();
2431 info.time_status_change = now;
2432 });
2433 }
2434
2435 pub fn update_atime_mtime(
2438 &self,
2439 current_task: &CurrentTask,
2440 mount: &MountInfo,
2441 atime: TimeUpdateType,
2442 mtime: TimeUpdateType,
2443 ) -> Result<(), Errno> {
2444 mount.check_readonly_filesystem()?;
2446
2447 let now = matches!((atime, mtime), (TimeUpdateType::Now, TimeUpdateType::Now));
2448 self.check_access(
2449 current_task,
2450 mount,
2451 Access::WRITE,
2452 CheckAccessReason::ChangeTimestamps { now },
2453 security::Auditable::Location(std::panic::Location::caller()),
2454 )?;
2455
2456 if !matches!((atime, mtime), (TimeUpdateType::Omit, TimeUpdateType::Omit)) {
2457 self.update_attributes(current_task, |info| {
2461 let now = utc::utc_now();
2462 let get_time = |time: TimeUpdateType| match time {
2463 TimeUpdateType::Now => Some(now),
2464 TimeUpdateType::Time(t) => Some(t),
2465 TimeUpdateType::Omit => None,
2466 };
2467 if let Some(time) = get_time(atime) {
2468 info.time_access = time;
2469 }
2470 if let Some(time) = get_time(mtime) {
2471 info.time_modify = time;
2472 }
2473 Ok(())
2474 })?;
2475 }
2476 Ok(())
2477 }
2478
2479 pub fn node_key(&self) -> ino_t {
2484 self.ops().node_key(self)
2485 }
2486
2487 fn ensure_rare_data(&self) -> &FsNodeRareData {
2488 self.rare_data.get_or_init(|| Box::new(FsNodeRareData::default()))
2489 }
2490
2491 pub fn ensure_watchers(&self) -> &inotify_hook::InotifyWatchers {
2496 &self.ensure_rare_data().watchers
2497 }
2498
2499 pub fn notify(
2501 &self,
2502 event_mask: InotifyMask,
2503 cookie: u32,
2504 name: &FsStr,
2505 mode: FileMode,
2506 is_dead: bool,
2507 ) {
2508 if let Some(rare_data) = self.rare_data.get() {
2509 let kernel = self.fs().kernel.upgrade().expect("kernel is dead");
2510 if let Some(hook) = kernel.expando.peek::<Arc<dyn inotify_hook::NotifyHook>>() {
2511 hook.notify(&rare_data.watchers, event_mask, cookie, name, mode, is_dead);
2512 }
2513 }
2514 }
2515
2516 pub fn enable_fsverity(
2518 &self,
2519 current_task: &CurrentTask,
2520 descriptor: &fsverity_descriptor,
2521 ) -> Result<(), Errno> {
2522 self.ops().enable_fsverity(self, current_task, descriptor)
2523 }
2524}
2525
2526impl std::fmt::Debug for FsNode {
2527 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2528 f.debug_struct("FsNode")
2529 .field("fs", &self.fs().name())
2530 .field("info", &*self.info())
2531 .field("ops_ty", &self.ops().type_name())
2532 .finish()
2533 }
2534}
2535
2536impl Releasable for FsNode {
2537 type Context<'a> = &'a CurrentTask;
2538
2539 fn release<'a>(self, context: &'a CurrentTask) {
2540 let current_task = context;
2541 if let Some(fs) = self.fs.upgrade() {
2542 fs.remove_node(&self);
2543 }
2544 if let Err(err) = self.ops.forget(current_task, self.info.into_inner()) {
2545 log_error!("Error on FsNodeOps::forget: {err:?}");
2546 }
2547 }
2548}
2549
2550fn check_access(
2551 fs_node: &FsNode,
2552 current_task: &CurrentTask,
2553 permission_flags: security::PermissionFlags,
2554 node_uid: uid_t,
2555 node_gid: gid_t,
2556 mode: FileMode,
2557) -> Result<(), Errno> {
2558 let (fsuid, is_in_group) = {
2560 let current_creds = current_task.current_creds();
2561 (current_creds.fsuid, current_creds.is_in_group(node_gid))
2562 };
2563 let granted = if fsuid == node_uid {
2564 mode.user_access()
2565 } else if is_in_group {
2566 mode.group_access()
2567 } else {
2568 mode.other_access()
2569 };
2570
2571 let access = permission_flags.as_access();
2572 if granted.contains(access) {
2573 return Ok(());
2574 }
2575
2576 let mut requested = access & !granted;
2579
2580 let have_dont_audit = OnceBool::new();
2583 let has_capability = move |current_task, capability| {
2584 let dont_audit = have_dont_audit.get_or_init(|| {
2585 permission_flags.contains(PermissionFlags::ACCESS)
2586 && security::has_dontaudit_access(current_task, fs_node)
2587 });
2588 if dont_audit {
2589 security::is_task_capable_noaudit(current_task, capability)
2590 } else {
2591 security::check_task_capable(current_task, capability).is_ok()
2592 }
2593 };
2594
2595 let dac_read_search_access =
2597 if mode.is_dir() { Access::READ | Access::EXEC } else { Access::READ };
2598 if dac_read_search_access.intersects(requested)
2599 && has_capability(current_task, CAP_DAC_READ_SEARCH)
2600 {
2601 requested.remove(dac_read_search_access);
2602 }
2603 if requested.is_empty() {
2604 return Ok(());
2605 }
2606
2607 let mut dac_override_access = Access::READ | Access::WRITE;
2609 dac_override_access |= if mode.is_dir() {
2610 Access::EXEC
2611 } else {
2612 (mode.user_access() | mode.group_access() | mode.other_access()) & Access::EXEC
2614 };
2615 if dac_override_access.intersects(requested) && has_capability(current_task, CAP_DAC_OVERRIDE) {
2616 requested.remove(dac_override_access);
2617 }
2618 if requested.is_empty() {
2619 return Ok(());
2620 }
2621
2622 return error!(EACCES);
2623}
2624
2625#[cfg(test)]
2626mod tests {
2627 use super::*;
2628 use crate::device::mem::mem_device_init;
2629 use crate::testing::*;
2630 use crate::vfs::buffers::VecOutputBuffer;
2631 use starnix_uapi::auth::Credentials;
2632 use starnix_uapi::file_mode::mode;
2633
2634 #[::fuchsia::test]
2635 async fn open_device_file() {
2636 spawn_kernel_and_run(async |current_task| {
2637 mem_device_init(current_task.kernel()).expect("mem_device_init");
2638
2639 current_task
2642 .fs()
2643 .root()
2644 .create_node(¤t_task, "zero".into(), mode!(IFCHR, 0o666), DeviceId::ZERO)
2645 .expect("create_node");
2646
2647 const CONTENT_LEN: usize = 10;
2648 let mut buffer = VecOutputBuffer::new(CONTENT_LEN);
2649
2650 let device_file =
2652 current_task.open_file("zero".into(), OpenFlags::RDONLY).expect("open device file");
2653 device_file.read(¤t_task, &mut buffer).expect("read from zero");
2654
2655 assert_eq!(&[0; CONTENT_LEN], buffer.data());
2657 })
2658 .await;
2659 }
2660
2661 #[::fuchsia::test]
2662 async fn node_info_is_reflected_in_stat() {
2663 spawn_kernel_and_run(async |current_task| {
2664 let node = ¤t_task
2666 .fs()
2667 .root()
2668 .create_node(¤t_task, "zero".into(), FileMode::IFCHR, DeviceId::ZERO)
2669 .expect("create_node")
2670 .entry
2671 .node;
2672 node.update_info(|info| {
2673 info.mode = FileMode::IFSOCK;
2674 info.size = 1;
2675 info.blocks = 2;
2676 info.blksize = 4;
2677 info.uid = 9;
2678 info.gid = 10;
2679 info.link_count = 11;
2680 info.time_status_change = UtcInstant::from_nanos(1);
2681 info.time_access = UtcInstant::from_nanos(2);
2682 info.time_modify = UtcInstant::from_nanos(3);
2683 info.rdev = DeviceId::new(13, 13);
2684 });
2685 let stat = node.stat(¤t_task).expect("stat");
2686
2687 assert_eq!(stat.st_mode, FileMode::IFSOCK.bits());
2688 assert_eq!(stat.st_size, 1);
2689 assert_eq!(stat.st_blksize, 4);
2690 assert_eq!(stat.st_blocks, 2);
2691 assert_eq!(stat.st_uid, 9);
2692 assert_eq!(stat.st_gid, 10);
2693 assert_eq!(stat.st_nlink, 11);
2694 assert_eq!(stat.st_ctime, 0);
2695 assert_eq!(stat.st_ctime_nsec, 1);
2696 assert_eq!(stat.st_atime, 0);
2697 assert_eq!(stat.st_atime_nsec, 2);
2698 assert_eq!(stat.st_mtime, 0);
2699 assert_eq!(stat.st_mtime_nsec, 3);
2700 assert_eq!(stat.st_rdev, DeviceId::new(13, 13).bits());
2701 })
2702 .await;
2703 }
2704
2705 #[::fuchsia::test]
2706 fn test_flock_operation() {
2707 assert!(FlockOperation::from_flags(0).is_err());
2708 assert!(FlockOperation::from_flags(u32::MAX).is_err());
2709
2710 let operation1 = FlockOperation::from_flags(LOCK_SH).expect("from_flags");
2711 assert!(!operation1.is_unlock());
2712 assert!(!operation1.is_lock_exclusive());
2713 assert!(operation1.is_blocking());
2714
2715 let operation2 = FlockOperation::from_flags(LOCK_EX | LOCK_NB).expect("from_flags");
2716 assert!(!operation2.is_unlock());
2717 assert!(operation2.is_lock_exclusive());
2718 assert!(!operation2.is_blocking());
2719
2720 let operation3 = FlockOperation::from_flags(LOCK_UN).expect("from_flags");
2721 assert!(operation3.is_unlock());
2722 assert!(!operation3.is_lock_exclusive());
2723 assert!(operation3.is_blocking());
2724 }
2725
2726 #[::fuchsia::test]
2727 async fn test_check_access() {
2728 spawn_kernel_and_run(async |current_task| {
2729 let mut creds = Credentials::with_ids(1, 2);
2730 creds.groups = vec![3, 4];
2731 current_task.set_creds(creds);
2732
2733 let node = ¤t_task
2735 .fs()
2736 .root()
2737 .create_node(¤t_task, "foo".into(), FileMode::IFREG, DeviceId::NONE)
2738 .expect("create_node")
2739 .entry
2740 .node;
2741 let check_access = |uid: uid_t, gid: gid_t, perm: u32, access: Access| {
2742 node.update_info(|info| {
2743 info.mode = mode!(IFREG, perm);
2744 info.uid = uid;
2745 info.gid = gid;
2746 });
2747 node.check_access(
2748 ¤t_task,
2749 &MountInfo::detached(),
2750 access,
2751 CheckAccessReason::InternalPermissionChecks,
2752 security::Auditable::Location(std::panic::Location::caller()),
2753 )
2754 };
2755
2756 assert_eq!(check_access(0, 0, 0o700, Access::EXEC), error!(EACCES));
2757 assert_eq!(check_access(0, 0, 0o700, Access::READ), error!(EACCES));
2758 assert_eq!(check_access(0, 0, 0o700, Access::WRITE), error!(EACCES));
2759
2760 assert_eq!(check_access(0, 0, 0o070, Access::EXEC), error!(EACCES));
2761 assert_eq!(check_access(0, 0, 0o070, Access::READ), error!(EACCES));
2762 assert_eq!(check_access(0, 0, 0o070, Access::WRITE), error!(EACCES));
2763
2764 assert_eq!(check_access(0, 0, 0o007, Access::EXEC), Ok(()));
2765 assert_eq!(check_access(0, 0, 0o007, Access::READ), Ok(()));
2766 assert_eq!(check_access(0, 0, 0o007, Access::WRITE), Ok(()));
2767
2768 assert_eq!(check_access(1, 0, 0o700, Access::EXEC), Ok(()));
2769 assert_eq!(check_access(1, 0, 0o700, Access::READ), Ok(()));
2770 assert_eq!(check_access(1, 0, 0o700, Access::WRITE), Ok(()));
2771
2772 assert_eq!(check_access(1, 0, 0o100, Access::EXEC), Ok(()));
2773 assert_eq!(check_access(1, 0, 0o100, Access::READ), error!(EACCES));
2774 assert_eq!(check_access(1, 0, 0o100, Access::WRITE), error!(EACCES));
2775
2776 assert_eq!(check_access(1, 0, 0o200, Access::EXEC), error!(EACCES));
2777 assert_eq!(check_access(1, 0, 0o200, Access::READ), error!(EACCES));
2778 assert_eq!(check_access(1, 0, 0o200, Access::WRITE), Ok(()));
2779
2780 assert_eq!(check_access(1, 0, 0o400, Access::EXEC), error!(EACCES));
2781 assert_eq!(check_access(1, 0, 0o400, Access::READ), Ok(()));
2782 assert_eq!(check_access(1, 0, 0o400, Access::WRITE), error!(EACCES));
2783
2784 assert_eq!(check_access(0, 2, 0o700, Access::EXEC), error!(EACCES));
2785 assert_eq!(check_access(0, 2, 0o700, Access::READ), error!(EACCES));
2786 assert_eq!(check_access(0, 2, 0o700, Access::WRITE), error!(EACCES));
2787
2788 assert_eq!(check_access(0, 2, 0o070, Access::EXEC), Ok(()));
2789 assert_eq!(check_access(0, 2, 0o070, Access::READ), Ok(()));
2790 assert_eq!(check_access(0, 2, 0o070, Access::WRITE), Ok(()));
2791
2792 assert_eq!(check_access(0, 3, 0o070, Access::EXEC), Ok(()));
2793 assert_eq!(check_access(0, 3, 0o070, Access::READ), Ok(()));
2794 assert_eq!(check_access(0, 3, 0o070, Access::WRITE), Ok(()));
2795 })
2796 .await;
2797 }
2798
2799 #[::fuchsia::test]
2800 async fn set_security_xattr_fails_without_security_module_or_root() {
2801 spawn_kernel_and_run(async |current_task| {
2802 let mut creds = Credentials::with_ids(1, 2);
2803 creds.groups = vec![3, 4];
2804 current_task.set_creds(creds);
2805
2806 let node = ¤t_task
2808 .fs()
2809 .root()
2810 .create_node(¤t_task, "foo".into(), FileMode::IFREG, DeviceId::NONE)
2811 .expect("create_node")
2812 .entry
2813 .node;
2814
2815 node.update_info(|info| info.mode = mode!(IFREG, 0o777));
2817
2818 assert_eq!(
2821 node.set_xattr(
2822 ¤t_task,
2823 &MountInfo::detached(),
2824 "security.name".into(),
2825 "security_label".into(),
2826 XattrOp::Create,
2827 ),
2828 error!(EPERM)
2829 );
2830 })
2831 .await;
2832 }
2833
2834 #[::fuchsia::test]
2835 async fn set_non_user_xattr_fails_without_security_module_or_root() {
2836 spawn_kernel_and_run(async |current_task| {
2837 let mut creds = Credentials::with_ids(1, 2);
2838 creds.groups = vec![3, 4];
2839 current_task.set_creds(creds);
2840
2841 let node = ¤t_task
2843 .fs()
2844 .root()
2845 .create_node(¤t_task, "foo".into(), FileMode::IFREG, DeviceId::NONE)
2846 .expect("create_node")
2847 .entry
2848 .node;
2849
2850 node.update_info(|info| info.mode = mode!(IFREG, 0o777));
2852
2853 assert_eq!(
2856 node.set_xattr(
2857 ¤t_task,
2858 &MountInfo::detached(),
2859 "trusted.name".into(),
2860 "some data".into(),
2861 XattrOp::Create,
2862 ),
2863 error!(EPERM)
2864 );
2865 })
2866 .await;
2867 }
2868
2869 #[::fuchsia::test]
2870 async fn get_security_xattr_succeeds_without_read_access() {
2871 spawn_kernel_and_run(async |current_task| {
2872 let mut creds = Credentials::with_ids(1, 2);
2873 creds.groups = vec![3, 4];
2874 current_task.set_creds(creds);
2875
2876 let node = ¤t_task
2878 .fs()
2879 .root()
2880 .create_node(¤t_task, "foo".into(), FileMode::IFREG, DeviceId::NONE)
2881 .expect("create_node")
2882 .entry
2883 .node;
2884
2885 node.update_info(|info| info.mode = mode!(IFREG, 0o100));
2887 current_task.set_creds(Credentials::with_ids(0, 0));
2888
2889 assert_eq!(
2891 node.set_xattr(
2892 ¤t_task,
2893 &MountInfo::detached(),
2894 "security.name".into(),
2895 "security_label".into(),
2896 XattrOp::Create,
2897 ),
2898 Ok(())
2899 );
2900
2901 current_task.set_creds(Credentials::with_ids(1, 1));
2903
2904 assert_eq!(
2906 node.get_xattr(¤t_task, &MountInfo::detached(), "security.name".into(), 4096),
2907 Ok(ValueOrSize::Value("security_label".into()))
2908 );
2909 })
2910 .await;
2911 }
2912
2913 #[fuchsia::test]
2914 async fn test_casefold_not_supported_by_default() {
2915 spawn_kernel_and_run(async |current_task| {
2916 let node = ¤t_task
2917 .fs()
2918 .root()
2919 .create_node(¤t_task, "foo".into(), FileMode::IFREG, DeviceId::NONE)
2920 .expect("create_node")
2921 .entry
2922 .node;
2923
2924 assert!(!node.ops().has_casefold_support(node));
2925 assert_eq!(
2926 node.update_attributes(¤t_task, |info| {
2927 info.casefold = true;
2928 Ok(())
2929 }),
2930 error!(ENOTSUP)
2931 );
2932 })
2933 .await;
2934 }
2935}