blob: 421cc020005520f13c0090335f0a8cce5d842e80 [file] [log] [blame]
Victor Hsieh88ac6ca2020-11-13 15:20:24 -08001/*
2 * Copyright (C) 2020 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
17//! This crate implements AuthFS, a FUSE-based, non-generic filesystem where file access is
18//! authenticated. This filesystem assumes the underlying layer is not trusted, e.g. file may be
19//! provided by an untrusted host/VM, so that the content can't be simply trusted. However, with a
20//! public key from a trusted party, this filesystem can still verify a (read-only) file signed by
21//! the trusted party even if the host/VM as the blob provider is malicious. With the Merkle tree,
22//! each read of file block can be verified individually only when needed.
23//!
24//! AuthFS only serve files that are specifically configured. A file configuration may include the
Victor Hsieh88e50172021-10-15 13:27:13 -070025//! source (e.g. remote file server), verification method (e.g. certificate for fs-verity
26//! verification, or no verification if expected to mount over dm-verity), and file ID. Regardless
27//! of the actual file name, the exposed file names through AuthFS are currently integer, e.g.
28//! /mountpoint/42.
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080029
Andrew Walbrancc093862021-03-05 16:59:35 +000030use anyhow::{bail, Context, Result};
Alan Stokese1b6e1c2021-10-01 12:44:49 +010031use log::error;
Victor Hsieh50d75ac2021-09-03 14:46:55 -070032use std::convert::TryInto;
Victor Hsiehd18b9752021-11-09 16:03:34 -080033use std::path::{Path, PathBuf};
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080034use structopt::StructOpt;
35
36mod auth;
37mod common;
38mod crypto;
Victor Hsieh09e26262021-03-03 16:00:55 -080039mod file;
Victor Hsiehf7fc3d32021-11-22 10:20:33 -080040mod fsstat;
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080041mod fsverity;
42mod fusefs;
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080043
44use auth::FakeAuthenticator;
Victor Hsiehd18b9752021-11-09 16:03:34 -080045use file::{
Victor Hsiehf393a722021-12-08 13:04:27 -080046 Attr, InMemoryDir, RemoteDirEditor, RemoteFileEditor, RemoteFileReader, RemoteMerkleTreeReader,
Victor Hsiehd18b9752021-11-09 16:03:34 -080047};
Victor Hsiehf7fc3d32021-11-22 10:20:33 -080048use fsstat::RemoteFsStatsReader;
Victor Hsieh6a47e7f2021-03-03 15:53:49 -080049use fsverity::{VerifiedFileEditor, VerifiedFileReader};
Victor Hsieh4d6b9d42021-11-08 15:53:49 -080050use fusefs::{AuthFs, AuthFsEntry};
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080051
52#[derive(StructOpt)]
Victor Hsiehf01f3232020-12-11 13:31:31 -080053struct Args {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080054 /// Mount point of AuthFS.
55 #[structopt(parse(from_os_str))]
56 mount_point: PathBuf,
57
Victor Hsieh2445e332021-06-04 16:44:53 -070058 /// CID of the VM where the service runs.
59 #[structopt(long)]
Victor Hsieh1a8cd042021-09-03 16:29:45 -070060 cid: u32,
Victor Hsieh2445e332021-06-04 16:44:53 -070061
Victor Hsieh4cc3b792021-08-04 12:00:04 -070062 /// Extra options to FUSE
63 #[structopt(short = "o")]
64 extra_options: Option<String>,
65
Victor Hsieh09e26262021-03-03 16:00:55 -080066 /// A read-only remote file with integrity check. Can be multiple.
Victor Hsiehf01f3232020-12-11 13:31:31 -080067 ///
Victor Hsiehb3588ce2021-11-02 15:02:32 -070068 /// For example, `--remote-ro-file 5:/path/to/cert` tells the filesystem to associate the
69 /// file $MOUNTPOINT/5 with a remote FD 5, and need to be verified against the /path/to/cert.
Victor Hsieh09e26262021-03-03 16:00:55 -080070 #[structopt(long, parse(try_from_str = parse_remote_ro_file_option))]
71 remote_ro_file: Vec<OptionRemoteRoFile>,
Victor Hsiehf01f3232020-12-11 13:31:31 -080072
Victor Hsieh09e26262021-03-03 16:00:55 -080073 /// A read-only remote file without integrity check. Can be multiple.
Victor Hsiehf01f3232020-12-11 13:31:31 -080074 ///
Victor Hsiehb3588ce2021-11-02 15:02:32 -070075 /// For example, `--remote-ro-file-unverified 5` tells the filesystem to associate the file
76 /// $MOUNTPOINT/5 with a remote FD 5.
77 #[structopt(long)]
78 remote_ro_file_unverified: Vec<i32>,
Victor Hsiehf01f3232020-12-11 13:31:31 -080079
Victor Hsieh6a47e7f2021-03-03 15:53:49 -080080 /// A new read-writable remote file with integrity check. Can be multiple.
81 ///
Victor Hsiehb3588ce2021-11-02 15:02:32 -070082 /// For example, `--remote-new-rw-file 5` tells the filesystem to associate the file
83 /// $MOUNTPOINT/5 with a remote FD 5.
84 #[structopt(long)]
85 remote_new_rw_file: Vec<i32>,
Victor Hsieh6a47e7f2021-03-03 15:53:49 -080086
Victor Hsiehd18b9752021-11-09 16:03:34 -080087 /// A read-only directory that represents a remote directory. The directory view is constructed
88 /// and finalized during the filesystem initialization based on the provided mapping file
89 /// (which is a serialized protobuf of android.security.fsverity.FSVerityDigests, which
90 /// essentially provides <file path, fs-verity digest> mappings of exported files). The mapping
91 /// file is supposed to come from a trusted location in order to provide a trusted view as well
92 /// as verified access of included files with their fs-verity digest. Not all files on the
93 /// remote host may be included in the mapping file, so the directory view may be partial. The
94 /// directory structure won't change throughout the filesystem lifetime.
95 ///
96 /// For example, `--remote-ro-dir 5:/path/to/mapping:/prefix/` tells the filesystem to
97 /// construct a directory structure defined in the mapping file at $MOUNTPOINT/5, which may
98 /// include a file like /5/system/framework/framework.jar. "/prefix/" tells the filesystem to
99 /// strip the path (e.g. "/system/") from the mount point to match the expected location of the
100 /// remote FD (e.g. a directory FD of "/system" in the remote).
101 #[structopt(long, parse(try_from_str = parse_remote_new_ro_dir_option))]
102 remote_ro_dir: Vec<OptionRemoteRoDir>,
103
Victor Hsieh45636232021-10-15 17:52:51 -0700104 /// A new directory that is assumed empty in the backing filesystem. New files created in this
105 /// directory are integrity-protected in the same way as --remote-new-verified-file. Can be
106 /// multiple.
107 ///
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700108 /// For example, `--remote-new-rw-dir 5` tells the filesystem to associate $MOUNTPOINT/5
109 /// with a remote dir FD 5.
110 #[structopt(long)]
111 remote_new_rw_dir: Vec<i32>,
Victor Hsieh45636232021-10-15 17:52:51 -0700112
Victor Hsieh9d0ab622021-04-26 17:07:02 -0700113 /// Enable debugging features.
114 #[structopt(long)]
115 debug: bool,
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800116}
117
Victor Hsieh09e26262021-03-03 16:00:55 -0800118struct OptionRemoteRoFile {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800119 /// ID to refer to the remote file.
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700120 remote_fd: i32,
Victor Hsiehf01f3232020-12-11 13:31:31 -0800121
Victor Hsiehf01f3232020-12-11 13:31:31 -0800122 /// Certificate to verify the authenticity of the file's fs-verity signature.
123 /// TODO(170494765): Implement PKCS#7 signature verification.
124 _certificate_path: PathBuf,
125}
126
Victor Hsiehd18b9752021-11-09 16:03:34 -0800127struct OptionRemoteRoDir {
128 /// ID to refer to the remote dir.
129 remote_dir_fd: i32,
130
131 /// A mapping file that describes the expecting file/directory structure and integrity metadata
132 /// in the remote directory. The file contains serialized protobuf of
133 /// android.security.fsverity.FSVerityDigests.
Victor Hsieh015bcb52021-11-17 17:28:01 -0800134 /// TODO(206869687): Really use the file when it's generated.
Victor Hsiehd18b9752021-11-09 16:03:34 -0800135 #[allow(dead_code)]
136 mapping_file_path: PathBuf,
137
138 prefix: PathBuf,
139}
140
Victor Hsieh09e26262021-03-03 16:00:55 -0800141fn parse_remote_ro_file_option(option: &str) -> Result<OptionRemoteRoFile> {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800142 let strs: Vec<&str> = option.split(':').collect();
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700143 if strs.len() != 2 {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800144 bail!("Invalid option: {}", option);
145 }
Victor Hsieh09e26262021-03-03 16:00:55 -0800146 Ok(OptionRemoteRoFile {
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700147 remote_fd: strs[0].parse::<i32>()?,
148 _certificate_path: PathBuf::from(strs[1]),
Victor Hsieh45636232021-10-15 17:52:51 -0700149 })
150}
151
Victor Hsiehd18b9752021-11-09 16:03:34 -0800152fn parse_remote_new_ro_dir_option(option: &str) -> Result<OptionRemoteRoDir> {
153 let strs: Vec<&str> = option.split(':').collect();
154 if strs.len() != 3 {
155 bail!("Invalid option: {}", option);
156 }
157 Ok(OptionRemoteRoDir {
158 remote_dir_fd: strs[0].parse::<i32>().unwrap(),
159 mapping_file_path: PathBuf::from(strs[1]),
160 prefix: PathBuf::from(strs[2]),
161 })
162}
163
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700164fn new_remote_verified_file_entry(
Victor Hsieh2445e332021-06-04 16:44:53 -0700165 service: file::VirtFdService,
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700166 remote_fd: i32,
Victor Hsieh2445e332021-06-04 16:44:53 -0700167 file_size: u64,
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700168) -> Result<AuthFsEntry> {
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700169 let signature = service.readFsveritySignature(remote_fd).context("Failed to read signature")?;
Victor Hsiehf01f3232020-12-11 13:31:31 -0800170
Victor Hsiehf01f3232020-12-11 13:31:31 -0800171 let authenticator = FakeAuthenticator::always_succeed();
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700172 Ok(AuthFsEntry::VerifiedReadonly {
Victor Hsieh1bcf4112021-03-19 14:26:57 -0700173 reader: VerifiedFileReader::new(
Victor Hsiehf01f3232020-12-11 13:31:31 -0800174 &authenticator,
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700175 RemoteFileReader::new(service.clone(), remote_fd),
Victor Hsiehf01f3232020-12-11 13:31:31 -0800176 file_size,
177 signature,
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700178 RemoteMerkleTreeReader::new(service.clone(), remote_fd),
Victor Hsiehf01f3232020-12-11 13:31:31 -0800179 )?,
180 file_size,
Victor Hsieh1bcf4112021-03-19 14:26:57 -0700181 })
Victor Hsiehf01f3232020-12-11 13:31:31 -0800182}
183
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700184fn new_remote_unverified_file_entry(
Victor Hsieh2445e332021-06-04 16:44:53 -0700185 service: file::VirtFdService,
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700186 remote_fd: i32,
Victor Hsieh2445e332021-06-04 16:44:53 -0700187 file_size: u64,
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700188) -> Result<AuthFsEntry> {
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700189 let reader = RemoteFileReader::new(service, remote_fd);
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700190 Ok(AuthFsEntry::UnverifiedReadonly { reader, file_size })
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800191}
192
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700193fn new_remote_new_verified_file_entry(
Victor Hsieh2445e332021-06-04 16:44:53 -0700194 service: file::VirtFdService,
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700195 remote_fd: i32,
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700196) -> Result<AuthFsEntry> {
Victor Hsiehf393a722021-12-08 13:04:27 -0800197 let remote_file = RemoteFileEditor::new(service.clone(), remote_fd);
198 Ok(AuthFsEntry::VerifiedNew {
199 editor: VerifiedFileEditor::new(remote_file),
200 attr: Attr::new_file(service, remote_fd),
201 })
Victor Hsieh6a47e7f2021-03-03 15:53:49 -0800202}
203
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700204fn new_remote_new_verified_dir_entry(
Victor Hsieh45636232021-10-15 17:52:51 -0700205 service: file::VirtFdService,
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700206 remote_fd: i32,
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700207) -> Result<AuthFsEntry> {
Victor Hsiehf393a722021-12-08 13:04:27 -0800208 let dir = RemoteDirEditor::new(service.clone(), remote_fd);
209 let attr = Attr::new_dir(service, remote_fd);
210 Ok(AuthFsEntry::VerifiedNewDirectory { dir, attr })
Victor Hsieh45636232021-10-15 17:52:51 -0700211}
212
Victor Hsiehf7fc3d32021-11-22 10:20:33 -0800213fn prepare_root_dir_entries(
214 service: file::VirtFdService,
215 authfs: &mut AuthFs,
216 args: &Args,
217) -> Result<()> {
Victor Hsieh88e50172021-10-15 13:27:13 -0700218 for config in &args.remote_ro_file {
Victor Hsieh4d6b9d42021-11-08 15:53:49 -0800219 authfs.add_entry_at_root_dir(
Victor Hsieh60c2f412021-11-03 13:02:19 -0700220 remote_fd_to_path_buf(config.remote_fd),
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700221 new_remote_verified_file_entry(
Victor Hsieh88e50172021-10-15 13:27:13 -0700222 service.clone(),
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700223 config.remote_fd,
224 service.getFileSize(config.remote_fd)?.try_into()?,
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800225 )?,
Victor Hsieh4d6b9d42021-11-08 15:53:49 -0800226 )?;
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800227 }
228
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700229 for remote_fd in &args.remote_ro_file_unverified {
230 let remote_fd = *remote_fd;
Victor Hsieh4d6b9d42021-11-08 15:53:49 -0800231 authfs.add_entry_at_root_dir(
Victor Hsieh60c2f412021-11-03 13:02:19 -0700232 remote_fd_to_path_buf(remote_fd),
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700233 new_remote_unverified_file_entry(
Victor Hsieh88e50172021-10-15 13:27:13 -0700234 service.clone(),
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700235 remote_fd,
236 service.getFileSize(remote_fd)?.try_into()?,
Victor Hsieh88e50172021-10-15 13:27:13 -0700237 )?,
Victor Hsieh4d6b9d42021-11-08 15:53:49 -0800238 )?;
Victor Hsieh88e50172021-10-15 13:27:13 -0700239 }
240
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700241 for remote_fd in &args.remote_new_rw_file {
242 let remote_fd = *remote_fd;
Victor Hsieh4d6b9d42021-11-08 15:53:49 -0800243 authfs.add_entry_at_root_dir(
Victor Hsieh60c2f412021-11-03 13:02:19 -0700244 remote_fd_to_path_buf(remote_fd),
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700245 new_remote_new_verified_file_entry(service.clone(), remote_fd)?,
Victor Hsieh4d6b9d42021-11-08 15:53:49 -0800246 )?;
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800247 }
248
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700249 for remote_fd in &args.remote_new_rw_dir {
250 let remote_fd = *remote_fd;
Victor Hsieh4d6b9d42021-11-08 15:53:49 -0800251 authfs.add_entry_at_root_dir(
Victor Hsieh60c2f412021-11-03 13:02:19 -0700252 remote_fd_to_path_buf(remote_fd),
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700253 new_remote_new_verified_dir_entry(service.clone(), remote_fd)?,
Victor Hsieh4d6b9d42021-11-08 15:53:49 -0800254 )?;
Victor Hsieh45636232021-10-15 17:52:51 -0700255 }
256
Victor Hsiehd18b9752021-11-09 16:03:34 -0800257 for config in &args.remote_ro_dir {
258 let dir_root_inode = authfs.add_entry_at_root_dir(
259 remote_fd_to_path_buf(config.remote_dir_fd),
260 AuthFsEntry::ReadonlyDirectory { dir: InMemoryDir::new() },
261 )?;
262
Victor Hsieh015bcb52021-11-17 17:28:01 -0800263 // TODO(206869687): Read actual path from config.mapping_file_path when it's generated.
Victor Hsiehd18b9752021-11-09 16:03:34 -0800264 let paths = vec![
Victor Hsieh8032b182021-11-16 14:26:37 -0800265 Path::new("/system/framework/com.android.location.provider.jar"),
266 Path::new("/system/framework/ethernet-service.jar"),
267 Path::new("/system/framework/ext.jar"),
268 Path::new("/system/framework/framework-graphics.jar"),
Victor Hsiehd18b9752021-11-09 16:03:34 -0800269 Path::new("/system/framework/framework.jar"),
Victor Hsieh8032b182021-11-16 14:26:37 -0800270 Path::new("/system/framework/ims-common.jar"),
Victor Hsiehd18b9752021-11-09 16:03:34 -0800271 Path::new("/system/framework/services.jar"),
Victor Hsieh8032b182021-11-16 14:26:37 -0800272 Path::new("/system/framework/telephony-common.jar"),
273 Path::new("/system/framework/voip-common.jar"),
274 Path::new("/system/etc/boot-image.prof"),
275 Path::new("/system/etc/dirty-image-objects"),
Victor Hsiehd18b9752021-11-09 16:03:34 -0800276 ];
277
278 for path in &paths {
279 let file_entry = {
280 // TODO(205883847): Not all files will be used. Open the remote file lazily.
281 let related_path = path.strip_prefix(&config.prefix)?;
282 let remote_file = RemoteFileReader::new_by_path(
283 service.clone(),
284 config.remote_dir_fd,
285 related_path,
286 )?;
287 let file_size = service.getFileSize(remote_file.get_remote_fd())?.try_into()?;
Victor Hsieh015bcb52021-11-17 17:28:01 -0800288 // TODO(206869687): Switch to VerifiedReadonly
Victor Hsiehd18b9752021-11-09 16:03:34 -0800289 AuthFsEntry::UnverifiedReadonly { reader: remote_file, file_size }
290 };
291 authfs.add_entry_at_ro_dir_by_path(
292 dir_root_inode,
293 path.strip_prefix("/")?,
294 file_entry,
295 )?;
296 }
297 }
298
Victor Hsieh4d6b9d42021-11-08 15:53:49 -0800299 Ok(())
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800300}
301
Victor Hsieh60c2f412021-11-03 13:02:19 -0700302fn remote_fd_to_path_buf(fd: i32) -> PathBuf {
303 PathBuf::from(fd.to_string())
304}
305
Alan Stokese1b6e1c2021-10-01 12:44:49 +0100306fn try_main() -> Result<()> {
Victor Hsieh2442abc2021-11-17 13:25:02 -0800307 let args = Args::from_args_safe()?;
Victor Hsieh9d0ab622021-04-26 17:07:02 -0700308
309 let log_level = if args.debug { log::Level::Debug } else { log::Level::Info };
310 android_logger::init_once(
311 android_logger::Config::default().with_tag("authfs").with_min_level(log_level),
312 );
313
Victor Hsiehf7fc3d32021-11-22 10:20:33 -0800314 let service = file::get_rpc_binder_service(args.cid)?;
315 let mut authfs = AuthFs::new(RemoteFsStatsReader::new(service.clone()));
316 prepare_root_dir_entries(service, &mut authfs, &args)?;
317
Victor Hsieh79f296b2021-12-02 15:38:08 -0800318 fusefs::mount_and_enter_message_loop(authfs, &args.mount_point, &args.extra_options)?;
Victor Hsiehf01f3232020-12-11 13:31:31 -0800319 bail!("Unexpected exit after the handler loop")
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800320}
Alan Stokese1b6e1c2021-10-01 12:44:49 +0100321
322fn main() {
323 if let Err(e) = try_main() {
324 error!("failed with {:?}", e);
325 std::process::exit(1);
326 }
327}