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