authfs: return Merkle tree hidden in the filesystem
fd_server is capable to return a tree "dump" from a file. But for the normal case where the served file already has fs-verity, we should use the new AuthFsTestCases ioctl to retrieve the tree and signature. Test is not included due to some setup difficulty (passed locally). Bug: 171280402 Test: atest AuthFsTestCases Change-Id: Ieba685ad065b69edafadce462d112b8fd118686a
This commit is contained in:
parent
a9a9a626ce
commit
4dc85c9ebc
|
@ -13,6 +13,7 @@ rust_binary {
|
|||
"libclap",
|
||||
"liblibc",
|
||||
"liblog_rust",
|
||||
"libnix",
|
||||
],
|
||||
apex_available: ["com.android.virt"],
|
||||
}
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* 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 nix::ioctl_readwrite;
|
||||
use std::io;
|
||||
|
||||
// Constants/values from uapi/linux/fsverity.h
|
||||
const FS_VERITY_METADATA_TYPE_MERKLE_TREE: u64 = 1;
|
||||
const FS_VERITY_METADATA_TYPE_SIGNATURE: u64 = 3;
|
||||
const FS_IOCTL_MAGIC: u8 = b'f';
|
||||
const FS_IOCTL_READ_VERITY_METADATA: u8 = 135;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct fsverity_read_metadata_arg {
|
||||
metadata_type: u64,
|
||||
offset: u64,
|
||||
length: u64,
|
||||
buf_ptr: u64,
|
||||
__reserved: u64,
|
||||
}
|
||||
|
||||
ioctl_readwrite!(
|
||||
read_verity_metadata,
|
||||
FS_IOCTL_MAGIC,
|
||||
FS_IOCTL_READ_VERITY_METADATA,
|
||||
fsverity_read_metadata_arg
|
||||
);
|
||||
|
||||
fn read_metadata(fd: i32, metadata_type: u64, offset: u64, buf: &mut [u8]) -> io::Result<usize> {
|
||||
let mut arg = fsverity_read_metadata_arg {
|
||||
metadata_type,
|
||||
offset,
|
||||
length: buf.len() as u64,
|
||||
buf_ptr: buf.as_mut_ptr() as u64,
|
||||
__reserved: 0,
|
||||
};
|
||||
Ok(unsafe { read_verity_metadata(fd, &mut arg) }.map_err(|e| {
|
||||
if let nix::Error::Sys(errno) = e {
|
||||
io::Error::from_raw_os_error(errno as i32)
|
||||
} else {
|
||||
// Document of nix::sys::ioctl indicates the macro-generated function always returns an
|
||||
// nix::errno::Errno, which can be converted nix::Error::Sys above. As the result, this
|
||||
// branch is unreachable.
|
||||
unreachable!();
|
||||
}
|
||||
})? as usize)
|
||||
}
|
||||
|
||||
/// Read the raw Merkle tree from the fd, if it exists. The API semantics is similar to a regular
|
||||
/// pread(2), and may not return full requested buffer.
|
||||
pub fn read_merkle_tree(fd: i32, offset: u64, buf: &mut [u8]) -> io::Result<usize> {
|
||||
read_metadata(fd, FS_VERITY_METADATA_TYPE_MERKLE_TREE, offset, buf)
|
||||
}
|
||||
|
||||
/// Read the fs-verity signature from the fd (if exists). The returned signature should be complete.
|
||||
pub fn read_signature(fd: i32, buf: &mut [u8]) -> io::Result<usize> {
|
||||
read_metadata(fd, FS_VERITY_METADATA_TYPE_SIGNATURE, 0 /* offset */, buf)
|
||||
}
|
|
@ -25,6 +25,8 @@
|
|||
//! [1] Since the remote binder is not ready, this currently implementation uses local binder
|
||||
//! first.
|
||||
|
||||
mod fsverity;
|
||||
|
||||
use std::cmp::min;
|
||||
use std::collections::BTreeMap;
|
||||
use std::convert::TryInto;
|
||||
|
@ -32,7 +34,7 @@ use std::ffi::CString;
|
|||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::os::unix::fs::FileExt;
|
||||
use std::os::unix::io::FromRawFd;
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd};
|
||||
|
||||
use anyhow::{bail, Context, Result};
|
||||
use binder::IBinderInternal; // TODO(178852354): remove once set_requesting_sid is exposed in the API.
|
||||
|
@ -130,18 +132,22 @@ impl IVirtFdService for FdService {
|
|||
let offset: u64 = validate_and_cast_offset(offset)?;
|
||||
|
||||
match &self.get_file_config(id)? {
|
||||
FdConfig::Readonly { alt_merkle_tree, .. } => {
|
||||
if let Some(file) = &alt_merkle_tree {
|
||||
read_into_buf(&file, size, offset).map_err(|e| {
|
||||
FdConfig::Readonly { file, alt_merkle_tree, .. } => {
|
||||
if let Some(tree_file) = &alt_merkle_tree {
|
||||
read_into_buf(&tree_file, size, offset).map_err(|e| {
|
||||
error!("readFsverityMerkleTree: read error: {}", e);
|
||||
Status::from(ERROR_IO)
|
||||
})
|
||||
} else {
|
||||
// TODO(victorhsieh) retrieve from the fd when the new ioctl is ready
|
||||
Err(new_binder_exception(
|
||||
ExceptionCode::UNSUPPORTED_OPERATION,
|
||||
"Not implemented yet",
|
||||
))
|
||||
let mut buf = vec![0; size];
|
||||
let s = fsverity::read_merkle_tree(file.as_raw_fd(), offset, &mut buf)
|
||||
.map_err(|e| {
|
||||
error!("readFsverityMerkleTree: failed to retrieve merkle tree: {}", e);
|
||||
Status::from(e.raw_os_error().unwrap_or(ERROR_IO))
|
||||
})?;
|
||||
debug_assert!(s <= buf.len(), "Shouldn't return more bytes than asked");
|
||||
buf.truncate(s);
|
||||
Ok(buf)
|
||||
}
|
||||
}
|
||||
FdConfig::ReadWrite(_file) => {
|
||||
|
@ -155,20 +161,24 @@ impl IVirtFdService for FdService {
|
|||
|
||||
fn readFsveritySignature(&self, id: i32) -> BinderResult<Vec<u8>> {
|
||||
match &self.get_file_config(id)? {
|
||||
FdConfig::Readonly { alt_signature, .. } => {
|
||||
if let Some(file) = &alt_signature {
|
||||
FdConfig::Readonly { file, alt_signature, .. } => {
|
||||
if let Some(sig_file) = &alt_signature {
|
||||
// Supposedly big enough buffer size to store signature.
|
||||
let size = MAX_REQUESTING_DATA as usize;
|
||||
read_into_buf(&file, size, 0).map_err(|e| {
|
||||
let offset = 0;
|
||||
read_into_buf(&sig_file, size, offset).map_err(|e| {
|
||||
error!("readFsveritySignature: read error: {}", e);
|
||||
Status::from(ERROR_IO)
|
||||
})
|
||||
} else {
|
||||
// TODO(victorhsieh) retrieve from the fd when the new ioctl is ready
|
||||
Err(new_binder_exception(
|
||||
ExceptionCode::UNSUPPORTED_OPERATION,
|
||||
"Not implemented yet",
|
||||
))
|
||||
let mut buf = vec![0; MAX_REQUESTING_DATA as usize];
|
||||
let s = fsverity::read_signature(file.as_raw_fd(), &mut buf).map_err(|e| {
|
||||
error!("readFsverityMerkleTree: failed to retrieve merkle tree: {}", e);
|
||||
Status::from(e.raw_os_error().unwrap_or(ERROR_IO))
|
||||
})?;
|
||||
debug_assert!(s <= buf.len(), "Shouldn't return more bytes than asked");
|
||||
buf.truncate(s);
|
||||
Ok(buf)
|
||||
}
|
||||
}
|
||||
FdConfig::ReadWrite(_file) => {
|
||||
|
|
Loading…
Reference in New Issue