Merge "Allow zipfuse to mount with fscontext and context"
diff --git a/apkverity/Android.bp b/apkverity/Android.bp
new file mode 100644
index 0000000..3d0dab5
--- /dev/null
+++ b/apkverity/Android.bp
@@ -0,0 +1,42 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_defaults {
+ name: "apkdmverity.defaults",
+ crate_name: "apkdmverity",
+ srcs: ["src/main.rs"],
+ edition: "2018",
+ prefer_rlib: true,
+ rustlibs: [
+ "libanyhow",
+ "libbitflags",
+ "libclap",
+ "liblibc",
+ "libnix",
+ "libnum_traits",
+ "libscopeguard",
+ "libuuid",
+ ],
+ proc_macros: ["libnum_derive"],
+ multilib: {
+ lib32: {
+ enabled: false,
+ },
+ },
+}
+
+rust_binary {
+ name: "apkdmverity",
+ defaults: ["apkdmverity.defaults"],
+}
+
+rust_test {
+ name: "apkdmverity.test",
+ defaults: ["apkdmverity.defaults"],
+ test_suites: ["general-tests"],
+ compile_multilib: "first",
+ rustlibs: [
+ "libtempfile",
+ ],
+}
diff --git a/apkverity/src/apksigv4.rs b/apkverity/src/apksigv4.rs
index f1ee0a4..7d8f318 100644
--- a/apkverity/src/apksigv4.rs
+++ b/apkverity/src/apksigv4.rs
@@ -57,7 +57,7 @@
impl Version {
fn from(val: u32) -> Result<Version> {
- Self::from_u32(val).ok_or(anyhow!("{} is an unsupported version", val))
+ Self::from_u32(val).ok_or_else(|| anyhow!("{} is an unsupported version", val))
}
}
@@ -69,7 +69,7 @@
impl HashAlgorithm {
fn from(val: u32) -> Result<HashAlgorithm> {
- Self::from_u32(val).ok_or(anyhow!("{} is an unsupported hash algorithm", val))
+ Self::from_u32(val).ok_or_else(|| anyhow!("{} is an unsupported hash algorithm", val))
}
}
@@ -157,7 +157,7 @@
use std::io::Cursor;
fn hexstring_from(s: &[u8]) -> String {
- s.iter().map(|byte| format!("{:02x}", byte)).reduce(|i, j| i + &j).unwrap_or(String::new())
+ s.iter().map(|byte| format!("{:02x}", byte)).reduce(|i, j| i + &j).unwrap_or_default()
}
#[test]
diff --git a/apkverity/src/dm.rs b/apkverity/src/dm.rs
index ec4248c..8828b0a 100644
--- a/apkverity/src/dm.rs
+++ b/apkverity/src/dm.rs
@@ -41,9 +41,10 @@
pub use verity::*;
nix::ioctl_readwrite!(_dm_dev_create, DM_IOCTL, Cmd::DM_DEV_CREATE, DmIoctl);
-nix::ioctl_readwrite!(_dm_dev_remove, DM_IOCTL, Cmd::DM_DEV_REMOVE, DmIoctl);
nix::ioctl_readwrite!(_dm_dev_suspend, DM_IOCTL, Cmd::DM_DEV_SUSPEND, DmIoctl);
nix::ioctl_readwrite!(_dm_table_load, DM_IOCTL, Cmd::DM_TABLE_LOAD, DmIoctl);
+#[cfg(test)]
+nix::ioctl_readwrite!(_dm_dev_remove, DM_IOCTL, Cmd::DM_DEV_REMOVE, DmIoctl);
fn dm_dev_create(dm: &DeviceMapper, ioctl: *mut DmIoctl) -> Result<i32> {
// SAFETY: `ioctl` is copied into the kernel. It modifies the state in the kernel, not the
@@ -51,12 +52,6 @@
Ok(unsafe { _dm_dev_create(dm.0.as_raw_fd(), ioctl) }?)
}
-fn dm_dev_remove(dm: &DeviceMapper, ioctl: *mut DmIoctl) -> Result<i32> {
- // SAFETY: `ioctl` is copied into the kernel. It modifies the state in the kernel, not the
- // state of this process in any way.
- Ok(unsafe { _dm_dev_remove(dm.0.as_raw_fd(), ioctl) }?)
-}
-
fn dm_dev_suspend(dm: &DeviceMapper, ioctl: *mut DmIoctl) -> Result<i32> {
// SAFETY: `ioctl` is copied into the kernel. It modifies the state in the kernel, not the
// state of this process in any way.
@@ -69,6 +64,13 @@
Ok(unsafe { _dm_table_load(dm.0.as_raw_fd(), ioctl) }?)
}
+#[cfg(test)]
+fn dm_dev_remove(dm: &DeviceMapper, ioctl: *mut DmIoctl) -> Result<i32> {
+ // SAFETY: `ioctl` is copied into the kernel. It modifies the state in the kernel, not the
+ // state of this process in any way.
+ Ok(unsafe { _dm_dev_remove(dm.0.as_raw_fd(), ioctl) }?)
+}
+
// `DmTargetSpec` is the header of the data structure for a device-mapper target. When doing the
// ioctl, one of more `DmTargetSpec` (and its body) are appened to the `DmIoctl` struct.
#[repr(C)]
@@ -90,7 +92,7 @@
fn as_u8_slice(&self) -> &[u8; size_of::<Self>()] {
// SAFETY: lifetime of the output reference isn't changed.
- unsafe { std::mem::transmute::<&Self, &[u8; size_of::<Self>()]>(&self) }
+ unsafe { &*(&self as *const &Self as *const [u8; size_of::<Self>()]) }
}
}
@@ -116,7 +118,7 @@
fn as_u8_slice(&self) -> &[u8; size_of::<Self>()] {
// SAFETY: lifetime of the output reference isn't changed.
- unsafe { std::mem::transmute::<&Self, &[u8; size_of::<Self>()]>(&self) }
+ unsafe { &*(&self as *const &Self as *const [u8; size_of::<Self>()]) }
}
}
@@ -150,8 +152,8 @@
data.flags |= Flag::DM_READONLY_FLAG;
let mut payload = Vec::with_capacity(payload_size);
- payload.extend_from_slice(&data.as_u8_slice()[..]);
- payload.extend_from_slice(&target.as_u8_slice()[..]);
+ payload.extend_from_slice(data.as_u8_slice());
+ payload.extend_from_slice(target.as_u8_slice());
dm_table_load(&self, payload.as_mut_ptr() as *mut DmIoctl)?;
// Step 3: activate the device (note: the term 'suspend' might be misleading, but it
@@ -166,6 +168,7 @@
}
/// Removes a mapper device
+ #[cfg(test)]
pub fn delete_device_deferred(&self, name: &str) -> Result<()> {
let mut data = DmIoctl::new(&name)?;
data.flags |= Flag::DM_DEFERRED_REMOVE;
diff --git a/apkverity/src/dm/verity.rs b/apkverity/src/dm/verity.rs
index cfc9504..950b26e 100644
--- a/apkverity/src/dm/verity.rs
+++ b/apkverity/src/dm/verity.rs
@@ -35,6 +35,7 @@
}
/// The hash algorithm to use. SHA256 and SHA512 are supported.
+#[allow(dead_code)]
pub enum DmVerityHashAlgorithm {
SHA256,
SHA512,
diff --git a/apkverity/src/loopdevice.rs b/apkverity/src/loopdevice.rs
index bb0e767..519e3bd 100644
--- a/apkverity/src/loopdevice.rs
+++ b/apkverity/src/loopdevice.rs
@@ -36,6 +36,7 @@
// These are old-style ioctls, thus *_bad.
nix::ioctl_none_bad!(_loop_ctl_get_free, LOOP_CTL_GET_FREE);
nix::ioctl_write_ptr_bad!(_loop_configure, LOOP_CONFIGURE, loop_config);
+#[cfg(test)]
nix::ioctl_none_bad!(_loop_clr_fd, LOOP_CLR_FD);
fn loop_ctl_get_free(ctrl_file: &File) -> Result<i32> {
@@ -50,6 +51,7 @@
Ok(unsafe { _loop_configure(device_file.as_raw_fd(), config) }?)
}
+#[cfg(test)]
fn loop_clr_fd(device_file: &File) -> Result<i32> {
// SAFETY: this ioctl disassociates the loop device with `device_file`, where the FD will
// remain opened afterward. The association itself is kept for open FDs.
@@ -122,13 +124,14 @@
.write(true)
.open(&device_path)
.context(format!("failed to open {:?}", &device_path))?;
- loop_configure(&device_file, &mut config)
+ loop_configure(&device_file, &config)
.context(format!("Failed to configure {:?}", &device_path))?;
Ok(PathBuf::from(device_path))
}
/// Detaches backing file from the loop device `path`.
+#[cfg(test)]
pub fn detach<P: AsRef<Path>>(path: P) -> Result<()> {
let device_file = OpenOptions::new().read(true).write(true).open(&path)?;
loop_clr_fd(&device_file)?;
diff --git a/apkverity/src/loopdevice/sys.rs b/apkverity/src/loopdevice/sys.rs
index 2d4977b..3f10f22 100644
--- a/apkverity/src/loopdevice/sys.rs
+++ b/apkverity/src/loopdevice/sys.rs
@@ -24,6 +24,7 @@
pub const LOOP_CTL_GET_FREE: libc::c_ulong = 0x4C82;
pub const LOOP_CONFIGURE: libc::c_ulong = 0x4C0A;
+#[cfg(test)]
pub const LOOP_CLR_FD: libc::c_ulong = 0x4C01;
#[repr(C)]
diff --git a/apkverity/src/main.rs b/apkverity/src/main.rs
index 6fe12a0..5094c50 100644
--- a/apkverity/src/main.rs
+++ b/apkverity/src/main.rs
@@ -57,12 +57,19 @@
)
.required(true),
)
+ .arg(Arg::with_name("verbose").short("v").long("verbose").help("Shows verbose output"))
.get_matches();
let apk = matches.value_of("apk").unwrap();
let idsig = matches.value_of("idsig").unwrap();
let name = matches.value_of("name").unwrap();
- enable_verity(apk, idsig, name)?;
+ let ret = enable_verity(apk, idsig, name)?;
+ if matches.is_present("verbose") {
+ println!(
+ "data_device: {:?}, hash_device: {:?}, mapper_device: {:?}",
+ ret.data_device, ret.hash_device, ret.mapper_device
+ );
+ }
Ok(())
}
diff --git a/apkverity/src/util.rs b/apkverity/src/util.rs
index 415e99b..d2bc799 100644
--- a/apkverity/src/util.rs
+++ b/apkverity/src/util.rs
@@ -16,7 +16,6 @@
use anyhow::{bail, Result};
use nix::sys::stat::FileStat;
-use std::fs;
use std::fs::File;
use std::os::unix::fs::FileTypeExt;
use std::os::unix::io::AsRawFd;
@@ -40,7 +39,7 @@
/// Returns hexadecimal reprentation of a given byte array.
pub fn hexstring_from(s: &[u8]) -> String {
- s.iter().map(|byte| format!("{:02x}", byte)).reduce(|i, j| i + &j).unwrap_or(String::new())
+ s.iter().map(|byte| format!("{:02x}", byte)).reduce(|i, j| i + &j).unwrap_or_default()
}
/// fstat that accepts a path rather than FD
diff --git a/tests/hostside/java/android/virt/test/MicrodroidTestCase.java b/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
index 13ca434..b3c3e27 100644
--- a/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
+++ b/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
@@ -177,7 +177,9 @@
assertThat(abiList.length, is(1));
final String libPath = "/mnt/apk/lib/" + abiList[0] + "/MicrodroidTestNativeLib.so";
- assertThat(executeCommandOnMicrodroid("shell ls " + libPath), is(libPath));
+ assertThat(
+ executeCommandOnMicrodroid("shell ls -Z " + libPath),
+ is("u:object_r:system_file:s0 " + libPath));
assertThat(
executeCommandOnMicrodroid(
diff --git a/zipfuse/src/main.rs b/zipfuse/src/main.rs
index 12c891c..9b70d08 100644
--- a/zipfuse/src/main.rs
+++ b/zipfuse/src/main.rs
@@ -39,35 +39,48 @@
fn main() -> Result<()> {
let matches = App::new("zipfuse")
+ .arg(
+ Arg::with_name("options")
+ .short("o")
+ .takes_value(true)
+ .required(false)
+ .help("Comma separated list of mount options")
+ )
.arg(Arg::with_name("ZIPFILE").required(true))
.arg(Arg::with_name("MOUNTPOINT").required(true))
.get_matches();
let zip_file = matches.value_of("ZIPFILE").unwrap().as_ref();
let mount_point = matches.value_of("MOUNTPOINT").unwrap().as_ref();
- run_fuse(zip_file, mount_point)?;
+ let options = matches.value_of("options");
+ run_fuse(zip_file, mount_point, options)?;
Ok(())
}
/// Runs a fuse filesystem by mounting `zip_file` on `mount_point`.
-pub fn run_fuse(zip_file: &Path, mount_point: &Path) -> Result<()> {
+pub fn run_fuse(zip_file: &Path, mount_point: &Path, extra_options: Option<&str>) -> Result<()> {
const MAX_READ: u32 = 1 << 20; // TODO(jiyong): tune this
const MAX_WRITE: u32 = 1 << 13; // This is a read-only filesystem
let dev_fuse = OpenOptions::new().read(true).write(true).open("/dev/fuse")?;
+ let mut mount_options = vec![
+ MountOption::FD(dev_fuse.as_raw_fd()),
+ MountOption::RootMode(libc::S_IFDIR | libc::S_IXUSR | libc::S_IXGRP | libc::S_IXOTH),
+ MountOption::AllowOther,
+ MountOption::UserId(0),
+ MountOption::GroupId(0),
+ MountOption::MaxRead(MAX_READ),
+ ];
+ if let Some(value) = extra_options {
+ mount_options.push(MountOption::Extra(value));
+ }
+
fuse::mount(
mount_point,
"zipfuse",
libc::MS_NOSUID | libc::MS_NODEV | libc::MS_RDONLY,
- &[
- MountOption::FD(dev_fuse.as_raw_fd()),
- MountOption::RootMode(libc::S_IFDIR | libc::S_IXUSR | libc::S_IXGRP | libc::S_IXOTH),
- MountOption::AllowOther,
- MountOption::UserId(0),
- MountOption::GroupId(0),
- MountOption::MaxRead(MAX_READ),
- ],
+ &mount_options,
)?;
Ok(fuse::worker::start_message_loop(dev_fuse, MAX_READ, MAX_WRITE, ZipFuse::new(zip_file)?)?)
}
@@ -388,7 +401,7 @@
let zip_path = PathBuf::from(zip_path);
let mnt_path = PathBuf::from(mnt_path);
std::thread::spawn(move || {
- crate::run_fuse(&zip_path, &mnt_path).unwrap();
+ crate::run_fuse(&zip_path, &mnt_path, None).unwrap();
});
}
diff --git a/zipfuse/zipfuse.rc b/zipfuse/zipfuse.rc
index 97306ea..ccd94b6 100644
--- a/zipfuse/zipfuse.rc
+++ b/zipfuse/zipfuse.rc
@@ -1,2 +1,2 @@
-service zipfuse /system/bin/zipfuse /dev/block/by-name/microdroid-apk /mnt/apk
+service zipfuse /system/bin/zipfuse -o fscontext=u:object_r:zipfusefs:s0,context=u:object_r:system_file:s0 /dev/block/by-name/microdroid-apk /mnt/apk
disabled