1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2019 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker
5*bb4ee6a4SAndroid Build Coastguard Worker use std::borrow::Cow;
6*bb4ee6a4SAndroid Build Coastguard Worker use std::cell::RefCell;
7*bb4ee6a4SAndroid Build Coastguard Worker use std::cmp;
8*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::btree_map;
9*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::BTreeMap;
10*bb4ee6a4SAndroid Build Coastguard Worker use std::ffi::CStr;
11*bb4ee6a4SAndroid Build Coastguard Worker use std::ffi::CString;
12*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "fs_runtime_ugid_map")]
13*bb4ee6a4SAndroid Build Coastguard Worker use std::ffi::OsStr;
14*bb4ee6a4SAndroid Build Coastguard Worker use std::fs::File;
15*bb4ee6a4SAndroid Build Coastguard Worker use std::io;
16*bb4ee6a4SAndroid Build Coastguard Worker use std::mem;
17*bb4ee6a4SAndroid Build Coastguard Worker use std::mem::size_of;
18*bb4ee6a4SAndroid Build Coastguard Worker use std::mem::MaybeUninit;
19*bb4ee6a4SAndroid Build Coastguard Worker use std::os::raw::c_int;
20*bb4ee6a4SAndroid Build Coastguard Worker use std::os::raw::c_long;
21*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "fs_runtime_ugid_map")]
22*bb4ee6a4SAndroid Build Coastguard Worker use std::os::unix::ffi::OsStrExt;
23*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "fs_runtime_ugid_map")]
24*bb4ee6a4SAndroid Build Coastguard Worker use std::path::Path;
25*bb4ee6a4SAndroid Build Coastguard Worker use std::ptr;
26*bb4ee6a4SAndroid Build Coastguard Worker use std::ptr::addr_of;
27*bb4ee6a4SAndroid Build Coastguard Worker use std::ptr::addr_of_mut;
28*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::atomic::AtomicBool;
29*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::atomic::AtomicU64;
30*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::atomic::Ordering;
31*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::Arc;
32*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::MutexGuard;
33*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "fs_permission_translation")]
34*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::RwLock;
35*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Duration;
36*bb4ee6a4SAndroid Build Coastguard Worker
37*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
38*bb4ee6a4SAndroid Build Coastguard Worker use base::debug;
39*bb4ee6a4SAndroid Build Coastguard Worker use base::error;
40*bb4ee6a4SAndroid Build Coastguard Worker use base::ioctl_ior_nr;
41*bb4ee6a4SAndroid Build Coastguard Worker use base::ioctl_iow_nr;
42*bb4ee6a4SAndroid Build Coastguard Worker use base::ioctl_iowr_nr;
43*bb4ee6a4SAndroid Build Coastguard Worker use base::ioctl_with_mut_ptr;
44*bb4ee6a4SAndroid Build Coastguard Worker use base::ioctl_with_ptr;
45*bb4ee6a4SAndroid Build Coastguard Worker use base::syscall;
46*bb4ee6a4SAndroid Build Coastguard Worker use base::unix::FileFlags;
47*bb4ee6a4SAndroid Build Coastguard Worker use base::warn;
48*bb4ee6a4SAndroid Build Coastguard Worker use base::AsRawDescriptor;
49*bb4ee6a4SAndroid Build Coastguard Worker use base::FromRawDescriptor;
50*bb4ee6a4SAndroid Build Coastguard Worker use base::IoctlNr;
51*bb4ee6a4SAndroid Build Coastguard Worker use base::Protection;
52*bb4ee6a4SAndroid Build Coastguard Worker use base::RawDescriptor;
53*bb4ee6a4SAndroid Build Coastguard Worker use fuse::filesystem::Context;
54*bb4ee6a4SAndroid Build Coastguard Worker use fuse::filesystem::DirectoryIterator;
55*bb4ee6a4SAndroid Build Coastguard Worker use fuse::filesystem::Entry;
56*bb4ee6a4SAndroid Build Coastguard Worker use fuse::filesystem::FileSystem;
57*bb4ee6a4SAndroid Build Coastguard Worker use fuse::filesystem::FsOptions;
58*bb4ee6a4SAndroid Build Coastguard Worker use fuse::filesystem::GetxattrReply;
59*bb4ee6a4SAndroid Build Coastguard Worker use fuse::filesystem::IoctlFlags;
60*bb4ee6a4SAndroid Build Coastguard Worker use fuse::filesystem::IoctlReply;
61*bb4ee6a4SAndroid Build Coastguard Worker use fuse::filesystem::ListxattrReply;
62*bb4ee6a4SAndroid Build Coastguard Worker use fuse::filesystem::OpenOptions;
63*bb4ee6a4SAndroid Build Coastguard Worker use fuse::filesystem::RemoveMappingOne;
64*bb4ee6a4SAndroid Build Coastguard Worker use fuse::filesystem::SetattrValid;
65*bb4ee6a4SAndroid Build Coastguard Worker use fuse::filesystem::ZeroCopyReader;
66*bb4ee6a4SAndroid Build Coastguard Worker use fuse::filesystem::ZeroCopyWriter;
67*bb4ee6a4SAndroid Build Coastguard Worker use fuse::filesystem::ROOT_ID;
68*bb4ee6a4SAndroid Build Coastguard Worker use fuse::sys::WRITE_KILL_PRIV;
69*bb4ee6a4SAndroid Build Coastguard Worker use fuse::Mapper;
70*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
71*bb4ee6a4SAndroid Build Coastguard Worker use protobuf::Message;
72*bb4ee6a4SAndroid Build Coastguard Worker use sync::Mutex;
73*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
74*bb4ee6a4SAndroid Build Coastguard Worker use system_api::client::OrgChromiumSpaced;
75*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
76*bb4ee6a4SAndroid Build Coastguard Worker use system_api::spaced::SetProjectIdReply;
77*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
78*bb4ee6a4SAndroid Build Coastguard Worker use system_api::spaced::SetProjectInheritanceFlagReply;
79*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::AsBytes;
80*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::FromBytes;
81*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::FromZeroes;
82*bb4ee6a4SAndroid Build Coastguard Worker
83*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
84*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::fs::arc_ioctl::FsPathXattrDataBuffer;
85*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
86*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::fs::arc_ioctl::FsPermissionDataBuffer;
87*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
88*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::fs::arc_ioctl::XattrData;
89*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::fs::caps::Capability;
90*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::fs::caps::Caps;
91*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::fs::caps::Set as CapSet;
92*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::fs::caps::Value as CapValue;
93*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::fs::config::CachePolicy;
94*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::fs::config::Config;
95*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "fs_permission_translation")]
96*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::fs::config::PermissionData;
97*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::fs::expiring_map::ExpiringMap;
98*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::fs::multikey::MultikeyBTreeMap;
99*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::fs::read_dir::ReadDir;
100*bb4ee6a4SAndroid Build Coastguard Worker
101*bb4ee6a4SAndroid Build Coastguard Worker const EMPTY_CSTR: &CStr = c"";
102*bb4ee6a4SAndroid Build Coastguard Worker const PROC_CSTR: &CStr = c"/proc";
103*bb4ee6a4SAndroid Build Coastguard Worker const UNLABELED_CSTR: &CStr = c"unlabeled";
104*bb4ee6a4SAndroid Build Coastguard Worker
105*bb4ee6a4SAndroid Build Coastguard Worker const USER_VIRTIOFS_XATTR: &[u8] = b"user.virtiofs.";
106*bb4ee6a4SAndroid Build Coastguard Worker const SECURITY_XATTR: &[u8] = b"security.";
107*bb4ee6a4SAndroid Build Coastguard Worker const SELINUX_XATTR: &[u8] = b"security.selinux";
108*bb4ee6a4SAndroid Build Coastguard Worker
109*bb4ee6a4SAndroid Build Coastguard Worker const FSCRYPT_KEY_DESCRIPTOR_SIZE: usize = 8;
110*bb4ee6a4SAndroid Build Coastguard Worker const FSCRYPT_KEY_IDENTIFIER_SIZE: usize = 16;
111*bb4ee6a4SAndroid Build Coastguard Worker
112*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
113*bb4ee6a4SAndroid Build Coastguard Worker const FS_PROJINHERIT_FL: c_int = 0x20000000;
114*bb4ee6a4SAndroid Build Coastguard Worker
115*bb4ee6a4SAndroid Build Coastguard Worker // 25 seconds is the default timeout for dbus-send.
116*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
117*bb4ee6a4SAndroid Build Coastguard Worker const DEFAULT_DBUS_TIMEOUT: Duration = Duration::from_secs(25);
118*bb4ee6a4SAndroid Build Coastguard Worker
119*bb4ee6a4SAndroid Build Coastguard Worker /// Internal utility wrapper for `cros_tracing::trace_event!()` macro with VirtioFS calls.
120*bb4ee6a4SAndroid Build Coastguard Worker macro_rules! fs_trace {
121*bb4ee6a4SAndroid Build Coastguard Worker ($tag:expr, $name:expr, $($arg:expr),+) => {
122*bb4ee6a4SAndroid Build Coastguard Worker cros_tracing::trace_event!(VirtioFs, $name, $tag, $($arg),*)
123*bb4ee6a4SAndroid Build Coastguard Worker };
124*bb4ee6a4SAndroid Build Coastguard Worker }
125*bb4ee6a4SAndroid Build Coastguard Worker
126*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)]
127*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, Copy, AsBytes, FromZeroes, FromBytes)]
128*bb4ee6a4SAndroid Build Coastguard Worker struct fscrypt_policy_v1 {
129*bb4ee6a4SAndroid Build Coastguard Worker _version: u8,
130*bb4ee6a4SAndroid Build Coastguard Worker _contents_encryption_mode: u8,
131*bb4ee6a4SAndroid Build Coastguard Worker _filenames_encryption_mode: u8,
132*bb4ee6a4SAndroid Build Coastguard Worker _flags: u8,
133*bb4ee6a4SAndroid Build Coastguard Worker _master_key_descriptor: [u8; FSCRYPT_KEY_DESCRIPTOR_SIZE],
134*bb4ee6a4SAndroid Build Coastguard Worker }
135*bb4ee6a4SAndroid Build Coastguard Worker
136*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)]
137*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, Copy, AsBytes, FromZeroes, FromBytes)]
138*bb4ee6a4SAndroid Build Coastguard Worker struct fscrypt_policy_v2 {
139*bb4ee6a4SAndroid Build Coastguard Worker _version: u8,
140*bb4ee6a4SAndroid Build Coastguard Worker _contents_encryption_mode: u8,
141*bb4ee6a4SAndroid Build Coastguard Worker _filenames_encryption_mode: u8,
142*bb4ee6a4SAndroid Build Coastguard Worker _flags: u8,
143*bb4ee6a4SAndroid Build Coastguard Worker __reserved: [u8; 4],
144*bb4ee6a4SAndroid Build Coastguard Worker master_key_identifier: [u8; FSCRYPT_KEY_IDENTIFIER_SIZE],
145*bb4ee6a4SAndroid Build Coastguard Worker }
146*bb4ee6a4SAndroid Build Coastguard Worker
147*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)]
148*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Copy, Clone, FromZeroes, FromBytes)]
149*bb4ee6a4SAndroid Build Coastguard Worker union fscrypt_policy {
150*bb4ee6a4SAndroid Build Coastguard Worker _version: u8,
151*bb4ee6a4SAndroid Build Coastguard Worker _v1: fscrypt_policy_v1,
152*bb4ee6a4SAndroid Build Coastguard Worker _v2: fscrypt_policy_v2,
153*bb4ee6a4SAndroid Build Coastguard Worker }
154*bb4ee6a4SAndroid Build Coastguard Worker
155*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)]
156*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Copy, Clone, FromZeroes, FromBytes)]
157*bb4ee6a4SAndroid Build Coastguard Worker struct fscrypt_get_policy_ex_arg {
158*bb4ee6a4SAndroid Build Coastguard Worker policy_size: u64, /* input/output */
159*bb4ee6a4SAndroid Build Coastguard Worker policy: fscrypt_policy, /* output */
160*bb4ee6a4SAndroid Build Coastguard Worker }
161*bb4ee6a4SAndroid Build Coastguard Worker
162*bb4ee6a4SAndroid Build Coastguard Worker impl From<&fscrypt_get_policy_ex_arg> for &[u8] {
from(value: &fscrypt_get_policy_ex_arg) -> Self163*bb4ee6a4SAndroid Build Coastguard Worker fn from(value: &fscrypt_get_policy_ex_arg) -> Self {
164*bb4ee6a4SAndroid Build Coastguard Worker assert!(value.policy_size <= size_of::<fscrypt_policy>() as u64);
165*bb4ee6a4SAndroid Build Coastguard Worker let data_raw: *const fscrypt_get_policy_ex_arg = value;
166*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: the length of the output slice is asserted to be within the struct it points to
167*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
168*bb4ee6a4SAndroid Build Coastguard Worker std::slice::from_raw_parts(
169*bb4ee6a4SAndroid Build Coastguard Worker data_raw.cast(),
170*bb4ee6a4SAndroid Build Coastguard Worker value.policy_size as usize + size_of::<u64>(),
171*bb4ee6a4SAndroid Build Coastguard Worker )
172*bb4ee6a4SAndroid Build Coastguard Worker }
173*bb4ee6a4SAndroid Build Coastguard Worker }
174*bb4ee6a4SAndroid Build Coastguard Worker }
175*bb4ee6a4SAndroid Build Coastguard Worker
176*bb4ee6a4SAndroid Build Coastguard Worker ioctl_iowr_nr!(FS_IOC_GET_ENCRYPTION_POLICY_EX, 'f' as u32, 22, [u8; 9]);
177*bb4ee6a4SAndroid Build Coastguard Worker
178*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)]
179*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, Copy, AsBytes, FromZeroes, FromBytes)]
180*bb4ee6a4SAndroid Build Coastguard Worker struct fsxattr {
181*bb4ee6a4SAndroid Build Coastguard Worker fsx_xflags: u32, /* xflags field value (get/set) */
182*bb4ee6a4SAndroid Build Coastguard Worker fsx_extsize: u32, /* extsize field value (get/set) */
183*bb4ee6a4SAndroid Build Coastguard Worker fsx_nextents: u32, /* nextents field value (get) */
184*bb4ee6a4SAndroid Build Coastguard Worker fsx_projid: u32, /* project identifier (get/set) */
185*bb4ee6a4SAndroid Build Coastguard Worker fsx_cowextsize: u32, /* CoW extsize field value (get/set) */
186*bb4ee6a4SAndroid Build Coastguard Worker fsx_pad: [u8; 8],
187*bb4ee6a4SAndroid Build Coastguard Worker }
188*bb4ee6a4SAndroid Build Coastguard Worker
189*bb4ee6a4SAndroid Build Coastguard Worker ioctl_ior_nr!(FS_IOC_FSGETXATTR, 'X' as u32, 31, fsxattr);
190*bb4ee6a4SAndroid Build Coastguard Worker ioctl_iow_nr!(FS_IOC_FSSETXATTR, 'X' as u32, 32, fsxattr);
191*bb4ee6a4SAndroid Build Coastguard Worker
192*bb4ee6a4SAndroid Build Coastguard Worker ioctl_ior_nr!(FS_IOC_GETFLAGS, 'f' as u32, 1, c_long);
193*bb4ee6a4SAndroid Build Coastguard Worker ioctl_iow_nr!(FS_IOC_SETFLAGS, 'f' as u32, 2, c_long);
194*bb4ee6a4SAndroid Build Coastguard Worker
195*bb4ee6a4SAndroid Build Coastguard Worker ioctl_ior_nr!(FS_IOC32_GETFLAGS, 'f' as u32, 1, u32);
196*bb4ee6a4SAndroid Build Coastguard Worker ioctl_iow_nr!(FS_IOC32_SETFLAGS, 'f' as u32, 2, u32);
197*bb4ee6a4SAndroid Build Coastguard Worker
198*bb4ee6a4SAndroid Build Coastguard Worker ioctl_ior_nr!(FS_IOC64_GETFLAGS, 'f' as u32, 1, u64);
199*bb4ee6a4SAndroid Build Coastguard Worker ioctl_iow_nr!(FS_IOC64_SETFLAGS, 'f' as u32, 2, u64);
200*bb4ee6a4SAndroid Build Coastguard Worker
201*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
202*bb4ee6a4SAndroid Build Coastguard Worker ioctl_iow_nr!(FS_IOC_SETPERMISSION, 'f' as u32, 1, FsPermissionDataBuffer);
203*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
204*bb4ee6a4SAndroid Build Coastguard Worker ioctl_iow_nr!(FS_IOC_SETPATHXATTR, 'f' as u32, 1, FsPathXattrDataBuffer);
205*bb4ee6a4SAndroid Build Coastguard Worker
206*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)]
207*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, Copy, AsBytes, FromZeroes, FromBytes)]
208*bb4ee6a4SAndroid Build Coastguard Worker struct fsverity_enable_arg {
209*bb4ee6a4SAndroid Build Coastguard Worker _version: u32,
210*bb4ee6a4SAndroid Build Coastguard Worker _hash_algorithm: u32,
211*bb4ee6a4SAndroid Build Coastguard Worker _block_size: u32,
212*bb4ee6a4SAndroid Build Coastguard Worker salt_size: u32,
213*bb4ee6a4SAndroid Build Coastguard Worker salt_ptr: u64,
214*bb4ee6a4SAndroid Build Coastguard Worker sig_size: u32,
215*bb4ee6a4SAndroid Build Coastguard Worker __reserved1: u32,
216*bb4ee6a4SAndroid Build Coastguard Worker sig_ptr: u64,
217*bb4ee6a4SAndroid Build Coastguard Worker __reserved2: [u64; 11],
218*bb4ee6a4SAndroid Build Coastguard Worker }
219*bb4ee6a4SAndroid Build Coastguard Worker
220*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)]
221*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, Copy, AsBytes, FromZeroes, FromBytes)]
222*bb4ee6a4SAndroid Build Coastguard Worker struct fsverity_digest {
223*bb4ee6a4SAndroid Build Coastguard Worker _digest_algorithm: u16,
224*bb4ee6a4SAndroid Build Coastguard Worker digest_size: u16,
225*bb4ee6a4SAndroid Build Coastguard Worker // __u8 digest[];
226*bb4ee6a4SAndroid Build Coastguard Worker }
227*bb4ee6a4SAndroid Build Coastguard Worker
228*bb4ee6a4SAndroid Build Coastguard Worker ioctl_iow_nr!(FS_IOC_ENABLE_VERITY, 'f' as u32, 133, fsverity_enable_arg);
229*bb4ee6a4SAndroid Build Coastguard Worker ioctl_iowr_nr!(FS_IOC_MEASURE_VERITY, 'f' as u32, 134, fsverity_digest);
230*bb4ee6a4SAndroid Build Coastguard Worker
231*bb4ee6a4SAndroid Build Coastguard Worker pub type Inode = u64;
232*bb4ee6a4SAndroid Build Coastguard Worker type Handle = u64;
233*bb4ee6a4SAndroid Build Coastguard Worker
234*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq)]
235*bb4ee6a4SAndroid Build Coastguard Worker struct InodeAltKey {
236*bb4ee6a4SAndroid Build Coastguard Worker ino: libc::ino64_t,
237*bb4ee6a4SAndroid Build Coastguard Worker dev: libc::dev_t,
238*bb4ee6a4SAndroid Build Coastguard Worker }
239*bb4ee6a4SAndroid Build Coastguard Worker
240*bb4ee6a4SAndroid Build Coastguard Worker #[derive(PartialEq, Eq, Debug)]
241*bb4ee6a4SAndroid Build Coastguard Worker enum FileType {
242*bb4ee6a4SAndroid Build Coastguard Worker Regular,
243*bb4ee6a4SAndroid Build Coastguard Worker Directory,
244*bb4ee6a4SAndroid Build Coastguard Worker Other,
245*bb4ee6a4SAndroid Build Coastguard Worker }
246*bb4ee6a4SAndroid Build Coastguard Worker
247*bb4ee6a4SAndroid Build Coastguard Worker impl From<libc::mode_t> for FileType {
from(mode: libc::mode_t) -> Self248*bb4ee6a4SAndroid Build Coastguard Worker fn from(mode: libc::mode_t) -> Self {
249*bb4ee6a4SAndroid Build Coastguard Worker match mode & libc::S_IFMT {
250*bb4ee6a4SAndroid Build Coastguard Worker libc::S_IFREG => FileType::Regular,
251*bb4ee6a4SAndroid Build Coastguard Worker libc::S_IFDIR => FileType::Directory,
252*bb4ee6a4SAndroid Build Coastguard Worker _ => FileType::Other,
253*bb4ee6a4SAndroid Build Coastguard Worker }
254*bb4ee6a4SAndroid Build Coastguard Worker }
255*bb4ee6a4SAndroid Build Coastguard Worker }
256*bb4ee6a4SAndroid Build Coastguard Worker
257*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug)]
258*bb4ee6a4SAndroid Build Coastguard Worker struct InodeData {
259*bb4ee6a4SAndroid Build Coastguard Worker inode: Inode,
260*bb4ee6a4SAndroid Build Coastguard Worker // (File, open_flags)
261*bb4ee6a4SAndroid Build Coastguard Worker file: Mutex<(File, libc::c_int)>,
262*bb4ee6a4SAndroid Build Coastguard Worker refcount: AtomicU64,
263*bb4ee6a4SAndroid Build Coastguard Worker filetype: FileType,
264*bb4ee6a4SAndroid Build Coastguard Worker path: String,
265*bb4ee6a4SAndroid Build Coastguard Worker }
266*bb4ee6a4SAndroid Build Coastguard Worker
267*bb4ee6a4SAndroid Build Coastguard Worker impl AsRawDescriptor for InodeData {
as_raw_descriptor(&self) -> RawDescriptor268*bb4ee6a4SAndroid Build Coastguard Worker fn as_raw_descriptor(&self) -> RawDescriptor {
269*bb4ee6a4SAndroid Build Coastguard Worker self.file.lock().0.as_raw_descriptor()
270*bb4ee6a4SAndroid Build Coastguard Worker }
271*bb4ee6a4SAndroid Build Coastguard Worker }
272*bb4ee6a4SAndroid Build Coastguard Worker
273*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug)]
274*bb4ee6a4SAndroid Build Coastguard Worker struct HandleData {
275*bb4ee6a4SAndroid Build Coastguard Worker inode: Inode,
276*bb4ee6a4SAndroid Build Coastguard Worker file: Mutex<File>,
277*bb4ee6a4SAndroid Build Coastguard Worker }
278*bb4ee6a4SAndroid Build Coastguard Worker
279*bb4ee6a4SAndroid Build Coastguard Worker impl AsRawDescriptor for HandleData {
as_raw_descriptor(&self) -> RawDescriptor280*bb4ee6a4SAndroid Build Coastguard Worker fn as_raw_descriptor(&self) -> RawDescriptor {
281*bb4ee6a4SAndroid Build Coastguard Worker self.file.lock().as_raw_descriptor()
282*bb4ee6a4SAndroid Build Coastguard Worker }
283*bb4ee6a4SAndroid Build Coastguard Worker }
284*bb4ee6a4SAndroid Build Coastguard Worker
285*bb4ee6a4SAndroid Build Coastguard Worker macro_rules! scoped_cred {
286*bb4ee6a4SAndroid Build Coastguard Worker ($name:ident, $ty:ty, $syscall_nr:expr) => {
287*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug)]
288*bb4ee6a4SAndroid Build Coastguard Worker struct $name {
289*bb4ee6a4SAndroid Build Coastguard Worker old: $ty,
290*bb4ee6a4SAndroid Build Coastguard Worker }
291*bb4ee6a4SAndroid Build Coastguard Worker
292*bb4ee6a4SAndroid Build Coastguard Worker impl $name {
293*bb4ee6a4SAndroid Build Coastguard Worker // Changes the effective uid/gid of the current thread to `val`. Changes the thread's
294*bb4ee6a4SAndroid Build Coastguard Worker // credentials back to `old` when the returned struct is dropped.
295*bb4ee6a4SAndroid Build Coastguard Worker fn new(val: $ty, old: $ty) -> io::Result<Option<$name>> {
296*bb4ee6a4SAndroid Build Coastguard Worker if val == old {
297*bb4ee6a4SAndroid Build Coastguard Worker // Nothing to do since we already have the correct value.
298*bb4ee6a4SAndroid Build Coastguard Worker return Ok(None);
299*bb4ee6a4SAndroid Build Coastguard Worker }
300*bb4ee6a4SAndroid Build Coastguard Worker
301*bb4ee6a4SAndroid Build Coastguard Worker // We want credential changes to be per-thread because otherwise
302*bb4ee6a4SAndroid Build Coastguard Worker // we might interfere with operations being carried out on other
303*bb4ee6a4SAndroid Build Coastguard Worker // threads with different uids/gids. However, posix requires that
304*bb4ee6a4SAndroid Build Coastguard Worker // all threads in a process share the same credentials. To do this
305*bb4ee6a4SAndroid Build Coastguard Worker // libc uses signals to ensure that when one thread changes its
306*bb4ee6a4SAndroid Build Coastguard Worker // credentials the other threads do the same thing.
307*bb4ee6a4SAndroid Build Coastguard Worker //
308*bb4ee6a4SAndroid Build Coastguard Worker // So instead we invoke the syscall directly in order to get around
309*bb4ee6a4SAndroid Build Coastguard Worker // this limitation. Another option is to use the setfsuid and
310*bb4ee6a4SAndroid Build Coastguard Worker // setfsgid systems calls. However since those calls have no way to
311*bb4ee6a4SAndroid Build Coastguard Worker // return an error, it's preferable to do this instead.
312*bb4ee6a4SAndroid Build Coastguard Worker
313*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this call is safe because it doesn't modify any memory and we
314*bb4ee6a4SAndroid Build Coastguard Worker // check the return value.
315*bb4ee6a4SAndroid Build Coastguard Worker let res = unsafe { libc::syscall($syscall_nr, -1, val, -1) };
316*bb4ee6a4SAndroid Build Coastguard Worker if res == 0 {
317*bb4ee6a4SAndroid Build Coastguard Worker Ok(Some($name { old }))
318*bb4ee6a4SAndroid Build Coastguard Worker } else {
319*bb4ee6a4SAndroid Build Coastguard Worker Err(io::Error::last_os_error())
320*bb4ee6a4SAndroid Build Coastguard Worker }
321*bb4ee6a4SAndroid Build Coastguard Worker }
322*bb4ee6a4SAndroid Build Coastguard Worker }
323*bb4ee6a4SAndroid Build Coastguard Worker
324*bb4ee6a4SAndroid Build Coastguard Worker impl Drop for $name {
325*bb4ee6a4SAndroid Build Coastguard Worker fn drop(&mut self) {
326*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: trivially safe
327*bb4ee6a4SAndroid Build Coastguard Worker let res = unsafe { libc::syscall($syscall_nr, -1, self.old, -1) };
328*bb4ee6a4SAndroid Build Coastguard Worker if res < 0 {
329*bb4ee6a4SAndroid Build Coastguard Worker error!(
330*bb4ee6a4SAndroid Build Coastguard Worker "failed to change credentials back to {}: {}",
331*bb4ee6a4SAndroid Build Coastguard Worker self.old,
332*bb4ee6a4SAndroid Build Coastguard Worker io::Error::last_os_error(),
333*bb4ee6a4SAndroid Build Coastguard Worker );
334*bb4ee6a4SAndroid Build Coastguard Worker }
335*bb4ee6a4SAndroid Build Coastguard Worker }
336*bb4ee6a4SAndroid Build Coastguard Worker }
337*bb4ee6a4SAndroid Build Coastguard Worker };
338*bb4ee6a4SAndroid Build Coastguard Worker }
339*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(not(target_arch = "arm"))]
340*bb4ee6a4SAndroid Build Coastguard Worker scoped_cred!(ScopedUid, libc::uid_t, libc::SYS_setresuid);
341*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "arm")]
342*bb4ee6a4SAndroid Build Coastguard Worker scoped_cred!(ScopedUid, libc::uid_t, libc::SYS_setresuid32);
343*bb4ee6a4SAndroid Build Coastguard Worker
344*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(not(target_arch = "arm"))]
345*bb4ee6a4SAndroid Build Coastguard Worker scoped_cred!(ScopedGid, libc::gid_t, libc::SYS_setresgid);
346*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "arm")]
347*bb4ee6a4SAndroid Build Coastguard Worker scoped_cred!(ScopedGid, libc::gid_t, libc::SYS_setresgid32);
348*bb4ee6a4SAndroid Build Coastguard Worker
349*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(not(target_arch = "arm"))]
350*bb4ee6a4SAndroid Build Coastguard Worker const SYS_GETEUID: libc::c_long = libc::SYS_geteuid;
351*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "arm")]
352*bb4ee6a4SAndroid Build Coastguard Worker const SYS_GETEUID: libc::c_long = libc::SYS_geteuid32;
353*bb4ee6a4SAndroid Build Coastguard Worker
354*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(not(target_arch = "arm"))]
355*bb4ee6a4SAndroid Build Coastguard Worker const SYS_GETEGID: libc::c_long = libc::SYS_getegid;
356*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "arm")]
357*bb4ee6a4SAndroid Build Coastguard Worker const SYS_GETEGID: libc::c_long = libc::SYS_getegid32;
358*bb4ee6a4SAndroid Build Coastguard Worker
359*bb4ee6a4SAndroid Build Coastguard Worker thread_local! {
360*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: both calls take no parameters and only return an integer value. The kernel also
361*bb4ee6a4SAndroid Build Coastguard Worker // guarantees that they can never fail.
362*bb4ee6a4SAndroid Build Coastguard Worker static THREAD_EUID: libc::uid_t = unsafe { libc::syscall(SYS_GETEUID) as libc::uid_t };
363*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: both calls take no parameters and only return an integer value. The kernel also
364*bb4ee6a4SAndroid Build Coastguard Worker // guarantees that they can never fail.
365*bb4ee6a4SAndroid Build Coastguard Worker static THREAD_EGID: libc::gid_t = unsafe { libc::syscall(SYS_GETEGID) as libc::gid_t };
366*bb4ee6a4SAndroid Build Coastguard Worker }
367*bb4ee6a4SAndroid Build Coastguard Worker
set_creds( uid: libc::uid_t, gid: libc::gid_t, ) -> io::Result<(Option<ScopedUid>, Option<ScopedGid>)>368*bb4ee6a4SAndroid Build Coastguard Worker fn set_creds(
369*bb4ee6a4SAndroid Build Coastguard Worker uid: libc::uid_t,
370*bb4ee6a4SAndroid Build Coastguard Worker gid: libc::gid_t,
371*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<(Option<ScopedUid>, Option<ScopedGid>)> {
372*bb4ee6a4SAndroid Build Coastguard Worker let olduid = THREAD_EUID.with(|uid| *uid);
373*bb4ee6a4SAndroid Build Coastguard Worker let oldgid = THREAD_EGID.with(|gid| *gid);
374*bb4ee6a4SAndroid Build Coastguard Worker
375*bb4ee6a4SAndroid Build Coastguard Worker // We have to change the gid before we change the uid because if we change the uid first then we
376*bb4ee6a4SAndroid Build Coastguard Worker // lose the capability to change the gid. However changing back can happen in any order.
377*bb4ee6a4SAndroid Build Coastguard Worker ScopedGid::new(gid, oldgid).and_then(|gid| Ok((ScopedUid::new(uid, olduid)?, gid)))
378*bb4ee6a4SAndroid Build Coastguard Worker }
379*bb4ee6a4SAndroid Build Coastguard Worker
380*bb4ee6a4SAndroid Build Coastguard Worker thread_local!(static THREAD_FSCREATE: RefCell<Option<File>> = const { RefCell::new(None) });
381*bb4ee6a4SAndroid Build Coastguard Worker
382*bb4ee6a4SAndroid Build Coastguard Worker // Opens and returns a write-only handle to /proc/thread-self/attr/fscreate. Panics if it fails to
383*bb4ee6a4SAndroid Build Coastguard Worker // open the file.
open_fscreate(proc: &File) -> File384*bb4ee6a4SAndroid Build Coastguard Worker fn open_fscreate(proc: &File) -> File {
385*bb4ee6a4SAndroid Build Coastguard Worker let fscreate = c"thread-self/attr/fscreate";
386*bb4ee6a4SAndroid Build Coastguard Worker
387*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value.
388*bb4ee6a4SAndroid Build Coastguard Worker let raw_descriptor = unsafe {
389*bb4ee6a4SAndroid Build Coastguard Worker libc::openat(
390*bb4ee6a4SAndroid Build Coastguard Worker proc.as_raw_descriptor(),
391*bb4ee6a4SAndroid Build Coastguard Worker fscreate.as_ptr(),
392*bb4ee6a4SAndroid Build Coastguard Worker libc::O_CLOEXEC | libc::O_WRONLY,
393*bb4ee6a4SAndroid Build Coastguard Worker )
394*bb4ee6a4SAndroid Build Coastguard Worker };
395*bb4ee6a4SAndroid Build Coastguard Worker
396*bb4ee6a4SAndroid Build Coastguard Worker // We don't expect this to fail and we're not in a position to return an error here so just
397*bb4ee6a4SAndroid Build Coastguard Worker // panic.
398*bb4ee6a4SAndroid Build Coastguard Worker if raw_descriptor < 0 {
399*bb4ee6a4SAndroid Build Coastguard Worker panic!(
400*bb4ee6a4SAndroid Build Coastguard Worker "Failed to open /proc/thread-self/attr/fscreate: {}",
401*bb4ee6a4SAndroid Build Coastguard Worker io::Error::last_os_error()
402*bb4ee6a4SAndroid Build Coastguard Worker );
403*bb4ee6a4SAndroid Build Coastguard Worker }
404*bb4ee6a4SAndroid Build Coastguard Worker
405*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: safe because we just opened this descriptor.
406*bb4ee6a4SAndroid Build Coastguard Worker unsafe { File::from_raw_descriptor(raw_descriptor) }
407*bb4ee6a4SAndroid Build Coastguard Worker }
408*bb4ee6a4SAndroid Build Coastguard Worker
409*bb4ee6a4SAndroid Build Coastguard Worker struct ScopedSecurityContext;
410*bb4ee6a4SAndroid Build Coastguard Worker
411*bb4ee6a4SAndroid Build Coastguard Worker impl ScopedSecurityContext {
new(proc: &File, ctx: &CStr) -> io::Result<ScopedSecurityContext>412*bb4ee6a4SAndroid Build Coastguard Worker fn new(proc: &File, ctx: &CStr) -> io::Result<ScopedSecurityContext> {
413*bb4ee6a4SAndroid Build Coastguard Worker THREAD_FSCREATE.with(|thread_fscreate| {
414*bb4ee6a4SAndroid Build Coastguard Worker let mut fscreate = thread_fscreate.borrow_mut();
415*bb4ee6a4SAndroid Build Coastguard Worker let file = fscreate.get_or_insert_with(|| open_fscreate(proc));
416*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value.
417*bb4ee6a4SAndroid Build Coastguard Worker let ret = unsafe {
418*bb4ee6a4SAndroid Build Coastguard Worker libc::write(
419*bb4ee6a4SAndroid Build Coastguard Worker file.as_raw_descriptor(),
420*bb4ee6a4SAndroid Build Coastguard Worker ctx.as_ptr() as *const libc::c_void,
421*bb4ee6a4SAndroid Build Coastguard Worker ctx.to_bytes_with_nul().len(),
422*bb4ee6a4SAndroid Build Coastguard Worker )
423*bb4ee6a4SAndroid Build Coastguard Worker };
424*bb4ee6a4SAndroid Build Coastguard Worker if ret < 0 {
425*bb4ee6a4SAndroid Build Coastguard Worker Err(io::Error::last_os_error())
426*bb4ee6a4SAndroid Build Coastguard Worker } else {
427*bb4ee6a4SAndroid Build Coastguard Worker Ok(ScopedSecurityContext)
428*bb4ee6a4SAndroid Build Coastguard Worker }
429*bb4ee6a4SAndroid Build Coastguard Worker })
430*bb4ee6a4SAndroid Build Coastguard Worker }
431*bb4ee6a4SAndroid Build Coastguard Worker }
432*bb4ee6a4SAndroid Build Coastguard Worker
433*bb4ee6a4SAndroid Build Coastguard Worker impl Drop for ScopedSecurityContext {
drop(&mut self)434*bb4ee6a4SAndroid Build Coastguard Worker fn drop(&mut self) {
435*bb4ee6a4SAndroid Build Coastguard Worker THREAD_FSCREATE.with(|thread_fscreate| {
436*bb4ee6a4SAndroid Build Coastguard Worker // expect is safe here because the thread local would have been initialized by the call
437*bb4ee6a4SAndroid Build Coastguard Worker // to `new` above.
438*bb4ee6a4SAndroid Build Coastguard Worker let fscreate = thread_fscreate.borrow();
439*bb4ee6a4SAndroid Build Coastguard Worker let file = fscreate
440*bb4ee6a4SAndroid Build Coastguard Worker .as_ref()
441*bb4ee6a4SAndroid Build Coastguard Worker .expect("Uninitialized thread-local when dropping ScopedSecurityContext");
442*bb4ee6a4SAndroid Build Coastguard Worker
443*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value.
444*bb4ee6a4SAndroid Build Coastguard Worker let ret = unsafe { libc::write(file.as_raw_descriptor(), ptr::null(), 0) };
445*bb4ee6a4SAndroid Build Coastguard Worker
446*bb4ee6a4SAndroid Build Coastguard Worker if ret < 0 {
447*bb4ee6a4SAndroid Build Coastguard Worker warn!(
448*bb4ee6a4SAndroid Build Coastguard Worker "Failed to restore security context: {}",
449*bb4ee6a4SAndroid Build Coastguard Worker io::Error::last_os_error()
450*bb4ee6a4SAndroid Build Coastguard Worker );
451*bb4ee6a4SAndroid Build Coastguard Worker }
452*bb4ee6a4SAndroid Build Coastguard Worker })
453*bb4ee6a4SAndroid Build Coastguard Worker }
454*bb4ee6a4SAndroid Build Coastguard Worker }
455*bb4ee6a4SAndroid Build Coastguard Worker
456*bb4ee6a4SAndroid Build Coastguard Worker struct ScopedUmask {
457*bb4ee6a4SAndroid Build Coastguard Worker old: libc::mode_t,
458*bb4ee6a4SAndroid Build Coastguard Worker mask: libc::mode_t,
459*bb4ee6a4SAndroid Build Coastguard Worker }
460*bb4ee6a4SAndroid Build Coastguard Worker
461*bb4ee6a4SAndroid Build Coastguard Worker impl ScopedUmask {
new(mask: libc::mode_t) -> ScopedUmask462*bb4ee6a4SAndroid Build Coastguard Worker fn new(mask: libc::mode_t) -> ScopedUmask {
463*bb4ee6a4SAndroid Build Coastguard Worker ScopedUmask {
464*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and always succeeds.
465*bb4ee6a4SAndroid Build Coastguard Worker old: unsafe { libc::umask(mask) },
466*bb4ee6a4SAndroid Build Coastguard Worker mask,
467*bb4ee6a4SAndroid Build Coastguard Worker }
468*bb4ee6a4SAndroid Build Coastguard Worker }
469*bb4ee6a4SAndroid Build Coastguard Worker }
470*bb4ee6a4SAndroid Build Coastguard Worker
471*bb4ee6a4SAndroid Build Coastguard Worker impl Drop for ScopedUmask {
drop(&mut self)472*bb4ee6a4SAndroid Build Coastguard Worker fn drop(&mut self) {
473*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and always succeeds.
474*bb4ee6a4SAndroid Build Coastguard Worker let previous = unsafe { libc::umask(self.old) };
475*bb4ee6a4SAndroid Build Coastguard Worker debug_assert_eq!(
476*bb4ee6a4SAndroid Build Coastguard Worker previous, self.mask,
477*bb4ee6a4SAndroid Build Coastguard Worker "umask changed while holding ScopedUmask"
478*bb4ee6a4SAndroid Build Coastguard Worker );
479*bb4ee6a4SAndroid Build Coastguard Worker }
480*bb4ee6a4SAndroid Build Coastguard Worker }
481*bb4ee6a4SAndroid Build Coastguard Worker
482*bb4ee6a4SAndroid Build Coastguard Worker struct ScopedFsetid(Caps);
483*bb4ee6a4SAndroid Build Coastguard Worker impl Drop for ScopedFsetid {
drop(&mut self)484*bb4ee6a4SAndroid Build Coastguard Worker fn drop(&mut self) {
485*bb4ee6a4SAndroid Build Coastguard Worker if let Err(e) = raise_cap_fsetid(&mut self.0) {
486*bb4ee6a4SAndroid Build Coastguard Worker error!(
487*bb4ee6a4SAndroid Build Coastguard Worker "Failed to restore CAP_FSETID: {}. Some operations may be broken.",
488*bb4ee6a4SAndroid Build Coastguard Worker e
489*bb4ee6a4SAndroid Build Coastguard Worker )
490*bb4ee6a4SAndroid Build Coastguard Worker }
491*bb4ee6a4SAndroid Build Coastguard Worker }
492*bb4ee6a4SAndroid Build Coastguard Worker }
493*bb4ee6a4SAndroid Build Coastguard Worker
raise_cap_fsetid(c: &mut Caps) -> io::Result<()>494*bb4ee6a4SAndroid Build Coastguard Worker fn raise_cap_fsetid(c: &mut Caps) -> io::Result<()> {
495*bb4ee6a4SAndroid Build Coastguard Worker c.update(&[Capability::Fsetid], CapSet::Effective, CapValue::Set)?;
496*bb4ee6a4SAndroid Build Coastguard Worker c.apply()
497*bb4ee6a4SAndroid Build Coastguard Worker }
498*bb4ee6a4SAndroid Build Coastguard Worker
499*bb4ee6a4SAndroid Build Coastguard Worker // Drops CAP_FSETID from the effective set for the current thread and returns an RAII guard that
500*bb4ee6a4SAndroid Build Coastguard Worker // adds the capability back when it is dropped.
drop_cap_fsetid() -> io::Result<ScopedFsetid>501*bb4ee6a4SAndroid Build Coastguard Worker fn drop_cap_fsetid() -> io::Result<ScopedFsetid> {
502*bb4ee6a4SAndroid Build Coastguard Worker let mut caps = Caps::for_current_thread()?;
503*bb4ee6a4SAndroid Build Coastguard Worker caps.update(&[Capability::Fsetid], CapSet::Effective, CapValue::Clear)?;
504*bb4ee6a4SAndroid Build Coastguard Worker caps.apply()?;
505*bb4ee6a4SAndroid Build Coastguard Worker Ok(ScopedFsetid(caps))
506*bb4ee6a4SAndroid Build Coastguard Worker }
507*bb4ee6a4SAndroid Build Coastguard Worker
ebadf() -> io::Error508*bb4ee6a4SAndroid Build Coastguard Worker fn ebadf() -> io::Error {
509*bb4ee6a4SAndroid Build Coastguard Worker io::Error::from_raw_os_error(libc::EBADF)
510*bb4ee6a4SAndroid Build Coastguard Worker }
511*bb4ee6a4SAndroid Build Coastguard Worker
eexist() -> io::Error512*bb4ee6a4SAndroid Build Coastguard Worker fn eexist() -> io::Error {
513*bb4ee6a4SAndroid Build Coastguard Worker io::Error::from_raw_os_error(libc::EEXIST)
514*bb4ee6a4SAndroid Build Coastguard Worker }
515*bb4ee6a4SAndroid Build Coastguard Worker
stat<F: AsRawDescriptor + ?Sized>(f: &F) -> io::Result<libc::stat64>516*bb4ee6a4SAndroid Build Coastguard Worker fn stat<F: AsRawDescriptor + ?Sized>(f: &F) -> io::Result<libc::stat64> {
517*bb4ee6a4SAndroid Build Coastguard Worker let mut st: MaybeUninit<libc::stat64> = MaybeUninit::<libc::stat64>::zeroed();
518*bb4ee6a4SAndroid Build Coastguard Worker
519*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: the kernel will only write data in `st` and we check the return value.
520*bb4ee6a4SAndroid Build Coastguard Worker syscall!(unsafe {
521*bb4ee6a4SAndroid Build Coastguard Worker libc::fstatat64(
522*bb4ee6a4SAndroid Build Coastguard Worker f.as_raw_descriptor(),
523*bb4ee6a4SAndroid Build Coastguard Worker EMPTY_CSTR.as_ptr(),
524*bb4ee6a4SAndroid Build Coastguard Worker st.as_mut_ptr(),
525*bb4ee6a4SAndroid Build Coastguard Worker libc::AT_EMPTY_PATH | libc::AT_SYMLINK_NOFOLLOW,
526*bb4ee6a4SAndroid Build Coastguard Worker )
527*bb4ee6a4SAndroid Build Coastguard Worker })?;
528*bb4ee6a4SAndroid Build Coastguard Worker
529*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: the kernel guarantees that the struct is now fully initialized.
530*bb4ee6a4SAndroid Build Coastguard Worker Ok(unsafe { st.assume_init() })
531*bb4ee6a4SAndroid Build Coastguard Worker }
532*bb4ee6a4SAndroid Build Coastguard Worker
statat<D: AsRawDescriptor>(dir: &D, name: &CStr) -> io::Result<libc::stat64>533*bb4ee6a4SAndroid Build Coastguard Worker fn statat<D: AsRawDescriptor>(dir: &D, name: &CStr) -> io::Result<libc::stat64> {
534*bb4ee6a4SAndroid Build Coastguard Worker let mut st = MaybeUninit::<libc::stat64>::zeroed();
535*bb4ee6a4SAndroid Build Coastguard Worker
536*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: the kernel will only write data in `st` and we check the return value.
537*bb4ee6a4SAndroid Build Coastguard Worker syscall!(unsafe {
538*bb4ee6a4SAndroid Build Coastguard Worker libc::fstatat64(
539*bb4ee6a4SAndroid Build Coastguard Worker dir.as_raw_descriptor(),
540*bb4ee6a4SAndroid Build Coastguard Worker name.as_ptr(),
541*bb4ee6a4SAndroid Build Coastguard Worker st.as_mut_ptr(),
542*bb4ee6a4SAndroid Build Coastguard Worker libc::AT_SYMLINK_NOFOLLOW,
543*bb4ee6a4SAndroid Build Coastguard Worker )
544*bb4ee6a4SAndroid Build Coastguard Worker })?;
545*bb4ee6a4SAndroid Build Coastguard Worker
546*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: the kernel guarantees that the struct is now fully initialized.
547*bb4ee6a4SAndroid Build Coastguard Worker Ok(unsafe { st.assume_init() })
548*bb4ee6a4SAndroid Build Coastguard Worker }
549*bb4ee6a4SAndroid Build Coastguard Worker
550*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
is_android_project_id(project_id: u32) -> bool551*bb4ee6a4SAndroid Build Coastguard Worker fn is_android_project_id(project_id: u32) -> bool {
552*bb4ee6a4SAndroid Build Coastguard Worker // The following constants defines the valid range of project ID used by
553*bb4ee6a4SAndroid Build Coastguard Worker // Android and are taken from android_filesystem_config.h in Android
554*bb4ee6a4SAndroid Build Coastguard Worker // codebase.
555*bb4ee6a4SAndroid Build Coastguard Worker //
556*bb4ee6a4SAndroid Build Coastguard Worker // Project IDs reserved for Android files on external storage. Total 100 IDs
557*bb4ee6a4SAndroid Build Coastguard Worker // from PROJECT_ID_EXT_DEFAULT (1000) are reserved.
558*bb4ee6a4SAndroid Build Coastguard Worker const PROJECT_ID_FOR_ANDROID_FILES: std::ops::RangeInclusive<u32> = 1000..=1099;
559*bb4ee6a4SAndroid Build Coastguard Worker // Project IDs reserved for Android apps.
560*bb4ee6a4SAndroid Build Coastguard Worker // The lower-limit of the range is PROJECT_ID_EXT_DATA_START.
561*bb4ee6a4SAndroid Build Coastguard Worker // The upper-limit of the range differs before and after T. Here we use that
562*bb4ee6a4SAndroid Build Coastguard Worker // of T (PROJECT_ID_APP_CACHE_END) as it is larger.
563*bb4ee6a4SAndroid Build Coastguard Worker const PROJECT_ID_FOR_ANDROID_APPS: std::ops::RangeInclusive<u32> = 20000..=69999;
564*bb4ee6a4SAndroid Build Coastguard Worker
565*bb4ee6a4SAndroid Build Coastguard Worker PROJECT_ID_FOR_ANDROID_FILES.contains(&project_id)
566*bb4ee6a4SAndroid Build Coastguard Worker || PROJECT_ID_FOR_ANDROID_APPS.contains(&project_id)
567*bb4ee6a4SAndroid Build Coastguard Worker }
568*bb4ee6a4SAndroid Build Coastguard Worker
569*bb4ee6a4SAndroid Build Coastguard Worker /// Per-directory cache for `PassthroughFs::ascii_casefold_lookup()`.
570*bb4ee6a4SAndroid Build Coastguard Worker ///
571*bb4ee6a4SAndroid Build Coastguard Worker /// The key of the underlying `BTreeMap` is a lower-cased file name in the direcoty.
572*bb4ee6a4SAndroid Build Coastguard Worker /// The value is the case-sensitive file name stored in the host file system.
573*bb4ee6a4SAndroid Build Coastguard Worker /// We assume that if PassthroughFs has exclusive access to the filesystem, this cache exhaustively
574*bb4ee6a4SAndroid Build Coastguard Worker /// covers all file names that exist within the directory.
575*bb4ee6a4SAndroid Build Coastguard Worker /// So every `PassthroughFs`'s handler that adds or removes files in the directory is expected to
576*bb4ee6a4SAndroid Build Coastguard Worker /// update this cache.
577*bb4ee6a4SAndroid Build Coastguard Worker struct CasefoldCache(BTreeMap<Vec<u8>, CString>);
578*bb4ee6a4SAndroid Build Coastguard Worker
579*bb4ee6a4SAndroid Build Coastguard Worker impl CasefoldCache {
new(dir: &InodeData) -> io::Result<Self>580*bb4ee6a4SAndroid Build Coastguard Worker fn new(dir: &InodeData) -> io::Result<Self> {
581*bb4ee6a4SAndroid Build Coastguard Worker let mut mp = BTreeMap::new();
582*bb4ee6a4SAndroid Build Coastguard Worker
583*bb4ee6a4SAndroid Build Coastguard Worker let mut buf = [0u8; 1024];
584*bb4ee6a4SAndroid Build Coastguard Worker let mut offset = 0;
585*bb4ee6a4SAndroid Build Coastguard Worker loop {
586*bb4ee6a4SAndroid Build Coastguard Worker let mut read_dir = ReadDir::new(dir, offset, &mut buf[..])?;
587*bb4ee6a4SAndroid Build Coastguard Worker if read_dir.remaining() == 0 {
588*bb4ee6a4SAndroid Build Coastguard Worker break;
589*bb4ee6a4SAndroid Build Coastguard Worker }
590*bb4ee6a4SAndroid Build Coastguard Worker
591*bb4ee6a4SAndroid Build Coastguard Worker while let Some(entry) = read_dir.next() {
592*bb4ee6a4SAndroid Build Coastguard Worker offset = entry.offset as libc::off64_t;
593*bb4ee6a4SAndroid Build Coastguard Worker let entry_name = entry.name;
594*bb4ee6a4SAndroid Build Coastguard Worker mp.insert(
595*bb4ee6a4SAndroid Build Coastguard Worker entry_name.to_bytes().to_ascii_lowercase(),
596*bb4ee6a4SAndroid Build Coastguard Worker entry_name.to_owned(),
597*bb4ee6a4SAndroid Build Coastguard Worker );
598*bb4ee6a4SAndroid Build Coastguard Worker }
599*bb4ee6a4SAndroid Build Coastguard Worker }
600*bb4ee6a4SAndroid Build Coastguard Worker Ok(Self(mp))
601*bb4ee6a4SAndroid Build Coastguard Worker }
602*bb4ee6a4SAndroid Build Coastguard Worker
insert(&mut self, name: &CStr)603*bb4ee6a4SAndroid Build Coastguard Worker fn insert(&mut self, name: &CStr) {
604*bb4ee6a4SAndroid Build Coastguard Worker let lower_case = name.to_bytes().to_ascii_lowercase();
605*bb4ee6a4SAndroid Build Coastguard Worker self.0.insert(lower_case, name.into());
606*bb4ee6a4SAndroid Build Coastguard Worker }
607*bb4ee6a4SAndroid Build Coastguard Worker
lookup(&self, name: &[u8]) -> Option<CString>608*bb4ee6a4SAndroid Build Coastguard Worker fn lookup(&self, name: &[u8]) -> Option<CString> {
609*bb4ee6a4SAndroid Build Coastguard Worker let lower = name.to_ascii_lowercase();
610*bb4ee6a4SAndroid Build Coastguard Worker self.0.get(&lower).cloned()
611*bb4ee6a4SAndroid Build Coastguard Worker }
612*bb4ee6a4SAndroid Build Coastguard Worker
remove(&mut self, name: &CStr)613*bb4ee6a4SAndroid Build Coastguard Worker fn remove(&mut self, name: &CStr) {
614*bb4ee6a4SAndroid Build Coastguard Worker let lower_case = name.to_bytes().to_ascii_lowercase();
615*bb4ee6a4SAndroid Build Coastguard Worker self.0.remove(&lower_case);
616*bb4ee6a4SAndroid Build Coastguard Worker }
617*bb4ee6a4SAndroid Build Coastguard Worker }
618*bb4ee6a4SAndroid Build Coastguard Worker
619*bb4ee6a4SAndroid Build Coastguard Worker /// Time expiring mapping from an inode of a directory to `CasefoldCache` for the directory.
620*bb4ee6a4SAndroid Build Coastguard Worker /// Each entry will be expired after `timeout`.
621*bb4ee6a4SAndroid Build Coastguard Worker /// When ascii_casefold is disabled, this struct does nothing.
622*bb4ee6a4SAndroid Build Coastguard Worker struct ExpiringCasefoldLookupCaches {
623*bb4ee6a4SAndroid Build Coastguard Worker inner: ExpiringMap<Inode, CasefoldCache>,
624*bb4ee6a4SAndroid Build Coastguard Worker }
625*bb4ee6a4SAndroid Build Coastguard Worker
626*bb4ee6a4SAndroid Build Coastguard Worker impl ExpiringCasefoldLookupCaches {
new(timeout: Duration) -> Self627*bb4ee6a4SAndroid Build Coastguard Worker fn new(timeout: Duration) -> Self {
628*bb4ee6a4SAndroid Build Coastguard Worker Self {
629*bb4ee6a4SAndroid Build Coastguard Worker inner: ExpiringMap::new(timeout),
630*bb4ee6a4SAndroid Build Coastguard Worker }
631*bb4ee6a4SAndroid Build Coastguard Worker }
632*bb4ee6a4SAndroid Build Coastguard Worker
insert(&mut self, parent: Inode, name: &CStr)633*bb4ee6a4SAndroid Build Coastguard Worker fn insert(&mut self, parent: Inode, name: &CStr) {
634*bb4ee6a4SAndroid Build Coastguard Worker if let Some(dir_cache) = self.inner.get_mut(&parent) {
635*bb4ee6a4SAndroid Build Coastguard Worker dir_cache.insert(name);
636*bb4ee6a4SAndroid Build Coastguard Worker }
637*bb4ee6a4SAndroid Build Coastguard Worker }
638*bb4ee6a4SAndroid Build Coastguard Worker
remove(&mut self, parent: Inode, name: &CStr)639*bb4ee6a4SAndroid Build Coastguard Worker fn remove(&mut self, parent: Inode, name: &CStr) {
640*bb4ee6a4SAndroid Build Coastguard Worker if let Some(dir_cache) = self.inner.get_mut(&parent) {
641*bb4ee6a4SAndroid Build Coastguard Worker dir_cache.remove(name);
642*bb4ee6a4SAndroid Build Coastguard Worker }
643*bb4ee6a4SAndroid Build Coastguard Worker }
644*bb4ee6a4SAndroid Build Coastguard Worker
forget(&mut self, parent: Inode)645*bb4ee6a4SAndroid Build Coastguard Worker fn forget(&mut self, parent: Inode) {
646*bb4ee6a4SAndroid Build Coastguard Worker self.inner.remove(&parent);
647*bb4ee6a4SAndroid Build Coastguard Worker }
648*bb4ee6a4SAndroid Build Coastguard Worker
649*bb4ee6a4SAndroid Build Coastguard Worker /// Get `CasefoldCache` for the given directory.
650*bb4ee6a4SAndroid Build Coastguard Worker /// If the cache doesn't exist, generate it by fetching directory information with
651*bb4ee6a4SAndroid Build Coastguard Worker /// `getdents64()`.
get(&mut self, parent: &InodeData) -> io::Result<&CasefoldCache>652*bb4ee6a4SAndroid Build Coastguard Worker fn get(&mut self, parent: &InodeData) -> io::Result<&CasefoldCache> {
653*bb4ee6a4SAndroid Build Coastguard Worker self.inner
654*bb4ee6a4SAndroid Build Coastguard Worker .get_or_insert_with(&parent.inode, || CasefoldCache::new(parent))
655*bb4ee6a4SAndroid Build Coastguard Worker }
656*bb4ee6a4SAndroid Build Coastguard Worker
657*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
exists_in_cache(&mut self, parent: Inode, name: &CStr) -> bool658*bb4ee6a4SAndroid Build Coastguard Worker fn exists_in_cache(&mut self, parent: Inode, name: &CStr) -> bool {
659*bb4ee6a4SAndroid Build Coastguard Worker if let Some(dir_cache) = self.inner.get(&parent) {
660*bb4ee6a4SAndroid Build Coastguard Worker dir_cache.lookup(name.to_bytes()).is_some()
661*bb4ee6a4SAndroid Build Coastguard Worker } else {
662*bb4ee6a4SAndroid Build Coastguard Worker false
663*bb4ee6a4SAndroid Build Coastguard Worker }
664*bb4ee6a4SAndroid Build Coastguard Worker }
665*bb4ee6a4SAndroid Build Coastguard Worker }
666*bb4ee6a4SAndroid Build Coastguard Worker
667*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "fs_permission_translation")]
668*bb4ee6a4SAndroid Build Coastguard Worker impl PermissionData {
need_set_permission(&self, path: &str) -> bool669*bb4ee6a4SAndroid Build Coastguard Worker pub(crate) fn need_set_permission(&self, path: &str) -> bool {
670*bb4ee6a4SAndroid Build Coastguard Worker path.starts_with(&self.perm_path)
671*bb4ee6a4SAndroid Build Coastguard Worker }
672*bb4ee6a4SAndroid Build Coastguard Worker }
673*bb4ee6a4SAndroid Build Coastguard Worker
674*bb4ee6a4SAndroid Build Coastguard Worker /// A file system that simply "passes through" all requests it receives to the underlying file
675*bb4ee6a4SAndroid Build Coastguard Worker /// system. To keep the implementation simple it servers the contents of its root directory. Users
676*bb4ee6a4SAndroid Build Coastguard Worker /// that wish to serve only a specific directory should set up the environment so that that
677*bb4ee6a4SAndroid Build Coastguard Worker /// directory ends up as the root of the file system process. One way to accomplish this is via a
678*bb4ee6a4SAndroid Build Coastguard Worker /// combination of mount namespaces and the pivot_root system call.
679*bb4ee6a4SAndroid Build Coastguard Worker pub struct PassthroughFs {
680*bb4ee6a4SAndroid Build Coastguard Worker // Mutex that must be acquired before executing a process-wide operation such as fchdir.
681*bb4ee6a4SAndroid Build Coastguard Worker process_lock: Mutex<()>,
682*bb4ee6a4SAndroid Build Coastguard Worker // virtio-fs tag that the guest uses when mounting. This is only used for debugging
683*bb4ee6a4SAndroid Build Coastguard Worker // when tracing is enabled.
684*bb4ee6a4SAndroid Build Coastguard Worker tag: String,
685*bb4ee6a4SAndroid Build Coastguard Worker
686*bb4ee6a4SAndroid Build Coastguard Worker // File descriptors for various points in the file system tree.
687*bb4ee6a4SAndroid Build Coastguard Worker inodes: Mutex<MultikeyBTreeMap<Inode, InodeAltKey, Arc<InodeData>>>,
688*bb4ee6a4SAndroid Build Coastguard Worker next_inode: AtomicU64,
689*bb4ee6a4SAndroid Build Coastguard Worker
690*bb4ee6a4SAndroid Build Coastguard Worker // File descriptors for open files and directories. Unlike the fds in `inodes`, these _can_ be
691*bb4ee6a4SAndroid Build Coastguard Worker // used for reading and writing data.
692*bb4ee6a4SAndroid Build Coastguard Worker handles: Mutex<BTreeMap<Handle, Arc<HandleData>>>,
693*bb4ee6a4SAndroid Build Coastguard Worker next_handle: AtomicU64,
694*bb4ee6a4SAndroid Build Coastguard Worker
695*bb4ee6a4SAndroid Build Coastguard Worker // File descriptor pointing to the `/proc` directory. This is used to convert an fd from
696*bb4ee6a4SAndroid Build Coastguard Worker // `inodes` into one that can go into `handles`. This is accomplished by reading the
697*bb4ee6a4SAndroid Build Coastguard Worker // `self/fd/{}` symlink. We keep an open fd here in case the file system tree that we are meant
698*bb4ee6a4SAndroid Build Coastguard Worker // to be serving doesn't have access to `/proc`.
699*bb4ee6a4SAndroid Build Coastguard Worker proc: File,
700*bb4ee6a4SAndroid Build Coastguard Worker
701*bb4ee6a4SAndroid Build Coastguard Worker // Whether writeback caching is enabled for this directory. This will only be true when
702*bb4ee6a4SAndroid Build Coastguard Worker // `cfg.writeback` is true and `init` was called with `FsOptions::WRITEBACK_CACHE`.
703*bb4ee6a4SAndroid Build Coastguard Worker writeback: AtomicBool,
704*bb4ee6a4SAndroid Build Coastguard Worker
705*bb4ee6a4SAndroid Build Coastguard Worker // Whether zero message opens are supported by the kernel driver.
706*bb4ee6a4SAndroid Build Coastguard Worker zero_message_open: AtomicBool,
707*bb4ee6a4SAndroid Build Coastguard Worker
708*bb4ee6a4SAndroid Build Coastguard Worker // Whether zero message opendir is supported by the kernel driver.
709*bb4ee6a4SAndroid Build Coastguard Worker zero_message_opendir: AtomicBool,
710*bb4ee6a4SAndroid Build Coastguard Worker
711*bb4ee6a4SAndroid Build Coastguard Worker // Used to communicate with other processes using D-Bus.
712*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
713*bb4ee6a4SAndroid Build Coastguard Worker dbus_connection: Option<Mutex<dbus::blocking::Connection>>,
714*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
715*bb4ee6a4SAndroid Build Coastguard Worker dbus_fd: Option<std::os::unix::io::RawFd>,
716*bb4ee6a4SAndroid Build Coastguard Worker
717*bb4ee6a4SAndroid Build Coastguard Worker // Time-expiring cache for `ascii_casefold_lookup()`.
718*bb4ee6a4SAndroid Build Coastguard Worker // The key is an inode of a directory, and the value is a cache for the directory.
719*bb4ee6a4SAndroid Build Coastguard Worker // Each value will be expired `cfg.timeout` after it's created.
720*bb4ee6a4SAndroid Build Coastguard Worker //
721*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/267748212): Instead of per-device Mutex, we might want to have per-directory Mutex
722*bb4ee6a4SAndroid Build Coastguard Worker // if we use PassthroughFs in multi-threaded environments.
723*bb4ee6a4SAndroid Build Coastguard Worker expiring_casefold_lookup_caches: Option<Mutex<ExpiringCasefoldLookupCaches>>,
724*bb4ee6a4SAndroid Build Coastguard Worker
725*bb4ee6a4SAndroid Build Coastguard Worker // paths and coresponding permission setting set by `crosvm_client_fs_permission_set` API
726*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "fs_permission_translation")]
727*bb4ee6a4SAndroid Build Coastguard Worker permission_paths: RwLock<Vec<PermissionData>>,
728*bb4ee6a4SAndroid Build Coastguard Worker
729*bb4ee6a4SAndroid Build Coastguard Worker // paths and coresponding xattr setting set by `crosvm_client_fs_xattr_set` API
730*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
731*bb4ee6a4SAndroid Build Coastguard Worker xattr_paths: RwLock<Vec<XattrData>>,
732*bb4ee6a4SAndroid Build Coastguard Worker
733*bb4ee6a4SAndroid Build Coastguard Worker cfg: Config,
734*bb4ee6a4SAndroid Build Coastguard Worker
735*bb4ee6a4SAndroid Build Coastguard Worker // Set the root directory when pivot root isn't enabled for jailed process.
736*bb4ee6a4SAndroid Build Coastguard Worker //
737*bb4ee6a4SAndroid Build Coastguard Worker // virtio-fs typically uses mount namespaces and pivot_root for file system isolation,
738*bb4ee6a4SAndroid Build Coastguard Worker // making the jailed process's root directory "/".
739*bb4ee6a4SAndroid Build Coastguard Worker //
740*bb4ee6a4SAndroid Build Coastguard Worker // However, Android's security model prevents crosvm from having the necessary SYS_ADMIN
741*bb4ee6a4SAndroid Build Coastguard Worker // capability for mount namespaces and pivot_root. This lack of isolation means that
742*bb4ee6a4SAndroid Build Coastguard Worker // root_dir defaults to the path provided via "--shared-dir".
743*bb4ee6a4SAndroid Build Coastguard Worker root_dir: String,
744*bb4ee6a4SAndroid Build Coastguard Worker }
745*bb4ee6a4SAndroid Build Coastguard Worker
746*bb4ee6a4SAndroid Build Coastguard Worker impl std::fmt::Debug for PassthroughFs {
fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result747*bb4ee6a4SAndroid Build Coastguard Worker fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
748*bb4ee6a4SAndroid Build Coastguard Worker f.debug_struct("PassthroughFs")
749*bb4ee6a4SAndroid Build Coastguard Worker .field("tag", &self.tag)
750*bb4ee6a4SAndroid Build Coastguard Worker .field("next_inode", &self.next_inode)
751*bb4ee6a4SAndroid Build Coastguard Worker .field("next_handle", &self.next_handle)
752*bb4ee6a4SAndroid Build Coastguard Worker .field("proc", &self.proc)
753*bb4ee6a4SAndroid Build Coastguard Worker .field("writeback", &self.writeback)
754*bb4ee6a4SAndroid Build Coastguard Worker .field("zero_message_open", &self.zero_message_open)
755*bb4ee6a4SAndroid Build Coastguard Worker .field("zero_message_opendir", &self.zero_message_opendir)
756*bb4ee6a4SAndroid Build Coastguard Worker .field("cfg", &self.cfg)
757*bb4ee6a4SAndroid Build Coastguard Worker .finish()
758*bb4ee6a4SAndroid Build Coastguard Worker }
759*bb4ee6a4SAndroid Build Coastguard Worker }
760*bb4ee6a4SAndroid Build Coastguard Worker
761*bb4ee6a4SAndroid Build Coastguard Worker impl PassthroughFs {
new(tag: &str, cfg: Config) -> io::Result<PassthroughFs>762*bb4ee6a4SAndroid Build Coastguard Worker pub fn new(tag: &str, cfg: Config) -> io::Result<PassthroughFs> {
763*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value.
764*bb4ee6a4SAndroid Build Coastguard Worker let raw_descriptor = syscall!(unsafe {
765*bb4ee6a4SAndroid Build Coastguard Worker libc::openat64(
766*bb4ee6a4SAndroid Build Coastguard Worker libc::AT_FDCWD,
767*bb4ee6a4SAndroid Build Coastguard Worker PROC_CSTR.as_ptr(),
768*bb4ee6a4SAndroid Build Coastguard Worker libc::O_PATH | libc::O_NOFOLLOW | libc::O_CLOEXEC,
769*bb4ee6a4SAndroid Build Coastguard Worker )
770*bb4ee6a4SAndroid Build Coastguard Worker })?;
771*bb4ee6a4SAndroid Build Coastguard Worker
772*bb4ee6a4SAndroid Build Coastguard Worker // Privileged UIDs can use D-Bus to perform some operations.
773*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
774*bb4ee6a4SAndroid Build Coastguard Worker let (dbus_connection, dbus_fd) = if cfg.privileged_quota_uids.is_empty() {
775*bb4ee6a4SAndroid Build Coastguard Worker (None, None)
776*bb4ee6a4SAndroid Build Coastguard Worker } else {
777*bb4ee6a4SAndroid Build Coastguard Worker let mut channel = dbus::channel::Channel::get_private(dbus::channel::BusType::System)
778*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
779*bb4ee6a4SAndroid Build Coastguard Worker channel.set_watch_enabled(true);
780*bb4ee6a4SAndroid Build Coastguard Worker let dbus_fd = channel.watch().fd;
781*bb4ee6a4SAndroid Build Coastguard Worker channel.set_watch_enabled(false);
782*bb4ee6a4SAndroid Build Coastguard Worker (
783*bb4ee6a4SAndroid Build Coastguard Worker Some(Mutex::new(dbus::blocking::Connection::from(channel))),
784*bb4ee6a4SAndroid Build Coastguard Worker Some(dbus_fd),
785*bb4ee6a4SAndroid Build Coastguard Worker )
786*bb4ee6a4SAndroid Build Coastguard Worker };
787*bb4ee6a4SAndroid Build Coastguard Worker
788*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: safe because we just opened this descriptor.
789*bb4ee6a4SAndroid Build Coastguard Worker let proc = unsafe { File::from_raw_descriptor(raw_descriptor) };
790*bb4ee6a4SAndroid Build Coastguard Worker
791*bb4ee6a4SAndroid Build Coastguard Worker let expiring_casefold_lookup_caches = if cfg.ascii_casefold {
792*bb4ee6a4SAndroid Build Coastguard Worker Some(Mutex::new(ExpiringCasefoldLookupCaches::new(cfg.timeout)))
793*bb4ee6a4SAndroid Build Coastguard Worker } else {
794*bb4ee6a4SAndroid Build Coastguard Worker None
795*bb4ee6a4SAndroid Build Coastguard Worker };
796*bb4ee6a4SAndroid Build Coastguard Worker
797*bb4ee6a4SAndroid Build Coastguard Worker #[allow(unused_mut)]
798*bb4ee6a4SAndroid Build Coastguard Worker let mut passthroughfs = PassthroughFs {
799*bb4ee6a4SAndroid Build Coastguard Worker process_lock: Mutex::new(()),
800*bb4ee6a4SAndroid Build Coastguard Worker tag: tag.to_string(),
801*bb4ee6a4SAndroid Build Coastguard Worker inodes: Mutex::new(MultikeyBTreeMap::new()),
802*bb4ee6a4SAndroid Build Coastguard Worker next_inode: AtomicU64::new(ROOT_ID + 1),
803*bb4ee6a4SAndroid Build Coastguard Worker
804*bb4ee6a4SAndroid Build Coastguard Worker handles: Mutex::new(BTreeMap::new()),
805*bb4ee6a4SAndroid Build Coastguard Worker next_handle: AtomicU64::new(1),
806*bb4ee6a4SAndroid Build Coastguard Worker
807*bb4ee6a4SAndroid Build Coastguard Worker proc,
808*bb4ee6a4SAndroid Build Coastguard Worker
809*bb4ee6a4SAndroid Build Coastguard Worker writeback: AtomicBool::new(false),
810*bb4ee6a4SAndroid Build Coastguard Worker zero_message_open: AtomicBool::new(false),
811*bb4ee6a4SAndroid Build Coastguard Worker zero_message_opendir: AtomicBool::new(false),
812*bb4ee6a4SAndroid Build Coastguard Worker
813*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
814*bb4ee6a4SAndroid Build Coastguard Worker dbus_connection,
815*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
816*bb4ee6a4SAndroid Build Coastguard Worker dbus_fd,
817*bb4ee6a4SAndroid Build Coastguard Worker expiring_casefold_lookup_caches,
818*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "fs_permission_translation")]
819*bb4ee6a4SAndroid Build Coastguard Worker permission_paths: RwLock::new(Vec::new()),
820*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
821*bb4ee6a4SAndroid Build Coastguard Worker xattr_paths: RwLock::new(Vec::new()),
822*bb4ee6a4SAndroid Build Coastguard Worker cfg,
823*bb4ee6a4SAndroid Build Coastguard Worker root_dir: "/".to_string(),
824*bb4ee6a4SAndroid Build Coastguard Worker };
825*bb4ee6a4SAndroid Build Coastguard Worker
826*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "fs_runtime_ugid_map")]
827*bb4ee6a4SAndroid Build Coastguard Worker passthroughfs.set_permission_path();
828*bb4ee6a4SAndroid Build Coastguard Worker
829*bb4ee6a4SAndroid Build Coastguard Worker cros_tracing::trace_simple_print!(
830*bb4ee6a4SAndroid Build Coastguard Worker VirtioFs,
831*bb4ee6a4SAndroid Build Coastguard Worker "New PassthroughFS initialized: {:?}",
832*bb4ee6a4SAndroid Build Coastguard Worker passthroughfs
833*bb4ee6a4SAndroid Build Coastguard Worker );
834*bb4ee6a4SAndroid Build Coastguard Worker Ok(passthroughfs)
835*bb4ee6a4SAndroid Build Coastguard Worker }
836*bb4ee6a4SAndroid Build Coastguard Worker
837*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "fs_runtime_ugid_map")]
set_permission_path(&mut self)838*bb4ee6a4SAndroid Build Coastguard Worker fn set_permission_path(&mut self) {
839*bb4ee6a4SAndroid Build Coastguard Worker if !self.cfg.ugid_map.is_empty() {
840*bb4ee6a4SAndroid Build Coastguard Worker let mut write_lock = self
841*bb4ee6a4SAndroid Build Coastguard Worker .permission_paths
842*bb4ee6a4SAndroid Build Coastguard Worker .write()
843*bb4ee6a4SAndroid Build Coastguard Worker .expect("Failed to acquire write lock on permission_paths");
844*bb4ee6a4SAndroid Build Coastguard Worker *write_lock = self.cfg.ugid_map.clone();
845*bb4ee6a4SAndroid Build Coastguard Worker }
846*bb4ee6a4SAndroid Build Coastguard Worker }
847*bb4ee6a4SAndroid Build Coastguard Worker
848*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "fs_runtime_ugid_map")]
set_root_dir(&mut self, shared_dir: String) -> io::Result<()>849*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_root_dir(&mut self, shared_dir: String) -> io::Result<()> {
850*bb4ee6a4SAndroid Build Coastguard Worker let canonicalized_root = match std::fs::canonicalize(shared_dir) {
851*bb4ee6a4SAndroid Build Coastguard Worker Ok(path) => path,
852*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => {
853*bb4ee6a4SAndroid Build Coastguard Worker return Err(io::Error::new(
854*bb4ee6a4SAndroid Build Coastguard Worker io::ErrorKind::InvalidInput,
855*bb4ee6a4SAndroid Build Coastguard Worker format!("Failed to canonicalize root_dir: {}", e),
856*bb4ee6a4SAndroid Build Coastguard Worker ));
857*bb4ee6a4SAndroid Build Coastguard Worker }
858*bb4ee6a4SAndroid Build Coastguard Worker };
859*bb4ee6a4SAndroid Build Coastguard Worker self.root_dir = canonicalized_root.to_string_lossy().to_string();
860*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
861*bb4ee6a4SAndroid Build Coastguard Worker }
862*bb4ee6a4SAndroid Build Coastguard Worker
cfg(&self) -> &Config863*bb4ee6a4SAndroid Build Coastguard Worker pub fn cfg(&self) -> &Config {
864*bb4ee6a4SAndroid Build Coastguard Worker &self.cfg
865*bb4ee6a4SAndroid Build Coastguard Worker }
866*bb4ee6a4SAndroid Build Coastguard Worker
keep_rds(&self) -> Vec<RawDescriptor>867*bb4ee6a4SAndroid Build Coastguard Worker pub fn keep_rds(&self) -> Vec<RawDescriptor> {
868*bb4ee6a4SAndroid Build Coastguard Worker #[cfg_attr(not(feature = "arc_quota"), allow(unused_mut))]
869*bb4ee6a4SAndroid Build Coastguard Worker let mut keep_rds = vec![self.proc.as_raw_descriptor()];
870*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
871*bb4ee6a4SAndroid Build Coastguard Worker if let Some(fd) = self.dbus_fd {
872*bb4ee6a4SAndroid Build Coastguard Worker keep_rds.push(fd);
873*bb4ee6a4SAndroid Build Coastguard Worker }
874*bb4ee6a4SAndroid Build Coastguard Worker keep_rds
875*bb4ee6a4SAndroid Build Coastguard Worker }
876*bb4ee6a4SAndroid Build Coastguard Worker
rewrite_xattr_name<'xattr>(&self, name: &'xattr CStr) -> Cow<'xattr, CStr>877*bb4ee6a4SAndroid Build Coastguard Worker fn rewrite_xattr_name<'xattr>(&self, name: &'xattr CStr) -> Cow<'xattr, CStr> {
878*bb4ee6a4SAndroid Build Coastguard Worker if !self.cfg.rewrite_security_xattrs {
879*bb4ee6a4SAndroid Build Coastguard Worker return Cow::Borrowed(name);
880*bb4ee6a4SAndroid Build Coastguard Worker }
881*bb4ee6a4SAndroid Build Coastguard Worker
882*bb4ee6a4SAndroid Build Coastguard Worker // Does not include nul-terminator.
883*bb4ee6a4SAndroid Build Coastguard Worker let buf = name.to_bytes();
884*bb4ee6a4SAndroid Build Coastguard Worker if !buf.starts_with(SECURITY_XATTR) || buf == SELINUX_XATTR {
885*bb4ee6a4SAndroid Build Coastguard Worker return Cow::Borrowed(name);
886*bb4ee6a4SAndroid Build Coastguard Worker }
887*bb4ee6a4SAndroid Build Coastguard Worker
888*bb4ee6a4SAndroid Build Coastguard Worker let mut newname = USER_VIRTIOFS_XATTR.to_vec();
889*bb4ee6a4SAndroid Build Coastguard Worker newname.extend_from_slice(buf);
890*bb4ee6a4SAndroid Build Coastguard Worker
891*bb4ee6a4SAndroid Build Coastguard Worker // The unwrap is safe here because the prefix doesn't contain any interior nul-bytes and the
892*bb4ee6a4SAndroid Build Coastguard Worker // to_bytes() call above will not return a byte slice with any interior nul-bytes either.
893*bb4ee6a4SAndroid Build Coastguard Worker Cow::Owned(CString::new(newname).expect("Failed to re-write xattr name"))
894*bb4ee6a4SAndroid Build Coastguard Worker }
895*bb4ee6a4SAndroid Build Coastguard Worker
find_inode(&self, inode: Inode) -> io::Result<Arc<InodeData>>896*bb4ee6a4SAndroid Build Coastguard Worker fn find_inode(&self, inode: Inode) -> io::Result<Arc<InodeData>> {
897*bb4ee6a4SAndroid Build Coastguard Worker self.inodes.lock().get(&inode).cloned().ok_or_else(ebadf)
898*bb4ee6a4SAndroid Build Coastguard Worker }
899*bb4ee6a4SAndroid Build Coastguard Worker
find_handle(&self, handle: Handle, inode: Inode) -> io::Result<Arc<HandleData>>900*bb4ee6a4SAndroid Build Coastguard Worker fn find_handle(&self, handle: Handle, inode: Inode) -> io::Result<Arc<HandleData>> {
901*bb4ee6a4SAndroid Build Coastguard Worker self.handles
902*bb4ee6a4SAndroid Build Coastguard Worker .lock()
903*bb4ee6a4SAndroid Build Coastguard Worker .get(&handle)
904*bb4ee6a4SAndroid Build Coastguard Worker .filter(|hd| hd.inode == inode)
905*bb4ee6a4SAndroid Build Coastguard Worker .cloned()
906*bb4ee6a4SAndroid Build Coastguard Worker .ok_or_else(ebadf)
907*bb4ee6a4SAndroid Build Coastguard Worker }
908*bb4ee6a4SAndroid Build Coastguard Worker
open_fd(&self, fd: RawDescriptor, flags: i32) -> io::Result<File>909*bb4ee6a4SAndroid Build Coastguard Worker fn open_fd(&self, fd: RawDescriptor, flags: i32) -> io::Result<File> {
910*bb4ee6a4SAndroid Build Coastguard Worker let pathname = CString::new(format!("self/fd/{}", fd))
911*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
912*bb4ee6a4SAndroid Build Coastguard Worker
913*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value. We don't really
914*bb4ee6a4SAndroid Build Coastguard Worker // check `flags` because if the kernel can't handle poorly specified flags then we have
915*bb4ee6a4SAndroid Build Coastguard Worker // much bigger problems. Also, clear the `O_NOFOLLOW` flag if it is set since we need
916*bb4ee6a4SAndroid Build Coastguard Worker // to follow the `/proc/self/fd` symlink to get the file.
917*bb4ee6a4SAndroid Build Coastguard Worker let raw_descriptor = syscall!(unsafe {
918*bb4ee6a4SAndroid Build Coastguard Worker libc::openat64(
919*bb4ee6a4SAndroid Build Coastguard Worker self.proc.as_raw_descriptor(),
920*bb4ee6a4SAndroid Build Coastguard Worker pathname.as_ptr(),
921*bb4ee6a4SAndroid Build Coastguard Worker (flags | libc::O_CLOEXEC) & !(libc::O_NOFOLLOW | libc::O_DIRECT),
922*bb4ee6a4SAndroid Build Coastguard Worker )
923*bb4ee6a4SAndroid Build Coastguard Worker })?;
924*bb4ee6a4SAndroid Build Coastguard Worker
925*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: safe because we just opened this descriptor.
926*bb4ee6a4SAndroid Build Coastguard Worker Ok(unsafe { File::from_raw_descriptor(raw_descriptor) })
927*bb4ee6a4SAndroid Build Coastguard Worker }
928*bb4ee6a4SAndroid Build Coastguard Worker
929*bb4ee6a4SAndroid Build Coastguard Worker /// Modifies the provided open flags based on the writeback caching configuration.
930*bb4ee6a4SAndroid Build Coastguard Worker /// Return the updated open flags.
update_open_flags(&self, mut flags: i32) -> i32931*bb4ee6a4SAndroid Build Coastguard Worker fn update_open_flags(&self, mut flags: i32) -> i32 {
932*bb4ee6a4SAndroid Build Coastguard Worker // When writeback caching is enabled, the kernel may send read requests even if the
933*bb4ee6a4SAndroid Build Coastguard Worker // userspace program opened the file write-only. So we need to ensure that we have opened
934*bb4ee6a4SAndroid Build Coastguard Worker // the file for reading as well as writing.
935*bb4ee6a4SAndroid Build Coastguard Worker let writeback = self.writeback.load(Ordering::Relaxed);
936*bb4ee6a4SAndroid Build Coastguard Worker if writeback && flags & libc::O_ACCMODE == libc::O_WRONLY {
937*bb4ee6a4SAndroid Build Coastguard Worker flags &= !libc::O_ACCMODE;
938*bb4ee6a4SAndroid Build Coastguard Worker flags |= libc::O_RDWR;
939*bb4ee6a4SAndroid Build Coastguard Worker }
940*bb4ee6a4SAndroid Build Coastguard Worker
941*bb4ee6a4SAndroid Build Coastguard Worker // When writeback caching is enabled the kernel is responsible for handling `O_APPEND`.
942*bb4ee6a4SAndroid Build Coastguard Worker // However, this breaks atomicity as the file may have changed on disk, invalidating the
943*bb4ee6a4SAndroid Build Coastguard Worker // cached copy of the data in the kernel and the offset that the kernel thinks is the end of
944*bb4ee6a4SAndroid Build Coastguard Worker // the file. Just allow this for now as it is the user's responsibility to enable writeback
945*bb4ee6a4SAndroid Build Coastguard Worker // caching only for directories that are not shared. It also means that we need to clear the
946*bb4ee6a4SAndroid Build Coastguard Worker // `O_APPEND` flag.
947*bb4ee6a4SAndroid Build Coastguard Worker if writeback && flags & libc::O_APPEND != 0 {
948*bb4ee6a4SAndroid Build Coastguard Worker flags &= !libc::O_APPEND;
949*bb4ee6a4SAndroid Build Coastguard Worker }
950*bb4ee6a4SAndroid Build Coastguard Worker
951*bb4ee6a4SAndroid Build Coastguard Worker flags
952*bb4ee6a4SAndroid Build Coastguard Worker }
953*bb4ee6a4SAndroid Build Coastguard Worker
open_inode(&self, inode: &InodeData, mut flags: i32) -> io::Result<File>954*bb4ee6a4SAndroid Build Coastguard Worker fn open_inode(&self, inode: &InodeData, mut flags: i32) -> io::Result<File> {
955*bb4ee6a4SAndroid Build Coastguard Worker // handle writeback caching cases
956*bb4ee6a4SAndroid Build Coastguard Worker flags = self.update_open_flags(flags);
957*bb4ee6a4SAndroid Build Coastguard Worker
958*bb4ee6a4SAndroid Build Coastguard Worker self.open_fd(inode.as_raw_descriptor(), flags)
959*bb4ee6a4SAndroid Build Coastguard Worker }
960*bb4ee6a4SAndroid Build Coastguard Worker
961*bb4ee6a4SAndroid Build Coastguard Worker // Increases the inode refcount and returns the inode.
increase_inode_refcount(&self, inode_data: &InodeData) -> Inode962*bb4ee6a4SAndroid Build Coastguard Worker fn increase_inode_refcount(&self, inode_data: &InodeData) -> Inode {
963*bb4ee6a4SAndroid Build Coastguard Worker // Matches with the release store in `forget`.
964*bb4ee6a4SAndroid Build Coastguard Worker inode_data.refcount.fetch_add(1, Ordering::Acquire);
965*bb4ee6a4SAndroid Build Coastguard Worker inode_data.inode
966*bb4ee6a4SAndroid Build Coastguard Worker }
967*bb4ee6a4SAndroid Build Coastguard Worker
968*bb4ee6a4SAndroid Build Coastguard Worker // Creates a new entry for `f` or increases the refcount of the existing entry for `f`.
969*bb4ee6a4SAndroid Build Coastguard Worker // The inodes mutex lock must not be already taken by the same thread otherwise this
970*bb4ee6a4SAndroid Build Coastguard Worker // will deadlock.
add_entry( &self, f: File, #[cfg_attr(not(feature = "fs_permission_translation"), allow(unused_mut))] mut st: libc::stat64, open_flags: libc::c_int, path: String, ) -> Entry971*bb4ee6a4SAndroid Build Coastguard Worker fn add_entry(
972*bb4ee6a4SAndroid Build Coastguard Worker &self,
973*bb4ee6a4SAndroid Build Coastguard Worker f: File,
974*bb4ee6a4SAndroid Build Coastguard Worker #[cfg_attr(not(feature = "fs_permission_translation"), allow(unused_mut))]
975*bb4ee6a4SAndroid Build Coastguard Worker mut st: libc::stat64,
976*bb4ee6a4SAndroid Build Coastguard Worker open_flags: libc::c_int,
977*bb4ee6a4SAndroid Build Coastguard Worker path: String,
978*bb4ee6a4SAndroid Build Coastguard Worker ) -> Entry {
979*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
980*bb4ee6a4SAndroid Build Coastguard Worker self.set_permission(&mut st, &path);
981*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "fs_runtime_ugid_map")]
982*bb4ee6a4SAndroid Build Coastguard Worker self.set_ugid_permission(&mut st, &path);
983*bb4ee6a4SAndroid Build Coastguard Worker let mut inodes = self.inodes.lock();
984*bb4ee6a4SAndroid Build Coastguard Worker
985*bb4ee6a4SAndroid Build Coastguard Worker let altkey = InodeAltKey {
986*bb4ee6a4SAndroid Build Coastguard Worker ino: st.st_ino,
987*bb4ee6a4SAndroid Build Coastguard Worker dev: st.st_dev,
988*bb4ee6a4SAndroid Build Coastguard Worker };
989*bb4ee6a4SAndroid Build Coastguard Worker
990*bb4ee6a4SAndroid Build Coastguard Worker let inode = if let Some(data) = inodes.get_alt(&altkey) {
991*bb4ee6a4SAndroid Build Coastguard Worker self.increase_inode_refcount(data)
992*bb4ee6a4SAndroid Build Coastguard Worker } else {
993*bb4ee6a4SAndroid Build Coastguard Worker let inode = self.next_inode.fetch_add(1, Ordering::Relaxed);
994*bb4ee6a4SAndroid Build Coastguard Worker inodes.insert(
995*bb4ee6a4SAndroid Build Coastguard Worker inode,
996*bb4ee6a4SAndroid Build Coastguard Worker altkey,
997*bb4ee6a4SAndroid Build Coastguard Worker Arc::new(InodeData {
998*bb4ee6a4SAndroid Build Coastguard Worker inode,
999*bb4ee6a4SAndroid Build Coastguard Worker file: Mutex::new((f, open_flags)),
1000*bb4ee6a4SAndroid Build Coastguard Worker refcount: AtomicU64::new(1),
1001*bb4ee6a4SAndroid Build Coastguard Worker filetype: st.st_mode.into(),
1002*bb4ee6a4SAndroid Build Coastguard Worker path,
1003*bb4ee6a4SAndroid Build Coastguard Worker }),
1004*bb4ee6a4SAndroid Build Coastguard Worker );
1005*bb4ee6a4SAndroid Build Coastguard Worker
1006*bb4ee6a4SAndroid Build Coastguard Worker inode
1007*bb4ee6a4SAndroid Build Coastguard Worker };
1008*bb4ee6a4SAndroid Build Coastguard Worker
1009*bb4ee6a4SAndroid Build Coastguard Worker Entry {
1010*bb4ee6a4SAndroid Build Coastguard Worker inode,
1011*bb4ee6a4SAndroid Build Coastguard Worker generation: 0,
1012*bb4ee6a4SAndroid Build Coastguard Worker attr: st,
1013*bb4ee6a4SAndroid Build Coastguard Worker // We use the same timeout for the attribute and the entry.
1014*bb4ee6a4SAndroid Build Coastguard Worker attr_timeout: self.cfg.timeout,
1015*bb4ee6a4SAndroid Build Coastguard Worker entry_timeout: self.cfg.timeout,
1016*bb4ee6a4SAndroid Build Coastguard Worker }
1017*bb4ee6a4SAndroid Build Coastguard Worker }
1018*bb4ee6a4SAndroid Build Coastguard Worker
1019*bb4ee6a4SAndroid Build Coastguard Worker /// Acquires lock of `expiring_casefold_lookup_caches` if `ascii_casefold` is enabled.
lock_casefold_lookup_caches(&self) -> Option<MutexGuard<'_, ExpiringCasefoldLookupCaches>>1020*bb4ee6a4SAndroid Build Coastguard Worker fn lock_casefold_lookup_caches(&self) -> Option<MutexGuard<'_, ExpiringCasefoldLookupCaches>> {
1021*bb4ee6a4SAndroid Build Coastguard Worker self.expiring_casefold_lookup_caches
1022*bb4ee6a4SAndroid Build Coastguard Worker .as_ref()
1023*bb4ee6a4SAndroid Build Coastguard Worker .map(|c| c.lock())
1024*bb4ee6a4SAndroid Build Coastguard Worker }
1025*bb4ee6a4SAndroid Build Coastguard Worker
1026*bb4ee6a4SAndroid Build Coastguard Worker // Returns an actual case-sensitive file name that matches with the given `name`.
1027*bb4ee6a4SAndroid Build Coastguard Worker // Returns `Ok(None)` if no file matches with the give `name`.
1028*bb4ee6a4SAndroid Build Coastguard Worker // This function will panic if casefold is not enabled.
get_case_unfolded_name( &self, parent: &InodeData, name: &[u8], ) -> io::Result<Option<CString>>1029*bb4ee6a4SAndroid Build Coastguard Worker fn get_case_unfolded_name(
1030*bb4ee6a4SAndroid Build Coastguard Worker &self,
1031*bb4ee6a4SAndroid Build Coastguard Worker parent: &InodeData,
1032*bb4ee6a4SAndroid Build Coastguard Worker name: &[u8],
1033*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<Option<CString>> {
1034*bb4ee6a4SAndroid Build Coastguard Worker let mut caches = self
1035*bb4ee6a4SAndroid Build Coastguard Worker .lock_casefold_lookup_caches()
1036*bb4ee6a4SAndroid Build Coastguard Worker .expect("casefold must be enabled");
1037*bb4ee6a4SAndroid Build Coastguard Worker let dir_cache = caches.get(parent)?;
1038*bb4ee6a4SAndroid Build Coastguard Worker Ok(dir_cache.lookup(name))
1039*bb4ee6a4SAndroid Build Coastguard Worker }
1040*bb4ee6a4SAndroid Build Coastguard Worker
1041*bb4ee6a4SAndroid Build Coastguard Worker // Performs an ascii case insensitive lookup.
ascii_casefold_lookup(&self, parent: &InodeData, name: &[u8]) -> io::Result<Entry>1042*bb4ee6a4SAndroid Build Coastguard Worker fn ascii_casefold_lookup(&self, parent: &InodeData, name: &[u8]) -> io::Result<Entry> {
1043*bb4ee6a4SAndroid Build Coastguard Worker match self.get_case_unfolded_name(parent, name)? {
1044*bb4ee6a4SAndroid Build Coastguard Worker None => Err(io::Error::from_raw_os_error(libc::ENOENT)),
1045*bb4ee6a4SAndroid Build Coastguard Worker Some(actual_name) => self.do_lookup(parent, &actual_name),
1046*bb4ee6a4SAndroid Build Coastguard Worker }
1047*bb4ee6a4SAndroid Build Coastguard Worker }
1048*bb4ee6a4SAndroid Build Coastguard Worker
1049*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
exists_in_casefold_cache(&self, parent: Inode, name: &CStr) -> bool1050*bb4ee6a4SAndroid Build Coastguard Worker fn exists_in_casefold_cache(&self, parent: Inode, name: &CStr) -> bool {
1051*bb4ee6a4SAndroid Build Coastguard Worker let mut cache = self
1052*bb4ee6a4SAndroid Build Coastguard Worker .lock_casefold_lookup_caches()
1053*bb4ee6a4SAndroid Build Coastguard Worker .expect("casefold must be enabled");
1054*bb4ee6a4SAndroid Build Coastguard Worker cache.exists_in_cache(parent, name)
1055*bb4ee6a4SAndroid Build Coastguard Worker }
1056*bb4ee6a4SAndroid Build Coastguard Worker
do_lookup(&self, parent: &InodeData, name: &CStr) -> io::Result<Entry>1057*bb4ee6a4SAndroid Build Coastguard Worker fn do_lookup(&self, parent: &InodeData, name: &CStr) -> io::Result<Entry> {
1058*bb4ee6a4SAndroid Build Coastguard Worker #[cfg_attr(not(feature = "fs_permission_translation"), allow(unused_mut))]
1059*bb4ee6a4SAndroid Build Coastguard Worker let mut st = statat(parent, name)?;
1060*bb4ee6a4SAndroid Build Coastguard Worker
1061*bb4ee6a4SAndroid Build Coastguard Worker let altkey = InodeAltKey {
1062*bb4ee6a4SAndroid Build Coastguard Worker ino: st.st_ino,
1063*bb4ee6a4SAndroid Build Coastguard Worker dev: st.st_dev,
1064*bb4ee6a4SAndroid Build Coastguard Worker };
1065*bb4ee6a4SAndroid Build Coastguard Worker
1066*bb4ee6a4SAndroid Build Coastguard Worker let path = format!(
1067*bb4ee6a4SAndroid Build Coastguard Worker "{}/{}",
1068*bb4ee6a4SAndroid Build Coastguard Worker parent.path.clone(),
1069*bb4ee6a4SAndroid Build Coastguard Worker name.to_str().unwrap_or("<non UTF-8 str>")
1070*bb4ee6a4SAndroid Build Coastguard Worker );
1071*bb4ee6a4SAndroid Build Coastguard Worker
1072*bb4ee6a4SAndroid Build Coastguard Worker // Check if we already have an entry before opening a new file.
1073*bb4ee6a4SAndroid Build Coastguard Worker if let Some(data) = self.inodes.lock().get_alt(&altkey) {
1074*bb4ee6a4SAndroid Build Coastguard Worker // Return the same inode with the reference counter increased.
1075*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
1076*bb4ee6a4SAndroid Build Coastguard Worker self.set_permission(&mut st, &path);
1077*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "fs_runtime_ugid_map")]
1078*bb4ee6a4SAndroid Build Coastguard Worker self.set_ugid_permission(&mut st, &path);
1079*bb4ee6a4SAndroid Build Coastguard Worker return Ok(Entry {
1080*bb4ee6a4SAndroid Build Coastguard Worker inode: self.increase_inode_refcount(data),
1081*bb4ee6a4SAndroid Build Coastguard Worker generation: 0,
1082*bb4ee6a4SAndroid Build Coastguard Worker attr: st,
1083*bb4ee6a4SAndroid Build Coastguard Worker // We use the same timeout for the attribute and the entry.
1084*bb4ee6a4SAndroid Build Coastguard Worker attr_timeout: self.cfg.timeout,
1085*bb4ee6a4SAndroid Build Coastguard Worker entry_timeout: self.cfg.timeout,
1086*bb4ee6a4SAndroid Build Coastguard Worker });
1087*bb4ee6a4SAndroid Build Coastguard Worker }
1088*bb4ee6a4SAndroid Build Coastguard Worker
1089*bb4ee6a4SAndroid Build Coastguard Worker // Open a regular file with O_RDONLY to store in `InodeData` so explicit open requests can
1090*bb4ee6a4SAndroid Build Coastguard Worker // be skipped later if the ZERO_MESSAGE_{OPEN,OPENDIR} features are enabled.
1091*bb4ee6a4SAndroid Build Coastguard Worker // If the crosvm process doesn't have a read permission, fall back to O_PATH below.
1092*bb4ee6a4SAndroid Build Coastguard Worker let mut flags = libc::O_RDONLY | libc::O_NOFOLLOW | libc::O_CLOEXEC;
1093*bb4ee6a4SAndroid Build Coastguard Worker match FileType::from(st.st_mode) {
1094*bb4ee6a4SAndroid Build Coastguard Worker FileType::Regular => {}
1095*bb4ee6a4SAndroid Build Coastguard Worker FileType::Directory => flags |= libc::O_DIRECTORY,
1096*bb4ee6a4SAndroid Build Coastguard Worker FileType::Other => flags |= libc::O_PATH,
1097*bb4ee6a4SAndroid Build Coastguard Worker };
1098*bb4ee6a4SAndroid Build Coastguard Worker
1099*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value.
1100*bb4ee6a4SAndroid Build Coastguard Worker let fd = match unsafe {
1101*bb4ee6a4SAndroid Build Coastguard Worker syscall!(libc::openat64(
1102*bb4ee6a4SAndroid Build Coastguard Worker parent.as_raw_descriptor(),
1103*bb4ee6a4SAndroid Build Coastguard Worker name.as_ptr(),
1104*bb4ee6a4SAndroid Build Coastguard Worker flags
1105*bb4ee6a4SAndroid Build Coastguard Worker ))
1106*bb4ee6a4SAndroid Build Coastguard Worker } {
1107*bb4ee6a4SAndroid Build Coastguard Worker Ok(fd) => fd,
1108*bb4ee6a4SAndroid Build Coastguard Worker Err(e) if e.errno() == libc::EACCES => {
1109*bb4ee6a4SAndroid Build Coastguard Worker // If O_RDONLY is unavailable, fall back to O_PATH to get an FD to store in
1110*bb4ee6a4SAndroid Build Coastguard Worker // `InodeData`.
1111*bb4ee6a4SAndroid Build Coastguard Worker // Note that some operations which should be allowed without read permissions
1112*bb4ee6a4SAndroid Build Coastguard Worker // require syscalls that don't support O_PATH fds. For those syscalls, we will
1113*bb4ee6a4SAndroid Build Coastguard Worker // need to fall back to their path-based equivalents with /self/fd/${FD}.
1114*bb4ee6a4SAndroid Build Coastguard Worker // e.g. `fgetxattr()` for an O_PATH FD fails while `getxaattr()` for /self/fd/${FD}
1115*bb4ee6a4SAndroid Build Coastguard Worker // works.
1116*bb4ee6a4SAndroid Build Coastguard Worker flags |= libc::O_PATH;
1117*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value.
1118*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
1119*bb4ee6a4SAndroid Build Coastguard Worker syscall!(libc::openat64(
1120*bb4ee6a4SAndroid Build Coastguard Worker parent.as_raw_descriptor(),
1121*bb4ee6a4SAndroid Build Coastguard Worker name.as_ptr(),
1122*bb4ee6a4SAndroid Build Coastguard Worker flags
1123*bb4ee6a4SAndroid Build Coastguard Worker ))
1124*bb4ee6a4SAndroid Build Coastguard Worker }?
1125*bb4ee6a4SAndroid Build Coastguard Worker }
1126*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => {
1127*bb4ee6a4SAndroid Build Coastguard Worker return Err(e.into());
1128*bb4ee6a4SAndroid Build Coastguard Worker }
1129*bb4ee6a4SAndroid Build Coastguard Worker };
1130*bb4ee6a4SAndroid Build Coastguard Worker
1131*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: safe because we own the fd.
1132*bb4ee6a4SAndroid Build Coastguard Worker let f = unsafe { File::from_raw_descriptor(fd) };
1133*bb4ee6a4SAndroid Build Coastguard Worker // We made sure the lock acquired for `self.inodes` is released automatically when
1134*bb4ee6a4SAndroid Build Coastguard Worker // the if block above is exited, so a call to `self.add_entry()` should not cause a deadlock
1135*bb4ee6a4SAndroid Build Coastguard Worker // here. This would not be the case if this were executed in an else block instead.
1136*bb4ee6a4SAndroid Build Coastguard Worker Ok(self.add_entry(f, st, flags, path))
1137*bb4ee6a4SAndroid Build Coastguard Worker }
1138*bb4ee6a4SAndroid Build Coastguard Worker
get_cache_open_options(&self, flags: u32) -> OpenOptions1139*bb4ee6a4SAndroid Build Coastguard Worker fn get_cache_open_options(&self, flags: u32) -> OpenOptions {
1140*bb4ee6a4SAndroid Build Coastguard Worker let mut opts = OpenOptions::empty();
1141*bb4ee6a4SAndroid Build Coastguard Worker match self.cfg.cache_policy {
1142*bb4ee6a4SAndroid Build Coastguard Worker // We only set the direct I/O option on files.
1143*bb4ee6a4SAndroid Build Coastguard Worker CachePolicy::Never => opts.set(
1144*bb4ee6a4SAndroid Build Coastguard Worker OpenOptions::DIRECT_IO,
1145*bb4ee6a4SAndroid Build Coastguard Worker flags & (libc::O_DIRECTORY as u32) == 0,
1146*bb4ee6a4SAndroid Build Coastguard Worker ),
1147*bb4ee6a4SAndroid Build Coastguard Worker CachePolicy::Always => {
1148*bb4ee6a4SAndroid Build Coastguard Worker opts |= if flags & (libc::O_DIRECTORY as u32) == 0 {
1149*bb4ee6a4SAndroid Build Coastguard Worker OpenOptions::KEEP_CACHE
1150*bb4ee6a4SAndroid Build Coastguard Worker } else {
1151*bb4ee6a4SAndroid Build Coastguard Worker OpenOptions::CACHE_DIR
1152*bb4ee6a4SAndroid Build Coastguard Worker }
1153*bb4ee6a4SAndroid Build Coastguard Worker }
1154*bb4ee6a4SAndroid Build Coastguard Worker _ => {}
1155*bb4ee6a4SAndroid Build Coastguard Worker };
1156*bb4ee6a4SAndroid Build Coastguard Worker opts
1157*bb4ee6a4SAndroid Build Coastguard Worker }
1158*bb4ee6a4SAndroid Build Coastguard Worker
1159*bb4ee6a4SAndroid Build Coastguard Worker // Performs lookup using original name first, if it fails and ascii_casefold is enabled,
1160*bb4ee6a4SAndroid Build Coastguard Worker // it tries to unfold the name and do lookup again.
do_lookup_with_casefold_fallback( &self, parent: &InodeData, name: &CStr, ) -> io::Result<Entry>1161*bb4ee6a4SAndroid Build Coastguard Worker fn do_lookup_with_casefold_fallback(
1162*bb4ee6a4SAndroid Build Coastguard Worker &self,
1163*bb4ee6a4SAndroid Build Coastguard Worker parent: &InodeData,
1164*bb4ee6a4SAndroid Build Coastguard Worker name: &CStr,
1165*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<Entry> {
1166*bb4ee6a4SAndroid Build Coastguard Worker let mut res = self.do_lookup(parent, name);
1167*bb4ee6a4SAndroid Build Coastguard Worker // If `ascii_casefold` is enabled, fallback to `ascii_casefold_lookup()`.
1168*bb4ee6a4SAndroid Build Coastguard Worker if res.is_err() && self.cfg.ascii_casefold {
1169*bb4ee6a4SAndroid Build Coastguard Worker res = self.ascii_casefold_lookup(parent, name.to_bytes());
1170*bb4ee6a4SAndroid Build Coastguard Worker }
1171*bb4ee6a4SAndroid Build Coastguard Worker res
1172*bb4ee6a4SAndroid Build Coastguard Worker }
1173*bb4ee6a4SAndroid Build Coastguard Worker
do_open(&self, inode: Inode, flags: u32) -> io::Result<(Option<Handle>, OpenOptions)>1174*bb4ee6a4SAndroid Build Coastguard Worker fn do_open(&self, inode: Inode, flags: u32) -> io::Result<(Option<Handle>, OpenOptions)> {
1175*bb4ee6a4SAndroid Build Coastguard Worker let inode_data = self.find_inode(inode)?;
1176*bb4ee6a4SAndroid Build Coastguard Worker
1177*bb4ee6a4SAndroid Build Coastguard Worker let file = Mutex::new(self.open_inode(&inode_data, flags as i32)?);
1178*bb4ee6a4SAndroid Build Coastguard Worker
1179*bb4ee6a4SAndroid Build Coastguard Worker let handle = self.next_handle.fetch_add(1, Ordering::Relaxed);
1180*bb4ee6a4SAndroid Build Coastguard Worker let data = HandleData { inode, file };
1181*bb4ee6a4SAndroid Build Coastguard Worker
1182*bb4ee6a4SAndroid Build Coastguard Worker self.handles.lock().insert(handle, Arc::new(data));
1183*bb4ee6a4SAndroid Build Coastguard Worker
1184*bb4ee6a4SAndroid Build Coastguard Worker let opts = self.get_cache_open_options(flags);
1185*bb4ee6a4SAndroid Build Coastguard Worker
1186*bb4ee6a4SAndroid Build Coastguard Worker Ok((Some(handle), opts))
1187*bb4ee6a4SAndroid Build Coastguard Worker }
1188*bb4ee6a4SAndroid Build Coastguard Worker
do_open_at( &self, parent_data: Arc<InodeData>, name: &CStr, inode: Inode, flags: u32, ) -> io::Result<(Option<Handle>, OpenOptions)>1189*bb4ee6a4SAndroid Build Coastguard Worker fn do_open_at(
1190*bb4ee6a4SAndroid Build Coastguard Worker &self,
1191*bb4ee6a4SAndroid Build Coastguard Worker parent_data: Arc<InodeData>,
1192*bb4ee6a4SAndroid Build Coastguard Worker name: &CStr,
1193*bb4ee6a4SAndroid Build Coastguard Worker inode: Inode,
1194*bb4ee6a4SAndroid Build Coastguard Worker flags: u32,
1195*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<(Option<Handle>, OpenOptions)> {
1196*bb4ee6a4SAndroid Build Coastguard Worker let open_flags = self.update_open_flags(flags as i32);
1197*bb4ee6a4SAndroid Build Coastguard Worker
1198*bb4ee6a4SAndroid Build Coastguard Worker let fd_open = syscall!(
1199*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: return value is checked.
1200*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
1201*bb4ee6a4SAndroid Build Coastguard Worker libc::openat64(
1202*bb4ee6a4SAndroid Build Coastguard Worker parent_data.as_raw_descriptor(),
1203*bb4ee6a4SAndroid Build Coastguard Worker name.as_ptr(),
1204*bb4ee6a4SAndroid Build Coastguard Worker (open_flags | libc::O_CLOEXEC) & !(libc::O_NOFOLLOW | libc::O_DIRECT),
1205*bb4ee6a4SAndroid Build Coastguard Worker )
1206*bb4ee6a4SAndroid Build Coastguard Worker }
1207*bb4ee6a4SAndroid Build Coastguard Worker )?;
1208*bb4ee6a4SAndroid Build Coastguard Worker
1209*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: fd_open is valid
1210*bb4ee6a4SAndroid Build Coastguard Worker let file_open = unsafe { File::from_raw_descriptor(fd_open) };
1211*bb4ee6a4SAndroid Build Coastguard Worker let handle = self.next_handle.fetch_add(1, Ordering::Relaxed);
1212*bb4ee6a4SAndroid Build Coastguard Worker let data = HandleData {
1213*bb4ee6a4SAndroid Build Coastguard Worker inode,
1214*bb4ee6a4SAndroid Build Coastguard Worker file: Mutex::new(file_open),
1215*bb4ee6a4SAndroid Build Coastguard Worker };
1216*bb4ee6a4SAndroid Build Coastguard Worker
1217*bb4ee6a4SAndroid Build Coastguard Worker self.handles.lock().insert(handle, Arc::new(data));
1218*bb4ee6a4SAndroid Build Coastguard Worker
1219*bb4ee6a4SAndroid Build Coastguard Worker let opts = self.get_cache_open_options(open_flags as u32);
1220*bb4ee6a4SAndroid Build Coastguard Worker Ok((Some(handle), opts))
1221*bb4ee6a4SAndroid Build Coastguard Worker }
1222*bb4ee6a4SAndroid Build Coastguard Worker
do_release(&self, inode: Inode, handle: Handle) -> io::Result<()>1223*bb4ee6a4SAndroid Build Coastguard Worker fn do_release(&self, inode: Inode, handle: Handle) -> io::Result<()> {
1224*bb4ee6a4SAndroid Build Coastguard Worker let mut handles = self.handles.lock();
1225*bb4ee6a4SAndroid Build Coastguard Worker
1226*bb4ee6a4SAndroid Build Coastguard Worker if let btree_map::Entry::Occupied(e) = handles.entry(handle) {
1227*bb4ee6a4SAndroid Build Coastguard Worker if e.get().inode == inode {
1228*bb4ee6a4SAndroid Build Coastguard Worker // We don't need to close the file here because that will happen automatically when
1229*bb4ee6a4SAndroid Build Coastguard Worker // the last `Arc` is dropped.
1230*bb4ee6a4SAndroid Build Coastguard Worker e.remove();
1231*bb4ee6a4SAndroid Build Coastguard Worker return Ok(());
1232*bb4ee6a4SAndroid Build Coastguard Worker }
1233*bb4ee6a4SAndroid Build Coastguard Worker }
1234*bb4ee6a4SAndroid Build Coastguard Worker
1235*bb4ee6a4SAndroid Build Coastguard Worker Err(ebadf())
1236*bb4ee6a4SAndroid Build Coastguard Worker }
1237*bb4ee6a4SAndroid Build Coastguard Worker
do_getattr(&self, inode: &InodeData) -> io::Result<(libc::stat64, Duration)>1238*bb4ee6a4SAndroid Build Coastguard Worker fn do_getattr(&self, inode: &InodeData) -> io::Result<(libc::stat64, Duration)> {
1239*bb4ee6a4SAndroid Build Coastguard Worker #[allow(unused_mut)]
1240*bb4ee6a4SAndroid Build Coastguard Worker let mut st = stat(inode)?;
1241*bb4ee6a4SAndroid Build Coastguard Worker
1242*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
1243*bb4ee6a4SAndroid Build Coastguard Worker self.set_permission(&mut st, &inode.path);
1244*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "fs_runtime_ugid_map")]
1245*bb4ee6a4SAndroid Build Coastguard Worker self.set_ugid_permission(&mut st, &inode.path);
1246*bb4ee6a4SAndroid Build Coastguard Worker Ok((st, self.cfg.timeout))
1247*bb4ee6a4SAndroid Build Coastguard Worker }
1248*bb4ee6a4SAndroid Build Coastguard Worker
do_unlink(&self, parent: &InodeData, name: &CStr, flags: libc::c_int) -> io::Result<()>1249*bb4ee6a4SAndroid Build Coastguard Worker fn do_unlink(&self, parent: &InodeData, name: &CStr, flags: libc::c_int) -> io::Result<()> {
1250*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value.
1251*bb4ee6a4SAndroid Build Coastguard Worker syscall!(unsafe { libc::unlinkat(parent.as_raw_descriptor(), name.as_ptr(), flags) })?;
1252*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
1253*bb4ee6a4SAndroid Build Coastguard Worker }
1254*bb4ee6a4SAndroid Build Coastguard Worker
do_fsync<F: AsRawDescriptor>(&self, file: &F, datasync: bool) -> io::Result<()>1255*bb4ee6a4SAndroid Build Coastguard Worker fn do_fsync<F: AsRawDescriptor>(&self, file: &F, datasync: bool) -> io::Result<()> {
1256*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value.
1257*bb4ee6a4SAndroid Build Coastguard Worker syscall!(unsafe {
1258*bb4ee6a4SAndroid Build Coastguard Worker if datasync {
1259*bb4ee6a4SAndroid Build Coastguard Worker libc::fdatasync(file.as_raw_descriptor())
1260*bb4ee6a4SAndroid Build Coastguard Worker } else {
1261*bb4ee6a4SAndroid Build Coastguard Worker libc::fsync(file.as_raw_descriptor())
1262*bb4ee6a4SAndroid Build Coastguard Worker }
1263*bb4ee6a4SAndroid Build Coastguard Worker })?;
1264*bb4ee6a4SAndroid Build Coastguard Worker
1265*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
1266*bb4ee6a4SAndroid Build Coastguard Worker }
1267*bb4ee6a4SAndroid Build Coastguard Worker
1268*bb4ee6a4SAndroid Build Coastguard Worker // Changes the CWD to `self.proc`, runs `f`, and then changes the CWD back to the root
1269*bb4ee6a4SAndroid Build Coastguard Worker // directory. This effectively emulates an *at syscall starting at /proc, which is useful when
1270*bb4ee6a4SAndroid Build Coastguard Worker // there is no *at syscall available. Panics if any of the fchdir calls fail or if there is no
1271*bb4ee6a4SAndroid Build Coastguard Worker // root inode.
1272*bb4ee6a4SAndroid Build Coastguard Worker //
1273*bb4ee6a4SAndroid Build Coastguard Worker // NOTE: this method acquires an `self`-wide lock. If any locks are acquired in `f`, care must
1274*bb4ee6a4SAndroid Build Coastguard Worker // be taken to avoid the risk of deadlocks.
with_proc_chdir<F, T>(&self, f: F) -> T where F: FnOnce() -> T,1275*bb4ee6a4SAndroid Build Coastguard Worker fn with_proc_chdir<F, T>(&self, f: F) -> T
1276*bb4ee6a4SAndroid Build Coastguard Worker where
1277*bb4ee6a4SAndroid Build Coastguard Worker F: FnOnce() -> T,
1278*bb4ee6a4SAndroid Build Coastguard Worker {
1279*bb4ee6a4SAndroid Build Coastguard Worker let root = self.find_inode(ROOT_ID).expect("failed to find root inode");
1280*bb4ee6a4SAndroid Build Coastguard Worker
1281*bb4ee6a4SAndroid Build Coastguard Worker // Acquire a lock for `fchdir`.
1282*bb4ee6a4SAndroid Build Coastguard Worker let _proc_lock = self.process_lock.lock();
1283*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value. Since the
1284*bb4ee6a4SAndroid Build Coastguard Worker // fchdir should never fail we just use debug_asserts.
1285*bb4ee6a4SAndroid Build Coastguard Worker let proc_cwd = unsafe { libc::fchdir(self.proc.as_raw_descriptor()) };
1286*bb4ee6a4SAndroid Build Coastguard Worker debug_assert_eq!(
1287*bb4ee6a4SAndroid Build Coastguard Worker proc_cwd,
1288*bb4ee6a4SAndroid Build Coastguard Worker 0,
1289*bb4ee6a4SAndroid Build Coastguard Worker "failed to fchdir to /proc: {}",
1290*bb4ee6a4SAndroid Build Coastguard Worker io::Error::last_os_error()
1291*bb4ee6a4SAndroid Build Coastguard Worker );
1292*bb4ee6a4SAndroid Build Coastguard Worker
1293*bb4ee6a4SAndroid Build Coastguard Worker let res = f();
1294*bb4ee6a4SAndroid Build Coastguard Worker
1295*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value. Since the
1296*bb4ee6a4SAndroid Build Coastguard Worker // fchdir should never fail we just use debug_asserts.
1297*bb4ee6a4SAndroid Build Coastguard Worker let root_cwd = unsafe { libc::fchdir(root.as_raw_descriptor()) };
1298*bb4ee6a4SAndroid Build Coastguard Worker debug_assert_eq!(
1299*bb4ee6a4SAndroid Build Coastguard Worker root_cwd,
1300*bb4ee6a4SAndroid Build Coastguard Worker 0,
1301*bb4ee6a4SAndroid Build Coastguard Worker "failed to fchdir back to root directory: {}",
1302*bb4ee6a4SAndroid Build Coastguard Worker io::Error::last_os_error()
1303*bb4ee6a4SAndroid Build Coastguard Worker );
1304*bb4ee6a4SAndroid Build Coastguard Worker
1305*bb4ee6a4SAndroid Build Coastguard Worker res
1306*bb4ee6a4SAndroid Build Coastguard Worker }
1307*bb4ee6a4SAndroid Build Coastguard Worker
do_getxattr(&self, inode: &InodeData, name: &CStr, value: &mut [u8]) -> io::Result<usize>1308*bb4ee6a4SAndroid Build Coastguard Worker fn do_getxattr(&self, inode: &InodeData, name: &CStr, value: &mut [u8]) -> io::Result<usize> {
1309*bb4ee6a4SAndroid Build Coastguard Worker let file = inode.file.lock();
1310*bb4ee6a4SAndroid Build Coastguard Worker let o_path_file = (file.1 & libc::O_PATH) != 0;
1311*bb4ee6a4SAndroid Build Coastguard Worker let res = if o_path_file {
1312*bb4ee6a4SAndroid Build Coastguard Worker // For FDs opened with `O_PATH`, we cannot call `fgetxattr` normally. Instead we
1313*bb4ee6a4SAndroid Build Coastguard Worker // emulate an _at syscall by changing the CWD to /proc, running the path based syscall,
1314*bb4ee6a4SAndroid Build Coastguard Worker // and then setting the CWD back to the root directory.
1315*bb4ee6a4SAndroid Build Coastguard Worker let path = CString::new(format!("self/fd/{}", file.0.as_raw_descriptor()))
1316*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
1317*bb4ee6a4SAndroid Build Coastguard Worker
1318*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this will only modify `value` and we check the return value.
1319*bb4ee6a4SAndroid Build Coastguard Worker self.with_proc_chdir(|| unsafe {
1320*bb4ee6a4SAndroid Build Coastguard Worker libc::getxattr(
1321*bb4ee6a4SAndroid Build Coastguard Worker path.as_ptr(),
1322*bb4ee6a4SAndroid Build Coastguard Worker name.as_ptr(),
1323*bb4ee6a4SAndroid Build Coastguard Worker value.as_mut_ptr() as *mut libc::c_void,
1324*bb4ee6a4SAndroid Build Coastguard Worker value.len() as libc::size_t,
1325*bb4ee6a4SAndroid Build Coastguard Worker )
1326*bb4ee6a4SAndroid Build Coastguard Worker })
1327*bb4ee6a4SAndroid Build Coastguard Worker } else {
1328*bb4ee6a4SAndroid Build Coastguard Worker // For regular files and directories, we can just use fgetxattr.
1329*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this will only write to `value` and we check the return value.
1330*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
1331*bb4ee6a4SAndroid Build Coastguard Worker libc::fgetxattr(
1332*bb4ee6a4SAndroid Build Coastguard Worker file.0.as_raw_descriptor(),
1333*bb4ee6a4SAndroid Build Coastguard Worker name.as_ptr(),
1334*bb4ee6a4SAndroid Build Coastguard Worker value.as_mut_ptr() as *mut libc::c_void,
1335*bb4ee6a4SAndroid Build Coastguard Worker value.len() as libc::size_t,
1336*bb4ee6a4SAndroid Build Coastguard Worker )
1337*bb4ee6a4SAndroid Build Coastguard Worker }
1338*bb4ee6a4SAndroid Build Coastguard Worker };
1339*bb4ee6a4SAndroid Build Coastguard Worker
1340*bb4ee6a4SAndroid Build Coastguard Worker if res < 0 {
1341*bb4ee6a4SAndroid Build Coastguard Worker Err(io::Error::last_os_error())
1342*bb4ee6a4SAndroid Build Coastguard Worker } else {
1343*bb4ee6a4SAndroid Build Coastguard Worker Ok(res as usize)
1344*bb4ee6a4SAndroid Build Coastguard Worker }
1345*bb4ee6a4SAndroid Build Coastguard Worker }
1346*bb4ee6a4SAndroid Build Coastguard Worker
get_encryption_policy_ex<R: io::Read>( &self, inode: Inode, handle: Handle, mut r: R, ) -> io::Result<IoctlReply>1347*bb4ee6a4SAndroid Build Coastguard Worker fn get_encryption_policy_ex<R: io::Read>(
1348*bb4ee6a4SAndroid Build Coastguard Worker &self,
1349*bb4ee6a4SAndroid Build Coastguard Worker inode: Inode,
1350*bb4ee6a4SAndroid Build Coastguard Worker handle: Handle,
1351*bb4ee6a4SAndroid Build Coastguard Worker mut r: R,
1352*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<IoctlReply> {
1353*bb4ee6a4SAndroid Build Coastguard Worker let data: Arc<dyn AsRawDescriptor> = if self.zero_message_open.load(Ordering::Relaxed) {
1354*bb4ee6a4SAndroid Build Coastguard Worker self.find_inode(inode)?
1355*bb4ee6a4SAndroid Build Coastguard Worker } else {
1356*bb4ee6a4SAndroid Build Coastguard Worker self.find_handle(handle, inode)?
1357*bb4ee6a4SAndroid Build Coastguard Worker };
1358*bb4ee6a4SAndroid Build Coastguard Worker
1359*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this struct only has integer fields and any value is valid.
1360*bb4ee6a4SAndroid Build Coastguard Worker let mut arg = unsafe { MaybeUninit::<fscrypt_get_policy_ex_arg>::zeroed().assume_init() };
1361*bb4ee6a4SAndroid Build Coastguard Worker r.read_exact(arg.policy_size.as_bytes_mut())?;
1362*bb4ee6a4SAndroid Build Coastguard Worker
1363*bb4ee6a4SAndroid Build Coastguard Worker let policy_size = cmp::min(arg.policy_size, size_of::<fscrypt_policy>() as u64);
1364*bb4ee6a4SAndroid Build Coastguard Worker arg.policy_size = policy_size;
1365*bb4ee6a4SAndroid Build Coastguard Worker
1366*bb4ee6a4SAndroid Build Coastguard Worker let res =
1367*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: the kernel will only write to `arg` and we check the return value.
1368*bb4ee6a4SAndroid Build Coastguard Worker unsafe { ioctl_with_mut_ptr(&*data, FS_IOC_GET_ENCRYPTION_POLICY_EX, &mut arg) };
1369*bb4ee6a4SAndroid Build Coastguard Worker if res < 0 {
1370*bb4ee6a4SAndroid Build Coastguard Worker Ok(IoctlReply::Done(Err(io::Error::last_os_error())))
1371*bb4ee6a4SAndroid Build Coastguard Worker } else {
1372*bb4ee6a4SAndroid Build Coastguard Worker let len = size_of::<u64>() + arg.policy_size as usize;
1373*bb4ee6a4SAndroid Build Coastguard Worker Ok(IoctlReply::Done(Ok(<&[u8]>::from(&arg)[..len].to_vec())))
1374*bb4ee6a4SAndroid Build Coastguard Worker }
1375*bb4ee6a4SAndroid Build Coastguard Worker }
1376*bb4ee6a4SAndroid Build Coastguard Worker
get_fsxattr(&self, inode: Inode, handle: Handle) -> io::Result<IoctlReply>1377*bb4ee6a4SAndroid Build Coastguard Worker fn get_fsxattr(&self, inode: Inode, handle: Handle) -> io::Result<IoctlReply> {
1378*bb4ee6a4SAndroid Build Coastguard Worker let data: Arc<dyn AsRawDescriptor> = if self.zero_message_open.load(Ordering::Relaxed) {
1379*bb4ee6a4SAndroid Build Coastguard Worker self.find_inode(inode)?
1380*bb4ee6a4SAndroid Build Coastguard Worker } else {
1381*bb4ee6a4SAndroid Build Coastguard Worker self.find_handle(handle, inode)?
1382*bb4ee6a4SAndroid Build Coastguard Worker };
1383*bb4ee6a4SAndroid Build Coastguard Worker
1384*bb4ee6a4SAndroid Build Coastguard Worker let mut buf = MaybeUninit::<fsxattr>::zeroed();
1385*bb4ee6a4SAndroid Build Coastguard Worker
1386*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: the kernel will only write to `buf` and we check the return value.
1387*bb4ee6a4SAndroid Build Coastguard Worker let res = unsafe { ioctl_with_mut_ptr(&*data, FS_IOC_FSGETXATTR, buf.as_mut_ptr()) };
1388*bb4ee6a4SAndroid Build Coastguard Worker if res < 0 {
1389*bb4ee6a4SAndroid Build Coastguard Worker Ok(IoctlReply::Done(Err(io::Error::last_os_error())))
1390*bb4ee6a4SAndroid Build Coastguard Worker } else {
1391*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: the kernel guarantees that the policy is now initialized.
1392*bb4ee6a4SAndroid Build Coastguard Worker let xattr = unsafe { buf.assume_init() };
1393*bb4ee6a4SAndroid Build Coastguard Worker Ok(IoctlReply::Done(Ok(xattr.as_bytes().to_vec())))
1394*bb4ee6a4SAndroid Build Coastguard Worker }
1395*bb4ee6a4SAndroid Build Coastguard Worker }
1396*bb4ee6a4SAndroid Build Coastguard Worker
set_fsxattr<R: io::Read>( &self, #[cfg_attr(not(feature = "arc_quota"), allow(unused_variables))] ctx: Context, inode: Inode, handle: Handle, mut r: R, ) -> io::Result<IoctlReply>1397*bb4ee6a4SAndroid Build Coastguard Worker fn set_fsxattr<R: io::Read>(
1398*bb4ee6a4SAndroid Build Coastguard Worker &self,
1399*bb4ee6a4SAndroid Build Coastguard Worker #[cfg_attr(not(feature = "arc_quota"), allow(unused_variables))] ctx: Context,
1400*bb4ee6a4SAndroid Build Coastguard Worker inode: Inode,
1401*bb4ee6a4SAndroid Build Coastguard Worker handle: Handle,
1402*bb4ee6a4SAndroid Build Coastguard Worker mut r: R,
1403*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<IoctlReply> {
1404*bb4ee6a4SAndroid Build Coastguard Worker let data: Arc<dyn AsRawDescriptor> = if self.zero_message_open.load(Ordering::Relaxed) {
1405*bb4ee6a4SAndroid Build Coastguard Worker self.find_inode(inode)?
1406*bb4ee6a4SAndroid Build Coastguard Worker } else {
1407*bb4ee6a4SAndroid Build Coastguard Worker self.find_handle(handle, inode)?
1408*bb4ee6a4SAndroid Build Coastguard Worker };
1409*bb4ee6a4SAndroid Build Coastguard Worker
1410*bb4ee6a4SAndroid Build Coastguard Worker let mut in_attr = fsxattr::new_zeroed();
1411*bb4ee6a4SAndroid Build Coastguard Worker r.read_exact(in_attr.as_bytes_mut())?;
1412*bb4ee6a4SAndroid Build Coastguard Worker
1413*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
1414*bb4ee6a4SAndroid Build Coastguard Worker let st = stat(&*data)?;
1415*bb4ee6a4SAndroid Build Coastguard Worker
1416*bb4ee6a4SAndroid Build Coastguard Worker // Changing quota project ID requires CAP_FOWNER or being file owner.
1417*bb4ee6a4SAndroid Build Coastguard Worker // Here we use privileged_quota_uids because we cannot perform a CAP_FOWNER check.
1418*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
1419*bb4ee6a4SAndroid Build Coastguard Worker if ctx.uid == st.st_uid || self.cfg.privileged_quota_uids.contains(&ctx.uid) {
1420*bb4ee6a4SAndroid Build Coastguard Worker // Get the current fsxattr.
1421*bb4ee6a4SAndroid Build Coastguard Worker let mut buf = MaybeUninit::<fsxattr>::zeroed();
1422*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: the kernel will only write to `buf` and we check the return value.
1423*bb4ee6a4SAndroid Build Coastguard Worker let res = unsafe { ioctl_with_mut_ptr(&*data, FS_IOC_FSGETXATTR, buf.as_mut_ptr()) };
1424*bb4ee6a4SAndroid Build Coastguard Worker if res < 0 {
1425*bb4ee6a4SAndroid Build Coastguard Worker return Ok(IoctlReply::Done(Err(io::Error::last_os_error())));
1426*bb4ee6a4SAndroid Build Coastguard Worker }
1427*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: the kernel guarantees that the policy is now initialized.
1428*bb4ee6a4SAndroid Build Coastguard Worker let current_attr = unsafe { buf.assume_init() };
1429*bb4ee6a4SAndroid Build Coastguard Worker
1430*bb4ee6a4SAndroid Build Coastguard Worker // Project ID cannot be changed inside a user namespace.
1431*bb4ee6a4SAndroid Build Coastguard Worker // Use Spaced to avoid this restriction.
1432*bb4ee6a4SAndroid Build Coastguard Worker if current_attr.fsx_projid != in_attr.fsx_projid {
1433*bb4ee6a4SAndroid Build Coastguard Worker let connection = self.dbus_connection.as_ref().unwrap().lock();
1434*bb4ee6a4SAndroid Build Coastguard Worker let proxy = connection.with_proxy(
1435*bb4ee6a4SAndroid Build Coastguard Worker "org.chromium.Spaced",
1436*bb4ee6a4SAndroid Build Coastguard Worker "/org/chromium/Spaced",
1437*bb4ee6a4SAndroid Build Coastguard Worker DEFAULT_DBUS_TIMEOUT,
1438*bb4ee6a4SAndroid Build Coastguard Worker );
1439*bb4ee6a4SAndroid Build Coastguard Worker let project_id = in_attr.fsx_projid;
1440*bb4ee6a4SAndroid Build Coastguard Worker if !is_android_project_id(project_id) {
1441*bb4ee6a4SAndroid Build Coastguard Worker return Err(io::Error::from_raw_os_error(libc::EINVAL));
1442*bb4ee6a4SAndroid Build Coastguard Worker }
1443*bb4ee6a4SAndroid Build Coastguard Worker let file_clone = base::SafeDescriptor::try_from(&*data)?;
1444*bb4ee6a4SAndroid Build Coastguard Worker match proxy.set_project_id(file_clone.into(), project_id) {
1445*bb4ee6a4SAndroid Build Coastguard Worker Ok(r) => {
1446*bb4ee6a4SAndroid Build Coastguard Worker let r = SetProjectIdReply::parse_from_bytes(&r)
1447*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
1448*bb4ee6a4SAndroid Build Coastguard Worker if !r.success {
1449*bb4ee6a4SAndroid Build Coastguard Worker return Ok(IoctlReply::Done(Err(io::Error::from_raw_os_error(
1450*bb4ee6a4SAndroid Build Coastguard Worker r.error,
1451*bb4ee6a4SAndroid Build Coastguard Worker ))));
1452*bb4ee6a4SAndroid Build Coastguard Worker }
1453*bb4ee6a4SAndroid Build Coastguard Worker }
1454*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => {
1455*bb4ee6a4SAndroid Build Coastguard Worker return Err(io::Error::new(io::ErrorKind::Other, e));
1456*bb4ee6a4SAndroid Build Coastguard Worker }
1457*bb4ee6a4SAndroid Build Coastguard Worker };
1458*bb4ee6a4SAndroid Build Coastguard Worker }
1459*bb4ee6a4SAndroid Build Coastguard Worker }
1460*bb4ee6a4SAndroid Build Coastguard Worker
1461*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value.
1462*bb4ee6a4SAndroid Build Coastguard Worker let res = unsafe { ioctl_with_ptr(&*data, FS_IOC_FSSETXATTR, &in_attr) };
1463*bb4ee6a4SAndroid Build Coastguard Worker if res < 0 {
1464*bb4ee6a4SAndroid Build Coastguard Worker Ok(IoctlReply::Done(Err(io::Error::last_os_error())))
1465*bb4ee6a4SAndroid Build Coastguard Worker } else {
1466*bb4ee6a4SAndroid Build Coastguard Worker Ok(IoctlReply::Done(Ok(Vec::new())))
1467*bb4ee6a4SAndroid Build Coastguard Worker }
1468*bb4ee6a4SAndroid Build Coastguard Worker }
1469*bb4ee6a4SAndroid Build Coastguard Worker
get_flags(&self, inode: Inode, handle: Handle) -> io::Result<IoctlReply>1470*bb4ee6a4SAndroid Build Coastguard Worker fn get_flags(&self, inode: Inode, handle: Handle) -> io::Result<IoctlReply> {
1471*bb4ee6a4SAndroid Build Coastguard Worker let data: Arc<dyn AsRawDescriptor> = if self.zero_message_open.load(Ordering::Relaxed) {
1472*bb4ee6a4SAndroid Build Coastguard Worker self.find_inode(inode)?
1473*bb4ee6a4SAndroid Build Coastguard Worker } else {
1474*bb4ee6a4SAndroid Build Coastguard Worker self.find_handle(handle, inode)?
1475*bb4ee6a4SAndroid Build Coastguard Worker };
1476*bb4ee6a4SAndroid Build Coastguard Worker
1477*bb4ee6a4SAndroid Build Coastguard Worker // The ioctl encoding is a long but the parameter is actually an int.
1478*bb4ee6a4SAndroid Build Coastguard Worker let mut flags: c_int = 0;
1479*bb4ee6a4SAndroid Build Coastguard Worker
1480*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: the kernel will only write to `flags` and we check the return value.
1481*bb4ee6a4SAndroid Build Coastguard Worker let res = unsafe { ioctl_with_mut_ptr(&*data, FS_IOC_GETFLAGS, &mut flags) };
1482*bb4ee6a4SAndroid Build Coastguard Worker if res < 0 {
1483*bb4ee6a4SAndroid Build Coastguard Worker Ok(IoctlReply::Done(Err(io::Error::last_os_error())))
1484*bb4ee6a4SAndroid Build Coastguard Worker } else {
1485*bb4ee6a4SAndroid Build Coastguard Worker Ok(IoctlReply::Done(Ok(flags.to_ne_bytes().to_vec())))
1486*bb4ee6a4SAndroid Build Coastguard Worker }
1487*bb4ee6a4SAndroid Build Coastguard Worker }
1488*bb4ee6a4SAndroid Build Coastguard Worker
set_flags<R: io::Read>( &self, #[cfg_attr(not(feature = "arc_quota"), allow(unused_variables))] ctx: Context, inode: Inode, handle: Handle, mut r: R, ) -> io::Result<IoctlReply>1489*bb4ee6a4SAndroid Build Coastguard Worker fn set_flags<R: io::Read>(
1490*bb4ee6a4SAndroid Build Coastguard Worker &self,
1491*bb4ee6a4SAndroid Build Coastguard Worker #[cfg_attr(not(feature = "arc_quota"), allow(unused_variables))] ctx: Context,
1492*bb4ee6a4SAndroid Build Coastguard Worker inode: Inode,
1493*bb4ee6a4SAndroid Build Coastguard Worker handle: Handle,
1494*bb4ee6a4SAndroid Build Coastguard Worker mut r: R,
1495*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<IoctlReply> {
1496*bb4ee6a4SAndroid Build Coastguard Worker let data: Arc<dyn AsRawDescriptor> = if self.zero_message_open.load(Ordering::Relaxed) {
1497*bb4ee6a4SAndroid Build Coastguard Worker self.find_inode(inode)?
1498*bb4ee6a4SAndroid Build Coastguard Worker } else {
1499*bb4ee6a4SAndroid Build Coastguard Worker self.find_handle(handle, inode)?
1500*bb4ee6a4SAndroid Build Coastguard Worker };
1501*bb4ee6a4SAndroid Build Coastguard Worker
1502*bb4ee6a4SAndroid Build Coastguard Worker // The ioctl encoding is a long but the parameter is actually an int.
1503*bb4ee6a4SAndroid Build Coastguard Worker let mut in_flags: c_int = 0;
1504*bb4ee6a4SAndroid Build Coastguard Worker r.read_exact(in_flags.as_bytes_mut())?;
1505*bb4ee6a4SAndroid Build Coastguard Worker
1506*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
1507*bb4ee6a4SAndroid Build Coastguard Worker let st = stat(&*data)?;
1508*bb4ee6a4SAndroid Build Coastguard Worker
1509*bb4ee6a4SAndroid Build Coastguard Worker // Only privleged uid can perform FS_IOC_SETFLAGS through cryptohome.
1510*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
1511*bb4ee6a4SAndroid Build Coastguard Worker if ctx.uid == st.st_uid || self.cfg.privileged_quota_uids.contains(&ctx.uid) {
1512*bb4ee6a4SAndroid Build Coastguard Worker // Get the current flag.
1513*bb4ee6a4SAndroid Build Coastguard Worker let mut buf = MaybeUninit::<c_int>::zeroed();
1514*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: the kernel will only write to `buf` and we check the return value.
1515*bb4ee6a4SAndroid Build Coastguard Worker let res = unsafe { ioctl_with_mut_ptr(&*data, FS_IOC_GETFLAGS, buf.as_mut_ptr()) };
1516*bb4ee6a4SAndroid Build Coastguard Worker if res < 0 {
1517*bb4ee6a4SAndroid Build Coastguard Worker return Ok(IoctlReply::Done(Err(io::Error::last_os_error())));
1518*bb4ee6a4SAndroid Build Coastguard Worker }
1519*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: the kernel guarantees that the policy is now initialized.
1520*bb4ee6a4SAndroid Build Coastguard Worker let current_flags = unsafe { buf.assume_init() };
1521*bb4ee6a4SAndroid Build Coastguard Worker
1522*bb4ee6a4SAndroid Build Coastguard Worker // Project inheritance flag cannot be changed inside a user namespace.
1523*bb4ee6a4SAndroid Build Coastguard Worker // Use Spaced to avoid this restriction.
1524*bb4ee6a4SAndroid Build Coastguard Worker if (in_flags & FS_PROJINHERIT_FL) != (current_flags & FS_PROJINHERIT_FL) {
1525*bb4ee6a4SAndroid Build Coastguard Worker let connection = self.dbus_connection.as_ref().unwrap().lock();
1526*bb4ee6a4SAndroid Build Coastguard Worker let proxy = connection.with_proxy(
1527*bb4ee6a4SAndroid Build Coastguard Worker "org.chromium.Spaced",
1528*bb4ee6a4SAndroid Build Coastguard Worker "/org/chromium/Spaced",
1529*bb4ee6a4SAndroid Build Coastguard Worker DEFAULT_DBUS_TIMEOUT,
1530*bb4ee6a4SAndroid Build Coastguard Worker );
1531*bb4ee6a4SAndroid Build Coastguard Worker // If the input flags contain FS_PROJINHERIT_FL, then it is a set. Otherwise it is a
1532*bb4ee6a4SAndroid Build Coastguard Worker // reset.
1533*bb4ee6a4SAndroid Build Coastguard Worker let enable = (in_flags & FS_PROJINHERIT_FL) == FS_PROJINHERIT_FL;
1534*bb4ee6a4SAndroid Build Coastguard Worker let file_clone = base::SafeDescriptor::try_from(&*data)?;
1535*bb4ee6a4SAndroid Build Coastguard Worker match proxy.set_project_inheritance_flag(file_clone.into(), enable) {
1536*bb4ee6a4SAndroid Build Coastguard Worker Ok(r) => {
1537*bb4ee6a4SAndroid Build Coastguard Worker let r = SetProjectInheritanceFlagReply::parse_from_bytes(&r)
1538*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
1539*bb4ee6a4SAndroid Build Coastguard Worker if !r.success {
1540*bb4ee6a4SAndroid Build Coastguard Worker return Ok(IoctlReply::Done(Err(io::Error::from_raw_os_error(
1541*bb4ee6a4SAndroid Build Coastguard Worker r.error,
1542*bb4ee6a4SAndroid Build Coastguard Worker ))));
1543*bb4ee6a4SAndroid Build Coastguard Worker }
1544*bb4ee6a4SAndroid Build Coastguard Worker }
1545*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => {
1546*bb4ee6a4SAndroid Build Coastguard Worker return Err(io::Error::new(io::ErrorKind::Other, e));
1547*bb4ee6a4SAndroid Build Coastguard Worker }
1548*bb4ee6a4SAndroid Build Coastguard Worker };
1549*bb4ee6a4SAndroid Build Coastguard Worker }
1550*bb4ee6a4SAndroid Build Coastguard Worker }
1551*bb4ee6a4SAndroid Build Coastguard Worker
1552*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value.
1553*bb4ee6a4SAndroid Build Coastguard Worker let res = unsafe { ioctl_with_ptr(&*data, FS_IOC_SETFLAGS, &in_flags) };
1554*bb4ee6a4SAndroid Build Coastguard Worker if res < 0 {
1555*bb4ee6a4SAndroid Build Coastguard Worker Ok(IoctlReply::Done(Err(io::Error::last_os_error())))
1556*bb4ee6a4SAndroid Build Coastguard Worker } else {
1557*bb4ee6a4SAndroid Build Coastguard Worker Ok(IoctlReply::Done(Ok(Vec::new())))
1558*bb4ee6a4SAndroid Build Coastguard Worker }
1559*bb4ee6a4SAndroid Build Coastguard Worker }
1560*bb4ee6a4SAndroid Build Coastguard Worker
enable_verity<R: io::Read>( &self, inode: Inode, handle: Handle, mut r: R, ) -> io::Result<IoctlReply>1561*bb4ee6a4SAndroid Build Coastguard Worker fn enable_verity<R: io::Read>(
1562*bb4ee6a4SAndroid Build Coastguard Worker &self,
1563*bb4ee6a4SAndroid Build Coastguard Worker inode: Inode,
1564*bb4ee6a4SAndroid Build Coastguard Worker handle: Handle,
1565*bb4ee6a4SAndroid Build Coastguard Worker mut r: R,
1566*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<IoctlReply> {
1567*bb4ee6a4SAndroid Build Coastguard Worker let inode_data = self.find_inode(inode)?;
1568*bb4ee6a4SAndroid Build Coastguard Worker
1569*bb4ee6a4SAndroid Build Coastguard Worker // These match the return codes from `fsverity_ioctl_enable` in the kernel.
1570*bb4ee6a4SAndroid Build Coastguard Worker match inode_data.filetype {
1571*bb4ee6a4SAndroid Build Coastguard Worker FileType::Regular => {}
1572*bb4ee6a4SAndroid Build Coastguard Worker FileType::Directory => return Err(io::Error::from_raw_os_error(libc::EISDIR)),
1573*bb4ee6a4SAndroid Build Coastguard Worker FileType::Other => return Err(io::Error::from_raw_os_error(libc::EINVAL)),
1574*bb4ee6a4SAndroid Build Coastguard Worker }
1575*bb4ee6a4SAndroid Build Coastguard Worker
1576*bb4ee6a4SAndroid Build Coastguard Worker {
1577*bb4ee6a4SAndroid Build Coastguard Worker // We cannot enable verity while holding a writable fd so get a new one, if necessary.
1578*bb4ee6a4SAndroid Build Coastguard Worker let mut file = inode_data.file.lock();
1579*bb4ee6a4SAndroid Build Coastguard Worker let mut flags = file.1;
1580*bb4ee6a4SAndroid Build Coastguard Worker match flags & libc::O_ACCMODE {
1581*bb4ee6a4SAndroid Build Coastguard Worker libc::O_WRONLY | libc::O_RDWR => {
1582*bb4ee6a4SAndroid Build Coastguard Worker flags &= !libc::O_ACCMODE;
1583*bb4ee6a4SAndroid Build Coastguard Worker flags |= libc::O_RDONLY;
1584*bb4ee6a4SAndroid Build Coastguard Worker
1585*bb4ee6a4SAndroid Build Coastguard Worker // We need to get a read-only handle for this file.
1586*bb4ee6a4SAndroid Build Coastguard Worker let newfile = self.open_fd(file.0.as_raw_descriptor(), libc::O_RDONLY)?;
1587*bb4ee6a4SAndroid Build Coastguard Worker *file = (newfile, flags);
1588*bb4ee6a4SAndroid Build Coastguard Worker }
1589*bb4ee6a4SAndroid Build Coastguard Worker libc::O_RDONLY => {}
1590*bb4ee6a4SAndroid Build Coastguard Worker _ => panic!("Unexpected flags: {:#x}", flags),
1591*bb4ee6a4SAndroid Build Coastguard Worker }
1592*bb4ee6a4SAndroid Build Coastguard Worker }
1593*bb4ee6a4SAndroid Build Coastguard Worker
1594*bb4ee6a4SAndroid Build Coastguard Worker let data: Arc<dyn AsRawDescriptor> = if self.zero_message_open.load(Ordering::Relaxed) {
1595*bb4ee6a4SAndroid Build Coastguard Worker inode_data
1596*bb4ee6a4SAndroid Build Coastguard Worker } else {
1597*bb4ee6a4SAndroid Build Coastguard Worker let data = self.find_handle(handle, inode)?;
1598*bb4ee6a4SAndroid Build Coastguard Worker
1599*bb4ee6a4SAndroid Build Coastguard Worker {
1600*bb4ee6a4SAndroid Build Coastguard Worker // We can't enable verity while holding a writable fd. We don't know whether the
1601*bb4ee6a4SAndroid Build Coastguard Worker // file was opened for writing so check it here. We don't expect
1602*bb4ee6a4SAndroid Build Coastguard Worker // this to be a frequent operation so the extra latency should be
1603*bb4ee6a4SAndroid Build Coastguard Worker // fine.
1604*bb4ee6a4SAndroid Build Coastguard Worker let mut file = data.file.lock();
1605*bb4ee6a4SAndroid Build Coastguard Worker let flags = FileFlags::from_file(&*file).map_err(io::Error::from)?;
1606*bb4ee6a4SAndroid Build Coastguard Worker match flags {
1607*bb4ee6a4SAndroid Build Coastguard Worker FileFlags::ReadWrite | FileFlags::Write => {
1608*bb4ee6a4SAndroid Build Coastguard Worker // We need to get a read-only handle for this file.
1609*bb4ee6a4SAndroid Build Coastguard Worker *file = self.open_fd(file.as_raw_descriptor(), libc::O_RDONLY)?;
1610*bb4ee6a4SAndroid Build Coastguard Worker }
1611*bb4ee6a4SAndroid Build Coastguard Worker FileFlags::Read => {}
1612*bb4ee6a4SAndroid Build Coastguard Worker }
1613*bb4ee6a4SAndroid Build Coastguard Worker }
1614*bb4ee6a4SAndroid Build Coastguard Worker
1615*bb4ee6a4SAndroid Build Coastguard Worker data
1616*bb4ee6a4SAndroid Build Coastguard Worker };
1617*bb4ee6a4SAndroid Build Coastguard Worker
1618*bb4ee6a4SAndroid Build Coastguard Worker let mut arg = fsverity_enable_arg::new_zeroed();
1619*bb4ee6a4SAndroid Build Coastguard Worker r.read_exact(arg.as_bytes_mut())?;
1620*bb4ee6a4SAndroid Build Coastguard Worker
1621*bb4ee6a4SAndroid Build Coastguard Worker let mut salt;
1622*bb4ee6a4SAndroid Build Coastguard Worker if arg.salt_size > 0 {
1623*bb4ee6a4SAndroid Build Coastguard Worker if arg.salt_size > self.max_buffer_size() {
1624*bb4ee6a4SAndroid Build Coastguard Worker return Ok(IoctlReply::Done(Err(io::Error::from_raw_os_error(
1625*bb4ee6a4SAndroid Build Coastguard Worker libc::ENOMEM,
1626*bb4ee6a4SAndroid Build Coastguard Worker ))));
1627*bb4ee6a4SAndroid Build Coastguard Worker }
1628*bb4ee6a4SAndroid Build Coastguard Worker salt = vec![0; arg.salt_size as usize];
1629*bb4ee6a4SAndroid Build Coastguard Worker r.read_exact(&mut salt)?;
1630*bb4ee6a4SAndroid Build Coastguard Worker arg.salt_ptr = salt.as_ptr() as usize as u64;
1631*bb4ee6a4SAndroid Build Coastguard Worker } else {
1632*bb4ee6a4SAndroid Build Coastguard Worker arg.salt_ptr = 0;
1633*bb4ee6a4SAndroid Build Coastguard Worker }
1634*bb4ee6a4SAndroid Build Coastguard Worker
1635*bb4ee6a4SAndroid Build Coastguard Worker let mut sig;
1636*bb4ee6a4SAndroid Build Coastguard Worker if arg.sig_size > 0 {
1637*bb4ee6a4SAndroid Build Coastguard Worker if arg.sig_size > self.max_buffer_size() {
1638*bb4ee6a4SAndroid Build Coastguard Worker return Ok(IoctlReply::Done(Err(io::Error::from_raw_os_error(
1639*bb4ee6a4SAndroid Build Coastguard Worker libc::ENOMEM,
1640*bb4ee6a4SAndroid Build Coastguard Worker ))));
1641*bb4ee6a4SAndroid Build Coastguard Worker }
1642*bb4ee6a4SAndroid Build Coastguard Worker sig = vec![0; arg.sig_size as usize];
1643*bb4ee6a4SAndroid Build Coastguard Worker r.read_exact(&mut sig)?;
1644*bb4ee6a4SAndroid Build Coastguard Worker arg.sig_ptr = sig.as_ptr() as usize as u64;
1645*bb4ee6a4SAndroid Build Coastguard Worker } else {
1646*bb4ee6a4SAndroid Build Coastguard Worker arg.sig_ptr = 0;
1647*bb4ee6a4SAndroid Build Coastguard Worker }
1648*bb4ee6a4SAndroid Build Coastguard Worker
1649*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value.
1650*bb4ee6a4SAndroid Build Coastguard Worker let res = unsafe { ioctl_with_ptr(&*data, FS_IOC_ENABLE_VERITY, &arg) };
1651*bb4ee6a4SAndroid Build Coastguard Worker if res < 0 {
1652*bb4ee6a4SAndroid Build Coastguard Worker Ok(IoctlReply::Done(Err(io::Error::last_os_error())))
1653*bb4ee6a4SAndroid Build Coastguard Worker } else {
1654*bb4ee6a4SAndroid Build Coastguard Worker Ok(IoctlReply::Done(Ok(Vec::new())))
1655*bb4ee6a4SAndroid Build Coastguard Worker }
1656*bb4ee6a4SAndroid Build Coastguard Worker }
1657*bb4ee6a4SAndroid Build Coastguard Worker
measure_verity<R: io::Read>( &self, inode: Inode, handle: Handle, mut r: R, out_size: u32, ) -> io::Result<IoctlReply>1658*bb4ee6a4SAndroid Build Coastguard Worker fn measure_verity<R: io::Read>(
1659*bb4ee6a4SAndroid Build Coastguard Worker &self,
1660*bb4ee6a4SAndroid Build Coastguard Worker inode: Inode,
1661*bb4ee6a4SAndroid Build Coastguard Worker handle: Handle,
1662*bb4ee6a4SAndroid Build Coastguard Worker mut r: R,
1663*bb4ee6a4SAndroid Build Coastguard Worker out_size: u32,
1664*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<IoctlReply> {
1665*bb4ee6a4SAndroid Build Coastguard Worker let data: Arc<dyn AsRawDescriptor> = if self.zero_message_open.load(Ordering::Relaxed) {
1666*bb4ee6a4SAndroid Build Coastguard Worker self.find_inode(inode)?
1667*bb4ee6a4SAndroid Build Coastguard Worker } else {
1668*bb4ee6a4SAndroid Build Coastguard Worker self.find_handle(handle, inode)?
1669*bb4ee6a4SAndroid Build Coastguard Worker };
1670*bb4ee6a4SAndroid Build Coastguard Worker
1671*bb4ee6a4SAndroid Build Coastguard Worker let mut digest = fsverity_digest::new_zeroed();
1672*bb4ee6a4SAndroid Build Coastguard Worker r.read_exact(digest.as_bytes_mut())?;
1673*bb4ee6a4SAndroid Build Coastguard Worker
1674*bb4ee6a4SAndroid Build Coastguard Worker // Taken from fs/verity/fsverity_private.h.
1675*bb4ee6a4SAndroid Build Coastguard Worker const FS_VERITY_MAX_DIGEST_SIZE: u16 = 64;
1676*bb4ee6a4SAndroid Build Coastguard Worker
1677*bb4ee6a4SAndroid Build Coastguard Worker // This digest size is what the fsverity command line utility uses.
1678*bb4ee6a4SAndroid Build Coastguard Worker const DIGEST_SIZE: u16 = FS_VERITY_MAX_DIGEST_SIZE * 2 + 1;
1679*bb4ee6a4SAndroid Build Coastguard Worker const BUFLEN: usize = size_of::<fsverity_digest>() + DIGEST_SIZE as usize;
1680*bb4ee6a4SAndroid Build Coastguard Worker const ROUNDED_LEN: usize =
1681*bb4ee6a4SAndroid Build Coastguard Worker (BUFLEN + size_of::<fsverity_digest>() - 1) / size_of::<fsverity_digest>();
1682*bb4ee6a4SAndroid Build Coastguard Worker
1683*bb4ee6a4SAndroid Build Coastguard Worker // Make sure we get a properly aligned allocation.
1684*bb4ee6a4SAndroid Build Coastguard Worker let mut buf = [MaybeUninit::<fsverity_digest>::uninit(); ROUNDED_LEN];
1685*bb4ee6a4SAndroid Build Coastguard Worker
1686*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: we are only writing data and not reading uninitialized memory.
1687*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
1688*bb4ee6a4SAndroid Build Coastguard Worker // TODO: Replace with `MaybeUninit::slice_as_mut_ptr` once it is stabilized.
1689*bb4ee6a4SAndroid Build Coastguard Worker addr_of_mut!((*(buf.as_mut_ptr() as *mut fsverity_digest)).digest_size)
1690*bb4ee6a4SAndroid Build Coastguard Worker .write(DIGEST_SIZE)
1691*bb4ee6a4SAndroid Build Coastguard Worker };
1692*bb4ee6a4SAndroid Build Coastguard Worker
1693*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this will only modify `buf` and we check the return value.
1694*bb4ee6a4SAndroid Build Coastguard Worker let res = unsafe { ioctl_with_mut_ptr(&*data, FS_IOC_MEASURE_VERITY, buf.as_mut_ptr()) };
1695*bb4ee6a4SAndroid Build Coastguard Worker if res < 0 {
1696*bb4ee6a4SAndroid Build Coastguard Worker Ok(IoctlReply::Done(Err(io::Error::last_os_error())))
1697*bb4ee6a4SAndroid Build Coastguard Worker } else {
1698*bb4ee6a4SAndroid Build Coastguard Worker let digest_size =
1699*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this value was initialized by us already and then overwritten by the kernel.
1700*bb4ee6a4SAndroid Build Coastguard Worker // TODO: Replace with `MaybeUninit::slice_as_ptr` once it is stabilized.
1701*bb4ee6a4SAndroid Build Coastguard Worker unsafe { addr_of!((*(buf.as_ptr() as *const fsverity_digest)).digest_size).read() };
1702*bb4ee6a4SAndroid Build Coastguard Worker let outlen = size_of::<fsverity_digest>() as u32 + u32::from(digest_size);
1703*bb4ee6a4SAndroid Build Coastguard Worker
1704*bb4ee6a4SAndroid Build Coastguard Worker // The kernel guarantees this but it doesn't hurt to be paranoid.
1705*bb4ee6a4SAndroid Build Coastguard Worker debug_assert!(outlen <= (ROUNDED_LEN * size_of::<fsverity_digest>()) as u32);
1706*bb4ee6a4SAndroid Build Coastguard Worker if digest.digest_size < digest_size || out_size < outlen {
1707*bb4ee6a4SAndroid Build Coastguard Worker return Ok(IoctlReply::Done(Err(io::Error::from_raw_os_error(
1708*bb4ee6a4SAndroid Build Coastguard Worker libc::EOVERFLOW,
1709*bb4ee6a4SAndroid Build Coastguard Worker ))));
1710*bb4ee6a4SAndroid Build Coastguard Worker }
1711*bb4ee6a4SAndroid Build Coastguard Worker
1712*bb4ee6a4SAndroid Build Coastguard Worker let buf: [MaybeUninit<u8>; ROUNDED_LEN * size_of::<fsverity_digest>()] =
1713*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: any bit pattern is valid for `MaybeUninit<u8>` and `fsverity_digest`
1714*bb4ee6a4SAndroid Build Coastguard Worker // doesn't contain any references.
1715*bb4ee6a4SAndroid Build Coastguard Worker unsafe { mem::transmute(buf) };
1716*bb4ee6a4SAndroid Build Coastguard Worker
1717*bb4ee6a4SAndroid Build Coastguard Worker let buf =
1718*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: Casting to `*const [u8]` is safe because the kernel guarantees that the
1719*bb4ee6a4SAndroid Build Coastguard Worker // first `outlen` bytes of `buf` are initialized and `MaybeUninit<u8>` is guaranteed
1720*bb4ee6a4SAndroid Build Coastguard Worker // to have the same layout as `u8`.
1721*bb4ee6a4SAndroid Build Coastguard Worker // TODO: Replace with `MaybeUninit::slice_assume_init_ref` once it is stabilized.
1722*bb4ee6a4SAndroid Build Coastguard Worker unsafe { &*(&buf[..outlen as usize] as *const [MaybeUninit<u8>] as *const [u8]) };
1723*bb4ee6a4SAndroid Build Coastguard Worker Ok(IoctlReply::Done(Ok(buf.to_vec())))
1724*bb4ee6a4SAndroid Build Coastguard Worker }
1725*bb4ee6a4SAndroid Build Coastguard Worker }
1726*bb4ee6a4SAndroid Build Coastguard Worker }
1727*bb4ee6a4SAndroid Build Coastguard Worker
1728*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "fs_runtime_ugid_map")]
1729*bb4ee6a4SAndroid Build Coastguard Worker impl PassthroughFs {
find_and_set_ugid_permission( &self, st: &mut libc::stat64, path: &str, is_root_path: bool, ) -> bool1730*bb4ee6a4SAndroid Build Coastguard Worker fn find_and_set_ugid_permission(
1731*bb4ee6a4SAndroid Build Coastguard Worker &self,
1732*bb4ee6a4SAndroid Build Coastguard Worker st: &mut libc::stat64,
1733*bb4ee6a4SAndroid Build Coastguard Worker path: &str,
1734*bb4ee6a4SAndroid Build Coastguard Worker is_root_path: bool,
1735*bb4ee6a4SAndroid Build Coastguard Worker ) -> bool {
1736*bb4ee6a4SAndroid Build Coastguard Worker for perm_data in self
1737*bb4ee6a4SAndroid Build Coastguard Worker .permission_paths
1738*bb4ee6a4SAndroid Build Coastguard Worker .read()
1739*bb4ee6a4SAndroid Build Coastguard Worker .expect("acquire permission_paths read lock")
1740*bb4ee6a4SAndroid Build Coastguard Worker .iter()
1741*bb4ee6a4SAndroid Build Coastguard Worker {
1742*bb4ee6a4SAndroid Build Coastguard Worker if (is_root_path && perm_data.perm_path == "/")
1743*bb4ee6a4SAndroid Build Coastguard Worker || (!is_root_path
1744*bb4ee6a4SAndroid Build Coastguard Worker && perm_data.perm_path != "/"
1745*bb4ee6a4SAndroid Build Coastguard Worker && perm_data.need_set_permission(path))
1746*bb4ee6a4SAndroid Build Coastguard Worker {
1747*bb4ee6a4SAndroid Build Coastguard Worker self.set_permission_from_data(st, perm_data);
1748*bb4ee6a4SAndroid Build Coastguard Worker return true;
1749*bb4ee6a4SAndroid Build Coastguard Worker }
1750*bb4ee6a4SAndroid Build Coastguard Worker }
1751*bb4ee6a4SAndroid Build Coastguard Worker false
1752*bb4ee6a4SAndroid Build Coastguard Worker }
1753*bb4ee6a4SAndroid Build Coastguard Worker
set_permission_from_data(&self, st: &mut libc::stat64, perm_data: &PermissionData)1754*bb4ee6a4SAndroid Build Coastguard Worker fn set_permission_from_data(&self, st: &mut libc::stat64, perm_data: &PermissionData) {
1755*bb4ee6a4SAndroid Build Coastguard Worker st.st_uid = perm_data.guest_uid;
1756*bb4ee6a4SAndroid Build Coastguard Worker st.st_gid = perm_data.guest_gid;
1757*bb4ee6a4SAndroid Build Coastguard Worker st.st_mode = (st.st_mode & libc::S_IFMT) | (0o777 & !perm_data.umask);
1758*bb4ee6a4SAndroid Build Coastguard Worker }
1759*bb4ee6a4SAndroid Build Coastguard Worker
1760*bb4ee6a4SAndroid Build Coastguard Worker /// Set permission according to path
set_ugid_permission(&self, st: &mut libc::stat64, path: &str)1761*bb4ee6a4SAndroid Build Coastguard Worker fn set_ugid_permission(&self, st: &mut libc::stat64, path: &str) {
1762*bb4ee6a4SAndroid Build Coastguard Worker let is_root_path = path.is_empty();
1763*bb4ee6a4SAndroid Build Coastguard Worker
1764*bb4ee6a4SAndroid Build Coastguard Worker if self.find_and_set_ugid_permission(st, path, is_root_path) {
1765*bb4ee6a4SAndroid Build Coastguard Worker return;
1766*bb4ee6a4SAndroid Build Coastguard Worker }
1767*bb4ee6a4SAndroid Build Coastguard Worker
1768*bb4ee6a4SAndroid Build Coastguard Worker if let Some(perm_data) = self
1769*bb4ee6a4SAndroid Build Coastguard Worker .permission_paths
1770*bb4ee6a4SAndroid Build Coastguard Worker .read()
1771*bb4ee6a4SAndroid Build Coastguard Worker .expect("acquire permission_paths read lock")
1772*bb4ee6a4SAndroid Build Coastguard Worker .iter()
1773*bb4ee6a4SAndroid Build Coastguard Worker .find(|pd| pd.perm_path == "/")
1774*bb4ee6a4SAndroid Build Coastguard Worker {
1775*bb4ee6a4SAndroid Build Coastguard Worker self.set_permission_from_data(st, perm_data);
1776*bb4ee6a4SAndroid Build Coastguard Worker }
1777*bb4ee6a4SAndroid Build Coastguard Worker }
1778*bb4ee6a4SAndroid Build Coastguard Worker
1779*bb4ee6a4SAndroid Build Coastguard Worker /// Set host uid/gid to configured value according to path
change_ugid_creds(&self, ctx: &Context, parent_data: &InodeData, name: &CStr) -> (u32, u32)1780*bb4ee6a4SAndroid Build Coastguard Worker fn change_ugid_creds(&self, ctx: &Context, parent_data: &InodeData, name: &CStr) -> (u32, u32) {
1781*bb4ee6a4SAndroid Build Coastguard Worker let path = format!(
1782*bb4ee6a4SAndroid Build Coastguard Worker "{}/{}",
1783*bb4ee6a4SAndroid Build Coastguard Worker parent_data.path.clone(),
1784*bb4ee6a4SAndroid Build Coastguard Worker name.to_str().unwrap_or("<non UTF-8 str>")
1785*bb4ee6a4SAndroid Build Coastguard Worker );
1786*bb4ee6a4SAndroid Build Coastguard Worker
1787*bb4ee6a4SAndroid Build Coastguard Worker let is_root_path = path.is_empty();
1788*bb4ee6a4SAndroid Build Coastguard Worker
1789*bb4ee6a4SAndroid Build Coastguard Worker if self.find_ugid_creds_for_path(&path, is_root_path).is_some() {
1790*bb4ee6a4SAndroid Build Coastguard Worker return self.find_ugid_creds_for_path(&path, is_root_path).unwrap();
1791*bb4ee6a4SAndroid Build Coastguard Worker }
1792*bb4ee6a4SAndroid Build Coastguard Worker
1793*bb4ee6a4SAndroid Build Coastguard Worker if let Some(perm_data) = self
1794*bb4ee6a4SAndroid Build Coastguard Worker .permission_paths
1795*bb4ee6a4SAndroid Build Coastguard Worker .read()
1796*bb4ee6a4SAndroid Build Coastguard Worker .expect("acquire permission_paths read lock")
1797*bb4ee6a4SAndroid Build Coastguard Worker .iter()
1798*bb4ee6a4SAndroid Build Coastguard Worker .find(|pd| pd.perm_path == "/")
1799*bb4ee6a4SAndroid Build Coastguard Worker {
1800*bb4ee6a4SAndroid Build Coastguard Worker return (perm_data.host_uid, perm_data.host_gid);
1801*bb4ee6a4SAndroid Build Coastguard Worker }
1802*bb4ee6a4SAndroid Build Coastguard Worker
1803*bb4ee6a4SAndroid Build Coastguard Worker (ctx.uid, ctx.gid)
1804*bb4ee6a4SAndroid Build Coastguard Worker }
1805*bb4ee6a4SAndroid Build Coastguard Worker
find_ugid_creds_for_path(&self, path: &str, is_root_path: bool) -> Option<(u32, u32)>1806*bb4ee6a4SAndroid Build Coastguard Worker fn find_ugid_creds_for_path(&self, path: &str, is_root_path: bool) -> Option<(u32, u32)> {
1807*bb4ee6a4SAndroid Build Coastguard Worker for perm_data in self
1808*bb4ee6a4SAndroid Build Coastguard Worker .permission_paths
1809*bb4ee6a4SAndroid Build Coastguard Worker .read()
1810*bb4ee6a4SAndroid Build Coastguard Worker .expect("acquire permission_paths read lock")
1811*bb4ee6a4SAndroid Build Coastguard Worker .iter()
1812*bb4ee6a4SAndroid Build Coastguard Worker {
1813*bb4ee6a4SAndroid Build Coastguard Worker if (is_root_path && perm_data.perm_path == "/")
1814*bb4ee6a4SAndroid Build Coastguard Worker || (!is_root_path
1815*bb4ee6a4SAndroid Build Coastguard Worker && perm_data.perm_path != "/"
1816*bb4ee6a4SAndroid Build Coastguard Worker && perm_data.need_set_permission(path))
1817*bb4ee6a4SAndroid Build Coastguard Worker {
1818*bb4ee6a4SAndroid Build Coastguard Worker return Some((perm_data.host_uid, perm_data.host_gid));
1819*bb4ee6a4SAndroid Build Coastguard Worker }
1820*bb4ee6a4SAndroid Build Coastguard Worker }
1821*bb4ee6a4SAndroid Build Coastguard Worker None
1822*bb4ee6a4SAndroid Build Coastguard Worker }
1823*bb4ee6a4SAndroid Build Coastguard Worker }
1824*bb4ee6a4SAndroid Build Coastguard Worker
1825*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
1826*bb4ee6a4SAndroid Build Coastguard Worker impl PassthroughFs {
1827*bb4ee6a4SAndroid Build Coastguard Worker /// Convert u8 slice to string
string_from_u8_slice(&self, buf: &[u8]) -> io::Result<String>1828*bb4ee6a4SAndroid Build Coastguard Worker fn string_from_u8_slice(&self, buf: &[u8]) -> io::Result<String> {
1829*bb4ee6a4SAndroid Build Coastguard Worker match CStr::from_bytes_until_nul(buf).map(|s| s.to_string_lossy().to_string()) {
1830*bb4ee6a4SAndroid Build Coastguard Worker Ok(s) => Ok(s),
1831*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => {
1832*bb4ee6a4SAndroid Build Coastguard Worker error!("fail to convert u8 slice to string: {}", e);
1833*bb4ee6a4SAndroid Build Coastguard Worker Err(io::Error::from_raw_os_error(libc::EINVAL))
1834*bb4ee6a4SAndroid Build Coastguard Worker }
1835*bb4ee6a4SAndroid Build Coastguard Worker }
1836*bb4ee6a4SAndroid Build Coastguard Worker }
1837*bb4ee6a4SAndroid Build Coastguard Worker
1838*bb4ee6a4SAndroid Build Coastguard Worker /// Set permission according to path
set_permission(&self, st: &mut libc::stat64, path: &str)1839*bb4ee6a4SAndroid Build Coastguard Worker fn set_permission(&self, st: &mut libc::stat64, path: &str) {
1840*bb4ee6a4SAndroid Build Coastguard Worker for perm_data in self
1841*bb4ee6a4SAndroid Build Coastguard Worker .permission_paths
1842*bb4ee6a4SAndroid Build Coastguard Worker .read()
1843*bb4ee6a4SAndroid Build Coastguard Worker .expect("acquire permission_paths read lock")
1844*bb4ee6a4SAndroid Build Coastguard Worker .iter()
1845*bb4ee6a4SAndroid Build Coastguard Worker {
1846*bb4ee6a4SAndroid Build Coastguard Worker if perm_data.need_set_permission(path) {
1847*bb4ee6a4SAndroid Build Coastguard Worker st.st_uid = perm_data.guest_uid;
1848*bb4ee6a4SAndroid Build Coastguard Worker st.st_gid = perm_data.guest_gid;
1849*bb4ee6a4SAndroid Build Coastguard Worker st.st_mode = (st.st_mode & libc::S_IFMT) | (0o777 & !perm_data.umask);
1850*bb4ee6a4SAndroid Build Coastguard Worker }
1851*bb4ee6a4SAndroid Build Coastguard Worker }
1852*bb4ee6a4SAndroid Build Coastguard Worker }
1853*bb4ee6a4SAndroid Build Coastguard Worker
1854*bb4ee6a4SAndroid Build Coastguard Worker /// Set host uid/gid to configured value according to path
change_creds(&self, ctx: &Context, parent_data: &InodeData, name: &CStr) -> (u32, u32)1855*bb4ee6a4SAndroid Build Coastguard Worker fn change_creds(&self, ctx: &Context, parent_data: &InodeData, name: &CStr) -> (u32, u32) {
1856*bb4ee6a4SAndroid Build Coastguard Worker let path = format!(
1857*bb4ee6a4SAndroid Build Coastguard Worker "{}/{}",
1858*bb4ee6a4SAndroid Build Coastguard Worker parent_data.path.clone(),
1859*bb4ee6a4SAndroid Build Coastguard Worker name.to_str().unwrap_or("<non UTF-8 str>")
1860*bb4ee6a4SAndroid Build Coastguard Worker );
1861*bb4ee6a4SAndroid Build Coastguard Worker
1862*bb4ee6a4SAndroid Build Coastguard Worker for perm_data in self
1863*bb4ee6a4SAndroid Build Coastguard Worker .permission_paths
1864*bb4ee6a4SAndroid Build Coastguard Worker .read()
1865*bb4ee6a4SAndroid Build Coastguard Worker .expect("acquire permission_paths read lock")
1866*bb4ee6a4SAndroid Build Coastguard Worker .iter()
1867*bb4ee6a4SAndroid Build Coastguard Worker {
1868*bb4ee6a4SAndroid Build Coastguard Worker if perm_data.need_set_permission(&path) {
1869*bb4ee6a4SAndroid Build Coastguard Worker return (perm_data.host_uid, perm_data.host_gid);
1870*bb4ee6a4SAndroid Build Coastguard Worker }
1871*bb4ee6a4SAndroid Build Coastguard Worker }
1872*bb4ee6a4SAndroid Build Coastguard Worker
1873*bb4ee6a4SAndroid Build Coastguard Worker (ctx.uid, ctx.gid)
1874*bb4ee6a4SAndroid Build Coastguard Worker }
1875*bb4ee6a4SAndroid Build Coastguard Worker
read_permission_data<R: io::Read>(&self, mut r: R) -> io::Result<PermissionData>1876*bb4ee6a4SAndroid Build Coastguard Worker fn read_permission_data<R: io::Read>(&self, mut r: R) -> io::Result<PermissionData> {
1877*bb4ee6a4SAndroid Build Coastguard Worker let mut fs_permission_data = FsPermissionDataBuffer::new_zeroed();
1878*bb4ee6a4SAndroid Build Coastguard Worker r.read_exact(fs_permission_data.as_bytes_mut())?;
1879*bb4ee6a4SAndroid Build Coastguard Worker
1880*bb4ee6a4SAndroid Build Coastguard Worker let perm_path = self.string_from_u8_slice(&fs_permission_data.perm_path)?;
1881*bb4ee6a4SAndroid Build Coastguard Worker if !perm_path.starts_with('/') {
1882*bb4ee6a4SAndroid Build Coastguard Worker error!("FS_IOC_SETPERMISSION: perm path must start with '/'");
1883*bb4ee6a4SAndroid Build Coastguard Worker return Err(io::Error::from_raw_os_error(libc::EINVAL));
1884*bb4ee6a4SAndroid Build Coastguard Worker }
1885*bb4ee6a4SAndroid Build Coastguard Worker Ok(PermissionData {
1886*bb4ee6a4SAndroid Build Coastguard Worker guest_uid: fs_permission_data.guest_uid,
1887*bb4ee6a4SAndroid Build Coastguard Worker guest_gid: fs_permission_data.guest_gid,
1888*bb4ee6a4SAndroid Build Coastguard Worker host_uid: fs_permission_data.host_uid,
1889*bb4ee6a4SAndroid Build Coastguard Worker host_gid: fs_permission_data.host_gid,
1890*bb4ee6a4SAndroid Build Coastguard Worker umask: fs_permission_data.umask,
1891*bb4ee6a4SAndroid Build Coastguard Worker perm_path,
1892*bb4ee6a4SAndroid Build Coastguard Worker })
1893*bb4ee6a4SAndroid Build Coastguard Worker }
1894*bb4ee6a4SAndroid Build Coastguard Worker
1895*bb4ee6a4SAndroid Build Coastguard Worker /// Sets uid/gid/umask for all files and directories under a specific path.
1896*bb4ee6a4SAndroid Build Coastguard Worker ///
1897*bb4ee6a4SAndroid Build Coastguard Worker /// This ioctl does not correspond to any upstream FUSE feature. It is used for arcvm
1898*bb4ee6a4SAndroid Build Coastguard Worker /// It associates the specified path with the provide uid, gid, and umask values within the
1899*bb4ee6a4SAndroid Build Coastguard Worker /// filesystem metadata.
1900*bb4ee6a4SAndroid Build Coastguard Worker ///
1901*bb4ee6a4SAndroid Build Coastguard Worker /// During subsequent lookup operations, the stored uid/gid/umask values are retrieved and
1902*bb4ee6a4SAndroid Build Coastguard Worker /// applied to all files and directories found under the registered path. Before sending
1903*bb4ee6a4SAndroid Build Coastguard Worker /// file stat information to the client, the uid and gid are substituted by `guest_uid` and
1904*bb4ee6a4SAndroid Build Coastguard Worker /// `guest_gid` if the file falls under the registered path. The file mode is masked by the
1905*bb4ee6a4SAndroid Build Coastguard Worker /// umask.
1906*bb4ee6a4SAndroid Build Coastguard Worker ///
1907*bb4ee6a4SAndroid Build Coastguard Worker /// When the guest creates a file within the specified path, the file gid/uid stat in host
1908*bb4ee6a4SAndroid Build Coastguard Worker /// will be overwritten to `host_uid` and `host_gid` values.
1909*bb4ee6a4SAndroid Build Coastguard Worker ///
1910*bb4ee6a4SAndroid Build Coastguard Worker /// This functionality enables dynamic configuration of ownership and permissions for a
1911*bb4ee6a4SAndroid Build Coastguard Worker /// specific directory hierarchy within the filesystem.
1912*bb4ee6a4SAndroid Build Coastguard Worker ///
1913*bb4ee6a4SAndroid Build Coastguard Worker /// # Notes
1914*bb4ee6a4SAndroid Build Coastguard Worker /// - This method affects all existing and future files under the registered path.
1915*bb4ee6a4SAndroid Build Coastguard Worker /// - The original file ownership and permissions are overridden by the provided values.
1916*bb4ee6a4SAndroid Build Coastguard Worker /// - The registered path should not be renamed
1917*bb4ee6a4SAndroid Build Coastguard Worker /// - Refer go/remove-mount-passthrough-fuse for more design details
set_permission_by_path<R: io::Read>(&self, r: R) -> IoctlReply1918*bb4ee6a4SAndroid Build Coastguard Worker fn set_permission_by_path<R: io::Read>(&self, r: R) -> IoctlReply {
1919*bb4ee6a4SAndroid Build Coastguard Worker if self
1920*bb4ee6a4SAndroid Build Coastguard Worker .permission_paths
1921*bb4ee6a4SAndroid Build Coastguard Worker .read()
1922*bb4ee6a4SAndroid Build Coastguard Worker .expect("acquire permission_paths read lock")
1923*bb4ee6a4SAndroid Build Coastguard Worker .len()
1924*bb4ee6a4SAndroid Build Coastguard Worker >= self.cfg.max_dynamic_perm
1925*bb4ee6a4SAndroid Build Coastguard Worker {
1926*bb4ee6a4SAndroid Build Coastguard Worker error!(
1927*bb4ee6a4SAndroid Build Coastguard Worker "FS_IOC_SETPERMISSION exceeds limits of max_dynamic_perm: {}",
1928*bb4ee6a4SAndroid Build Coastguard Worker self.cfg.max_dynamic_perm
1929*bb4ee6a4SAndroid Build Coastguard Worker );
1930*bb4ee6a4SAndroid Build Coastguard Worker return IoctlReply::Done(Err(io::Error::from_raw_os_error(libc::EPERM)));
1931*bb4ee6a4SAndroid Build Coastguard Worker }
1932*bb4ee6a4SAndroid Build Coastguard Worker
1933*bb4ee6a4SAndroid Build Coastguard Worker let perm_data = match self.read_permission_data(r) {
1934*bb4ee6a4SAndroid Build Coastguard Worker Ok(data) => data,
1935*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => {
1936*bb4ee6a4SAndroid Build Coastguard Worker error!("fail to read permission data: {}", e);
1937*bb4ee6a4SAndroid Build Coastguard Worker return IoctlReply::Done(Err(e));
1938*bb4ee6a4SAndroid Build Coastguard Worker }
1939*bb4ee6a4SAndroid Build Coastguard Worker };
1940*bb4ee6a4SAndroid Build Coastguard Worker
1941*bb4ee6a4SAndroid Build Coastguard Worker self.permission_paths
1942*bb4ee6a4SAndroid Build Coastguard Worker .write()
1943*bb4ee6a4SAndroid Build Coastguard Worker .expect("acquire permission_paths write lock")
1944*bb4ee6a4SAndroid Build Coastguard Worker .push(perm_data);
1945*bb4ee6a4SAndroid Build Coastguard Worker
1946*bb4ee6a4SAndroid Build Coastguard Worker IoctlReply::Done(Ok(Vec::new()))
1947*bb4ee6a4SAndroid Build Coastguard Worker }
1948*bb4ee6a4SAndroid Build Coastguard Worker
1949*bb4ee6a4SAndroid Build Coastguard Worker // Get xattr value according to path and name
get_xattr_by_path(&self, path: &str, name: &str) -> Option<String>1950*bb4ee6a4SAndroid Build Coastguard Worker fn get_xattr_by_path(&self, path: &str, name: &str) -> Option<String> {
1951*bb4ee6a4SAndroid Build Coastguard Worker self.xattr_paths
1952*bb4ee6a4SAndroid Build Coastguard Worker .read()
1953*bb4ee6a4SAndroid Build Coastguard Worker .expect("acquire permission_paths read lock")
1954*bb4ee6a4SAndroid Build Coastguard Worker .iter()
1955*bb4ee6a4SAndroid Build Coastguard Worker .find(|data| data.need_set_guest_xattr(path, name))
1956*bb4ee6a4SAndroid Build Coastguard Worker .map(|data| data.xattr_value.clone())
1957*bb4ee6a4SAndroid Build Coastguard Worker }
1958*bb4ee6a4SAndroid Build Coastguard Worker
skip_host_set_xattr(&self, path: &str, name: &str) -> bool1959*bb4ee6a4SAndroid Build Coastguard Worker fn skip_host_set_xattr(&self, path: &str, name: &str) -> bool {
1960*bb4ee6a4SAndroid Build Coastguard Worker self.get_xattr_by_path(path, name).is_some()
1961*bb4ee6a4SAndroid Build Coastguard Worker }
1962*bb4ee6a4SAndroid Build Coastguard Worker
read_xattr_data<R: io::Read>(&self, mut r: R) -> io::Result<XattrData>1963*bb4ee6a4SAndroid Build Coastguard Worker fn read_xattr_data<R: io::Read>(&self, mut r: R) -> io::Result<XattrData> {
1964*bb4ee6a4SAndroid Build Coastguard Worker let mut fs_path_xattr_data = FsPathXattrDataBuffer::new_zeroed();
1965*bb4ee6a4SAndroid Build Coastguard Worker r.read_exact(fs_path_xattr_data.as_bytes_mut())?;
1966*bb4ee6a4SAndroid Build Coastguard Worker
1967*bb4ee6a4SAndroid Build Coastguard Worker let xattr_path = self.string_from_u8_slice(&fs_path_xattr_data.path)?;
1968*bb4ee6a4SAndroid Build Coastguard Worker if !xattr_path.starts_with('/') {
1969*bb4ee6a4SAndroid Build Coastguard Worker error!("FS_IOC_SETPATHXATTR: perm path must start with '/'");
1970*bb4ee6a4SAndroid Build Coastguard Worker return Err(io::Error::from_raw_os_error(libc::EINVAL));
1971*bb4ee6a4SAndroid Build Coastguard Worker }
1972*bb4ee6a4SAndroid Build Coastguard Worker let xattr_name = self.string_from_u8_slice(&fs_path_xattr_data.xattr_name)?;
1973*bb4ee6a4SAndroid Build Coastguard Worker let xattr_value = self.string_from_u8_slice(&fs_path_xattr_data.xattr_value)?;
1974*bb4ee6a4SAndroid Build Coastguard Worker
1975*bb4ee6a4SAndroid Build Coastguard Worker Ok(XattrData {
1976*bb4ee6a4SAndroid Build Coastguard Worker xattr_path,
1977*bb4ee6a4SAndroid Build Coastguard Worker xattr_name,
1978*bb4ee6a4SAndroid Build Coastguard Worker xattr_value,
1979*bb4ee6a4SAndroid Build Coastguard Worker })
1980*bb4ee6a4SAndroid Build Coastguard Worker }
1981*bb4ee6a4SAndroid Build Coastguard Worker
1982*bb4ee6a4SAndroid Build Coastguard Worker /// Sets xattr value for all files and directories under a specific path.
1983*bb4ee6a4SAndroid Build Coastguard Worker ///
1984*bb4ee6a4SAndroid Build Coastguard Worker /// This ioctl does not correspond to any upstream FUSE feature. It is used for arcvm.
1985*bb4ee6a4SAndroid Build Coastguard Worker /// It associates the specified path and xattr name with a value.
1986*bb4ee6a4SAndroid Build Coastguard Worker ///
1987*bb4ee6a4SAndroid Build Coastguard Worker /// When the getxattr is called for the specified path and name, the predefined
1988*bb4ee6a4SAndroid Build Coastguard Worker /// value is returned.
1989*bb4ee6a4SAndroid Build Coastguard Worker ///
1990*bb4ee6a4SAndroid Build Coastguard Worker /// # Notes
1991*bb4ee6a4SAndroid Build Coastguard Worker /// - This method affects all existing and future files under the registered path.
1992*bb4ee6a4SAndroid Build Coastguard Worker /// - The SECURITY_CONTEXT feature will be disabled if this ioctl is enabled.
1993*bb4ee6a4SAndroid Build Coastguard Worker /// - The registered path should not be renamed
1994*bb4ee6a4SAndroid Build Coastguard Worker /// - Refer go/remove-mount-passthrough-fuse for more design details
set_xattr_by_path<R: io::Read>(&self, r: R) -> IoctlReply1995*bb4ee6a4SAndroid Build Coastguard Worker fn set_xattr_by_path<R: io::Read>(&self, r: R) -> IoctlReply {
1996*bb4ee6a4SAndroid Build Coastguard Worker if self
1997*bb4ee6a4SAndroid Build Coastguard Worker .xattr_paths
1998*bb4ee6a4SAndroid Build Coastguard Worker .read()
1999*bb4ee6a4SAndroid Build Coastguard Worker .expect("acquire xattr_paths read lock")
2000*bb4ee6a4SAndroid Build Coastguard Worker .len()
2001*bb4ee6a4SAndroid Build Coastguard Worker >= self.cfg.max_dynamic_xattr
2002*bb4ee6a4SAndroid Build Coastguard Worker {
2003*bb4ee6a4SAndroid Build Coastguard Worker error!(
2004*bb4ee6a4SAndroid Build Coastguard Worker "FS_IOC_SETPATHXATTR exceeds limits of max_dynamic_xattr: {}",
2005*bb4ee6a4SAndroid Build Coastguard Worker self.cfg.max_dynamic_xattr
2006*bb4ee6a4SAndroid Build Coastguard Worker );
2007*bb4ee6a4SAndroid Build Coastguard Worker return IoctlReply::Done(Err(io::Error::from_raw_os_error(libc::EPERM)));
2008*bb4ee6a4SAndroid Build Coastguard Worker }
2009*bb4ee6a4SAndroid Build Coastguard Worker
2010*bb4ee6a4SAndroid Build Coastguard Worker let xattr_data = match self.read_xattr_data(r) {
2011*bb4ee6a4SAndroid Build Coastguard Worker Ok(data) => data,
2012*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => {
2013*bb4ee6a4SAndroid Build Coastguard Worker error!("fail to read xattr data: {}", e);
2014*bb4ee6a4SAndroid Build Coastguard Worker return IoctlReply::Done(Err(e));
2015*bb4ee6a4SAndroid Build Coastguard Worker }
2016*bb4ee6a4SAndroid Build Coastguard Worker };
2017*bb4ee6a4SAndroid Build Coastguard Worker
2018*bb4ee6a4SAndroid Build Coastguard Worker self.xattr_paths
2019*bb4ee6a4SAndroid Build Coastguard Worker .write()
2020*bb4ee6a4SAndroid Build Coastguard Worker .expect("acquire xattr_paths write lock")
2021*bb4ee6a4SAndroid Build Coastguard Worker .push(xattr_data);
2022*bb4ee6a4SAndroid Build Coastguard Worker
2023*bb4ee6a4SAndroid Build Coastguard Worker IoctlReply::Done(Ok(Vec::new()))
2024*bb4ee6a4SAndroid Build Coastguard Worker }
2025*bb4ee6a4SAndroid Build Coastguard Worker
do_getxattr_with_filter( &self, data: Arc<InodeData>, name: Cow<CStr>, buf: &mut [u8], ) -> io::Result<usize>2026*bb4ee6a4SAndroid Build Coastguard Worker fn do_getxattr_with_filter(
2027*bb4ee6a4SAndroid Build Coastguard Worker &self,
2028*bb4ee6a4SAndroid Build Coastguard Worker data: Arc<InodeData>,
2029*bb4ee6a4SAndroid Build Coastguard Worker name: Cow<CStr>,
2030*bb4ee6a4SAndroid Build Coastguard Worker buf: &mut [u8],
2031*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<usize> {
2032*bb4ee6a4SAndroid Build Coastguard Worker let res: usize = match self.get_xattr_by_path(&data.path, &name.to_string_lossy()) {
2033*bb4ee6a4SAndroid Build Coastguard Worker Some(predifined_xattr) => {
2034*bb4ee6a4SAndroid Build Coastguard Worker let x = predifined_xattr.into_bytes();
2035*bb4ee6a4SAndroid Build Coastguard Worker if x.len() > buf.len() {
2036*bb4ee6a4SAndroid Build Coastguard Worker return Err(io::Error::from_raw_os_error(libc::ERANGE));
2037*bb4ee6a4SAndroid Build Coastguard Worker }
2038*bb4ee6a4SAndroid Build Coastguard Worker buf[..x.len()].copy_from_slice(&x);
2039*bb4ee6a4SAndroid Build Coastguard Worker x.len()
2040*bb4ee6a4SAndroid Build Coastguard Worker }
2041*bb4ee6a4SAndroid Build Coastguard Worker None => self.do_getxattr(&data, &name, &mut buf[..])?,
2042*bb4ee6a4SAndroid Build Coastguard Worker };
2043*bb4ee6a4SAndroid Build Coastguard Worker Ok(res)
2044*bb4ee6a4SAndroid Build Coastguard Worker }
2045*bb4ee6a4SAndroid Build Coastguard Worker }
2046*bb4ee6a4SAndroid Build Coastguard Worker
2047*bb4ee6a4SAndroid Build Coastguard Worker /// Decrements the refcount of the inode.
2048*bb4ee6a4SAndroid Build Coastguard Worker /// Returns `true` if the refcount became 0.
forget_one( inodes: &mut MultikeyBTreeMap<Inode, InodeAltKey, Arc<InodeData>>, inode: Inode, count: u64, ) -> bool2049*bb4ee6a4SAndroid Build Coastguard Worker fn forget_one(
2050*bb4ee6a4SAndroid Build Coastguard Worker inodes: &mut MultikeyBTreeMap<Inode, InodeAltKey, Arc<InodeData>>,
2051*bb4ee6a4SAndroid Build Coastguard Worker inode: Inode,
2052*bb4ee6a4SAndroid Build Coastguard Worker count: u64,
2053*bb4ee6a4SAndroid Build Coastguard Worker ) -> bool {
2054*bb4ee6a4SAndroid Build Coastguard Worker if let Some(data) = inodes.get(&inode) {
2055*bb4ee6a4SAndroid Build Coastguard Worker // Acquiring the write lock on the inode map prevents new lookups from incrementing the
2056*bb4ee6a4SAndroid Build Coastguard Worker // refcount but there is the possibility that a previous lookup already acquired a
2057*bb4ee6a4SAndroid Build Coastguard Worker // reference to the inode data and is in the process of updating the refcount so we need
2058*bb4ee6a4SAndroid Build Coastguard Worker // to loop here until we can decrement successfully.
2059*bb4ee6a4SAndroid Build Coastguard Worker loop {
2060*bb4ee6a4SAndroid Build Coastguard Worker let refcount = data.refcount.load(Ordering::Relaxed);
2061*bb4ee6a4SAndroid Build Coastguard Worker
2062*bb4ee6a4SAndroid Build Coastguard Worker // Saturating sub because it doesn't make sense for a refcount to go below zero and
2063*bb4ee6a4SAndroid Build Coastguard Worker // we don't want misbehaving clients to cause integer overflow.
2064*bb4ee6a4SAndroid Build Coastguard Worker let new_count = refcount.saturating_sub(count);
2065*bb4ee6a4SAndroid Build Coastguard Worker
2066*bb4ee6a4SAndroid Build Coastguard Worker // Synchronizes with the acquire load in `do_lookup`.
2067*bb4ee6a4SAndroid Build Coastguard Worker if data
2068*bb4ee6a4SAndroid Build Coastguard Worker .refcount
2069*bb4ee6a4SAndroid Build Coastguard Worker .compare_exchange_weak(refcount, new_count, Ordering::Release, Ordering::Relaxed)
2070*bb4ee6a4SAndroid Build Coastguard Worker .is_ok()
2071*bb4ee6a4SAndroid Build Coastguard Worker {
2072*bb4ee6a4SAndroid Build Coastguard Worker if new_count == 0 {
2073*bb4ee6a4SAndroid Build Coastguard Worker // We just removed the last refcount for this inode. There's no need for an
2074*bb4ee6a4SAndroid Build Coastguard Worker // acquire fence here because we hold a write lock on the inode map and any
2075*bb4ee6a4SAndroid Build Coastguard Worker // thread that is waiting to do a forget on the same inode will have to wait
2076*bb4ee6a4SAndroid Build Coastguard Worker // until we release the lock. So there's is no other release store for us to
2077*bb4ee6a4SAndroid Build Coastguard Worker // synchronize with before deleting the entry.
2078*bb4ee6a4SAndroid Build Coastguard Worker inodes.remove(&inode);
2079*bb4ee6a4SAndroid Build Coastguard Worker return true;
2080*bb4ee6a4SAndroid Build Coastguard Worker }
2081*bb4ee6a4SAndroid Build Coastguard Worker break;
2082*bb4ee6a4SAndroid Build Coastguard Worker }
2083*bb4ee6a4SAndroid Build Coastguard Worker }
2084*bb4ee6a4SAndroid Build Coastguard Worker }
2085*bb4ee6a4SAndroid Build Coastguard Worker false
2086*bb4ee6a4SAndroid Build Coastguard Worker }
2087*bb4ee6a4SAndroid Build Coastguard Worker
2088*bb4ee6a4SAndroid Build Coastguard Worker // Strips any `user.virtiofs.` prefix from `buf`. If buf contains one or more nul-bytes, each
2089*bb4ee6a4SAndroid Build Coastguard Worker // nul-byte-separated slice is treated as a C string and the prefix is stripped from each one.
strip_xattr_prefix(buf: &mut Vec<u8>)2090*bb4ee6a4SAndroid Build Coastguard Worker fn strip_xattr_prefix(buf: &mut Vec<u8>) {
2091*bb4ee6a4SAndroid Build Coastguard Worker fn next_cstr(b: &[u8], start: usize) -> Option<&[u8]> {
2092*bb4ee6a4SAndroid Build Coastguard Worker if start >= b.len() {
2093*bb4ee6a4SAndroid Build Coastguard Worker return None;
2094*bb4ee6a4SAndroid Build Coastguard Worker }
2095*bb4ee6a4SAndroid Build Coastguard Worker
2096*bb4ee6a4SAndroid Build Coastguard Worker let end = b[start..]
2097*bb4ee6a4SAndroid Build Coastguard Worker .iter()
2098*bb4ee6a4SAndroid Build Coastguard Worker .position(|&c| c == b'\0')
2099*bb4ee6a4SAndroid Build Coastguard Worker .map(|p| start + p + 1)
2100*bb4ee6a4SAndroid Build Coastguard Worker .unwrap_or(b.len());
2101*bb4ee6a4SAndroid Build Coastguard Worker
2102*bb4ee6a4SAndroid Build Coastguard Worker Some(&b[start..end])
2103*bb4ee6a4SAndroid Build Coastguard Worker }
2104*bb4ee6a4SAndroid Build Coastguard Worker
2105*bb4ee6a4SAndroid Build Coastguard Worker let mut pos = 0;
2106*bb4ee6a4SAndroid Build Coastguard Worker while let Some(name) = next_cstr(buf, pos) {
2107*bb4ee6a4SAndroid Build Coastguard Worker if !name.starts_with(USER_VIRTIOFS_XATTR) {
2108*bb4ee6a4SAndroid Build Coastguard Worker pos += name.len();
2109*bb4ee6a4SAndroid Build Coastguard Worker continue;
2110*bb4ee6a4SAndroid Build Coastguard Worker }
2111*bb4ee6a4SAndroid Build Coastguard Worker
2112*bb4ee6a4SAndroid Build Coastguard Worker let newlen = name.len() - USER_VIRTIOFS_XATTR.len();
2113*bb4ee6a4SAndroid Build Coastguard Worker buf.drain(pos..pos + USER_VIRTIOFS_XATTR.len());
2114*bb4ee6a4SAndroid Build Coastguard Worker pos += newlen;
2115*bb4ee6a4SAndroid Build Coastguard Worker }
2116*bb4ee6a4SAndroid Build Coastguard Worker }
2117*bb4ee6a4SAndroid Build Coastguard Worker
2118*bb4ee6a4SAndroid Build Coastguard Worker impl FileSystem for PassthroughFs {
2119*bb4ee6a4SAndroid Build Coastguard Worker type Inode = Inode;
2120*bb4ee6a4SAndroid Build Coastguard Worker type Handle = Handle;
2121*bb4ee6a4SAndroid Build Coastguard Worker type DirIter = ReadDir<Box<[u8]>>;
2122*bb4ee6a4SAndroid Build Coastguard Worker
init(&self, capable: FsOptions) -> io::Result<FsOptions>2123*bb4ee6a4SAndroid Build Coastguard Worker fn init(&self, capable: FsOptions) -> io::Result<FsOptions> {
2124*bb4ee6a4SAndroid Build Coastguard Worker let root = CString::new(self.root_dir.clone())
2125*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e))?;
2126*bb4ee6a4SAndroid Build Coastguard Worker
2127*bb4ee6a4SAndroid Build Coastguard Worker let flags = libc::O_DIRECTORY | libc::O_NOFOLLOW | libc::O_CLOEXEC;
2128*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value.
2129*bb4ee6a4SAndroid Build Coastguard Worker let raw_descriptor = unsafe { libc::openat64(libc::AT_FDCWD, root.as_ptr(), flags) };
2130*bb4ee6a4SAndroid Build Coastguard Worker if raw_descriptor < 0 {
2131*bb4ee6a4SAndroid Build Coastguard Worker return Err(io::Error::last_os_error());
2132*bb4ee6a4SAndroid Build Coastguard Worker }
2133*bb4ee6a4SAndroid Build Coastguard Worker
2134*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: safe because we just opened this descriptor above.
2135*bb4ee6a4SAndroid Build Coastguard Worker let f = unsafe { File::from_raw_descriptor(raw_descriptor) };
2136*bb4ee6a4SAndroid Build Coastguard Worker
2137*bb4ee6a4SAndroid Build Coastguard Worker let st = stat(&f)?;
2138*bb4ee6a4SAndroid Build Coastguard Worker
2139*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and there is no need to check the return
2140*bb4ee6a4SAndroid Build Coastguard Worker // value because this system call always succeeds. We need to clear the umask here because
2141*bb4ee6a4SAndroid Build Coastguard Worker // we want the client to be able to set all the bits in the mode.
2142*bb4ee6a4SAndroid Build Coastguard Worker unsafe { libc::umask(0o000) };
2143*bb4ee6a4SAndroid Build Coastguard Worker
2144*bb4ee6a4SAndroid Build Coastguard Worker let mut inodes = self.inodes.lock();
2145*bb4ee6a4SAndroid Build Coastguard Worker
2146*bb4ee6a4SAndroid Build Coastguard Worker // Not sure why the root inode gets a refcount of 2 but that's what libfuse does.
2147*bb4ee6a4SAndroid Build Coastguard Worker inodes.insert(
2148*bb4ee6a4SAndroid Build Coastguard Worker ROOT_ID,
2149*bb4ee6a4SAndroid Build Coastguard Worker InodeAltKey {
2150*bb4ee6a4SAndroid Build Coastguard Worker ino: st.st_ino,
2151*bb4ee6a4SAndroid Build Coastguard Worker dev: st.st_dev,
2152*bb4ee6a4SAndroid Build Coastguard Worker },
2153*bb4ee6a4SAndroid Build Coastguard Worker Arc::new(InodeData {
2154*bb4ee6a4SAndroid Build Coastguard Worker inode: ROOT_ID,
2155*bb4ee6a4SAndroid Build Coastguard Worker file: Mutex::new((f, flags)),
2156*bb4ee6a4SAndroid Build Coastguard Worker refcount: AtomicU64::new(2),
2157*bb4ee6a4SAndroid Build Coastguard Worker filetype: st.st_mode.into(),
2158*bb4ee6a4SAndroid Build Coastguard Worker path: "".to_string(),
2159*bb4ee6a4SAndroid Build Coastguard Worker }),
2160*bb4ee6a4SAndroid Build Coastguard Worker );
2161*bb4ee6a4SAndroid Build Coastguard Worker
2162*bb4ee6a4SAndroid Build Coastguard Worker let mut opts = FsOptions::DO_READDIRPLUS
2163*bb4ee6a4SAndroid Build Coastguard Worker | FsOptions::READDIRPLUS_AUTO
2164*bb4ee6a4SAndroid Build Coastguard Worker | FsOptions::EXPORT_SUPPORT
2165*bb4ee6a4SAndroid Build Coastguard Worker | FsOptions::DONT_MASK
2166*bb4ee6a4SAndroid Build Coastguard Worker | FsOptions::CACHE_SYMLINKS;
2167*bb4ee6a4SAndroid Build Coastguard Worker
2168*bb4ee6a4SAndroid Build Coastguard Worker // Device using dynamic xattr feature will have different security context in
2169*bb4ee6a4SAndroid Build Coastguard Worker // host and guests. The SECURITY_CONTEXT feature should not be enabled in the
2170*bb4ee6a4SAndroid Build Coastguard Worker // device.
2171*bb4ee6a4SAndroid Build Coastguard Worker if self.cfg.max_dynamic_xattr == 0 && self.cfg.security_ctx {
2172*bb4ee6a4SAndroid Build Coastguard Worker opts |= FsOptions::SECURITY_CONTEXT;
2173*bb4ee6a4SAndroid Build Coastguard Worker }
2174*bb4ee6a4SAndroid Build Coastguard Worker
2175*bb4ee6a4SAndroid Build Coastguard Worker if self.cfg.posix_acl {
2176*bb4ee6a4SAndroid Build Coastguard Worker opts |= FsOptions::POSIX_ACL;
2177*bb4ee6a4SAndroid Build Coastguard Worker }
2178*bb4ee6a4SAndroid Build Coastguard Worker if self.cfg.writeback && capable.contains(FsOptions::WRITEBACK_CACHE) {
2179*bb4ee6a4SAndroid Build Coastguard Worker opts |= FsOptions::WRITEBACK_CACHE;
2180*bb4ee6a4SAndroid Build Coastguard Worker self.writeback.store(true, Ordering::Relaxed);
2181*bb4ee6a4SAndroid Build Coastguard Worker }
2182*bb4ee6a4SAndroid Build Coastguard Worker if self.cfg.cache_policy == CachePolicy::Always {
2183*bb4ee6a4SAndroid Build Coastguard Worker if capable.contains(FsOptions::ZERO_MESSAGE_OPEN) {
2184*bb4ee6a4SAndroid Build Coastguard Worker opts |= FsOptions::ZERO_MESSAGE_OPEN;
2185*bb4ee6a4SAndroid Build Coastguard Worker self.zero_message_open.store(true, Ordering::Relaxed);
2186*bb4ee6a4SAndroid Build Coastguard Worker }
2187*bb4ee6a4SAndroid Build Coastguard Worker if capable.contains(FsOptions::ZERO_MESSAGE_OPENDIR) {
2188*bb4ee6a4SAndroid Build Coastguard Worker opts |= FsOptions::ZERO_MESSAGE_OPENDIR;
2189*bb4ee6a4SAndroid Build Coastguard Worker self.zero_message_opendir.store(true, Ordering::Relaxed);
2190*bb4ee6a4SAndroid Build Coastguard Worker }
2191*bb4ee6a4SAndroid Build Coastguard Worker }
2192*bb4ee6a4SAndroid Build Coastguard Worker Ok(opts)
2193*bb4ee6a4SAndroid Build Coastguard Worker }
2194*bb4ee6a4SAndroid Build Coastguard Worker
destroy(&self)2195*bb4ee6a4SAndroid Build Coastguard Worker fn destroy(&self) {
2196*bb4ee6a4SAndroid Build Coastguard Worker cros_tracing::trace_simple_print!(VirtioFs, "{:?}: destroy", self);
2197*bb4ee6a4SAndroid Build Coastguard Worker self.handles.lock().clear();
2198*bb4ee6a4SAndroid Build Coastguard Worker self.inodes.lock().clear();
2199*bb4ee6a4SAndroid Build Coastguard Worker }
2200*bb4ee6a4SAndroid Build Coastguard Worker
statfs(&self, _ctx: Context, inode: Inode) -> io::Result<libc::statvfs64>2201*bb4ee6a4SAndroid Build Coastguard Worker fn statfs(&self, _ctx: Context, inode: Inode) -> io::Result<libc::statvfs64> {
2202*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "statfs", inode);
2203*bb4ee6a4SAndroid Build Coastguard Worker let data = self.find_inode(inode)?;
2204*bb4ee6a4SAndroid Build Coastguard Worker
2205*bb4ee6a4SAndroid Build Coastguard Worker let mut out = MaybeUninit::<libc::statvfs64>::zeroed();
2206*bb4ee6a4SAndroid Build Coastguard Worker
2207*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this will only modify `out` and we check the return value.
2208*bb4ee6a4SAndroid Build Coastguard Worker syscall!(unsafe { libc::fstatvfs64(data.as_raw_descriptor(), out.as_mut_ptr()) })?;
2209*bb4ee6a4SAndroid Build Coastguard Worker
2210*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: the kernel guarantees that `out` has been initialized.
2211*bb4ee6a4SAndroid Build Coastguard Worker Ok(unsafe { out.assume_init() })
2212*bb4ee6a4SAndroid Build Coastguard Worker }
2213*bb4ee6a4SAndroid Build Coastguard Worker
lookup(&self, _ctx: Context, parent: Inode, name: &CStr) -> io::Result<Entry>2214*bb4ee6a4SAndroid Build Coastguard Worker fn lookup(&self, _ctx: Context, parent: Inode, name: &CStr) -> io::Result<Entry> {
2215*bb4ee6a4SAndroid Build Coastguard Worker let data = self.find_inode(parent)?;
2216*bb4ee6a4SAndroid Build Coastguard Worker #[allow(unused_variables)]
2217*bb4ee6a4SAndroid Build Coastguard Worker let path = format!(
2218*bb4ee6a4SAndroid Build Coastguard Worker "{}/{}",
2219*bb4ee6a4SAndroid Build Coastguard Worker data.path,
2220*bb4ee6a4SAndroid Build Coastguard Worker name.to_str().unwrap_or("<non UTF-8 path>")
2221*bb4ee6a4SAndroid Build Coastguard Worker );
2222*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "lookup", parent, path);
2223*bb4ee6a4SAndroid Build Coastguard Worker
2224*bb4ee6a4SAndroid Build Coastguard Worker let mut res = self.do_lookup_with_casefold_fallback(&data, name);
2225*bb4ee6a4SAndroid Build Coastguard Worker
2226*bb4ee6a4SAndroid Build Coastguard Worker // FUSE takes a inode=0 as a request to do negative dentry cache.
2227*bb4ee6a4SAndroid Build Coastguard Worker // So, if `negative_timeout` is set, return success with the timeout value and inode=0 as a
2228*bb4ee6a4SAndroid Build Coastguard Worker // response.
2229*bb4ee6a4SAndroid Build Coastguard Worker if let Err(e) = &res {
2230*bb4ee6a4SAndroid Build Coastguard Worker if e.kind() == std::io::ErrorKind::NotFound && !self.cfg.negative_timeout.is_zero() {
2231*bb4ee6a4SAndroid Build Coastguard Worker res = Ok(Entry::new_negative(self.cfg.negative_timeout));
2232*bb4ee6a4SAndroid Build Coastguard Worker }
2233*bb4ee6a4SAndroid Build Coastguard Worker }
2234*bb4ee6a4SAndroid Build Coastguard Worker
2235*bb4ee6a4SAndroid Build Coastguard Worker res
2236*bb4ee6a4SAndroid Build Coastguard Worker }
2237*bb4ee6a4SAndroid Build Coastguard Worker
forget(&self, _ctx: Context, inode: Inode, count: u64)2238*bb4ee6a4SAndroid Build Coastguard Worker fn forget(&self, _ctx: Context, inode: Inode, count: u64) {
2239*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "forget", inode, count);
2240*bb4ee6a4SAndroid Build Coastguard Worker let mut inodes = self.inodes.lock();
2241*bb4ee6a4SAndroid Build Coastguard Worker let caches = self.lock_casefold_lookup_caches();
2242*bb4ee6a4SAndroid Build Coastguard Worker if forget_one(&mut inodes, inode, count) {
2243*bb4ee6a4SAndroid Build Coastguard Worker if let Some(mut c) = caches {
2244*bb4ee6a4SAndroid Build Coastguard Worker c.forget(inode);
2245*bb4ee6a4SAndroid Build Coastguard Worker }
2246*bb4ee6a4SAndroid Build Coastguard Worker }
2247*bb4ee6a4SAndroid Build Coastguard Worker }
2248*bb4ee6a4SAndroid Build Coastguard Worker
batch_forget(&self, _ctx: Context, requests: Vec<(Inode, u64)>)2249*bb4ee6a4SAndroid Build Coastguard Worker fn batch_forget(&self, _ctx: Context, requests: Vec<(Inode, u64)>) {
2250*bb4ee6a4SAndroid Build Coastguard Worker let mut inodes = self.inodes.lock();
2251*bb4ee6a4SAndroid Build Coastguard Worker let mut caches = self.lock_casefold_lookup_caches();
2252*bb4ee6a4SAndroid Build Coastguard Worker for (inode, count) in requests {
2253*bb4ee6a4SAndroid Build Coastguard Worker if forget_one(&mut inodes, inode, count) {
2254*bb4ee6a4SAndroid Build Coastguard Worker if let Some(c) = caches.as_mut() {
2255*bb4ee6a4SAndroid Build Coastguard Worker c.forget(inode);
2256*bb4ee6a4SAndroid Build Coastguard Worker }
2257*bb4ee6a4SAndroid Build Coastguard Worker }
2258*bb4ee6a4SAndroid Build Coastguard Worker }
2259*bb4ee6a4SAndroid Build Coastguard Worker }
2260*bb4ee6a4SAndroid Build Coastguard Worker
opendir( &self, _ctx: Context, inode: Inode, flags: u32, ) -> io::Result<(Option<Handle>, OpenOptions)>2261*bb4ee6a4SAndroid Build Coastguard Worker fn opendir(
2262*bb4ee6a4SAndroid Build Coastguard Worker &self,
2263*bb4ee6a4SAndroid Build Coastguard Worker _ctx: Context,
2264*bb4ee6a4SAndroid Build Coastguard Worker inode: Inode,
2265*bb4ee6a4SAndroid Build Coastguard Worker flags: u32,
2266*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<(Option<Handle>, OpenOptions)> {
2267*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "opendir", inode, flags);
2268*bb4ee6a4SAndroid Build Coastguard Worker if self.zero_message_opendir.load(Ordering::Relaxed) {
2269*bb4ee6a4SAndroid Build Coastguard Worker Err(io::Error::from_raw_os_error(libc::ENOSYS))
2270*bb4ee6a4SAndroid Build Coastguard Worker } else {
2271*bb4ee6a4SAndroid Build Coastguard Worker self.do_open(inode, flags | (libc::O_DIRECTORY as u32))
2272*bb4ee6a4SAndroid Build Coastguard Worker }
2273*bb4ee6a4SAndroid Build Coastguard Worker }
2274*bb4ee6a4SAndroid Build Coastguard Worker
releasedir( &self, _ctx: Context, inode: Inode, _flags: u32, handle: Handle, ) -> io::Result<()>2275*bb4ee6a4SAndroid Build Coastguard Worker fn releasedir(
2276*bb4ee6a4SAndroid Build Coastguard Worker &self,
2277*bb4ee6a4SAndroid Build Coastguard Worker _ctx: Context,
2278*bb4ee6a4SAndroid Build Coastguard Worker inode: Inode,
2279*bb4ee6a4SAndroid Build Coastguard Worker _flags: u32,
2280*bb4ee6a4SAndroid Build Coastguard Worker handle: Handle,
2281*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<()> {
2282*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "releasedir", inode, handle);
2283*bb4ee6a4SAndroid Build Coastguard Worker if self.zero_message_opendir.load(Ordering::Relaxed) {
2284*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
2285*bb4ee6a4SAndroid Build Coastguard Worker } else {
2286*bb4ee6a4SAndroid Build Coastguard Worker self.do_release(inode, handle)
2287*bb4ee6a4SAndroid Build Coastguard Worker }
2288*bb4ee6a4SAndroid Build Coastguard Worker }
2289*bb4ee6a4SAndroid Build Coastguard Worker
mkdir( &self, ctx: Context, parent: Inode, name: &CStr, mode: u32, umask: u32, security_ctx: Option<&CStr>, ) -> io::Result<Entry>2290*bb4ee6a4SAndroid Build Coastguard Worker fn mkdir(
2291*bb4ee6a4SAndroid Build Coastguard Worker &self,
2292*bb4ee6a4SAndroid Build Coastguard Worker ctx: Context,
2293*bb4ee6a4SAndroid Build Coastguard Worker parent: Inode,
2294*bb4ee6a4SAndroid Build Coastguard Worker name: &CStr,
2295*bb4ee6a4SAndroid Build Coastguard Worker mode: u32,
2296*bb4ee6a4SAndroid Build Coastguard Worker umask: u32,
2297*bb4ee6a4SAndroid Build Coastguard Worker security_ctx: Option<&CStr>,
2298*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<Entry> {
2299*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "mkdir", parent, name, mode, umask, security_ctx);
2300*bb4ee6a4SAndroid Build Coastguard Worker let data = self.find_inode(parent)?;
2301*bb4ee6a4SAndroid Build Coastguard Worker
2302*bb4ee6a4SAndroid Build Coastguard Worker let _ctx = security_ctx
2303*bb4ee6a4SAndroid Build Coastguard Worker .filter(|ctx| *ctx != UNLABELED_CSTR)
2304*bb4ee6a4SAndroid Build Coastguard Worker .map(|ctx| ScopedSecurityContext::new(&self.proc, ctx))
2305*bb4ee6a4SAndroid Build Coastguard Worker .transpose()?;
2306*bb4ee6a4SAndroid Build Coastguard Worker
2307*bb4ee6a4SAndroid Build Coastguard Worker #[allow(unused_variables)]
2308*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
2309*bb4ee6a4SAndroid Build Coastguard Worker let (uid, gid) = self.change_creds(&ctx, &data, name);
2310*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "fs_runtime_ugid_map")]
2311*bb4ee6a4SAndroid Build Coastguard Worker let (uid, gid) = self.change_ugid_creds(&ctx, &data, name);
2312*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(not(feature = "fs_permission_translation"))]
2313*bb4ee6a4SAndroid Build Coastguard Worker let (uid, gid) = (ctx.uid, ctx.gid);
2314*bb4ee6a4SAndroid Build Coastguard Worker
2315*bb4ee6a4SAndroid Build Coastguard Worker let (_uid, _gid) = set_creds(uid, gid)?;
2316*bb4ee6a4SAndroid Build Coastguard Worker {
2317*bb4ee6a4SAndroid Build Coastguard Worker let casefold_cache = self.lock_casefold_lookup_caches();
2318*bb4ee6a4SAndroid Build Coastguard Worker let _scoped_umask = ScopedUmask::new(umask);
2319*bb4ee6a4SAndroid Build Coastguard Worker
2320*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value.
2321*bb4ee6a4SAndroid Build Coastguard Worker syscall!(unsafe { libc::mkdirat(data.as_raw_descriptor(), name.as_ptr(), mode) })?;
2322*bb4ee6a4SAndroid Build Coastguard Worker if let Some(mut c) = casefold_cache {
2323*bb4ee6a4SAndroid Build Coastguard Worker c.insert(data.inode, name);
2324*bb4ee6a4SAndroid Build Coastguard Worker }
2325*bb4ee6a4SAndroid Build Coastguard Worker }
2326*bb4ee6a4SAndroid Build Coastguard Worker self.do_lookup(&data, name)
2327*bb4ee6a4SAndroid Build Coastguard Worker }
2328*bb4ee6a4SAndroid Build Coastguard Worker
rmdir(&self, _ctx: Context, parent: Inode, name: &CStr) -> io::Result<()>2329*bb4ee6a4SAndroid Build Coastguard Worker fn rmdir(&self, _ctx: Context, parent: Inode, name: &CStr) -> io::Result<()> {
2330*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "rmdir", parent, name);
2331*bb4ee6a4SAndroid Build Coastguard Worker let data = self.find_inode(parent)?;
2332*bb4ee6a4SAndroid Build Coastguard Worker let casefold_cache = self.lock_casefold_lookup_caches();
2333*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/278691962): If ascii_casefold is enabled, we need to call
2334*bb4ee6a4SAndroid Build Coastguard Worker // `get_case_unfolded_name()` to get the actual name to be unlinked.
2335*bb4ee6a4SAndroid Build Coastguard Worker self.do_unlink(&data, name, libc::AT_REMOVEDIR)?;
2336*bb4ee6a4SAndroid Build Coastguard Worker if let Some(mut c) = casefold_cache {
2337*bb4ee6a4SAndroid Build Coastguard Worker c.remove(data.inode, name);
2338*bb4ee6a4SAndroid Build Coastguard Worker }
2339*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
2340*bb4ee6a4SAndroid Build Coastguard Worker }
2341*bb4ee6a4SAndroid Build Coastguard Worker
readdir( &self, _ctx: Context, inode: Inode, handle: Handle, size: u32, offset: u64, ) -> io::Result<Self::DirIter>2342*bb4ee6a4SAndroid Build Coastguard Worker fn readdir(
2343*bb4ee6a4SAndroid Build Coastguard Worker &self,
2344*bb4ee6a4SAndroid Build Coastguard Worker _ctx: Context,
2345*bb4ee6a4SAndroid Build Coastguard Worker inode: Inode,
2346*bb4ee6a4SAndroid Build Coastguard Worker handle: Handle,
2347*bb4ee6a4SAndroid Build Coastguard Worker size: u32,
2348*bb4ee6a4SAndroid Build Coastguard Worker offset: u64,
2349*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<Self::DirIter> {
2350*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "readdir", inode, handle, size, offset);
2351*bb4ee6a4SAndroid Build Coastguard Worker let buf = vec![0; size as usize].into_boxed_slice();
2352*bb4ee6a4SAndroid Build Coastguard Worker
2353*bb4ee6a4SAndroid Build Coastguard Worker if self.zero_message_opendir.load(Ordering::Relaxed) {
2354*bb4ee6a4SAndroid Build Coastguard Worker let data = self.find_inode(inode)?;
2355*bb4ee6a4SAndroid Build Coastguard Worker ReadDir::new(&*data, offset as libc::off64_t, buf)
2356*bb4ee6a4SAndroid Build Coastguard Worker } else {
2357*bb4ee6a4SAndroid Build Coastguard Worker let data = self.find_handle(handle, inode)?;
2358*bb4ee6a4SAndroid Build Coastguard Worker
2359*bb4ee6a4SAndroid Build Coastguard Worker let dir = data.file.lock();
2360*bb4ee6a4SAndroid Build Coastguard Worker
2361*bb4ee6a4SAndroid Build Coastguard Worker ReadDir::new(&*dir, offset as libc::off64_t, buf)
2362*bb4ee6a4SAndroid Build Coastguard Worker }
2363*bb4ee6a4SAndroid Build Coastguard Worker }
2364*bb4ee6a4SAndroid Build Coastguard Worker
open( &self, _ctx: Context, inode: Inode, flags: u32, ) -> io::Result<(Option<Handle>, OpenOptions)>2365*bb4ee6a4SAndroid Build Coastguard Worker fn open(
2366*bb4ee6a4SAndroid Build Coastguard Worker &self,
2367*bb4ee6a4SAndroid Build Coastguard Worker _ctx: Context,
2368*bb4ee6a4SAndroid Build Coastguard Worker inode: Inode,
2369*bb4ee6a4SAndroid Build Coastguard Worker flags: u32,
2370*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<(Option<Handle>, OpenOptions)> {
2371*bb4ee6a4SAndroid Build Coastguard Worker if self.zero_message_open.load(Ordering::Relaxed) {
2372*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "open (zero-message)", inode, flags);
2373*bb4ee6a4SAndroid Build Coastguard Worker Err(io::Error::from_raw_os_error(libc::ENOSYS))
2374*bb4ee6a4SAndroid Build Coastguard Worker } else {
2375*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "open", inode, flags);
2376*bb4ee6a4SAndroid Build Coastguard Worker self.do_open(inode, flags)
2377*bb4ee6a4SAndroid Build Coastguard Worker }
2378*bb4ee6a4SAndroid Build Coastguard Worker }
2379*bb4ee6a4SAndroid Build Coastguard Worker
release( &self, _ctx: Context, inode: Inode, _flags: u32, handle: Handle, _flush: bool, _flock_release: bool, _lock_owner: Option<u64>, ) -> io::Result<()>2380*bb4ee6a4SAndroid Build Coastguard Worker fn release(
2381*bb4ee6a4SAndroid Build Coastguard Worker &self,
2382*bb4ee6a4SAndroid Build Coastguard Worker _ctx: Context,
2383*bb4ee6a4SAndroid Build Coastguard Worker inode: Inode,
2384*bb4ee6a4SAndroid Build Coastguard Worker _flags: u32,
2385*bb4ee6a4SAndroid Build Coastguard Worker handle: Handle,
2386*bb4ee6a4SAndroid Build Coastguard Worker _flush: bool,
2387*bb4ee6a4SAndroid Build Coastguard Worker _flock_release: bool,
2388*bb4ee6a4SAndroid Build Coastguard Worker _lock_owner: Option<u64>,
2389*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<()> {
2390*bb4ee6a4SAndroid Build Coastguard Worker if self.zero_message_open.load(Ordering::Relaxed) {
2391*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "release (zero-message)", inode, handle);
2392*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
2393*bb4ee6a4SAndroid Build Coastguard Worker } else {
2394*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "release", inode, handle);
2395*bb4ee6a4SAndroid Build Coastguard Worker self.do_release(inode, handle)
2396*bb4ee6a4SAndroid Build Coastguard Worker }
2397*bb4ee6a4SAndroid Build Coastguard Worker }
2398*bb4ee6a4SAndroid Build Coastguard Worker
chromeos_tmpfile( &self, ctx: Context, parent: Self::Inode, mode: u32, umask: u32, security_ctx: Option<&CStr>, ) -> io::Result<Entry>2399*bb4ee6a4SAndroid Build Coastguard Worker fn chromeos_tmpfile(
2400*bb4ee6a4SAndroid Build Coastguard Worker &self,
2401*bb4ee6a4SAndroid Build Coastguard Worker ctx: Context,
2402*bb4ee6a4SAndroid Build Coastguard Worker parent: Self::Inode,
2403*bb4ee6a4SAndroid Build Coastguard Worker mode: u32,
2404*bb4ee6a4SAndroid Build Coastguard Worker umask: u32,
2405*bb4ee6a4SAndroid Build Coastguard Worker security_ctx: Option<&CStr>,
2406*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<Entry> {
2407*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(
2408*bb4ee6a4SAndroid Build Coastguard Worker self.tag,
2409*bb4ee6a4SAndroid Build Coastguard Worker "chromeos_tempfile",
2410*bb4ee6a4SAndroid Build Coastguard Worker parent,
2411*bb4ee6a4SAndroid Build Coastguard Worker mode,
2412*bb4ee6a4SAndroid Build Coastguard Worker umask,
2413*bb4ee6a4SAndroid Build Coastguard Worker security_ctx
2414*bb4ee6a4SAndroid Build Coastguard Worker );
2415*bb4ee6a4SAndroid Build Coastguard Worker let data = self.find_inode(parent)?;
2416*bb4ee6a4SAndroid Build Coastguard Worker
2417*bb4ee6a4SAndroid Build Coastguard Worker let _ctx = security_ctx
2418*bb4ee6a4SAndroid Build Coastguard Worker .filter(|ctx| *ctx != UNLABELED_CSTR)
2419*bb4ee6a4SAndroid Build Coastguard Worker .map(|ctx| ScopedSecurityContext::new(&self.proc, ctx))
2420*bb4ee6a4SAndroid Build Coastguard Worker .transpose()?;
2421*bb4ee6a4SAndroid Build Coastguard Worker
2422*bb4ee6a4SAndroid Build Coastguard Worker let tmpflags = libc::O_RDWR | libc::O_TMPFILE | libc::O_CLOEXEC | libc::O_NOFOLLOW;
2423*bb4ee6a4SAndroid Build Coastguard Worker
2424*bb4ee6a4SAndroid Build Coastguard Worker let current_dir = c".";
2425*bb4ee6a4SAndroid Build Coastguard Worker
2426*bb4ee6a4SAndroid Build Coastguard Worker #[allow(unused_variables)]
2427*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
2428*bb4ee6a4SAndroid Build Coastguard Worker let (uid, gid) = self.change_creds(&ctx, &data, current_dir);
2429*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "fs_runtime_ugid_map")]
2430*bb4ee6a4SAndroid Build Coastguard Worker let (uid, gid) = self.change_ugid_creds(&ctx, &data, current_dir);
2431*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(not(feature = "fs_permission_translation"))]
2432*bb4ee6a4SAndroid Build Coastguard Worker let (uid, gid) = (ctx.uid, ctx.gid);
2433*bb4ee6a4SAndroid Build Coastguard Worker
2434*bb4ee6a4SAndroid Build Coastguard Worker let (_uid, _gid) = set_creds(uid, gid)?;
2435*bb4ee6a4SAndroid Build Coastguard Worker
2436*bb4ee6a4SAndroid Build Coastguard Worker let fd = {
2437*bb4ee6a4SAndroid Build Coastguard Worker let _scoped_umask = ScopedUmask::new(umask);
2438*bb4ee6a4SAndroid Build Coastguard Worker
2439*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value.
2440*bb4ee6a4SAndroid Build Coastguard Worker syscall!(unsafe {
2441*bb4ee6a4SAndroid Build Coastguard Worker libc::openat64(
2442*bb4ee6a4SAndroid Build Coastguard Worker data.as_raw_descriptor(),
2443*bb4ee6a4SAndroid Build Coastguard Worker current_dir.as_ptr(),
2444*bb4ee6a4SAndroid Build Coastguard Worker tmpflags,
2445*bb4ee6a4SAndroid Build Coastguard Worker mode,
2446*bb4ee6a4SAndroid Build Coastguard Worker )
2447*bb4ee6a4SAndroid Build Coastguard Worker })?
2448*bb4ee6a4SAndroid Build Coastguard Worker };
2449*bb4ee6a4SAndroid Build Coastguard Worker // No need to add casefold_cache becuase we created an anonymous file.
2450*bb4ee6a4SAndroid Build Coastguard Worker
2451*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: safe because we just opened this fd.
2452*bb4ee6a4SAndroid Build Coastguard Worker let tmpfile = unsafe { File::from_raw_descriptor(fd) };
2453*bb4ee6a4SAndroid Build Coastguard Worker let st = stat(&tmpfile)?;
2454*bb4ee6a4SAndroid Build Coastguard Worker let path = format!(
2455*bb4ee6a4SAndroid Build Coastguard Worker "{}/{}",
2456*bb4ee6a4SAndroid Build Coastguard Worker data.path.clone(),
2457*bb4ee6a4SAndroid Build Coastguard Worker current_dir.to_str().unwrap_or("<non UTF-8 str>")
2458*bb4ee6a4SAndroid Build Coastguard Worker );
2459*bb4ee6a4SAndroid Build Coastguard Worker Ok(self.add_entry(tmpfile, st, tmpflags, path))
2460*bb4ee6a4SAndroid Build Coastguard Worker }
2461*bb4ee6a4SAndroid Build Coastguard Worker
create( &self, ctx: Context, parent: Inode, name: &CStr, mode: u32, flags: u32, umask: u32, security_ctx: Option<&CStr>, ) -> io::Result<(Entry, Option<Handle>, OpenOptions)>2462*bb4ee6a4SAndroid Build Coastguard Worker fn create(
2463*bb4ee6a4SAndroid Build Coastguard Worker &self,
2464*bb4ee6a4SAndroid Build Coastguard Worker ctx: Context,
2465*bb4ee6a4SAndroid Build Coastguard Worker parent: Inode,
2466*bb4ee6a4SAndroid Build Coastguard Worker name: &CStr,
2467*bb4ee6a4SAndroid Build Coastguard Worker mode: u32,
2468*bb4ee6a4SAndroid Build Coastguard Worker flags: u32,
2469*bb4ee6a4SAndroid Build Coastguard Worker umask: u32,
2470*bb4ee6a4SAndroid Build Coastguard Worker security_ctx: Option<&CStr>,
2471*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<(Entry, Option<Handle>, OpenOptions)> {
2472*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(
2473*bb4ee6a4SAndroid Build Coastguard Worker self.tag,
2474*bb4ee6a4SAndroid Build Coastguard Worker "create",
2475*bb4ee6a4SAndroid Build Coastguard Worker parent,
2476*bb4ee6a4SAndroid Build Coastguard Worker name,
2477*bb4ee6a4SAndroid Build Coastguard Worker mode,
2478*bb4ee6a4SAndroid Build Coastguard Worker flags,
2479*bb4ee6a4SAndroid Build Coastguard Worker umask,
2480*bb4ee6a4SAndroid Build Coastguard Worker security_ctx
2481*bb4ee6a4SAndroid Build Coastguard Worker );
2482*bb4ee6a4SAndroid Build Coastguard Worker let data = self.find_inode(parent)?;
2483*bb4ee6a4SAndroid Build Coastguard Worker
2484*bb4ee6a4SAndroid Build Coastguard Worker let _ctx = security_ctx
2485*bb4ee6a4SAndroid Build Coastguard Worker .filter(|ctx| *ctx != UNLABELED_CSTR)
2486*bb4ee6a4SAndroid Build Coastguard Worker .map(|ctx| ScopedSecurityContext::new(&self.proc, ctx))
2487*bb4ee6a4SAndroid Build Coastguard Worker .transpose()?;
2488*bb4ee6a4SAndroid Build Coastguard Worker
2489*bb4ee6a4SAndroid Build Coastguard Worker #[allow(unused_variables)]
2490*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
2491*bb4ee6a4SAndroid Build Coastguard Worker let (uid, gid) = self.change_creds(&ctx, &data, name);
2492*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "fs_runtime_ugid_map")]
2493*bb4ee6a4SAndroid Build Coastguard Worker let (uid, gid) = self.change_ugid_creds(&ctx, &data, name);
2494*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(not(feature = "fs_permission_translation"))]
2495*bb4ee6a4SAndroid Build Coastguard Worker let (uid, gid) = (ctx.uid, ctx.gid);
2496*bb4ee6a4SAndroid Build Coastguard Worker
2497*bb4ee6a4SAndroid Build Coastguard Worker let (_uid, _gid) = set_creds(uid, gid)?;
2498*bb4ee6a4SAndroid Build Coastguard Worker
2499*bb4ee6a4SAndroid Build Coastguard Worker let flags = self.update_open_flags(flags as i32);
2500*bb4ee6a4SAndroid Build Coastguard Worker let create_flags =
2501*bb4ee6a4SAndroid Build Coastguard Worker (flags | libc::O_CREAT | libc::O_CLOEXEC | libc::O_NOFOLLOW) & !libc::O_DIRECT;
2502*bb4ee6a4SAndroid Build Coastguard Worker
2503*bb4ee6a4SAndroid Build Coastguard Worker let fd = {
2504*bb4ee6a4SAndroid Build Coastguard Worker let _scoped_umask = ScopedUmask::new(umask);
2505*bb4ee6a4SAndroid Build Coastguard Worker let casefold_cache = self.lock_casefold_lookup_caches();
2506*bb4ee6a4SAndroid Build Coastguard Worker
2507*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value. We don't really
2508*bb4ee6a4SAndroid Build Coastguard Worker // check `flags` because if the kernel can't handle poorly specified flags then we have
2509*bb4ee6a4SAndroid Build Coastguard Worker // much bigger problems.
2510*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/278691962): If ascii_casefold is enabled, we need to call
2511*bb4ee6a4SAndroid Build Coastguard Worker // `get_case_unfolded_name()` to get the actual name to be created.
2512*bb4ee6a4SAndroid Build Coastguard Worker let fd = syscall!(unsafe {
2513*bb4ee6a4SAndroid Build Coastguard Worker libc::openat64(data.as_raw_descriptor(), name.as_ptr(), create_flags, mode)
2514*bb4ee6a4SAndroid Build Coastguard Worker })?;
2515*bb4ee6a4SAndroid Build Coastguard Worker if let Some(mut c) = casefold_cache {
2516*bb4ee6a4SAndroid Build Coastguard Worker c.insert(parent, name);
2517*bb4ee6a4SAndroid Build Coastguard Worker }
2518*bb4ee6a4SAndroid Build Coastguard Worker fd
2519*bb4ee6a4SAndroid Build Coastguard Worker };
2520*bb4ee6a4SAndroid Build Coastguard Worker
2521*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: safe because we just opened this fd.
2522*bb4ee6a4SAndroid Build Coastguard Worker let file = unsafe { File::from_raw_descriptor(fd) };
2523*bb4ee6a4SAndroid Build Coastguard Worker
2524*bb4ee6a4SAndroid Build Coastguard Worker let st = stat(&file)?;
2525*bb4ee6a4SAndroid Build Coastguard Worker let path = format!(
2526*bb4ee6a4SAndroid Build Coastguard Worker "{}/{}",
2527*bb4ee6a4SAndroid Build Coastguard Worker data.path.clone(),
2528*bb4ee6a4SAndroid Build Coastguard Worker name.to_str().unwrap_or("<non UTF-8 str>")
2529*bb4ee6a4SAndroid Build Coastguard Worker );
2530*bb4ee6a4SAndroid Build Coastguard Worker let entry = self.add_entry(file, st, create_flags, path);
2531*bb4ee6a4SAndroid Build Coastguard Worker
2532*bb4ee6a4SAndroid Build Coastguard Worker let (handle, opts) = if self.zero_message_open.load(Ordering::Relaxed) {
2533*bb4ee6a4SAndroid Build Coastguard Worker (None, OpenOptions::KEEP_CACHE)
2534*bb4ee6a4SAndroid Build Coastguard Worker } else {
2535*bb4ee6a4SAndroid Build Coastguard Worker self.do_open_at(
2536*bb4ee6a4SAndroid Build Coastguard Worker data,
2537*bb4ee6a4SAndroid Build Coastguard Worker name,
2538*bb4ee6a4SAndroid Build Coastguard Worker entry.inode,
2539*bb4ee6a4SAndroid Build Coastguard Worker flags as u32 & !((libc::O_CREAT | libc::O_EXCL | libc::O_NOCTTY) as u32),
2540*bb4ee6a4SAndroid Build Coastguard Worker )
2541*bb4ee6a4SAndroid Build Coastguard Worker .inspect_err(|_e| {
2542*bb4ee6a4SAndroid Build Coastguard Worker // Don't leak the entry.
2543*bb4ee6a4SAndroid Build Coastguard Worker self.forget(ctx, entry.inode, 1);
2544*bb4ee6a4SAndroid Build Coastguard Worker })?
2545*bb4ee6a4SAndroid Build Coastguard Worker };
2546*bb4ee6a4SAndroid Build Coastguard Worker Ok((entry, handle, opts))
2547*bb4ee6a4SAndroid Build Coastguard Worker }
2548*bb4ee6a4SAndroid Build Coastguard Worker
unlink(&self, _ctx: Context, parent: Inode, name: &CStr) -> io::Result<()>2549*bb4ee6a4SAndroid Build Coastguard Worker fn unlink(&self, _ctx: Context, parent: Inode, name: &CStr) -> io::Result<()> {
2550*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "unlink", parent, name);
2551*bb4ee6a4SAndroid Build Coastguard Worker let data = self.find_inode(parent)?;
2552*bb4ee6a4SAndroid Build Coastguard Worker let casefold_cache = self.lock_casefold_lookup_caches();
2553*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/278691962): If ascii_casefold is enabled, we need to call
2554*bb4ee6a4SAndroid Build Coastguard Worker // `get_case_unfolded_name()` to get the actual name to be unlinked.
2555*bb4ee6a4SAndroid Build Coastguard Worker self.do_unlink(&data, name, 0)?;
2556*bb4ee6a4SAndroid Build Coastguard Worker if let Some(mut c) = casefold_cache {
2557*bb4ee6a4SAndroid Build Coastguard Worker c.remove(data.inode, name);
2558*bb4ee6a4SAndroid Build Coastguard Worker }
2559*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
2560*bb4ee6a4SAndroid Build Coastguard Worker }
2561*bb4ee6a4SAndroid Build Coastguard Worker
read<W: io::Write + ZeroCopyWriter>( &self, _ctx: Context, inode: Inode, handle: Handle, mut w: W, size: u32, offset: u64, _lock_owner: Option<u64>, _flags: u32, ) -> io::Result<usize>2562*bb4ee6a4SAndroid Build Coastguard Worker fn read<W: io::Write + ZeroCopyWriter>(
2563*bb4ee6a4SAndroid Build Coastguard Worker &self,
2564*bb4ee6a4SAndroid Build Coastguard Worker _ctx: Context,
2565*bb4ee6a4SAndroid Build Coastguard Worker inode: Inode,
2566*bb4ee6a4SAndroid Build Coastguard Worker handle: Handle,
2567*bb4ee6a4SAndroid Build Coastguard Worker mut w: W,
2568*bb4ee6a4SAndroid Build Coastguard Worker size: u32,
2569*bb4ee6a4SAndroid Build Coastguard Worker offset: u64,
2570*bb4ee6a4SAndroid Build Coastguard Worker _lock_owner: Option<u64>,
2571*bb4ee6a4SAndroid Build Coastguard Worker _flags: u32,
2572*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<usize> {
2573*bb4ee6a4SAndroid Build Coastguard Worker if self.zero_message_open.load(Ordering::Relaxed) {
2574*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "read (zero-message)", inode, handle, size, offset);
2575*bb4ee6a4SAndroid Build Coastguard Worker let data = self.find_inode(inode)?;
2576*bb4ee6a4SAndroid Build Coastguard Worker
2577*bb4ee6a4SAndroid Build Coastguard Worker let mut file = data.file.lock();
2578*bb4ee6a4SAndroid Build Coastguard Worker let mut flags = file.1;
2579*bb4ee6a4SAndroid Build Coastguard Worker match flags & libc::O_ACCMODE {
2580*bb4ee6a4SAndroid Build Coastguard Worker libc::O_WRONLY => {
2581*bb4ee6a4SAndroid Build Coastguard Worker flags &= !libc::O_WRONLY;
2582*bb4ee6a4SAndroid Build Coastguard Worker flags |= libc::O_RDWR;
2583*bb4ee6a4SAndroid Build Coastguard Worker
2584*bb4ee6a4SAndroid Build Coastguard Worker // We need to get a readable handle for this file.
2585*bb4ee6a4SAndroid Build Coastguard Worker let newfile = self.open_fd(file.0.as_raw_descriptor(), libc::O_RDWR)?;
2586*bb4ee6a4SAndroid Build Coastguard Worker *file = (newfile, flags);
2587*bb4ee6a4SAndroid Build Coastguard Worker }
2588*bb4ee6a4SAndroid Build Coastguard Worker libc::O_RDONLY | libc::O_RDWR => {}
2589*bb4ee6a4SAndroid Build Coastguard Worker _ => panic!("Unexpected flags: {:#x}", flags),
2590*bb4ee6a4SAndroid Build Coastguard Worker }
2591*bb4ee6a4SAndroid Build Coastguard Worker
2592*bb4ee6a4SAndroid Build Coastguard Worker w.write_from(&mut file.0, size as usize, offset)
2593*bb4ee6a4SAndroid Build Coastguard Worker } else {
2594*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "read", inode, handle, size, offset);
2595*bb4ee6a4SAndroid Build Coastguard Worker let data = self.find_handle(handle, inode)?;
2596*bb4ee6a4SAndroid Build Coastguard Worker
2597*bb4ee6a4SAndroid Build Coastguard Worker let mut f = data.file.lock();
2598*bb4ee6a4SAndroid Build Coastguard Worker w.write_from(&mut f, size as usize, offset)
2599*bb4ee6a4SAndroid Build Coastguard Worker }
2600*bb4ee6a4SAndroid Build Coastguard Worker }
2601*bb4ee6a4SAndroid Build Coastguard Worker
write<R: io::Read + ZeroCopyReader>( &self, _ctx: Context, inode: Inode, handle: Handle, mut r: R, size: u32, offset: u64, _lock_owner: Option<u64>, _delayed_write: bool, flags: u32, ) -> io::Result<usize>2602*bb4ee6a4SAndroid Build Coastguard Worker fn write<R: io::Read + ZeroCopyReader>(
2603*bb4ee6a4SAndroid Build Coastguard Worker &self,
2604*bb4ee6a4SAndroid Build Coastguard Worker _ctx: Context,
2605*bb4ee6a4SAndroid Build Coastguard Worker inode: Inode,
2606*bb4ee6a4SAndroid Build Coastguard Worker handle: Handle,
2607*bb4ee6a4SAndroid Build Coastguard Worker mut r: R,
2608*bb4ee6a4SAndroid Build Coastguard Worker size: u32,
2609*bb4ee6a4SAndroid Build Coastguard Worker offset: u64,
2610*bb4ee6a4SAndroid Build Coastguard Worker _lock_owner: Option<u64>,
2611*bb4ee6a4SAndroid Build Coastguard Worker _delayed_write: bool,
2612*bb4ee6a4SAndroid Build Coastguard Worker flags: u32,
2613*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<usize> {
2614*bb4ee6a4SAndroid Build Coastguard Worker // When the WRITE_KILL_PRIV flag is set, drop CAP_FSETID so that the kernel will
2615*bb4ee6a4SAndroid Build Coastguard Worker // automatically clear the setuid and setgid bits for us.
2616*bb4ee6a4SAndroid Build Coastguard Worker let _fsetid = if flags & WRITE_KILL_PRIV != 0 {
2617*bb4ee6a4SAndroid Build Coastguard Worker Some(drop_cap_fsetid()?)
2618*bb4ee6a4SAndroid Build Coastguard Worker } else {
2619*bb4ee6a4SAndroid Build Coastguard Worker None
2620*bb4ee6a4SAndroid Build Coastguard Worker };
2621*bb4ee6a4SAndroid Build Coastguard Worker
2622*bb4ee6a4SAndroid Build Coastguard Worker if self.zero_message_open.load(Ordering::Relaxed) {
2623*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(
2624*bb4ee6a4SAndroid Build Coastguard Worker self.tag,
2625*bb4ee6a4SAndroid Build Coastguard Worker "write (zero-message)",
2626*bb4ee6a4SAndroid Build Coastguard Worker inode,
2627*bb4ee6a4SAndroid Build Coastguard Worker handle,
2628*bb4ee6a4SAndroid Build Coastguard Worker size,
2629*bb4ee6a4SAndroid Build Coastguard Worker offset
2630*bb4ee6a4SAndroid Build Coastguard Worker );
2631*bb4ee6a4SAndroid Build Coastguard Worker
2632*bb4ee6a4SAndroid Build Coastguard Worker let data = self.find_inode(inode)?;
2633*bb4ee6a4SAndroid Build Coastguard Worker
2634*bb4ee6a4SAndroid Build Coastguard Worker let mut file = data.file.lock();
2635*bb4ee6a4SAndroid Build Coastguard Worker let mut flags = file.1;
2636*bb4ee6a4SAndroid Build Coastguard Worker match flags & libc::O_ACCMODE {
2637*bb4ee6a4SAndroid Build Coastguard Worker libc::O_RDONLY => {
2638*bb4ee6a4SAndroid Build Coastguard Worker flags &= !libc::O_RDONLY;
2639*bb4ee6a4SAndroid Build Coastguard Worker flags |= libc::O_RDWR;
2640*bb4ee6a4SAndroid Build Coastguard Worker
2641*bb4ee6a4SAndroid Build Coastguard Worker // We need to get a writable handle for this file.
2642*bb4ee6a4SAndroid Build Coastguard Worker let newfile = self.open_fd(file.0.as_raw_descriptor(), libc::O_RDWR)?;
2643*bb4ee6a4SAndroid Build Coastguard Worker *file = (newfile, flags);
2644*bb4ee6a4SAndroid Build Coastguard Worker }
2645*bb4ee6a4SAndroid Build Coastguard Worker libc::O_WRONLY | libc::O_RDWR => {}
2646*bb4ee6a4SAndroid Build Coastguard Worker _ => panic!("Unexpected flags: {:#x}", flags),
2647*bb4ee6a4SAndroid Build Coastguard Worker }
2648*bb4ee6a4SAndroid Build Coastguard Worker
2649*bb4ee6a4SAndroid Build Coastguard Worker r.read_to(&mut file.0, size as usize, offset)
2650*bb4ee6a4SAndroid Build Coastguard Worker } else {
2651*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "write", inode, handle, size, offset);
2652*bb4ee6a4SAndroid Build Coastguard Worker
2653*bb4ee6a4SAndroid Build Coastguard Worker let data = self.find_handle(handle, inode)?;
2654*bb4ee6a4SAndroid Build Coastguard Worker
2655*bb4ee6a4SAndroid Build Coastguard Worker let mut f = data.file.lock();
2656*bb4ee6a4SAndroid Build Coastguard Worker r.read_to(&mut f, size as usize, offset)
2657*bb4ee6a4SAndroid Build Coastguard Worker }
2658*bb4ee6a4SAndroid Build Coastguard Worker }
2659*bb4ee6a4SAndroid Build Coastguard Worker
getattr( &self, _ctx: Context, inode: Inode, _handle: Option<Handle>, ) -> io::Result<(libc::stat64, Duration)>2660*bb4ee6a4SAndroid Build Coastguard Worker fn getattr(
2661*bb4ee6a4SAndroid Build Coastguard Worker &self,
2662*bb4ee6a4SAndroid Build Coastguard Worker _ctx: Context,
2663*bb4ee6a4SAndroid Build Coastguard Worker inode: Inode,
2664*bb4ee6a4SAndroid Build Coastguard Worker _handle: Option<Handle>,
2665*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<(libc::stat64, Duration)> {
2666*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "getattr", inode, _handle);
2667*bb4ee6a4SAndroid Build Coastguard Worker
2668*bb4ee6a4SAndroid Build Coastguard Worker let data = self.find_inode(inode)?;
2669*bb4ee6a4SAndroid Build Coastguard Worker self.do_getattr(&data)
2670*bb4ee6a4SAndroid Build Coastguard Worker }
2671*bb4ee6a4SAndroid Build Coastguard Worker
setattr( &self, _ctx: Context, inode: Inode, attr: libc::stat64, handle: Option<Handle>, valid: SetattrValid, ) -> io::Result<(libc::stat64, Duration)>2672*bb4ee6a4SAndroid Build Coastguard Worker fn setattr(
2673*bb4ee6a4SAndroid Build Coastguard Worker &self,
2674*bb4ee6a4SAndroid Build Coastguard Worker _ctx: Context,
2675*bb4ee6a4SAndroid Build Coastguard Worker inode: Inode,
2676*bb4ee6a4SAndroid Build Coastguard Worker attr: libc::stat64,
2677*bb4ee6a4SAndroid Build Coastguard Worker handle: Option<Handle>,
2678*bb4ee6a4SAndroid Build Coastguard Worker valid: SetattrValid,
2679*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<(libc::stat64, Duration)> {
2680*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "setattr", inode, handle);
2681*bb4ee6a4SAndroid Build Coastguard Worker let inode_data = self.find_inode(inode)?;
2682*bb4ee6a4SAndroid Build Coastguard Worker
2683*bb4ee6a4SAndroid Build Coastguard Worker enum Data<'a> {
2684*bb4ee6a4SAndroid Build Coastguard Worker Handle(MutexGuard<'a, File>),
2685*bb4ee6a4SAndroid Build Coastguard Worker ProcPath(CString),
2686*bb4ee6a4SAndroid Build Coastguard Worker }
2687*bb4ee6a4SAndroid Build Coastguard Worker
2688*bb4ee6a4SAndroid Build Coastguard Worker // If we have a handle then use it otherwise get a new fd from the inode.
2689*bb4ee6a4SAndroid Build Coastguard Worker let hd;
2690*bb4ee6a4SAndroid Build Coastguard Worker let data = if let Some(handle) = handle.filter(|&h| h != 0) {
2691*bb4ee6a4SAndroid Build Coastguard Worker hd = self.find_handle(handle, inode)?;
2692*bb4ee6a4SAndroid Build Coastguard Worker Data::Handle(hd.file.lock())
2693*bb4ee6a4SAndroid Build Coastguard Worker } else {
2694*bb4ee6a4SAndroid Build Coastguard Worker let pathname = CString::new(format!("self/fd/{}", inode_data.as_raw_descriptor()))
2695*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
2696*bb4ee6a4SAndroid Build Coastguard Worker Data::ProcPath(pathname)
2697*bb4ee6a4SAndroid Build Coastguard Worker };
2698*bb4ee6a4SAndroid Build Coastguard Worker
2699*bb4ee6a4SAndroid Build Coastguard Worker if valid.contains(SetattrValid::MODE) {
2700*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value.
2701*bb4ee6a4SAndroid Build Coastguard Worker syscall!(unsafe {
2702*bb4ee6a4SAndroid Build Coastguard Worker match data {
2703*bb4ee6a4SAndroid Build Coastguard Worker Data::Handle(ref fd) => libc::fchmod(fd.as_raw_descriptor(), attr.st_mode),
2704*bb4ee6a4SAndroid Build Coastguard Worker Data::ProcPath(ref p) => {
2705*bb4ee6a4SAndroid Build Coastguard Worker libc::fchmodat(self.proc.as_raw_descriptor(), p.as_ptr(), attr.st_mode, 0)
2706*bb4ee6a4SAndroid Build Coastguard Worker }
2707*bb4ee6a4SAndroid Build Coastguard Worker }
2708*bb4ee6a4SAndroid Build Coastguard Worker })?;
2709*bb4ee6a4SAndroid Build Coastguard Worker }
2710*bb4ee6a4SAndroid Build Coastguard Worker
2711*bb4ee6a4SAndroid Build Coastguard Worker if valid.intersects(SetattrValid::UID | SetattrValid::GID) {
2712*bb4ee6a4SAndroid Build Coastguard Worker let uid = if valid.contains(SetattrValid::UID) {
2713*bb4ee6a4SAndroid Build Coastguard Worker attr.st_uid
2714*bb4ee6a4SAndroid Build Coastguard Worker } else {
2715*bb4ee6a4SAndroid Build Coastguard Worker // Cannot use -1 here because these are unsigned values.
2716*bb4ee6a4SAndroid Build Coastguard Worker u32::MAX
2717*bb4ee6a4SAndroid Build Coastguard Worker };
2718*bb4ee6a4SAndroid Build Coastguard Worker let gid = if valid.contains(SetattrValid::GID) {
2719*bb4ee6a4SAndroid Build Coastguard Worker attr.st_gid
2720*bb4ee6a4SAndroid Build Coastguard Worker } else {
2721*bb4ee6a4SAndroid Build Coastguard Worker // Cannot use -1 here because these are unsigned values.
2722*bb4ee6a4SAndroid Build Coastguard Worker u32::MAX
2723*bb4ee6a4SAndroid Build Coastguard Worker };
2724*bb4ee6a4SAndroid Build Coastguard Worker
2725*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value.
2726*bb4ee6a4SAndroid Build Coastguard Worker syscall!(unsafe {
2727*bb4ee6a4SAndroid Build Coastguard Worker libc::fchownat(
2728*bb4ee6a4SAndroid Build Coastguard Worker inode_data.as_raw_descriptor(),
2729*bb4ee6a4SAndroid Build Coastguard Worker EMPTY_CSTR.as_ptr(),
2730*bb4ee6a4SAndroid Build Coastguard Worker uid,
2731*bb4ee6a4SAndroid Build Coastguard Worker gid,
2732*bb4ee6a4SAndroid Build Coastguard Worker libc::AT_EMPTY_PATH | libc::AT_SYMLINK_NOFOLLOW,
2733*bb4ee6a4SAndroid Build Coastguard Worker )
2734*bb4ee6a4SAndroid Build Coastguard Worker })?;
2735*bb4ee6a4SAndroid Build Coastguard Worker }
2736*bb4ee6a4SAndroid Build Coastguard Worker
2737*bb4ee6a4SAndroid Build Coastguard Worker if valid.contains(SetattrValid::SIZE) {
2738*bb4ee6a4SAndroid Build Coastguard Worker syscall!(match data {
2739*bb4ee6a4SAndroid Build Coastguard Worker Data::Handle(ref fd) => {
2740*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value.
2741*bb4ee6a4SAndroid Build Coastguard Worker unsafe { libc::ftruncate64(fd.as_raw_descriptor(), attr.st_size) }
2742*bb4ee6a4SAndroid Build Coastguard Worker }
2743*bb4ee6a4SAndroid Build Coastguard Worker _ => {
2744*bb4ee6a4SAndroid Build Coastguard Worker // There is no `ftruncateat` so we need to get a new fd and truncate it.
2745*bb4ee6a4SAndroid Build Coastguard Worker let f = self.open_inode(&inode_data, libc::O_NONBLOCK | libc::O_RDWR)?;
2746*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value.
2747*bb4ee6a4SAndroid Build Coastguard Worker unsafe { libc::ftruncate64(f.as_raw_descriptor(), attr.st_size) }
2748*bb4ee6a4SAndroid Build Coastguard Worker }
2749*bb4ee6a4SAndroid Build Coastguard Worker })?;
2750*bb4ee6a4SAndroid Build Coastguard Worker }
2751*bb4ee6a4SAndroid Build Coastguard Worker
2752*bb4ee6a4SAndroid Build Coastguard Worker if valid.intersects(SetattrValid::ATIME | SetattrValid::MTIME) {
2753*bb4ee6a4SAndroid Build Coastguard Worker let mut tvs = [
2754*bb4ee6a4SAndroid Build Coastguard Worker libc::timespec {
2755*bb4ee6a4SAndroid Build Coastguard Worker tv_sec: 0,
2756*bb4ee6a4SAndroid Build Coastguard Worker tv_nsec: libc::UTIME_OMIT,
2757*bb4ee6a4SAndroid Build Coastguard Worker },
2758*bb4ee6a4SAndroid Build Coastguard Worker libc::timespec {
2759*bb4ee6a4SAndroid Build Coastguard Worker tv_sec: 0,
2760*bb4ee6a4SAndroid Build Coastguard Worker tv_nsec: libc::UTIME_OMIT,
2761*bb4ee6a4SAndroid Build Coastguard Worker },
2762*bb4ee6a4SAndroid Build Coastguard Worker ];
2763*bb4ee6a4SAndroid Build Coastguard Worker
2764*bb4ee6a4SAndroid Build Coastguard Worker if valid.contains(SetattrValid::ATIME_NOW) {
2765*bb4ee6a4SAndroid Build Coastguard Worker tvs[0].tv_nsec = libc::UTIME_NOW;
2766*bb4ee6a4SAndroid Build Coastguard Worker } else if valid.contains(SetattrValid::ATIME) {
2767*bb4ee6a4SAndroid Build Coastguard Worker tvs[0].tv_sec = attr.st_atime;
2768*bb4ee6a4SAndroid Build Coastguard Worker tvs[0].tv_nsec = attr.st_atime_nsec;
2769*bb4ee6a4SAndroid Build Coastguard Worker }
2770*bb4ee6a4SAndroid Build Coastguard Worker
2771*bb4ee6a4SAndroid Build Coastguard Worker if valid.contains(SetattrValid::MTIME_NOW) {
2772*bb4ee6a4SAndroid Build Coastguard Worker tvs[1].tv_nsec = libc::UTIME_NOW;
2773*bb4ee6a4SAndroid Build Coastguard Worker } else if valid.contains(SetattrValid::MTIME) {
2774*bb4ee6a4SAndroid Build Coastguard Worker tvs[1].tv_sec = attr.st_mtime;
2775*bb4ee6a4SAndroid Build Coastguard Worker tvs[1].tv_nsec = attr.st_mtime_nsec;
2776*bb4ee6a4SAndroid Build Coastguard Worker }
2777*bb4ee6a4SAndroid Build Coastguard Worker
2778*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value.
2779*bb4ee6a4SAndroid Build Coastguard Worker syscall!(unsafe {
2780*bb4ee6a4SAndroid Build Coastguard Worker match data {
2781*bb4ee6a4SAndroid Build Coastguard Worker Data::Handle(ref fd) => libc::futimens(fd.as_raw_descriptor(), tvs.as_ptr()),
2782*bb4ee6a4SAndroid Build Coastguard Worker Data::ProcPath(ref p) => {
2783*bb4ee6a4SAndroid Build Coastguard Worker libc::utimensat(self.proc.as_raw_descriptor(), p.as_ptr(), tvs.as_ptr(), 0)
2784*bb4ee6a4SAndroid Build Coastguard Worker }
2785*bb4ee6a4SAndroid Build Coastguard Worker }
2786*bb4ee6a4SAndroid Build Coastguard Worker })?;
2787*bb4ee6a4SAndroid Build Coastguard Worker }
2788*bb4ee6a4SAndroid Build Coastguard Worker
2789*bb4ee6a4SAndroid Build Coastguard Worker self.do_getattr(&inode_data)
2790*bb4ee6a4SAndroid Build Coastguard Worker }
2791*bb4ee6a4SAndroid Build Coastguard Worker
rename( &self, _ctx: Context, olddir: Inode, oldname: &CStr, newdir: Inode, newname: &CStr, flags: u32, ) -> io::Result<()>2792*bb4ee6a4SAndroid Build Coastguard Worker fn rename(
2793*bb4ee6a4SAndroid Build Coastguard Worker &self,
2794*bb4ee6a4SAndroid Build Coastguard Worker _ctx: Context,
2795*bb4ee6a4SAndroid Build Coastguard Worker olddir: Inode,
2796*bb4ee6a4SAndroid Build Coastguard Worker oldname: &CStr,
2797*bb4ee6a4SAndroid Build Coastguard Worker newdir: Inode,
2798*bb4ee6a4SAndroid Build Coastguard Worker newname: &CStr,
2799*bb4ee6a4SAndroid Build Coastguard Worker flags: u32,
2800*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<()> {
2801*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "rename", olddir, oldname, newdir, newname, flags);
2802*bb4ee6a4SAndroid Build Coastguard Worker
2803*bb4ee6a4SAndroid Build Coastguard Worker let old_inode = self.find_inode(olddir)?;
2804*bb4ee6a4SAndroid Build Coastguard Worker let new_inode = self.find_inode(newdir)?;
2805*bb4ee6a4SAndroid Build Coastguard Worker {
2806*bb4ee6a4SAndroid Build Coastguard Worker let casefold_cache = self.lock_casefold_lookup_caches();
2807*bb4ee6a4SAndroid Build Coastguard Worker
2808*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value.
2809*bb4ee6a4SAndroid Build Coastguard Worker // TODO: Switch to libc::renameat2 once https://github.com/rust-lang/libc/pull/1508 lands
2810*bb4ee6a4SAndroid Build Coastguard Worker // and we have glibc 2.28.
2811*bb4ee6a4SAndroid Build Coastguard Worker syscall!(unsafe {
2812*bb4ee6a4SAndroid Build Coastguard Worker libc::syscall(
2813*bb4ee6a4SAndroid Build Coastguard Worker libc::SYS_renameat2,
2814*bb4ee6a4SAndroid Build Coastguard Worker old_inode.as_raw_descriptor(),
2815*bb4ee6a4SAndroid Build Coastguard Worker oldname.as_ptr(),
2816*bb4ee6a4SAndroid Build Coastguard Worker new_inode.as_raw_descriptor(),
2817*bb4ee6a4SAndroid Build Coastguard Worker newname.as_ptr(),
2818*bb4ee6a4SAndroid Build Coastguard Worker flags,
2819*bb4ee6a4SAndroid Build Coastguard Worker )
2820*bb4ee6a4SAndroid Build Coastguard Worker })?;
2821*bb4ee6a4SAndroid Build Coastguard Worker if let Some(mut c) = casefold_cache {
2822*bb4ee6a4SAndroid Build Coastguard Worker c.remove(olddir, oldname);
2823*bb4ee6a4SAndroid Build Coastguard Worker c.insert(newdir, newname);
2824*bb4ee6a4SAndroid Build Coastguard Worker }
2825*bb4ee6a4SAndroid Build Coastguard Worker }
2826*bb4ee6a4SAndroid Build Coastguard Worker
2827*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
2828*bb4ee6a4SAndroid Build Coastguard Worker }
2829*bb4ee6a4SAndroid Build Coastguard Worker
mknod( &self, ctx: Context, parent: Inode, name: &CStr, mode: u32, rdev: u32, umask: u32, security_ctx: Option<&CStr>, ) -> io::Result<Entry>2830*bb4ee6a4SAndroid Build Coastguard Worker fn mknod(
2831*bb4ee6a4SAndroid Build Coastguard Worker &self,
2832*bb4ee6a4SAndroid Build Coastguard Worker ctx: Context,
2833*bb4ee6a4SAndroid Build Coastguard Worker parent: Inode,
2834*bb4ee6a4SAndroid Build Coastguard Worker name: &CStr,
2835*bb4ee6a4SAndroid Build Coastguard Worker mode: u32,
2836*bb4ee6a4SAndroid Build Coastguard Worker rdev: u32,
2837*bb4ee6a4SAndroid Build Coastguard Worker umask: u32,
2838*bb4ee6a4SAndroid Build Coastguard Worker security_ctx: Option<&CStr>,
2839*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<Entry> {
2840*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(
2841*bb4ee6a4SAndroid Build Coastguard Worker self.tag,
2842*bb4ee6a4SAndroid Build Coastguard Worker "mknod",
2843*bb4ee6a4SAndroid Build Coastguard Worker parent,
2844*bb4ee6a4SAndroid Build Coastguard Worker name,
2845*bb4ee6a4SAndroid Build Coastguard Worker mode,
2846*bb4ee6a4SAndroid Build Coastguard Worker rdev,
2847*bb4ee6a4SAndroid Build Coastguard Worker umask,
2848*bb4ee6a4SAndroid Build Coastguard Worker security_ctx
2849*bb4ee6a4SAndroid Build Coastguard Worker );
2850*bb4ee6a4SAndroid Build Coastguard Worker let data = self.find_inode(parent)?;
2851*bb4ee6a4SAndroid Build Coastguard Worker
2852*bb4ee6a4SAndroid Build Coastguard Worker let _ctx = security_ctx
2853*bb4ee6a4SAndroid Build Coastguard Worker .filter(|ctx| *ctx != UNLABELED_CSTR)
2854*bb4ee6a4SAndroid Build Coastguard Worker .map(|ctx| ScopedSecurityContext::new(&self.proc, ctx))
2855*bb4ee6a4SAndroid Build Coastguard Worker .transpose()?;
2856*bb4ee6a4SAndroid Build Coastguard Worker
2857*bb4ee6a4SAndroid Build Coastguard Worker #[allow(unused_variables)]
2858*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
2859*bb4ee6a4SAndroid Build Coastguard Worker let (uid, gid) = self.change_creds(&ctx, &data, name);
2860*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "fs_runtime_ugid_map")]
2861*bb4ee6a4SAndroid Build Coastguard Worker let (uid, gid) = self.change_ugid_creds(&ctx, &data, name);
2862*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(not(feature = "fs_permission_translation"))]
2863*bb4ee6a4SAndroid Build Coastguard Worker let (uid, gid) = (ctx.uid, ctx.gid);
2864*bb4ee6a4SAndroid Build Coastguard Worker
2865*bb4ee6a4SAndroid Build Coastguard Worker let (_uid, _gid) = set_creds(uid, gid)?;
2866*bb4ee6a4SAndroid Build Coastguard Worker {
2867*bb4ee6a4SAndroid Build Coastguard Worker let _scoped_umask = ScopedUmask::new(umask);
2868*bb4ee6a4SAndroid Build Coastguard Worker let casefold_cache = self.lock_casefold_lookup_caches();
2869*bb4ee6a4SAndroid Build Coastguard Worker
2870*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value.
2871*bb4ee6a4SAndroid Build Coastguard Worker syscall!(unsafe {
2872*bb4ee6a4SAndroid Build Coastguard Worker libc::mknodat(
2873*bb4ee6a4SAndroid Build Coastguard Worker data.as_raw_descriptor(),
2874*bb4ee6a4SAndroid Build Coastguard Worker name.as_ptr(),
2875*bb4ee6a4SAndroid Build Coastguard Worker mode as libc::mode_t,
2876*bb4ee6a4SAndroid Build Coastguard Worker rdev as libc::dev_t,
2877*bb4ee6a4SAndroid Build Coastguard Worker )
2878*bb4ee6a4SAndroid Build Coastguard Worker })?;
2879*bb4ee6a4SAndroid Build Coastguard Worker if let Some(mut c) = casefold_cache {
2880*bb4ee6a4SAndroid Build Coastguard Worker c.insert(parent, name);
2881*bb4ee6a4SAndroid Build Coastguard Worker }
2882*bb4ee6a4SAndroid Build Coastguard Worker }
2883*bb4ee6a4SAndroid Build Coastguard Worker
2884*bb4ee6a4SAndroid Build Coastguard Worker self.do_lookup(&data, name)
2885*bb4ee6a4SAndroid Build Coastguard Worker }
2886*bb4ee6a4SAndroid Build Coastguard Worker
link( &self, _ctx: Context, inode: Inode, newparent: Inode, newname: &CStr, ) -> io::Result<Entry>2887*bb4ee6a4SAndroid Build Coastguard Worker fn link(
2888*bb4ee6a4SAndroid Build Coastguard Worker &self,
2889*bb4ee6a4SAndroid Build Coastguard Worker _ctx: Context,
2890*bb4ee6a4SAndroid Build Coastguard Worker inode: Inode,
2891*bb4ee6a4SAndroid Build Coastguard Worker newparent: Inode,
2892*bb4ee6a4SAndroid Build Coastguard Worker newname: &CStr,
2893*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<Entry> {
2894*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "link", inode, newparent, newname);
2895*bb4ee6a4SAndroid Build Coastguard Worker let data = self.find_inode(inode)?;
2896*bb4ee6a4SAndroid Build Coastguard Worker let new_inode = self.find_inode(newparent)?;
2897*bb4ee6a4SAndroid Build Coastguard Worker
2898*bb4ee6a4SAndroid Build Coastguard Worker let path = CString::new(format!("self/fd/{}", data.as_raw_descriptor()))
2899*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
2900*bb4ee6a4SAndroid Build Coastguard Worker
2901*bb4ee6a4SAndroid Build Coastguard Worker {
2902*bb4ee6a4SAndroid Build Coastguard Worker let casefold_cache = self.lock_casefold_lookup_caches();
2903*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value.
2904*bb4ee6a4SAndroid Build Coastguard Worker syscall!(unsafe {
2905*bb4ee6a4SAndroid Build Coastguard Worker libc::linkat(
2906*bb4ee6a4SAndroid Build Coastguard Worker self.proc.as_raw_descriptor(),
2907*bb4ee6a4SAndroid Build Coastguard Worker path.as_ptr(),
2908*bb4ee6a4SAndroid Build Coastguard Worker new_inode.as_raw_descriptor(),
2909*bb4ee6a4SAndroid Build Coastguard Worker newname.as_ptr(),
2910*bb4ee6a4SAndroid Build Coastguard Worker libc::AT_SYMLINK_FOLLOW,
2911*bb4ee6a4SAndroid Build Coastguard Worker )
2912*bb4ee6a4SAndroid Build Coastguard Worker })?;
2913*bb4ee6a4SAndroid Build Coastguard Worker if let Some(mut c) = casefold_cache {
2914*bb4ee6a4SAndroid Build Coastguard Worker c.insert(newparent, newname);
2915*bb4ee6a4SAndroid Build Coastguard Worker }
2916*bb4ee6a4SAndroid Build Coastguard Worker }
2917*bb4ee6a4SAndroid Build Coastguard Worker
2918*bb4ee6a4SAndroid Build Coastguard Worker self.do_lookup(&new_inode, newname)
2919*bb4ee6a4SAndroid Build Coastguard Worker }
2920*bb4ee6a4SAndroid Build Coastguard Worker
symlink( &self, ctx: Context, linkname: &CStr, parent: Inode, name: &CStr, security_ctx: Option<&CStr>, ) -> io::Result<Entry>2921*bb4ee6a4SAndroid Build Coastguard Worker fn symlink(
2922*bb4ee6a4SAndroid Build Coastguard Worker &self,
2923*bb4ee6a4SAndroid Build Coastguard Worker ctx: Context,
2924*bb4ee6a4SAndroid Build Coastguard Worker linkname: &CStr,
2925*bb4ee6a4SAndroid Build Coastguard Worker parent: Inode,
2926*bb4ee6a4SAndroid Build Coastguard Worker name: &CStr,
2927*bb4ee6a4SAndroid Build Coastguard Worker security_ctx: Option<&CStr>,
2928*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<Entry> {
2929*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "symlink", parent, linkname, name, security_ctx);
2930*bb4ee6a4SAndroid Build Coastguard Worker let data = self.find_inode(parent)?;
2931*bb4ee6a4SAndroid Build Coastguard Worker
2932*bb4ee6a4SAndroid Build Coastguard Worker let _ctx = security_ctx
2933*bb4ee6a4SAndroid Build Coastguard Worker .filter(|ctx| *ctx != UNLABELED_CSTR)
2934*bb4ee6a4SAndroid Build Coastguard Worker .map(|ctx| ScopedSecurityContext::new(&self.proc, ctx))
2935*bb4ee6a4SAndroid Build Coastguard Worker .transpose()?;
2936*bb4ee6a4SAndroid Build Coastguard Worker
2937*bb4ee6a4SAndroid Build Coastguard Worker #[allow(unused_variables)]
2938*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
2939*bb4ee6a4SAndroid Build Coastguard Worker let (uid, gid) = self.change_creds(&ctx, &data, name);
2940*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "fs_runtime_ugid_map")]
2941*bb4ee6a4SAndroid Build Coastguard Worker let (uid, gid) = self.change_ugid_creds(&ctx, &data, name);
2942*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(not(feature = "fs_permission_translation"))]
2943*bb4ee6a4SAndroid Build Coastguard Worker let (uid, gid) = (ctx.uid, ctx.gid);
2944*bb4ee6a4SAndroid Build Coastguard Worker
2945*bb4ee6a4SAndroid Build Coastguard Worker let (_uid, _gid) = set_creds(uid, gid)?;
2946*bb4ee6a4SAndroid Build Coastguard Worker {
2947*bb4ee6a4SAndroid Build Coastguard Worker let casefold_cache = self.lock_casefold_lookup_caches();
2948*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value.
2949*bb4ee6a4SAndroid Build Coastguard Worker syscall!(unsafe {
2950*bb4ee6a4SAndroid Build Coastguard Worker libc::symlinkat(linkname.as_ptr(), data.as_raw_descriptor(), name.as_ptr())
2951*bb4ee6a4SAndroid Build Coastguard Worker })?;
2952*bb4ee6a4SAndroid Build Coastguard Worker if let Some(mut c) = casefold_cache {
2953*bb4ee6a4SAndroid Build Coastguard Worker c.insert(parent, name);
2954*bb4ee6a4SAndroid Build Coastguard Worker }
2955*bb4ee6a4SAndroid Build Coastguard Worker }
2956*bb4ee6a4SAndroid Build Coastguard Worker
2957*bb4ee6a4SAndroid Build Coastguard Worker self.do_lookup(&data, name)
2958*bb4ee6a4SAndroid Build Coastguard Worker }
2959*bb4ee6a4SAndroid Build Coastguard Worker
readlink(&self, _ctx: Context, inode: Inode) -> io::Result<Vec<u8>>2960*bb4ee6a4SAndroid Build Coastguard Worker fn readlink(&self, _ctx: Context, inode: Inode) -> io::Result<Vec<u8>> {
2961*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "readlink", inode);
2962*bb4ee6a4SAndroid Build Coastguard Worker let data = self.find_inode(inode)?;
2963*bb4ee6a4SAndroid Build Coastguard Worker
2964*bb4ee6a4SAndroid Build Coastguard Worker let mut buf = vec![0; libc::PATH_MAX as usize];
2965*bb4ee6a4SAndroid Build Coastguard Worker
2966*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this will only modify the contents of `buf` and we check the return value.
2967*bb4ee6a4SAndroid Build Coastguard Worker let res = syscall!(unsafe {
2968*bb4ee6a4SAndroid Build Coastguard Worker libc::readlinkat(
2969*bb4ee6a4SAndroid Build Coastguard Worker data.as_raw_descriptor(),
2970*bb4ee6a4SAndroid Build Coastguard Worker EMPTY_CSTR.as_ptr(),
2971*bb4ee6a4SAndroid Build Coastguard Worker buf.as_mut_ptr() as *mut libc::c_char,
2972*bb4ee6a4SAndroid Build Coastguard Worker buf.len(),
2973*bb4ee6a4SAndroid Build Coastguard Worker )
2974*bb4ee6a4SAndroid Build Coastguard Worker })?;
2975*bb4ee6a4SAndroid Build Coastguard Worker
2976*bb4ee6a4SAndroid Build Coastguard Worker buf.resize(res as usize, 0);
2977*bb4ee6a4SAndroid Build Coastguard Worker
2978*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "fs_runtime_ugid_map")]
2979*bb4ee6a4SAndroid Build Coastguard Worker {
2980*bb4ee6a4SAndroid Build Coastguard Worker let link_target = Path::new(OsStr::from_bytes(&buf[..res as usize]));
2981*bb4ee6a4SAndroid Build Coastguard Worker if !link_target.starts_with(&self.root_dir) {
2982*bb4ee6a4SAndroid Build Coastguard Worker return Err(io::Error::new(
2983*bb4ee6a4SAndroid Build Coastguard Worker io::ErrorKind::InvalidInput,
2984*bb4ee6a4SAndroid Build Coastguard Worker "Symbolic link points outside of root_dir",
2985*bb4ee6a4SAndroid Build Coastguard Worker ));
2986*bb4ee6a4SAndroid Build Coastguard Worker }
2987*bb4ee6a4SAndroid Build Coastguard Worker }
2988*bb4ee6a4SAndroid Build Coastguard Worker Ok(buf)
2989*bb4ee6a4SAndroid Build Coastguard Worker }
2990*bb4ee6a4SAndroid Build Coastguard Worker
flush( &self, _ctx: Context, inode: Inode, handle: Handle, _lock_owner: u64, ) -> io::Result<()>2991*bb4ee6a4SAndroid Build Coastguard Worker fn flush(
2992*bb4ee6a4SAndroid Build Coastguard Worker &self,
2993*bb4ee6a4SAndroid Build Coastguard Worker _ctx: Context,
2994*bb4ee6a4SAndroid Build Coastguard Worker inode: Inode,
2995*bb4ee6a4SAndroid Build Coastguard Worker handle: Handle,
2996*bb4ee6a4SAndroid Build Coastguard Worker _lock_owner: u64,
2997*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<()> {
2998*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "flush", inode, handle);
2999*bb4ee6a4SAndroid Build Coastguard Worker let data: Arc<dyn AsRawDescriptor> = if self.zero_message_open.load(Ordering::Relaxed) {
3000*bb4ee6a4SAndroid Build Coastguard Worker self.find_inode(inode)?
3001*bb4ee6a4SAndroid Build Coastguard Worker } else {
3002*bb4ee6a4SAndroid Build Coastguard Worker self.find_handle(handle, inode)?
3003*bb4ee6a4SAndroid Build Coastguard Worker };
3004*bb4ee6a4SAndroid Build Coastguard Worker
3005*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY:
3006*bb4ee6a4SAndroid Build Coastguard Worker // Since this method is called whenever an fd is closed in the client, we can emulate that
3007*bb4ee6a4SAndroid Build Coastguard Worker // behavior by doing the same thing (dup-ing the fd and then immediately closing it). Safe
3008*bb4ee6a4SAndroid Build Coastguard Worker // because this doesn't modify any memory and we check the return values.
3009*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
3010*bb4ee6a4SAndroid Build Coastguard Worker let newfd = syscall!(libc::fcntl(
3011*bb4ee6a4SAndroid Build Coastguard Worker data.as_raw_descriptor(),
3012*bb4ee6a4SAndroid Build Coastguard Worker libc::F_DUPFD_CLOEXEC,
3013*bb4ee6a4SAndroid Build Coastguard Worker 0
3014*bb4ee6a4SAndroid Build Coastguard Worker ))?;
3015*bb4ee6a4SAndroid Build Coastguard Worker
3016*bb4ee6a4SAndroid Build Coastguard Worker syscall!(libc::close(newfd))?;
3017*bb4ee6a4SAndroid Build Coastguard Worker }
3018*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
3019*bb4ee6a4SAndroid Build Coastguard Worker }
3020*bb4ee6a4SAndroid Build Coastguard Worker
fsync(&self, _ctx: Context, inode: Inode, datasync: bool, handle: Handle) -> io::Result<()>3021*bb4ee6a4SAndroid Build Coastguard Worker fn fsync(&self, _ctx: Context, inode: Inode, datasync: bool, handle: Handle) -> io::Result<()> {
3022*bb4ee6a4SAndroid Build Coastguard Worker if self.zero_message_open.load(Ordering::Relaxed) {
3023*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "fsync (zero-message)", inode, datasync, handle);
3024*bb4ee6a4SAndroid Build Coastguard Worker let data = self.find_inode(inode)?;
3025*bb4ee6a4SAndroid Build Coastguard Worker self.do_fsync(&*data, datasync)
3026*bb4ee6a4SAndroid Build Coastguard Worker } else {
3027*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "fsync", inode, datasync, handle);
3028*bb4ee6a4SAndroid Build Coastguard Worker let data = self.find_handle(handle, inode)?;
3029*bb4ee6a4SAndroid Build Coastguard Worker
3030*bb4ee6a4SAndroid Build Coastguard Worker let file = data.file.lock();
3031*bb4ee6a4SAndroid Build Coastguard Worker self.do_fsync(&*file, datasync)
3032*bb4ee6a4SAndroid Build Coastguard Worker }
3033*bb4ee6a4SAndroid Build Coastguard Worker }
3034*bb4ee6a4SAndroid Build Coastguard Worker
fsyncdir( &self, _ctx: Context, inode: Inode, datasync: bool, handle: Handle, ) -> io::Result<()>3035*bb4ee6a4SAndroid Build Coastguard Worker fn fsyncdir(
3036*bb4ee6a4SAndroid Build Coastguard Worker &self,
3037*bb4ee6a4SAndroid Build Coastguard Worker _ctx: Context,
3038*bb4ee6a4SAndroid Build Coastguard Worker inode: Inode,
3039*bb4ee6a4SAndroid Build Coastguard Worker datasync: bool,
3040*bb4ee6a4SAndroid Build Coastguard Worker handle: Handle,
3041*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<()> {
3042*bb4ee6a4SAndroid Build Coastguard Worker if self.zero_message_opendir.load(Ordering::Relaxed) {
3043*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "fsyncdir (zero-message)", inode, datasync, handle);
3044*bb4ee6a4SAndroid Build Coastguard Worker let data = self.find_inode(inode)?;
3045*bb4ee6a4SAndroid Build Coastguard Worker self.do_fsync(&*data, datasync)
3046*bb4ee6a4SAndroid Build Coastguard Worker } else {
3047*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "fsyncdir", inode, datasync, handle);
3048*bb4ee6a4SAndroid Build Coastguard Worker let data = self.find_handle(handle, inode)?;
3049*bb4ee6a4SAndroid Build Coastguard Worker
3050*bb4ee6a4SAndroid Build Coastguard Worker let file = data.file.lock();
3051*bb4ee6a4SAndroid Build Coastguard Worker self.do_fsync(&*file, datasync)
3052*bb4ee6a4SAndroid Build Coastguard Worker }
3053*bb4ee6a4SAndroid Build Coastguard Worker }
3054*bb4ee6a4SAndroid Build Coastguard Worker
access(&self, ctx: Context, inode: Inode, mask: u32) -> io::Result<()>3055*bb4ee6a4SAndroid Build Coastguard Worker fn access(&self, ctx: Context, inode: Inode, mask: u32) -> io::Result<()> {
3056*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "access", inode, mask);
3057*bb4ee6a4SAndroid Build Coastguard Worker let data = self.find_inode(inode)?;
3058*bb4ee6a4SAndroid Build Coastguard Worker
3059*bb4ee6a4SAndroid Build Coastguard Worker let st = stat(&*data)?;
3060*bb4ee6a4SAndroid Build Coastguard Worker let mode = mask as i32 & (libc::R_OK | libc::W_OK | libc::X_OK);
3061*bb4ee6a4SAndroid Build Coastguard Worker
3062*bb4ee6a4SAndroid Build Coastguard Worker if mode == libc::F_OK {
3063*bb4ee6a4SAndroid Build Coastguard Worker // The file exists since we were able to call `stat(2)` on it.
3064*bb4ee6a4SAndroid Build Coastguard Worker return Ok(());
3065*bb4ee6a4SAndroid Build Coastguard Worker }
3066*bb4ee6a4SAndroid Build Coastguard Worker
3067*bb4ee6a4SAndroid Build Coastguard Worker if (mode & libc::R_OK) != 0 {
3068*bb4ee6a4SAndroid Build Coastguard Worker if ctx.uid != 0
3069*bb4ee6a4SAndroid Build Coastguard Worker && (st.st_uid != ctx.uid || st.st_mode & 0o400 == 0)
3070*bb4ee6a4SAndroid Build Coastguard Worker && (st.st_gid != ctx.gid || st.st_mode & 0o040 == 0)
3071*bb4ee6a4SAndroid Build Coastguard Worker && st.st_mode & 0o004 == 0
3072*bb4ee6a4SAndroid Build Coastguard Worker {
3073*bb4ee6a4SAndroid Build Coastguard Worker return Err(io::Error::from_raw_os_error(libc::EACCES));
3074*bb4ee6a4SAndroid Build Coastguard Worker }
3075*bb4ee6a4SAndroid Build Coastguard Worker }
3076*bb4ee6a4SAndroid Build Coastguard Worker
3077*bb4ee6a4SAndroid Build Coastguard Worker if (mode & libc::W_OK) != 0 {
3078*bb4ee6a4SAndroid Build Coastguard Worker if ctx.uid != 0
3079*bb4ee6a4SAndroid Build Coastguard Worker && (st.st_uid != ctx.uid || st.st_mode & 0o200 == 0)
3080*bb4ee6a4SAndroid Build Coastguard Worker && (st.st_gid != ctx.gid || st.st_mode & 0o020 == 0)
3081*bb4ee6a4SAndroid Build Coastguard Worker && st.st_mode & 0o002 == 0
3082*bb4ee6a4SAndroid Build Coastguard Worker {
3083*bb4ee6a4SAndroid Build Coastguard Worker return Err(io::Error::from_raw_os_error(libc::EACCES));
3084*bb4ee6a4SAndroid Build Coastguard Worker }
3085*bb4ee6a4SAndroid Build Coastguard Worker }
3086*bb4ee6a4SAndroid Build Coastguard Worker
3087*bb4ee6a4SAndroid Build Coastguard Worker // root can only execute something if it is executable by one of the owner, the group, or
3088*bb4ee6a4SAndroid Build Coastguard Worker // everyone.
3089*bb4ee6a4SAndroid Build Coastguard Worker if (mode & libc::X_OK) != 0 {
3090*bb4ee6a4SAndroid Build Coastguard Worker if (ctx.uid != 0 || st.st_mode & 0o111 == 0)
3091*bb4ee6a4SAndroid Build Coastguard Worker && (st.st_uid != ctx.uid || st.st_mode & 0o100 == 0)
3092*bb4ee6a4SAndroid Build Coastguard Worker && (st.st_gid != ctx.gid || st.st_mode & 0o010 == 0)
3093*bb4ee6a4SAndroid Build Coastguard Worker && st.st_mode & 0o001 == 0
3094*bb4ee6a4SAndroid Build Coastguard Worker {
3095*bb4ee6a4SAndroid Build Coastguard Worker return Err(io::Error::from_raw_os_error(libc::EACCES));
3096*bb4ee6a4SAndroid Build Coastguard Worker }
3097*bb4ee6a4SAndroid Build Coastguard Worker }
3098*bb4ee6a4SAndroid Build Coastguard Worker
3099*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
3100*bb4ee6a4SAndroid Build Coastguard Worker }
3101*bb4ee6a4SAndroid Build Coastguard Worker
setxattr( &self, _ctx: Context, inode: Inode, name: &CStr, value: &[u8], flags: u32, ) -> io::Result<()>3102*bb4ee6a4SAndroid Build Coastguard Worker fn setxattr(
3103*bb4ee6a4SAndroid Build Coastguard Worker &self,
3104*bb4ee6a4SAndroid Build Coastguard Worker _ctx: Context,
3105*bb4ee6a4SAndroid Build Coastguard Worker inode: Inode,
3106*bb4ee6a4SAndroid Build Coastguard Worker name: &CStr,
3107*bb4ee6a4SAndroid Build Coastguard Worker value: &[u8],
3108*bb4ee6a4SAndroid Build Coastguard Worker flags: u32,
3109*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<()> {
3110*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "setxattr", inode, name, flags);
3111*bb4ee6a4SAndroid Build Coastguard Worker // We can't allow the VM to set this xattr because an unprivileged process may use it to set
3112*bb4ee6a4SAndroid Build Coastguard Worker // a privileged xattr.
3113*bb4ee6a4SAndroid Build Coastguard Worker if self.cfg.rewrite_security_xattrs && name.to_bytes().starts_with(USER_VIRTIOFS_XATTR) {
3114*bb4ee6a4SAndroid Build Coastguard Worker return Err(io::Error::from_raw_os_error(libc::EPERM));
3115*bb4ee6a4SAndroid Build Coastguard Worker }
3116*bb4ee6a4SAndroid Build Coastguard Worker
3117*bb4ee6a4SAndroid Build Coastguard Worker let data = self.find_inode(inode)?;
3118*bb4ee6a4SAndroid Build Coastguard Worker let name = self.rewrite_xattr_name(name);
3119*bb4ee6a4SAndroid Build Coastguard Worker
3120*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
3121*bb4ee6a4SAndroid Build Coastguard Worker if self.skip_host_set_xattr(&data.path, &name.to_string_lossy()) {
3122*bb4ee6a4SAndroid Build Coastguard Worker debug!(
3123*bb4ee6a4SAndroid Build Coastguard Worker "ignore setxattr for path:{} xattr_name:{}",
3124*bb4ee6a4SAndroid Build Coastguard Worker &data.path,
3125*bb4ee6a4SAndroid Build Coastguard Worker &name.to_string_lossy()
3126*bb4ee6a4SAndroid Build Coastguard Worker );
3127*bb4ee6a4SAndroid Build Coastguard Worker return Ok(());
3128*bb4ee6a4SAndroid Build Coastguard Worker }
3129*bb4ee6a4SAndroid Build Coastguard Worker
3130*bb4ee6a4SAndroid Build Coastguard Worker let file = data.file.lock();
3131*bb4ee6a4SAndroid Build Coastguard Worker let o_path_file = (file.1 & libc::O_PATH) != 0;
3132*bb4ee6a4SAndroid Build Coastguard Worker if o_path_file {
3133*bb4ee6a4SAndroid Build Coastguard Worker // For FDs opened with `O_PATH`, we cannot call `fsetxattr` normally. Instead we emulate
3134*bb4ee6a4SAndroid Build Coastguard Worker // an _at syscall by changing the CWD to /proc, running the path based syscall, and then
3135*bb4ee6a4SAndroid Build Coastguard Worker // setting the CWD back to the root directory.
3136*bb4ee6a4SAndroid Build Coastguard Worker let path = CString::new(format!("self/fd/{}", file.0.as_raw_descriptor()))
3137*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
3138*bb4ee6a4SAndroid Build Coastguard Worker
3139*bb4ee6a4SAndroid Build Coastguard Worker syscall!(self.with_proc_chdir(|| {
3140*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value.
3141*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
3142*bb4ee6a4SAndroid Build Coastguard Worker libc::setxattr(
3143*bb4ee6a4SAndroid Build Coastguard Worker path.as_ptr(),
3144*bb4ee6a4SAndroid Build Coastguard Worker name.as_ptr(),
3145*bb4ee6a4SAndroid Build Coastguard Worker value.as_ptr() as *const libc::c_void,
3146*bb4ee6a4SAndroid Build Coastguard Worker value.len() as libc::size_t,
3147*bb4ee6a4SAndroid Build Coastguard Worker flags as c_int,
3148*bb4ee6a4SAndroid Build Coastguard Worker )
3149*bb4ee6a4SAndroid Build Coastguard Worker }
3150*bb4ee6a4SAndroid Build Coastguard Worker }))?;
3151*bb4ee6a4SAndroid Build Coastguard Worker } else {
3152*bb4ee6a4SAndroid Build Coastguard Worker syscall!(
3153*bb4ee6a4SAndroid Build Coastguard Worker // For regular files and directories, we can just use fsetxattr.
3154*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value.
3155*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
3156*bb4ee6a4SAndroid Build Coastguard Worker libc::fsetxattr(
3157*bb4ee6a4SAndroid Build Coastguard Worker file.0.as_raw_descriptor(),
3158*bb4ee6a4SAndroid Build Coastguard Worker name.as_ptr(),
3159*bb4ee6a4SAndroid Build Coastguard Worker value.as_ptr() as *const libc::c_void,
3160*bb4ee6a4SAndroid Build Coastguard Worker value.len() as libc::size_t,
3161*bb4ee6a4SAndroid Build Coastguard Worker flags as c_int,
3162*bb4ee6a4SAndroid Build Coastguard Worker )
3163*bb4ee6a4SAndroid Build Coastguard Worker }
3164*bb4ee6a4SAndroid Build Coastguard Worker )?;
3165*bb4ee6a4SAndroid Build Coastguard Worker }
3166*bb4ee6a4SAndroid Build Coastguard Worker
3167*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
3168*bb4ee6a4SAndroid Build Coastguard Worker }
3169*bb4ee6a4SAndroid Build Coastguard Worker
getxattr( &self, _ctx: Context, inode: Inode, name: &CStr, size: u32, ) -> io::Result<GetxattrReply>3170*bb4ee6a4SAndroid Build Coastguard Worker fn getxattr(
3171*bb4ee6a4SAndroid Build Coastguard Worker &self,
3172*bb4ee6a4SAndroid Build Coastguard Worker _ctx: Context,
3173*bb4ee6a4SAndroid Build Coastguard Worker inode: Inode,
3174*bb4ee6a4SAndroid Build Coastguard Worker name: &CStr,
3175*bb4ee6a4SAndroid Build Coastguard Worker size: u32,
3176*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<GetxattrReply> {
3177*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "getxattr", inode, name, size);
3178*bb4ee6a4SAndroid Build Coastguard Worker // We don't allow the VM to set this xattr so we also pretend there is no value associated
3179*bb4ee6a4SAndroid Build Coastguard Worker // with it.
3180*bb4ee6a4SAndroid Build Coastguard Worker if self.cfg.rewrite_security_xattrs && name.to_bytes().starts_with(USER_VIRTIOFS_XATTR) {
3181*bb4ee6a4SAndroid Build Coastguard Worker return Err(io::Error::from_raw_os_error(libc::ENODATA));
3182*bb4ee6a4SAndroid Build Coastguard Worker }
3183*bb4ee6a4SAndroid Build Coastguard Worker
3184*bb4ee6a4SAndroid Build Coastguard Worker let data = self.find_inode(inode)?;
3185*bb4ee6a4SAndroid Build Coastguard Worker let name = self.rewrite_xattr_name(name);
3186*bb4ee6a4SAndroid Build Coastguard Worker let mut buf = vec![0u8; size as usize];
3187*bb4ee6a4SAndroid Build Coastguard Worker
3188*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
3189*bb4ee6a4SAndroid Build Coastguard Worker let res = self.do_getxattr_with_filter(data, name, &mut buf)?;
3190*bb4ee6a4SAndroid Build Coastguard Worker
3191*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(not(feature = "arc_quota"))]
3192*bb4ee6a4SAndroid Build Coastguard Worker let res = self.do_getxattr(&data, &name, &mut buf[..])?;
3193*bb4ee6a4SAndroid Build Coastguard Worker
3194*bb4ee6a4SAndroid Build Coastguard Worker if size == 0 {
3195*bb4ee6a4SAndroid Build Coastguard Worker Ok(GetxattrReply::Count(res as u32))
3196*bb4ee6a4SAndroid Build Coastguard Worker } else {
3197*bb4ee6a4SAndroid Build Coastguard Worker buf.truncate(res);
3198*bb4ee6a4SAndroid Build Coastguard Worker Ok(GetxattrReply::Value(buf))
3199*bb4ee6a4SAndroid Build Coastguard Worker }
3200*bb4ee6a4SAndroid Build Coastguard Worker }
3201*bb4ee6a4SAndroid Build Coastguard Worker
listxattr(&self, _ctx: Context, inode: Inode, size: u32) -> io::Result<ListxattrReply>3202*bb4ee6a4SAndroid Build Coastguard Worker fn listxattr(&self, _ctx: Context, inode: Inode, size: u32) -> io::Result<ListxattrReply> {
3203*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "listxattr", inode, size);
3204*bb4ee6a4SAndroid Build Coastguard Worker let data = self.find_inode(inode)?;
3205*bb4ee6a4SAndroid Build Coastguard Worker
3206*bb4ee6a4SAndroid Build Coastguard Worker let mut buf = vec![0u8; size as usize];
3207*bb4ee6a4SAndroid Build Coastguard Worker
3208*bb4ee6a4SAndroid Build Coastguard Worker let file = data.file.lock();
3209*bb4ee6a4SAndroid Build Coastguard Worker let o_path_file = (file.1 & libc::O_PATH) != 0;
3210*bb4ee6a4SAndroid Build Coastguard Worker let res = if o_path_file {
3211*bb4ee6a4SAndroid Build Coastguard Worker // For FDs opened with `O_PATH`, we cannot call `flistxattr` normally. Instead we
3212*bb4ee6a4SAndroid Build Coastguard Worker // emulate an _at syscall by changing the CWD to /proc, running the path based syscall,
3213*bb4ee6a4SAndroid Build Coastguard Worker // and then setting the CWD back to the root directory.
3214*bb4ee6a4SAndroid Build Coastguard Worker let path = CString::new(format!("self/fd/{}", file.0.as_raw_descriptor()))
3215*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
3216*bb4ee6a4SAndroid Build Coastguard Worker
3217*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this will only modify `buf` and we check the return value.
3218*bb4ee6a4SAndroid Build Coastguard Worker syscall!(self.with_proc_chdir(|| unsafe {
3219*bb4ee6a4SAndroid Build Coastguard Worker libc::listxattr(
3220*bb4ee6a4SAndroid Build Coastguard Worker path.as_ptr(),
3221*bb4ee6a4SAndroid Build Coastguard Worker buf.as_mut_ptr() as *mut libc::c_char,
3222*bb4ee6a4SAndroid Build Coastguard Worker buf.len() as libc::size_t,
3223*bb4ee6a4SAndroid Build Coastguard Worker )
3224*bb4ee6a4SAndroid Build Coastguard Worker }))?
3225*bb4ee6a4SAndroid Build Coastguard Worker } else {
3226*bb4ee6a4SAndroid Build Coastguard Worker // For regular files and directories, we can just flistxattr.
3227*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this will only write to `buf` and we check the return value.
3228*bb4ee6a4SAndroid Build Coastguard Worker syscall!(unsafe {
3229*bb4ee6a4SAndroid Build Coastguard Worker libc::flistxattr(
3230*bb4ee6a4SAndroid Build Coastguard Worker file.0.as_raw_descriptor(),
3231*bb4ee6a4SAndroid Build Coastguard Worker buf.as_mut_ptr() as *mut libc::c_char,
3232*bb4ee6a4SAndroid Build Coastguard Worker buf.len() as libc::size_t,
3233*bb4ee6a4SAndroid Build Coastguard Worker )
3234*bb4ee6a4SAndroid Build Coastguard Worker })?
3235*bb4ee6a4SAndroid Build Coastguard Worker };
3236*bb4ee6a4SAndroid Build Coastguard Worker
3237*bb4ee6a4SAndroid Build Coastguard Worker if size == 0 {
3238*bb4ee6a4SAndroid Build Coastguard Worker Ok(ListxattrReply::Count(res as u32))
3239*bb4ee6a4SAndroid Build Coastguard Worker } else {
3240*bb4ee6a4SAndroid Build Coastguard Worker buf.truncate(res as usize);
3241*bb4ee6a4SAndroid Build Coastguard Worker
3242*bb4ee6a4SAndroid Build Coastguard Worker if self.cfg.rewrite_security_xattrs {
3243*bb4ee6a4SAndroid Build Coastguard Worker strip_xattr_prefix(&mut buf);
3244*bb4ee6a4SAndroid Build Coastguard Worker }
3245*bb4ee6a4SAndroid Build Coastguard Worker Ok(ListxattrReply::Names(buf))
3246*bb4ee6a4SAndroid Build Coastguard Worker }
3247*bb4ee6a4SAndroid Build Coastguard Worker }
3248*bb4ee6a4SAndroid Build Coastguard Worker
removexattr(&self, _ctx: Context, inode: Inode, name: &CStr) -> io::Result<()>3249*bb4ee6a4SAndroid Build Coastguard Worker fn removexattr(&self, _ctx: Context, inode: Inode, name: &CStr) -> io::Result<()> {
3250*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "removexattr", inode, name);
3251*bb4ee6a4SAndroid Build Coastguard Worker // We don't allow the VM to set this xattr so we also pretend there is no value associated
3252*bb4ee6a4SAndroid Build Coastguard Worker // with it.
3253*bb4ee6a4SAndroid Build Coastguard Worker if self.cfg.rewrite_security_xattrs && name.to_bytes().starts_with(USER_VIRTIOFS_XATTR) {
3254*bb4ee6a4SAndroid Build Coastguard Worker return Err(io::Error::from_raw_os_error(libc::ENODATA));
3255*bb4ee6a4SAndroid Build Coastguard Worker }
3256*bb4ee6a4SAndroid Build Coastguard Worker
3257*bb4ee6a4SAndroid Build Coastguard Worker let data = self.find_inode(inode)?;
3258*bb4ee6a4SAndroid Build Coastguard Worker let name = self.rewrite_xattr_name(name);
3259*bb4ee6a4SAndroid Build Coastguard Worker
3260*bb4ee6a4SAndroid Build Coastguard Worker let file = data.file.lock();
3261*bb4ee6a4SAndroid Build Coastguard Worker let o_path_file = (file.1 & libc::O_PATH) != 0;
3262*bb4ee6a4SAndroid Build Coastguard Worker if o_path_file {
3263*bb4ee6a4SAndroid Build Coastguard Worker // For files opened with `O_PATH`, we cannot call `fremovexattr` normally. Instead we
3264*bb4ee6a4SAndroid Build Coastguard Worker // emulate an _at syscall by changing the CWD to /proc, running the path based syscall,
3265*bb4ee6a4SAndroid Build Coastguard Worker // and then setting the CWD back to the root directory.
3266*bb4ee6a4SAndroid Build Coastguard Worker let path = CString::new(format!("self/fd/{}", file.0.as_raw_descriptor()))
3267*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
3268*bb4ee6a4SAndroid Build Coastguard Worker
3269*bb4ee6a4SAndroid Build Coastguard Worker syscall!(self.with_proc_chdir(||
3270*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value.
3271*bb4ee6a4SAndroid Build Coastguard Worker unsafe { libc::removexattr(path.as_ptr(), name.as_ptr()) }))?;
3272*bb4ee6a4SAndroid Build Coastguard Worker } else {
3273*bb4ee6a4SAndroid Build Coastguard Worker // For regular files and directories, we can just use fremovexattr.
3274*bb4ee6a4SAndroid Build Coastguard Worker syscall!(
3275*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value.
3276*bb4ee6a4SAndroid Build Coastguard Worker unsafe { libc::fremovexattr(file.0.as_raw_descriptor(), name.as_ptr()) }
3277*bb4ee6a4SAndroid Build Coastguard Worker )?;
3278*bb4ee6a4SAndroid Build Coastguard Worker }
3279*bb4ee6a4SAndroid Build Coastguard Worker
3280*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
3281*bb4ee6a4SAndroid Build Coastguard Worker }
3282*bb4ee6a4SAndroid Build Coastguard Worker
fallocate( &self, _ctx: Context, inode: Inode, handle: Handle, mode: u32, offset: u64, length: u64, ) -> io::Result<()>3283*bb4ee6a4SAndroid Build Coastguard Worker fn fallocate(
3284*bb4ee6a4SAndroid Build Coastguard Worker &self,
3285*bb4ee6a4SAndroid Build Coastguard Worker _ctx: Context,
3286*bb4ee6a4SAndroid Build Coastguard Worker inode: Inode,
3287*bb4ee6a4SAndroid Build Coastguard Worker handle: Handle,
3288*bb4ee6a4SAndroid Build Coastguard Worker mode: u32,
3289*bb4ee6a4SAndroid Build Coastguard Worker offset: u64,
3290*bb4ee6a4SAndroid Build Coastguard Worker length: u64,
3291*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<()> {
3292*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "fallocate", inode, handle, mode, offset, length);
3293*bb4ee6a4SAndroid Build Coastguard Worker
3294*bb4ee6a4SAndroid Build Coastguard Worker let data: Arc<dyn AsRawDescriptor> = if self.zero_message_open.load(Ordering::Relaxed) {
3295*bb4ee6a4SAndroid Build Coastguard Worker let data = self.find_inode(inode)?;
3296*bb4ee6a4SAndroid Build Coastguard Worker
3297*bb4ee6a4SAndroid Build Coastguard Worker {
3298*bb4ee6a4SAndroid Build Coastguard Worker // fallocate needs a writable fd
3299*bb4ee6a4SAndroid Build Coastguard Worker let mut file = data.file.lock();
3300*bb4ee6a4SAndroid Build Coastguard Worker let mut flags = file.1;
3301*bb4ee6a4SAndroid Build Coastguard Worker match flags & libc::O_ACCMODE {
3302*bb4ee6a4SAndroid Build Coastguard Worker libc::O_RDONLY => {
3303*bb4ee6a4SAndroid Build Coastguard Worker flags &= !libc::O_RDONLY;
3304*bb4ee6a4SAndroid Build Coastguard Worker flags |= libc::O_RDWR;
3305*bb4ee6a4SAndroid Build Coastguard Worker
3306*bb4ee6a4SAndroid Build Coastguard Worker // We need to get a writable handle for this file.
3307*bb4ee6a4SAndroid Build Coastguard Worker let newfile = self.open_fd(file.0.as_raw_descriptor(), libc::O_RDWR)?;
3308*bb4ee6a4SAndroid Build Coastguard Worker *file = (newfile, flags);
3309*bb4ee6a4SAndroid Build Coastguard Worker }
3310*bb4ee6a4SAndroid Build Coastguard Worker libc::O_WRONLY | libc::O_RDWR => {}
3311*bb4ee6a4SAndroid Build Coastguard Worker _ => panic!("Unexpected flags: {:#x}", flags),
3312*bb4ee6a4SAndroid Build Coastguard Worker }
3313*bb4ee6a4SAndroid Build Coastguard Worker }
3314*bb4ee6a4SAndroid Build Coastguard Worker
3315*bb4ee6a4SAndroid Build Coastguard Worker data
3316*bb4ee6a4SAndroid Build Coastguard Worker } else {
3317*bb4ee6a4SAndroid Build Coastguard Worker self.find_handle(handle, inode)?
3318*bb4ee6a4SAndroid Build Coastguard Worker };
3319*bb4ee6a4SAndroid Build Coastguard Worker
3320*bb4ee6a4SAndroid Build Coastguard Worker let fd = data.as_raw_descriptor();
3321*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this doesn't modify any memory and we check the return value.
3322*bb4ee6a4SAndroid Build Coastguard Worker syscall!(unsafe {
3323*bb4ee6a4SAndroid Build Coastguard Worker libc::fallocate64(
3324*bb4ee6a4SAndroid Build Coastguard Worker fd,
3325*bb4ee6a4SAndroid Build Coastguard Worker mode as libc::c_int,
3326*bb4ee6a4SAndroid Build Coastguard Worker offset as libc::off64_t,
3327*bb4ee6a4SAndroid Build Coastguard Worker length as libc::off64_t,
3328*bb4ee6a4SAndroid Build Coastguard Worker )
3329*bb4ee6a4SAndroid Build Coastguard Worker })?;
3330*bb4ee6a4SAndroid Build Coastguard Worker
3331*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
3332*bb4ee6a4SAndroid Build Coastguard Worker }
3333*bb4ee6a4SAndroid Build Coastguard Worker
3334*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::unnecessary_cast)]
ioctl<R: io::Read>( &self, ctx: Context, inode: Inode, handle: Handle, _flags: IoctlFlags, cmd: u32, _arg: u64, in_size: u32, out_size: u32, r: R, ) -> io::Result<IoctlReply>3335*bb4ee6a4SAndroid Build Coastguard Worker fn ioctl<R: io::Read>(
3336*bb4ee6a4SAndroid Build Coastguard Worker &self,
3337*bb4ee6a4SAndroid Build Coastguard Worker ctx: Context,
3338*bb4ee6a4SAndroid Build Coastguard Worker inode: Inode,
3339*bb4ee6a4SAndroid Build Coastguard Worker handle: Handle,
3340*bb4ee6a4SAndroid Build Coastguard Worker _flags: IoctlFlags,
3341*bb4ee6a4SAndroid Build Coastguard Worker cmd: u32,
3342*bb4ee6a4SAndroid Build Coastguard Worker _arg: u64,
3343*bb4ee6a4SAndroid Build Coastguard Worker in_size: u32,
3344*bb4ee6a4SAndroid Build Coastguard Worker out_size: u32,
3345*bb4ee6a4SAndroid Build Coastguard Worker r: R,
3346*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<IoctlReply> {
3347*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "ioctl", inode, handle, cmd, in_size, out_size);
3348*bb4ee6a4SAndroid Build Coastguard Worker
3349*bb4ee6a4SAndroid Build Coastguard Worker match cmd as IoctlNr {
3350*bb4ee6a4SAndroid Build Coastguard Worker FS_IOC_GET_ENCRYPTION_POLICY_EX => self.get_encryption_policy_ex(inode, handle, r),
3351*bb4ee6a4SAndroid Build Coastguard Worker FS_IOC_FSGETXATTR => {
3352*bb4ee6a4SAndroid Build Coastguard Worker if out_size < size_of::<fsxattr>() as u32 {
3353*bb4ee6a4SAndroid Build Coastguard Worker Err(io::Error::from_raw_os_error(libc::ENOMEM))
3354*bb4ee6a4SAndroid Build Coastguard Worker } else {
3355*bb4ee6a4SAndroid Build Coastguard Worker self.get_fsxattr(inode, handle)
3356*bb4ee6a4SAndroid Build Coastguard Worker }
3357*bb4ee6a4SAndroid Build Coastguard Worker }
3358*bb4ee6a4SAndroid Build Coastguard Worker FS_IOC_FSSETXATTR => {
3359*bb4ee6a4SAndroid Build Coastguard Worker if in_size < size_of::<fsxattr>() as u32 {
3360*bb4ee6a4SAndroid Build Coastguard Worker Err(io::Error::from_raw_os_error(libc::EINVAL))
3361*bb4ee6a4SAndroid Build Coastguard Worker } else {
3362*bb4ee6a4SAndroid Build Coastguard Worker self.set_fsxattr(ctx, inode, handle, r)
3363*bb4ee6a4SAndroid Build Coastguard Worker }
3364*bb4ee6a4SAndroid Build Coastguard Worker }
3365*bb4ee6a4SAndroid Build Coastguard Worker FS_IOC32_GETFLAGS | FS_IOC64_GETFLAGS => {
3366*bb4ee6a4SAndroid Build Coastguard Worker if out_size < size_of::<c_int>() as u32 {
3367*bb4ee6a4SAndroid Build Coastguard Worker Err(io::Error::from_raw_os_error(libc::ENOMEM))
3368*bb4ee6a4SAndroid Build Coastguard Worker } else {
3369*bb4ee6a4SAndroid Build Coastguard Worker self.get_flags(inode, handle)
3370*bb4ee6a4SAndroid Build Coastguard Worker }
3371*bb4ee6a4SAndroid Build Coastguard Worker }
3372*bb4ee6a4SAndroid Build Coastguard Worker FS_IOC32_SETFLAGS | FS_IOC64_SETFLAGS => {
3373*bb4ee6a4SAndroid Build Coastguard Worker if in_size < size_of::<c_int>() as u32 {
3374*bb4ee6a4SAndroid Build Coastguard Worker Err(io::Error::from_raw_os_error(libc::ENOMEM))
3375*bb4ee6a4SAndroid Build Coastguard Worker } else {
3376*bb4ee6a4SAndroid Build Coastguard Worker self.set_flags(ctx, inode, handle, r)
3377*bb4ee6a4SAndroid Build Coastguard Worker }
3378*bb4ee6a4SAndroid Build Coastguard Worker }
3379*bb4ee6a4SAndroid Build Coastguard Worker FS_IOC_ENABLE_VERITY => {
3380*bb4ee6a4SAndroid Build Coastguard Worker if in_size < size_of::<fsverity_enable_arg>() as u32 {
3381*bb4ee6a4SAndroid Build Coastguard Worker Err(io::Error::from_raw_os_error(libc::ENOMEM))
3382*bb4ee6a4SAndroid Build Coastguard Worker } else {
3383*bb4ee6a4SAndroid Build Coastguard Worker self.enable_verity(inode, handle, r)
3384*bb4ee6a4SAndroid Build Coastguard Worker }
3385*bb4ee6a4SAndroid Build Coastguard Worker }
3386*bb4ee6a4SAndroid Build Coastguard Worker FS_IOC_MEASURE_VERITY => {
3387*bb4ee6a4SAndroid Build Coastguard Worker if in_size < size_of::<fsverity_digest>() as u32
3388*bb4ee6a4SAndroid Build Coastguard Worker || out_size < size_of::<fsverity_digest>() as u32
3389*bb4ee6a4SAndroid Build Coastguard Worker {
3390*bb4ee6a4SAndroid Build Coastguard Worker Err(io::Error::from_raw_os_error(libc::ENOMEM))
3391*bb4ee6a4SAndroid Build Coastguard Worker } else {
3392*bb4ee6a4SAndroid Build Coastguard Worker self.measure_verity(inode, handle, r, out_size)
3393*bb4ee6a4SAndroid Build Coastguard Worker }
3394*bb4ee6a4SAndroid Build Coastguard Worker }
3395*bb4ee6a4SAndroid Build Coastguard Worker // The following is ARCVM-specific ioctl
3396*bb4ee6a4SAndroid Build Coastguard Worker // Refer go/remove-mount-passthrough-fuse for more design details
3397*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
3398*bb4ee6a4SAndroid Build Coastguard Worker FS_IOC_SETPERMISSION => {
3399*bb4ee6a4SAndroid Build Coastguard Worker if in_size != size_of::<FsPermissionDataBuffer>() as u32 {
3400*bb4ee6a4SAndroid Build Coastguard Worker Err(io::Error::from_raw_os_error(libc::EINVAL))
3401*bb4ee6a4SAndroid Build Coastguard Worker } else {
3402*bb4ee6a4SAndroid Build Coastguard Worker Ok(self.set_permission_by_path(r))
3403*bb4ee6a4SAndroid Build Coastguard Worker }
3404*bb4ee6a4SAndroid Build Coastguard Worker }
3405*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
3406*bb4ee6a4SAndroid Build Coastguard Worker FS_IOC_SETPATHXATTR => {
3407*bb4ee6a4SAndroid Build Coastguard Worker if in_size != size_of::<FsPathXattrDataBuffer>() as u32 {
3408*bb4ee6a4SAndroid Build Coastguard Worker Err(io::Error::from_raw_os_error(libc::EINVAL))
3409*bb4ee6a4SAndroid Build Coastguard Worker } else {
3410*bb4ee6a4SAndroid Build Coastguard Worker Ok(self.set_xattr_by_path(r))
3411*bb4ee6a4SAndroid Build Coastguard Worker }
3412*bb4ee6a4SAndroid Build Coastguard Worker }
3413*bb4ee6a4SAndroid Build Coastguard Worker _ => Err(io::Error::from_raw_os_error(libc::ENOTTY)),
3414*bb4ee6a4SAndroid Build Coastguard Worker }
3415*bb4ee6a4SAndroid Build Coastguard Worker }
3416*bb4ee6a4SAndroid Build Coastguard Worker
copy_file_range( &self, ctx: Context, inode_src: Inode, handle_src: Handle, offset_src: u64, inode_dst: Inode, handle_dst: Handle, offset_dst: u64, length: u64, flags: u64, ) -> io::Result<usize>3417*bb4ee6a4SAndroid Build Coastguard Worker fn copy_file_range(
3418*bb4ee6a4SAndroid Build Coastguard Worker &self,
3419*bb4ee6a4SAndroid Build Coastguard Worker ctx: Context,
3420*bb4ee6a4SAndroid Build Coastguard Worker inode_src: Inode,
3421*bb4ee6a4SAndroid Build Coastguard Worker handle_src: Handle,
3422*bb4ee6a4SAndroid Build Coastguard Worker offset_src: u64,
3423*bb4ee6a4SAndroid Build Coastguard Worker inode_dst: Inode,
3424*bb4ee6a4SAndroid Build Coastguard Worker handle_dst: Handle,
3425*bb4ee6a4SAndroid Build Coastguard Worker offset_dst: u64,
3426*bb4ee6a4SAndroid Build Coastguard Worker length: u64,
3427*bb4ee6a4SAndroid Build Coastguard Worker flags: u64,
3428*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<usize> {
3429*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(
3430*bb4ee6a4SAndroid Build Coastguard Worker self.tag,
3431*bb4ee6a4SAndroid Build Coastguard Worker "copy_file_range",
3432*bb4ee6a4SAndroid Build Coastguard Worker inode_src,
3433*bb4ee6a4SAndroid Build Coastguard Worker handle_src,
3434*bb4ee6a4SAndroid Build Coastguard Worker offset_src,
3435*bb4ee6a4SAndroid Build Coastguard Worker inode_dst,
3436*bb4ee6a4SAndroid Build Coastguard Worker handle_dst,
3437*bb4ee6a4SAndroid Build Coastguard Worker offset_dst,
3438*bb4ee6a4SAndroid Build Coastguard Worker length,
3439*bb4ee6a4SAndroid Build Coastguard Worker flags
3440*bb4ee6a4SAndroid Build Coastguard Worker );
3441*bb4ee6a4SAndroid Build Coastguard Worker // We need to change credentials during a write so that the kernel will remove setuid or
3442*bb4ee6a4SAndroid Build Coastguard Worker // setgid bits from the file if it was written to by someone other than the owner.
3443*bb4ee6a4SAndroid Build Coastguard Worker let (_uid, _gid) = set_creds(ctx.uid, ctx.gid)?;
3444*bb4ee6a4SAndroid Build Coastguard Worker let (src_data, dst_data): (Arc<dyn AsRawDescriptor>, Arc<dyn AsRawDescriptor>) =
3445*bb4ee6a4SAndroid Build Coastguard Worker if self.zero_message_open.load(Ordering::Relaxed) {
3446*bb4ee6a4SAndroid Build Coastguard Worker (self.find_inode(inode_src)?, self.find_inode(inode_dst)?)
3447*bb4ee6a4SAndroid Build Coastguard Worker } else {
3448*bb4ee6a4SAndroid Build Coastguard Worker (
3449*bb4ee6a4SAndroid Build Coastguard Worker self.find_handle(handle_src, inode_src)?,
3450*bb4ee6a4SAndroid Build Coastguard Worker self.find_handle(handle_dst, inode_dst)?,
3451*bb4ee6a4SAndroid Build Coastguard Worker )
3452*bb4ee6a4SAndroid Build Coastguard Worker };
3453*bb4ee6a4SAndroid Build Coastguard Worker
3454*bb4ee6a4SAndroid Build Coastguard Worker let src = src_data.as_raw_descriptor();
3455*bb4ee6a4SAndroid Build Coastguard Worker let dst = dst_data.as_raw_descriptor();
3456*bb4ee6a4SAndroid Build Coastguard Worker
3457*bb4ee6a4SAndroid Build Coastguard Worker Ok(syscall!(
3458*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: this call is safe because it doesn't modify any memory and we
3459*bb4ee6a4SAndroid Build Coastguard Worker // check the return value.
3460*bb4ee6a4SAndroid Build Coastguard Worker unsafe {
3461*bb4ee6a4SAndroid Build Coastguard Worker libc::syscall(
3462*bb4ee6a4SAndroid Build Coastguard Worker libc::SYS_copy_file_range,
3463*bb4ee6a4SAndroid Build Coastguard Worker src,
3464*bb4ee6a4SAndroid Build Coastguard Worker &offset_src,
3465*bb4ee6a4SAndroid Build Coastguard Worker dst,
3466*bb4ee6a4SAndroid Build Coastguard Worker &offset_dst,
3467*bb4ee6a4SAndroid Build Coastguard Worker length,
3468*bb4ee6a4SAndroid Build Coastguard Worker flags,
3469*bb4ee6a4SAndroid Build Coastguard Worker )
3470*bb4ee6a4SAndroid Build Coastguard Worker }
3471*bb4ee6a4SAndroid Build Coastguard Worker )? as usize)
3472*bb4ee6a4SAndroid Build Coastguard Worker }
3473*bb4ee6a4SAndroid Build Coastguard Worker
set_up_mapping<M: Mapper>( &self, _ctx: Context, inode: Self::Inode, _handle: Self::Handle, file_offset: u64, mem_offset: u64, size: usize, prot: u32, mapper: M, ) -> io::Result<()>3474*bb4ee6a4SAndroid Build Coastguard Worker fn set_up_mapping<M: Mapper>(
3475*bb4ee6a4SAndroid Build Coastguard Worker &self,
3476*bb4ee6a4SAndroid Build Coastguard Worker _ctx: Context,
3477*bb4ee6a4SAndroid Build Coastguard Worker inode: Self::Inode,
3478*bb4ee6a4SAndroid Build Coastguard Worker _handle: Self::Handle,
3479*bb4ee6a4SAndroid Build Coastguard Worker file_offset: u64,
3480*bb4ee6a4SAndroid Build Coastguard Worker mem_offset: u64,
3481*bb4ee6a4SAndroid Build Coastguard Worker size: usize,
3482*bb4ee6a4SAndroid Build Coastguard Worker prot: u32,
3483*bb4ee6a4SAndroid Build Coastguard Worker mapper: M,
3484*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<()> {
3485*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(
3486*bb4ee6a4SAndroid Build Coastguard Worker self.tag,
3487*bb4ee6a4SAndroid Build Coastguard Worker "set_up_mapping",
3488*bb4ee6a4SAndroid Build Coastguard Worker inode,
3489*bb4ee6a4SAndroid Build Coastguard Worker file_offset,
3490*bb4ee6a4SAndroid Build Coastguard Worker mem_offset,
3491*bb4ee6a4SAndroid Build Coastguard Worker size,
3492*bb4ee6a4SAndroid Build Coastguard Worker prot
3493*bb4ee6a4SAndroid Build Coastguard Worker );
3494*bb4ee6a4SAndroid Build Coastguard Worker if !self.cfg.use_dax {
3495*bb4ee6a4SAndroid Build Coastguard Worker return Err(io::Error::from_raw_os_error(libc::ENOSYS));
3496*bb4ee6a4SAndroid Build Coastguard Worker }
3497*bb4ee6a4SAndroid Build Coastguard Worker
3498*bb4ee6a4SAndroid Build Coastguard Worker let read = prot & libc::PROT_READ as u32 != 0;
3499*bb4ee6a4SAndroid Build Coastguard Worker let write = prot & libc::PROT_WRITE as u32 != 0;
3500*bb4ee6a4SAndroid Build Coastguard Worker let (mmap_flags, prot) = match (read, write) {
3501*bb4ee6a4SAndroid Build Coastguard Worker (true, true) => (libc::O_RDWR, Protection::read_write()),
3502*bb4ee6a4SAndroid Build Coastguard Worker (true, false) => (libc::O_RDONLY, Protection::read()),
3503*bb4ee6a4SAndroid Build Coastguard Worker // Write-only is mapped to O_RDWR since mmap always requires an fd opened for reading.
3504*bb4ee6a4SAndroid Build Coastguard Worker (false, true) => (libc::O_RDWR, Protection::write()),
3505*bb4ee6a4SAndroid Build Coastguard Worker (false, false) => return Err(io::Error::from_raw_os_error(libc::EINVAL)),
3506*bb4ee6a4SAndroid Build Coastguard Worker };
3507*bb4ee6a4SAndroid Build Coastguard Worker
3508*bb4ee6a4SAndroid Build Coastguard Worker let data = self.find_inode(inode)?;
3509*bb4ee6a4SAndroid Build Coastguard Worker
3510*bb4ee6a4SAndroid Build Coastguard Worker if self.zero_message_open.load(Ordering::Relaxed) {
3511*bb4ee6a4SAndroid Build Coastguard Worker let mut file = data.file.lock();
3512*bb4ee6a4SAndroid Build Coastguard Worker let mut open_flags = file.1;
3513*bb4ee6a4SAndroid Build Coastguard Worker match (mmap_flags, open_flags & libc::O_ACCMODE) {
3514*bb4ee6a4SAndroid Build Coastguard Worker (libc::O_RDONLY, libc::O_WRONLY)
3515*bb4ee6a4SAndroid Build Coastguard Worker | (libc::O_RDWR, libc::O_RDONLY)
3516*bb4ee6a4SAndroid Build Coastguard Worker | (libc::O_RDWR, libc::O_WRONLY) => {
3517*bb4ee6a4SAndroid Build Coastguard Worker // We have a read-only or write-only fd and we need to upgrade it.
3518*bb4ee6a4SAndroid Build Coastguard Worker open_flags &= !libc::O_ACCMODE;
3519*bb4ee6a4SAndroid Build Coastguard Worker open_flags |= libc::O_RDWR;
3520*bb4ee6a4SAndroid Build Coastguard Worker
3521*bb4ee6a4SAndroid Build Coastguard Worker let newfile = self.open_fd(file.0.as_raw_descriptor(), libc::O_RDWR)?;
3522*bb4ee6a4SAndroid Build Coastguard Worker *file = (newfile, open_flags);
3523*bb4ee6a4SAndroid Build Coastguard Worker }
3524*bb4ee6a4SAndroid Build Coastguard Worker (libc::O_RDONLY, libc::O_RDONLY)
3525*bb4ee6a4SAndroid Build Coastguard Worker | (libc::O_RDONLY, libc::O_RDWR)
3526*bb4ee6a4SAndroid Build Coastguard Worker | (libc::O_RDWR, libc::O_RDWR) => {}
3527*bb4ee6a4SAndroid Build Coastguard Worker (m, o) => panic!(
3528*bb4ee6a4SAndroid Build Coastguard Worker "Unexpected combination of access flags: ({:#x}, {:#x})",
3529*bb4ee6a4SAndroid Build Coastguard Worker m, o
3530*bb4ee6a4SAndroid Build Coastguard Worker ),
3531*bb4ee6a4SAndroid Build Coastguard Worker }
3532*bb4ee6a4SAndroid Build Coastguard Worker mapper.map(mem_offset, size, &file.0, file_offset, prot)
3533*bb4ee6a4SAndroid Build Coastguard Worker } else {
3534*bb4ee6a4SAndroid Build Coastguard Worker let file = self.open_inode(&data, mmap_flags | libc::O_NONBLOCK)?;
3535*bb4ee6a4SAndroid Build Coastguard Worker mapper.map(mem_offset, size, &file, file_offset, prot)
3536*bb4ee6a4SAndroid Build Coastguard Worker }
3537*bb4ee6a4SAndroid Build Coastguard Worker }
3538*bb4ee6a4SAndroid Build Coastguard Worker
remove_mapping<M: Mapper>(&self, msgs: &[RemoveMappingOne], mapper: M) -> io::Result<()>3539*bb4ee6a4SAndroid Build Coastguard Worker fn remove_mapping<M: Mapper>(&self, msgs: &[RemoveMappingOne], mapper: M) -> io::Result<()> {
3540*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(self.tag, "remove_mapping", msgs);
3541*bb4ee6a4SAndroid Build Coastguard Worker if !self.cfg.use_dax {
3542*bb4ee6a4SAndroid Build Coastguard Worker return Err(io::Error::from_raw_os_error(libc::ENOSYS));
3543*bb4ee6a4SAndroid Build Coastguard Worker }
3544*bb4ee6a4SAndroid Build Coastguard Worker
3545*bb4ee6a4SAndroid Build Coastguard Worker for RemoveMappingOne { moffset, len } in msgs {
3546*bb4ee6a4SAndroid Build Coastguard Worker mapper.unmap(*moffset, *len)?;
3547*bb4ee6a4SAndroid Build Coastguard Worker }
3548*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
3549*bb4ee6a4SAndroid Build Coastguard Worker }
3550*bb4ee6a4SAndroid Build Coastguard Worker
atomic_open( &self, ctx: Context, parent: Self::Inode, name: &CStr, mode: u32, flags: u32, umask: u32, security_ctx: Option<&CStr>, ) -> io::Result<(Entry, Option<Self::Handle>, OpenOptions)>3551*bb4ee6a4SAndroid Build Coastguard Worker fn atomic_open(
3552*bb4ee6a4SAndroid Build Coastguard Worker &self,
3553*bb4ee6a4SAndroid Build Coastguard Worker ctx: Context,
3554*bb4ee6a4SAndroid Build Coastguard Worker parent: Self::Inode,
3555*bb4ee6a4SAndroid Build Coastguard Worker name: &CStr,
3556*bb4ee6a4SAndroid Build Coastguard Worker mode: u32,
3557*bb4ee6a4SAndroid Build Coastguard Worker flags: u32,
3558*bb4ee6a4SAndroid Build Coastguard Worker umask: u32,
3559*bb4ee6a4SAndroid Build Coastguard Worker security_ctx: Option<&CStr>,
3560*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<(Entry, Option<Self::Handle>, OpenOptions)> {
3561*bb4ee6a4SAndroid Build Coastguard Worker let _trace = fs_trace!(
3562*bb4ee6a4SAndroid Build Coastguard Worker self.tag,
3563*bb4ee6a4SAndroid Build Coastguard Worker "atomic_open",
3564*bb4ee6a4SAndroid Build Coastguard Worker parent,
3565*bb4ee6a4SAndroid Build Coastguard Worker name,
3566*bb4ee6a4SAndroid Build Coastguard Worker mode,
3567*bb4ee6a4SAndroid Build Coastguard Worker flags,
3568*bb4ee6a4SAndroid Build Coastguard Worker umask,
3569*bb4ee6a4SAndroid Build Coastguard Worker security_ctx
3570*bb4ee6a4SAndroid Build Coastguard Worker );
3571*bb4ee6a4SAndroid Build Coastguard Worker // Perform lookup but not create negative dentry
3572*bb4ee6a4SAndroid Build Coastguard Worker let data = self.find_inode(parent)?;
3573*bb4ee6a4SAndroid Build Coastguard Worker
3574*bb4ee6a4SAndroid Build Coastguard Worker #[allow(unused_variables)]
3575*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
3576*bb4ee6a4SAndroid Build Coastguard Worker let (uid, gid) = self.change_creds(&ctx, &data, name);
3577*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "fs_runtime_ugid_map")]
3578*bb4ee6a4SAndroid Build Coastguard Worker let (uid, gid) = self.change_ugid_creds(&ctx, &data, name);
3579*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(not(feature = "fs_permission_translation"))]
3580*bb4ee6a4SAndroid Build Coastguard Worker let (uid, gid) = (ctx.uid, ctx.gid);
3581*bb4ee6a4SAndroid Build Coastguard Worker
3582*bb4ee6a4SAndroid Build Coastguard Worker let (_uid, _gid) = set_creds(uid, gid)?;
3583*bb4ee6a4SAndroid Build Coastguard Worker
3584*bb4ee6a4SAndroid Build Coastguard Worker // This lookup serves two purposes:
3585*bb4ee6a4SAndroid Build Coastguard Worker // 1. If the O_CREATE flag is not set, it retrieves the d_entry for the file.
3586*bb4ee6a4SAndroid Build Coastguard Worker // 2. If the O_CREATE flag is set, it checks whether the file exists.
3587*bb4ee6a4SAndroid Build Coastguard Worker let res = self.do_lookup_with_casefold_fallback(&data, name);
3588*bb4ee6a4SAndroid Build Coastguard Worker
3589*bb4ee6a4SAndroid Build Coastguard Worker if let Err(e) = res {
3590*bb4ee6a4SAndroid Build Coastguard Worker if e.kind() == std::io::ErrorKind::NotFound && (flags as i32 & libc::O_CREAT) != 0 {
3591*bb4ee6a4SAndroid Build Coastguard Worker // If the file did not exist & O_CREAT is set,
3592*bb4ee6a4SAndroid Build Coastguard Worker // create file & set FILE_CREATED bits in open options
3593*bb4ee6a4SAndroid Build Coastguard Worker let (entry, handler, mut opts) =
3594*bb4ee6a4SAndroid Build Coastguard Worker self.create(ctx, parent, name, mode, flags, umask, security_ctx)?;
3595*bb4ee6a4SAndroid Build Coastguard Worker opts |= OpenOptions::FILE_CREATED;
3596*bb4ee6a4SAndroid Build Coastguard Worker return Ok((entry, handler, opts));
3597*bb4ee6a4SAndroid Build Coastguard Worker } else if e.kind() == std::io::ErrorKind::NotFound
3598*bb4ee6a4SAndroid Build Coastguard Worker && !self.cfg.negative_timeout.is_zero()
3599*bb4ee6a4SAndroid Build Coastguard Worker {
3600*bb4ee6a4SAndroid Build Coastguard Worker return Ok((
3601*bb4ee6a4SAndroid Build Coastguard Worker Entry::new_negative(self.cfg.negative_timeout),
3602*bb4ee6a4SAndroid Build Coastguard Worker None,
3603*bb4ee6a4SAndroid Build Coastguard Worker OpenOptions::empty(),
3604*bb4ee6a4SAndroid Build Coastguard Worker ));
3605*bb4ee6a4SAndroid Build Coastguard Worker }
3606*bb4ee6a4SAndroid Build Coastguard Worker return Err(e);
3607*bb4ee6a4SAndroid Build Coastguard Worker }
3608*bb4ee6a4SAndroid Build Coastguard Worker
3609*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: checked res is not error before
3610*bb4ee6a4SAndroid Build Coastguard Worker let entry = res.unwrap();
3611*bb4ee6a4SAndroid Build Coastguard Worker
3612*bb4ee6a4SAndroid Build Coastguard Worker if entry.attr.st_mode & libc::S_IFMT == libc::S_IFLNK {
3613*bb4ee6a4SAndroid Build Coastguard Worker return Ok((entry, None, OpenOptions::empty()));
3614*bb4ee6a4SAndroid Build Coastguard Worker }
3615*bb4ee6a4SAndroid Build Coastguard Worker
3616*bb4ee6a4SAndroid Build Coastguard Worker if (flags as i32 & (libc::O_CREAT | libc::O_EXCL)) == (libc::O_CREAT | libc::O_EXCL) {
3617*bb4ee6a4SAndroid Build Coastguard Worker return Err(eexist());
3618*bb4ee6a4SAndroid Build Coastguard Worker }
3619*bb4ee6a4SAndroid Build Coastguard Worker
3620*bb4ee6a4SAndroid Build Coastguard Worker let (handler, opts) = if self.zero_message_open.load(Ordering::Relaxed) {
3621*bb4ee6a4SAndroid Build Coastguard Worker (None, OpenOptions::KEEP_CACHE)
3622*bb4ee6a4SAndroid Build Coastguard Worker } else {
3623*bb4ee6a4SAndroid Build Coastguard Worker let (handler, opts) = self.do_open(entry.inode, flags)?;
3624*bb4ee6a4SAndroid Build Coastguard Worker (handler, opts)
3625*bb4ee6a4SAndroid Build Coastguard Worker };
3626*bb4ee6a4SAndroid Build Coastguard Worker Ok((entry, handler, opts))
3627*bb4ee6a4SAndroid Build Coastguard Worker }
3628*bb4ee6a4SAndroid Build Coastguard Worker }
3629*bb4ee6a4SAndroid Build Coastguard Worker
3630*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
3631*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
3632*bb4ee6a4SAndroid Build Coastguard Worker use std::path::Path;
3633*bb4ee6a4SAndroid Build Coastguard Worker
3634*bb4ee6a4SAndroid Build Coastguard Worker use named_lock::NamedLock;
3635*bb4ee6a4SAndroid Build Coastguard Worker use tempfile::TempDir;
3636*bb4ee6a4SAndroid Build Coastguard Worker
3637*bb4ee6a4SAndroid Build Coastguard Worker use super::*;
3638*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
3639*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::fs::arc_ioctl::FS_IOCTL_PATH_MAX_LEN;
3640*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
3641*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::fs::arc_ioctl::FS_IOCTL_XATTR_NAME_MAX_LEN;
3642*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
3643*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::fs::arc_ioctl::FS_IOCTL_XATTR_VALUE_MAX_LEN;
3644*bb4ee6a4SAndroid Build Coastguard Worker
3645*bb4ee6a4SAndroid Build Coastguard Worker const UNITTEST_LOCK_NAME: &str = "passthroughfs_unittest_lock";
3646*bb4ee6a4SAndroid Build Coastguard Worker
3647*bb4ee6a4SAndroid Build Coastguard Worker // Create an instance of `Context` with valid uid, gid, and pid.
3648*bb4ee6a4SAndroid Build Coastguard Worker // The correct ids are necessary for test cases where new files are created.
get_context() -> Context3649*bb4ee6a4SAndroid Build Coastguard Worker fn get_context() -> Context {
3650*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: both calls take no parameters and only return an integer value. The kernel also
3651*bb4ee6a4SAndroid Build Coastguard Worker // guarantees that they can never fail.
3652*bb4ee6a4SAndroid Build Coastguard Worker let uid = unsafe { libc::syscall(SYS_GETEUID) as libc::uid_t };
3653*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: both calls take no parameters and only return an integer value. The kernel also
3654*bb4ee6a4SAndroid Build Coastguard Worker // guarantees that they can never fail.
3655*bb4ee6a4SAndroid Build Coastguard Worker let gid = unsafe { libc::syscall(SYS_GETEGID) as libc::gid_t };
3656*bb4ee6a4SAndroid Build Coastguard Worker let pid = std::process::id() as libc::pid_t;
3657*bb4ee6a4SAndroid Build Coastguard Worker Context { uid, gid, pid }
3658*bb4ee6a4SAndroid Build Coastguard Worker }
3659*bb4ee6a4SAndroid Build Coastguard Worker
3660*bb4ee6a4SAndroid Build Coastguard Worker /// Creates the given directories and files under `temp_dir`.
create_test_data(temp_dir: &TempDir, dirs: &[&str], files: &[&str])3661*bb4ee6a4SAndroid Build Coastguard Worker fn create_test_data(temp_dir: &TempDir, dirs: &[&str], files: &[&str]) {
3662*bb4ee6a4SAndroid Build Coastguard Worker let path = temp_dir.path();
3663*bb4ee6a4SAndroid Build Coastguard Worker
3664*bb4ee6a4SAndroid Build Coastguard Worker for d in dirs {
3665*bb4ee6a4SAndroid Build Coastguard Worker std::fs::create_dir_all(path.join(d)).unwrap();
3666*bb4ee6a4SAndroid Build Coastguard Worker }
3667*bb4ee6a4SAndroid Build Coastguard Worker
3668*bb4ee6a4SAndroid Build Coastguard Worker for f in files {
3669*bb4ee6a4SAndroid Build Coastguard Worker File::create(path.join(f)).unwrap();
3670*bb4ee6a4SAndroid Build Coastguard Worker }
3671*bb4ee6a4SAndroid Build Coastguard Worker }
3672*bb4ee6a4SAndroid Build Coastguard Worker
3673*bb4ee6a4SAndroid Build Coastguard Worker /// Looks up the given `path` in `fs`.
lookup(fs: &PassthroughFs, path: &Path) -> io::Result<Inode>3674*bb4ee6a4SAndroid Build Coastguard Worker fn lookup(fs: &PassthroughFs, path: &Path) -> io::Result<Inode> {
3675*bb4ee6a4SAndroid Build Coastguard Worker let mut inode = 1;
3676*bb4ee6a4SAndroid Build Coastguard Worker let ctx = get_context();
3677*bb4ee6a4SAndroid Build Coastguard Worker for name in path.iter() {
3678*bb4ee6a4SAndroid Build Coastguard Worker let name = CString::new(name.to_str().unwrap()).unwrap();
3679*bb4ee6a4SAndroid Build Coastguard Worker let ent = match fs.lookup(ctx, inode, &name) {
3680*bb4ee6a4SAndroid Build Coastguard Worker Ok(ent) => ent,
3681*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => {
3682*bb4ee6a4SAndroid Build Coastguard Worker return Err(e);
3683*bb4ee6a4SAndroid Build Coastguard Worker }
3684*bb4ee6a4SAndroid Build Coastguard Worker };
3685*bb4ee6a4SAndroid Build Coastguard Worker inode = ent.inode;
3686*bb4ee6a4SAndroid Build Coastguard Worker }
3687*bb4ee6a4SAndroid Build Coastguard Worker Ok(inode)
3688*bb4ee6a4SAndroid Build Coastguard Worker }
3689*bb4ee6a4SAndroid Build Coastguard Worker
3690*bb4ee6a4SAndroid Build Coastguard Worker /// Looks up the given `path` in `fs`.
3691*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
lookup_ent(fs: &PassthroughFs, path: &Path) -> io::Result<Entry>3692*bb4ee6a4SAndroid Build Coastguard Worker fn lookup_ent(fs: &PassthroughFs, path: &Path) -> io::Result<Entry> {
3693*bb4ee6a4SAndroid Build Coastguard Worker let mut inode = 1;
3694*bb4ee6a4SAndroid Build Coastguard Worker let ctx = get_context();
3695*bb4ee6a4SAndroid Build Coastguard Worker let mut entry = Entry::new_negative(Duration::from_secs(10));
3696*bb4ee6a4SAndroid Build Coastguard Worker for name in path.iter() {
3697*bb4ee6a4SAndroid Build Coastguard Worker let name = CString::new(name.to_str().unwrap()).unwrap();
3698*bb4ee6a4SAndroid Build Coastguard Worker entry = match fs.lookup(ctx, inode, &name) {
3699*bb4ee6a4SAndroid Build Coastguard Worker Ok(ent) => ent,
3700*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => {
3701*bb4ee6a4SAndroid Build Coastguard Worker return Err(e);
3702*bb4ee6a4SAndroid Build Coastguard Worker }
3703*bb4ee6a4SAndroid Build Coastguard Worker };
3704*bb4ee6a4SAndroid Build Coastguard Worker inode = entry.inode;
3705*bb4ee6a4SAndroid Build Coastguard Worker }
3706*bb4ee6a4SAndroid Build Coastguard Worker Ok(entry)
3707*bb4ee6a4SAndroid Build Coastguard Worker }
3708*bb4ee6a4SAndroid Build Coastguard Worker
3709*bb4ee6a4SAndroid Build Coastguard Worker /// Creates a file at the given `path`.
create(fs: &PassthroughFs, path: &Path) -> io::Result<Entry>3710*bb4ee6a4SAndroid Build Coastguard Worker fn create(fs: &PassthroughFs, path: &Path) -> io::Result<Entry> {
3711*bb4ee6a4SAndroid Build Coastguard Worker let parent = path.parent().unwrap();
3712*bb4ee6a4SAndroid Build Coastguard Worker let filename = CString::new(path.file_name().unwrap().to_str().unwrap()).unwrap();
3713*bb4ee6a4SAndroid Build Coastguard Worker let parent_inode = lookup(fs, parent)?;
3714*bb4ee6a4SAndroid Build Coastguard Worker let ctx = get_context();
3715*bb4ee6a4SAndroid Build Coastguard Worker let security_ctx = None;
3716*bb4ee6a4SAndroid Build Coastguard Worker fs.create(
3717*bb4ee6a4SAndroid Build Coastguard Worker ctx,
3718*bb4ee6a4SAndroid Build Coastguard Worker parent_inode,
3719*bb4ee6a4SAndroid Build Coastguard Worker &filename,
3720*bb4ee6a4SAndroid Build Coastguard Worker 0o666,
3721*bb4ee6a4SAndroid Build Coastguard Worker libc::O_RDWR as u32,
3722*bb4ee6a4SAndroid Build Coastguard Worker 0,
3723*bb4ee6a4SAndroid Build Coastguard Worker security_ctx,
3724*bb4ee6a4SAndroid Build Coastguard Worker )
3725*bb4ee6a4SAndroid Build Coastguard Worker .map(|(entry, _, _)| entry)
3726*bb4ee6a4SAndroid Build Coastguard Worker }
3727*bb4ee6a4SAndroid Build Coastguard Worker
3728*bb4ee6a4SAndroid Build Coastguard Worker /// Removes a file at the given `path`.
unlink(fs: &PassthroughFs, path: &Path) -> io::Result<()>3729*bb4ee6a4SAndroid Build Coastguard Worker fn unlink(fs: &PassthroughFs, path: &Path) -> io::Result<()> {
3730*bb4ee6a4SAndroid Build Coastguard Worker let parent = path.parent().unwrap();
3731*bb4ee6a4SAndroid Build Coastguard Worker let filename = CString::new(path.file_name().unwrap().to_str().unwrap()).unwrap();
3732*bb4ee6a4SAndroid Build Coastguard Worker let parent_inode = lookup(fs, parent)?;
3733*bb4ee6a4SAndroid Build Coastguard Worker let ctx = get_context();
3734*bb4ee6a4SAndroid Build Coastguard Worker fs.unlink(ctx, parent_inode, &filename)
3735*bb4ee6a4SAndroid Build Coastguard Worker }
3736*bb4ee6a4SAndroid Build Coastguard Worker
3737*bb4ee6a4SAndroid Build Coastguard Worker /// Forgets cache.
forget(fs: &PassthroughFs, path: &Path) -> io::Result<()>3738*bb4ee6a4SAndroid Build Coastguard Worker fn forget(fs: &PassthroughFs, path: &Path) -> io::Result<()> {
3739*bb4ee6a4SAndroid Build Coastguard Worker let ctx = get_context();
3740*bb4ee6a4SAndroid Build Coastguard Worker let inode = lookup(fs, path)?;
3741*bb4ee6a4SAndroid Build Coastguard Worker // Pass `u64::MAX` to ensure that the refcount goes to 0 and we forget inode.
3742*bb4ee6a4SAndroid Build Coastguard Worker fs.forget(ctx, inode, u64::MAX);
3743*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
3744*bb4ee6a4SAndroid Build Coastguard Worker }
3745*bb4ee6a4SAndroid Build Coastguard Worker
3746*bb4ee6a4SAndroid Build Coastguard Worker /// Looks up and open the given `path` in `fs`.
atomic_open( fs: &PassthroughFs, path: &Path, mode: u32, flags: u32, umask: u32, security_ctx: Option<&CStr>, ) -> io::Result<(Entry, Option<Handle>, OpenOptions)>3747*bb4ee6a4SAndroid Build Coastguard Worker fn atomic_open(
3748*bb4ee6a4SAndroid Build Coastguard Worker fs: &PassthroughFs,
3749*bb4ee6a4SAndroid Build Coastguard Worker path: &Path,
3750*bb4ee6a4SAndroid Build Coastguard Worker mode: u32,
3751*bb4ee6a4SAndroid Build Coastguard Worker flags: u32,
3752*bb4ee6a4SAndroid Build Coastguard Worker umask: u32,
3753*bb4ee6a4SAndroid Build Coastguard Worker security_ctx: Option<&CStr>,
3754*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<(Entry, Option<Handle>, OpenOptions)> {
3755*bb4ee6a4SAndroid Build Coastguard Worker let mut inode = 1;
3756*bb4ee6a4SAndroid Build Coastguard Worker let ctx = get_context();
3757*bb4ee6a4SAndroid Build Coastguard Worker
3758*bb4ee6a4SAndroid Build Coastguard Worker let path_vec: Vec<_> = path.iter().collect();
3759*bb4ee6a4SAndroid Build Coastguard Worker let vec_len = path_vec.len();
3760*bb4ee6a4SAndroid Build Coastguard Worker
3761*bb4ee6a4SAndroid Build Coastguard Worker // Do lookup before util (vec_len-1)-th pathname, this operation is to simulate
3762*bb4ee6a4SAndroid Build Coastguard Worker // the behavior of VFS, since when VFS call atomic_open only at last look up.
3763*bb4ee6a4SAndroid Build Coastguard Worker for name in &path_vec[0..vec_len - 1] {
3764*bb4ee6a4SAndroid Build Coastguard Worker let name = CString::new(name.to_str().unwrap()).unwrap();
3765*bb4ee6a4SAndroid Build Coastguard Worker let ent = fs.lookup(ctx, inode, &name)?;
3766*bb4ee6a4SAndroid Build Coastguard Worker inode = ent.inode;
3767*bb4ee6a4SAndroid Build Coastguard Worker }
3768*bb4ee6a4SAndroid Build Coastguard Worker
3769*bb4ee6a4SAndroid Build Coastguard Worker let name = CString::new(path_vec[vec_len - 1].to_str().unwrap()).unwrap();
3770*bb4ee6a4SAndroid Build Coastguard Worker
3771*bb4ee6a4SAndroid Build Coastguard Worker fs.atomic_open(ctx, inode, &name, mode, flags, umask, security_ctx)
3772*bb4ee6a4SAndroid Build Coastguard Worker }
3773*bb4ee6a4SAndroid Build Coastguard Worker
symlink( fs: &PassthroughFs, linkname: &Path, name: &Path, security_ctx: Option<&CStr>, ) -> io::Result<Entry>3774*bb4ee6a4SAndroid Build Coastguard Worker fn symlink(
3775*bb4ee6a4SAndroid Build Coastguard Worker fs: &PassthroughFs,
3776*bb4ee6a4SAndroid Build Coastguard Worker linkname: &Path,
3777*bb4ee6a4SAndroid Build Coastguard Worker name: &Path,
3778*bb4ee6a4SAndroid Build Coastguard Worker security_ctx: Option<&CStr>,
3779*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<Entry> {
3780*bb4ee6a4SAndroid Build Coastguard Worker let inode = 1;
3781*bb4ee6a4SAndroid Build Coastguard Worker let ctx = get_context();
3782*bb4ee6a4SAndroid Build Coastguard Worker let name = CString::new(name.to_str().unwrap()).unwrap();
3783*bb4ee6a4SAndroid Build Coastguard Worker let linkname = CString::new(linkname.to_str().unwrap()).unwrap();
3784*bb4ee6a4SAndroid Build Coastguard Worker fs.symlink(ctx, &linkname, inode, &name, security_ctx)
3785*bb4ee6a4SAndroid Build Coastguard Worker }
3786*bb4ee6a4SAndroid Build Coastguard Worker
3787*bb4ee6a4SAndroid Build Coastguard Worker // In this ioctl inode,handle,flags,arg and out_size is irrelavant, set to empty value.
3788*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
fs_ioc_setpermission<R: io::Read>( fs: &PassthroughFs, in_size: u32, r: R, ) -> io::Result<IoctlReply>3789*bb4ee6a4SAndroid Build Coastguard Worker fn fs_ioc_setpermission<R: io::Read>(
3790*bb4ee6a4SAndroid Build Coastguard Worker fs: &PassthroughFs,
3791*bb4ee6a4SAndroid Build Coastguard Worker in_size: u32,
3792*bb4ee6a4SAndroid Build Coastguard Worker r: R,
3793*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<IoctlReply> {
3794*bb4ee6a4SAndroid Build Coastguard Worker let ctx = get_context();
3795*bb4ee6a4SAndroid Build Coastguard Worker fs.ioctl(
3796*bb4ee6a4SAndroid Build Coastguard Worker ctx,
3797*bb4ee6a4SAndroid Build Coastguard Worker 0,
3798*bb4ee6a4SAndroid Build Coastguard Worker 0,
3799*bb4ee6a4SAndroid Build Coastguard Worker IoctlFlags::empty(),
3800*bb4ee6a4SAndroid Build Coastguard Worker FS_IOC_SETPERMISSION as u32,
3801*bb4ee6a4SAndroid Build Coastguard Worker 0,
3802*bb4ee6a4SAndroid Build Coastguard Worker in_size,
3803*bb4ee6a4SAndroid Build Coastguard Worker 0,
3804*bb4ee6a4SAndroid Build Coastguard Worker r,
3805*bb4ee6a4SAndroid Build Coastguard Worker )
3806*bb4ee6a4SAndroid Build Coastguard Worker }
3807*bb4ee6a4SAndroid Build Coastguard Worker
3808*bb4ee6a4SAndroid Build Coastguard Worker // In this ioctl inode,handle,flags,arg and out_size is irrelavant, set to empty value.
3809*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
fs_ioc_setpathxattr<R: io::Read>( fs: &PassthroughFs, in_size: u32, r: R, ) -> io::Result<IoctlReply>3810*bb4ee6a4SAndroid Build Coastguard Worker fn fs_ioc_setpathxattr<R: io::Read>(
3811*bb4ee6a4SAndroid Build Coastguard Worker fs: &PassthroughFs,
3812*bb4ee6a4SAndroid Build Coastguard Worker in_size: u32,
3813*bb4ee6a4SAndroid Build Coastguard Worker r: R,
3814*bb4ee6a4SAndroid Build Coastguard Worker ) -> io::Result<IoctlReply> {
3815*bb4ee6a4SAndroid Build Coastguard Worker let ctx = get_context();
3816*bb4ee6a4SAndroid Build Coastguard Worker fs.ioctl(
3817*bb4ee6a4SAndroid Build Coastguard Worker ctx,
3818*bb4ee6a4SAndroid Build Coastguard Worker 0,
3819*bb4ee6a4SAndroid Build Coastguard Worker 0,
3820*bb4ee6a4SAndroid Build Coastguard Worker IoctlFlags::empty(),
3821*bb4ee6a4SAndroid Build Coastguard Worker FS_IOC_SETPATHXATTR as u32,
3822*bb4ee6a4SAndroid Build Coastguard Worker 0,
3823*bb4ee6a4SAndroid Build Coastguard Worker in_size,
3824*bb4ee6a4SAndroid Build Coastguard Worker 0,
3825*bb4ee6a4SAndroid Build Coastguard Worker r,
3826*bb4ee6a4SAndroid Build Coastguard Worker )
3827*bb4ee6a4SAndroid Build Coastguard Worker }
3828*bb4ee6a4SAndroid Build Coastguard Worker
3829*bb4ee6a4SAndroid Build Coastguard Worker #[test]
rewrite_xattr_names()3830*bb4ee6a4SAndroid Build Coastguard Worker fn rewrite_xattr_names() {
3831*bb4ee6a4SAndroid Build Coastguard Worker // Since PassthroughFs may executes process-wide operations such as `fchdir`, acquire
3832*bb4ee6a4SAndroid Build Coastguard Worker // `NamedLock` before starting each unit test creating a `PassthroughFs` instance.
3833*bb4ee6a4SAndroid Build Coastguard Worker let lock = NamedLock::create(UNITTEST_LOCK_NAME).expect("create named lock");
3834*bb4ee6a4SAndroid Build Coastguard Worker let _guard = lock.lock().expect("acquire named lock");
3835*bb4ee6a4SAndroid Build Coastguard Worker
3836*bb4ee6a4SAndroid Build Coastguard Worker let cfg = Config {
3837*bb4ee6a4SAndroid Build Coastguard Worker rewrite_security_xattrs: true,
3838*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default()
3839*bb4ee6a4SAndroid Build Coastguard Worker };
3840*bb4ee6a4SAndroid Build Coastguard Worker
3841*bb4ee6a4SAndroid Build Coastguard Worker let p = PassthroughFs::new("tag", cfg).expect("Failed to create PassthroughFs");
3842*bb4ee6a4SAndroid Build Coastguard Worker
3843*bb4ee6a4SAndroid Build Coastguard Worker // Selinux shouldn't get overwritten.
3844*bb4ee6a4SAndroid Build Coastguard Worker let selinux = c"security.selinux";
3845*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(p.rewrite_xattr_name(selinux).to_bytes(), selinux.to_bytes());
3846*bb4ee6a4SAndroid Build Coastguard Worker
3847*bb4ee6a4SAndroid Build Coastguard Worker // user, trusted, and system should not be changed either.
3848*bb4ee6a4SAndroid Build Coastguard Worker let user = c"user.foobar";
3849*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(p.rewrite_xattr_name(user).to_bytes(), user.to_bytes());
3850*bb4ee6a4SAndroid Build Coastguard Worker let trusted = c"trusted.foobar";
3851*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(p.rewrite_xattr_name(trusted).to_bytes(), trusted.to_bytes());
3852*bb4ee6a4SAndroid Build Coastguard Worker let system = c"system.foobar";
3853*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(p.rewrite_xattr_name(system).to_bytes(), system.to_bytes());
3854*bb4ee6a4SAndroid Build Coastguard Worker
3855*bb4ee6a4SAndroid Build Coastguard Worker // sehash should be re-written.
3856*bb4ee6a4SAndroid Build Coastguard Worker let sehash = c"security.sehash";
3857*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
3858*bb4ee6a4SAndroid Build Coastguard Worker p.rewrite_xattr_name(sehash).to_bytes(),
3859*bb4ee6a4SAndroid Build Coastguard Worker b"user.virtiofs.security.sehash"
3860*bb4ee6a4SAndroid Build Coastguard Worker );
3861*bb4ee6a4SAndroid Build Coastguard Worker }
3862*bb4ee6a4SAndroid Build Coastguard Worker
3863*bb4ee6a4SAndroid Build Coastguard Worker #[test]
strip_xattr_names()3864*bb4ee6a4SAndroid Build Coastguard Worker fn strip_xattr_names() {
3865*bb4ee6a4SAndroid Build Coastguard Worker let only_nuls = b"\0\0\0\0\0";
3866*bb4ee6a4SAndroid Build Coastguard Worker let mut actual = only_nuls.to_vec();
3867*bb4ee6a4SAndroid Build Coastguard Worker strip_xattr_prefix(&mut actual);
3868*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(&actual[..], &only_nuls[..]);
3869*bb4ee6a4SAndroid Build Coastguard Worker
3870*bb4ee6a4SAndroid Build Coastguard Worker let no_nuls = b"security.sehashuser.virtiofs";
3871*bb4ee6a4SAndroid Build Coastguard Worker let mut actual = no_nuls.to_vec();
3872*bb4ee6a4SAndroid Build Coastguard Worker strip_xattr_prefix(&mut actual);
3873*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(&actual[..], &no_nuls[..]);
3874*bb4ee6a4SAndroid Build Coastguard Worker
3875*bb4ee6a4SAndroid Build Coastguard Worker let empty = b"";
3876*bb4ee6a4SAndroid Build Coastguard Worker let mut actual = empty.to_vec();
3877*bb4ee6a4SAndroid Build Coastguard Worker strip_xattr_prefix(&mut actual);
3878*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(&actual[..], &empty[..]);
3879*bb4ee6a4SAndroid Build Coastguard Worker
3880*bb4ee6a4SAndroid Build Coastguard Worker let no_strippable_names = b"security.selinux\0user.foobar\0system.test\0";
3881*bb4ee6a4SAndroid Build Coastguard Worker let mut actual = no_strippable_names.to_vec();
3882*bb4ee6a4SAndroid Build Coastguard Worker strip_xattr_prefix(&mut actual);
3883*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(&actual[..], &no_strippable_names[..]);
3884*bb4ee6a4SAndroid Build Coastguard Worker
3885*bb4ee6a4SAndroid Build Coastguard Worker let only_strippable_names = b"user.virtiofs.security.sehash\0user.virtiofs.security.wat\0";
3886*bb4ee6a4SAndroid Build Coastguard Worker let mut actual = only_strippable_names.to_vec();
3887*bb4ee6a4SAndroid Build Coastguard Worker strip_xattr_prefix(&mut actual);
3888*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(&actual[..], b"security.sehash\0security.wat\0");
3889*bb4ee6a4SAndroid Build Coastguard Worker
3890*bb4ee6a4SAndroid Build Coastguard Worker let mixed_names = b"user.virtiofs.security.sehash\0security.selinux\0user.virtiofs.security.wat\0user.foobar\0";
3891*bb4ee6a4SAndroid Build Coastguard Worker let mut actual = mixed_names.to_vec();
3892*bb4ee6a4SAndroid Build Coastguard Worker strip_xattr_prefix(&mut actual);
3893*bb4ee6a4SAndroid Build Coastguard Worker let expected = b"security.sehash\0security.selinux\0security.wat\0user.foobar\0";
3894*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(&actual[..], &expected[..]);
3895*bb4ee6a4SAndroid Build Coastguard Worker
3896*bb4ee6a4SAndroid Build Coastguard Worker let no_nul_with_prefix = b"user.virtiofs.security.sehash";
3897*bb4ee6a4SAndroid Build Coastguard Worker let mut actual = no_nul_with_prefix.to_vec();
3898*bb4ee6a4SAndroid Build Coastguard Worker strip_xattr_prefix(&mut actual);
3899*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(&actual[..], b"security.sehash");
3900*bb4ee6a4SAndroid Build Coastguard Worker }
3901*bb4ee6a4SAndroid Build Coastguard Worker
3902*bb4ee6a4SAndroid Build Coastguard Worker #[test]
lookup_files()3903*bb4ee6a4SAndroid Build Coastguard Worker fn lookup_files() {
3904*bb4ee6a4SAndroid Build Coastguard Worker // Since PassthroughFs may executes process-wide operations such as `fchdir`, acquire
3905*bb4ee6a4SAndroid Build Coastguard Worker // `NamedLock` before starting each unit test creating a `PassthroughFs` instance.
3906*bb4ee6a4SAndroid Build Coastguard Worker let lock = NamedLock::create(UNITTEST_LOCK_NAME).expect("create named lock");
3907*bb4ee6a4SAndroid Build Coastguard Worker let _guard = lock.lock().expect("acquire named lock");
3908*bb4ee6a4SAndroid Build Coastguard Worker
3909*bb4ee6a4SAndroid Build Coastguard Worker let temp_dir = TempDir::new().unwrap();
3910*bb4ee6a4SAndroid Build Coastguard Worker create_test_data(&temp_dir, &["dir"], &["a.txt", "dir/b.txt"]);
3911*bb4ee6a4SAndroid Build Coastguard Worker
3912*bb4ee6a4SAndroid Build Coastguard Worker let cfg = Default::default();
3913*bb4ee6a4SAndroid Build Coastguard Worker let fs = PassthroughFs::new("tag", cfg).unwrap();
3914*bb4ee6a4SAndroid Build Coastguard Worker
3915*bb4ee6a4SAndroid Build Coastguard Worker let capable = FsOptions::empty();
3916*bb4ee6a4SAndroid Build Coastguard Worker fs.init(capable).unwrap();
3917*bb4ee6a4SAndroid Build Coastguard Worker
3918*bb4ee6a4SAndroid Build Coastguard Worker assert!(lookup(&fs, &temp_dir.path().join("a.txt")).is_ok());
3919*bb4ee6a4SAndroid Build Coastguard Worker assert!(lookup(&fs, &temp_dir.path().join("dir")).is_ok());
3920*bb4ee6a4SAndroid Build Coastguard Worker assert!(lookup(&fs, &temp_dir.path().join("dir/b.txt")).is_ok());
3921*bb4ee6a4SAndroid Build Coastguard Worker
3922*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
3923*bb4ee6a4SAndroid Build Coastguard Worker lookup(&fs, &temp_dir.path().join("nonexistent-file"))
3924*bb4ee6a4SAndroid Build Coastguard Worker .expect_err("file must not exist")
3925*bb4ee6a4SAndroid Build Coastguard Worker .kind(),
3926*bb4ee6a4SAndroid Build Coastguard Worker io::ErrorKind::NotFound
3927*bb4ee6a4SAndroid Build Coastguard Worker );
3928*bb4ee6a4SAndroid Build Coastguard Worker // "A.txt" is different from "a.txt".
3929*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
3930*bb4ee6a4SAndroid Build Coastguard Worker lookup(&fs, &temp_dir.path().join("A.txt"))
3931*bb4ee6a4SAndroid Build Coastguard Worker .expect_err("file must not exist")
3932*bb4ee6a4SAndroid Build Coastguard Worker .kind(),
3933*bb4ee6a4SAndroid Build Coastguard Worker io::ErrorKind::NotFound
3934*bb4ee6a4SAndroid Build Coastguard Worker );
3935*bb4ee6a4SAndroid Build Coastguard Worker }
3936*bb4ee6a4SAndroid Build Coastguard Worker
3937*bb4ee6a4SAndroid Build Coastguard Worker #[test]
lookup_files_ascii_casefold()3938*bb4ee6a4SAndroid Build Coastguard Worker fn lookup_files_ascii_casefold() {
3939*bb4ee6a4SAndroid Build Coastguard Worker // Since PassthroughFs may executes process-wide operations such as `fchdir`, acquire
3940*bb4ee6a4SAndroid Build Coastguard Worker // `NamedLock` before starting each unit test creating a `PassthroughFs` instance.
3941*bb4ee6a4SAndroid Build Coastguard Worker let lock = NamedLock::create(UNITTEST_LOCK_NAME).expect("create named lock");
3942*bb4ee6a4SAndroid Build Coastguard Worker let _guard = lock.lock().expect("acquire named lock");
3943*bb4ee6a4SAndroid Build Coastguard Worker
3944*bb4ee6a4SAndroid Build Coastguard Worker let temp_dir = TempDir::new().unwrap();
3945*bb4ee6a4SAndroid Build Coastguard Worker create_test_data(&temp_dir, &["dir"], &["a.txt", "dir/b.txt"]);
3946*bb4ee6a4SAndroid Build Coastguard Worker
3947*bb4ee6a4SAndroid Build Coastguard Worker let cfg = Config {
3948*bb4ee6a4SAndroid Build Coastguard Worker ascii_casefold: true,
3949*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default()
3950*bb4ee6a4SAndroid Build Coastguard Worker };
3951*bb4ee6a4SAndroid Build Coastguard Worker let fs = PassthroughFs::new("tag", cfg).unwrap();
3952*bb4ee6a4SAndroid Build Coastguard Worker
3953*bb4ee6a4SAndroid Build Coastguard Worker let capable = FsOptions::empty();
3954*bb4ee6a4SAndroid Build Coastguard Worker fs.init(capable).unwrap();
3955*bb4ee6a4SAndroid Build Coastguard Worker
3956*bb4ee6a4SAndroid Build Coastguard Worker // Ensure that "A.txt" is equated with "a.txt".
3957*bb4ee6a4SAndroid Build Coastguard Worker let a_inode = lookup(&fs, &temp_dir.path().join("a.txt")).expect("a.txt must be found");
3958*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
3959*bb4ee6a4SAndroid Build Coastguard Worker lookup(&fs, &temp_dir.path().join("A.txt")).expect("A.txt must exist"),
3960*bb4ee6a4SAndroid Build Coastguard Worker a_inode
3961*bb4ee6a4SAndroid Build Coastguard Worker );
3962*bb4ee6a4SAndroid Build Coastguard Worker
3963*bb4ee6a4SAndroid Build Coastguard Worker let dir_inode = lookup(&fs, &temp_dir.path().join("dir")).expect("dir must be found");
3964*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
3965*bb4ee6a4SAndroid Build Coastguard Worker lookup(&fs, &temp_dir.path().join("DiR")).expect("DiR must exist"),
3966*bb4ee6a4SAndroid Build Coastguard Worker dir_inode
3967*bb4ee6a4SAndroid Build Coastguard Worker );
3968*bb4ee6a4SAndroid Build Coastguard Worker
3969*bb4ee6a4SAndroid Build Coastguard Worker let b_inode =
3970*bb4ee6a4SAndroid Build Coastguard Worker lookup(&fs, &temp_dir.path().join("dir/b.txt")).expect("dir/b.txt must be found");
3971*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
3972*bb4ee6a4SAndroid Build Coastguard Worker lookup(&fs, &temp_dir.path().join("dIr/B.TxT")).expect("dIr/B.TxT must exist"),
3973*bb4ee6a4SAndroid Build Coastguard Worker b_inode
3974*bb4ee6a4SAndroid Build Coastguard Worker );
3975*bb4ee6a4SAndroid Build Coastguard Worker
3976*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
3977*bb4ee6a4SAndroid Build Coastguard Worker lookup(&fs, &temp_dir.path().join("nonexistent-file"))
3978*bb4ee6a4SAndroid Build Coastguard Worker .expect_err("file must not exist")
3979*bb4ee6a4SAndroid Build Coastguard Worker .kind(),
3980*bb4ee6a4SAndroid Build Coastguard Worker io::ErrorKind::NotFound
3981*bb4ee6a4SAndroid Build Coastguard Worker );
3982*bb4ee6a4SAndroid Build Coastguard Worker }
3983*bb4ee6a4SAndroid Build Coastguard Worker
test_create_and_remove(ascii_casefold: bool)3984*bb4ee6a4SAndroid Build Coastguard Worker fn test_create_and_remove(ascii_casefold: bool) {
3985*bb4ee6a4SAndroid Build Coastguard Worker // Since PassthroughFs may executes process-wide operations such as `fchdir`, acquire
3986*bb4ee6a4SAndroid Build Coastguard Worker // `NamedLock` before starting each unit test creating a `PassthroughFs` instance.
3987*bb4ee6a4SAndroid Build Coastguard Worker let lock = NamedLock::create(UNITTEST_LOCK_NAME).expect("create named lock");
3988*bb4ee6a4SAndroid Build Coastguard Worker let _guard = lock.lock().expect("acquire named lock");
3989*bb4ee6a4SAndroid Build Coastguard Worker
3990*bb4ee6a4SAndroid Build Coastguard Worker let temp_dir = TempDir::new().unwrap();
3991*bb4ee6a4SAndroid Build Coastguard Worker let timeout = Duration::from_millis(10);
3992*bb4ee6a4SAndroid Build Coastguard Worker let cfg = Config {
3993*bb4ee6a4SAndroid Build Coastguard Worker timeout,
3994*bb4ee6a4SAndroid Build Coastguard Worker cache_policy: CachePolicy::Auto,
3995*bb4ee6a4SAndroid Build Coastguard Worker ascii_casefold,
3996*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default()
3997*bb4ee6a4SAndroid Build Coastguard Worker };
3998*bb4ee6a4SAndroid Build Coastguard Worker let fs = PassthroughFs::new("tag", cfg).unwrap();
3999*bb4ee6a4SAndroid Build Coastguard Worker
4000*bb4ee6a4SAndroid Build Coastguard Worker let capable = FsOptions::empty();
4001*bb4ee6a4SAndroid Build Coastguard Worker fs.init(capable).unwrap();
4002*bb4ee6a4SAndroid Build Coastguard Worker
4003*bb4ee6a4SAndroid Build Coastguard Worker // Create a.txt and b.txt.
4004*bb4ee6a4SAndroid Build Coastguard Worker let a_path = temp_dir.path().join("a.txt");
4005*bb4ee6a4SAndroid Build Coastguard Worker let b_path = temp_dir.path().join("b.txt");
4006*bb4ee6a4SAndroid Build Coastguard Worker let a_entry = create(&fs, &a_path).expect("create a.txt");
4007*bb4ee6a4SAndroid Build Coastguard Worker let b_entry = create(&fs, &b_path).expect("create b.txt");
4008*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
4009*bb4ee6a4SAndroid Build Coastguard Worker a_entry.inode,
4010*bb4ee6a4SAndroid Build Coastguard Worker lookup(&fs, &a_path).expect("lookup a.txt"),
4011*bb4ee6a4SAndroid Build Coastguard Worker "Created file 'a.txt' must be looked up"
4012*bb4ee6a4SAndroid Build Coastguard Worker );
4013*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
4014*bb4ee6a4SAndroid Build Coastguard Worker b_entry.inode,
4015*bb4ee6a4SAndroid Build Coastguard Worker lookup(&fs, &b_path).expect("lookup b.txt"),
4016*bb4ee6a4SAndroid Build Coastguard Worker "Created file 'b.txt' must be looked up"
4017*bb4ee6a4SAndroid Build Coastguard Worker );
4018*bb4ee6a4SAndroid Build Coastguard Worker
4019*bb4ee6a4SAndroid Build Coastguard Worker // Remove a.txt only
4020*bb4ee6a4SAndroid Build Coastguard Worker unlink(&fs, &a_path).expect("Remove");
4021*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
4022*bb4ee6a4SAndroid Build Coastguard Worker lookup(&fs, &a_path)
4023*bb4ee6a4SAndroid Build Coastguard Worker .expect_err("file must not exist")
4024*bb4ee6a4SAndroid Build Coastguard Worker .kind(),
4025*bb4ee6a4SAndroid Build Coastguard Worker io::ErrorKind::NotFound,
4026*bb4ee6a4SAndroid Build Coastguard Worker "a.txt must be removed"
4027*bb4ee6a4SAndroid Build Coastguard Worker );
4028*bb4ee6a4SAndroid Build Coastguard Worker // "A.TXT" must not be found regardless of whether casefold is enabled or not.
4029*bb4ee6a4SAndroid Build Coastguard Worker let upper_a_path = temp_dir.path().join("A.TXT");
4030*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
4031*bb4ee6a4SAndroid Build Coastguard Worker lookup(&fs, &upper_a_path)
4032*bb4ee6a4SAndroid Build Coastguard Worker .expect_err("file must not exist")
4033*bb4ee6a4SAndroid Build Coastguard Worker .kind(),
4034*bb4ee6a4SAndroid Build Coastguard Worker io::ErrorKind::NotFound,
4035*bb4ee6a4SAndroid Build Coastguard Worker "A.txt must be removed"
4036*bb4ee6a4SAndroid Build Coastguard Worker );
4037*bb4ee6a4SAndroid Build Coastguard Worker
4038*bb4ee6a4SAndroid Build Coastguard Worker // Check if the host file system doesn't have a.txt but does b.txt.
4039*bb4ee6a4SAndroid Build Coastguard Worker assert!(!a_path.exists(), "a.txt must be removed");
4040*bb4ee6a4SAndroid Build Coastguard Worker assert!(b_path.exists(), "b.txt must exist");
4041*bb4ee6a4SAndroid Build Coastguard Worker }
4042*bb4ee6a4SAndroid Build Coastguard Worker
4043*bb4ee6a4SAndroid Build Coastguard Worker #[test]
create_and_remove()4044*bb4ee6a4SAndroid Build Coastguard Worker fn create_and_remove() {
4045*bb4ee6a4SAndroid Build Coastguard Worker test_create_and_remove(false /* casefold */);
4046*bb4ee6a4SAndroid Build Coastguard Worker }
4047*bb4ee6a4SAndroid Build Coastguard Worker
4048*bb4ee6a4SAndroid Build Coastguard Worker #[test]
create_and_remove_casefold()4049*bb4ee6a4SAndroid Build Coastguard Worker fn create_and_remove_casefold() {
4050*bb4ee6a4SAndroid Build Coastguard Worker test_create_and_remove(true /* casefold */);
4051*bb4ee6a4SAndroid Build Coastguard Worker }
4052*bb4ee6a4SAndroid Build Coastguard Worker
test_create_and_forget(ascii_casefold: bool)4053*bb4ee6a4SAndroid Build Coastguard Worker fn test_create_and_forget(ascii_casefold: bool) {
4054*bb4ee6a4SAndroid Build Coastguard Worker // Since PassthroughFs may executes process-wide operations such as `fchdir`, acquire
4055*bb4ee6a4SAndroid Build Coastguard Worker // `NamedLock` before starting each unit test creating a `PassthroughFs` instance.
4056*bb4ee6a4SAndroid Build Coastguard Worker let lock = NamedLock::create(UNITTEST_LOCK_NAME).expect("create named lock");
4057*bb4ee6a4SAndroid Build Coastguard Worker let _guard = lock.lock().expect("acquire named lock");
4058*bb4ee6a4SAndroid Build Coastguard Worker
4059*bb4ee6a4SAndroid Build Coastguard Worker let temp_dir = TempDir::new().unwrap();
4060*bb4ee6a4SAndroid Build Coastguard Worker let timeout = Duration::from_millis(10);
4061*bb4ee6a4SAndroid Build Coastguard Worker let cfg = Config {
4062*bb4ee6a4SAndroid Build Coastguard Worker timeout,
4063*bb4ee6a4SAndroid Build Coastguard Worker cache_policy: CachePolicy::Auto,
4064*bb4ee6a4SAndroid Build Coastguard Worker ascii_casefold,
4065*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default()
4066*bb4ee6a4SAndroid Build Coastguard Worker };
4067*bb4ee6a4SAndroid Build Coastguard Worker let fs = PassthroughFs::new("tag", cfg).unwrap();
4068*bb4ee6a4SAndroid Build Coastguard Worker
4069*bb4ee6a4SAndroid Build Coastguard Worker let capable = FsOptions::empty();
4070*bb4ee6a4SAndroid Build Coastguard Worker fs.init(capable).unwrap();
4071*bb4ee6a4SAndroid Build Coastguard Worker
4072*bb4ee6a4SAndroid Build Coastguard Worker // Create a.txt.
4073*bb4ee6a4SAndroid Build Coastguard Worker let a_path = temp_dir.path().join("a.txt");
4074*bb4ee6a4SAndroid Build Coastguard Worker let a_entry = create(&fs, &a_path).expect("create a.txt");
4075*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
4076*bb4ee6a4SAndroid Build Coastguard Worker a_entry.inode,
4077*bb4ee6a4SAndroid Build Coastguard Worker lookup(&fs, &a_path).expect("lookup a.txt"),
4078*bb4ee6a4SAndroid Build Coastguard Worker "Created file 'a.txt' must be looked up"
4079*bb4ee6a4SAndroid Build Coastguard Worker );
4080*bb4ee6a4SAndroid Build Coastguard Worker
4081*bb4ee6a4SAndroid Build Coastguard Worker // Forget a.txt's inode from PassthroughFs's internal cache.
4082*bb4ee6a4SAndroid Build Coastguard Worker forget(&fs, &a_path).expect("forget a.txt");
4083*bb4ee6a4SAndroid Build Coastguard Worker
4084*bb4ee6a4SAndroid Build Coastguard Worker if ascii_casefold {
4085*bb4ee6a4SAndroid Build Coastguard Worker let upper_a_path = temp_dir.path().join("A.TXT");
4086*bb4ee6a4SAndroid Build Coastguard Worker let new_a_inode = lookup(&fs, &upper_a_path).expect("lookup a.txt");
4087*bb4ee6a4SAndroid Build Coastguard Worker assert_ne!(
4088*bb4ee6a4SAndroid Build Coastguard Worker a_entry.inode, new_a_inode,
4089*bb4ee6a4SAndroid Build Coastguard Worker "inode must be changed after forget()"
4090*bb4ee6a4SAndroid Build Coastguard Worker );
4091*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
4092*bb4ee6a4SAndroid Build Coastguard Worker new_a_inode,
4093*bb4ee6a4SAndroid Build Coastguard Worker lookup(&fs, &a_path).expect("lookup a.txt"),
4094*bb4ee6a4SAndroid Build Coastguard Worker "inode must be same for a.txt and A.TXT"
4095*bb4ee6a4SAndroid Build Coastguard Worker );
4096*bb4ee6a4SAndroid Build Coastguard Worker } else {
4097*bb4ee6a4SAndroid Build Coastguard Worker assert_ne!(
4098*bb4ee6a4SAndroid Build Coastguard Worker a_entry.inode,
4099*bb4ee6a4SAndroid Build Coastguard Worker lookup(&fs, &a_path).expect("lookup a.txt"),
4100*bb4ee6a4SAndroid Build Coastguard Worker "inode must be changed after forget()"
4101*bb4ee6a4SAndroid Build Coastguard Worker );
4102*bb4ee6a4SAndroid Build Coastguard Worker }
4103*bb4ee6a4SAndroid Build Coastguard Worker }
4104*bb4ee6a4SAndroid Build Coastguard Worker
4105*bb4ee6a4SAndroid Build Coastguard Worker #[test]
create_and_forget()4106*bb4ee6a4SAndroid Build Coastguard Worker fn create_and_forget() {
4107*bb4ee6a4SAndroid Build Coastguard Worker test_create_and_forget(false /* ascii_casefold */);
4108*bb4ee6a4SAndroid Build Coastguard Worker }
4109*bb4ee6a4SAndroid Build Coastguard Worker
4110*bb4ee6a4SAndroid Build Coastguard Worker #[test]
create_and_forget_casefold()4111*bb4ee6a4SAndroid Build Coastguard Worker fn create_and_forget_casefold() {
4112*bb4ee6a4SAndroid Build Coastguard Worker test_create_and_forget(true /* ascii_casefold */);
4113*bb4ee6a4SAndroid Build Coastguard Worker }
4114*bb4ee6a4SAndroid Build Coastguard Worker
4115*bb4ee6a4SAndroid Build Coastguard Worker #[test]
casefold_lookup_cache()4116*bb4ee6a4SAndroid Build Coastguard Worker fn casefold_lookup_cache() {
4117*bb4ee6a4SAndroid Build Coastguard Worker let temp_dir = TempDir::new().unwrap();
4118*bb4ee6a4SAndroid Build Coastguard Worker // Prepare `a.txt` before starting the test.
4119*bb4ee6a4SAndroid Build Coastguard Worker create_test_data(&temp_dir, &[], &["a.txt"]);
4120*bb4ee6a4SAndroid Build Coastguard Worker
4121*bb4ee6a4SAndroid Build Coastguard Worker let cfg = Config {
4122*bb4ee6a4SAndroid Build Coastguard Worker ascii_casefold: true,
4123*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default()
4124*bb4ee6a4SAndroid Build Coastguard Worker };
4125*bb4ee6a4SAndroid Build Coastguard Worker let fs = PassthroughFs::new("tag", cfg).unwrap();
4126*bb4ee6a4SAndroid Build Coastguard Worker
4127*bb4ee6a4SAndroid Build Coastguard Worker let capable = FsOptions::empty();
4128*bb4ee6a4SAndroid Build Coastguard Worker fs.init(capable).unwrap();
4129*bb4ee6a4SAndroid Build Coastguard Worker
4130*bb4ee6a4SAndroid Build Coastguard Worker let parent = lookup(&fs, temp_dir.path()).expect("lookup temp_dir");
4131*bb4ee6a4SAndroid Build Coastguard Worker
4132*bb4ee6a4SAndroid Build Coastguard Worker // Since `a.txt` exists, "A.TXT" must exist.
4133*bb4ee6a4SAndroid Build Coastguard Worker let large_a_path = temp_dir.path().join("A.TXT");
4134*bb4ee6a4SAndroid Build Coastguard Worker // Looking up "A.TXT" must create a CasefoldCache entry.
4135*bb4ee6a4SAndroid Build Coastguard Worker lookup(&fs, &large_a_path).expect("A.TXT must exist");
4136*bb4ee6a4SAndroid Build Coastguard Worker assert!(fs.exists_in_casefold_cache(parent, &CString::new("A.TXT").unwrap()));
4137*bb4ee6a4SAndroid Build Coastguard Worker
4138*bb4ee6a4SAndroid Build Coastguard Worker // Create b.txt.
4139*bb4ee6a4SAndroid Build Coastguard Worker let b_path = temp_dir.path().join("b.txt");
4140*bb4ee6a4SAndroid Build Coastguard Worker create(&fs, &b_path).expect("create b.txt");
4141*bb4ee6a4SAndroid Build Coastguard Worker // Then, b.txt must exists in the cache.
4142*bb4ee6a4SAndroid Build Coastguard Worker assert!(fs.exists_in_casefold_cache(parent, &CString::new("B.TXT").unwrap()));
4143*bb4ee6a4SAndroid Build Coastguard Worker // When removing b.txt, it must be removed from the cache as well.
4144*bb4ee6a4SAndroid Build Coastguard Worker unlink(&fs, &b_path).expect("remove b.txt");
4145*bb4ee6a4SAndroid Build Coastguard Worker assert!(!fs.exists_in_casefold_cache(parent, &CString::new("B.TXT").unwrap()));
4146*bb4ee6a4SAndroid Build Coastguard Worker }
4147*bb4ee6a4SAndroid Build Coastguard Worker
4148*bb4ee6a4SAndroid Build Coastguard Worker #[test]
lookup_negative_cache()4149*bb4ee6a4SAndroid Build Coastguard Worker fn lookup_negative_cache() {
4150*bb4ee6a4SAndroid Build Coastguard Worker let temp_dir = TempDir::new().unwrap();
4151*bb4ee6a4SAndroid Build Coastguard Worker // Prepare `a.txt` before starting the test.
4152*bb4ee6a4SAndroid Build Coastguard Worker create_test_data(&temp_dir, &[], &[]);
4153*bb4ee6a4SAndroid Build Coastguard Worker
4154*bb4ee6a4SAndroid Build Coastguard Worker let cfg = Config {
4155*bb4ee6a4SAndroid Build Coastguard Worker negative_timeout: Duration::from_secs(5),
4156*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default()
4157*bb4ee6a4SAndroid Build Coastguard Worker };
4158*bb4ee6a4SAndroid Build Coastguard Worker let fs = PassthroughFs::new("tag", cfg).unwrap();
4159*bb4ee6a4SAndroid Build Coastguard Worker
4160*bb4ee6a4SAndroid Build Coastguard Worker let capable = FsOptions::empty();
4161*bb4ee6a4SAndroid Build Coastguard Worker fs.init(capable).unwrap();
4162*bb4ee6a4SAndroid Build Coastguard Worker
4163*bb4ee6a4SAndroid Build Coastguard Worker let a_path = temp_dir.path().join("a.txt");
4164*bb4ee6a4SAndroid Build Coastguard Worker // a.txt hasn't existed yet.
4165*bb4ee6a4SAndroid Build Coastguard Worker // Since negative_timeout is enabled, success with inode=0 is expected.
4166*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
4167*bb4ee6a4SAndroid Build Coastguard Worker 0,
4168*bb4ee6a4SAndroid Build Coastguard Worker lookup(&fs, &a_path).expect("lookup a.txt"),
4169*bb4ee6a4SAndroid Build Coastguard Worker "Entry with inode=0 is expected for non-existing file 'a.txt'"
4170*bb4ee6a4SAndroid Build Coastguard Worker );
4171*bb4ee6a4SAndroid Build Coastguard Worker // Create a.txt
4172*bb4ee6a4SAndroid Build Coastguard Worker let a_entry = create(&fs, &a_path).expect("create a.txt");
4173*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
4174*bb4ee6a4SAndroid Build Coastguard Worker a_entry.inode,
4175*bb4ee6a4SAndroid Build Coastguard Worker lookup(&fs, &a_path).expect("lookup a.txt"),
4176*bb4ee6a4SAndroid Build Coastguard Worker "Created file 'a.txt' must be looked up"
4177*bb4ee6a4SAndroid Build Coastguard Worker );
4178*bb4ee6a4SAndroid Build Coastguard Worker // Remove a.txt
4179*bb4ee6a4SAndroid Build Coastguard Worker unlink(&fs, &a_path).expect("Remove");
4180*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
4181*bb4ee6a4SAndroid Build Coastguard Worker 0,
4182*bb4ee6a4SAndroid Build Coastguard Worker lookup(&fs, &a_path).expect("lookup a.txt"),
4183*bb4ee6a4SAndroid Build Coastguard Worker "Entry with inode=0 is expected for the removed file 'a.txt'"
4184*bb4ee6a4SAndroid Build Coastguard Worker );
4185*bb4ee6a4SAndroid Build Coastguard Worker }
4186*bb4ee6a4SAndroid Build Coastguard Worker #[test]
test_atomic_open_existing_file()4187*bb4ee6a4SAndroid Build Coastguard Worker fn test_atomic_open_existing_file() {
4188*bb4ee6a4SAndroid Build Coastguard Worker atomic_open_existing_file(false);
4189*bb4ee6a4SAndroid Build Coastguard Worker }
4190*bb4ee6a4SAndroid Build Coastguard Worker
4191*bb4ee6a4SAndroid Build Coastguard Worker #[test]
test_atomic_open_existing_file_zero_message()4192*bb4ee6a4SAndroid Build Coastguard Worker fn test_atomic_open_existing_file_zero_message() {
4193*bb4ee6a4SAndroid Build Coastguard Worker atomic_open_existing_file(true);
4194*bb4ee6a4SAndroid Build Coastguard Worker }
4195*bb4ee6a4SAndroid Build Coastguard Worker
atomic_open_existing_file(zero_message_open: bool)4196*bb4ee6a4SAndroid Build Coastguard Worker fn atomic_open_existing_file(zero_message_open: bool) {
4197*bb4ee6a4SAndroid Build Coastguard Worker // Since PassthroughFs may executes process-wide operations such as `fchdir`, acquire
4198*bb4ee6a4SAndroid Build Coastguard Worker // `NamedLock` before starting each unit test creating a `PassthroughFs` instance.
4199*bb4ee6a4SAndroid Build Coastguard Worker let lock = NamedLock::create(UNITTEST_LOCK_NAME).expect("create named lock");
4200*bb4ee6a4SAndroid Build Coastguard Worker let _guard = lock.lock().expect("acquire named lock");
4201*bb4ee6a4SAndroid Build Coastguard Worker
4202*bb4ee6a4SAndroid Build Coastguard Worker let temp_dir = TempDir::new().unwrap();
4203*bb4ee6a4SAndroid Build Coastguard Worker create_test_data(&temp_dir, &["dir"], &["a.txt", "dir/b.txt", "dir/c.txt"]);
4204*bb4ee6a4SAndroid Build Coastguard Worker
4205*bb4ee6a4SAndroid Build Coastguard Worker let cache_policy = match zero_message_open {
4206*bb4ee6a4SAndroid Build Coastguard Worker true => CachePolicy::Always,
4207*bb4ee6a4SAndroid Build Coastguard Worker false => CachePolicy::Auto,
4208*bb4ee6a4SAndroid Build Coastguard Worker };
4209*bb4ee6a4SAndroid Build Coastguard Worker
4210*bb4ee6a4SAndroid Build Coastguard Worker let cfg = Config {
4211*bb4ee6a4SAndroid Build Coastguard Worker cache_policy,
4212*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default()
4213*bb4ee6a4SAndroid Build Coastguard Worker };
4214*bb4ee6a4SAndroid Build Coastguard Worker let fs = PassthroughFs::new("tag", cfg).unwrap();
4215*bb4ee6a4SAndroid Build Coastguard Worker
4216*bb4ee6a4SAndroid Build Coastguard Worker let capable = FsOptions::ZERO_MESSAGE_OPEN;
4217*bb4ee6a4SAndroid Build Coastguard Worker fs.init(capable).unwrap();
4218*bb4ee6a4SAndroid Build Coastguard Worker
4219*bb4ee6a4SAndroid Build Coastguard Worker // atomic_open with flag O_RDWR, should return positive dentry and file handler
4220*bb4ee6a4SAndroid Build Coastguard Worker let res = atomic_open(
4221*bb4ee6a4SAndroid Build Coastguard Worker &fs,
4222*bb4ee6a4SAndroid Build Coastguard Worker &temp_dir.path().join("a.txt"),
4223*bb4ee6a4SAndroid Build Coastguard Worker 0o666,
4224*bb4ee6a4SAndroid Build Coastguard Worker libc::O_RDWR as u32,
4225*bb4ee6a4SAndroid Build Coastguard Worker 0,
4226*bb4ee6a4SAndroid Build Coastguard Worker None,
4227*bb4ee6a4SAndroid Build Coastguard Worker );
4228*bb4ee6a4SAndroid Build Coastguard Worker assert!(res.is_ok());
4229*bb4ee6a4SAndroid Build Coastguard Worker let (entry, handler, open_options) = res.unwrap();
4230*bb4ee6a4SAndroid Build Coastguard Worker assert_ne!(entry.inode, 0);
4231*bb4ee6a4SAndroid Build Coastguard Worker
4232*bb4ee6a4SAndroid Build Coastguard Worker if zero_message_open {
4233*bb4ee6a4SAndroid Build Coastguard Worker assert!(handler.is_none());
4234*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(open_options, OpenOptions::KEEP_CACHE);
4235*bb4ee6a4SAndroid Build Coastguard Worker } else {
4236*bb4ee6a4SAndroid Build Coastguard Worker assert!(handler.is_some());
4237*bb4ee6a4SAndroid Build Coastguard Worker assert_ne!(
4238*bb4ee6a4SAndroid Build Coastguard Worker open_options & OpenOptions::FILE_CREATED,
4239*bb4ee6a4SAndroid Build Coastguard Worker OpenOptions::FILE_CREATED
4240*bb4ee6a4SAndroid Build Coastguard Worker );
4241*bb4ee6a4SAndroid Build Coastguard Worker }
4242*bb4ee6a4SAndroid Build Coastguard Worker
4243*bb4ee6a4SAndroid Build Coastguard Worker // atomic_open with flag O_RDWR | O_CREATE, should return positive dentry and file handler
4244*bb4ee6a4SAndroid Build Coastguard Worker let res = atomic_open(
4245*bb4ee6a4SAndroid Build Coastguard Worker &fs,
4246*bb4ee6a4SAndroid Build Coastguard Worker &temp_dir.path().join("dir/b.txt"),
4247*bb4ee6a4SAndroid Build Coastguard Worker 0o666,
4248*bb4ee6a4SAndroid Build Coastguard Worker (libc::O_RDWR | libc::O_CREAT) as u32,
4249*bb4ee6a4SAndroid Build Coastguard Worker 0,
4250*bb4ee6a4SAndroid Build Coastguard Worker None,
4251*bb4ee6a4SAndroid Build Coastguard Worker );
4252*bb4ee6a4SAndroid Build Coastguard Worker assert!(res.is_ok());
4253*bb4ee6a4SAndroid Build Coastguard Worker let (entry, handler, open_options) = res.unwrap();
4254*bb4ee6a4SAndroid Build Coastguard Worker assert_ne!(entry.inode, 0);
4255*bb4ee6a4SAndroid Build Coastguard Worker
4256*bb4ee6a4SAndroid Build Coastguard Worker if zero_message_open {
4257*bb4ee6a4SAndroid Build Coastguard Worker assert!(handler.is_none());
4258*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(open_options, OpenOptions::KEEP_CACHE);
4259*bb4ee6a4SAndroid Build Coastguard Worker } else {
4260*bb4ee6a4SAndroid Build Coastguard Worker assert!(handler.is_some());
4261*bb4ee6a4SAndroid Build Coastguard Worker assert_ne!(
4262*bb4ee6a4SAndroid Build Coastguard Worker open_options & OpenOptions::FILE_CREATED,
4263*bb4ee6a4SAndroid Build Coastguard Worker OpenOptions::FILE_CREATED
4264*bb4ee6a4SAndroid Build Coastguard Worker );
4265*bb4ee6a4SAndroid Build Coastguard Worker }
4266*bb4ee6a4SAndroid Build Coastguard Worker
4267*bb4ee6a4SAndroid Build Coastguard Worker // atomic_open with flag O_RDWR | O_CREATE | O_EXCL, should return positive dentry and file
4268*bb4ee6a4SAndroid Build Coastguard Worker // handler
4269*bb4ee6a4SAndroid Build Coastguard Worker let res = atomic_open(
4270*bb4ee6a4SAndroid Build Coastguard Worker &fs,
4271*bb4ee6a4SAndroid Build Coastguard Worker &temp_dir.path().join("dir/c.txt"),
4272*bb4ee6a4SAndroid Build Coastguard Worker 0o666,
4273*bb4ee6a4SAndroid Build Coastguard Worker (libc::O_RDWR | libc::O_CREAT | libc::O_EXCL) as u32,
4274*bb4ee6a4SAndroid Build Coastguard Worker 0,
4275*bb4ee6a4SAndroid Build Coastguard Worker None,
4276*bb4ee6a4SAndroid Build Coastguard Worker );
4277*bb4ee6a4SAndroid Build Coastguard Worker assert!(res.is_err());
4278*bb4ee6a4SAndroid Build Coastguard Worker let err_kind = res.unwrap_err().kind();
4279*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(err_kind, io::ErrorKind::AlreadyExists);
4280*bb4ee6a4SAndroid Build Coastguard Worker }
4281*bb4ee6a4SAndroid Build Coastguard Worker
4282*bb4ee6a4SAndroid Build Coastguard Worker #[test]
test_atomic_open_non_existing_file()4283*bb4ee6a4SAndroid Build Coastguard Worker fn test_atomic_open_non_existing_file() {
4284*bb4ee6a4SAndroid Build Coastguard Worker atomic_open_non_existing_file(false);
4285*bb4ee6a4SAndroid Build Coastguard Worker }
4286*bb4ee6a4SAndroid Build Coastguard Worker
4287*bb4ee6a4SAndroid Build Coastguard Worker #[test]
test_atomic_open_non_existing_file_zero_message()4288*bb4ee6a4SAndroid Build Coastguard Worker fn test_atomic_open_non_existing_file_zero_message() {
4289*bb4ee6a4SAndroid Build Coastguard Worker atomic_open_non_existing_file(true);
4290*bb4ee6a4SAndroid Build Coastguard Worker }
4291*bb4ee6a4SAndroid Build Coastguard Worker
atomic_open_non_existing_file(zero_message_open: bool)4292*bb4ee6a4SAndroid Build Coastguard Worker fn atomic_open_non_existing_file(zero_message_open: bool) {
4293*bb4ee6a4SAndroid Build Coastguard Worker // Since PassthroughFs may executes process-wide operations such as `fchdir`, acquire
4294*bb4ee6a4SAndroid Build Coastguard Worker // `NamedLock` before starting each unit test creating a `PassthroughFs` instance.
4295*bb4ee6a4SAndroid Build Coastguard Worker let lock = NamedLock::create(UNITTEST_LOCK_NAME).expect("create named lock");
4296*bb4ee6a4SAndroid Build Coastguard Worker let _guard = lock.lock().expect("acquire named lock");
4297*bb4ee6a4SAndroid Build Coastguard Worker
4298*bb4ee6a4SAndroid Build Coastguard Worker let temp_dir = TempDir::new().unwrap();
4299*bb4ee6a4SAndroid Build Coastguard Worker
4300*bb4ee6a4SAndroid Build Coastguard Worker let cache_policy = match zero_message_open {
4301*bb4ee6a4SAndroid Build Coastguard Worker true => CachePolicy::Always,
4302*bb4ee6a4SAndroid Build Coastguard Worker false => CachePolicy::Auto,
4303*bb4ee6a4SAndroid Build Coastguard Worker };
4304*bb4ee6a4SAndroid Build Coastguard Worker
4305*bb4ee6a4SAndroid Build Coastguard Worker let cfg = Config {
4306*bb4ee6a4SAndroid Build Coastguard Worker cache_policy,
4307*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default()
4308*bb4ee6a4SAndroid Build Coastguard Worker };
4309*bb4ee6a4SAndroid Build Coastguard Worker let fs = PassthroughFs::new("tag", cfg).unwrap();
4310*bb4ee6a4SAndroid Build Coastguard Worker
4311*bb4ee6a4SAndroid Build Coastguard Worker let capable = FsOptions::ZERO_MESSAGE_OPEN;
4312*bb4ee6a4SAndroid Build Coastguard Worker fs.init(capable).unwrap();
4313*bb4ee6a4SAndroid Build Coastguard Worker
4314*bb4ee6a4SAndroid Build Coastguard Worker // atomic_open with flag O_RDWR, should return NO_EXIST error
4315*bb4ee6a4SAndroid Build Coastguard Worker let res = atomic_open(
4316*bb4ee6a4SAndroid Build Coastguard Worker &fs,
4317*bb4ee6a4SAndroid Build Coastguard Worker &temp_dir.path().join("a.txt"),
4318*bb4ee6a4SAndroid Build Coastguard Worker 0o666,
4319*bb4ee6a4SAndroid Build Coastguard Worker libc::O_RDWR as u32,
4320*bb4ee6a4SAndroid Build Coastguard Worker 0,
4321*bb4ee6a4SAndroid Build Coastguard Worker None,
4322*bb4ee6a4SAndroid Build Coastguard Worker );
4323*bb4ee6a4SAndroid Build Coastguard Worker assert!(res.is_err());
4324*bb4ee6a4SAndroid Build Coastguard Worker let err_kind = res.unwrap_err().kind();
4325*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(err_kind, io::ErrorKind::NotFound);
4326*bb4ee6a4SAndroid Build Coastguard Worker
4327*bb4ee6a4SAndroid Build Coastguard Worker // atomic_open with flag O_RDWR | O_CREATE, should return positive dentry and file handler
4328*bb4ee6a4SAndroid Build Coastguard Worker let res = atomic_open(
4329*bb4ee6a4SAndroid Build Coastguard Worker &fs,
4330*bb4ee6a4SAndroid Build Coastguard Worker &temp_dir.path().join("b.txt"),
4331*bb4ee6a4SAndroid Build Coastguard Worker 0o666,
4332*bb4ee6a4SAndroid Build Coastguard Worker (libc::O_RDWR | libc::O_CREAT) as u32,
4333*bb4ee6a4SAndroid Build Coastguard Worker 0,
4334*bb4ee6a4SAndroid Build Coastguard Worker None,
4335*bb4ee6a4SAndroid Build Coastguard Worker );
4336*bb4ee6a4SAndroid Build Coastguard Worker assert!(res.is_ok());
4337*bb4ee6a4SAndroid Build Coastguard Worker let (entry, handler, open_options) = res.unwrap();
4338*bb4ee6a4SAndroid Build Coastguard Worker assert_ne!(entry.inode, 0);
4339*bb4ee6a4SAndroid Build Coastguard Worker
4340*bb4ee6a4SAndroid Build Coastguard Worker if zero_message_open {
4341*bb4ee6a4SAndroid Build Coastguard Worker assert!(handler.is_none());
4342*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
4343*bb4ee6a4SAndroid Build Coastguard Worker open_options & OpenOptions::KEEP_CACHE,
4344*bb4ee6a4SAndroid Build Coastguard Worker OpenOptions::KEEP_CACHE
4345*bb4ee6a4SAndroid Build Coastguard Worker );
4346*bb4ee6a4SAndroid Build Coastguard Worker } else {
4347*bb4ee6a4SAndroid Build Coastguard Worker assert!(handler.is_some());
4348*bb4ee6a4SAndroid Build Coastguard Worker }
4349*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
4350*bb4ee6a4SAndroid Build Coastguard Worker open_options & OpenOptions::FILE_CREATED,
4351*bb4ee6a4SAndroid Build Coastguard Worker OpenOptions::FILE_CREATED
4352*bb4ee6a4SAndroid Build Coastguard Worker );
4353*bb4ee6a4SAndroid Build Coastguard Worker }
4354*bb4ee6a4SAndroid Build Coastguard Worker
4355*bb4ee6a4SAndroid Build Coastguard Worker #[test]
atomic_open_symbol_link()4356*bb4ee6a4SAndroid Build Coastguard Worker fn atomic_open_symbol_link() {
4357*bb4ee6a4SAndroid Build Coastguard Worker // Since PassthroughFs may executes process-wide operations such as `fchdir`, acquire
4358*bb4ee6a4SAndroid Build Coastguard Worker // `NamedLock` before starting each unit test creating a `PassthroughFs` instance.
4359*bb4ee6a4SAndroid Build Coastguard Worker let lock = NamedLock::create(UNITTEST_LOCK_NAME).expect("create named lock");
4360*bb4ee6a4SAndroid Build Coastguard Worker let _guard = lock.lock().expect("acquire named lock");
4361*bb4ee6a4SAndroid Build Coastguard Worker
4362*bb4ee6a4SAndroid Build Coastguard Worker let temp_dir = TempDir::new().unwrap();
4363*bb4ee6a4SAndroid Build Coastguard Worker create_test_data(&temp_dir, &["dir"], &["a.txt"]);
4364*bb4ee6a4SAndroid Build Coastguard Worker
4365*bb4ee6a4SAndroid Build Coastguard Worker let cfg = Default::default();
4366*bb4ee6a4SAndroid Build Coastguard Worker let fs = PassthroughFs::new("tag", cfg).unwrap();
4367*bb4ee6a4SAndroid Build Coastguard Worker
4368*bb4ee6a4SAndroid Build Coastguard Worker let capable = FsOptions::empty();
4369*bb4ee6a4SAndroid Build Coastguard Worker fs.init(capable).unwrap();
4370*bb4ee6a4SAndroid Build Coastguard Worker
4371*bb4ee6a4SAndroid Build Coastguard Worker // atomic open the link destination file
4372*bb4ee6a4SAndroid Build Coastguard Worker let res_dst = atomic_open(
4373*bb4ee6a4SAndroid Build Coastguard Worker &fs,
4374*bb4ee6a4SAndroid Build Coastguard Worker &temp_dir.path().join("a.txt"),
4375*bb4ee6a4SAndroid Build Coastguard Worker 0o666,
4376*bb4ee6a4SAndroid Build Coastguard Worker libc::O_RDWR as u32,
4377*bb4ee6a4SAndroid Build Coastguard Worker 0,
4378*bb4ee6a4SAndroid Build Coastguard Worker None,
4379*bb4ee6a4SAndroid Build Coastguard Worker );
4380*bb4ee6a4SAndroid Build Coastguard Worker assert!(res_dst.is_ok());
4381*bb4ee6a4SAndroid Build Coastguard Worker let (entry_dst, handler_dst, _) = res_dst.unwrap();
4382*bb4ee6a4SAndroid Build Coastguard Worker assert_ne!(entry_dst.inode, 0);
4383*bb4ee6a4SAndroid Build Coastguard Worker assert!(handler_dst.is_some());
4384*bb4ee6a4SAndroid Build Coastguard Worker
4385*bb4ee6a4SAndroid Build Coastguard Worker // create depth 1 symbol link
4386*bb4ee6a4SAndroid Build Coastguard Worker let sym1_res = symlink(
4387*bb4ee6a4SAndroid Build Coastguard Worker &fs,
4388*bb4ee6a4SAndroid Build Coastguard Worker &temp_dir.path().join("a.txt"),
4389*bb4ee6a4SAndroid Build Coastguard Worker &temp_dir.path().join("blink"),
4390*bb4ee6a4SAndroid Build Coastguard Worker None,
4391*bb4ee6a4SAndroid Build Coastguard Worker );
4392*bb4ee6a4SAndroid Build Coastguard Worker assert!(sym1_res.is_ok());
4393*bb4ee6a4SAndroid Build Coastguard Worker let sym1_entry = sym1_res.unwrap();
4394*bb4ee6a4SAndroid Build Coastguard Worker assert_ne!(sym1_entry.inode, 0);
4395*bb4ee6a4SAndroid Build Coastguard Worker
4396*bb4ee6a4SAndroid Build Coastguard Worker // atomic_open symbol link, should return dentry with no handler
4397*bb4ee6a4SAndroid Build Coastguard Worker let res = atomic_open(
4398*bb4ee6a4SAndroid Build Coastguard Worker &fs,
4399*bb4ee6a4SAndroid Build Coastguard Worker &temp_dir.path().join("blink"),
4400*bb4ee6a4SAndroid Build Coastguard Worker 0o666,
4401*bb4ee6a4SAndroid Build Coastguard Worker libc::O_RDWR as u32,
4402*bb4ee6a4SAndroid Build Coastguard Worker 0,
4403*bb4ee6a4SAndroid Build Coastguard Worker None,
4404*bb4ee6a4SAndroid Build Coastguard Worker );
4405*bb4ee6a4SAndroid Build Coastguard Worker assert!(res.is_ok());
4406*bb4ee6a4SAndroid Build Coastguard Worker let (entry, handler, open_options) = res.unwrap();
4407*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(entry.inode, sym1_entry.inode);
4408*bb4ee6a4SAndroid Build Coastguard Worker assert!(handler.is_none());
4409*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(open_options, OpenOptions::empty());
4410*bb4ee6a4SAndroid Build Coastguard Worker
4411*bb4ee6a4SAndroid Build Coastguard Worker // delete link destination
4412*bb4ee6a4SAndroid Build Coastguard Worker unlink(&fs, &temp_dir.path().join("a.txt")).expect("Remove");
4413*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(
4414*bb4ee6a4SAndroid Build Coastguard Worker lookup(&fs, &temp_dir.path().join("a.txt"))
4415*bb4ee6a4SAndroid Build Coastguard Worker .expect_err("file must not exist")
4416*bb4ee6a4SAndroid Build Coastguard Worker .kind(),
4417*bb4ee6a4SAndroid Build Coastguard Worker io::ErrorKind::NotFound,
4418*bb4ee6a4SAndroid Build Coastguard Worker "a.txt must be removed"
4419*bb4ee6a4SAndroid Build Coastguard Worker );
4420*bb4ee6a4SAndroid Build Coastguard Worker
4421*bb4ee6a4SAndroid Build Coastguard Worker // after link destination removed, should still return valid dentry
4422*bb4ee6a4SAndroid Build Coastguard Worker let res = atomic_open(
4423*bb4ee6a4SAndroid Build Coastguard Worker &fs,
4424*bb4ee6a4SAndroid Build Coastguard Worker &temp_dir.path().join("blink"),
4425*bb4ee6a4SAndroid Build Coastguard Worker 0o666,
4426*bb4ee6a4SAndroid Build Coastguard Worker libc::O_RDWR as u32,
4427*bb4ee6a4SAndroid Build Coastguard Worker 0,
4428*bb4ee6a4SAndroid Build Coastguard Worker None,
4429*bb4ee6a4SAndroid Build Coastguard Worker );
4430*bb4ee6a4SAndroid Build Coastguard Worker assert!(res.is_ok());
4431*bb4ee6a4SAndroid Build Coastguard Worker let (entry, handler, open_options) = res.unwrap();
4432*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(entry.inode, sym1_entry.inode);
4433*bb4ee6a4SAndroid Build Coastguard Worker assert!(handler.is_none());
4434*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(open_options, OpenOptions::empty());
4435*bb4ee6a4SAndroid Build Coastguard Worker }
4436*bb4ee6a4SAndroid Build Coastguard Worker
4437*bb4ee6a4SAndroid Build Coastguard Worker #[test]
4438*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
set_permission_ioctl_valid_data()4439*bb4ee6a4SAndroid Build Coastguard Worker fn set_permission_ioctl_valid_data() {
4440*bb4ee6a4SAndroid Build Coastguard Worker // Since PassthroughFs may executes process-wide operations such as `fchdir`, acquire
4441*bb4ee6a4SAndroid Build Coastguard Worker // `NamedLock` before starting each unit test creating a `PassthroughFs` instance.
4442*bb4ee6a4SAndroid Build Coastguard Worker let lock = NamedLock::create(UNITTEST_LOCK_NAME).expect("create named lock");
4443*bb4ee6a4SAndroid Build Coastguard Worker let _guard = lock.lock().expect("acquire named lock");
4444*bb4ee6a4SAndroid Build Coastguard Worker
4445*bb4ee6a4SAndroid Build Coastguard Worker let cfg = Config {
4446*bb4ee6a4SAndroid Build Coastguard Worker max_dynamic_perm: 1,
4447*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default()
4448*bb4ee6a4SAndroid Build Coastguard Worker };
4449*bb4ee6a4SAndroid Build Coastguard Worker let p = PassthroughFs::new("tag", cfg).expect("Failed to create PassthroughFs");
4450*bb4ee6a4SAndroid Build Coastguard Worker
4451*bb4ee6a4SAndroid Build Coastguard Worker let perm_path_string = String::from("/test");
4452*bb4ee6a4SAndroid Build Coastguard Worker let fs_permission_data_buffer = FsPermissionDataBuffer {
4453*bb4ee6a4SAndroid Build Coastguard Worker guest_uid: 1,
4454*bb4ee6a4SAndroid Build Coastguard Worker guest_gid: 2,
4455*bb4ee6a4SAndroid Build Coastguard Worker host_uid: 3,
4456*bb4ee6a4SAndroid Build Coastguard Worker host_gid: 4,
4457*bb4ee6a4SAndroid Build Coastguard Worker umask: 5,
4458*bb4ee6a4SAndroid Build Coastguard Worker pad: 0,
4459*bb4ee6a4SAndroid Build Coastguard Worker perm_path: {
4460*bb4ee6a4SAndroid Build Coastguard Worker let mut perm_path: [u8; FS_IOCTL_PATH_MAX_LEN] = [0; FS_IOCTL_PATH_MAX_LEN];
4461*bb4ee6a4SAndroid Build Coastguard Worker perm_path[..perm_path_string.len()].copy_from_slice(perm_path_string.as_bytes());
4462*bb4ee6a4SAndroid Build Coastguard Worker perm_path
4463*bb4ee6a4SAndroid Build Coastguard Worker },
4464*bb4ee6a4SAndroid Build Coastguard Worker };
4465*bb4ee6a4SAndroid Build Coastguard Worker let r = std::io::Cursor::new(fs_permission_data_buffer.as_bytes());
4466*bb4ee6a4SAndroid Build Coastguard Worker
4467*bb4ee6a4SAndroid Build Coastguard Worker let res = fs_ioc_setpermission(
4468*bb4ee6a4SAndroid Build Coastguard Worker &p,
4469*bb4ee6a4SAndroid Build Coastguard Worker mem::size_of_val(&fs_permission_data_buffer) as u32,
4470*bb4ee6a4SAndroid Build Coastguard Worker r.clone(),
4471*bb4ee6a4SAndroid Build Coastguard Worker )
4472*bb4ee6a4SAndroid Build Coastguard Worker .expect("valid input should get IoctlReply");
4473*bb4ee6a4SAndroid Build Coastguard Worker assert!(matches!(res, IoctlReply::Done(Ok(data)) if data.is_empty()));
4474*bb4ee6a4SAndroid Build Coastguard Worker
4475*bb4ee6a4SAndroid Build Coastguard Worker let read_guard = p
4476*bb4ee6a4SAndroid Build Coastguard Worker .permission_paths
4477*bb4ee6a4SAndroid Build Coastguard Worker .read()
4478*bb4ee6a4SAndroid Build Coastguard Worker .expect("read permission_paths failed");
4479*bb4ee6a4SAndroid Build Coastguard Worker let permission_data = read_guard
4480*bb4ee6a4SAndroid Build Coastguard Worker .first()
4481*bb4ee6a4SAndroid Build Coastguard Worker .expect("permission path should not be empty");
4482*bb4ee6a4SAndroid Build Coastguard Worker
4483*bb4ee6a4SAndroid Build Coastguard Worker // Check expected data item is added to permission_paths.
4484*bb4ee6a4SAndroid Build Coastguard Worker let expected_data = PermissionData {
4485*bb4ee6a4SAndroid Build Coastguard Worker guest_uid: 1,
4486*bb4ee6a4SAndroid Build Coastguard Worker guest_gid: 2,
4487*bb4ee6a4SAndroid Build Coastguard Worker host_uid: 3,
4488*bb4ee6a4SAndroid Build Coastguard Worker host_gid: 4,
4489*bb4ee6a4SAndroid Build Coastguard Worker umask: 5,
4490*bb4ee6a4SAndroid Build Coastguard Worker perm_path: perm_path_string,
4491*bb4ee6a4SAndroid Build Coastguard Worker };
4492*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(*permission_data, expected_data);
4493*bb4ee6a4SAndroid Build Coastguard Worker
4494*bb4ee6a4SAndroid Build Coastguard Worker // Second ioctl should not succeed since max_dynamic_perm is set to 1
4495*bb4ee6a4SAndroid Build Coastguard Worker let res = fs_ioc_setpermission(
4496*bb4ee6a4SAndroid Build Coastguard Worker &p,
4497*bb4ee6a4SAndroid Build Coastguard Worker mem::size_of_val(&fs_permission_data_buffer) as u32,
4498*bb4ee6a4SAndroid Build Coastguard Worker r.clone(),
4499*bb4ee6a4SAndroid Build Coastguard Worker )
4500*bb4ee6a4SAndroid Build Coastguard Worker .expect("valid input should get IoctlReply");
4501*bb4ee6a4SAndroid Build Coastguard Worker assert!(
4502*bb4ee6a4SAndroid Build Coastguard Worker matches!(res, IoctlReply::Done(Err(err)) if err.raw_os_error().is_some_and(|errno| {
4503*bb4ee6a4SAndroid Build Coastguard Worker errno == libc::EPERM
4504*bb4ee6a4SAndroid Build Coastguard Worker }))
4505*bb4ee6a4SAndroid Build Coastguard Worker );
4506*bb4ee6a4SAndroid Build Coastguard Worker }
4507*bb4ee6a4SAndroid Build Coastguard Worker
4508*bb4ee6a4SAndroid Build Coastguard Worker #[test]
4509*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
set_permission_ioctl_invalid_data()4510*bb4ee6a4SAndroid Build Coastguard Worker fn set_permission_ioctl_invalid_data() {
4511*bb4ee6a4SAndroid Build Coastguard Worker // Since PassthroughFs may executes process-wide operations such as `fchdir`, acquire
4512*bb4ee6a4SAndroid Build Coastguard Worker // `NamedLock` before starting each unit test creating a `PassthroughFs` instance.
4513*bb4ee6a4SAndroid Build Coastguard Worker let lock = NamedLock::create(UNITTEST_LOCK_NAME).expect("create named lock");
4514*bb4ee6a4SAndroid Build Coastguard Worker let _guard = lock.lock().expect("acquire named lock");
4515*bb4ee6a4SAndroid Build Coastguard Worker
4516*bb4ee6a4SAndroid Build Coastguard Worker let cfg = Config {
4517*bb4ee6a4SAndroid Build Coastguard Worker max_dynamic_perm: 1,
4518*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default()
4519*bb4ee6a4SAndroid Build Coastguard Worker };
4520*bb4ee6a4SAndroid Build Coastguard Worker let p = PassthroughFs::new("tag", cfg).expect("Failed to create PassthroughFs");
4521*bb4ee6a4SAndroid Build Coastguard Worker
4522*bb4ee6a4SAndroid Build Coastguard Worker // The perm_path is not valid since it does not start with /.
4523*bb4ee6a4SAndroid Build Coastguard Worker let perm_path_string = String::from("test");
4524*bb4ee6a4SAndroid Build Coastguard Worker let fs_permission_data_buffer = FsPermissionDataBuffer {
4525*bb4ee6a4SAndroid Build Coastguard Worker guest_uid: 1,
4526*bb4ee6a4SAndroid Build Coastguard Worker guest_gid: 2,
4527*bb4ee6a4SAndroid Build Coastguard Worker host_uid: 3,
4528*bb4ee6a4SAndroid Build Coastguard Worker host_gid: 4,
4529*bb4ee6a4SAndroid Build Coastguard Worker umask: 5,
4530*bb4ee6a4SAndroid Build Coastguard Worker pad: 0,
4531*bb4ee6a4SAndroid Build Coastguard Worker perm_path: {
4532*bb4ee6a4SAndroid Build Coastguard Worker let mut perm_path: [u8; FS_IOCTL_PATH_MAX_LEN] = [0; FS_IOCTL_PATH_MAX_LEN];
4533*bb4ee6a4SAndroid Build Coastguard Worker perm_path[..perm_path_string.len()].copy_from_slice(perm_path_string.as_bytes());
4534*bb4ee6a4SAndroid Build Coastguard Worker perm_path
4535*bb4ee6a4SAndroid Build Coastguard Worker },
4536*bb4ee6a4SAndroid Build Coastguard Worker };
4537*bb4ee6a4SAndroid Build Coastguard Worker
4538*bb4ee6a4SAndroid Build Coastguard Worker let r = std::io::Cursor::new(fs_permission_data_buffer.as_bytes());
4539*bb4ee6a4SAndroid Build Coastguard Worker // In this ioctl inode,handle,flags,arg and out_size is irrelavant, set to empty value.
4540*bb4ee6a4SAndroid Build Coastguard Worker // This call is supposed to get EINVAL ioctlReply, since the perm_path is invalid.
4541*bb4ee6a4SAndroid Build Coastguard Worker let res = fs_ioc_setpermission(&p, mem::size_of_val(&fs_permission_data_buffer) as u32, r)
4542*bb4ee6a4SAndroid Build Coastguard Worker .expect("invalid perm_path should get IoctlReply");
4543*bb4ee6a4SAndroid Build Coastguard Worker assert!(
4544*bb4ee6a4SAndroid Build Coastguard Worker matches!(res, IoctlReply::Done(Err(err)) if err.raw_os_error().is_some_and(|errno| {
4545*bb4ee6a4SAndroid Build Coastguard Worker errno == libc::EINVAL
4546*bb4ee6a4SAndroid Build Coastguard Worker }))
4547*bb4ee6a4SAndroid Build Coastguard Worker );
4548*bb4ee6a4SAndroid Build Coastguard Worker
4549*bb4ee6a4SAndroid Build Coastguard Worker let fake_data_buffer: [u8; 128] = [0; 128];
4550*bb4ee6a4SAndroid Build Coastguard Worker let r = std::io::Cursor::new(fake_data_buffer.as_bytes());
4551*bb4ee6a4SAndroid Build Coastguard Worker
4552*bb4ee6a4SAndroid Build Coastguard Worker // This call is supposed to get EINVAL ioctlReply, since the in_size is not the size of
4553*bb4ee6a4SAndroid Build Coastguard Worker // struct FsPermissionDataBuffer.
4554*bb4ee6a4SAndroid Build Coastguard Worker let res = fs_ioc_setpermission(&p, mem::size_of_val(&fake_data_buffer) as u32, r)
4555*bb4ee6a4SAndroid Build Coastguard Worker .expect_err("invalid in_size should get Error");
4556*bb4ee6a4SAndroid Build Coastguard Worker assert!(res
4557*bb4ee6a4SAndroid Build Coastguard Worker .raw_os_error()
4558*bb4ee6a4SAndroid Build Coastguard Worker .is_some_and(|errno| { errno == libc::EINVAL }));
4559*bb4ee6a4SAndroid Build Coastguard Worker }
4560*bb4ee6a4SAndroid Build Coastguard Worker
4561*bb4ee6a4SAndroid Build Coastguard Worker #[test]
4562*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
permission_data_path_matching()4563*bb4ee6a4SAndroid Build Coastguard Worker fn permission_data_path_matching() {
4564*bb4ee6a4SAndroid Build Coastguard Worker let ctx = get_context();
4565*bb4ee6a4SAndroid Build Coastguard Worker let temp_dir = TempDir::new().unwrap();
4566*bb4ee6a4SAndroid Build Coastguard Worker // Prepare `a.txt` before starting the test.
4567*bb4ee6a4SAndroid Build Coastguard Worker create_test_data(&temp_dir, &["dir"], &["a.txt", "dir/a.txt"]);
4568*bb4ee6a4SAndroid Build Coastguard Worker
4569*bb4ee6a4SAndroid Build Coastguard Worker let cfg = Config {
4570*bb4ee6a4SAndroid Build Coastguard Worker max_dynamic_perm: 1,
4571*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default()
4572*bb4ee6a4SAndroid Build Coastguard Worker };
4573*bb4ee6a4SAndroid Build Coastguard Worker let fs = PassthroughFs::new("tag", cfg).unwrap();
4574*bb4ee6a4SAndroid Build Coastguard Worker
4575*bb4ee6a4SAndroid Build Coastguard Worker let capable = FsOptions::empty();
4576*bb4ee6a4SAndroid Build Coastguard Worker fs.init(capable).unwrap();
4577*bb4ee6a4SAndroid Build Coastguard Worker
4578*bb4ee6a4SAndroid Build Coastguard Worker const BY_PATH_UID: u32 = 655360;
4579*bb4ee6a4SAndroid Build Coastguard Worker const BY_PATH_GID: u32 = 655361;
4580*bb4ee6a4SAndroid Build Coastguard Worker const BY_PATH_UMASK: u32 = 0o007;
4581*bb4ee6a4SAndroid Build Coastguard Worker
4582*bb4ee6a4SAndroid Build Coastguard Worker let dir_path = temp_dir.path().join("dir");
4583*bb4ee6a4SAndroid Build Coastguard Worker let permission_data = PermissionData {
4584*bb4ee6a4SAndroid Build Coastguard Worker guest_uid: BY_PATH_UID,
4585*bb4ee6a4SAndroid Build Coastguard Worker guest_gid: BY_PATH_GID,
4586*bb4ee6a4SAndroid Build Coastguard Worker host_uid: ctx.uid,
4587*bb4ee6a4SAndroid Build Coastguard Worker host_gid: ctx.gid,
4588*bb4ee6a4SAndroid Build Coastguard Worker umask: BY_PATH_UMASK,
4589*bb4ee6a4SAndroid Build Coastguard Worker perm_path: dir_path.to_string_lossy().into_owned(),
4590*bb4ee6a4SAndroid Build Coastguard Worker };
4591*bb4ee6a4SAndroid Build Coastguard Worker fs.permission_paths
4592*bb4ee6a4SAndroid Build Coastguard Worker .write()
4593*bb4ee6a4SAndroid Build Coastguard Worker .expect("permission_path lock must be acquired")
4594*bb4ee6a4SAndroid Build Coastguard Worker .push(permission_data);
4595*bb4ee6a4SAndroid Build Coastguard Worker
4596*bb4ee6a4SAndroid Build Coastguard Worker // a_path is the path with out set permission by path
4597*bb4ee6a4SAndroid Build Coastguard Worker let a_path = temp_dir.path().join("a.txt");
4598*bb4ee6a4SAndroid Build Coastguard Worker let in_dir_a_path = dir_path.join("a.txt");
4599*bb4ee6a4SAndroid Build Coastguard Worker
4600*bb4ee6a4SAndroid Build Coastguard Worker // a.txt should not be set with guest_uid/guest_uid/umask by path
4601*bb4ee6a4SAndroid Build Coastguard Worker let a_entry = lookup_ent(&fs, &a_path).expect("a.txt must exist");
4602*bb4ee6a4SAndroid Build Coastguard Worker assert_ne!(a_entry.attr.st_uid, BY_PATH_UID);
4603*bb4ee6a4SAndroid Build Coastguard Worker assert_ne!(a_entry.attr.st_gid, BY_PATH_GID);
4604*bb4ee6a4SAndroid Build Coastguard Worker
4605*bb4ee6a4SAndroid Build Coastguard Worker // a.txt in dir should be set guest_uid/guest_uid/umask by path
4606*bb4ee6a4SAndroid Build Coastguard Worker let in_dir_a_entry = lookup_ent(&fs, &in_dir_a_path).expect("dir/a.txt must exist");
4607*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(in_dir_a_entry.attr.st_uid, BY_PATH_UID);
4608*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(in_dir_a_entry.attr.st_gid, BY_PATH_GID);
4609*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(in_dir_a_entry.attr.st_mode & 0o777, !BY_PATH_UMASK & 0o777);
4610*bb4ee6a4SAndroid Build Coastguard Worker
4611*bb4ee6a4SAndroid Build Coastguard Worker // Create dir/b.txt.
4612*bb4ee6a4SAndroid Build Coastguard Worker let in_dir_b_path = dir_path.join("b.txt");
4613*bb4ee6a4SAndroid Build Coastguard Worker create(&fs, &in_dir_b_path).expect("create b.txt");
4614*bb4ee6a4SAndroid Build Coastguard Worker
4615*bb4ee6a4SAndroid Build Coastguard Worker // newly created b.txt in dir should be set guest_uid/guest_uid/umask by path
4616*bb4ee6a4SAndroid Build Coastguard Worker let in_dir_b_entry = lookup_ent(&fs, &in_dir_a_path).expect("dir/b.txt must exist");
4617*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(in_dir_b_entry.attr.st_uid, BY_PATH_UID);
4618*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(in_dir_b_entry.attr.st_gid, BY_PATH_GID);
4619*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(in_dir_b_entry.attr.st_mode & 0o777, !BY_PATH_UMASK & 0o777);
4620*bb4ee6a4SAndroid Build Coastguard Worker }
4621*bb4ee6a4SAndroid Build Coastguard Worker
4622*bb4ee6a4SAndroid Build Coastguard Worker #[test]
4623*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
set_path_xattr_ioctl_valid_data()4624*bb4ee6a4SAndroid Build Coastguard Worker fn set_path_xattr_ioctl_valid_data() {
4625*bb4ee6a4SAndroid Build Coastguard Worker // Since PassthroughFs may executes process-wide operations such as `fchdir`, acquire
4626*bb4ee6a4SAndroid Build Coastguard Worker // `NamedLock` before starting each unit test creating a `PassthroughFs` instance.
4627*bb4ee6a4SAndroid Build Coastguard Worker let lock = NamedLock::create(UNITTEST_LOCK_NAME).expect("create named lock");
4628*bb4ee6a4SAndroid Build Coastguard Worker let _guard = lock.lock().expect("acquire named lock");
4629*bb4ee6a4SAndroid Build Coastguard Worker
4630*bb4ee6a4SAndroid Build Coastguard Worker let cfg: Config = Config {
4631*bb4ee6a4SAndroid Build Coastguard Worker max_dynamic_xattr: 1,
4632*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default()
4633*bb4ee6a4SAndroid Build Coastguard Worker };
4634*bb4ee6a4SAndroid Build Coastguard Worker let p = PassthroughFs::new("tag", cfg).expect("Failed to create PassthroughFs");
4635*bb4ee6a4SAndroid Build Coastguard Worker
4636*bb4ee6a4SAndroid Build Coastguard Worker let path_string = String::from("/test");
4637*bb4ee6a4SAndroid Build Coastguard Worker let xattr_name_string = String::from("test_name");
4638*bb4ee6a4SAndroid Build Coastguard Worker let xattr_value_string = String::from("test_value");
4639*bb4ee6a4SAndroid Build Coastguard Worker let fs_path_xattr_data_buffer = FsPathXattrDataBuffer {
4640*bb4ee6a4SAndroid Build Coastguard Worker path: {
4641*bb4ee6a4SAndroid Build Coastguard Worker let mut path: [u8; FS_IOCTL_PATH_MAX_LEN] = [0; FS_IOCTL_PATH_MAX_LEN];
4642*bb4ee6a4SAndroid Build Coastguard Worker path[..path_string.len()].copy_from_slice(path_string.as_bytes());
4643*bb4ee6a4SAndroid Build Coastguard Worker path
4644*bb4ee6a4SAndroid Build Coastguard Worker },
4645*bb4ee6a4SAndroid Build Coastguard Worker xattr_name: {
4646*bb4ee6a4SAndroid Build Coastguard Worker let mut xattr_name: [u8; FS_IOCTL_XATTR_NAME_MAX_LEN] =
4647*bb4ee6a4SAndroid Build Coastguard Worker [0; FS_IOCTL_XATTR_NAME_MAX_LEN];
4648*bb4ee6a4SAndroid Build Coastguard Worker xattr_name[..xattr_name_string.len()].copy_from_slice(xattr_name_string.as_bytes());
4649*bb4ee6a4SAndroid Build Coastguard Worker xattr_name
4650*bb4ee6a4SAndroid Build Coastguard Worker },
4651*bb4ee6a4SAndroid Build Coastguard Worker xattr_value: {
4652*bb4ee6a4SAndroid Build Coastguard Worker let mut xattr_value: [u8; FS_IOCTL_XATTR_VALUE_MAX_LEN] =
4653*bb4ee6a4SAndroid Build Coastguard Worker [0; FS_IOCTL_XATTR_VALUE_MAX_LEN];
4654*bb4ee6a4SAndroid Build Coastguard Worker xattr_value[..xattr_value_string.len()]
4655*bb4ee6a4SAndroid Build Coastguard Worker .copy_from_slice(xattr_value_string.as_bytes());
4656*bb4ee6a4SAndroid Build Coastguard Worker xattr_value
4657*bb4ee6a4SAndroid Build Coastguard Worker },
4658*bb4ee6a4SAndroid Build Coastguard Worker };
4659*bb4ee6a4SAndroid Build Coastguard Worker let r = std::io::Cursor::new(fs_path_xattr_data_buffer.as_bytes());
4660*bb4ee6a4SAndroid Build Coastguard Worker
4661*bb4ee6a4SAndroid Build Coastguard Worker let res = fs_ioc_setpathxattr(
4662*bb4ee6a4SAndroid Build Coastguard Worker &p,
4663*bb4ee6a4SAndroid Build Coastguard Worker mem::size_of_val(&fs_path_xattr_data_buffer) as u32,
4664*bb4ee6a4SAndroid Build Coastguard Worker r.clone(),
4665*bb4ee6a4SAndroid Build Coastguard Worker )
4666*bb4ee6a4SAndroid Build Coastguard Worker .expect("valid input should get IoctlReply");
4667*bb4ee6a4SAndroid Build Coastguard Worker assert!(matches!(res, IoctlReply::Done(Ok(data)) if data.is_empty()));
4668*bb4ee6a4SAndroid Build Coastguard Worker
4669*bb4ee6a4SAndroid Build Coastguard Worker let read_guard = p.xattr_paths.read().expect("read xattr_paths failed");
4670*bb4ee6a4SAndroid Build Coastguard Worker let xattr_data = read_guard.first().expect("xattr_paths should not be empty");
4671*bb4ee6a4SAndroid Build Coastguard Worker
4672*bb4ee6a4SAndroid Build Coastguard Worker // Check expected data item is added to permission_paths.
4673*bb4ee6a4SAndroid Build Coastguard Worker let expected_data = XattrData {
4674*bb4ee6a4SAndroid Build Coastguard Worker xattr_path: path_string,
4675*bb4ee6a4SAndroid Build Coastguard Worker xattr_name: xattr_name_string,
4676*bb4ee6a4SAndroid Build Coastguard Worker xattr_value: xattr_value_string,
4677*bb4ee6a4SAndroid Build Coastguard Worker };
4678*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(*xattr_data, expected_data);
4679*bb4ee6a4SAndroid Build Coastguard Worker
4680*bb4ee6a4SAndroid Build Coastguard Worker // Second ioctl should not succeed since max_dynamic_perm is set to 1
4681*bb4ee6a4SAndroid Build Coastguard Worker let res = fs_ioc_setpathxattr(
4682*bb4ee6a4SAndroid Build Coastguard Worker &p,
4683*bb4ee6a4SAndroid Build Coastguard Worker mem::size_of_val(&fs_path_xattr_data_buffer) as u32,
4684*bb4ee6a4SAndroid Build Coastguard Worker r.clone(),
4685*bb4ee6a4SAndroid Build Coastguard Worker )
4686*bb4ee6a4SAndroid Build Coastguard Worker .expect("valid input should get IoctlReply");
4687*bb4ee6a4SAndroid Build Coastguard Worker assert!(
4688*bb4ee6a4SAndroid Build Coastguard Worker matches!(res, IoctlReply::Done(Err(err)) if err.raw_os_error().is_some_and(|errno| {
4689*bb4ee6a4SAndroid Build Coastguard Worker errno == libc::EPERM
4690*bb4ee6a4SAndroid Build Coastguard Worker }))
4691*bb4ee6a4SAndroid Build Coastguard Worker );
4692*bb4ee6a4SAndroid Build Coastguard Worker }
4693*bb4ee6a4SAndroid Build Coastguard Worker #[test]
4694*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
set_path_xattr_ioctl_invalid_data()4695*bb4ee6a4SAndroid Build Coastguard Worker fn set_path_xattr_ioctl_invalid_data() {
4696*bb4ee6a4SAndroid Build Coastguard Worker // Since PassthroughFs may executes process-wide operations such as `fchdir`, acquire
4697*bb4ee6a4SAndroid Build Coastguard Worker // `NamedLock` before starting each unit test creating a `PassthroughFs` instance.
4698*bb4ee6a4SAndroid Build Coastguard Worker let lock = NamedLock::create(UNITTEST_LOCK_NAME).expect("create named lock");
4699*bb4ee6a4SAndroid Build Coastguard Worker let _guard = lock.lock().expect("acquire named lock");
4700*bb4ee6a4SAndroid Build Coastguard Worker
4701*bb4ee6a4SAndroid Build Coastguard Worker let cfg: Config = Config {
4702*bb4ee6a4SAndroid Build Coastguard Worker max_dynamic_xattr: 1,
4703*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default()
4704*bb4ee6a4SAndroid Build Coastguard Worker };
4705*bb4ee6a4SAndroid Build Coastguard Worker let p = PassthroughFs::new("tag", cfg).expect("Failed to create PassthroughFs");
4706*bb4ee6a4SAndroid Build Coastguard Worker
4707*bb4ee6a4SAndroid Build Coastguard Worker let path_string = String::from("test");
4708*bb4ee6a4SAndroid Build Coastguard Worker let xattr_name_string = String::from("test_name");
4709*bb4ee6a4SAndroid Build Coastguard Worker let xattr_value_string = String::from("test_value");
4710*bb4ee6a4SAndroid Build Coastguard Worker let fs_path_xattr_data_buffer = FsPathXattrDataBuffer {
4711*bb4ee6a4SAndroid Build Coastguard Worker path: {
4712*bb4ee6a4SAndroid Build Coastguard Worker let mut path: [u8; FS_IOCTL_PATH_MAX_LEN] = [0; FS_IOCTL_PATH_MAX_LEN];
4713*bb4ee6a4SAndroid Build Coastguard Worker path[..path_string.len()].copy_from_slice(path_string.as_bytes());
4714*bb4ee6a4SAndroid Build Coastguard Worker path
4715*bb4ee6a4SAndroid Build Coastguard Worker },
4716*bb4ee6a4SAndroid Build Coastguard Worker xattr_name: {
4717*bb4ee6a4SAndroid Build Coastguard Worker let mut xattr_name: [u8; FS_IOCTL_XATTR_NAME_MAX_LEN] =
4718*bb4ee6a4SAndroid Build Coastguard Worker [0; FS_IOCTL_XATTR_NAME_MAX_LEN];
4719*bb4ee6a4SAndroid Build Coastguard Worker xattr_name[..xattr_name_string.len()].copy_from_slice(xattr_name_string.as_bytes());
4720*bb4ee6a4SAndroid Build Coastguard Worker xattr_name
4721*bb4ee6a4SAndroid Build Coastguard Worker },
4722*bb4ee6a4SAndroid Build Coastguard Worker xattr_value: {
4723*bb4ee6a4SAndroid Build Coastguard Worker let mut xattr_value: [u8; FS_IOCTL_XATTR_VALUE_MAX_LEN] =
4724*bb4ee6a4SAndroid Build Coastguard Worker [0; FS_IOCTL_XATTR_VALUE_MAX_LEN];
4725*bb4ee6a4SAndroid Build Coastguard Worker xattr_value[..xattr_value_string.len()]
4726*bb4ee6a4SAndroid Build Coastguard Worker .copy_from_slice(xattr_value_string.as_bytes());
4727*bb4ee6a4SAndroid Build Coastguard Worker xattr_value
4728*bb4ee6a4SAndroid Build Coastguard Worker },
4729*bb4ee6a4SAndroid Build Coastguard Worker };
4730*bb4ee6a4SAndroid Build Coastguard Worker let r = std::io::Cursor::new(fs_path_xattr_data_buffer.as_bytes());
4731*bb4ee6a4SAndroid Build Coastguard Worker
4732*bb4ee6a4SAndroid Build Coastguard Worker // This call is supposed to get EINVAL ioctlReply, since the perm_path is invalid.
4733*bb4ee6a4SAndroid Build Coastguard Worker let res = fs_ioc_setpathxattr(
4734*bb4ee6a4SAndroid Build Coastguard Worker &p,
4735*bb4ee6a4SAndroid Build Coastguard Worker mem::size_of_val(&fs_path_xattr_data_buffer) as u32,
4736*bb4ee6a4SAndroid Build Coastguard Worker r.clone(),
4737*bb4ee6a4SAndroid Build Coastguard Worker )
4738*bb4ee6a4SAndroid Build Coastguard Worker .expect("valid input should get IoctlReply");
4739*bb4ee6a4SAndroid Build Coastguard Worker assert!(
4740*bb4ee6a4SAndroid Build Coastguard Worker matches!(res, IoctlReply::Done(Err(err)) if err.raw_os_error().is_some_and(|errno| {
4741*bb4ee6a4SAndroid Build Coastguard Worker errno == libc::EINVAL
4742*bb4ee6a4SAndroid Build Coastguard Worker }))
4743*bb4ee6a4SAndroid Build Coastguard Worker );
4744*bb4ee6a4SAndroid Build Coastguard Worker
4745*bb4ee6a4SAndroid Build Coastguard Worker let fake_data_buffer: [u8; 128] = [0; 128];
4746*bb4ee6a4SAndroid Build Coastguard Worker let r = std::io::Cursor::new(fake_data_buffer.as_bytes());
4747*bb4ee6a4SAndroid Build Coastguard Worker // This call is supposed to get EINVAL ioctlReply, since the in_size is not the size of
4748*bb4ee6a4SAndroid Build Coastguard Worker // struct FsPathXattrDataBuffer.
4749*bb4ee6a4SAndroid Build Coastguard Worker let res = fs_ioc_setpathxattr(&p, mem::size_of_val(&fake_data_buffer) as u32, r.clone())
4750*bb4ee6a4SAndroid Build Coastguard Worker .expect_err("valid input should get IoctlReply");
4751*bb4ee6a4SAndroid Build Coastguard Worker assert!(res
4752*bb4ee6a4SAndroid Build Coastguard Worker .raw_os_error()
4753*bb4ee6a4SAndroid Build Coastguard Worker .is_some_and(|errno| { errno == libc::EINVAL }));
4754*bb4ee6a4SAndroid Build Coastguard Worker }
4755*bb4ee6a4SAndroid Build Coastguard Worker
4756*bb4ee6a4SAndroid Build Coastguard Worker #[test]
4757*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "arc_quota")]
xattr_data_path_matching()4758*bb4ee6a4SAndroid Build Coastguard Worker fn xattr_data_path_matching() {
4759*bb4ee6a4SAndroid Build Coastguard Worker let ctx = get_context();
4760*bb4ee6a4SAndroid Build Coastguard Worker let temp_dir = TempDir::new().unwrap();
4761*bb4ee6a4SAndroid Build Coastguard Worker // Prepare `a.txt` before starting the test.
4762*bb4ee6a4SAndroid Build Coastguard Worker create_test_data(&temp_dir, &["dir"], &["a.txt", "dir/a.txt"]);
4763*bb4ee6a4SAndroid Build Coastguard Worker
4764*bb4ee6a4SAndroid Build Coastguard Worker let cfg = Config {
4765*bb4ee6a4SAndroid Build Coastguard Worker max_dynamic_xattr: 1,
4766*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default()
4767*bb4ee6a4SAndroid Build Coastguard Worker };
4768*bb4ee6a4SAndroid Build Coastguard Worker let fs = PassthroughFs::new("tag", cfg).unwrap();
4769*bb4ee6a4SAndroid Build Coastguard Worker
4770*bb4ee6a4SAndroid Build Coastguard Worker let capable = FsOptions::empty();
4771*bb4ee6a4SAndroid Build Coastguard Worker fs.init(capable).unwrap();
4772*bb4ee6a4SAndroid Build Coastguard Worker
4773*bb4ee6a4SAndroid Build Coastguard Worker let dir_path = temp_dir.path().join("dir");
4774*bb4ee6a4SAndroid Build Coastguard Worker let xattr_name_string = String::from("test_name");
4775*bb4ee6a4SAndroid Build Coastguard Worker let xattr_name_cstring = CString::new(xattr_name_string.clone()).expect("create c string");
4776*bb4ee6a4SAndroid Build Coastguard Worker let xattr_value_string = String::from("test_value");
4777*bb4ee6a4SAndroid Build Coastguard Worker let xattr_value_bytes = xattr_value_string.clone().into_bytes();
4778*bb4ee6a4SAndroid Build Coastguard Worker
4779*bb4ee6a4SAndroid Build Coastguard Worker let xattr_data = XattrData {
4780*bb4ee6a4SAndroid Build Coastguard Worker xattr_name: xattr_name_string,
4781*bb4ee6a4SAndroid Build Coastguard Worker xattr_value: xattr_value_string,
4782*bb4ee6a4SAndroid Build Coastguard Worker xattr_path: dir_path.to_string_lossy().into_owned(),
4783*bb4ee6a4SAndroid Build Coastguard Worker };
4784*bb4ee6a4SAndroid Build Coastguard Worker fs.xattr_paths
4785*bb4ee6a4SAndroid Build Coastguard Worker .write()
4786*bb4ee6a4SAndroid Build Coastguard Worker .expect("xattr_paths lock must be acquired")
4787*bb4ee6a4SAndroid Build Coastguard Worker .push(xattr_data);
4788*bb4ee6a4SAndroid Build Coastguard Worker
4789*bb4ee6a4SAndroid Build Coastguard Worker // a_path is the path with out set xattr by path
4790*bb4ee6a4SAndroid Build Coastguard Worker let a_path: std::path::PathBuf = temp_dir.path().join("a.txt");
4791*bb4ee6a4SAndroid Build Coastguard Worker let in_dir_a_path = dir_path.join("a.txt");
4792*bb4ee6a4SAndroid Build Coastguard Worker
4793*bb4ee6a4SAndroid Build Coastguard Worker let a_node = lookup(&fs, a_path.as_path()).expect("lookup a node");
4794*bb4ee6a4SAndroid Build Coastguard Worker // a.txt should not be set with xattr by path
4795*bb4ee6a4SAndroid Build Coastguard Worker assert!(fs
4796*bb4ee6a4SAndroid Build Coastguard Worker .getxattr(
4797*bb4ee6a4SAndroid Build Coastguard Worker ctx,
4798*bb4ee6a4SAndroid Build Coastguard Worker a_node,
4799*bb4ee6a4SAndroid Build Coastguard Worker &xattr_name_cstring,
4800*bb4ee6a4SAndroid Build Coastguard Worker xattr_value_bytes.len() as u32
4801*bb4ee6a4SAndroid Build Coastguard Worker )
4802*bb4ee6a4SAndroid Build Coastguard Worker .is_err());
4803*bb4ee6a4SAndroid Build Coastguard Worker
4804*bb4ee6a4SAndroid Build Coastguard Worker let in_dir_a_node = lookup(&fs, in_dir_a_path.as_path()).expect("lookup in dir a node");
4805*bb4ee6a4SAndroid Build Coastguard Worker // a.txt in dir should be set xattr by path
4806*bb4ee6a4SAndroid Build Coastguard Worker let in_dir_a_reply = fs
4807*bb4ee6a4SAndroid Build Coastguard Worker .getxattr(
4808*bb4ee6a4SAndroid Build Coastguard Worker ctx,
4809*bb4ee6a4SAndroid Build Coastguard Worker in_dir_a_node,
4810*bb4ee6a4SAndroid Build Coastguard Worker &xattr_name_cstring,
4811*bb4ee6a4SAndroid Build Coastguard Worker xattr_value_bytes.len() as u32,
4812*bb4ee6a4SAndroid Build Coastguard Worker )
4813*bb4ee6a4SAndroid Build Coastguard Worker .expect("Getxattr should success");
4814*bb4ee6a4SAndroid Build Coastguard Worker assert!(matches!(in_dir_a_reply, GetxattrReply::Value(v) if v == xattr_value_bytes));
4815*bb4ee6a4SAndroid Build Coastguard Worker // Create dir/b.txt.
4816*bb4ee6a4SAndroid Build Coastguard Worker let in_dir_b_path = dir_path.join("b.txt");
4817*bb4ee6a4SAndroid Build Coastguard Worker create(&fs, &in_dir_b_path).expect("create b.txt");
4818*bb4ee6a4SAndroid Build Coastguard Worker
4819*bb4ee6a4SAndroid Build Coastguard Worker // newly created b.txt in dir should be set xattr by path
4820*bb4ee6a4SAndroid Build Coastguard Worker let in_dir_b_node = lookup(&fs, in_dir_a_path.as_path()).expect("lookup in dir b node");
4821*bb4ee6a4SAndroid Build Coastguard Worker let in_dir_b_reply = fs
4822*bb4ee6a4SAndroid Build Coastguard Worker .getxattr(
4823*bb4ee6a4SAndroid Build Coastguard Worker ctx,
4824*bb4ee6a4SAndroid Build Coastguard Worker in_dir_b_node,
4825*bb4ee6a4SAndroid Build Coastguard Worker &xattr_name_cstring,
4826*bb4ee6a4SAndroid Build Coastguard Worker xattr_value_bytes.len() as u32,
4827*bb4ee6a4SAndroid Build Coastguard Worker )
4828*bb4ee6a4SAndroid Build Coastguard Worker .expect("Getxattr should success");
4829*bb4ee6a4SAndroid Build Coastguard Worker assert!(matches!(in_dir_b_reply, GetxattrReply::Value(v) if v == xattr_value_bytes));
4830*bb4ee6a4SAndroid Build Coastguard Worker }
4831*bb4ee6a4SAndroid Build Coastguard Worker
4832*bb4ee6a4SAndroid Build Coastguard Worker /// Creates and open a new file by atomic_open with O_APPEND flag.
4833*bb4ee6a4SAndroid Build Coastguard Worker /// We check O_APPEND is properly handled, depending on writeback cache is enabled or not.
atomic_open_create_o_append(writeback: bool)4834*bb4ee6a4SAndroid Build Coastguard Worker fn atomic_open_create_o_append(writeback: bool) {
4835*bb4ee6a4SAndroid Build Coastguard Worker // Since PassthroughFs may executes process-wide operations such as `fchdir`, acquire
4836*bb4ee6a4SAndroid Build Coastguard Worker // `NamedLock` before starting each unit test creating a `PassthroughFs` instance.
4837*bb4ee6a4SAndroid Build Coastguard Worker let lock = NamedLock::create(UNITTEST_LOCK_NAME).expect("create named lock");
4838*bb4ee6a4SAndroid Build Coastguard Worker let _guard = lock.lock().expect("acquire named lock");
4839*bb4ee6a4SAndroid Build Coastguard Worker
4840*bb4ee6a4SAndroid Build Coastguard Worker let temp_dir = TempDir::new().unwrap();
4841*bb4ee6a4SAndroid Build Coastguard Worker
4842*bb4ee6a4SAndroid Build Coastguard Worker let cfg = Config {
4843*bb4ee6a4SAndroid Build Coastguard Worker cache_policy: CachePolicy::Always,
4844*bb4ee6a4SAndroid Build Coastguard Worker writeback,
4845*bb4ee6a4SAndroid Build Coastguard Worker ..Default::default()
4846*bb4ee6a4SAndroid Build Coastguard Worker };
4847*bb4ee6a4SAndroid Build Coastguard Worker let fs = PassthroughFs::new("tag", cfg).unwrap();
4848*bb4ee6a4SAndroid Build Coastguard Worker
4849*bb4ee6a4SAndroid Build Coastguard Worker let capable = FsOptions::ZERO_MESSAGE_OPEN | FsOptions::WRITEBACK_CACHE;
4850*bb4ee6a4SAndroid Build Coastguard Worker fs.init(capable).unwrap();
4851*bb4ee6a4SAndroid Build Coastguard Worker
4852*bb4ee6a4SAndroid Build Coastguard Worker let (entry, _, _) = atomic_open(
4853*bb4ee6a4SAndroid Build Coastguard Worker &fs,
4854*bb4ee6a4SAndroid Build Coastguard Worker &temp_dir.path().join("a.txt"),
4855*bb4ee6a4SAndroid Build Coastguard Worker 0o666,
4856*bb4ee6a4SAndroid Build Coastguard Worker (libc::O_RDWR | libc::O_CREAT | libc::O_APPEND) as u32,
4857*bb4ee6a4SAndroid Build Coastguard Worker 0,
4858*bb4ee6a4SAndroid Build Coastguard Worker None,
4859*bb4ee6a4SAndroid Build Coastguard Worker )
4860*bb4ee6a4SAndroid Build Coastguard Worker .expect("atomic_open");
4861*bb4ee6a4SAndroid Build Coastguard Worker assert_ne!(entry.inode, 0);
4862*bb4ee6a4SAndroid Build Coastguard Worker
4863*bb4ee6a4SAndroid Build Coastguard Worker let inodes = fs.inodes.lock();
4864*bb4ee6a4SAndroid Build Coastguard Worker let data = inodes.get(&entry.inode).unwrap();
4865*bb4ee6a4SAndroid Build Coastguard Worker let flags = data.file.lock().1;
4866*bb4ee6a4SAndroid Build Coastguard Worker if writeback {
4867*bb4ee6a4SAndroid Build Coastguard Worker // When writeback is enabled, O_APPEND must be handled by the guest kernel.
4868*bb4ee6a4SAndroid Build Coastguard Worker // So, it must be cleared.
4869*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(flags & libc::O_APPEND, 0);
4870*bb4ee6a4SAndroid Build Coastguard Worker } else {
4871*bb4ee6a4SAndroid Build Coastguard Worker // Without writeback cache, O_APPEND must not be cleared.
4872*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(flags & libc::O_APPEND, libc::O_APPEND);
4873*bb4ee6a4SAndroid Build Coastguard Worker }
4874*bb4ee6a4SAndroid Build Coastguard Worker }
4875*bb4ee6a4SAndroid Build Coastguard Worker
4876*bb4ee6a4SAndroid Build Coastguard Worker #[test]
test_atomic_open_create_o_append_no_writeback()4877*bb4ee6a4SAndroid Build Coastguard Worker fn test_atomic_open_create_o_append_no_writeback() {
4878*bb4ee6a4SAndroid Build Coastguard Worker atomic_open_create_o_append(false);
4879*bb4ee6a4SAndroid Build Coastguard Worker }
4880*bb4ee6a4SAndroid Build Coastguard Worker
4881*bb4ee6a4SAndroid Build Coastguard Worker #[test]
test_atomic_open_create_o_append_writeback()4882*bb4ee6a4SAndroid Build Coastguard Worker fn test_atomic_open_create_o_append_writeback() {
4883*bb4ee6a4SAndroid Build Coastguard Worker atomic_open_create_o_append(true);
4884*bb4ee6a4SAndroid Build Coastguard Worker }
4885*bb4ee6a4SAndroid Build Coastguard Worker }
4886