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