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;