blob: 9d36c3febffa31752dbaa2c728a2a027ed7a4283 [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};
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080031use std::collections::BTreeMap;
32use std::fs::File;
33use std::io::Read;
Victor Hsieh6cf75b52021-04-01 12:45:49 -070034use std::path::{Path, PathBuf};
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080035use structopt::StructOpt;
36
37mod auth;
38mod common;
39mod crypto;
Victor Hsieh09e26262021-03-03 16:00:55 -080040mod file;
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080041mod fsverity;
42mod fusefs;
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080043
44use auth::FakeAuthenticator;
Victor Hsieh6a47e7f2021-03-03 15:53:49 -080045use file::{LocalFileReader, RemoteFileEditor, RemoteFileReader, RemoteMerkleTreeReader};
46use fsverity::{VerifiedFileEditor, VerifiedFileReader};
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080047use fusefs::{FileConfig, Inode};
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080048
49#[derive(StructOpt)]
Victor Hsiehf01f3232020-12-11 13:31:31 -080050struct Args {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080051 /// Mount point of AuthFS.
52 #[structopt(parse(from_os_str))]
53 mount_point: PathBuf,
54
Victor Hsieh2445e332021-06-04 16:44:53 -070055 /// CID of the VM where the service runs.
56 #[structopt(long)]
57 cid: Option<u32>,
58
Victor Hsieh09e26262021-03-03 16:00:55 -080059 /// A read-only remote file with integrity check. Can be multiple.
Victor Hsiehf01f3232020-12-11 13:31:31 -080060 ///
61 /// For example, `--remote-verified-file 5:10:1234:/path/to/cert` tells the filesystem to
62 /// associate entry 5 with a remote file 10 of size 1234 bytes, and need to be verified against
63 /// the /path/to/cert.
Victor Hsieh09e26262021-03-03 16:00:55 -080064 #[structopt(long, parse(try_from_str = parse_remote_ro_file_option))]
65 remote_ro_file: Vec<OptionRemoteRoFile>,
Victor Hsiehf01f3232020-12-11 13:31:31 -080066
Victor Hsieh09e26262021-03-03 16:00:55 -080067 /// A read-only remote file without integrity check. Can be multiple.
Victor Hsiehf01f3232020-12-11 13:31:31 -080068 ///
69 /// For example, `--remote-unverified-file 5:10:1234` tells the filesystem to associate entry 5
70 /// with a remote file 10 of size 1234 bytes.
Victor Hsieh09e26262021-03-03 16:00:55 -080071 #[structopt(long, parse(try_from_str = parse_remote_ro_file_unverified_option))]
72 remote_ro_file_unverified: Vec<OptionRemoteRoFileUnverified>,
Victor Hsiehf01f3232020-12-11 13:31:31 -080073
Victor Hsieh6a47e7f2021-03-03 15:53:49 -080074 /// A new read-writable remote file with integrity check. Can be multiple.
75 ///
76 /// For example, `--remote-new-verified-file 12:34` tells the filesystem to associate entry 12
77 /// with a remote file 34.
78 #[structopt(long, parse(try_from_str = parse_remote_new_rw_file_option))]
79 remote_new_rw_file: Vec<OptionRemoteRwFile>,
80
Victor Hsieh09e26262021-03-03 16:00:55 -080081 /// Debug only. A read-only local file with integrity check. Can be multiple.
82 #[structopt(long, parse(try_from_str = parse_local_file_ro_option))]
83 local_ro_file: Vec<OptionLocalFileRo>,
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080084
Victor Hsieh09e26262021-03-03 16:00:55 -080085 /// Debug only. A read-only local file without integrity check. Can be multiple.
86 #[structopt(long, parse(try_from_str = parse_local_ro_file_unverified_ro_option))]
87 local_ro_file_unverified: Vec<OptionLocalRoFileUnverified>,
Victor Hsieh9d0ab622021-04-26 17:07:02 -070088
89 /// Enable debugging features.
90 #[structopt(long)]
91 debug: bool,
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080092}
93
Victor Hsieh9ab13e52021-06-29 09:23:29 -070094impl Args {
95 fn has_remote_files(&self) -> bool {
96 !self.remote_ro_file.is_empty()
97 || !self.remote_ro_file_unverified.is_empty()
98 || !self.remote_new_rw_file.is_empty()
99 }
100}
101
Victor Hsieh09e26262021-03-03 16:00:55 -0800102struct OptionRemoteRoFile {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800103 ino: Inode,
104
105 /// ID to refer to the remote file.
106 remote_id: i32,
107
108 /// Expected size of the remote file. Necessary for signature check and Merkle tree
109 /// verification.
110 file_size: u64,
111
112 /// Certificate to verify the authenticity of the file's fs-verity signature.
113 /// TODO(170494765): Implement PKCS#7 signature verification.
114 _certificate_path: PathBuf,
115}
116
Victor Hsieh09e26262021-03-03 16:00:55 -0800117struct OptionRemoteRoFileUnverified {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800118 ino: Inode,
119
120 /// ID to refer to the remote file.
121 remote_id: i32,
122
123 /// Expected size of the remote file.
124 file_size: u64,
125}
126
Victor Hsieh6a47e7f2021-03-03 15:53:49 -0800127struct OptionRemoteRwFile {
128 ino: Inode,
129
130 /// ID to refer to the remote file.
131 remote_id: i32,
132}
133
Victor Hsieh09e26262021-03-03 16:00:55 -0800134struct OptionLocalFileRo {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800135 ino: Inode,
Victor Hsiehf01f3232020-12-11 13:31:31 -0800136
137 /// Local path of the backing file.
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800138 file_path: PathBuf,
Victor Hsiehf01f3232020-12-11 13:31:31 -0800139
140 /// Local path of the backing file's fs-verity Merkle tree dump.
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800141 merkle_tree_dump_path: PathBuf,
Victor Hsiehf01f3232020-12-11 13:31:31 -0800142
143 /// Local path of fs-verity signature for the backing file.
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800144 signature_path: PathBuf,
Victor Hsiehf01f3232020-12-11 13:31:31 -0800145
146 /// Certificate to verify the authenticity of the file's fs-verity signature.
147 /// TODO(170494765): Implement PKCS#7 signature verification.
148 _certificate_path: PathBuf,
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800149}
150
Victor Hsieh09e26262021-03-03 16:00:55 -0800151struct OptionLocalRoFileUnverified {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800152 ino: Inode,
Victor Hsiehf01f3232020-12-11 13:31:31 -0800153
154 /// Local path of the backing file.
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800155 file_path: PathBuf,
156}
157
Victor Hsieh09e26262021-03-03 16:00:55 -0800158fn parse_remote_ro_file_option(option: &str) -> Result<OptionRemoteRoFile> {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800159 let strs: Vec<&str> = option.split(':').collect();
160 if strs.len() != 4 {
161 bail!("Invalid option: {}", option);
162 }
Victor Hsieh09e26262021-03-03 16:00:55 -0800163 Ok(OptionRemoteRoFile {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800164 ino: strs[0].parse::<Inode>()?,
165 remote_id: strs[1].parse::<i32>()?,
166 file_size: strs[2].parse::<u64>()?,
167 _certificate_path: PathBuf::from(strs[3]),
168 })
169}
170
Victor Hsieh09e26262021-03-03 16:00:55 -0800171fn parse_remote_ro_file_unverified_option(option: &str) -> Result<OptionRemoteRoFileUnverified> {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800172 let strs: Vec<&str> = option.split(':').collect();
173 if strs.len() != 3 {
174 bail!("Invalid option: {}", option);
175 }
Victor Hsieh09e26262021-03-03 16:00:55 -0800176 Ok(OptionRemoteRoFileUnverified {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800177 ino: strs[0].parse::<Inode>()?,
178 remote_id: strs[1].parse::<i32>()?,
179 file_size: strs[2].parse::<u64>()?,
180 })
181}
182
Victor Hsieh6a47e7f2021-03-03 15:53:49 -0800183fn parse_remote_new_rw_file_option(option: &str) -> Result<OptionRemoteRwFile> {
184 let strs: Vec<&str> = option.split(':').collect();
185 if strs.len() != 2 {
186 bail!("Invalid option: {}", option);
187 }
188 Ok(OptionRemoteRwFile {
189 ino: strs[0].parse::<Inode>().unwrap(),
190 remote_id: strs[1].parse::<i32>().unwrap(),
191 })
192}
193
Victor Hsieh09e26262021-03-03 16:00:55 -0800194fn parse_local_file_ro_option(option: &str) -> Result<OptionLocalFileRo> {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800195 let strs: Vec<&str> = option.split(':').collect();
196 if strs.len() != 5 {
197 bail!("Invalid option: {}", option);
198 }
Victor Hsieh09e26262021-03-03 16:00:55 -0800199 Ok(OptionLocalFileRo {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800200 ino: strs[0].parse::<Inode>()?,
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800201 file_path: PathBuf::from(strs[1]),
202 merkle_tree_dump_path: PathBuf::from(strs[2]),
203 signature_path: PathBuf::from(strs[3]),
Victor Hsiehf01f3232020-12-11 13:31:31 -0800204 _certificate_path: PathBuf::from(strs[4]),
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800205 })
206}
207
Victor Hsieh09e26262021-03-03 16:00:55 -0800208fn parse_local_ro_file_unverified_ro_option(option: &str) -> Result<OptionLocalRoFileUnverified> {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800209 let strs: Vec<&str> = option.split(':').collect();
210 if strs.len() != 2 {
211 bail!("Invalid option: {}", option);
212 }
Victor Hsieh09e26262021-03-03 16:00:55 -0800213 Ok(OptionLocalRoFileUnverified {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800214 ino: strs[0].parse::<Inode>()?,
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800215 file_path: PathBuf::from(strs[1]),
216 })
217}
218
Victor Hsieh2445e332021-06-04 16:44:53 -0700219fn new_config_remote_verified_file(
220 service: file::VirtFdService,
221 remote_id: i32,
222 file_size: u64,
223) -> Result<FileConfig> {
Andrew Walbrancc093862021-03-05 16:59:35 +0000224 let signature = service.readFsveritySignature(remote_id).context("Failed to read signature")?;
Victor Hsiehf01f3232020-12-11 13:31:31 -0800225
Victor Hsiehf01f3232020-12-11 13:31:31 -0800226 let authenticator = FakeAuthenticator::always_succeed();
Victor Hsieh1bcf4112021-03-19 14:26:57 -0700227 Ok(FileConfig::RemoteVerifiedReadonlyFile {
228 reader: VerifiedFileReader::new(
Victor Hsiehf01f3232020-12-11 13:31:31 -0800229 &authenticator,
Victor Hsiehc3d45b12021-06-30 09:16:41 -0700230 RemoteFileReader::new(service.clone(), remote_id),
Victor Hsiehf01f3232020-12-11 13:31:31 -0800231 file_size,
232 signature,
Victor Hsiehc3d45b12021-06-30 09:16:41 -0700233 RemoteMerkleTreeReader::new(service.clone(), remote_id),
Victor Hsiehf01f3232020-12-11 13:31:31 -0800234 )?,
235 file_size,
Victor Hsieh1bcf4112021-03-19 14:26:57 -0700236 })
Victor Hsiehf01f3232020-12-11 13:31:31 -0800237}
238
Victor Hsieh2445e332021-06-04 16:44:53 -0700239fn new_config_remote_unverified_file(
240 service: file::VirtFdService,
241 remote_id: i32,
242 file_size: u64,
243) -> Result<FileConfig> {
Victor Hsiehc3d45b12021-06-30 09:16:41 -0700244 let reader = RemoteFileReader::new(service, remote_id);
Victor Hsieh1bcf4112021-03-19 14:26:57 -0700245 Ok(FileConfig::RemoteUnverifiedReadonlyFile { reader, file_size })
Victor Hsiehf01f3232020-12-11 13:31:31 -0800246}
247
Victor Hsieh09e26262021-03-03 16:00:55 -0800248fn new_config_local_ro_file(
Victor Hsieh6cf75b52021-04-01 12:45:49 -0700249 protected_file: &Path,
250 merkle_tree_dump: &Path,
251 signature: &Path,
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800252) -> Result<FileConfig> {
253 let file = File::open(&protected_file)?;
254 let file_size = file.metadata()?.len();
Victor Hsieh09e26262021-03-03 16:00:55 -0800255 let file_reader = LocalFileReader::new(file)?;
256 let merkle_tree_reader = LocalFileReader::new(File::open(merkle_tree_dump)?)?;
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800257 let authenticator = FakeAuthenticator::always_succeed();
258 let mut sig = Vec::new();
259 let _ = File::open(signature)?.read_to_end(&mut sig)?;
Victor Hsieh1bcf4112021-03-19 14:26:57 -0700260 let reader =
Victor Hsieh09e26262021-03-03 16:00:55 -0800261 VerifiedFileReader::new(&authenticator, file_reader, file_size, sig, merkle_tree_reader)?;
Victor Hsieh1bcf4112021-03-19 14:26:57 -0700262 Ok(FileConfig::LocalVerifiedReadonlyFile { reader, file_size })
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800263}
264
Victor Hsieh6cf75b52021-04-01 12:45:49 -0700265fn new_config_local_ro_file_unverified(file_path: &Path) -> Result<FileConfig> {
Victor Hsieh1bcf4112021-03-19 14:26:57 -0700266 let reader = LocalFileReader::new(File::open(file_path)?)?;
267 let file_size = reader.len();
268 Ok(FileConfig::LocalUnverifiedReadonlyFile { reader, file_size })
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800269}
270
Victor Hsieh2445e332021-06-04 16:44:53 -0700271fn new_config_remote_new_verified_file(
272 service: file::VirtFdService,
273 remote_id: i32,
274) -> Result<FileConfig> {
Victor Hsiehc3d45b12021-06-30 09:16:41 -0700275 let remote_file = RemoteFileEditor::new(service, remote_id);
Victor Hsieh1bcf4112021-03-19 14:26:57 -0700276 Ok(FileConfig::RemoteVerifiedNewFile { editor: VerifiedFileEditor::new(remote_file) })
Victor Hsieh6a47e7f2021-03-03 15:53:49 -0800277}
278
Victor Hsiehf01f3232020-12-11 13:31:31 -0800279fn prepare_file_pool(args: &Args) -> Result<BTreeMap<Inode, FileConfig>> {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800280 let mut file_pool = BTreeMap::new();
281
Victor Hsieh9ab13e52021-06-29 09:23:29 -0700282 if args.has_remote_files() {
283 let service = file::get_binder_service(args.cid)?;
Victor Hsieh2445e332021-06-04 16:44:53 -0700284
Victor Hsieh9ab13e52021-06-29 09:23:29 -0700285 for config in &args.remote_ro_file {
286 file_pool.insert(
287 config.ino,
288 new_config_remote_verified_file(
289 service.clone(),
290 config.remote_id,
291 config.file_size,
292 )?,
293 );
294 }
Victor Hsiehf01f3232020-12-11 13:31:31 -0800295
Victor Hsieh9ab13e52021-06-29 09:23:29 -0700296 for config in &args.remote_ro_file_unverified {
297 file_pool.insert(
298 config.ino,
299 new_config_remote_unverified_file(
300 service.clone(),
301 config.remote_id,
302 config.file_size,
303 )?,
304 );
305 }
Victor Hsiehf01f3232020-12-11 13:31:31 -0800306
Victor Hsieh9ab13e52021-06-29 09:23:29 -0700307 for config in &args.remote_new_rw_file {
308 file_pool.insert(
309 config.ino,
310 new_config_remote_new_verified_file(service.clone(), config.remote_id)?,
311 );
312 }
Victor Hsieh6a47e7f2021-03-03 15:53:49 -0800313 }
314
Victor Hsieh09e26262021-03-03 16:00:55 -0800315 for config in &args.local_ro_file {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800316 file_pool.insert(
317 config.ino,
Victor Hsieh09e26262021-03-03 16:00:55 -0800318 new_config_local_ro_file(
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800319 &config.file_path,
320 &config.merkle_tree_dump_path,
321 &config.signature_path,
322 )?,
323 );
324 }
325
Victor Hsieh09e26262021-03-03 16:00:55 -0800326 for config in &args.local_ro_file_unverified {
327 file_pool.insert(config.ino, new_config_local_ro_file_unverified(&config.file_path)?);
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800328 }
329
330 Ok(file_pool)
331}
332
333fn main() -> Result<()> {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800334 let args = Args::from_args();
Victor Hsieh9d0ab622021-04-26 17:07:02 -0700335
336 let log_level = if args.debug { log::Level::Debug } else { log::Level::Info };
337 android_logger::init_once(
338 android_logger::Config::default().with_tag("authfs").with_min_level(log_level),
339 );
340
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800341 let file_pool = prepare_file_pool(&args)?;
342 fusefs::loop_forever(file_pool, &args.mount_point)?;
Victor Hsiehf01f3232020-12-11 13:31:31 -0800343 bail!("Unexpected exit after the handler loop")
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800344}