blob: 39482e31f44a1efb77469a51d7548e5e18af51ff [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;
34use std::path::PathBuf;
Victor Hsiehf01f3232020-12-11 13:31:31 -080035use std::sync::{Arc, Mutex};
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 Hsieh88ac6ca2020-11-13 15:20:24 -080042mod fsverity;
43mod fusefs;
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080044
45use auth::FakeAuthenticator;
Victor Hsieh09e26262021-03-03 16:00:55 -080046use file::{LocalFileReader, RemoteFileReader, RemoteMerkleTreeReader};
47use fsverity::VerifiedFileReader;
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080048use fusefs::{FileConfig, Inode};
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080049
50#[derive(StructOpt)]
Victor Hsiehf01f3232020-12-11 13:31:31 -080051struct Args {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080052 /// Mount point of AuthFS.
53 #[structopt(parse(from_os_str))]
54 mount_point: PathBuf,
55
Victor Hsieh09e26262021-03-03 16:00:55 -080056 /// A read-only remote file with integrity check. Can be multiple.
Victor Hsiehf01f3232020-12-11 13:31:31 -080057 ///
58 /// For example, `--remote-verified-file 5:10:1234:/path/to/cert` tells the filesystem to
59 /// associate entry 5 with a remote file 10 of size 1234 bytes, and need to be verified against
60 /// the /path/to/cert.
Victor Hsieh09e26262021-03-03 16:00:55 -080061 #[structopt(long, parse(try_from_str = parse_remote_ro_file_option))]
62 remote_ro_file: Vec<OptionRemoteRoFile>,
Victor Hsiehf01f3232020-12-11 13:31:31 -080063
Victor Hsieh09e26262021-03-03 16:00:55 -080064 /// A read-only remote file without integrity check. Can be multiple.
Victor Hsiehf01f3232020-12-11 13:31:31 -080065 ///
66 /// For example, `--remote-unverified-file 5:10:1234` tells the filesystem to associate entry 5
67 /// with a remote file 10 of size 1234 bytes.
Victor Hsieh09e26262021-03-03 16:00:55 -080068 #[structopt(long, parse(try_from_str = parse_remote_ro_file_unverified_option))]
69 remote_ro_file_unverified: Vec<OptionRemoteRoFileUnverified>,
Victor Hsiehf01f3232020-12-11 13:31:31 -080070
Victor Hsieh09e26262021-03-03 16:00:55 -080071 /// Debug only. A read-only local file with integrity check. Can be multiple.
72 #[structopt(long, parse(try_from_str = parse_local_file_ro_option))]
73 local_ro_file: Vec<OptionLocalFileRo>,
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080074
Victor Hsieh09e26262021-03-03 16:00:55 -080075 /// Debug only. A read-only local file without integrity check. Can be multiple.
76 #[structopt(long, parse(try_from_str = parse_local_ro_file_unverified_ro_option))]
77 local_ro_file_unverified: Vec<OptionLocalRoFileUnverified>,
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080078}
79
Victor Hsieh09e26262021-03-03 16:00:55 -080080struct OptionRemoteRoFile {
Victor Hsiehf01f3232020-12-11 13:31:31 -080081 ino: Inode,
82
83 /// ID to refer to the remote file.
84 remote_id: i32,
85
86 /// Expected size of the remote file. Necessary for signature check and Merkle tree
87 /// verification.
88 file_size: u64,
89
90 /// Certificate to verify the authenticity of the file's fs-verity signature.
91 /// TODO(170494765): Implement PKCS#7 signature verification.
92 _certificate_path: PathBuf,
93}
94
Victor Hsieh09e26262021-03-03 16:00:55 -080095struct OptionRemoteRoFileUnverified {
Victor Hsiehf01f3232020-12-11 13:31:31 -080096 ino: Inode,
97
98 /// ID to refer to the remote file.
99 remote_id: i32,
100
101 /// Expected size of the remote file.
102 file_size: u64,
103}
104
Victor Hsieh09e26262021-03-03 16:00:55 -0800105struct OptionLocalFileRo {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800106 ino: Inode,
Victor Hsiehf01f3232020-12-11 13:31:31 -0800107
108 /// Local path of the backing file.
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800109 file_path: PathBuf,
Victor Hsiehf01f3232020-12-11 13:31:31 -0800110
111 /// Local path of the backing file's fs-verity Merkle tree dump.
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800112 merkle_tree_dump_path: PathBuf,
Victor Hsiehf01f3232020-12-11 13:31:31 -0800113
114 /// Local path of fs-verity signature for the backing file.
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800115 signature_path: PathBuf,
Victor Hsiehf01f3232020-12-11 13:31:31 -0800116
117 /// Certificate to verify the authenticity of the file's fs-verity signature.
118 /// TODO(170494765): Implement PKCS#7 signature verification.
119 _certificate_path: PathBuf,
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800120}
121
Victor Hsieh09e26262021-03-03 16:00:55 -0800122struct OptionLocalRoFileUnverified {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800123 ino: Inode,
Victor Hsiehf01f3232020-12-11 13:31:31 -0800124
125 /// Local path of the backing file.
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800126 file_path: PathBuf,
127}
128
Victor Hsieh09e26262021-03-03 16:00:55 -0800129fn parse_remote_ro_file_option(option: &str) -> Result<OptionRemoteRoFile> {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800130 let strs: Vec<&str> = option.split(':').collect();
131 if strs.len() != 4 {
132 bail!("Invalid option: {}", option);
133 }
Victor Hsieh09e26262021-03-03 16:00:55 -0800134 Ok(OptionRemoteRoFile {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800135 ino: strs[0].parse::<Inode>()?,
136 remote_id: strs[1].parse::<i32>()?,
137 file_size: strs[2].parse::<u64>()?,
138 _certificate_path: PathBuf::from(strs[3]),
139 })
140}
141
Victor Hsieh09e26262021-03-03 16:00:55 -0800142fn parse_remote_ro_file_unverified_option(option: &str) -> Result<OptionRemoteRoFileUnverified> {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800143 let strs: Vec<&str> = option.split(':').collect();
144 if strs.len() != 3 {
145 bail!("Invalid option: {}", option);
146 }
Victor Hsieh09e26262021-03-03 16:00:55 -0800147 Ok(OptionRemoteRoFileUnverified {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800148 ino: strs[0].parse::<Inode>()?,
149 remote_id: strs[1].parse::<i32>()?,
150 file_size: strs[2].parse::<u64>()?,
151 })
152}
153
Victor Hsieh09e26262021-03-03 16:00:55 -0800154fn parse_local_file_ro_option(option: &str) -> Result<OptionLocalFileRo> {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800155 let strs: Vec<&str> = option.split(':').collect();
156 if strs.len() != 5 {
157 bail!("Invalid option: {}", option);
158 }
Victor Hsieh09e26262021-03-03 16:00:55 -0800159 Ok(OptionLocalFileRo {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800160 ino: strs[0].parse::<Inode>()?,
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800161 file_path: PathBuf::from(strs[1]),
162 merkle_tree_dump_path: PathBuf::from(strs[2]),
163 signature_path: PathBuf::from(strs[3]),
Victor Hsiehf01f3232020-12-11 13:31:31 -0800164 _certificate_path: PathBuf::from(strs[4]),
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800165 })
166}
167
Victor Hsieh09e26262021-03-03 16:00:55 -0800168fn parse_local_ro_file_unverified_ro_option(option: &str) -> Result<OptionLocalRoFileUnverified> {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800169 let strs: Vec<&str> = option.split(':').collect();
170 if strs.len() != 2 {
171 bail!("Invalid option: {}", option);
172 }
Victor Hsieh09e26262021-03-03 16:00:55 -0800173 Ok(OptionLocalRoFileUnverified {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800174 ino: strs[0].parse::<Inode>()?,
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800175 file_path: PathBuf::from(strs[1]),
176 })
177}
178
Victor Hsiehf01f3232020-12-11 13:31:31 -0800179fn new_config_remote_verified_file(remote_id: i32, file_size: u64) -> Result<FileConfig> {
Victor Hsieh09e26262021-03-03 16:00:55 -0800180 let service = file::get_local_binder();
Andrew Walbrancc093862021-03-05 16:59:35 +0000181 let signature = service.readFsveritySignature(remote_id).context("Failed to read signature")?;
Victor Hsiehf01f3232020-12-11 13:31:31 -0800182
183 let service = Arc::new(Mutex::new(service));
184 let authenticator = FakeAuthenticator::always_succeed();
Victor Hsieh09e26262021-03-03 16:00:55 -0800185 Ok(FileConfig::RemoteVerifiedReadonlyFile(
186 VerifiedFileReader::new(
Victor Hsiehf01f3232020-12-11 13:31:31 -0800187 &authenticator,
Victor Hsieh09e26262021-03-03 16:00:55 -0800188 RemoteFileReader::new(Arc::clone(&service), remote_id),
Victor Hsiehf01f3232020-12-11 13:31:31 -0800189 file_size,
190 signature,
Victor Hsieh09e26262021-03-03 16:00:55 -0800191 RemoteMerkleTreeReader::new(Arc::clone(&service), remote_id),
Victor Hsiehf01f3232020-12-11 13:31:31 -0800192 )?,
193 file_size,
194 ))
195}
196
197fn new_config_remote_unverified_file(remote_id: i32, file_size: u64) -> Result<FileConfig> {
Victor Hsieh09e26262021-03-03 16:00:55 -0800198 let file_reader =
199 RemoteFileReader::new(Arc::new(Mutex::new(file::get_local_binder())), remote_id);
200 Ok(FileConfig::RemoteUnverifiedReadonlyFile(file_reader, file_size))
Victor Hsiehf01f3232020-12-11 13:31:31 -0800201}
202
Victor Hsieh09e26262021-03-03 16:00:55 -0800203fn new_config_local_ro_file(
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800204 protected_file: &PathBuf,
205 merkle_tree_dump: &PathBuf,
206 signature: &PathBuf,
207) -> Result<FileConfig> {
208 let file = File::open(&protected_file)?;
209 let file_size = file.metadata()?.len();
Victor Hsieh09e26262021-03-03 16:00:55 -0800210 let file_reader = LocalFileReader::new(file)?;
211 let merkle_tree_reader = LocalFileReader::new(File::open(merkle_tree_dump)?)?;
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800212 let authenticator = FakeAuthenticator::always_succeed();
213 let mut sig = Vec::new();
214 let _ = File::open(signature)?.read_to_end(&mut sig)?;
Victor Hsieh09e26262021-03-03 16:00:55 -0800215 let file_reader =
216 VerifiedFileReader::new(&authenticator, file_reader, file_size, sig, merkle_tree_reader)?;
217 Ok(FileConfig::LocalVerifiedReadonlyFile(file_reader, file_size))
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800218}
219
Victor Hsieh09e26262021-03-03 16:00:55 -0800220fn new_config_local_ro_file_unverified(file_path: &PathBuf) -> Result<FileConfig> {
221 let file_reader = LocalFileReader::new(File::open(file_path)?)?;
Victor Hsiehfa4477a2021-02-08 10:51:50 -0800222 let file_size = file_reader.len();
Victor Hsieh09e26262021-03-03 16:00:55 -0800223 Ok(FileConfig::LocalUnverifiedReadonlyFile(file_reader, file_size))
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800224}
225
Victor Hsiehf01f3232020-12-11 13:31:31 -0800226fn prepare_file_pool(args: &Args) -> Result<BTreeMap<Inode, FileConfig>> {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800227 let mut file_pool = BTreeMap::new();
228
Victor Hsieh09e26262021-03-03 16:00:55 -0800229 for config in &args.remote_ro_file {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800230 file_pool.insert(
231 config.ino,
232 new_config_remote_verified_file(config.remote_id, config.file_size)?,
233 );
234 }
235
Victor Hsieh09e26262021-03-03 16:00:55 -0800236 for config in &args.remote_ro_file_unverified {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800237 file_pool.insert(
238 config.ino,
239 new_config_remote_unverified_file(config.remote_id, config.file_size)?,
240 );
241 }
242
Victor Hsieh09e26262021-03-03 16:00:55 -0800243 for config in &args.local_ro_file {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800244 file_pool.insert(
245 config.ino,
Victor Hsieh09e26262021-03-03 16:00:55 -0800246 new_config_local_ro_file(
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800247 &config.file_path,
248 &config.merkle_tree_dump_path,
249 &config.signature_path,
250 )?,
251 );
252 }
253
Victor Hsieh09e26262021-03-03 16:00:55 -0800254 for config in &args.local_ro_file_unverified {
255 file_pool.insert(config.ino, new_config_local_ro_file_unverified(&config.file_path)?);
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800256 }
257
258 Ok(file_pool)
259}
260
261fn main() -> Result<()> {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800262 let args = Args::from_args();
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800263 let file_pool = prepare_file_pool(&args)?;
264 fusefs::loop_forever(file_pool, &args.mount_point)?;
Victor Hsiehf01f3232020-12-11 13:31:31 -0800265 bail!("Unexpected exit after the handler loop")
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800266}