authfs: Support binder-backed file source
This change adds remote file support to authfs. This allows a process to
read a remote file through a local path with transparent fs-verity
verification.
This is supposed to work across VM boundary, but before the remote
binder is ready, this change uses local binder.
Test: Shell #1
$ adb shell 'exec
9</system/bin/sh
8</data/local/tmp/input.4m
7</data/local/tmp/input.4m.merkle_dump
6</data/local/tmp/input.4m.fsv_sig
fd_server
--ro-fds 9
--ro-fds 8:7:6'`
Shell #2
$ adb push tools/device-test.sh /data/local/tmp/ && \
adb shell /data/local/tmp/device-test.sh
Change-Id: Ia69fae548b83ff3ba572f4a496a7cbcca518cbef
diff --git a/authfs/src/remote_file.rs b/authfs/src/remote_file.rs
new file mode 100644
index 0000000..7c3d12e
--- /dev/null
+++ b/authfs/src/remote_file.rs
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+use std::convert::TryFrom;
+use std::io;
+use std::io::Write;
+use std::sync::{Arc, Mutex};
+
+use crate::reader::ReadOnlyDataByChunk;
+
+use authfs_aidl_interface::aidl::com::android::virt::fs::IVirtFdService;
+use authfs_aidl_interface::binder::Strong;
+
+type VirtFdService = Strong<dyn IVirtFdService::IVirtFdService>;
+
+pub mod server {
+ // TODO(victorhsieh): use remote binder.
+ pub fn get_local_service() -> super::VirtFdService {
+ let service_name = "authfs_fd_server";
+ authfs_aidl_interface::binder::get_interface(&service_name)
+ .expect("Cannot reach authfs_fd_server binder service")
+ }
+}
+
+pub struct RemoteChunkedFileReader {
+ // This needs to have Sync trait to be used in fuse::worker::start_message_loop.
+ service: Arc<Mutex<VirtFdService>>,
+ file_fd: i32,
+}
+
+impl RemoteChunkedFileReader {
+ pub fn new(service: Arc<Mutex<VirtFdService>>, file_fd: i32) -> Self {
+ RemoteChunkedFileReader { service, file_fd }
+ }
+}
+
+impl ReadOnlyDataByChunk for RemoteChunkedFileReader {
+ fn read_chunk(&self, chunk_index: u64, mut buf: &mut [u8]) -> io::Result<usize> {
+ let offset = i64::try_from(chunk_index * Self::CHUNK_SIZE)
+ .map_err(|_| io::Error::from_raw_os_error(libc::EOVERFLOW))?;
+
+ let service = Arc::clone(&self.service);
+ let chunk = service
+ .lock()
+ .unwrap()
+ .readFile(self.file_fd, offset, buf.len() as i32)
+ .map_err(|e| io::Error::new(io::ErrorKind::Other, e.get_description()))?;
+ buf.write(&chunk)
+ }
+}
+
+pub struct RemoteFsverityMerkleTreeReader {
+ // This needs to be a Sync to be used in fuse::worker::start_message_loop.
+ // TODO(victorhsieh): change to Strong<> once binder supports it.
+ service: Arc<Mutex<VirtFdService>>,
+ file_fd: i32,
+}
+
+impl RemoteFsverityMerkleTreeReader {
+ pub fn new(service: Arc<Mutex<VirtFdService>>, file_fd: i32) -> Self {
+ RemoteFsverityMerkleTreeReader { service, file_fd }
+ }
+}
+
+impl ReadOnlyDataByChunk for RemoteFsverityMerkleTreeReader {
+ fn read_chunk(&self, chunk_index: u64, mut buf: &mut [u8]) -> io::Result<usize> {
+ let offset = i64::try_from(chunk_index * Self::CHUNK_SIZE)
+ .map_err(|_| io::Error::from_raw_os_error(libc::EOVERFLOW))?;
+
+ let service = Arc::clone(&self.service);
+ let chunk = service
+ .lock()
+ .unwrap()
+ .readFsverityMerkleTree(self.file_fd, offset, buf.len() as i32)
+ .map_err(|e| io::Error::new(io::ErrorKind::Other, e.get_description()))?;
+ buf.write(&chunk)
+ }
+}