blob: f6a2a567b3c8e4263cbaea891fe96f4dabdbd4e3 [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 Hsieh60c2f412021-11-03 13:02:19 -070032use std::collections::HashMap;
Victor Hsieh50d75ac2021-09-03 14:46:55 -070033use std::convert::TryInto;
Victor Hsieh88e50172021-10-15 13:27:13 -070034use std::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 Hsieh45636232021-10-15 17:52:51 -070045use file::{RemoteDirEditor, RemoteFileEditor, RemoteFileReader, RemoteMerkleTreeReader};
Victor Hsieh6a47e7f2021-03-03 15:53:49 -080046use fsverity::{VerifiedFileEditor, VerifiedFileReader};
Victor Hsieh60c2f412021-11-03 13:02:19 -070047use fusefs::AuthFsEntry;
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)]
Victor Hsieh1a8cd042021-09-03 16:29:45 -070057 cid: u32,
Victor Hsieh2445e332021-06-04 16:44:53 -070058
Victor Hsieh4cc3b792021-08-04 12:00:04 -070059 /// Extra options to FUSE
60 #[structopt(short = "o")]
61 extra_options: Option<String>,
62
Victor Hsieh09e26262021-03-03 16:00:55 -080063 /// A read-only remote file with integrity check. Can be multiple.
Victor Hsiehf01f3232020-12-11 13:31:31 -080064 ///
Victor Hsiehb3588ce2021-11-02 15:02:32 -070065 /// For example, `--remote-ro-file 5:/path/to/cert` tells the filesystem to associate the
66 /// 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 -080067 #[structopt(long, parse(try_from_str = parse_remote_ro_file_option))]
68 remote_ro_file: Vec<OptionRemoteRoFile>,
Victor Hsiehf01f3232020-12-11 13:31:31 -080069
Victor Hsieh09e26262021-03-03 16:00:55 -080070 /// A read-only remote file without 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-unverified 5` tells the filesystem to associate the file
73 /// $MOUNTPOINT/5 with a remote FD 5.
74 #[structopt(long)]
75 remote_ro_file_unverified: Vec<i32>,
Victor Hsiehf01f3232020-12-11 13:31:31 -080076
Victor Hsieh6a47e7f2021-03-03 15:53:49 -080077 /// A new read-writable remote file with integrity check. Can be multiple.
78 ///
Victor Hsiehb3588ce2021-11-02 15:02:32 -070079 /// For example, `--remote-new-rw-file 5` tells the filesystem to associate the file
80 /// $MOUNTPOINT/5 with a remote FD 5.
81 #[structopt(long)]
82 remote_new_rw_file: Vec<i32>,
Victor Hsieh6a47e7f2021-03-03 15:53:49 -080083
Victor Hsieh45636232021-10-15 17:52:51 -070084 /// A new directory that is assumed empty in the backing filesystem. New files created in this
85 /// directory are integrity-protected in the same way as --remote-new-verified-file. Can be
86 /// multiple.
87 ///
Victor Hsiehb3588ce2021-11-02 15:02:32 -070088 /// For example, `--remote-new-rw-dir 5` tells the filesystem to associate $MOUNTPOINT/5
89 /// with a remote dir FD 5.
90 #[structopt(long)]
91 remote_new_rw_dir: Vec<i32>,
Victor Hsieh45636232021-10-15 17:52:51 -070092
Victor Hsieh9d0ab622021-04-26 17:07:02 -070093 /// Enable debugging features.
94 #[structopt(long)]
95 debug: bool,
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080096}
97
Victor Hsieh09e26262021-03-03 16:00:55 -080098struct OptionRemoteRoFile {
Victor Hsiehf01f3232020-12-11 13:31:31 -080099 /// ID to refer to the remote file.
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700100 remote_fd: i32,
Victor Hsiehf01f3232020-12-11 13:31:31 -0800101
Victor Hsiehf01f3232020-12-11 13:31:31 -0800102 /// Certificate to verify the authenticity of the file's fs-verity signature.
103 /// TODO(170494765): Implement PKCS#7 signature verification.
104 _certificate_path: PathBuf,
105}
106
Victor Hsieh09e26262021-03-03 16:00:55 -0800107fn parse_remote_ro_file_option(option: &str) -> Result<OptionRemoteRoFile> {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800108 let strs: Vec<&str> = option.split(':').collect();
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700109 if strs.len() != 2 {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800110 bail!("Invalid option: {}", option);
111 }
Victor Hsieh09e26262021-03-03 16:00:55 -0800112 Ok(OptionRemoteRoFile {
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700113 remote_fd: strs[0].parse::<i32>()?,
114 _certificate_path: PathBuf::from(strs[1]),
Victor Hsieh45636232021-10-15 17:52:51 -0700115 })
116}
117
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700118fn new_remote_verified_file_entry(
Victor Hsieh2445e332021-06-04 16:44:53 -0700119 service: file::VirtFdService,
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700120 remote_fd: i32,
Victor Hsieh2445e332021-06-04 16:44:53 -0700121 file_size: u64,
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700122) -> Result<AuthFsEntry> {
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700123 let signature = service.readFsveritySignature(remote_fd).context("Failed to read signature")?;
Victor Hsiehf01f3232020-12-11 13:31:31 -0800124
Victor Hsiehf01f3232020-12-11 13:31:31 -0800125 let authenticator = FakeAuthenticator::always_succeed();
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700126 Ok(AuthFsEntry::VerifiedReadonly {
Victor Hsieh1bcf4112021-03-19 14:26:57 -0700127 reader: VerifiedFileReader::new(
Victor Hsiehf01f3232020-12-11 13:31:31 -0800128 &authenticator,
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700129 RemoteFileReader::new(service.clone(), remote_fd),
Victor Hsiehf01f3232020-12-11 13:31:31 -0800130 file_size,
131 signature,
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700132 RemoteMerkleTreeReader::new(service.clone(), remote_fd),
Victor Hsiehf01f3232020-12-11 13:31:31 -0800133 )?,
134 file_size,
Victor Hsieh1bcf4112021-03-19 14:26:57 -0700135 })
Victor Hsiehf01f3232020-12-11 13:31:31 -0800136}
137
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700138fn new_remote_unverified_file_entry(
Victor Hsieh2445e332021-06-04 16:44:53 -0700139 service: file::VirtFdService,
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700140 remote_fd: i32,
Victor Hsieh2445e332021-06-04 16:44:53 -0700141 file_size: u64,
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700142) -> Result<AuthFsEntry> {
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700143 let reader = RemoteFileReader::new(service, remote_fd);
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700144 Ok(AuthFsEntry::UnverifiedReadonly { reader, file_size })
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800145}
146
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700147fn new_remote_new_verified_file_entry(
Victor Hsieh2445e332021-06-04 16:44:53 -0700148 service: file::VirtFdService,
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700149 remote_fd: i32,
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700150) -> Result<AuthFsEntry> {
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700151 let remote_file = RemoteFileEditor::new(service, remote_fd);
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700152 Ok(AuthFsEntry::VerifiedNew { editor: VerifiedFileEditor::new(remote_file) })
Victor Hsieh6a47e7f2021-03-03 15:53:49 -0800153}
154
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700155fn new_remote_new_verified_dir_entry(
Victor Hsieh45636232021-10-15 17:52:51 -0700156 service: file::VirtFdService,
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700157 remote_fd: i32,
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700158) -> Result<AuthFsEntry> {
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700159 let dir = RemoteDirEditor::new(service, remote_fd);
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700160 Ok(AuthFsEntry::VerifiedNewDirectory { dir })
Victor Hsieh45636232021-10-15 17:52:51 -0700161}
162
Victor Hsieh60c2f412021-11-03 13:02:19 -0700163fn prepare_root_dir_entries(args: &Args) -> Result<HashMap<PathBuf, AuthFsEntry>> {
164 let mut root_entries = HashMap::new();
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800165
Victor Hsieh88e50172021-10-15 13:27:13 -0700166 let service = file::get_rpc_binder_service(args.cid)?;
Victor Hsieh2445e332021-06-04 16:44:53 -0700167
Victor Hsieh88e50172021-10-15 13:27:13 -0700168 for config in &args.remote_ro_file {
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700169 root_entries.insert(
Victor Hsieh60c2f412021-11-03 13:02:19 -0700170 remote_fd_to_path_buf(config.remote_fd),
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700171 new_remote_verified_file_entry(
Victor Hsieh88e50172021-10-15 13:27:13 -0700172 service.clone(),
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700173 config.remote_fd,
174 service.getFileSize(config.remote_fd)?.try_into()?,
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800175 )?,
176 );
177 }
178
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700179 for remote_fd in &args.remote_ro_file_unverified {
180 let remote_fd = *remote_fd;
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700181 root_entries.insert(
Victor Hsieh60c2f412021-11-03 13:02:19 -0700182 remote_fd_to_path_buf(remote_fd),
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700183 new_remote_unverified_file_entry(
Victor Hsieh88e50172021-10-15 13:27:13 -0700184 service.clone(),
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700185 remote_fd,
186 service.getFileSize(remote_fd)?.try_into()?,
Victor Hsieh88e50172021-10-15 13:27:13 -0700187 )?,
188 );
189 }
190
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700191 for remote_fd in &args.remote_new_rw_file {
192 let remote_fd = *remote_fd;
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700193 root_entries.insert(
Victor Hsieh60c2f412021-11-03 13:02:19 -0700194 remote_fd_to_path_buf(remote_fd),
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700195 new_remote_new_verified_file_entry(service.clone(), remote_fd)?,
Victor Hsieh88e50172021-10-15 13:27:13 -0700196 );
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800197 }
198
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700199 for remote_fd in &args.remote_new_rw_dir {
200 let remote_fd = *remote_fd;
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700201 root_entries.insert(
Victor Hsieh60c2f412021-11-03 13:02:19 -0700202 remote_fd_to_path_buf(remote_fd),
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700203 new_remote_new_verified_dir_entry(service.clone(), remote_fd)?,
Victor Hsieh45636232021-10-15 17:52:51 -0700204 );
205 }
206
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700207 Ok(root_entries)
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800208}
209
Victor Hsieh60c2f412021-11-03 13:02:19 -0700210fn remote_fd_to_path_buf(fd: i32) -> PathBuf {
211 PathBuf::from(fd.to_string())
212}
213
Alan Stokese1b6e1c2021-10-01 12:44:49 +0100214fn try_main() -> Result<()> {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800215 let args = Args::from_args();
Victor Hsieh9d0ab622021-04-26 17:07:02 -0700216
217 let log_level = if args.debug { log::Level::Debug } else { log::Level::Info };
218 android_logger::init_once(
219 android_logger::Config::default().with_tag("authfs").with_min_level(log_level),
220 );
221
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700222 let root_entries = prepare_root_dir_entries(&args)?;
223 fusefs::loop_forever(root_entries, &args.mount_point, &args.extra_options)?;
Victor Hsiehf01f3232020-12-11 13:31:31 -0800224 bail!("Unexpected exit after the handler loop")
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800225}
Alan Stokese1b6e1c2021-10-01 12:44:49 +0100226
227fn main() {
228 if let Err(e) = try_main() {
229 error!("failed with {:?}", e);
230 std::process::exit(1);
231 }
232}