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/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.