authfs: expose fsverity digest via xattr
Due to the FUSE uapi limitation in the kernel (b/196264590), we can't
simply implement the standard fs-verity ioctls with FUSE. Until it's
possible, implement getxattr as a non-standard API.
Currently, only allow retrieving fsverity digest. In the future, we may
need to get signature, but xattr won't be big enough for the Merkle tree.
Bug: 161471326
Bug: 196635431
Test: retrieve xattr in compsvc
Change-Id: I152284015f1860f19ed60ca632cba141c51b44c4
diff --git a/authfs/src/fsverity/editor.rs b/authfs/src/fsverity/editor.rs
index 86ff4d6..f1e7529 100644
--- a/authfs/src/fsverity/editor.rs
+++ b/authfs/src/fsverity/editor.rs
@@ -88,8 +88,12 @@
Self { file, merkle_tree: Arc::new(RwLock::new(MerkleLeaves::new())) }
}
+ /// Returns the fs-verity digest size in bytes.
+ pub fn get_fsverity_digest_size(&self) -> usize {
+ Sha256Hasher::HASH_SIZE
+ }
+
/// Calculates the fs-verity digest of the current file.
- #[allow(dead_code)]
pub fn calculate_fsverity_digest(&self) -> io::Result<Sha256Hash> {
let merkle_tree = self.merkle_tree.read().unwrap();
merkle_tree.calculate_fsverity_digest().map_err(|e| io::Error::new(io::ErrorKind::Other, e))
diff --git a/authfs/src/fusefs.rs b/authfs/src/fusefs.rs
index 1b0e935..6bdb498 100644
--- a/authfs/src/fusefs.rs
+++ b/authfs/src/fusefs.rs
@@ -28,8 +28,8 @@
use std::time::Duration;
use fuse::filesystem::{
- Context, DirEntry, DirectoryIterator, Entry, FileSystem, FsOptions, SetattrValid,
- ZeroCopyReader, ZeroCopyWriter,
+ Context, DirEntry, DirectoryIterator, Entry, FileSystem, FsOptions, GetxattrReply,
+ SetattrValid, ZeroCopyReader, ZeroCopyWriter,
};
use fuse::mount::MountOption;
@@ -374,6 +374,38 @@
_ => Err(io::Error::from_raw_os_error(libc::EBADF)),
}
}
+
+ fn getxattr(
+ &self,
+ _ctx: Context,
+ inode: Self::Inode,
+ name: &CStr,
+ size: u32,
+ ) -> io::Result<GetxattrReply> {
+ match self.get_file_config(&inode)? {
+ FileConfig::RemoteVerifiedNew { editor } => {
+ // FUSE ioctl is limited, thus we can't implement fs-verity ioctls without a kernel
+ // change (see b/196635431). Until it's possible, use xattr to expose what we need
+ // as an authfs specific API.
+ if name != CStr::from_bytes_with_nul(b"authfs.fsverity.digest\0").unwrap() {
+ return Err(io::Error::from_raw_os_error(libc::ENODATA));
+ }
+
+ if size == 0 {
+ // Per protocol, when size is 0, return the value size.
+ Ok(GetxattrReply::Count(editor.get_fsverity_digest_size() as u32))
+ } else {
+ let digest = editor.calculate_fsverity_digest()?;
+ if digest.len() > size as usize {
+ Err(io::Error::from_raw_os_error(libc::ERANGE))
+ } else {
+ Ok(GetxattrReply::Value(digest.to_vec()))
+ }
+ }
+ }
+ _ => Err(io::Error::from_raw_os_error(libc::ENODATA)),
+ }
+ }
}
/// Mount and start the FUSE instance. This requires CAP_SYS_ADMIN.