blob: 3561b8fa3c4b3c613780453cebb0f2ff5eca71ae [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
Victor Hsieh99782572022-01-05 15:38:33 -080030use anyhow::{anyhow, bail, Result};
Alan Stokese1b6e1c2021-10-01 12:44:49 +010031use log::error;
Victor Hsieh99782572022-01-05 15:38:33 -080032use protobuf::Message;
Victor Hsieh50d75ac2021-09-03 14:46:55 -070033use std::convert::TryInto;
Victor Hsieh99782572022-01-05 15:38:33 -080034use std::fs::File;
Victor Hsiehd18b9752021-11-09 16:03:34 -080035use std::path::{Path, PathBuf};
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080036use structopt::StructOpt;
37
38mod auth;
39mod common;
40mod crypto;
Victor Hsieh09e26262021-03-03 16:00:55 -080041mod file;
Victor Hsiehf7fc3d32021-11-22 10:20:33 -080042mod fsstat;
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080043mod fsverity;
44mod fusefs;
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080045
46use auth::FakeAuthenticator;
Victor Hsiehd18b9752021-11-09 16:03:34 -080047use file::{
Victor Hsieh35dfa1e2022-01-12 17:03:35 -080048 Attr, EagerChunkReader, InMemoryDir, RemoteDirEditor, RemoteFileEditor, RemoteFileReader,
49 RemoteMerkleTreeReader,
Victor Hsiehd18b9752021-11-09 16:03:34 -080050};
Victor Hsiehf7fc3d32021-11-22 10:20:33 -080051use fsstat::RemoteFsStatsReader;
Victor Hsieh35dfa1e2022-01-12 17:03:35 -080052use fsverity::{merkle_tree_size, VerifiedFileEditor, VerifiedFileReader};
Victor Hsieh99782572022-01-05 15:38:33 -080053use fsverity_digests_proto::fsverity_digests::FSVerityDigests;
Victor Hsieh4d6b9d42021-11-08 15:53:49 -080054use fusefs::{AuthFs, AuthFsEntry};
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080055
56#[derive(StructOpt)]
Victor Hsiehf01f3232020-12-11 13:31:31 -080057struct Args {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080058 /// Mount point of AuthFS.
59 #[structopt(parse(from_os_str))]
60 mount_point: PathBuf,
61
Victor Hsieh2445e332021-06-04 16:44:53 -070062 /// CID of the VM where the service runs.
63 #[structopt(long)]
Victor Hsieh1a8cd042021-09-03 16:29:45 -070064 cid: u32,
Victor Hsieh2445e332021-06-04 16:44:53 -070065
Victor Hsieh4cc3b792021-08-04 12:00:04 -070066 /// Extra options to FUSE
67 #[structopt(short = "o")]
68 extra_options: Option<String>,
69
Victor Hsieh09e26262021-03-03 16:00:55 -080070 /// A read-only remote file with integrity check. Can be multiple.
Victor Hsiehf01f3232020-12-11 13:31:31 -080071 ///
Victor Hsiehb3588ce2021-11-02 15:02:32 -070072 /// For example, `--remote-ro-file 5:/path/to/cert` tells the filesystem to associate the
73 /// 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 -080074 #[structopt(long, parse(try_from_str = parse_remote_ro_file_option))]
75 remote_ro_file: Vec<OptionRemoteRoFile>,
Victor Hsiehf01f3232020-12-11 13:31:31 -080076
Victor Hsieh09e26262021-03-03 16:00:55 -080077 /// A read-only remote file without integrity check. Can be multiple.
Victor Hsiehf01f3232020-12-11 13:31:31 -080078 ///
Victor Hsiehb3588ce2021-11-02 15:02:32 -070079 /// For example, `--remote-ro-file-unverified 5` tells the filesystem to associate the file
80 /// $MOUNTPOINT/5 with a remote FD 5.
81 #[structopt(long)]
82 remote_ro_file_unverified: Vec<i32>,
Victor Hsiehf01f3232020-12-11 13:31:31 -080083
Victor Hsieh6a47e7f2021-03-03 15:53:49 -080084 /// A new read-writable remote file with integrity check. Can be multiple.
85 ///
Victor Hsiehb3588ce2021-11-02 15:02:32 -070086 /// For example, `--remote-new-rw-file 5` tells the filesystem to associate the file
87 /// $MOUNTPOINT/5 with a remote FD 5.
88 #[structopt(long)]
89 remote_new_rw_file: Vec<i32>,
Victor Hsieh6a47e7f2021-03-03 15:53:49 -080090
Victor Hsiehd18b9752021-11-09 16:03:34 -080091 /// A read-only directory that represents a remote directory. The directory view is constructed
92 /// and finalized during the filesystem initialization based on the provided mapping file
93 /// (which is a serialized protobuf of android.security.fsverity.FSVerityDigests, which
94 /// essentially provides <file path, fs-verity digest> mappings of exported files). The mapping
95 /// file is supposed to come from a trusted location in order to provide a trusted view as well
96 /// as verified access of included files with their fs-verity digest. Not all files on the
97 /// remote host may be included in the mapping file, so the directory view may be partial. The
98 /// directory structure won't change throughout the filesystem lifetime.
99 ///
Victor Hsieh99782572022-01-05 15:38:33 -0800100 /// For example, `--remote-ro-dir 5:/path/to/mapping:prefix/` tells the filesystem to
Victor Hsiehd18b9752021-11-09 16:03:34 -0800101 /// construct a directory structure defined in the mapping file at $MOUNTPOINT/5, which may
Victor Hsieh99782572022-01-05 15:38:33 -0800102 /// include a file like /5/system/framework/framework.jar. "prefix/" tells the filesystem to
103 /// strip the path (e.g. "system/") from the mount point to match the expected location of the
Victor Hsiehd18b9752021-11-09 16:03:34 -0800104 /// remote FD (e.g. a directory FD of "/system" in the remote).
105 #[structopt(long, parse(try_from_str = parse_remote_new_ro_dir_option))]
106 remote_ro_dir: Vec<OptionRemoteRoDir>,
107
Victor Hsieh45636232021-10-15 17:52:51 -0700108 /// A new directory that is assumed empty in the backing filesystem. New files created in this
109 /// directory are integrity-protected in the same way as --remote-new-verified-file. Can be
110 /// multiple.
111 ///
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700112 /// For example, `--remote-new-rw-dir 5` tells the filesystem to associate $MOUNTPOINT/5
113 /// with a remote dir FD 5.
114 #[structopt(long)]
115 remote_new_rw_dir: Vec<i32>,
Victor Hsieh45636232021-10-15 17:52:51 -0700116
Victor Hsieh9d0ab622021-04-26 17:07:02 -0700117 /// Enable debugging features.
118 #[structopt(long)]
119 debug: bool,
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800120}
121
Victor Hsieh09e26262021-03-03 16:00:55 -0800122struct OptionRemoteRoFile {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800123 /// ID to refer to the remote file.
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700124 remote_fd: i32,
Victor Hsiehf01f3232020-12-11 13:31:31 -0800125
Victor Hsiehf01f3232020-12-11 13:31:31 -0800126 /// Certificate to verify the authenticity of the file's fs-verity signature.
127 /// TODO(170494765): Implement PKCS#7 signature verification.
128 _certificate_path: PathBuf,
129}
130
Victor Hsiehd18b9752021-11-09 16:03:34 -0800131struct OptionRemoteRoDir {
132 /// ID to refer to the remote dir.
133 remote_dir_fd: i32,
134
135 /// A mapping file that describes the expecting file/directory structure and integrity metadata
136 /// in the remote directory. The file contains serialized protobuf of
137 /// android.security.fsverity.FSVerityDigests.
Victor Hsiehd18b9752021-11-09 16:03:34 -0800138 mapping_file_path: PathBuf,
139
Victor Hsieh99782572022-01-05 15:38:33 -0800140 prefix: String,
Victor Hsiehd18b9752021-11-09 16:03:34 -0800141}
142
Victor Hsieh09e26262021-03-03 16:00:55 -0800143fn parse_remote_ro_file_option(option: &str) -> Result<OptionRemoteRoFile> {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800144 let strs: Vec<&str> = option.split(':').collect();
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700145 if strs.len() != 2 {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800146 bail!("Invalid option: {}", option);
147 }
Victor Hsieh09e26262021-03-03 16:00:55 -0800148 Ok(OptionRemoteRoFile {
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700149 remote_fd: strs[0].parse::<i32>()?,
150 _certificate_path: PathBuf::from(strs[1]),
Victor Hsieh45636232021-10-15 17:52:51 -0700151 })
152}
153
Victor Hsiehd18b9752021-11-09 16:03:34 -0800154fn parse_remote_new_ro_dir_option(option: &str) -> Result<OptionRemoteRoDir> {
155 let strs: Vec<&str> = option.split(':').collect();
156 if strs.len() != 3 {
157 bail!("Invalid option: {}", option);
158 }
159 Ok(OptionRemoteRoDir {
160 remote_dir_fd: strs[0].parse::<i32>().unwrap(),
161 mapping_file_path: PathBuf::from(strs[1]),
Victor Hsieh99782572022-01-05 15:38:33 -0800162 prefix: String::from(strs[2]),
Victor Hsiehd18b9752021-11-09 16:03:34 -0800163 })
164}
165
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700166fn new_remote_verified_file_entry(
Victor Hsieh2445e332021-06-04 16:44:53 -0700167 service: file::VirtFdService,
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700168 remote_fd: i32,
Victor Hsieh2445e332021-06-04 16:44:53 -0700169 file_size: u64,
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700170) -> Result<AuthFsEntry> {
Inseob Kimc0886c22021-12-13 17:41:24 +0900171 let signature = service.readFsveritySignature(remote_fd).ok();
Victor Hsiehf01f3232020-12-11 13:31:31 -0800172
Victor Hsiehf01f3232020-12-11 13:31:31 -0800173 let authenticator = FakeAuthenticator::always_succeed();
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700174 Ok(AuthFsEntry::VerifiedReadonly {
Victor Hsieh1bcf4112021-03-19 14:26:57 -0700175 reader: VerifiedFileReader::new(
Victor Hsiehf01f3232020-12-11 13:31:31 -0800176 &authenticator,
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700177 RemoteFileReader::new(service.clone(), remote_fd),
Victor Hsiehf01f3232020-12-11 13:31:31 -0800178 file_size,
Inseob Kimc0886c22021-12-13 17:41:24 +0900179 signature.as_deref(),
Victor Hsieh35dfa1e2022-01-12 17:03:35 -0800180 EagerChunkReader::new(
181 RemoteMerkleTreeReader::new(service.clone(), remote_fd),
182 merkle_tree_size(file_size),
183 )?,
Victor Hsiehf01f3232020-12-11 13:31:31 -0800184 )?,
185 file_size,
Victor Hsieh1bcf4112021-03-19 14:26:57 -0700186 })
Victor Hsiehf01f3232020-12-11 13:31:31 -0800187}
188
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700189fn new_remote_unverified_file_entry(
Victor Hsieh2445e332021-06-04 16:44:53 -0700190 service: file::VirtFdService,
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700191 remote_fd: i32,
Victor Hsieh2445e332021-06-04 16:44:53 -0700192 file_size: u64,
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700193) -> Result<AuthFsEntry> {
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700194 let reader = RemoteFileReader::new(service, remote_fd);
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700195 Ok(AuthFsEntry::UnverifiedReadonly { reader, file_size })
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800196}
197
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700198fn new_remote_new_verified_file_entry(
Victor Hsieh2445e332021-06-04 16:44:53 -0700199 service: file::VirtFdService,
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700200 remote_fd: i32,
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700201) -> Result<AuthFsEntry> {
Victor Hsiehf393a722021-12-08 13:04:27 -0800202 let remote_file = RemoteFileEditor::new(service.clone(), remote_fd);
203 Ok(AuthFsEntry::VerifiedNew {
204 editor: VerifiedFileEditor::new(remote_file),
205 attr: Attr::new_file(service, remote_fd),
206 })
Victor Hsieh6a47e7f2021-03-03 15:53:49 -0800207}
208
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700209fn new_remote_new_verified_dir_entry(
Victor Hsieh45636232021-10-15 17:52:51 -0700210 service: file::VirtFdService,
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700211 remote_fd: i32,
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700212) -> Result<AuthFsEntry> {
Victor Hsiehf393a722021-12-08 13:04:27 -0800213 let dir = RemoteDirEditor::new(service.clone(), remote_fd);
214 let attr = Attr::new_dir(service, remote_fd);
215 Ok(AuthFsEntry::VerifiedNewDirectory { dir, attr })
Victor Hsieh45636232021-10-15 17:52:51 -0700216}
217
Victor Hsiehf7fc3d32021-11-22 10:20:33 -0800218fn prepare_root_dir_entries(
219 service: file::VirtFdService,
220 authfs: &mut AuthFs,
221 args: &Args,
222) -> Result<()> {
Victor Hsieh88e50172021-10-15 13:27:13 -0700223 for config in &args.remote_ro_file {
Victor Hsieh4d6b9d42021-11-08 15:53:49 -0800224 authfs.add_entry_at_root_dir(
Victor Hsieh60c2f412021-11-03 13:02:19 -0700225 remote_fd_to_path_buf(config.remote_fd),
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700226 new_remote_verified_file_entry(
Victor Hsieh88e50172021-10-15 13:27:13 -0700227 service.clone(),
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700228 config.remote_fd,
229 service.getFileSize(config.remote_fd)?.try_into()?,
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800230 )?,
Victor Hsieh4d6b9d42021-11-08 15:53:49 -0800231 )?;
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800232 }
233
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700234 for remote_fd in &args.remote_ro_file_unverified {
235 let remote_fd = *remote_fd;
Victor Hsieh4d6b9d42021-11-08 15:53:49 -0800236 authfs.add_entry_at_root_dir(
Victor Hsieh60c2f412021-11-03 13:02:19 -0700237 remote_fd_to_path_buf(remote_fd),
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700238 new_remote_unverified_file_entry(
Victor Hsieh88e50172021-10-15 13:27:13 -0700239 service.clone(),
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700240 remote_fd,
241 service.getFileSize(remote_fd)?.try_into()?,
Victor Hsieh88e50172021-10-15 13:27:13 -0700242 )?,
Victor Hsieh4d6b9d42021-11-08 15:53:49 -0800243 )?;
Victor Hsieh88e50172021-10-15 13:27:13 -0700244 }
245
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700246 for remote_fd in &args.remote_new_rw_file {
247 let remote_fd = *remote_fd;
Victor Hsieh4d6b9d42021-11-08 15:53:49 -0800248 authfs.add_entry_at_root_dir(
Victor Hsieh60c2f412021-11-03 13:02:19 -0700249 remote_fd_to_path_buf(remote_fd),
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700250 new_remote_new_verified_file_entry(service.clone(), remote_fd)?,
Victor Hsieh4d6b9d42021-11-08 15:53:49 -0800251 )?;
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800252 }
253
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700254 for remote_fd in &args.remote_new_rw_dir {
255 let remote_fd = *remote_fd;
Victor Hsieh4d6b9d42021-11-08 15:53:49 -0800256 authfs.add_entry_at_root_dir(
Victor Hsieh60c2f412021-11-03 13:02:19 -0700257 remote_fd_to_path_buf(remote_fd),
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700258 new_remote_new_verified_dir_entry(service.clone(), remote_fd)?,
Victor Hsieh4d6b9d42021-11-08 15:53:49 -0800259 )?;
Victor Hsieh45636232021-10-15 17:52:51 -0700260 }
261
Victor Hsiehd18b9752021-11-09 16:03:34 -0800262 for config in &args.remote_ro_dir {
263 let dir_root_inode = authfs.add_entry_at_root_dir(
264 remote_fd_to_path_buf(config.remote_dir_fd),
265 AuthFsEntry::ReadonlyDirectory { dir: InMemoryDir::new() },
266 )?;
267
Victor Hsieh99782572022-01-05 15:38:33 -0800268 // Build the directory tree based on the mapping file.
269 let mut reader = File::open(&config.mapping_file_path)?;
270 let proto = FSVerityDigests::parse_from_reader(&mut reader)?;
271 for path_str in proto.digests.keys() {
Victor Hsiehd18b9752021-11-09 16:03:34 -0800272 let file_entry = {
Victor Hsieh99782572022-01-05 15:38:33 -0800273 let remote_path_str = path_str.strip_prefix(&config.prefix).ok_or_else(|| {
274 anyhow!("Expect path {} to match prefix {}", path_str, config.prefix)
275 })?;
Victor Hsiehd18b9752021-11-09 16:03:34 -0800276 // TODO(205883847): Not all files will be used. Open the remote file lazily.
Victor Hsiehd18b9752021-11-09 16:03:34 -0800277 let remote_file = RemoteFileReader::new_by_path(
278 service.clone(),
279 config.remote_dir_fd,
Victor Hsieh99782572022-01-05 15:38:33 -0800280 Path::new(remote_path_str),
Victor Hsiehd18b9752021-11-09 16:03:34 -0800281 )?;
282 let file_size = service.getFileSize(remote_file.get_remote_fd())?.try_into()?;
Victor Hsieh015bcb52021-11-17 17:28:01 -0800283 // TODO(206869687): Switch to VerifiedReadonly
Victor Hsiehd18b9752021-11-09 16:03:34 -0800284 AuthFsEntry::UnverifiedReadonly { reader: remote_file, file_size }
285 };
Victor Hsieh99782572022-01-05 15:38:33 -0800286 authfs.add_entry_at_ro_dir_by_path(dir_root_inode, Path::new(path_str), file_entry)?;
Victor Hsiehd18b9752021-11-09 16:03:34 -0800287 }
288 }
289
Victor Hsieh4d6b9d42021-11-08 15:53:49 -0800290 Ok(())
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800291}
292
Victor Hsieh60c2f412021-11-03 13:02:19 -0700293fn remote_fd_to_path_buf(fd: i32) -> PathBuf {
294 PathBuf::from(fd.to_string())
295}
296
Alan Stokese1b6e1c2021-10-01 12:44:49 +0100297fn try_main() -> Result<()> {
Victor Hsieh2442abc2021-11-17 13:25:02 -0800298 let args = Args::from_args_safe()?;
Victor Hsieh9d0ab622021-04-26 17:07:02 -0700299
300 let log_level = if args.debug { log::Level::Debug } else { log::Level::Info };
301 android_logger::init_once(
302 android_logger::Config::default().with_tag("authfs").with_min_level(log_level),
303 );
304
Victor Hsiehf7fc3d32021-11-22 10:20:33 -0800305 let service = file::get_rpc_binder_service(args.cid)?;
306 let mut authfs = AuthFs::new(RemoteFsStatsReader::new(service.clone()));
307 prepare_root_dir_entries(service, &mut authfs, &args)?;
308
Victor Hsieh79f296b2021-12-02 15:38:08 -0800309 fusefs::mount_and_enter_message_loop(authfs, &args.mount_point, &args.extra_options)?;
Victor Hsiehf01f3232020-12-11 13:31:31 -0800310 bail!("Unexpected exit after the handler loop")
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800311}
Alan Stokese1b6e1c2021-10-01 12:44:49 +0100312
313fn main() {
314 if let Err(e) = try_main() {
315 error!("failed with {:?}", e);
316 std::process::exit(1);
317 }
318}