blob: ae446e363debba446194aea1d63ec3412dd13ea3 [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 Hsieh50d75ac2021-09-03 14:46:55 -070032use std::convert::TryInto;
Victor Hsieh88e50172021-10-15 13:27:13 -070033use std::path::PathBuf;
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080034use structopt::StructOpt;
35
36mod auth;
37mod common;
38mod crypto;
Victor Hsieh09e26262021-03-03 16:00:55 -080039mod file;
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080040mod fsverity;
41mod fusefs;
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080042
43use auth::FakeAuthenticator;
Victor Hsieh45636232021-10-15 17:52:51 -070044use file::{RemoteDirEditor, RemoteFileEditor, RemoteFileReader, RemoteMerkleTreeReader};
Victor Hsieh6a47e7f2021-03-03 15:53:49 -080045use fsverity::{VerifiedFileEditor, VerifiedFileReader};
Victor Hsieh4d6b9d42021-11-08 15:53:49 -080046use fusefs::{AuthFs, AuthFsEntry};
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080047
48#[derive(StructOpt)]
Victor Hsiehf01f3232020-12-11 13:31:31 -080049struct Args {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080050 /// Mount point of AuthFS.
51 #[structopt(parse(from_os_str))]
52 mount_point: PathBuf,
53
Victor Hsieh2445e332021-06-04 16:44:53 -070054 /// CID of the VM where the service runs.
55 #[structopt(long)]
Victor Hsieh1a8cd042021-09-03 16:29:45 -070056 cid: u32,
Victor Hsieh2445e332021-06-04 16:44:53 -070057
Victor Hsieh4cc3b792021-08-04 12:00:04 -070058 /// Extra options to FUSE
59 #[structopt(short = "o")]
60 extra_options: Option<String>,
61
Victor Hsieh09e26262021-03-03 16:00:55 -080062 /// A read-only remote file with integrity check. Can be multiple.
Victor Hsiehf01f3232020-12-11 13:31:31 -080063 ///
Victor Hsiehb3588ce2021-11-02 15:02:32 -070064 /// For example, `--remote-ro-file 5:/path/to/cert` tells the filesystem to associate the
65 /// 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 -080066 #[structopt(long, parse(try_from_str = parse_remote_ro_file_option))]
67 remote_ro_file: Vec<OptionRemoteRoFile>,
Victor Hsiehf01f3232020-12-11 13:31:31 -080068
Victor Hsieh09e26262021-03-03 16:00:55 -080069 /// A read-only remote file without integrity check. Can be multiple.
Victor Hsiehf01f3232020-12-11 13:31:31 -080070 ///
Victor Hsiehb3588ce2021-11-02 15:02:32 -070071 /// For example, `--remote-ro-file-unverified 5` tells the filesystem to associate the file
72 /// $MOUNTPOINT/5 with a remote FD 5.
73 #[structopt(long)]
74 remote_ro_file_unverified: Vec<i32>,
Victor Hsiehf01f3232020-12-11 13:31:31 -080075
Victor Hsieh6a47e7f2021-03-03 15:53:49 -080076 /// A new read-writable remote file with integrity check. Can be multiple.
77 ///
Victor Hsiehb3588ce2021-11-02 15:02:32 -070078 /// For example, `--remote-new-rw-file 5` tells the filesystem to associate the file
79 /// $MOUNTPOINT/5 with a remote FD 5.
80 #[structopt(long)]
81 remote_new_rw_file: Vec<i32>,
Victor Hsieh6a47e7f2021-03-03 15:53:49 -080082
Victor Hsieh45636232021-10-15 17:52:51 -070083 /// A new directory that is assumed empty in the backing filesystem. New files created in this
84 /// directory are integrity-protected in the same way as --remote-new-verified-file. Can be
85 /// multiple.
86 ///
Victor Hsiehb3588ce2021-11-02 15:02:32 -070087 /// For example, `--remote-new-rw-dir 5` tells the filesystem to associate $MOUNTPOINT/5
88 /// with a remote dir FD 5.
89 #[structopt(long)]
90 remote_new_rw_dir: Vec<i32>,
Victor Hsieh45636232021-10-15 17:52:51 -070091
Victor Hsieh9d0ab622021-04-26 17:07:02 -070092 /// Enable debugging features.
93 #[structopt(long)]
94 debug: bool,
Victor Hsieh88ac6ca2020-11-13 15:20:24 -080095}
96
Victor Hsieh09e26262021-03-03 16:00:55 -080097struct OptionRemoteRoFile {
Victor Hsiehf01f3232020-12-11 13:31:31 -080098 /// ID to refer to the remote file.
Victor Hsiehb3588ce2021-11-02 15:02:32 -070099 remote_fd: i32,
Victor Hsiehf01f3232020-12-11 13:31:31 -0800100
Victor Hsiehf01f3232020-12-11 13:31:31 -0800101 /// Certificate to verify the authenticity of the file's fs-verity signature.
102 /// TODO(170494765): Implement PKCS#7 signature verification.
103 _certificate_path: PathBuf,
104}
105
Victor Hsieh09e26262021-03-03 16:00:55 -0800106fn parse_remote_ro_file_option(option: &str) -> Result<OptionRemoteRoFile> {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800107 let strs: Vec<&str> = option.split(':').collect();
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700108 if strs.len() != 2 {
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800109 bail!("Invalid option: {}", option);
110 }
Victor Hsieh09e26262021-03-03 16:00:55 -0800111 Ok(OptionRemoteRoFile {
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700112 remote_fd: strs[0].parse::<i32>()?,
113 _certificate_path: PathBuf::from(strs[1]),
Victor Hsieh45636232021-10-15 17:52:51 -0700114 })
115}
116
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700117fn new_remote_verified_file_entry(
Victor Hsieh2445e332021-06-04 16:44:53 -0700118 service: file::VirtFdService,
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700119 remote_fd: i32,
Victor Hsieh2445e332021-06-04 16:44:53 -0700120 file_size: u64,
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700121) -> Result<AuthFsEntry> {
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700122 let signature = service.readFsveritySignature(remote_fd).context("Failed to read signature")?;
Victor Hsiehf01f3232020-12-11 13:31:31 -0800123
Victor Hsiehf01f3232020-12-11 13:31:31 -0800124 let authenticator = FakeAuthenticator::always_succeed();
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700125 Ok(AuthFsEntry::VerifiedReadonly {
Victor Hsieh1bcf4112021-03-19 14:26:57 -0700126 reader: VerifiedFileReader::new(
Victor Hsiehf01f3232020-12-11 13:31:31 -0800127 &authenticator,
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700128 RemoteFileReader::new(service.clone(), remote_fd),
Victor Hsiehf01f3232020-12-11 13:31:31 -0800129 file_size,
130 signature,
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700131 RemoteMerkleTreeReader::new(service.clone(), remote_fd),
Victor Hsiehf01f3232020-12-11 13:31:31 -0800132 )?,
133 file_size,
Victor Hsieh1bcf4112021-03-19 14:26:57 -0700134 })
Victor Hsiehf01f3232020-12-11 13:31:31 -0800135}
136
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700137fn new_remote_unverified_file_entry(
Victor Hsieh2445e332021-06-04 16:44:53 -0700138 service: file::VirtFdService,
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700139 remote_fd: i32,
Victor Hsieh2445e332021-06-04 16:44:53 -0700140 file_size: u64,
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700141) -> Result<AuthFsEntry> {
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700142 let reader = RemoteFileReader::new(service, remote_fd);
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700143 Ok(AuthFsEntry::UnverifiedReadonly { reader, file_size })
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800144}
145
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700146fn new_remote_new_verified_file_entry(
Victor Hsieh2445e332021-06-04 16:44:53 -0700147 service: file::VirtFdService,
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700148 remote_fd: i32,
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700149) -> Result<AuthFsEntry> {
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700150 let remote_file = RemoteFileEditor::new(service, remote_fd);
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700151 Ok(AuthFsEntry::VerifiedNew { editor: VerifiedFileEditor::new(remote_file) })
Victor Hsieh6a47e7f2021-03-03 15:53:49 -0800152}
153
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700154fn new_remote_new_verified_dir_entry(
Victor Hsieh45636232021-10-15 17:52:51 -0700155 service: file::VirtFdService,
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700156 remote_fd: i32,
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700157) -> Result<AuthFsEntry> {
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700158 let dir = RemoteDirEditor::new(service, remote_fd);
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700159 Ok(AuthFsEntry::VerifiedNewDirectory { dir })
Victor Hsieh45636232021-10-15 17:52:51 -0700160}
161
Victor Hsieh4d6b9d42021-11-08 15:53:49 -0800162fn prepare_root_dir_entries(authfs: &mut AuthFs, args: &Args) -> Result<()> {
Victor Hsieh88e50172021-10-15 13:27:13 -0700163 let service = file::get_rpc_binder_service(args.cid)?;
Victor Hsieh2445e332021-06-04 16:44:53 -0700164
Victor Hsieh88e50172021-10-15 13:27:13 -0700165 for config in &args.remote_ro_file {
Victor Hsieh4d6b9d42021-11-08 15:53:49 -0800166 authfs.add_entry_at_root_dir(
Victor Hsieh60c2f412021-11-03 13:02:19 -0700167 remote_fd_to_path_buf(config.remote_fd),
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700168 new_remote_verified_file_entry(
Victor Hsieh88e50172021-10-15 13:27:13 -0700169 service.clone(),
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700170 config.remote_fd,
171 service.getFileSize(config.remote_fd)?.try_into()?,
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800172 )?,
Victor Hsieh4d6b9d42021-11-08 15:53:49 -0800173 )?;
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800174 }
175
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700176 for remote_fd in &args.remote_ro_file_unverified {
177 let remote_fd = *remote_fd;
Victor Hsieh4d6b9d42021-11-08 15:53:49 -0800178 authfs.add_entry_at_root_dir(
Victor Hsieh60c2f412021-11-03 13:02:19 -0700179 remote_fd_to_path_buf(remote_fd),
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700180 new_remote_unverified_file_entry(
Victor Hsieh88e50172021-10-15 13:27:13 -0700181 service.clone(),
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700182 remote_fd,
183 service.getFileSize(remote_fd)?.try_into()?,
Victor Hsieh88e50172021-10-15 13:27:13 -0700184 )?,
Victor Hsieh4d6b9d42021-11-08 15:53:49 -0800185 )?;
Victor Hsieh88e50172021-10-15 13:27:13 -0700186 }
187
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700188 for remote_fd in &args.remote_new_rw_file {
189 let remote_fd = *remote_fd;
Victor Hsieh4d6b9d42021-11-08 15:53:49 -0800190 authfs.add_entry_at_root_dir(
Victor Hsieh60c2f412021-11-03 13:02:19 -0700191 remote_fd_to_path_buf(remote_fd),
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700192 new_remote_new_verified_file_entry(service.clone(), remote_fd)?,
Victor Hsieh4d6b9d42021-11-08 15:53:49 -0800193 )?;
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800194 }
195
Victor Hsiehb3588ce2021-11-02 15:02:32 -0700196 for remote_fd in &args.remote_new_rw_dir {
197 let remote_fd = *remote_fd;
Victor Hsieh4d6b9d42021-11-08 15:53:49 -0800198 authfs.add_entry_at_root_dir(
Victor Hsieh60c2f412021-11-03 13:02:19 -0700199 remote_fd_to_path_buf(remote_fd),
Victor Hsieh26cea2f2021-11-03 10:28:33 -0700200 new_remote_new_verified_dir_entry(service.clone(), remote_fd)?,
Victor Hsieh4d6b9d42021-11-08 15:53:49 -0800201 )?;
Victor Hsieh45636232021-10-15 17:52:51 -0700202 }
203
Victor Hsieh4d6b9d42021-11-08 15:53:49 -0800204 Ok(())
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800205}
206
Victor Hsieh60c2f412021-11-03 13:02:19 -0700207fn remote_fd_to_path_buf(fd: i32) -> PathBuf {
208 PathBuf::from(fd.to_string())
209}
210
Alan Stokese1b6e1c2021-10-01 12:44:49 +0100211fn try_main() -> Result<()> {
Victor Hsiehf01f3232020-12-11 13:31:31 -0800212 let args = Args::from_args();
Victor Hsieh9d0ab622021-04-26 17:07:02 -0700213
214 let log_level = if args.debug { log::Level::Debug } else { log::Level::Info };
215 android_logger::init_once(
216 android_logger::Config::default().with_tag("authfs").with_min_level(log_level),
217 );
218
Victor Hsieh4d6b9d42021-11-08 15:53:49 -0800219 let mut authfs = AuthFs::new();
220 prepare_root_dir_entries(&mut authfs, &args)?;
221 fusefs::loop_forever(authfs, &args.mount_point, &args.extra_options)?;
Victor Hsiehf01f3232020-12-11 13:31:31 -0800222 bail!("Unexpected exit after the handler loop")
Victor Hsieh88ac6ca2020-11-13 15:20:24 -0800223}
Alan Stokese1b6e1c2021-10-01 12:44:49 +0100224
225fn main() {
226 if let Err(e) = try_main() {
227 error!("failed with {:?}", e);
228 std::process::exit(1);
229 }
230}