microdroid: pass idsig in payload.img
apkdmverity is added to microdroid as well.
Bug: 190343842
Test: MicrodroidHostTestCases (not changed)
Change-Id: If5d6608b52cc93cd13ace85c03b5b2891041b8b4
diff --git a/apkdmverity/src/loopdevice.rs b/apkdmverity/src/loopdevice.rs
index 69920d5..376abd4 100644
--- a/apkdmverity/src/loopdevice.rs
+++ b/apkdmverity/src/loopdevice.rs
@@ -37,7 +37,8 @@
// 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);
+nix::ioctl_write_int_bad!(_loop_set_fd, LOOP_SET_FD);
+nix::ioctl_write_ptr_bad!(_loop_set_status64, LOOP_SET_STATUS64, loop_info64);
#[cfg(test)]
nix::ioctl_none_bad!(_loop_clr_fd, LOOP_CLR_FD);
@@ -48,9 +49,14 @@
Ok(unsafe { _loop_ctl_get_free(ctrl_file.as_raw_fd()) }?)
}
-fn loop_configure(device_file: &File, config: &loop_config) -> Result<i32> {
+fn loop_set_fd(device_file: &File, fd: i32) -> Result<i32> {
// SAFETY: this ioctl changes the state in kernel, but not the state in this process.
- Ok(unsafe { _loop_configure(device_file.as_raw_fd(), config) }?)
+ Ok(unsafe { _loop_set_fd(device_file.as_raw_fd(), fd) }?)
+}
+
+fn loop_set_status64(device_file: &File, info: &loop_info64) -> Result<i32> {
+ // SAFETY: this ioctl changes the state in kernel, but not the state in this process.
+ Ok(unsafe { _loop_set_status64(device_file.as_raw_fd(), info) }?)
}
#[cfg(test)]
@@ -103,26 +109,24 @@
.context("Failed to open loop control")?;
let num = loop_ctl_get_free(&ctrl_file).context("Failed to get free loop device")?;
- // Construct the loop_config struct
+ // Construct the loop_info64 struct
let backing_file = OpenOptions::new()
.read(true)
.open(&path)
.context(format!("failed to open {:?}", path.as_ref()))?;
// safe because the size of the array is the same as the size of the struct
- let mut config: loop_config =
- *DataInit::from_mut_slice(&mut [0; size_of::<loop_config>()]).unwrap();
- config.fd = backing_file.as_raw_fd() as u32;
- config.block_size = 4096;
- config.info.lo_offset = offset;
- config.info.lo_sizelimit = size_limit;
- config.info.lo_flags |= Flag::LO_FLAGS_DIRECT_IO | Flag::LO_FLAGS_READ_ONLY;
+ let mut info: loop_info64 =
+ *DataInit::from_mut_slice(&mut [0; size_of::<loop_info64>()]).unwrap();
+ info.lo_offset = offset;
+ info.lo_sizelimit = size_limit;
+ info.lo_flags |= Flag::LO_FLAGS_DIRECT_IO | Flag::LO_FLAGS_READ_ONLY;
// Special case: don't use direct IO when the backing file is already a loop device, which
// happens only during test. DirectIO-on-loop-over-loop makes the outer loop device
// unaccessible.
#[cfg(test)]
if path.as_ref().to_str().unwrap().starts_with(LOOP_DEV_PREFIX) {
- config.info.lo_flags.remove(Flag::LO_FLAGS_DIRECT_IO);
+ info.lo_flags.remove(Flag::LO_FLAGS_DIRECT_IO);
}
// Configure the loop device to attach the backing file
@@ -133,8 +137,8 @@
.write(true)
.open(&device_path)
.context(format!("failed to open {:?}", &device_path))?;
- loop_configure(&device_file, &config)
- .context(format!("Failed to configure {:?}", &device_path))?;
+ loop_set_fd(&device_file, backing_file.as_raw_fd() as i32)?;
+ loop_set_status64(&device_file, &info)?;
Ok(PathBuf::from(device_path))
}
diff --git a/apkdmverity/src/loopdevice/sys.rs b/apkdmverity/src/loopdevice/sys.rs
index 5de0c92..d32987a 100644
--- a/apkdmverity/src/loopdevice/sys.rs
+++ b/apkdmverity/src/loopdevice/sys.rs
@@ -24,7 +24,8 @@
pub const LOOP_CONTROL: &str = "/dev/loop-control";
pub const LOOP_CTL_GET_FREE: libc::c_ulong = 0x4C82;
-pub const LOOP_CONFIGURE: libc::c_ulong = 0x4C0A;
+pub const LOOP_SET_FD: libc::c_ulong = 0x4C00;
+pub const LOOP_SET_STATUS64: libc::c_ulong = 0x4C04;
#[cfg(test)]
pub const LOOP_CLR_FD: libc::c_ulong = 0x4C01;
@@ -58,6 +59,9 @@
pub lo_init: [u64; 2],
}
+// SAFETY: C struct is safe to be initialized from raw data
+unsafe impl DataInit for loop_info64 {}
+
bitflags! {
pub struct Flag: u32 {
const LO_FLAGS_READ_ONLY = 1 << 0;
diff --git a/apkdmverity/src/main.rs b/apkdmverity/src/main.rs
index 5094c50..54d5def 100644
--- a/apkdmverity/src/main.rs
+++ b/apkdmverity/src/main.rs
@@ -37,7 +37,7 @@
use std::path::{Path, PathBuf};
fn main() -> Result<()> {
- let matches = App::new("apkverity")
+ let matches = App::new("apkdmverity")
.about("Creates a dm-verity block device out of APK signed with APK signature scheme V4.")
.arg(
Arg::with_name("apk")
diff --git a/microdroid/Android.bp b/microdroid/Android.bp
index 6f731bb..4f0d17a 100644
--- a/microdroid/Android.bp
+++ b/microdroid/Android.bp
@@ -49,6 +49,7 @@
"microdroid_init_rc",
"microdroid_launcher",
"microdroid_manager",
+
"ueventd.rc",
"libbinder",
"libbinder_ndk",
@@ -99,6 +100,7 @@
},
lib64: {
deps: [
+ "apkdmverity",
"zipfuse",
],
},
diff --git a/microdroid/payload/mk_payload.cc b/microdroid/payload/mk_payload.cc
index 1da71de..c3db122 100644
--- a/microdroid/payload/mk_payload.cc
+++ b/microdroid/payload/mk_payload.cc
@@ -87,8 +87,9 @@
struct ApkConfig {
std::string name;
- // TODO(jooyung): find path/idsig with name
std::string path;
+ // TODO(jooyung) make this required?
+ std::optional<std::string> idsig_path;
};
struct Config {
@@ -144,6 +145,7 @@
Result<void> ParseJson(const Json::Value& value, ApkConfig& apk_config) {
DO(ParseJson(value["name"], apk_config.name));
DO(ParseJson(value["path"], apk_config.path));
+ DO(ParseJson(value["idsig_path"], apk_config.idsig_path));
return {};
}
@@ -226,7 +228,9 @@
auto* apk = metadata.mutable_apk();
apk->set_name(config.apk->name);
apk->set_payload_partition_name("microdroid-apk");
- // TODO(jooyung): set idsig partition as well
+ if (config.apk->idsig_path.has_value()) {
+ apk->set_idsig_partition_name("microdroid-apk-idsig");
+ }
}
if (config.payload_config_path.has_value()) {
@@ -237,7 +241,9 @@
return WriteMetadata(metadata, out);
}
-Result<void> GenerateFiller(const std::string& file_path, const std::string& filler_path) {
+// fill (zeros + original file's size) with aligning BLOCK_SIZE(4096) boundary
+// return true when the filler is generated.
+Result<bool> SizeFiller(const std::string& file_path, const std::string& filler_path) {
auto file_size = GetFileSize(file_path);
if (!file_size.ok()) {
return file_size.error();
@@ -258,9 +264,41 @@
if (write(fd.get(), &size, sizeof(size)) <= 0) {
return ErrnoError() << "write(" << filler_path << ") failed.";
}
- return {};
+ return true;
}
+// fill zeros to align |file_path|'s size to BLOCK_SIZE(4096) boundary.
+// return true when the filler is generated.
+Result<bool> ZeroFiller(const std::string& file_path, const std::string& filler_path) {
+ auto file_size = GetFileSize(file_path);
+ if (!file_size.ok()) {
+ return file_size.error();
+ }
+ auto disk_size = AlignToPartitionSize(*file_size);
+ if (disk_size <= *file_size) {
+ return false;
+ }
+
+ unique_fd fd(TEMP_FAILURE_RETRY(open(filler_path.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0600)));
+ if (fd.get() == -1) {
+ return ErrnoError() << "open(" << filler_path << ") failed.";
+ }
+ if (!android::base::WriteStringToFd(std::string(disk_size - *file_size, '\0'), fd)) {
+ return ErrnoError() << "write(" << filler_path << ") failed.";
+ }
+ return true;
+}
+
+// Do not generate any fillers
+// Note that CreateCompositeDisk() handles gaps between partitions.
+Result<bool> NoFiller(const std::string& file_path, const std::string& filler_path) {
+ (void)file_path;
+ (void)filler_path;
+ return false;
+}
+
+// fill zeros to align |file_path|'s size to BLOCK_SIZE(4096) boundary.
+// return true when the filler is generated.
Result<void> MakePayload(const Config& config, const std::string& metadata_file,
const std::string& output_file) {
std::vector<MultipleImagePartition> partitions;
@@ -274,14 +312,18 @@
});
int filler_count = 0;
- auto add_partition = [&](auto partition_name, auto file_path) -> Result<void> {
+ auto add_partition = [&](auto partition_name, auto file_path, auto filler) -> Result<void> {
+ std::vector<std::string> image_files{file_path};
+
std::string filler_path = output_file + "." + std::to_string(filler_count++);
- if (auto ret = GenerateFiller(file_path, filler_path); !ret.ok()) {
+ if (auto ret = filler(file_path, filler_path); !ret.ok()) {
return ret.error();
+ } else if (*ret) {
+ image_files.push_back(filler_path);
}
partitions.push_back(MultipleImagePartition{
.label = partition_name,
- .image_file_paths = {file_path, filler_path},
+ .image_file_paths = image_files,
.type = kLinuxFilesystem,
.read_only = true,
});
@@ -292,18 +334,24 @@
for (size_t i = 0; i < config.apexes.size(); i++) {
const auto& apex_config = config.apexes[i];
std::string apex_path = ToAbsolute(apex_config.path, config.dirname);
- if (auto ret = add_partition("microdroid-apex-" + std::to_string(i), apex_path);
+ if (auto ret = add_partition("microdroid-apex-" + std::to_string(i), apex_path, SizeFiller);
!ret.ok()) {
return ret.error();
}
}
- // put apk with "size" filler if necessary.
+ // put apk with "zero" filler.
// TODO(jooyung): partition name("microdroid-apk") is TBD
if (config.apk.has_value()) {
std::string apk_path = ToAbsolute(config.apk->path, config.dirname);
- if (auto ret = add_partition("microdroid-apk", apk_path); !ret.ok()) {
+ if (auto ret = add_partition("microdroid-apk", apk_path, ZeroFiller); !ret.ok()) {
return ret.error();
}
+ if (config.apk->idsig_path.has_value()) {
+ std::string idsig_path = ToAbsolute(config.apk->idsig_path.value(), config.dirname);
+ if (auto ret = add_partition("microdroid-apk-idsig", idsig_path, NoFiller); !ret.ok()) {
+ return ret.error();
+ }
+ }
}
const std::string gpt_header = AppendFileName(output_file, "-header");
diff --git a/microdroid/sepolicy/system/private/kernel.te b/microdroid/sepolicy/system/private/kernel.te
index 5341163..cfec715 100644
--- a/microdroid/sepolicy/system/private/kernel.te
+++ b/microdroid/sepolicy/system/private/kernel.te
@@ -28,6 +28,7 @@
allow kernel null_device:chr_file relabelto;
allow kernel random_device:chr_file relabelto;
allow kernel snapuserd_exec:file relabelto;
+allow kernel vd_device:blk_file read;
allow kernel kmsg_device:chr_file write;
allow kernel gsid:fd use;