1use crate::mm::memory::MemoryObject;
6use crate::mm::{DesiredAddress, MappingName, MappingOptions, MemoryAccessorExt, ProtectionFlags};
7use crate::power::OnWakeOps;
8use crate::security;
9use crate::task::{
10 CurrentTask, EventHandler, Pid, WaitCallback, WaitCanceler, Waiter, register_delayed_release,
11};
12use crate::vfs::buffers::{InputBuffer, OutputBuffer};
13use crate::vfs::file_server::serve_file;
14use crate::vfs::fsverity::{
15 FsVerityState, {self},
16};
17use crate::vfs::{
18 ActiveNamespaceNode, DirentSink, EpollFileObject, EpollKey, FallocMode, FdTableId, FileMapping,
19 FileSystemHandle, FileWriteGuardMode, FsNodeHandle, FsString, NamespaceNode, RecordLockCommand,
20 RecordLockOwner,
21};
22use starnix_crypt::EncryptionKeyId;
23use starnix_lifecycle::{ObjectReleaser, ReleaserAction};
24use starnix_rcu::RcuAtomic;
25use starnix_types::ownership::ReleaseGuard;
26use starnix_uapi::mount_flags::MountFlags;
27use starnix_uapi::user_address::ArchSpecific;
28
29use fidl::endpoints::ProtocolMarker as _;
30use linux_uapi::{FSCRYPT_MODE_AES_256_CTS, FSCRYPT_MODE_AES_256_XTS};
31use starnix_logging::{CATEGORY_STARNIX_MM, impossible_error, log_error, track_stub};
32use starnix_sync::{
33 FileAsyncOwnerLock, FileEpollFilesLock, FileLeaseLock, FileObjectOffset, LockDepMutex,
34};
35use starnix_syscalls::{SUCCESS, SyscallArg, SyscallResult};
36use starnix_types::math::round_up_to_system_page_size;
37use starnix_types::ownership::Releasable;
38use starnix_uapi::arc_key::WeakKey;
39use starnix_uapi::as_any::AsAny;
40use starnix_uapi::auth::{CAP_FOWNER, CAP_SYS_RAWIO};
41use starnix_uapi::errors::{EAGAIN, ETIMEDOUT, Errno};
42use starnix_uapi::file_lease::FileLeaseType;
43use starnix_uapi::file_mode::Access;
44use starnix_uapi::inotify_mask::InotifyMask;
45use starnix_uapi::open_flags::{AtomicOpenFlags, OpenFlags};
46use starnix_uapi::seal_flags::SealFlags;
47use starnix_uapi::user_address::{UserAddress, UserRef};
48use starnix_uapi::vfs::FdEvents;
49use starnix_uapi::{
50 F_OWNER_PGRP, F_OWNER_PID, F_OWNER_TID, FIBMAP, FIGETBSZ, FIONBIO, FIONREAD, FIOQSIZE,
51 FS_CASEFOLD_FL, FS_IOC_ADD_ENCRYPTION_KEY, FS_IOC_ENABLE_VERITY, FS_IOC_FSGETXATTR,
52 FS_IOC_FSSETXATTR, FS_IOC_MEASURE_VERITY, FS_IOC_READ_VERITY_METADATA,
53 FS_IOC_REMOVE_ENCRYPTION_KEY, FS_IOC_SET_ENCRYPTION_POLICY, FS_VERITY_FL,
54 FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER, FSCRYPT_POLICY_V2, SEEK_CUR, SEEK_DATA, SEEK_END, SEEK_HOLE,
55 SEEK_SET, errno, error, fscrypt_add_key_arg, fscrypt_identifier, fsxattr, off_t, pid_t, uapi,
56};
57use std::collections::HashMap;
58use std::fmt;
59use std::ops::Deref;
60use std::sync::atomic::Ordering;
61use std::sync::{Arc, Weak};
62
63pub const MAX_LFS_FILESIZE: usize = 0x7fff_ffff_ffff_ffff;
64
65pub fn checked_add_offset_and_length(offset: usize, length: usize) -> Result<usize, Errno> {
66 let end = offset.checked_add(length).ok_or_else(|| errno!(EINVAL))?;
67 if end > MAX_LFS_FILESIZE {
68 return error!(EINVAL);
69 }
70 Ok(end)
71}
72
73#[derive(Debug)]
74pub enum SeekTarget {
75 Set(off_t),
77 Cur(off_t),
79 End(off_t),
81 Data(off_t),
83 Hole(off_t),
85}
86
87impl SeekTarget {
88 pub fn from_raw(whence: u32, offset: off_t) -> Result<SeekTarget, Errno> {
89 match whence {
90 SEEK_SET => Ok(SeekTarget::Set(offset)),
91 SEEK_CUR => Ok(SeekTarget::Cur(offset)),
92 SEEK_END => Ok(SeekTarget::End(offset)),
93 SEEK_DATA => Ok(SeekTarget::Data(offset)),
94 SEEK_HOLE => Ok(SeekTarget::Hole(offset)),
95 _ => error!(EINVAL),
96 }
97 }
98
99 pub fn whence(&self) -> u32 {
100 match self {
101 Self::Set(_) => SEEK_SET,
102 Self::Cur(_) => SEEK_CUR,
103 Self::End(_) => SEEK_END,
104 Self::Data(_) => SEEK_DATA,
105 Self::Hole(_) => SEEK_HOLE,
106 }
107 }
108
109 pub fn offset(&self) -> off_t {
110 match self {
111 Self::Set(off)
112 | Self::Cur(off)
113 | Self::End(off)
114 | Self::Data(off)
115 | Self::Hole(off) => *off,
116 }
117 }
118}
119
120pub trait FileOps: Send + Sync + AsAny + 'static {
122 fn open(&self, _file: &FileObject, _current_task: &CurrentTask) -> Result<(), Errno> {
124 Ok(())
125 }
126
127 fn close(self: Box<Self>, _file: &FileObjectState, _current_task: &CurrentTask) {}
129
130 fn flush(&self, _file: &FileObject, _current_task: &CurrentTask) {}
133
134 fn has_persistent_offsets(&self) -> bool {
138 self.is_seekable()
139 }
140
141 fn is_seekable(&self) -> bool;
143
144 fn writes_update_seek_offset(&self) -> bool {
146 self.has_persistent_offsets()
147 }
148
149 fn read(
153 &self,
154 file: &FileObject,
155 current_task: &CurrentTask,
156 offset: usize,
157 data: &mut dyn OutputBuffer,
158 ) -> Result<usize, Errno>;
159
160 fn write(
164 &self,
165 file: &FileObject,
166 current_task: &CurrentTask,
167 offset: usize,
168 data: &mut dyn InputBuffer,
169 ) -> Result<usize, Errno>;
170
171 fn seek(
173 &self,
174 file: &FileObject,
175 current_task: &CurrentTask,
176 current_offset: off_t,
177 target: SeekTarget,
178 ) -> Result<off_t, Errno>;
179
180 fn sync(&self, file: &FileObject, current_task: &CurrentTask) -> Result<(), Errno> {
184 file.node().ops().sync(file.node(), current_task)
185 }
186
187 fn data_sync(&self, file: &FileObject, current_task: &CurrentTask) -> Result<(), Errno> {
191 self.sync(file, current_task)
193 }
194
195 fn get_memory(
202 &self,
203 _file: &FileObject,
204 _current_task: &CurrentTask,
205 _length: Option<usize>,
206 _prot: ProtectionFlags,
207 ) -> Result<Arc<MemoryObject>, Errno> {
208 error!(ENODEV)
209 }
210
211 fn mmap(
216 &self,
217 file: &FileObject,
218 current_task: &CurrentTask,
219 addr: DesiredAddress,
220 memory_offset: u64,
221 length: usize,
222 prot_flags: ProtectionFlags,
223 options: MappingOptions,
224 ) -> Result<UserAddress, Errno> {
225 default_mmap(file, current_task, addr, memory_offset, length, prot_flags, options)
226 }
227
228 fn readdir(
233 &self,
234 _file: &FileObject,
235 _current_task: &CurrentTask,
236 _sink: &mut dyn DirentSink,
237 ) -> Result<(), Errno> {
238 error!(ENOTDIR)
239 }
240
241 fn wait_async(
250 &self,
251 _file: &FileObject,
252 _current_task: &CurrentTask,
253 _waiter: &Waiter,
254 _events: FdEvents,
255 _handler: EventHandler,
256 ) -> Option<WaitCanceler> {
257 None
258 }
259
260 fn query_events(
268 &self,
269 _file: &FileObject,
270 _current_task: &CurrentTask,
271 ) -> Result<FdEvents, Errno> {
272 Ok(FdEvents::POLLIN | FdEvents::POLLOUT)
273 }
274
275 fn ioctl(
276 &self,
277 _file: &FileObject,
278 _current_task: &CurrentTask,
279 _request: u32,
280 _arg: SyscallArg,
281 ) -> Result<SyscallResult, Errno> {
282 error!(ENOTTY)
283 }
284
285 fn fcntl(
286 &self,
287 _file: &FileObject,
288 _current_task: &CurrentTask,
289 cmd: u32,
290 _arg: u64,
291 ) -> Result<SyscallResult, Errno> {
292 default_fcntl(cmd)
293 }
294
295 fn to_handle(
299 &self,
300 file: &FileObject,
301 current_task: &CurrentTask,
302 ) -> Result<Option<zx::NullableHandle>, Errno> {
303 serve_file(current_task, file, current_task.current_creds().clone())
304 .map(|c| Some(c.0.into_channel().into()))
305 }
306
307 fn get_handles(
323 &self,
324 _file: &FileObject,
325 _current_task: &CurrentTask,
326 ) -> Result<Vec<zx::NullableHandle>, Errno> {
327 error!(ENOTSUP)
328 }
329
330 fn as_pid(&self, _file: &FileObject) -> Result<Pid, Errno> {
334 error!(EBADF)
335 }
336
337 fn readahead(
338 &self,
339 _file: &FileObject,
340 _current_task: &CurrentTask,
341 _offset: usize,
342 _length: usize,
343 ) -> Result<(), Errno> {
344 error!(EINVAL)
345 }
346
347 fn extra_fdinfo(&self, _file: &FileHandle, _current_task: &CurrentTask) -> Option<FsString> {
349 None
350 }
351}
352
353pub trait CloseFreeSafe {}
356impl<T: FileOps + CloseFreeSafe, P: Deref<Target = T> + Send + Sync + 'static> FileOps for P {
357 fn close(self: Box<Self>, _file: &FileObjectState, _current_task: &CurrentTask) {
358 }
360
361 fn flush(&self, file: &FileObject, current_task: &CurrentTask) {
362 self.deref().flush(file, current_task)
363 }
364
365 fn has_persistent_offsets(&self) -> bool {
366 self.deref().has_persistent_offsets()
367 }
368
369 fn writes_update_seek_offset(&self) -> bool {
370 self.deref().writes_update_seek_offset()
371 }
372
373 fn is_seekable(&self) -> bool {
374 self.deref().is_seekable()
375 }
376
377 fn read(
378 &self,
379 file: &FileObject,
380 current_task: &CurrentTask,
381 offset: usize,
382 data: &mut dyn OutputBuffer,
383 ) -> Result<usize, Errno> {
384 self.deref().read(file, current_task, offset, data)
385 }
386
387 fn write(
388 &self,
389 file: &FileObject,
390 current_task: &CurrentTask,
391 offset: usize,
392 data: &mut dyn InputBuffer,
393 ) -> Result<usize, Errno> {
394 self.deref().write(file, current_task, offset, data)
395 }
396
397 fn seek(
398 &self,
399 file: &FileObject,
400 current_task: &CurrentTask,
401 current_offset: off_t,
402 target: SeekTarget,
403 ) -> Result<off_t, Errno> {
404 self.deref().seek(file, current_task, current_offset, target)
405 }
406
407 fn sync(&self, file: &FileObject, current_task: &CurrentTask) -> Result<(), Errno> {
408 self.deref().sync(file, current_task)
409 }
410
411 fn data_sync(&self, file: &FileObject, current_task: &CurrentTask) -> Result<(), Errno> {
412 self.deref().data_sync(file, current_task)
413 }
414
415 fn get_memory(
416 &self,
417 file: &FileObject,
418 current_task: &CurrentTask,
419 length: Option<usize>,
420 prot: ProtectionFlags,
421 ) -> Result<Arc<MemoryObject>, Errno> {
422 self.deref().get_memory(file, current_task, length, prot)
423 }
424
425 fn mmap(
426 &self,
427 file: &FileObject,
428 current_task: &CurrentTask,
429 addr: DesiredAddress,
430 memory_offset: u64,
431 length: usize,
432 prot_flags: ProtectionFlags,
433 options: MappingOptions,
434 ) -> Result<UserAddress, Errno> {
435 self.deref().mmap(file, current_task, addr, memory_offset, length, prot_flags, options)
436 }
437
438 fn readdir(
439 &self,
440 file: &FileObject,
441 current_task: &CurrentTask,
442 sink: &mut dyn DirentSink,
443 ) -> Result<(), Errno> {
444 self.deref().readdir(file, current_task, sink)
445 }
446
447 fn wait_async(
448 &self,
449 file: &FileObject,
450 current_task: &CurrentTask,
451 waiter: &Waiter,
452 events: FdEvents,
453 handler: EventHandler,
454 ) -> Option<WaitCanceler> {
455 self.deref().wait_async(file, current_task, waiter, events, handler)
456 }
457
458 fn query_events(
459 &self,
460 file: &FileObject,
461 current_task: &CurrentTask,
462 ) -> Result<FdEvents, Errno> {
463 self.deref().query_events(file, current_task)
464 }
465
466 fn ioctl(
467 &self,
468 file: &FileObject,
469 current_task: &CurrentTask,
470 request: u32,
471 arg: SyscallArg,
472 ) -> Result<SyscallResult, Errno> {
473 self.deref().ioctl(file, current_task, request, arg)
474 }
475
476 fn fcntl(
477 &self,
478 file: &FileObject,
479 current_task: &CurrentTask,
480 cmd: u32,
481 arg: u64,
482 ) -> Result<SyscallResult, Errno> {
483 self.deref().fcntl(file, current_task, cmd, arg)
484 }
485
486 fn to_handle(
487 &self,
488 file: &FileObject,
489 current_task: &CurrentTask,
490 ) -> Result<Option<zx::NullableHandle>, Errno> {
491 self.deref().to_handle(file, current_task)
492 }
493
494 fn get_handles(
495 &self,
496 file: &FileObject,
497 current_task: &CurrentTask,
498 ) -> Result<Vec<zx::NullableHandle>, Errno> {
499 self.deref().get_handles(file, current_task)
500 }
501
502 fn as_pid(&self, file: &FileObject) -> Result<Pid, Errno> {
503 self.deref().as_pid(file)
504 }
505
506 fn readahead(
507 &self,
508 file: &FileObject,
509 current_task: &CurrentTask,
510 offset: usize,
511 length: usize,
512 ) -> Result<(), Errno> {
513 self.deref().readahead(file, current_task, offset, length)
514 }
515
516 fn extra_fdinfo(&self, file: &FileHandle, current_task: &CurrentTask) -> Option<FsString> {
517 self.deref().extra_fdinfo(file, current_task)
518 }
519}
520
521pub fn default_eof_offset(file: &FileObject, current_task: &CurrentTask) -> Result<off_t, Errno> {
522 Ok(file.node().get_size(current_task)? as off_t)
523}
524
525pub fn default_seek<F>(
535 current_offset: off_t,
536 target: SeekTarget,
537 compute_end: F,
538) -> Result<off_t, Errno>
539where
540 F: FnOnce() -> Result<off_t, Errno>,
541{
542 let new_offset = match target {
543 SeekTarget::Set(offset) => Some(offset),
544 SeekTarget::Cur(offset) => current_offset.checked_add(offset),
545 SeekTarget::End(offset) => compute_end()?.checked_add(offset),
546 SeekTarget::Data(offset) => {
547 let eof = compute_end().unwrap_or(off_t::MAX);
548 if offset >= eof {
549 return error!(ENXIO);
550 }
551 Some(offset)
552 }
553 SeekTarget::Hole(offset) => {
554 let eof = compute_end()?;
555 if offset >= eof {
556 return error!(ENXIO);
557 }
558 Some(eof)
559 }
560 }
561 .ok_or_else(|| errno!(EINVAL))?;
562
563 if new_offset < 0 {
564 return error!(EINVAL);
565 }
566
567 Ok(new_offset)
568}
569
570pub fn unbounded_seek(current_offset: off_t, target: SeekTarget) -> Result<off_t, Errno> {
579 default_seek(current_offset, target, || Ok(MAX_LFS_FILESIZE as off_t))
580}
581
582#[macro_export]
583macro_rules! fileops_impl_delegate_read_write_and_seek {
584 ($self:ident, $delegate:expr) => {
585 fn is_seekable(&self) -> bool {
586 true
587 }
588
589 fn read(
590 &$self,
591 file: &FileObject,
592 current_task: &$crate::task::CurrentTask,
593 offset: usize,
594 data: &mut dyn $crate::vfs::buffers::OutputBuffer,
595 ) -> Result<usize, starnix_uapi::errors::Errno> {
596 $delegate.read(file, current_task, offset, data)
597 }
598
599 fn write(
600 &$self,
601 file: &FileObject,
602 current_task: &$crate::task::CurrentTask,
603 offset: usize,
604 data: &mut dyn $crate::vfs::buffers::InputBuffer,
605 ) -> Result<usize, starnix_uapi::errors::Errno> {
606 $delegate.write(file, current_task, offset, data)
607 }
608
609 fn seek(
610 &$self,
611 file: &FileObject,
612 current_task: &$crate::task::CurrentTask,
613 current_offset: starnix_uapi::off_t,
614 target: $crate::vfs::SeekTarget,
615 ) -> Result<starnix_uapi::off_t, starnix_uapi::errors::Errno> {
616 $delegate.seek(file, current_task, current_offset, target)
617 }
618 };
619}
620
621#[macro_export]
623macro_rules! fileops_impl_seekable {
624 () => {
625 fn is_seekable(&self) -> bool {
626 true
627 }
628
629 fn seek(
630 &self,
631 file: &$crate::vfs::FileObject,
632 current_task: &$crate::task::CurrentTask,
633 current_offset: starnix_uapi::off_t,
634 target: $crate::vfs::SeekTarget,
635 ) -> Result<starnix_uapi::off_t, starnix_uapi::errors::Errno> {
636 $crate::vfs::default_seek(current_offset, target, || {
637 $crate::vfs::default_eof_offset(file, current_task)
638 })
639 }
640 };
641}
642
643#[macro_export]
645macro_rules! fileops_impl_nonseekable {
646 () => {
647 fn is_seekable(&self) -> bool {
648 false
649 }
650
651 fn seek(
652 &self,
653 _file: &$crate::vfs::FileObject,
654 _current_task: &$crate::task::CurrentTask,
655 _current_offset: starnix_uapi::off_t,
656 _target: $crate::vfs::SeekTarget,
657 ) -> Result<starnix_uapi::off_t, starnix_uapi::errors::Errno> {
658 starnix_uapi::error!(ESPIPE)
659 }
660 };
661}
662
663#[macro_export]
666macro_rules! fileops_impl_seekless {
667 () => {
668 fn has_persistent_offsets(&self) -> bool {
669 false
670 }
671
672 fn is_seekable(&self) -> bool {
673 true
674 }
675
676 fn seek(
677 &self,
678 _file: &$crate::vfs::FileObject,
679 _current_task: &$crate::task::CurrentTask,
680 _current_offset: starnix_uapi::off_t,
681 _target: $crate::vfs::SeekTarget,
682 ) -> Result<starnix_uapi::off_t, starnix_uapi::errors::Errno> {
683 Ok(0)
684 }
685 };
686}
687
688#[macro_export]
689macro_rules! fileops_impl_dataless {
690 () => {
691 fn write(
692 &self,
693 _file: &$crate::vfs::FileObject,
694 _current_task: &$crate::task::CurrentTask,
695 _offset: usize,
696 _data: &mut dyn $crate::vfs::buffers::InputBuffer,
697 ) -> Result<usize, starnix_uapi::errors::Errno> {
698 starnix_uapi::error!(EINVAL)
699 }
700
701 fn read(
702 &self,
703 _file: &$crate::vfs::FileObject,
704 _current_task: &$crate::task::CurrentTask,
705 _offset: usize,
706 _data: &mut dyn $crate::vfs::buffers::OutputBuffer,
707 ) -> Result<usize, starnix_uapi::errors::Errno> {
708 starnix_uapi::error!(EINVAL)
709 }
710 };
711}
712
713#[macro_export]
716macro_rules! fileops_impl_directory {
717 () => {
718 fn is_seekable(&self) -> bool {
719 true
720 }
721
722 fn read(
723 &self,
724 _file: &$crate::vfs::FileObject,
725 _current_task: &$crate::task::CurrentTask,
726 _offset: usize,
727 _data: &mut dyn $crate::vfs::buffers::OutputBuffer,
728 ) -> Result<usize, starnix_uapi::errors::Errno> {
729 starnix_uapi::error!(EISDIR)
730 }
731
732 fn write(
733 &self,
734 _file: &$crate::vfs::FileObject,
735 _current_task: &$crate::task::CurrentTask,
736 _offset: usize,
737 _data: &mut dyn $crate::vfs::buffers::InputBuffer,
738 ) -> Result<usize, starnix_uapi::errors::Errno> {
739 starnix_uapi::error!(EISDIR)
740 }
741 };
742}
743
744#[macro_export]
745macro_rules! fileops_impl_unbounded_seek {
746 () => {
747 fn seek(
748 &self,
749 _file: &$crate::vfs::FileObject,
750 _current_task: &$crate::task::CurrentTask,
751 current_offset: starnix_uapi::off_t,
752 target: $crate::vfs::SeekTarget,
753 ) -> Result<starnix_uapi::off_t, starnix_uapi::errors::Errno> {
754 $crate::vfs::unbounded_seek(current_offset, target)
755 }
756 };
757}
758
759#[macro_export]
760macro_rules! fileops_impl_noop_sync {
761 () => {
762 fn sync(
763 &self,
764 file: &$crate::vfs::FileObject,
765 _current_task: &$crate::task::CurrentTask,
766 ) -> Result<(), starnix_uapi::errors::Errno> {
767 if !file.node().is_reg() && !file.node().is_dir() {
768 return starnix_uapi::error!(EINVAL);
769 }
770 Ok(())
771 }
772 };
773}
774
775pub use fileops_impl_dataless;
778pub use fileops_impl_delegate_read_write_and_seek;
779pub use fileops_impl_directory;
780pub use fileops_impl_nonseekable;
781pub use fileops_impl_noop_sync;
782pub use fileops_impl_seekable;
783pub use fileops_impl_seekless;
784pub use fileops_impl_unbounded_seek;
785pub const AES256_KEY_SIZE: usize = 32;
786
787pub fn canonicalize_ioctl_request(current_task: &CurrentTask, request: u32) -> u32 {
788 if current_task.is_arch32() {
789 match request {
790 uapi::arch32::FS_IOC_GETFLAGS => uapi::FS_IOC_GETFLAGS,
791 uapi::arch32::FS_IOC_SETFLAGS => uapi::FS_IOC_SETFLAGS,
792 _ => request,
793 }
794 } else {
795 request
796 }
797}
798
799pub fn default_vfs_ioctl(
807 file: &FileObject,
808 current_task: &CurrentTask,
809 request: u32,
810 arg: SyscallArg,
811) -> Result<Option<SyscallResult>, Errno> {
812 match canonicalize_ioctl_request(current_task, request) {
813 FIGETBSZ if file.node().is_reg() || file.node().is_dir() => {
814 let blocksize = file.node().stat(current_task)?.st_blksize;
815 current_task.write_object(arg.into(), &blocksize)?;
816 Ok(Some(SUCCESS))
817 }
818 FIONBIO => {
819 let arg_ref = UserAddress::from(arg).into();
820 let arg: i32 = current_task.read_object(arg_ref)?;
821 let val = if arg == 0 {
822 OpenFlags::empty()
824 } else {
825 OpenFlags::NONBLOCK
827 };
828 file.update_file_flags(val, OpenFlags::NONBLOCK);
829 Ok(Some(SUCCESS))
830 }
831 FIOQSIZE if file.node().is_reg() || file.node().is_dir() => {
832 let size = file.node().stat(current_task)?.st_size;
833 current_task.write_object(arg.into(), &size)?;
834 Ok(Some(SUCCESS))
835 }
836 FIONREAD if file.node().is_reg() => {
837 track_stub!(TODO("https://fxbug.dev/322874897"), "FIONREAD");
838 let size =
839 file.node().fetch_and_refresh_info(current_task).map_err(|_| errno!(EINVAL))?.size;
840 let offset = usize::try_from(file.offset.read()).map_err(|_| errno!(EINVAL))?;
841 let remaining =
842 if size < offset { 0 } else { i32::try_from(size - offset).unwrap_or(i32::MAX) };
843 current_task.write_object(arg.into(), &remaining)?;
844 Ok(Some(SUCCESS))
845 }
846 FS_IOC_FSGETXATTR => {
847 track_stub!(TODO("https://fxbug.dev/322875209"), "FS_IOC_FSGETXATTR");
848 let arg = UserAddress::from(arg).into();
849 current_task.write_object(arg, &fsxattr::default())?;
850 Ok(Some(SUCCESS))
851 }
852 FS_IOC_FSSETXATTR => {
853 track_stub!(TODO("https://fxbug.dev/322875271"), "FS_IOC_FSSETXATTR");
854 let arg = UserAddress::from(arg).into();
855 let _: fsxattr = current_task.read_object(arg)?;
856 Ok(Some(SUCCESS))
857 }
858 uapi::FS_IOC_GETFLAGS => {
859 track_stub!(TODO("https://fxbug.dev/322874935"), "FS_IOC_GETFLAGS");
860 let arg = UserRef::<u32>::from(arg);
861 let mut flags: u32 = 0;
862 if matches!(*file.node().fsverity.lock(), FsVerityState::FsVerity) {
863 flags |= FS_VERITY_FL;
864 }
865 if file.node().info().casefold {
866 flags |= FS_CASEFOLD_FL;
867 }
868 current_task.write_object(arg, &flags)?;
869 Ok(Some(SUCCESS))
870 }
871 uapi::FS_IOC_SETFLAGS => {
872 track_stub!(TODO("https://fxbug.dev/322875367"), "FS_IOC_SETFLAGS");
873 file.name.mount.check_readonly_filesystem()?;
877 let arg = UserRef::<u32>::from(arg);
878 let flags: u32 = current_task.read_object(arg)?;
879 let new_casefold = flags & FS_CASEFOLD_FL != 0;
880 file.name.entry.set_casefold(current_task, new_casefold)?;
881
882 Ok(Some(SUCCESS))
883 }
884 FS_IOC_ENABLE_VERITY => {
885 fsverity::ioctl::enable(current_task, UserAddress::from(arg).into(), file).map(Some)
886 }
887 FS_IOC_MEASURE_VERITY => {
888 fsverity::ioctl::measure(current_task, UserAddress::from(arg).into(), file).map(Some)
889 }
890 FS_IOC_READ_VERITY_METADATA => {
891 fsverity::ioctl::read_metadata(current_task, UserAddress::from(arg).into(), file)
892 .map(Some)
893 }
894 FS_IOC_ADD_ENCRYPTION_KEY => {
895 let fscrypt_add_key_ref = UserRef::<fscrypt_add_key_arg>::from(arg);
896 let key_ref_addr = fscrypt_add_key_ref.next()?.addr();
897 let mut fscrypt_add_key_arg = current_task.read_object(fscrypt_add_key_ref.clone())?;
898 if fscrypt_add_key_arg.key_id != 0 {
899 track_stub!(TODO("https://fxbug.dev/375649227"), "non-zero key ids");
900 return error!(ENOTSUP);
901 }
902 if fscrypt_add_key_arg.key_spec.type_ != FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER {
903 track_stub!(TODO("https://fxbug.dev/375648306"), "fscrypt descriptor type");
904 return error!(ENOTSUP);
905 }
906 let key = current_task
907 .read_memory_to_vec(key_ref_addr, fscrypt_add_key_arg.raw_size as usize)?;
908 let user_id = current_task.current_creds().uid;
909
910 let crypt_service = file.node().fs().crypt_service().ok_or_else(|| errno!(ENOTSUP))?;
911 let key_identifier = crypt_service.add_wrapping_key(&key, user_id)?;
912 fscrypt_add_key_arg.key_spec.u.identifier =
913 fscrypt_identifier { value: key_identifier, ..Default::default() };
914 current_task.write_object(fscrypt_add_key_ref, &fscrypt_add_key_arg)?;
915 Ok(Some(SUCCESS))
916 }
917 FS_IOC_SET_ENCRYPTION_POLICY => {
918 let fscrypt_policy_ref = UserRef::<uapi::fscrypt_policy_v2>::from(arg);
919 let policy = current_task.read_object(fscrypt_policy_ref)?;
920 if policy.version as u32 != FSCRYPT_POLICY_V2 {
921 track_stub!(TODO("https://fxbug.dev/375649656"), "fscrypt policy v1");
922 return error!(ENOTSUP);
923 }
924 if policy.flags != 0 {
925 track_stub!(
926 TODO("https://fxbug.dev/375700939"),
927 "fscrypt policy flags",
928 policy.flags
929 );
930 }
931 if policy.contents_encryption_mode as u32 != FSCRYPT_MODE_AES_256_XTS {
932 track_stub!(
933 TODO("https://fxbug.dev/375684057"),
934 "fscrypt encryption modes",
935 policy.contents_encryption_mode
936 );
937 }
938 if policy.filenames_encryption_mode as u32 != FSCRYPT_MODE_AES_256_CTS {
939 track_stub!(
940 TODO("https://fxbug.dev/375684057"),
941 "fscrypt encryption modes",
942 policy.filenames_encryption_mode
943 );
944 }
945 let user_id = current_task.current_creds().uid;
946 if user_id != file.node().info().uid {
947 security::check_task_capable(current_task, CAP_FOWNER)
948 .map_err(|_| errno!(EACCES))?;
949 }
950
951 let crypt_service = file.node().fs().crypt_service().ok_or_else(|| errno!(ENOTSUP))?;
952 if let Some(users) =
953 crypt_service.get_users_for_key(EncryptionKeyId::from(policy.master_key_identifier))
954 {
955 if !users.contains(&user_id) {
956 return error!(ENOKEY);
957 }
958 } else {
959 track_stub!(
960 TODO("https://fxbug.dev/375067633"),
961 "users with CAP_FOWNER can set encryption policies with unadded keys"
962 );
963 return error!(ENOKEY);
964 }
965
966 let attributes = file.node().fetch_and_refresh_info(current_task)?;
967 if let Some(wrapping_key_id) = &attributes.wrapping_key_id {
968 if wrapping_key_id != &policy.master_key_identifier {
969 return error!(EEXIST);
970 }
971 } else {
972 std::mem::drop(attributes);
974 file.node().update_attributes(current_task, |info| {
975 info.wrapping_key_id = Some(policy.master_key_identifier);
976 Ok(())
977 })?;
978 }
979 Ok(Some(SUCCESS))
980 }
981 FS_IOC_REMOVE_ENCRYPTION_KEY => {
982 let fscrypt_remove_key_arg_ref = UserRef::<uapi::fscrypt_remove_key_arg>::from(arg);
983 let fscrypt_remove_key_arg = current_task.read_object(fscrypt_remove_key_arg_ref)?;
984 if fscrypt_remove_key_arg.key_spec.type_ != FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER {
985 track_stub!(TODO("https://fxbug.dev/375648306"), "fscrypt descriptor type");
986 return error!(ENOTSUP);
987 }
988 let crypt_service = file.node().fs().crypt_service().ok_or_else(|| errno!(ENOTSUP))?;
989 let user_id = current_task.current_creds().uid;
990 #[allow(
991 clippy::undocumented_unsafe_blocks,
992 reason = "Force documented unsafe blocks in Starnix"
993 )]
994 let identifier = unsafe { fscrypt_remove_key_arg.key_spec.u.identifier.value };
995 crypt_service.forget_wrapping_key(identifier, user_id)?;
996 Ok(Some(SUCCESS))
997 }
998 linux_uapi::FICLONE | linux_uapi::FICLONERANGE | linux_uapi::FIDEDUPERANGE => {
999 error!(EOPNOTSUPP)
1000 }
1001 _ => Ok(None),
1002 }
1003}
1004
1005pub fn default_fcntl(cmd: u32) -> Result<SyscallResult, Errno> {
1006 track_stub!(TODO("https://fxbug.dev/322875704"), "default fcntl", cmd);
1007 error!(EINVAL)
1008}
1009
1010pub fn default_mmap(
1011 file: &FileObject,
1012 current_task: &CurrentTask,
1013 addr: DesiredAddress,
1014 memory_offset: u64,
1015 length: usize,
1016 prot_flags: ProtectionFlags,
1017 options: MappingOptions,
1018) -> Result<UserAddress, Errno> {
1019 fuchsia_trace::duration!(CATEGORY_STARNIX_MM, "FileOpsDefaultMmap");
1020 let min_memory_size = (memory_offset as usize)
1021 .checked_add(round_up_to_system_page_size(length)?)
1022 .ok_or_else(|| errno!(EINVAL))?;
1023 let mut memory = if options.contains(MappingOptions::SHARED) {
1024 fuchsia_trace::duration!(CATEGORY_STARNIX_MM, "GetSharedVmo");
1025 file.ops.get_memory(file, current_task, Some(min_memory_size), prot_flags)?
1026 } else {
1027 fuchsia_trace::duration!(CATEGORY_STARNIX_MM, "GetPrivateVmo");
1028 let base_prot_flags = (prot_flags | ProtectionFlags::READ) - ProtectionFlags::WRITE;
1030 let memory =
1031 file.ops.get_memory(file, current_task, Some(min_memory_size), base_prot_flags)?;
1032 let mut clone_flags = zx::VmoChildOptions::SNAPSHOT_AT_LEAST_ON_WRITE;
1033 if !prot_flags.contains(ProtectionFlags::WRITE) {
1034 clone_flags |= zx::VmoChildOptions::NO_WRITE;
1035 }
1036 fuchsia_trace::duration!(CATEGORY_STARNIX_MM, "CreatePrivateChildVmo");
1037 Arc::new(memory.create_child(clone_flags, 0, memory.get_size()).map_err(impossible_error)?)
1038 };
1039
1040 let file_write_guard = if options.contains(MappingOptions::SHARED) && file.can_write() {
1043 let node = &file.name.entry.node;
1044 let state = node.write_guard_state.lock();
1045
1046 let seals = state.get_seals().unwrap_or(SealFlags::empty());
1051 if seals.contains(SealFlags::FUTURE_WRITE)
1052 && !seals.contains(SealFlags::WRITE)
1053 && !prot_flags.contains(ProtectionFlags::WRITE)
1054 {
1055 let mut new_rights = zx::Rights::VMO_DEFAULT - zx::Rights::WRITE;
1056 if prot_flags.contains(ProtectionFlags::EXEC) {
1057 new_rights |= zx::Rights::EXECUTE;
1058 }
1059 memory = Arc::new(memory.duplicate_handle(new_rights).map_err(impossible_error)?);
1060
1061 None
1062 } else {
1063 Some(FileWriteGuardMode::WriteMapping)
1064 }
1065 } else {
1066 None
1067 };
1068
1069 current_task.mm()?.map_memory(
1070 addr,
1071 memory,
1072 memory_offset,
1073 length,
1074 prot_flags,
1075 options,
1076 MappingName::File(file.to_mapping(file_write_guard)?),
1077 )
1078}
1079
1080pub struct OPathOps {}
1081
1082impl OPathOps {
1083 pub fn new() -> OPathOps {
1084 OPathOps {}
1085 }
1086}
1087
1088impl FileOps for OPathOps {
1089 fileops_impl_noop_sync!();
1090
1091 fn has_persistent_offsets(&self) -> bool {
1092 false
1093 }
1094 fn is_seekable(&self) -> bool {
1095 true
1096 }
1097 fn read(
1098 &self,
1099 _file: &FileObject,
1100 _current_task: &CurrentTask,
1101 _offset: usize,
1102 _data: &mut dyn OutputBuffer,
1103 ) -> Result<usize, Errno> {
1104 error!(EBADF)
1105 }
1106 fn write(
1107 &self,
1108 _file: &FileObject,
1109 _current_task: &CurrentTask,
1110 _offset: usize,
1111 _data: &mut dyn InputBuffer,
1112 ) -> Result<usize, Errno> {
1113 error!(EBADF)
1114 }
1115 fn seek(
1116 &self,
1117 _file: &FileObject,
1118 _current_task: &CurrentTask,
1119 _current_offset: off_t,
1120 _target: SeekTarget,
1121 ) -> Result<off_t, Errno> {
1122 error!(EBADF)
1123 }
1124 fn get_memory(
1125 &self,
1126 _file: &FileObject,
1127 _current_task: &CurrentTask,
1128 _length: Option<usize>,
1129 _prot: ProtectionFlags,
1130 ) -> Result<Arc<MemoryObject>, Errno> {
1131 error!(EBADF)
1132 }
1133 fn readdir(
1134 &self,
1135 _file: &FileObject,
1136 _current_task: &CurrentTask,
1137 _sink: &mut dyn DirentSink,
1138 ) -> Result<(), Errno> {
1139 error!(EBADF)
1140 }
1141
1142 fn ioctl(
1143 &self,
1144 _file: &FileObject,
1145 _current_task: &CurrentTask,
1146 _request: u32,
1147 _arg: SyscallArg,
1148 ) -> Result<SyscallResult, Errno> {
1149 error!(EBADF)
1150 }
1151}
1152
1153pub struct ProxyFileOps(pub FileHandle);
1154
1155impl FileOps for ProxyFileOps {
1156 fn has_persistent_offsets(&self) -> bool {
1161 self.0.ops().has_persistent_offsets()
1162 }
1163 fn writes_update_seek_offset(&self) -> bool {
1164 self.0.ops().writes_update_seek_offset()
1165 }
1166 fn is_seekable(&self) -> bool {
1167 self.0.ops().is_seekable()
1168 }
1169 fn flush(&self, _file: &FileObject, current_task: &CurrentTask) {
1170 self.0.ops().flush(&self.0, current_task);
1171 }
1172 fn wait_async(
1173 &self,
1174 _file: &FileObject,
1175 current_task: &CurrentTask,
1176 waiter: &Waiter,
1177 events: FdEvents,
1178 handler: EventHandler,
1179 ) -> Option<WaitCanceler> {
1180 self.0.ops().wait_async(&self.0, current_task, waiter, events, handler)
1181 }
1182 fn query_events(
1183 &self,
1184 _file: &FileObject,
1185 current_task: &CurrentTask,
1186 ) -> Result<FdEvents, Errno> {
1187 self.0.ops().query_events(&self.0, current_task)
1188 }
1189 fn read(
1190 &self,
1191 _file: &FileObject,
1192 current_task: &CurrentTask,
1193 offset: usize,
1194 data: &mut dyn OutputBuffer,
1195 ) -> Result<usize, Errno> {
1196 self.0.ops().read(&self.0, current_task, offset, data)
1197 }
1198 fn write(
1199 &self,
1200 _file: &FileObject,
1201 current_task: &CurrentTask,
1202 offset: usize,
1203 data: &mut dyn InputBuffer,
1204 ) -> Result<usize, Errno> {
1205 self.0.ops().write(&self.0, current_task, offset, data)
1206 }
1207 fn ioctl(
1208 &self,
1209 _file: &FileObject,
1210 current_task: &CurrentTask,
1211 request: u32,
1212 arg: SyscallArg,
1213 ) -> Result<SyscallResult, Errno> {
1214 self.0.ops().ioctl(&self.0, current_task, request, arg)
1215 }
1216 fn fcntl(
1217 &self,
1218 _file: &FileObject,
1219 current_task: &CurrentTask,
1220 cmd: u32,
1221 arg: u64,
1222 ) -> Result<SyscallResult, Errno> {
1223 self.0.ops().fcntl(&self.0, current_task, cmd, arg)
1224 }
1225 fn readdir(
1226 &self,
1227 _file: &FileObject,
1228 current_task: &CurrentTask,
1229 sink: &mut dyn DirentSink,
1230 ) -> Result<(), Errno> {
1231 self.0.ops().readdir(&self.0, current_task, sink)
1232 }
1233 fn sync(&self, _file: &FileObject, current_task: &CurrentTask) -> Result<(), Errno> {
1234 self.0.ops().sync(&self.0, current_task)
1235 }
1236 fn data_sync(&self, _file: &FileObject, current_task: &CurrentTask) -> Result<(), Errno> {
1237 self.0.ops().sync(&self.0, current_task)
1238 }
1239 fn get_memory(
1240 &self,
1241 _file: &FileObject,
1242 current_task: &CurrentTask,
1243 length: Option<usize>,
1244 prot: ProtectionFlags,
1245 ) -> Result<Arc<MemoryObject>, Errno> {
1246 self.0.ops.get_memory(&self.0, current_task, length, prot)
1247 }
1248 fn mmap(
1249 &self,
1250 _file: &FileObject,
1251 current_task: &CurrentTask,
1252 addr: DesiredAddress,
1253 memory_offset: u64,
1254 length: usize,
1255 prot_flags: ProtectionFlags,
1256 options: MappingOptions,
1257 ) -> Result<UserAddress, Errno> {
1258 self.0.ops.mmap(&self.0, current_task, addr, memory_offset, length, prot_flags, options)
1259 }
1260 fn seek(
1261 &self,
1262 _file: &FileObject,
1263 current_task: &CurrentTask,
1264 offset: off_t,
1265 target: SeekTarget,
1266 ) -> Result<off_t, Errno> {
1267 self.0.ops.seek(&self.0, current_task, offset, target)
1268 }
1269}
1270
1271#[derive(Debug, Default, Clone, PartialEq, Eq)]
1272pub enum FileAsyncOwner {
1273 #[default]
1274 Unowned,
1275 Thread(Option<Pid>),
1276 Process(Option<Pid>),
1277 ProcessGroup(Option<Pid>),
1278}
1279
1280impl FileAsyncOwner {
1281 pub fn new(current_task: &CurrentTask, pid: pid_t) -> Result<Self, Errno> {
1282 if pid == 0 {
1283 Ok(Self::Unowned)
1284 } else if pid > 0 {
1285 let entry = current_task.kernel().pids.get(pid)?;
1286 entry.get_task()?;
1287 Ok(Self::Process(Some(entry)))
1288 } else {
1289 let pgid = pid.checked_neg().ok_or_else(|| errno!(EINVAL))?;
1290 let entry = current_task.kernel().pids.get(pgid)?;
1291 entry.get_process_group()?;
1292 Ok(Self::ProcessGroup(Some(entry)))
1293 }
1294 }
1295
1296 pub fn new_ex(
1297 current_task: &CurrentTask,
1298 requested_owner: uapi::f_owner_ex,
1299 ) -> Result<Self, Errno> {
1300 let pids = ¤t_task.kernel().pids;
1301 let get_pid = |lookup_pg: bool| -> Result<Option<Pid>, Errno> {
1302 if requested_owner.pid == 0 {
1303 Ok(None)
1304 } else {
1305 let entry = pids.get(requested_owner.pid)?;
1306 if lookup_pg {
1307 entry.get_process_group()?;
1308 } else {
1309 entry.get_task()?;
1310 }
1311 Ok(Some(entry))
1312 }
1313 };
1314 match requested_owner.type_ as u32 {
1315 F_OWNER_TID => Ok(Self::Thread(get_pid(false)?)),
1316 F_OWNER_PID => Ok(Self::Process(get_pid(false)?)),
1317 F_OWNER_PGRP => Ok(Self::ProcessGroup(get_pid(true)?)),
1318 _ => error!(EINVAL),
1319 }
1320 }
1321
1322 pub fn get_owner(&self) -> pid_t {
1323 match self {
1324 Self::Unowned | Self::Thread(None) | Self::Process(None) | Self::ProcessGroup(None) => {
1325 0
1326 }
1327 Self::Thread(Some(pid)) | Self::Process(Some(pid)) => pid.id,
1328 Self::ProcessGroup(Some(pid)) => -pid.id,
1329 }
1330 }
1331
1332 pub fn get_owner_ex(&self) -> uapi::f_owner_ex {
1333 match self {
1334 Self::Unowned => uapi::f_owner_ex { type_: F_OWNER_TID as i32, pid: 0 },
1335 Self::Thread(pid) => uapi::f_owner_ex {
1336 type_: F_OWNER_TID as i32,
1337 pid: pid.as_ref().map_or(0, |p| p.id),
1338 },
1339 Self::Process(pid) => uapi::f_owner_ex {
1340 type_: F_OWNER_PID as i32,
1341 pid: pid.as_ref().map_or(0, |p| p.id),
1342 },
1343 Self::ProcessGroup(pid) => uapi::f_owner_ex {
1344 type_: F_OWNER_PGRP as i32,
1345 pid: pid.as_ref().map_or(0, |p| p.id),
1346 },
1347 }
1348 }
1349}
1350
1351#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
1352pub struct FileObjectId(u64);
1353
1354impl FileObjectId {
1355 pub fn as_epoll_key(&self) -> EpollKey {
1356 self.0 as EpollKey
1357 }
1358}
1359
1360pub struct FileObject {
1367 ops: Box<dyn FileOps>,
1368 state: FileObjectState,
1369}
1370
1371impl std::ops::Deref for FileObject {
1372 type Target = FileObjectState;
1373 fn deref(&self) -> &Self::Target {
1374 &self.state
1375 }
1376}
1377
1378pub struct FileObjectState {
1379 pub weak_handle: WeakFileHandle,
1382
1383 pub id: FileObjectId,
1385
1386 pub name: ActiveNamespaceNode,
1390
1391 pub fs: FileSystemHandle,
1392
1393 pub offset: RcuAtomic<off_t, FileObjectOffset>,
1394
1395 flags: AtomicOpenFlags,
1396
1397 async_owner: LockDepMutex<FileAsyncOwner, FileAsyncOwnerLock>,
1398
1399 epoll_files: LockDepMutex<HashMap<FileHandleKey, WeakFileHandle>, FileEpollFilesLock>,
1402
1403 lease: LockDepMutex<FileLeaseType, FileLeaseLock>,
1405
1406 _mysterious_node: Option<FsNodeHandle>,
1409
1410 pub security_state: security::FileObjectState,
1412}
1413
1414pub enum FileObjectReleaserAction {}
1415impl ReleaserAction<FileObject> for FileObjectReleaserAction {
1416 fn release(file_object: ReleaseGuard<FileObject>) {
1417 register_delayed_release(file_object);
1418 }
1419}
1420pub type FileReleaser = ObjectReleaser<FileObject, FileObjectReleaserAction>;
1421pub type FileHandle = Arc<FileReleaser>;
1422pub type WeakFileHandle = Weak<FileReleaser>;
1423pub type FileHandleKey = WeakKey<FileReleaser>;
1424
1425impl FileObjectState {
1426 pub fn node(&self) -> &FsNodeHandle {
1428 &self.name.entry.node
1429 }
1430
1431 pub fn flags(&self) -> OpenFlags {
1432 self.flags.load(Ordering::Relaxed)
1433 }
1434
1435 pub fn can_read(&self) -> bool {
1436 self.flags.load(Ordering::Relaxed).can_read()
1437 }
1438
1439 pub fn can_write(&self) -> bool {
1440 self.flags.load(Ordering::Relaxed).can_write()
1441 }
1442
1443 pub fn can_exec(&self) -> bool {
1445 let mounted_no_exec = self.name.to_passive().mount.flags().contains(MountFlags::NOEXEC);
1446 let no_exec_seal = self
1447 .node()
1448 .write_guard_state
1449 .lock()
1450 .get_seals()
1451 .map(|seals| seals.contains(SealFlags::NO_EXEC))
1452 .unwrap_or(false);
1453 !(mounted_no_exec || no_exec_seal)
1454 }
1455
1456 pub fn notify(&self, event_mask: InotifyMask) {
1458 self.name.notify(event_mask)
1459 }
1460}
1461
1462impl FileObject {
1463 pub fn new_anonymous(
1471 current_task: &CurrentTask,
1472 ops: Box<dyn FileOps>,
1473 node: FsNodeHandle,
1474 flags: OpenFlags,
1475 ) -> FileHandle {
1476 assert!(!node.fs().has_permanent_entries());
1477 Self::new(
1478 current_task,
1479 ops,
1480 NamespaceNode::new_anonymous_unrooted(current_task, node),
1481 flags,
1482 )
1483 .expect("Failed to create anonymous FileObject")
1484 }
1485
1486 pub fn new(
1491 current_task: &CurrentTask,
1492 ops: Box<dyn FileOps>,
1493 name: NamespaceNode,
1494 flags: OpenFlags,
1495 ) -> Result<FileHandle, Errno> {
1496 let _mysterious_node = if flags.can_write() {
1497 name.entry.node.write_guard_state.lock().acquire(FileWriteGuardMode::WriteFile)?;
1498 Some(name.entry.node.clone())
1499 } else {
1500 None
1501 };
1502 let fs = name.entry.node.fs();
1503 let id = FileObjectId(current_task.kernel.next_file_object_id.next());
1504 let security_state = security::file_alloc_security(current_task);
1505 let file = FileHandle::new_cyclic(|weak_handle| {
1506 Self {
1507 ops,
1508 state: FileObjectState {
1509 weak_handle: weak_handle.clone(),
1510 id,
1511 name: name.into_active(),
1512 fs,
1513 offset: RcuAtomic::new(0),
1514 flags: AtomicOpenFlags::new(flags - OpenFlags::CREAT),
1515 async_owner: Default::default(),
1516 epoll_files: Default::default(),
1517 lease: Default::default(),
1518 _mysterious_node,
1519 security_state,
1520 },
1521 }
1522 .into()
1523 });
1524 file.notify(InotifyMask::OPEN);
1525
1526 file.ops().open(&file, current_task)?;
1527 Ok(file)
1528 }
1529
1530 pub fn max_access_for_memory_mapping(&self) -> Access {
1531 let mut access = Access::EXIST;
1532 if self.can_exec() {
1533 access |= Access::EXEC;
1534 }
1535 let flags = self.flags.load(Ordering::Relaxed);
1536 if flags.can_read() {
1537 access |= Access::READ;
1538 }
1539 if flags.can_write() {
1540 access |= Access::WRITE;
1541 }
1542 access
1543 }
1544
1545 pub fn ops(&self) -> &dyn FileOps {
1546 self.ops.as_ref()
1547 }
1548
1549 pub fn ops_type_name(&self) -> &'static str {
1550 self.ops().type_name()
1551 }
1552
1553 pub fn is_non_blocking(&self) -> bool {
1554 self.flags().contains(OpenFlags::NONBLOCK)
1555 }
1556
1557 pub fn blocking_op<T, Op>(
1573 &self,
1574 current_task: &CurrentTask,
1575 events: FdEvents,
1576 deadline: Option<zx::MonotonicInstant>,
1577 mut op: Op,
1578 ) -> Result<T, Errno>
1579 where
1580 Op: FnMut() -> Result<T, Errno>,
1581 {
1582 let can_return_eagain = self.flags().contains(OpenFlags::NONBLOCK)
1585 && !self.flags().contains(OpenFlags::DIRECTORY);
1586 match op() {
1588 Err(errno) if errno == EAGAIN && !can_return_eagain => {}
1589 result => return result,
1590 }
1591
1592 let waiter = Waiter::new();
1593 loop {
1594 self.wait_async(current_task, &waiter, events, WaitCallback::none());
1596 match op() {
1597 Err(e) if e == EAGAIN => {}
1598 result => return result,
1599 }
1600 waiter
1601 .wait_until(current_task, deadline.unwrap_or(zx::MonotonicInstant::INFINITE))
1602 .map_err(|e| if e == ETIMEDOUT { errno!(EAGAIN) } else { e })?;
1603 }
1604 }
1605
1606 pub fn is_seekable(&self) -> bool {
1607 self.ops().is_seekable()
1608 }
1609
1610 pub fn has_persistent_offsets(&self) -> bool {
1611 self.ops().has_persistent_offsets()
1612 }
1613
1614 fn read_internal<R>(&self, current_task: &CurrentTask, read: R) -> Result<usize, Errno>
1616 where
1617 R: FnOnce() -> Result<usize, Errno>,
1618 {
1619 security::file_permission(current_task, self, security::PermissionFlags::READ)?;
1620
1621 if !self.can_read() {
1622 return error!(EBADF);
1623 }
1624 let bytes_read = read()?;
1625
1626 self.update_atime();
1629 if bytes_read > 0 {
1630 self.notify(InotifyMask::ACCESS);
1631 }
1632
1633 Ok(bytes_read)
1634 }
1635
1636 pub fn read(
1637 &self,
1638 current_task: &CurrentTask,
1639 data: &mut dyn OutputBuffer,
1640 ) -> Result<usize, Errno> {
1641 self.read_internal(current_task, || {
1642 if !self.ops().has_persistent_offsets() {
1643 if data.available() > MAX_LFS_FILESIZE {
1644 return error!(EINVAL);
1645 }
1646 return self.ops.read(self, current_task, 0, data);
1647 }
1648
1649 let mut offset_guard = self.offset.copy();
1650 let offset = *offset_guard as usize;
1651 checked_add_offset_and_length(offset, data.available())?;
1652 let read = self.ops.read(self, current_task, offset, data)?;
1653 *offset_guard += read as off_t;
1654 offset_guard.update();
1655 Ok(read)
1656 })
1657 }
1658
1659 pub fn read_at(
1660 &self,
1661 current_task: &CurrentTask,
1662 offset: usize,
1663 data: &mut dyn OutputBuffer,
1664 ) -> Result<usize, Errno> {
1665 if !self.ops().is_seekable() {
1666 return error!(ESPIPE);
1667 }
1668 checked_add_offset_and_length(offset, data.available())?;
1669 self.read_internal(current_task, || self.ops.read(self, current_task, offset, data))
1670 }
1671
1672 fn write_common(
1674 &self,
1675 current_task: &CurrentTask,
1676 offset: usize,
1677 data: &mut dyn InputBuffer,
1678 ) -> Result<usize, Errno> {
1679 security::file_permission(current_task, self, security::PermissionFlags::WRITE)?;
1680
1681 checked_add_offset_and_length(offset, data.available())?;
1688 self.ops().write(self, current_task, offset, data)
1689 }
1690
1691 fn write_fn<W>(&self, current_task: &CurrentTask, write: W) -> Result<usize, Errno>
1693 where
1694 W: FnOnce() -> Result<usize, Errno>,
1695 {
1696 if !self.can_write() {
1697 return error!(EBADF);
1698 }
1699 self.node().clear_suid_and_sgid_bits(current_task)?;
1700 let bytes_written = write()?;
1701 self.node().update_ctime_mtime();
1702
1703 if bytes_written > 0 {
1704 self.notify(InotifyMask::MODIFY);
1705 }
1706
1707 Ok(bytes_written)
1708 }
1709
1710 pub fn write(
1711 &self,
1712 current_task: &CurrentTask,
1713 data: &mut dyn InputBuffer,
1714 ) -> Result<usize, Errno> {
1715 self.write_fn(current_task, || {
1716 if !self.ops().has_persistent_offsets() {
1717 return self.write_common(current_task, 0, data);
1718 }
1719 let mut offset = self.offset.copy();
1720 let bytes_written = if self.flags().contains(OpenFlags::APPEND) {
1721 let _guard = self.node().ops().append_lock_write(self.node(), current_task)?;
1722 *offset = self.ops().seek(self, current_task, *offset, SeekTarget::End(0))?;
1723 self.write_common(current_task, *offset as usize, data)
1724 } else {
1725 let _guard = self.node().ops().append_lock_read(self.node(), current_task)?;
1726 self.write_common(current_task, *offset as usize, data)
1727 }?;
1728 if self.ops().writes_update_seek_offset() {
1729 *offset += bytes_written as off_t;
1730 }
1731 offset.update();
1732 Ok(bytes_written)
1733 })
1734 }
1735
1736 pub fn write_at(
1737 &self,
1738 current_task: &CurrentTask,
1739 mut offset: usize,
1740 data: &mut dyn InputBuffer,
1741 ) -> Result<usize, Errno> {
1742 if !self.ops().is_seekable() {
1743 return error!(ESPIPE);
1744 }
1745 self.write_fn(current_task, || {
1746 if self.flags().contains(OpenFlags::APPEND) {
1747 let _guard = self.node().append_lock.write(current_task)?;
1748 if self.ops().is_seekable() {
1754 checked_add_offset_and_length(offset, data.available())?;
1755 offset = default_eof_offset(self, current_task)? as usize;
1756 }
1757 self.write_common(current_task, offset, data)
1758 } else {
1759 let _guard = self.node().append_lock.read(current_task)?;
1760 self.write_common(current_task, offset, data)
1761 }
1762 })
1763 }
1764
1765 pub fn seek(&self, current_task: &CurrentTask, target: SeekTarget) -> Result<off_t, Errno> {
1766 if !self.ops().is_seekable() {
1767 return error!(ESPIPE);
1768 }
1769
1770 if !self.ops().has_persistent_offsets() {
1771 return self.ops().seek(self, current_task, 0, target);
1772 }
1773
1774 let mut offset_guard = self.offset.copy();
1775 let new_offset = self.ops().seek(self, current_task, *offset_guard, target)?;
1776 *offset_guard = new_offset;
1777 offset_guard.update();
1778 Ok(new_offset)
1779 }
1780
1781 pub fn sync(&self, current_task: &CurrentTask) -> Result<(), Errno> {
1782 self.ops().sync(self, current_task)
1783 }
1784
1785 pub fn data_sync(&self, current_task: &CurrentTask) -> Result<(), Errno> {
1786 self.ops().data_sync(self, current_task)
1787 }
1788
1789 pub fn get_memory(
1790 &self,
1791 current_task: &CurrentTask,
1792 length: Option<usize>,
1793 prot: ProtectionFlags,
1794 ) -> Result<Arc<MemoryObject>, Errno> {
1795 if prot.contains(ProtectionFlags::READ) && !self.can_read() {
1796 return error!(EACCES);
1797 }
1798 if prot.contains(ProtectionFlags::WRITE) && !self.can_write() {
1799 return error!(EACCES);
1800 }
1801 if prot.contains(ProtectionFlags::EXEC) && !self.can_exec() {
1802 return error!(EPERM);
1803 }
1804 self.ops().get_memory(self, current_task, length, prot)
1805 }
1806
1807 pub fn mmap(
1808 &self,
1809 current_task: &CurrentTask,
1810 addr: DesiredAddress,
1811 memory_offset: u64,
1812 length: usize,
1813 prot_flags: ProtectionFlags,
1814 options: MappingOptions,
1815 ) -> Result<UserAddress, Errno> {
1816 if !self.can_read() {
1817 return error!(EACCES);
1818 }
1819 if prot_flags.contains(ProtectionFlags::WRITE)
1820 && !self.can_write()
1821 && options.contains(MappingOptions::SHARED)
1822 {
1823 return error!(EACCES);
1824 }
1825 if prot_flags.contains(ProtectionFlags::EXEC) && !self.can_exec() {
1826 return error!(EPERM);
1827 }
1828 self.ops().mmap(self, current_task, addr, memory_offset, length, prot_flags, options)
1829 }
1830
1831 pub fn readdir(
1832 &self,
1833 current_task: &CurrentTask,
1834 sink: &mut dyn DirentSink,
1835 ) -> Result<(), Errno> {
1836 if self.name.entry.is_dead() {
1837 return error!(ENOENT);
1838 }
1839
1840 security::file_permission(current_task, self, security::PermissionFlags::READ)?;
1841
1842 self.ops().readdir(self, current_task, sink)?;
1843 self.update_atime();
1844 self.notify(InotifyMask::ACCESS);
1845 Ok(())
1846 }
1847
1848 pub fn ioctl(
1849 &self,
1850 current_task: &CurrentTask,
1851 request: u32,
1852 arg: SyscallArg,
1853 ) -> Result<SyscallResult, Errno> {
1854 security::check_file_ioctl_access(current_task, &self, request)?;
1855
1856 if request == FIBMAP {
1857 security::check_task_capable(current_task, CAP_SYS_RAWIO)?;
1858
1859 if current_task.kernel().features.selinux_test_suite {
1862 let phoney_block = 0xbadf000du32;
1863 current_task.write_object(arg.into(), &phoney_block)?;
1864 return Ok(SUCCESS);
1865 }
1866 }
1867
1868 if let Some(result) = default_vfs_ioctl(self, current_task, request, arg)? {
1869 return Ok(result);
1870 }
1871
1872 self.ops().ioctl(self, current_task, request, arg)
1873 }
1874
1875 pub fn fcntl(
1876 &self,
1877 current_task: &CurrentTask,
1878 cmd: u32,
1879 arg: u64,
1880 ) -> Result<SyscallResult, Errno> {
1881 self.ops().fcntl(self, current_task, cmd, arg)
1882 }
1883
1884 pub fn ftruncate(&self, current_task: &CurrentTask, length: u64) -> Result<(), Errno> {
1885 if !self.can_write() {
1888 return error!(EINVAL);
1889 }
1890 self.node().ftruncate(current_task, length)?;
1891 self.name.entry.notify_ignoring_excl_unlink(InotifyMask::MODIFY);
1892 Ok(())
1893 }
1894
1895 pub fn fallocate(
1896 &self,
1897 current_task: &CurrentTask,
1898 mode: FallocMode,
1899 offset: u64,
1900 length: u64,
1901 ) -> Result<(), Errno> {
1902 if self.node().is_fifo() {
1905 return error!(ESPIPE);
1906 }
1907
1908 if !self.node().is_dir() && !self.node().is_reg() {
1911 return error!(ENODEV);
1912 }
1913
1914 if !self.can_write() {
1917 return error!(EBADF);
1918 }
1919
1920 security::file_permission(current_task, self, security::PermissionFlags::WRITE)?;
1921
1922 self.node().fallocate(current_task, mode, offset, length)?;
1923 self.notify(InotifyMask::MODIFY);
1924 Ok(())
1925 }
1926
1927 pub fn to_handle(
1928 &self,
1929 current_task: &CurrentTask,
1930 ) -> Result<Option<zx::NullableHandle>, Errno> {
1931 self.ops().to_handle(self, current_task)
1932 }
1933
1934 pub fn get_handles(
1935 &self,
1936 current_task: &CurrentTask,
1937 ) -> Result<Vec<zx::NullableHandle>, Errno> {
1938 self.ops().get_handles(self, current_task)
1939 }
1940
1941 pub fn as_pid(&self) -> Result<Pid, Errno> {
1942 self.ops().as_pid(self)
1943 }
1944
1945 pub fn to_file_handle(&self) -> FileHandle {
1948 self.weak_handle.upgrade().expect("FileObject is alive, so weak_handle must upgrade")
1949 }
1950
1951 pub fn to_mapping(&self, mode: Option<FileWriteGuardMode>) -> Result<Arc<FileMapping>, Errno> {
1954 FileMapping::new(self.to_file_handle(), mode)
1955 }
1956
1957 pub fn update_file_flags(&self, value: OpenFlags, mask: OpenFlags) {
1963 self.flags.update(value, mask, Ordering::Relaxed, Ordering::Relaxed);
1964 }
1965
1966 pub fn get_async_owner(&self) -> FileAsyncOwner {
1970 self.async_owner.lock().clone()
1971 }
1972
1973 pub fn set_async_owner(&self, owner: FileAsyncOwner) {
1977 *self.async_owner.lock() = owner;
1978 }
1979
1980 pub fn get_lease(&self) -> FileLeaseType {
1982 *self.lease.lock()
1983 }
1984
1985 pub fn set_lease(&self, current_task: &CurrentTask, lease: FileLeaseType) -> Result<(), Errno> {
1987 if !self.node().is_reg() {
1988 return error!(EINVAL);
1989 }
1990 security::check_file_lock_access(current_task, self)?;
1991 if lease == FileLeaseType::Read && self.can_write() {
1992 return error!(EAGAIN);
1993 }
1994 *self.lease.lock() = lease;
1995 Ok(())
1996 }
1997
1998 pub fn wait_async(
2000 &self,
2001 current_task: &CurrentTask,
2002 waiter: &Waiter,
2003 events: FdEvents,
2004 handler: EventHandler,
2005 ) -> Option<WaitCanceler> {
2006 self.ops().wait_async(self, current_task, waiter, events, handler)
2007 }
2008
2009 pub fn query_events(&self, current_task: &CurrentTask) -> Result<FdEvents, Errno> {
2011 self.ops().query_events(self, current_task).map(FdEvents::add_equivalent_fd_events)
2012 }
2013
2014 pub fn record_lock(
2015 &self,
2016 current_task: &CurrentTask,
2017 cmd: RecordLockCommand,
2018 flock: uapi::flock,
2019 ) -> Result<Option<uapi::flock>, Errno> {
2020 security::check_file_lock_access(current_task, self)?;
2021 self.node().record_lock(current_task, self, cmd, flock)
2022 }
2023
2024 pub fn flush(&self, current_task: &CurrentTask, id: FdTableId) {
2025 self.name.entry.node.record_lock_release(RecordLockOwner::FdTable(id));
2026 self.ops().flush(self, current_task)
2027 }
2028
2029 fn update_atime(&self) {
2030 if !self.flags().contains(OpenFlags::NOATIME) {
2031 self.name.update_atime();
2032 }
2033 }
2034
2035 pub fn readahead(
2036 &self,
2037 current_task: &CurrentTask,
2038 offset: usize,
2039 length: usize,
2040 ) -> Result<(), Errno> {
2041 if !self.can_read() {
2043 return error!(EBADF);
2044 }
2045 checked_add_offset_and_length(offset, length)?;
2046 self.ops().readahead(self, current_task, offset, length)
2047 }
2048
2049 pub fn extra_fdinfo(&self, current_task: &CurrentTask) -> Option<FsString> {
2050 let file = self.weak_handle.upgrade()?;
2051 self.ops().extra_fdinfo(&file, current_task)
2052 }
2053
2054 pub fn register_epfd(&self, file: &FileHandle) {
2057 self.epoll_files.lock().insert(WeakKey::from(file), file.weak_handle.clone());
2058 }
2059
2060 pub fn unregister_epfd(&self, file: &FileHandle) {
2061 self.epoll_files.lock().remove(&WeakKey::from(file));
2062 }
2063}
2064
2065impl Releasable for FileObject {
2066 type Context<'a> = &'a CurrentTask;
2067
2068 fn release<'a>(self, context: &'a CurrentTask) {
2069 let current_task = context;
2070 for (_, file) in self.epoll_files.lock().drain() {
2073 if let Some(file) = file.upgrade() {
2074 if let Some(epoll_object) = file.downcast_file::<EpollFileObject>() {
2075 let _ = epoll_object.delete(current_task, &self);
2076 }
2077 }
2078 }
2079
2080 if self.can_write() {
2081 self.name.entry.node.write_guard_state.lock().release(FileWriteGuardMode::WriteFile);
2082 }
2083
2084 let ops = self.ops;
2085 let state = self.state;
2086 ops.close(&state, current_task);
2087 state.name.entry.node.on_file_closed(&state);
2088 let event =
2089 if state.can_write() { InotifyMask::CLOSE_WRITE } else { InotifyMask::CLOSE_NOWRITE };
2090 state.notify(event);
2091 }
2092}
2093
2094impl fmt::Debug for FileObject {
2095 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2096 f.debug_struct("FileObject")
2097 .field("name", &self.name)
2098 .field("fs", &self.fs.name())
2099 .field("offset", &self.offset)
2100 .field("flags", &self.flags)
2101 .field("ops_ty", &self.ops().type_name())
2102 .finish()
2103 }
2104}
2105
2106impl OnWakeOps for FileReleaser {
2107 fn on_wake(&self, _current_task: &CurrentTask, _baton_lease: &zx::NullableHandle) {}
2108}
2109
2110pub struct DowncastedFile<'a, Ops> {
2112 file: &'a FileObject,
2113 ops: &'a Ops,
2114}
2115impl<'a, Ops> Copy for DowncastedFile<'a, Ops> {}
2116impl<'a, Ops> Clone for DowncastedFile<'a, Ops> {
2117 fn clone(&self) -> Self {
2118 *self
2119 }
2120}
2121
2122impl<'a, Ops> DowncastedFile<'a, Ops> {
2123 pub fn file(&self) -> &'a FileObject {
2124 self.file
2125 }
2126}
2127
2128impl<'a, Ops> Deref for DowncastedFile<'a, Ops> {
2129 type Target = &'a Ops;
2130 fn deref(&self) -> &Self::Target {
2131 &self.ops
2132 }
2133}
2134
2135impl FileObject {
2136 pub fn downcast_file<'a, T>(&'a self) -> Option<DowncastedFile<'a, T>>
2141 where
2142 T: 'static,
2143 {
2144 let ops = self.ops().as_any().downcast_ref::<T>()?;
2145 Some(DowncastedFile { file: self, ops })
2146 }
2147}
2148
2149pub fn call_fidl_and_await_close<P, M>(method: M, proxy: &P)
2157where
2158 P: fidl::endpoints::SynchronousProxy,
2159 M: FnOnce(&P) -> Result<(), fidl::Error>,
2160{
2161 if let Err(e) = method(proxy) {
2162 log_error!("call_fidl_and_await_close: call {} failed: {e:?}", P::Protocol::DEBUG_NAME);
2163 return;
2164 }
2165 let channel = proxy.as_channel();
2166 let result = channel.wait_one(zx::Signals::CHANNEL_PEER_CLOSED, zx::MonotonicInstant::INFINITE);
2167 if let Err(status) = result.to_result() {
2168 log_error!(
2169 "call_fidl_and_await_close: wait_one {} failed: {status:?}",
2170 P::Protocol::DEBUG_NAME
2171 );
2172 }
2173}
2174
2175#[cfg(test)]
2176mod tests {
2177 use crate::fs::tmpfs::TmpFs;
2178 use crate::task::CurrentTask;
2179 use crate::task::dynamic_thread_spawner::SpawnRequestBuilder;
2180 use crate::testing::*;
2181 use crate::vfs::MountInfo;
2182 use crate::vfs::buffers::{VecInputBuffer, VecOutputBuffer};
2183 use starnix_uapi::auth::FsCred;
2184 use starnix_uapi::device_id::DeviceId;
2185 use starnix_uapi::file_mode::FileMode;
2186 use starnix_uapi::open_flags::OpenFlags;
2187 use std::sync::Arc;
2188 use std::sync::atomic::{AtomicBool, Ordering};
2189 use zerocopy::{FromBytes, IntoBytes, LE, U64};
2190
2191 #[::fuchsia::test]
2192 async fn test_append_truncate_race() {
2193 spawn_kernel_and_run(async |current_task| {
2194 let kernel = current_task.kernel();
2195 let root_fs = TmpFs::new_fs(&kernel);
2196 let mount = MountInfo::detached();
2197 let root_node = Arc::clone(root_fs.root());
2198 let file = root_node
2199 .create_entry(¤t_task, &mount, "test".into(), |dir, mount, name| {
2200 dir.create_node(
2201 ¤t_task,
2202 mount,
2203 name,
2204 FileMode::IFREG | FileMode::ALLOW_ALL,
2205 DeviceId::NONE,
2206 FsCred::root(),
2207 )
2208 })
2209 .expect("create_node failed");
2210 let file_handle = file
2211 .open_anonymous(¤t_task, OpenFlags::APPEND | OpenFlags::RDWR)
2212 .expect("open failed");
2213 let done = Arc::new(AtomicBool::new(false));
2214
2215 let fh = file_handle.clone();
2216 let done_clone = done.clone();
2217 let closure = move |current_task: &CurrentTask| {
2218 for i in 0..2000 {
2219 fh.write(current_task, &mut VecInputBuffer::new(U64::<LE>::new(i).as_bytes()))
2220 .expect("write failed");
2221 }
2222 done_clone.store(true, Ordering::SeqCst);
2223 let result: Result<(), starnix_uapi::errors::Errno> = Ok(());
2224 result
2225 };
2226 let (write_thread, req) =
2227 SpawnRequestBuilder::new().with_sync_closure(closure).build_with_sync_result();
2228 kernel.kthreads.spawner().spawn_from_request(req);
2229
2230 let fh = file_handle.clone();
2231 let done_clone = done.clone();
2232 let closure = move |current_task: &CurrentTask| {
2233 while !done_clone.load(Ordering::SeqCst) {
2234 fh.ftruncate(current_task, 0).expect("truncate failed");
2235 }
2236 let result: Result<(), starnix_uapi::errors::Errno> = Ok(());
2237 result
2238 };
2239 let (truncate_thread, req) =
2240 SpawnRequestBuilder::new().with_sync_closure(closure).build_with_sync_result();
2241 kernel.kthreads.spawner().spawn_from_request(req);
2242
2243 while !done.load(Ordering::SeqCst) {
2246 let mut buffer = VecOutputBuffer::new(4096);
2247 let amount =
2248 file_handle.read_at(¤t_task, 0, &mut buffer).expect("read failed");
2249 let mut last = None;
2250 let buffer = &Vec::from(buffer)[..amount];
2251 for i in
2252 buffer.chunks_exact(8).map(|chunk| U64::<LE>::read_from_bytes(chunk).unwrap())
2253 {
2254 if let Some(last) = last {
2255 assert!(i.get() > last, "buffer: {:?}", buffer);
2256 }
2257 last = Some(i.get());
2258 }
2259 }
2260
2261 let _ = write_thread().unwrap();
2262 let _ = truncate_thread().unwrap();
2263 })
2264 .await;
2265 }
2266}