xref: /aosp_15_r20/external/crosvm/e2e_tests/tests/fs.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2023 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 //! Testing virtio-fs.
6*bb4ee6a4SAndroid Build Coastguard Worker 
7*bb4ee6a4SAndroid Build Coastguard Worker #![cfg(any(target_os = "android", target_os = "linux"))]
8*bb4ee6a4SAndroid Build Coastguard Worker 
9*bb4ee6a4SAndroid Build Coastguard Worker use std::path::Path;
10*bb4ee6a4SAndroid Build Coastguard Worker 
11*bb4ee6a4SAndroid Build Coastguard Worker use fixture::vhost_user::CmdType;
12*bb4ee6a4SAndroid Build Coastguard Worker use fixture::vhost_user::Config as VuConfig;
13*bb4ee6a4SAndroid Build Coastguard Worker use fixture::vhost_user::VhostUserBackend;
14*bb4ee6a4SAndroid Build Coastguard Worker use fixture::vm::Config;
15*bb4ee6a4SAndroid Build Coastguard Worker use fixture::vm::TestVm;
16*bb4ee6a4SAndroid Build Coastguard Worker use tempfile::NamedTempFile;
17*bb4ee6a4SAndroid Build Coastguard Worker use tempfile::TempDir;
18*bb4ee6a4SAndroid Build Coastguard Worker 
19*bb4ee6a4SAndroid Build Coastguard Worker /// Tests file copy
20*bb4ee6a4SAndroid Build Coastguard Worker ///
21*bb4ee6a4SAndroid Build Coastguard Worker /// 1. Create `original.txt` on a temporal directory.
22*bb4ee6a4SAndroid Build Coastguard Worker /// 2. Start a VM with a virtiofs device for the temporal directory.
23*bb4ee6a4SAndroid Build Coastguard Worker /// 3. Copy `original.txt` to `new.txt` in the guest.
24*bb4ee6a4SAndroid Build Coastguard Worker /// 4. Check that `new.txt` is created in the host.
copy_file(mut vm: TestVm, tag: &str, dir: TempDir)25*bb4ee6a4SAndroid Build Coastguard Worker fn copy_file(mut vm: TestVm, tag: &str, dir: TempDir) {
26*bb4ee6a4SAndroid Build Coastguard Worker     const ORIGINAL_FILE_NAME: &str = "original.txt";
27*bb4ee6a4SAndroid Build Coastguard Worker     const NEW_FILE_NAME: &str = "new.txt";
28*bb4ee6a4SAndroid Build Coastguard Worker     const TEST_DATA: &str = "virtiofs works!";
29*bb4ee6a4SAndroid Build Coastguard Worker 
30*bb4ee6a4SAndroid Build Coastguard Worker     let orig_file = dir.path().join(ORIGINAL_FILE_NAME);
31*bb4ee6a4SAndroid Build Coastguard Worker 
32*bb4ee6a4SAndroid Build Coastguard Worker     std::fs::write(orig_file, TEST_DATA).unwrap();
33*bb4ee6a4SAndroid Build Coastguard Worker 
34*bb4ee6a4SAndroid Build Coastguard Worker     // TODO(b/269137600): Split this into multiple lines instead of connecting commands with `&&`.
35*bb4ee6a4SAndroid Build Coastguard Worker     vm.exec_in_guest(&format!(
36*bb4ee6a4SAndroid Build Coastguard Worker         "mount -t virtiofs {tag} /mnt && cp /mnt/{} /mnt/{} && sync",
37*bb4ee6a4SAndroid Build Coastguard Worker         ORIGINAL_FILE_NAME, NEW_FILE_NAME,
38*bb4ee6a4SAndroid Build Coastguard Worker     ))
39*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap();
40*bb4ee6a4SAndroid Build Coastguard Worker 
41*bb4ee6a4SAndroid Build Coastguard Worker     let new_file = dir.path().join(NEW_FILE_NAME);
42*bb4ee6a4SAndroid Build Coastguard Worker     let contents = std::fs::read(new_file).unwrap();
43*bb4ee6a4SAndroid Build Coastguard Worker     assert_eq!(TEST_DATA.as_bytes(), &contents);
44*bb4ee6a4SAndroid Build Coastguard Worker }
45*bb4ee6a4SAndroid Build Coastguard Worker 
46*bb4ee6a4SAndroid Build Coastguard Worker /// Tests mount/read/create/write
47*bb4ee6a4SAndroid Build Coastguard Worker /// 1. Create `read_file.txt` with test data in host's temporal directory.
48*bb4ee6a4SAndroid Build Coastguard Worker /// 2. Start a VM with a virtiofs device for the temporal directory.
49*bb4ee6a4SAndroid Build Coastguard Worker /// 3. Guest reads read_file.txt file & verify the content is test data
50*bb4ee6a4SAndroid Build Coastguard Worker /// 4. Guest creates a write_file.txt file in shared directory
51*bb4ee6a4SAndroid Build Coastguard Worker /// 5. Host reads file from host's temporal directory & verify content is test data
mount_rw(mut vm: TestVm, tag: &str, dir: TempDir)52*bb4ee6a4SAndroid Build Coastguard Worker fn mount_rw(mut vm: TestVm, tag: &str, dir: TempDir) {
53*bb4ee6a4SAndroid Build Coastguard Worker     const READ_FILE_NAME: &str = "read_test.txt";
54*bb4ee6a4SAndroid Build Coastguard Worker     const WRITE_FILE_NAME: &str = "write_test.txt";
55*bb4ee6a4SAndroid Build Coastguard Worker     const TEST_DATA: &str = "hello world";
56*bb4ee6a4SAndroid Build Coastguard Worker 
57*bb4ee6a4SAndroid Build Coastguard Worker     let read_test_file = dir.path().join(READ_FILE_NAME);
58*bb4ee6a4SAndroid Build Coastguard Worker     let write_test_file = dir.path().join(WRITE_FILE_NAME);
59*bb4ee6a4SAndroid Build Coastguard Worker     std::fs::write(read_test_file, TEST_DATA).unwrap();
60*bb4ee6a4SAndroid Build Coastguard Worker 
61*bb4ee6a4SAndroid Build Coastguard Worker     assert_eq!(
62*bb4ee6a4SAndroid Build Coastguard Worker         vm.exec_in_guest(&format!(
63*bb4ee6a4SAndroid Build Coastguard Worker             "mount -t virtiofs {tag} /mnt && cat /mnt/read_test.txt"
64*bb4ee6a4SAndroid Build Coastguard Worker         ))
65*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap()
66*bb4ee6a4SAndroid Build Coastguard Worker         .stdout
67*bb4ee6a4SAndroid Build Coastguard Worker         .trim(),
68*bb4ee6a4SAndroid Build Coastguard Worker         TEST_DATA
69*bb4ee6a4SAndroid Build Coastguard Worker     );
70*bb4ee6a4SAndroid Build Coastguard Worker 
71*bb4ee6a4SAndroid Build Coastguard Worker     const IN_FS_WRITE_FILE_PATH: &str = "/mnt/write_test.txt";
72*bb4ee6a4SAndroid Build Coastguard Worker     let _ = vm.exec_in_guest(&format!("echo -n {TEST_DATA} > {IN_FS_WRITE_FILE_PATH}"));
73*bb4ee6a4SAndroid Build Coastguard Worker     let read_contents = std::fs::read(write_test_file).unwrap();
74*bb4ee6a4SAndroid Build Coastguard Worker     assert_eq!(TEST_DATA.as_bytes(), &read_contents);
75*bb4ee6a4SAndroid Build Coastguard Worker }
76*bb4ee6a4SAndroid Build Coastguard Worker 
77*bb4ee6a4SAndroid Build Coastguard Worker #[test]
fs_copy_file()78*bb4ee6a4SAndroid Build Coastguard Worker fn fs_copy_file() {
79*bb4ee6a4SAndroid Build Coastguard Worker     let tag = "mtdtest";
80*bb4ee6a4SAndroid Build Coastguard Worker     let temp_dir = tempfile::tempdir().unwrap();
81*bb4ee6a4SAndroid Build Coastguard Worker 
82*bb4ee6a4SAndroid Build Coastguard Worker     let config = Config::new().extra_args(vec![
83*bb4ee6a4SAndroid Build Coastguard Worker         "--shared-dir".to_string(),
84*bb4ee6a4SAndroid Build Coastguard Worker         format!(
85*bb4ee6a4SAndroid Build Coastguard Worker             "{}:{tag}:type=fs:cache=auto",
86*bb4ee6a4SAndroid Build Coastguard Worker             temp_dir.path().to_str().unwrap()
87*bb4ee6a4SAndroid Build Coastguard Worker         ),
88*bb4ee6a4SAndroid Build Coastguard Worker     ]);
89*bb4ee6a4SAndroid Build Coastguard Worker 
90*bb4ee6a4SAndroid Build Coastguard Worker     let vm = TestVm::new(config).unwrap();
91*bb4ee6a4SAndroid Build Coastguard Worker     copy_file(vm, tag, temp_dir)
92*bb4ee6a4SAndroid Build Coastguard Worker }
93*bb4ee6a4SAndroid Build Coastguard Worker 
94*bb4ee6a4SAndroid Build Coastguard Worker #[test]
fs_mount_rw()95*bb4ee6a4SAndroid Build Coastguard Worker fn fs_mount_rw() {
96*bb4ee6a4SAndroid Build Coastguard Worker     let tag = "mtdtest";
97*bb4ee6a4SAndroid Build Coastguard Worker     let temp_dir = tempfile::tempdir().unwrap();
98*bb4ee6a4SAndroid Build Coastguard Worker 
99*bb4ee6a4SAndroid Build Coastguard Worker     let config = Config::new().extra_args(vec![
100*bb4ee6a4SAndroid Build Coastguard Worker         "--shared-dir".to_string(),
101*bb4ee6a4SAndroid Build Coastguard Worker         format!(
102*bb4ee6a4SAndroid Build Coastguard Worker             "{}:{tag}:type=fs:cache=auto",
103*bb4ee6a4SAndroid Build Coastguard Worker             temp_dir.path().to_str().unwrap()
104*bb4ee6a4SAndroid Build Coastguard Worker         ),
105*bb4ee6a4SAndroid Build Coastguard Worker     ]);
106*bb4ee6a4SAndroid Build Coastguard Worker 
107*bb4ee6a4SAndroid Build Coastguard Worker     let vm = TestVm::new(config).unwrap();
108*bb4ee6a4SAndroid Build Coastguard Worker     mount_rw(vm, tag, temp_dir)
109*bb4ee6a4SAndroid Build Coastguard Worker }
110*bb4ee6a4SAndroid Build Coastguard Worker 
111*bb4ee6a4SAndroid Build Coastguard Worker /// Tests file ownership seen by the VM.
112*bb4ee6a4SAndroid Build Coastguard Worker ///
113*bb4ee6a4SAndroid Build Coastguard Worker /// 1. Create `user_file.txt` owned by the current user of the host on a temporal directory.
114*bb4ee6a4SAndroid Build Coastguard Worker /// 2. Set virtiofs options: uidmap=<mapped-uid> <current-uid> 1, uid=<mapped-uid>.
115*bb4ee6a4SAndroid Build Coastguard Worker /// 3. Start a VM with a virtiofs device for the temporal directory.
116*bb4ee6a4SAndroid Build Coastguard Worker /// 4. Check that `user_file.txt`'s uid is <mapped-uid> in the VM.
117*bb4ee6a4SAndroid Build Coastguard Worker /// 5. Verify gid similarly.
118*bb4ee6a4SAndroid Build Coastguard Worker #[test]
file_ugid()119*bb4ee6a4SAndroid Build Coastguard Worker fn file_ugid() {
120*bb4ee6a4SAndroid Build Coastguard Worker     const FILE_NAME: &str = "user_file.txt";
121*bb4ee6a4SAndroid Build Coastguard Worker     let uid = base::geteuid();
122*bb4ee6a4SAndroid Build Coastguard Worker     let gid = base::getegid();
123*bb4ee6a4SAndroid Build Coastguard Worker     let mapped_uid: u32 = rand::random();
124*bb4ee6a4SAndroid Build Coastguard Worker     let mapped_gid: u32 = rand::random();
125*bb4ee6a4SAndroid Build Coastguard Worker     let uid_map: String = format!("{} {} 1", mapped_uid, uid);
126*bb4ee6a4SAndroid Build Coastguard Worker     let gid_map = format!("{} {} 1", mapped_gid, gid);
127*bb4ee6a4SAndroid Build Coastguard Worker 
128*bb4ee6a4SAndroid Build Coastguard Worker     let temp_dir = tempfile::tempdir().unwrap();
129*bb4ee6a4SAndroid Build Coastguard Worker     let orig_file = temp_dir.path().join(FILE_NAME);
130*bb4ee6a4SAndroid Build Coastguard Worker 
131*bb4ee6a4SAndroid Build Coastguard Worker     std::fs::write(orig_file, "").unwrap();
132*bb4ee6a4SAndroid Build Coastguard Worker 
133*bb4ee6a4SAndroid Build Coastguard Worker     let tag = "mtdtest";
134*bb4ee6a4SAndroid Build Coastguard Worker 
135*bb4ee6a4SAndroid Build Coastguard Worker     let config = Config::new().extra_args(vec![
136*bb4ee6a4SAndroid Build Coastguard Worker         "--shared-dir".to_string(),
137*bb4ee6a4SAndroid Build Coastguard Worker         format!(
138*bb4ee6a4SAndroid Build Coastguard Worker             "{}:{tag}:type=fs:uidmap={}:gidmap={}:uid={}:gid={}",
139*bb4ee6a4SAndroid Build Coastguard Worker             temp_dir.path().to_str().unwrap(),
140*bb4ee6a4SAndroid Build Coastguard Worker             uid_map,
141*bb4ee6a4SAndroid Build Coastguard Worker             gid_map,
142*bb4ee6a4SAndroid Build Coastguard Worker             mapped_uid,
143*bb4ee6a4SAndroid Build Coastguard Worker             mapped_gid
144*bb4ee6a4SAndroid Build Coastguard Worker         ),
145*bb4ee6a4SAndroid Build Coastguard Worker     ]);
146*bb4ee6a4SAndroid Build Coastguard Worker 
147*bb4ee6a4SAndroid Build Coastguard Worker     let mut vm = TestVm::new(config).unwrap();
148*bb4ee6a4SAndroid Build Coastguard Worker     vm.exec_in_guest(&format!("mount -t virtiofs {tag} /mnt"))
149*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap();
150*bb4ee6a4SAndroid Build Coastguard Worker     let output = vm
151*bb4ee6a4SAndroid Build Coastguard Worker         .exec_in_guest(&format!("stat /mnt/{}", FILE_NAME,))
152*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap();
153*bb4ee6a4SAndroid Build Coastguard Worker     // stat output example:
154*bb4ee6a4SAndroid Build Coastguard Worker     // File: /mnt/user_file.txt
155*bb4ee6a4SAndroid Build Coastguard Worker     // Size: 0                 Blocks: 0          IO Block: 4096   regular empty file
156*bb4ee6a4SAndroid Build Coastguard Worker     // Device: 0,11    Inode: 11666031    Links: 1
157*bb4ee6a4SAndroid Build Coastguard Worker     // Access: (0640/-rw-r-----)  Uid: (2350626183/ UNKNOWN)   Gid: (949179291/ UNKNOWN)
158*bb4ee6a4SAndroid Build Coastguard Worker     // Access: 2023-04-05 03:06:27.110144457 +0000
159*bb4ee6a4SAndroid Build Coastguard Worker     // Modify: 2023-04-05 03:06:27.110144457 +0000
160*bb4ee6a4SAndroid Build Coastguard Worker     // Change: 2023-04-05 03:06:27.110144457 +0000
161*bb4ee6a4SAndroid Build Coastguard Worker     assert!(output.stdout.contains(&format!("Uid: ({}/", mapped_uid)));
162*bb4ee6a4SAndroid Build Coastguard Worker     assert!(output.stdout.contains(&format!("Gid: ({}/", mapped_gid)));
163*bb4ee6a4SAndroid Build Coastguard Worker }
164*bb4ee6a4SAndroid Build Coastguard Worker 
create_vu_fs_config(socket: &Path, shared_dir: &Path, tag: &str) -> VuConfig165*bb4ee6a4SAndroid Build Coastguard Worker pub fn create_vu_fs_config(socket: &Path, shared_dir: &Path, tag: &str) -> VuConfig {
166*bb4ee6a4SAndroid Build Coastguard Worker     let uid = base::geteuid();
167*bb4ee6a4SAndroid Build Coastguard Worker     let gid = base::getegid();
168*bb4ee6a4SAndroid Build Coastguard Worker     let socket_path = socket.to_str().unwrap();
169*bb4ee6a4SAndroid Build Coastguard Worker     let shared_dir_path = shared_dir.to_str().unwrap();
170*bb4ee6a4SAndroid Build Coastguard Worker     println!("socket={socket_path}, tag={tag}, shared_dir={shared_dir_path}");
171*bb4ee6a4SAndroid Build Coastguard Worker     VuConfig::new(CmdType::Device, "vhost-user-fs").extra_args(vec![
172*bb4ee6a4SAndroid Build Coastguard Worker         "fs".to_string(),
173*bb4ee6a4SAndroid Build Coastguard Worker         format!("--socket-path={socket_path}"),
174*bb4ee6a4SAndroid Build Coastguard Worker         format!("--shared-dir={shared_dir_path}"),
175*bb4ee6a4SAndroid Build Coastguard Worker         format!("--tag={tag}"),
176*bb4ee6a4SAndroid Build Coastguard Worker         format!("--uid-map=0 {uid} 1"),
177*bb4ee6a4SAndroid Build Coastguard Worker         format!("--gid-map=0 {gid} 1"),
178*bb4ee6a4SAndroid Build Coastguard Worker     ])
179*bb4ee6a4SAndroid Build Coastguard Worker }
180*bb4ee6a4SAndroid Build Coastguard Worker 
181*bb4ee6a4SAndroid Build Coastguard Worker /// Tests vhost-user fs device copy file.
182*bb4ee6a4SAndroid Build Coastguard Worker #[test]
vhost_user_fs_copy_file()183*bb4ee6a4SAndroid Build Coastguard Worker fn vhost_user_fs_copy_file() {
184*bb4ee6a4SAndroid Build Coastguard Worker     let socket = NamedTempFile::new().unwrap();
185*bb4ee6a4SAndroid Build Coastguard Worker     let temp_dir = tempfile::tempdir().unwrap();
186*bb4ee6a4SAndroid Build Coastguard Worker 
187*bb4ee6a4SAndroid Build Coastguard Worker     let config = Config::new();
188*bb4ee6a4SAndroid Build Coastguard Worker     let tag = "mtdtest";
189*bb4ee6a4SAndroid Build Coastguard Worker 
190*bb4ee6a4SAndroid Build Coastguard Worker     let vu_config = create_vu_fs_config(socket.path(), temp_dir.path(), tag);
191*bb4ee6a4SAndroid Build Coastguard Worker     let _vu_device = VhostUserBackend::new(vu_config).unwrap();
192*bb4ee6a4SAndroid Build Coastguard Worker 
193*bb4ee6a4SAndroid Build Coastguard Worker     let config = config.with_vhost_user_fs(socket.path(), tag);
194*bb4ee6a4SAndroid Build Coastguard Worker     let vm = TestVm::new(config).unwrap();
195*bb4ee6a4SAndroid Build Coastguard Worker 
196*bb4ee6a4SAndroid Build Coastguard Worker     copy_file(vm, tag, temp_dir);
197*bb4ee6a4SAndroid Build Coastguard Worker }
198*bb4ee6a4SAndroid Build Coastguard Worker 
199*bb4ee6a4SAndroid Build Coastguard Worker /// Tests vhost-user fs device mount and read write.
200*bb4ee6a4SAndroid Build Coastguard Worker #[test]
vhost_user_fs_mount_rw()201*bb4ee6a4SAndroid Build Coastguard Worker fn vhost_user_fs_mount_rw() {
202*bb4ee6a4SAndroid Build Coastguard Worker     let socket = NamedTempFile::new().unwrap();
203*bb4ee6a4SAndroid Build Coastguard Worker     let temp_dir = tempfile::tempdir().unwrap();
204*bb4ee6a4SAndroid Build Coastguard Worker 
205*bb4ee6a4SAndroid Build Coastguard Worker     let config = Config::new();
206*bb4ee6a4SAndroid Build Coastguard Worker     let tag = "mtdtest";
207*bb4ee6a4SAndroid Build Coastguard Worker 
208*bb4ee6a4SAndroid Build Coastguard Worker     let vu_config = create_vu_fs_config(socket.path(), temp_dir.path(), tag);
209*bb4ee6a4SAndroid Build Coastguard Worker     let _vu_device = VhostUserBackend::new(vu_config).unwrap();
210*bb4ee6a4SAndroid Build Coastguard Worker 
211*bb4ee6a4SAndroid Build Coastguard Worker     let config = config.with_vhost_user_fs(socket.path(), tag);
212*bb4ee6a4SAndroid Build Coastguard Worker     let vm = TestVm::new(config).unwrap();
213*bb4ee6a4SAndroid Build Coastguard Worker 
214*bb4ee6a4SAndroid Build Coastguard Worker     mount_rw(vm, tag, temp_dir);
215*bb4ee6a4SAndroid Build Coastguard Worker }
216*bb4ee6a4SAndroid Build Coastguard Worker 
copy_file_validate_ugid_mapping( mut vm: TestVm, tag: &str, dir: TempDir, mapped_uid: u32, mapped_gid: u32, )217*bb4ee6a4SAndroid Build Coastguard Worker fn copy_file_validate_ugid_mapping(
218*bb4ee6a4SAndroid Build Coastguard Worker     mut vm: TestVm,
219*bb4ee6a4SAndroid Build Coastguard Worker     tag: &str,
220*bb4ee6a4SAndroid Build Coastguard Worker     dir: TempDir,
221*bb4ee6a4SAndroid Build Coastguard Worker     mapped_uid: u32,
222*bb4ee6a4SAndroid Build Coastguard Worker     mapped_gid: u32,
223*bb4ee6a4SAndroid Build Coastguard Worker ) {
224*bb4ee6a4SAndroid Build Coastguard Worker     use std::os::linux::fs::MetadataExt;
225*bb4ee6a4SAndroid Build Coastguard Worker     const ORIGINAL_FILE_NAME: &str = "original.txt";
226*bb4ee6a4SAndroid Build Coastguard Worker     const NEW_FILE_NAME: &str = "new.txt";
227*bb4ee6a4SAndroid Build Coastguard Worker     const TEST_DATA: &str = "Hello world!";
228*bb4ee6a4SAndroid Build Coastguard Worker 
229*bb4ee6a4SAndroid Build Coastguard Worker     let orig_file = dir.path().join(ORIGINAL_FILE_NAME);
230*bb4ee6a4SAndroid Build Coastguard Worker 
231*bb4ee6a4SAndroid Build Coastguard Worker     std::fs::write(orig_file, TEST_DATA).unwrap();
232*bb4ee6a4SAndroid Build Coastguard Worker 
233*bb4ee6a4SAndroid Build Coastguard Worker     vm.exec_in_guest(&format!(
234*bb4ee6a4SAndroid Build Coastguard Worker         "mount -t virtiofs {tag} /mnt && cp /mnt/{} /mnt/{} && sync",
235*bb4ee6a4SAndroid Build Coastguard Worker         ORIGINAL_FILE_NAME, NEW_FILE_NAME,
236*bb4ee6a4SAndroid Build Coastguard Worker     ))
237*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap();
238*bb4ee6a4SAndroid Build Coastguard Worker 
239*bb4ee6a4SAndroid Build Coastguard Worker     let output = vm
240*bb4ee6a4SAndroid Build Coastguard Worker         .exec_in_guest(&format!("stat /mnt/{}", ORIGINAL_FILE_NAME,))
241*bb4ee6a4SAndroid Build Coastguard Worker         .unwrap();
242*bb4ee6a4SAndroid Build Coastguard Worker 
243*bb4ee6a4SAndroid Build Coastguard Worker     assert!(output.stdout.contains(&format!("Uid: ({}/", mapped_uid)));
244*bb4ee6a4SAndroid Build Coastguard Worker     assert!(output.stdout.contains(&format!("Gid: ({}/", mapped_gid)));
245*bb4ee6a4SAndroid Build Coastguard Worker 
246*bb4ee6a4SAndroid Build Coastguard Worker     let new_file = dir.path().join(NEW_FILE_NAME);
247*bb4ee6a4SAndroid Build Coastguard Worker     let output_stat = std::fs::metadata(new_file.clone());
248*bb4ee6a4SAndroid Build Coastguard Worker 
249*bb4ee6a4SAndroid Build Coastguard Worker     assert_eq!(
250*bb4ee6a4SAndroid Build Coastguard Worker         output_stat
251*bb4ee6a4SAndroid Build Coastguard Worker             .as_ref()
252*bb4ee6a4SAndroid Build Coastguard Worker             .expect("stat of new_file failed")
253*bb4ee6a4SAndroid Build Coastguard Worker             .st_uid(),
254*bb4ee6a4SAndroid Build Coastguard Worker         base::geteuid()
255*bb4ee6a4SAndroid Build Coastguard Worker     );
256*bb4ee6a4SAndroid Build Coastguard Worker     assert_eq!(
257*bb4ee6a4SAndroid Build Coastguard Worker         output_stat
258*bb4ee6a4SAndroid Build Coastguard Worker             .as_ref()
259*bb4ee6a4SAndroid Build Coastguard Worker             .expect("stat of new_file failed")
260*bb4ee6a4SAndroid Build Coastguard Worker             .st_gid(),
261*bb4ee6a4SAndroid Build Coastguard Worker         base::getegid()
262*bb4ee6a4SAndroid Build Coastguard Worker     );
263*bb4ee6a4SAndroid Build Coastguard Worker 
264*bb4ee6a4SAndroid Build Coastguard Worker     let contents = std::fs::read(new_file).unwrap();
265*bb4ee6a4SAndroid Build Coastguard Worker     assert_eq!(TEST_DATA.as_bytes(), &contents);
266*bb4ee6a4SAndroid Build Coastguard Worker }
267*bb4ee6a4SAndroid Build Coastguard Worker 
create_ugid_map_config( socket: &Path, shared_dir: &Path, tag: &str, mapped_uid: u32, mapped_gid: u32, ) -> VuConfig268*bb4ee6a4SAndroid Build Coastguard Worker pub fn create_ugid_map_config(
269*bb4ee6a4SAndroid Build Coastguard Worker     socket: &Path,
270*bb4ee6a4SAndroid Build Coastguard Worker     shared_dir: &Path,
271*bb4ee6a4SAndroid Build Coastguard Worker     tag: &str,
272*bb4ee6a4SAndroid Build Coastguard Worker     mapped_uid: u32,
273*bb4ee6a4SAndroid Build Coastguard Worker     mapped_gid: u32,
274*bb4ee6a4SAndroid Build Coastguard Worker ) -> VuConfig {
275*bb4ee6a4SAndroid Build Coastguard Worker     let socket_path = socket.to_str().unwrap();
276*bb4ee6a4SAndroid Build Coastguard Worker     let shared_dir_path = shared_dir.to_str().unwrap();
277*bb4ee6a4SAndroid Build Coastguard Worker 
278*bb4ee6a4SAndroid Build Coastguard Worker     let uid = base::geteuid();
279*bb4ee6a4SAndroid Build Coastguard Worker     let gid = base::getegid();
280*bb4ee6a4SAndroid Build Coastguard Worker     let ugid_map_value = format!("{} {} {} {} 7 /", mapped_uid, mapped_gid, uid, gid,);
281*bb4ee6a4SAndroid Build Coastguard Worker 
282*bb4ee6a4SAndroid Build Coastguard Worker     let cfg_arg = format!("writeback=true,ugid_map='{}'", ugid_map_value);
283*bb4ee6a4SAndroid Build Coastguard Worker 
284*bb4ee6a4SAndroid Build Coastguard Worker     println!("socket={socket_path}, tag={tag}, shared_dir={shared_dir_path}");
285*bb4ee6a4SAndroid Build Coastguard Worker 
286*bb4ee6a4SAndroid Build Coastguard Worker     VuConfig::new(CmdType::Device, "vhost-user-fs").extra_args(vec![
287*bb4ee6a4SAndroid Build Coastguard Worker         "fs".to_string(),
288*bb4ee6a4SAndroid Build Coastguard Worker         format!("--socket-path={socket_path}"),
289*bb4ee6a4SAndroid Build Coastguard Worker         format!("--shared-dir={shared_dir_path}"),
290*bb4ee6a4SAndroid Build Coastguard Worker         format!("--tag={tag}"),
291*bb4ee6a4SAndroid Build Coastguard Worker         format!("--cfg={cfg_arg}"),
292*bb4ee6a4SAndroid Build Coastguard Worker         format!("--disable-sandbox"),
293*bb4ee6a4SAndroid Build Coastguard Worker         format!("--skip-pivot-root=true"),
294*bb4ee6a4SAndroid Build Coastguard Worker     ])
295*bb4ee6a4SAndroid Build Coastguard Worker }
296*bb4ee6a4SAndroid Build Coastguard Worker 
297*bb4ee6a4SAndroid Build Coastguard Worker /// Tests file copy with disabled sandbox
298*bb4ee6a4SAndroid Build Coastguard Worker ///
299*bb4ee6a4SAndroid Build Coastguard Worker /// 1. Create `original.txt` on a temporal directory.
300*bb4ee6a4SAndroid Build Coastguard Worker /// 2. Setup ugid_map for vhost-user-fs backend
301*bb4ee6a4SAndroid Build Coastguard Worker /// 3. Start a VM with a virtiofs device for the temporal directory.
302*bb4ee6a4SAndroid Build Coastguard Worker /// 4. Copy `original.txt` to `new.txt` in the guest.
303*bb4ee6a4SAndroid Build Coastguard Worker /// 5. Check that `new.txt` is created in the host.
304*bb4ee6a4SAndroid Build Coastguard Worker /// 6. Verify the UID/GID of the files both in the guest and the host.
305*bb4ee6a4SAndroid Build Coastguard Worker #[test]
vhost_user_fs_without_sandbox_and_pivot_root()306*bb4ee6a4SAndroid Build Coastguard Worker fn vhost_user_fs_without_sandbox_and_pivot_root() {
307*bb4ee6a4SAndroid Build Coastguard Worker     let socket = NamedTempFile::new().unwrap();
308*bb4ee6a4SAndroid Build Coastguard Worker     let temp_dir = tempfile::tempdir().unwrap();
309*bb4ee6a4SAndroid Build Coastguard Worker 
310*bb4ee6a4SAndroid Build Coastguard Worker     let config = Config::new();
311*bb4ee6a4SAndroid Build Coastguard Worker     let tag = "android";
312*bb4ee6a4SAndroid Build Coastguard Worker 
313*bb4ee6a4SAndroid Build Coastguard Worker     let mapped_uid = 123456;
314*bb4ee6a4SAndroid Build Coastguard Worker     let mapped_gid = 12345;
315*bb4ee6a4SAndroid Build Coastguard Worker     let vu_config =
316*bb4ee6a4SAndroid Build Coastguard Worker         create_ugid_map_config(socket.path(), temp_dir.path(), tag, mapped_uid, mapped_gid);
317*bb4ee6a4SAndroid Build Coastguard Worker 
318*bb4ee6a4SAndroid Build Coastguard Worker     let _vu_device = VhostUserBackend::new(vu_config).unwrap();
319*bb4ee6a4SAndroid Build Coastguard Worker 
320*bb4ee6a4SAndroid Build Coastguard Worker     let config = config.with_vhost_user_fs(socket.path(), tag);
321*bb4ee6a4SAndroid Build Coastguard Worker     let vm = TestVm::new(config).unwrap();
322*bb4ee6a4SAndroid Build Coastguard Worker 
323*bb4ee6a4SAndroid Build Coastguard Worker     copy_file_validate_ugid_mapping(vm, tag, temp_dir, mapped_uid, mapped_gid);
324*bb4ee6a4SAndroid Build Coastguard Worker }
325