blob: 547d15d22d320a94b2ff8caafdcf0e19fc65c8e6 [file] [log] [blame]
Victor Hsieh045f1e62021-08-03 12:04:34 -07001/*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17use anyhow::{bail, Context, Result};
18use log::{debug, error, warn};
19use nix::mount::{umount2, MntFlags};
20use nix::sys::statfs::{statfs, FsType};
21use shared_child::SharedChild;
22use std::ffi::{OsStr, OsString};
23use std::fs::{remove_dir, OpenOptions};
24use std::path::PathBuf;
25use std::process::Command;
26use std::thread::sleep;
27use std::time::{Duration, Instant};
28
Victor Hsieh015bcb52021-11-17 17:28:01 -080029use authfs_aidl_interface::aidl::com::android::virt::fs::AuthFsConfig::{
30 AuthFsConfig, InputDirFdAnnotation::InputDirFdAnnotation, InputFdAnnotation::InputFdAnnotation,
31 OutputDirFdAnnotation::OutputDirFdAnnotation, OutputFdAnnotation::OutputFdAnnotation,
Victor Hsieh045f1e62021-08-03 12:04:34 -070032};
Victor Hsieh015bcb52021-11-17 17:28:01 -080033use authfs_aidl_interface::aidl::com::android::virt::fs::IAuthFs::{BnAuthFs, IAuthFs};
Victor Hsieh045f1e62021-08-03 12:04:34 -070034use authfs_aidl_interface::binder::{
Andrew Walbrandcf9d582022-08-03 11:25:24 +000035 self, BinderFeatures, Interface, ParcelFileDescriptor, Status, Strong,
Victor Hsieh045f1e62021-08-03 12:04:34 -070036};
37
38const AUTHFS_BIN: &str = "/system/bin/authfs";
39const AUTHFS_SETUP_POLL_INTERVAL_MS: Duration = Duration::from_millis(50);
40const AUTHFS_SETUP_TIMEOUT_SEC: Duration = Duration::from_secs(10);
41const FUSE_SUPER_MAGIC: FsType = FsType(0x65735546);
42
43/// An `AuthFs` instance is supposed to be backed by an `authfs` process. When the lifetime of the
44/// instance is over, it should leave no trace on the system: the process should be terminated, the
45/// FUSE should be unmounted, and the mount directory should be deleted.
46pub struct AuthFs {
47 mountpoint: OsString,
48 process: SharedChild,
49}
50
51impl Interface for AuthFs {}
52
53impl IAuthFs for AuthFs {
54 fn openFile(
55 &self,
Victor Hsiehebb1d902021-08-06 13:00:18 -070056 remote_fd_name: i32,
Victor Hsieh045f1e62021-08-03 12:04:34 -070057 writable: bool,
58 ) -> binder::Result<ParcelFileDescriptor> {
59 let mut path = PathBuf::from(&self.mountpoint);
60 path.push(remote_fd_name.to_string());
61 let file = OpenOptions::new().read(true).write(writable).open(&path).map_err(|e| {
Andrew Walbrandcf9d582022-08-03 11:25:24 +000062 Status::new_service_specific_error_str(
63 -1,
64 Some(format!("failed to open {:?} on authfs: {}", &path, e)),
Victor Hsieh045f1e62021-08-03 12:04:34 -070065 )
66 })?;
67 Ok(ParcelFileDescriptor::new(file))
68 }
Victor Hsiehf9968692021-11-18 11:34:39 -080069
70 fn getMountPoint(&self) -> binder::Result<String> {
71 if let Some(s) = self.mountpoint.to_str() {
72 Ok(s.to_string())
73 } else {
Andrew Walbrandcf9d582022-08-03 11:25:24 +000074 Err(Status::new_service_specific_error_str(-1, Some("Bad string encoding")))
Victor Hsiehf9968692021-11-18 11:34:39 -080075 }
76 }
Victor Hsieh045f1e62021-08-03 12:04:34 -070077}
78
79impl AuthFs {
80 /// Mount an authfs at `mountpoint` with specified FD annotations.
81 pub fn mount_and_wait(
82 mountpoint: OsString,
83 config: &AuthFsConfig,
84 debuggable: bool,
85 ) -> Result<Strong<dyn IAuthFs>> {
86 let child = run_authfs(
87 &mountpoint,
88 &config.inputFdAnnotations,
89 &config.outputFdAnnotations,
Victor Hsieh015bcb52021-11-17 17:28:01 -080090 &config.inputDirFdAnnotations,
91 &config.outputDirFdAnnotations,
Victor Hsieh045f1e62021-08-03 12:04:34 -070092 debuggable,
93 )?;
Alan Stokese1b6e1c2021-10-01 12:44:49 +010094 wait_until_authfs_ready(&child, &mountpoint).map_err(|e| {
95 match child.wait() {
96 Ok(status) => debug!("Wait for authfs: {}", status),
97 Err(e) => warn!("Failed to wait for child: {}", e),
98 }
Victor Hsieh045f1e62021-08-03 12:04:34 -070099 e
100 })?;
101
102 let authfs = AuthFs { mountpoint, process: child };
103 Ok(BnAuthFs::new_binder(authfs, BinderFeatures::default()))
104 }
105}
106
107impl Drop for AuthFs {
108 /// On drop, try to erase all the traces for this authfs mount.
109 fn drop(&mut self) {
110 debug!("Dropping AuthFs instance at mountpoint {:?}", &self.mountpoint);
111 if let Err(e) = self.process.kill() {
112 error!("Failed to kill authfs: {}", e);
113 }
114 match self.process.wait() {
115 Ok(status) => debug!("authfs exit code: {}", status),
116 Err(e) => warn!("Failed to wait for authfs: {}", e),
117 }
118 // The client may still hold the file descriptors that refer to this filesystem. Use
119 // MNT_DETACH to detach the mountpoint, and automatically unmount when there is no more
120 // reference.
121 if let Err(e) = umount2(self.mountpoint.as_os_str(), MntFlags::MNT_DETACH) {
122 error!("Failed to umount authfs at {:?}: {}", &self.mountpoint, e)
123 }
124
125 if let Err(e) = remove_dir(&self.mountpoint) {
126 error!("Failed to clean up mount directory {:?}: {}", &self.mountpoint, e)
127 }
128 }
129}
130
131fn run_authfs(
132 mountpoint: &OsStr,
Victor Hsieh015bcb52021-11-17 17:28:01 -0800133 in_file_fds: &[InputFdAnnotation],
134 out_file_fds: &[OutputFdAnnotation],
135 in_dir_fds: &[InputDirFdAnnotation],
136 out_dir_fds: &[OutputDirFdAnnotation],
Victor Hsieh045f1e62021-08-03 12:04:34 -0700137 debuggable: bool,
138) -> Result<SharedChild> {
139 let mut args = vec![mountpoint.to_owned(), OsString::from("--cid=2")];
Victor Hsieh8bb67b62021-08-04 12:10:58 -0700140 args.push(OsString::from("-o"));
141 args.push(OsString::from("fscontext=u:object_r:authfs_fuse:s0"));
Victor Hsieh015bcb52021-11-17 17:28:01 -0800142 for conf in in_file_fds {
Victor Hsieh045f1e62021-08-03 12:04:34 -0700143 // TODO(b/185178698): Many input files need to be signed and verified.
144 // or can we use debug cert for now, which is better than nothing?
145 args.push(OsString::from("--remote-ro-file-unverified"));
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700146 args.push(OsString::from(conf.fd.to_string()));
Victor Hsieh045f1e62021-08-03 12:04:34 -0700147 }
Victor Hsieh015bcb52021-11-17 17:28:01 -0800148 for conf in out_file_fds {
Victor Hsieh045f1e62021-08-03 12:04:34 -0700149 args.push(OsString::from("--remote-new-rw-file"));
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700150 args.push(OsString::from(conf.fd.to_string()));
Victor Hsieh045f1e62021-08-03 12:04:34 -0700151 }
Victor Hsieh015bcb52021-11-17 17:28:01 -0800152 for conf in in_dir_fds {
153 args.push(OsString::from("--remote-ro-dir"));
Victor Hsieh015bcb52021-11-17 17:28:01 -0800154 args.push(OsString::from(format!("{}:{}:{}", conf.fd, conf.manifestPath, conf.prefix)));
155 }
156 for conf in out_dir_fds {
157 args.push(OsString::from("--remote-new-rw-dir"));
158 args.push(OsString::from(conf.fd.to_string()));
159 }
Victor Hsieh045f1e62021-08-03 12:04:34 -0700160 if debuggable {
161 args.push(OsString::from("--debug"));
162 }
163
164 let mut command = Command::new(AUTHFS_BIN);
165 command.args(&args);
Victor Hsieh015bcb52021-11-17 17:28:01 -0800166 debug!("Spawn authfs: {:?}", command);
Victor Hsieh045f1e62021-08-03 12:04:34 -0700167 SharedChild::spawn(&mut command).context("Spawn authfs")
168}
169
Alan Stokese1b6e1c2021-10-01 12:44:49 +0100170fn wait_until_authfs_ready(child: &SharedChild, mountpoint: &OsStr) -> Result<()> {
Victor Hsieh045f1e62021-08-03 12:04:34 -0700171 let start_time = Instant::now();
172 loop {
173 if is_fuse(mountpoint)? {
174 break;
175 }
Alan Stokese1b6e1c2021-10-01 12:44:49 +0100176 if let Some(exit_status) = child.try_wait()? {
177 // If the child has exited, we will never become ready.
178 bail!("Child has exited: {}", exit_status);
179 }
Victor Hsieh045f1e62021-08-03 12:04:34 -0700180 if start_time.elapsed() > AUTHFS_SETUP_TIMEOUT_SEC {
Alan Stokese1b6e1c2021-10-01 12:44:49 +0100181 let _ = child.kill();
Victor Hsieh045f1e62021-08-03 12:04:34 -0700182 bail!("Time out mounting authfs");
183 }
184 sleep(AUTHFS_SETUP_POLL_INTERVAL_MS);
185 }
186 Ok(())
187}
188
189fn is_fuse(path: &OsStr) -> Result<bool> {
190 Ok(statfs(path)?.filesystem_type() == FUSE_SUPER_MAGIC)
191}