Decouple apkdmverity from device mapper modules
We need to extend & reuse device mapper modules to construct other
targets such as crypt. This patch moves dm related modules to a separate
lib & change apkdmverity binary to use that library.
Other changes include making delete_device_deferred removing test
annotation from delete_device_deferred & changing visibility of
functions.
Test: atest apkdmverity.test
Bug: 250880499
Change-Id: I5894c362e2b85c6260931b4c9d90f7e3d602291c
diff --git a/apkdmverity/Android.bp b/apkdmverity/Android.bp
index 4346089..92b23a7 100644
--- a/apkdmverity/Android.bp
+++ b/apkdmverity/Android.bp
@@ -14,6 +14,7 @@
"libbitflags",
"libclap",
"libdata_model",
+ "libdm_rust",
"libitertools",
"liblibc",
"libnix",
diff --git a/apkdmverity/src/loopdevice.rs b/apkdmverity/src/loopdevice.rs
index 35ae154..fa49cea 100644
--- a/apkdmverity/src/loopdevice.rs
+++ b/apkdmverity/src/loopdevice.rs
@@ -25,6 +25,7 @@
use anyhow::{Context, Result};
use data_model::DataInit;
+use dm::util::*;
use libc::O_DIRECT;
use std::fs::{File, OpenOptions};
use std::mem::size_of;
@@ -35,7 +36,6 @@
use std::time::{Duration, Instant};
use crate::loopdevice::sys::*;
-use crate::util::*;
// These are old-style ioctls, thus *_bad.
nix::ioctl_none_bad!(_loop_ctl_get_free, LOOP_CTL_GET_FREE);
@@ -71,7 +71,7 @@
) -> Result<PathBuf> {
// Attaching a file to a loop device can make a race condition; a loop device number obtained
// from LOOP_CTL_GET_FREE might have been used by another thread or process. In that case the
- // subsequet LOOP_CONFIGURE ioctl returns with EBUSY. Try until it succeeds.
+ // subsequent LOOP_CONFIGURE ioctl returns with EBUSY. Try until it succeeds.
//
// Note that the timing parameters below are chosen rather arbitrarily. In practice (i.e.
// inside Microdroid) we can't experience the race condition because `apkverity` is the only
diff --git a/apkdmverity/src/main.rs b/apkdmverity/src/main.rs
index bce25e8..1a4a929 100644
--- a/apkdmverity/src/main.rs
+++ b/apkdmverity/src/main.rs
@@ -21,13 +21,13 @@
//! system managed by the host Android which is assumed to be compromisable, it is important to
//! keep the integrity of the file "inside" Microdroid.
-mod dm;
mod loopdevice;
-mod util;
use anyhow::{bail, Context, Result};
use apkverify::{HashAlgorithm, V4Signature};
use clap::{App, Arg};
+use dm::util;
+use dm::verity::{DmVerityHashAlgorithm, DmVerityTargetBuilder};
use itertools::Itertools;
use std::fmt::Debug;
use std::fs;
@@ -114,7 +114,7 @@
// Build a dm-verity target spec from the information from the idsig file. The apk and the
// idsig files are used as the data device and the hash device, respectively.
- let target = dm::DmVerityTargetBuilder::default()
+ let target = DmVerityTargetBuilder::default()
.data_device(&data_device, apk_size)
.hash_device(&hash_device)
.root_digest(if let Some(roothash) = roothash {
@@ -123,7 +123,7 @@
&sig.hashing_info.raw_root_hash
})
.hash_algorithm(match sig.hashing_info.hash_algorithm {
- HashAlgorithm::SHA256 => dm::DmVerityHashAlgorithm::SHA256,
+ HashAlgorithm::SHA256 => DmVerityHashAlgorithm::SHA256,
})
.salt(&sig.hashing_info.salt)
.build()
@@ -132,7 +132,7 @@
// Actually create a dm-verity block device using the spec.
let dm = dm::DeviceMapper::new()?;
let mapper_device =
- dm.create_device(name, &target).context("Failed to create dm-verity device")?;
+ dm.create_verity_device(name, &target).context("Failed to create dm-verity device")?;
Ok(VerityResult { data_device, hash_device, mapper_device })
}
diff --git a/libs/devicemapper/Android.bp b/libs/devicemapper/Android.bp
new file mode 100644
index 0000000..61ffa22
--- /dev/null
+++ b/libs/devicemapper/Android.bp
@@ -0,0 +1,29 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_defaults {
+ name: "libdm_rust.defaults",
+ crate_name: "dm",
+ srcs: ["src/lib.rs"],
+ edition: "2021",
+ prefer_rlib: true,
+ rustlibs: [
+ "libanyhow",
+ "libbitflags",
+ "liblibc",
+ "libdata_model",
+ "libnix",
+ "libuuid",
+ ],
+ multilib: {
+ lib32: {
+ enabled: false,
+ },
+ },
+}
+
+rust_library {
+ name: "libdm_rust",
+ defaults: ["libdm_rust.defaults"],
+}
diff --git a/apkdmverity/src/dm.rs b/libs/devicemapper/src/lib.rs
similarity index 93%
rename from apkdmverity/src/dm.rs
rename to libs/devicemapper/src/lib.rs
index 4cb24fc..1bcaf1a 100644
--- a/apkdmverity/src/dm.rs
+++ b/libs/devicemapper/src/lib.rs
@@ -26,7 +26,9 @@
// the device mapper block devices that are currently listed in the kernel. Size is an important
// criteria for Microdroid.
-use crate::util::*;
+//! A library to create device mapper spec & issue ioctls.
+
+#![allow(missing_docs)]
use anyhow::{Context, Result};
use data_model::DataInit;
@@ -36,17 +38,22 @@
use std::os::unix::io::AsRawFd;
use std::path::{Path, PathBuf};
+/// Expose util functions
+pub mod util;
+/// Exposes the DmVerityTarget & related builder
+pub mod verity;
+
mod sys;
-mod verity;
use sys::*;
-pub use verity::*;
+use util::*;
+use verity::*;
nix::ioctl_readwrite!(_dm_dev_create, DM_IOCTL, Cmd::DM_DEV_CREATE, 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);
+/// Create a new (mapper) device
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
// state of this process in any way.
@@ -65,7 +72,6 @@
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.
@@ -145,10 +151,10 @@
/// Creates a device mapper device and configure it according to the `target` specification.
/// The path to the generated device is "/dev/mapper/<name>".
- pub fn create_device(&self, name: &str, target: &DmVerityTarget) -> Result<PathBuf> {
+ pub fn create_verity_device(&self, name: &str, target: &DmVerityTarget) -> Result<PathBuf> {
// Step 1: create an empty device
let mut data = DmIoctl::new(name)?;
- data.set_uuid(&uuid()?)?;
+ data.set_uuid(&uuid("apkver".as_bytes())?)?;
dm_dev_create(self, &mut data)
.context(format!("failed to create an empty device with name {}", &name))?;
@@ -179,7 +185,6 @@
}
/// 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;
@@ -190,7 +195,7 @@
}
/// Used to derive a UUID that uniquely identifies a device mapper device when creating it.
-fn uuid() -> Result<String> {
+fn uuid(node_id: &[u8]) -> Result<String> {
use std::time::{SystemTime, UNIX_EPOCH};
use uuid::v1::{Context, Timestamp};
use uuid::Uuid;
@@ -198,6 +203,6 @@
let context = Context::new(0);
let now = SystemTime::now().duration_since(UNIX_EPOCH)?;
let ts = Timestamp::from_unix(&context, now.as_secs(), now.subsec_nanos());
- let uuid = Uuid::new_v1(ts, "apkver".as_bytes())?;
+ let uuid = Uuid::new_v1(ts, node_id)?;
Ok(String::from(uuid.to_hyphenated().encode_lower(&mut Uuid::encode_buffer())))
}
diff --git a/apkdmverity/src/dm/sys.rs b/libs/devicemapper/src/sys.rs
similarity index 100%
rename from apkdmverity/src/dm/sys.rs
rename to libs/devicemapper/src/sys.rs
diff --git a/apkdmverity/src/util.rs b/libs/devicemapper/src/util.rs
similarity index 100%
rename from apkdmverity/src/util.rs
rename to libs/devicemapper/src/util.rs
diff --git a/apkdmverity/src/dm/verity.rs b/libs/devicemapper/src/verity.rs
similarity index 93%
rename from apkdmverity/src/dm/verity.rs
rename to libs/devicemapper/src/verity.rs
index 3a49ee2..e0c5e52 100644
--- a/apkdmverity/src/dm/verity.rs
+++ b/libs/devicemapper/src/verity.rs
@@ -24,21 +24,28 @@
use std::mem::size_of;
use std::path::Path;
-use super::DmTargetSpec;
use crate::util::*;
+use crate::DmTargetSpec;
// The UAPI for the verity target is here.
// https://www.kernel.org/doc/Documentation/device-mapper/verity.txt
-/// Version of the verity target spec. Only `V1` is supported.
+/// Device-Mapper’s “verity” target provides transparent integrity checking of block devices using
+/// a cryptographic digest provided by the kernel crypto API
+pub struct DmVerityTarget(Box<[u8]>);
+
+/// Version of the verity target spec.
pub enum DmVerityVersion {
+ /// Only `1` is supported.
V1,
}
/// The hash algorithm to use. SHA256 and SHA512 are supported.
#[allow(dead_code)]
pub enum DmVerityHashAlgorithm {
+ /// sha with 256 bit hash
SHA256,
+ /// sha with 512 bit hash
SHA512,
}
@@ -53,9 +60,8 @@
salt: Option<&'a [u8]>,
}
-pub struct DmVerityTarget(Box<[u8]>);
-
impl DmVerityTarget {
+ /// flatten into slice
pub fn as_slice(&self) -> &[u8] {
self.0.as_ref()
}
@@ -89,7 +95,7 @@
self
}
- /// Sets the hash algorithm that the merkel tree is using.
+ /// Sets the hash algorithm that the merkle tree is using.
pub fn hash_algorithm(&mut self, algo: DmVerityHashAlgorithm) -> &mut Self {
self.hash_algorithm = algo;
self