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)
+    }
+}