blob: ecb0e68523bf8854314c2fbb9948af78b0208d0b [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
25//! source (e.g. local file or remote file server), verification method (e.g. certificate for
26//! fs-verity verification, or no verification if expected to mount over dm-verity), and file ID.
27//! Regardless of the actual file name, the exposed file names through AuthFS are currently integer,
28//! e.g. /mountpoint/42.
29
Andrew Walbrancc093862021-03-05 16:59:35 +000030use anyhow::{bail, Context, Result};
Alan Stokese1b6e1c2021-10-01 12:44:49 +010031use log::error;
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080032use std::collections::BTreeMap;
Victor Hsieh50d75ac2021-09-03 14:46:55 -070033use std::convert::TryInto;
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080034use std::fs::File;
35use std::io::Read;
Victor Hsieh6cf75b52021-04-01 12:45:49 -070036use std::path::{Path, PathBuf};
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080037use structopt::StructOpt;
38
39mod auth;
40mod common;
41mod crypto;
Victor Hsieh09e26262021-03-03 16:00:55 -080042mod file;
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080043mod fsverity;
44mod fusefs;
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080045
46use auth::FakeAuthenticator;
Victor Hsieh6a47e7f2021-03-03 15:53:49 -080047use file::{LocalFileReader, RemoteFileEditor, RemoteFileReader, RemoteMerkleTreeReader};
48use fsverity::{VerifiedFileEditor, VerifiedFileReader};
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080049use fusefs::{FileConfig, Inode};
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080050
51#[derive(StructOpt)]
Victor Hsiehf01f3232020-12-11 13:31:31 -080052struct Args {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080053 /// Mount point of AuthFS.
54 #[structopt(parse(from_os_str))]
55 mount_point: PathBuf,
56
Victor Hsieh2445e332021-06-04 16:44:53 -070057 /// CID of the VM where the service runs.
58 #[structopt(long)]
Victor Hsieh1a8cd042021-09-03 16:29:45 -070059 cid: u32,
Victor Hsieh2445e332021-06-04 16:44:53 -070060
Victor Hsieh4cc3b792021-08-04 12:00:04 -070061 /// Extra options to FUSE
62 #[structopt(short = "o")]
63 extra_options: Option<String>,
64
Victor Hsieh09e26262021-03-03 16:00:55 -080065 /// A read-only remote file with integrity check. Can be multiple.
Victor Hsiehf01f3232020-12-11 13:31:31 -080066 ///
Victor Hsieh50d75ac2021-09-03 14:46:55 -070067 /// For example, `--remote-verified-file 5:10:/path/to/cert` tells the filesystem to associate
68 /// entry 5 with a remote file 10, and need to be verified against the /path/to/cert.
Victor Hsieh09e26262021-03-03 16:00:55 -080069 #[structopt(long, parse(try_from_str = parse_remote_ro_file_option))]
70 remote_ro_file: Vec<OptionRemoteRoFile>,
Victor Hsiehf01f3232020-12-11 13:31:31 -080071
Victor Hsieh09e26262021-03-03 16:00:55 -080072 /// A read-only remote file without integrity check. Can be multiple.
Victor Hsiehf01f3232020-12-11 13:31:31 -080073 ///
Victor Hsieh50d75ac2021-09-03 14:46:55 -070074 /// For example, `--remote-unverified-file 5:10` tells the filesystem to associate entry 5
75 /// with a remote file 10.
Victor Hsieh09e26262021-03-03 16:00:55 -080076 #[structopt(long, parse(try_from_str = parse_remote_ro_file_unverified_option))]
77 remote_ro_file_unverified: Vec<OptionRemoteRoFileUnverified>,
Victor Hsiehf01f3232020-12-11 13:31:31 -080078
Victor Hsieh6a47e7f2021-03-03 15:53:49 -080079 /// A new read-writable remote file with integrity check. Can be multiple.
80 ///
81 /// For example, `--remote-new-verified-file 12:34` tells the filesystem to associate entry 12
82 /// with a remote file 34.
83 #[structopt(long, parse(try_from_str = parse_remote_new_rw_file_option))]
84 remote_new_rw_file: Vec<OptionRemoteRwFile>,
85
Victor Hsieh09e26262021-03-03 16:00:55 -080086 /// Debug only. A read-only local file with integrity check. Can be multiple.
87 #[structopt(long, parse(try_from_str = parse_local_file_ro_option))]
88 local_ro_file: Vec<OptionLocalFileRo>,
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080089
Victor Hsieh09e26262021-03-03 16:00:55 -080090 /// Debug only. A read-only local file without integrity check. Can be multiple.
91 #[structopt(long, parse(try_from_str = parse_local_ro_file_unverified_ro_option))]
92 local_ro_file_unverified: Vec<OptionLocalRoFileUnverified>,
Victor Hsieh9d0ab622021-04-26 17:07:02 -070093
94 /// Enable debugging features.
95 #[structopt(long)]
96 debug: bool,
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080097}
98
Victor Hsieh9ab13e52021-06-29 09:23:29 -070099impl Args {
100 fn has_remote_files(&self) -> bool {
101 !self.remote_ro_file.is_empty()
102 || !self.remote_ro_file_unverified.is_empty()
103 || !self.remote_new_rw_file.is_empty()
104 }
105}
106
Victor Hsieh09e26262021-03-03 16:00:55 -0800107struct OptionRemoteRoFile {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800108 ino: Inode,
109
110 /// ID to refer to the remote file.
111 remote_id: i32,
112
Victor Hsiehf01f3232020-12-11 13:31:31 -0800113 /// Certificate to verify the authenticity of the file's fs-verity signature.
114 /// TODO(170494765): Implement PKCS#7 signature verification.
115 _certificate_path: PathBuf,
116}
117
Victor Hsieh09e26262021-03-03 16:00:55 -0800118struct OptionRemoteRoFileUnverified {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800119 ino: Inode,
120
121 /// ID to refer to the remote file.
122 remote_id: i32,
Victor Hsiehf01f3232020-12-11 13:31:31 -0800123}
124
Victor Hsieh6a47e7f2021-03-03 15:53:49 -0800125struct OptionRemoteRwFile {
126 ino: Inode,
127
128 /// ID to refer to the remote file.
129 remote_id: i32,
130}
131
Victor Hsieh09e26262021-03-03 16:00:55 -0800132struct OptionLocalFileRo {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800133 ino: Inode,
Victor Hsiehf01f3232020-12-11 13:31:31 -0800134
135 /// Local path of the backing file.
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800136 file_path: PathBuf,
Victor Hsiehf01f3232020-12-11 13:31:31 -0800137
138 /// Local path of the backing file's fs-verity Merkle tree dump.
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800139 merkle_tree_dump_path: PathBuf,
Victor Hsiehf01f3232020-12-11 13:31:31 -0800140
141 /// Local path of fs-verity signature for the backing file.
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800142 signature_path: PathBuf,
Victor Hsiehf01f3232020-12-11 13:31:31 -0800143
144 /// Certificate to verify the authenticity of the file's fs-verity signature.
145 /// TODO(170494765): Implement PKCS#7 signature verification.
146 _certificate_path: PathBuf,
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800147}
148
Victor Hsieh09e26262021-03-03 16:00:55 -0800149struct OptionLocalRoFileUnverified {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800150 ino: Inode,
Victor Hsiehf01f3232020-12-11 13:31:31 -0800151
152 /// Local path of the backing file.
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800153 file_path: PathBuf,
154}
155
Victor Hsieh09e26262021-03-03 16:00:55 -0800156fn parse_remote_ro_file_option(option: &str) -> Result<OptionRemoteRoFile> {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800157 let strs: Vec<&str> = option.split(':').collect();
Victor Hsieh50d75ac2021-09-03 14:46:55 -0700158 if strs.len() != 3 {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800159 bail!("Invalid option: {}", option);
160 }
Victor Hsieh09e26262021-03-03 16:00:55 -0800161 Ok(OptionRemoteRoFile {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800162 ino: strs[0].parse::<Inode>()?,
163 remote_id: strs[1].parse::<i32>()?,
Victor Hsieh50d75ac2021-09-03 14:46:55 -0700164 _certificate_path: PathBuf::from(strs[2]),
Victor Hsiehf01f3232020-12-11 13:31:31 -0800165 })
166}
167
Victor Hsieh09e26262021-03-03 16:00:55 -0800168fn parse_remote_ro_file_unverified_option(option: &str) -> Result<OptionRemoteRoFileUnverified> {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800169 let strs: Vec<&str> = option.split(':').collect();
Victor Hsieh50d75ac2021-09-03 14:46:55 -0700170 if strs.len() != 2 {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800171 bail!("Invalid option: {}", option);
172 }
Victor Hsieh09e26262021-03-03 16:00:55 -0800173 Ok(OptionRemoteRoFileUnverified {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800174 ino: strs[0].parse::<Inode>()?,
175 remote_id: strs[1].parse::<i32>()?,
Victor Hsiehf01f3232020-12-11 13:31:31 -0800176 })
177}
178
Victor Hsieh6a47e7f2021-03-03 15:53:49 -0800179fn parse_remote_new_rw_file_option(option: &str) -> Result<OptionRemoteRwFile> {
180 let strs: Vec<&str> = option.split(':').collect();
181 if strs.len() != 2 {
182 bail!("Invalid option: {}", option);
183 }
184 Ok(OptionRemoteRwFile {
185 ino: strs[0].parse::<Inode>().unwrap(),
186 remote_id: strs[1].parse::<i32>().unwrap(),
187 })
188}
189
Victor Hsieh09e26262021-03-03 16:00:55 -0800190fn parse_local_file_ro_option(option: &str) -> Result<OptionLocalFileRo> {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800191 let strs: Vec<&str> = option.split(':').collect();
192 if strs.len() != 5 {
193 bail!("Invalid option: {}", option);
194 }
Victor Hsieh09e26262021-03-03 16:00:55 -0800195 Ok(OptionLocalFileRo {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800196 ino: strs[0].parse::<Inode>()?,
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800197 file_path: PathBuf::from(strs[1]),
198 merkle_tree_dump_path: PathBuf::from(strs[2]),
199 signature_path: PathBuf::from(strs[3]),
Victor Hsiehf01f3232020-12-11 13:31:31 -0800200 _certificate_path: PathBuf::from(strs[4]),
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800201 })
202}
203
Victor Hsieh09e26262021-03-03 16:00:55 -0800204fn parse_local_ro_file_unverified_ro_option(option: &str) -> Result<OptionLocalRoFileUnverified> {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800205 let strs: Vec<&str> = option.split(':').collect();
206 if strs.len() != 2 {
207 bail!("Invalid option: {}", option);
208 }
Victor Hsieh09e26262021-03-03 16:00:55 -0800209 Ok(OptionLocalRoFileUnverified {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800210 ino: strs[0].parse::<Inode>()?,
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800211 file_path: PathBuf::from(strs[1]),
212 })
213}
214
Victor Hsieh2445e332021-06-04 16:44:53 -0700215fn new_config_remote_verified_file(
216 service: file::VirtFdService,
217 remote_id: i32,
218 file_size: u64,
219) -> Result<FileConfig> {
Andrew Walbrancc093862021-03-05 16:59:35 +0000220 let signature = service.readFsveritySignature(remote_id).context("Failed to read signature")?;
Victor Hsiehf01f3232020-12-11 13:31:31 -0800221
Victor Hsiehf01f3232020-12-11 13:31:31 -0800222 let authenticator = FakeAuthenticator::always_succeed();
Chris Wailes68c39f82021-07-27 16:03:44 -0700223 Ok(FileConfig::RemoteVerifiedReadonly {
Victor Hsieh1bcf4112021-03-19 14:26:57 -0700224 reader: VerifiedFileReader::new(
Victor Hsiehf01f3232020-12-11 13:31:31 -0800225 &authenticator,
Victor Hsiehc3d45b12021-06-30 09:16:41 -0700226 RemoteFileReader::new(service.clone(), remote_id),
Victor Hsiehf01f3232020-12-11 13:31:31 -0800227 file_size,
228 signature,
Victor Hsiehc3d45b12021-06-30 09:16:41 -0700229 RemoteMerkleTreeReader::new(service.clone(), remote_id),
Victor Hsiehf01f3232020-12-11 13:31:31 -0800230 )?,
231 file_size,
Victor Hsieh1bcf4112021-03-19 14:26:57 -0700232 })
Victor Hsiehf01f3232020-12-11 13:31:31 -0800233}
234
Victor Hsieh2445e332021-06-04 16:44:53 -0700235fn new_config_remote_unverified_file(
236 service: file::VirtFdService,
237 remote_id: i32,
238 file_size: u64,
239) -> Result<FileConfig> {
Victor Hsiehc3d45b12021-06-30 09:16:41 -0700240 let reader = RemoteFileReader::new(service, remote_id);
Chris Wailes68c39f82021-07-27 16:03:44 -0700241 Ok(FileConfig::RemoteUnverifiedReadonly { reader, file_size })
Victor Hsiehf01f3232020-12-11 13:31:31 -0800242}
243
Victor Hsieh09e26262021-03-03 16:00:55 -0800244fn new_config_local_ro_file(
Victor Hsieh6cf75b52021-04-01 12:45:49 -0700245 protected_file: &Path,
246 merkle_tree_dump: &Path,
247 signature: &Path,
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800248) -> Result<FileConfig> {
249 let file = File::open(&protected_file)?;
250 let file_size = file.metadata()?.len();
Victor Hsieh09e26262021-03-03 16:00:55 -0800251 let file_reader = LocalFileReader::new(file)?;
252 let merkle_tree_reader = LocalFileReader::new(File::open(merkle_tree_dump)?)?;
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800253 let authenticator = FakeAuthenticator::always_succeed();
254 let mut sig = Vec::new();
255 let _ = File::open(signature)?.read_to_end(&mut sig)?;
Victor Hsieh1bcf4112021-03-19 14:26:57 -0700256 let reader =
Victor Hsieh09e26262021-03-03 16:00:55 -0800257 VerifiedFileReader::new(&authenticator, file_reader, file_size, sig, merkle_tree_reader)?;
Chris Wailes68c39f82021-07-27 16:03:44 -0700258 Ok(FileConfig::LocalVerifiedReadonly { reader, file_size })
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800259}
260
Victor Hsieh6cf75b52021-04-01 12:45:49 -0700261fn new_config_local_ro_file_unverified(file_path: &Path) -> Result<FileConfig> {
Victor Hsieh1bcf4112021-03-19 14:26:57 -0700262 let reader = LocalFileReader::new(File::open(file_path)?)?;
263 let file_size = reader.len();
Chris Wailes68c39f82021-07-27 16:03:44 -0700264 Ok(FileConfig::LocalUnverifiedReadonly { reader, file_size })
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800265}
266
Victor Hsieh2445e332021-06-04 16:44:53 -0700267fn new_config_remote_new_verified_file(
268 service: file::VirtFdService,
269 remote_id: i32,
270) -> Result<FileConfig> {
Victor Hsiehc3d45b12021-06-30 09:16:41 -0700271 let remote_file = RemoteFileEditor::new(service, remote_id);
Chris Wailes68c39f82021-07-27 16:03:44 -0700272 Ok(FileConfig::RemoteVerifiedNew { editor: VerifiedFileEditor::new(remote_file) })
Victor Hsieh6a47e7f2021-03-03 15:53:49 -0800273}
274
Victor Hsiehf01f3232020-12-11 13:31:31 -0800275fn prepare_file_pool(args: &Args) -> Result<BTreeMap<Inode, FileConfig>> {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800276 let mut file_pool = BTreeMap::new();
277
Victor Hsieh9ab13e52021-06-29 09:23:29 -0700278 if args.has_remote_files() {
Victor Hsieh1a8cd042021-09-03 16:29:45 -0700279 let service = file::get_rpc_binder_service(args.cid)?;
Victor Hsieh2445e332021-06-04 16:44:53 -0700280
Victor Hsieh9ab13e52021-06-29 09:23:29 -0700281 for config in &args.remote_ro_file {
282 file_pool.insert(
283 config.ino,
284 new_config_remote_verified_file(
285 service.clone(),
286 config.remote_id,
Victor Hsieh50d75ac2021-09-03 14:46:55 -0700287 service.getFileSize(config.remote_id)?.try_into()?,
Victor Hsieh9ab13e52021-06-29 09:23:29 -0700288 )?,
289 );
290 }
Victor Hsiehf01f3232020-12-11 13:31:31 -0800291
Victor Hsieh9ab13e52021-06-29 09:23:29 -0700292 for config in &args.remote_ro_file_unverified {
293 file_pool.insert(
294 config.ino,
295 new_config_remote_unverified_file(
296 service.clone(),
297 config.remote_id,
Victor Hsieh50d75ac2021-09-03 14:46:55 -0700298 service.getFileSize(config.remote_id)?.try_into()?,
Victor Hsieh9ab13e52021-06-29 09:23:29 -0700299 )?,
300 );
301 }
Victor Hsiehf01f3232020-12-11 13:31:31 -0800302
Victor Hsieh9ab13e52021-06-29 09:23:29 -0700303 for config in &args.remote_new_rw_file {
304 file_pool.insert(
305 config.ino,
306 new_config_remote_new_verified_file(service.clone(), config.remote_id)?,
307 );
308 }
Victor Hsieh6a47e7f2021-03-03 15:53:49 -0800309 }
310
Victor Hsieh09e26262021-03-03 16:00:55 -0800311 for config in &args.local_ro_file {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800312 file_pool.insert(
313 config.ino,
Victor Hsieh09e26262021-03-03 16:00:55 -0800314 new_config_local_ro_file(
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800315 &config.file_path,
316 &config.merkle_tree_dump_path,
317 &config.signature_path,
318 )?,
319 );
320 }
321
Victor Hsieh09e26262021-03-03 16:00:55 -0800322 for config in &args.local_ro_file_unverified {
323 file_pool.insert(config.ino, new_config_local_ro_file_unverified(&config.file_path)?);
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800324 }
325
326 Ok(file_pool)
327}
328
Alan Stokese1b6e1c2021-10-01 12:44:49 +0100329fn try_main() -> Result<()> {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800330 let args = Args::from_args();
Victor Hsieh9d0ab622021-04-26 17:07:02 -0700331
332 let log_level = if args.debug { log::Level::Debug } else { log::Level::Info };
333 android_logger::init_once(
334 android_logger::Config::default().with_tag("authfs").with_min_level(log_level),
335 );
336
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800337 let file_pool = prepare_file_pool(&args)?;
Victor Hsieh4cc3b792021-08-04 12:00:04 -0700338 fusefs::loop_forever(file_pool, &args.mount_point, &args.extra_options)?;
Victor Hsiehf01f3232020-12-11 13:31:31 -0800339 bail!("Unexpected exit after the handler loop")
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800340}
Alan Stokese1b6e1c2021-10-01 12:44:49 +0100341
342fn main() {
343 if let Err(e) = try_main() {
344 error!("failed with {:?}", e);
345 std::process::exit(1);
346 }
347}