summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Pursell <dpursell@google.com>2024-05-15 13:49:05 -0700
committerDavid Pursell <dpursell@google.com>2024-05-20 12:11:51 -0700
commitb2164fd7b709e6073ec3e7af825aab5f7766010e (patch)
tree10061290ba3cfbc5eca190ca3b3460a67e39df01
parent5e713b7ecd8d7b670e53904a6c46f68564415393 (diff)
downloadlibbootloader-main.tar.gz
[libgbl] hook up libavb and remove sw_digestHEADmastermain
Hook up enough of libavb to get the existing verification tests passing. Just uses the base libavb for now, will add more tests and use the libavb_cert extensions later on. The test data generation script has also been updated to be more deterministic and provide the now-required key data. Also removes sw_digest; it turns out this is going to be pretty difficult to integrate given libavb's somewhat awkward hashing API, and the `ring` crate is not approved for production use in Android. We'll revisit this later to try to figure out how to inject custom hashing implementations, but for now it just uses the built-in libavb software implementation. Bug: b/334962570 Change-Id: Ie55ce0719c88855ce7032f2ba55018265385d99c
-rw-r--r--gbl/libgbl/BUILD7
-rw-r--r--gbl/libgbl/Cargo.toml4
-rw-r--r--gbl/libgbl/src/digest.rs3
-rw-r--r--gbl/libgbl/src/error.rs4
-rw-r--r--gbl/libgbl/src/lib.rs94
-rw-r--r--gbl/libgbl/src/ops.rs61
-rw-r--r--gbl/libgbl/src/sw_digest.rs125
-rw-r--r--gbl/libgbl/testdata/README.md7
-rwxr-xr-x[-rw-r--r--]gbl/libgbl/testdata/gen_test_data.py132
-rw-r--r--gbl/libgbl/testdata/sparse_test.binbin24704 -> 24704 bytes
-rw-r--r--gbl/libgbl/testdata/sparse_test_blk1024.binbin24704 -> 24704 bytes
-rw-r--r--gbl/libgbl/testdata/sparse_test_raw.binbin57344 -> 57344 bytes
-rw-r--r--gbl/libgbl/testdata/test_image.imgbin128 -> 0 bytes
-rw-r--r--gbl/libgbl/testdata/testkey_rsa4096.pem98
-rw-r--r--gbl/libgbl/testdata/testkey_rsa4096.pub.pem14
-rw-r--r--gbl/libgbl/testdata/testkey_rsa4096_pub.binbin0 -> 1032 bytes
-rw-r--r--gbl/libgbl/testdata/testkey_rsa4096_pub.pem14
-rw-r--r--gbl/libgbl/testdata/writeback_test_disk.binbin65536 -> 65536 bytes
-rw-r--r--gbl/libgbl/testdata/zircon_a.binbin16384 -> 16384 bytes
-rw-r--r--gbl/libgbl/testdata/zircon_a.vbmetabin0 -> 2048 bytes
-rw-r--r--gbl/libgbl/testdata/zircon_b.binbin16384 -> 16384 bytes
-rw-r--r--gbl/libgbl/testdata/zircon_gpt.binbin131072 -> 131072 bytes
-rw-r--r--gbl/libgbl/testdata/zircon_r.binbin16384 -> 16384 bytes
-rw-r--r--gbl/libgbl/tests/integration_tests.rs45
-rw-r--r--gbl/libstorage/src/lib.rs2
-rwxr-xr-xgbl/tools/gen_gpt_disk.py92
26 files changed, 313 insertions, 389 deletions
diff --git a/gbl/libgbl/BUILD b/gbl/libgbl/BUILD
index 75b58fd..df19be0 100644
--- a/gbl/libgbl/BUILD
+++ b/gbl/libgbl/BUILD
@@ -46,12 +46,13 @@ rust_test(
"@gbl//libgbl/testdata:sparse_test.bin",
"@gbl//libgbl/testdata:sparse_test_blk1024.bin",
"@gbl//libgbl/testdata:sparse_test_raw.bin",
- "@gbl//libgbl/testdata:test_image.img",
- "@gbl//libgbl/testdata:testkey_rsa4096.pem",
- "@gbl//libgbl/testdata:testkey_rsa4096.pub.pem",
+ "@gbl//libgbl/testdata:testkey_rsa4096_pub.bin",
"@gbl//libgbl/testdata:writeback_test_disk.bin",
+ "@gbl//libgbl/testdata:zircon_a.bin",
+ "@gbl//libgbl/testdata:zircon_a.vbmeta",
],
deps = [
+ "@avb//:avb_crypto_ops_sha_impl_staticlib",
"@avb//:avb_test",
"@gbl//libavb:sysdeps",
"@gbl//libstorage:libstorage_testlib",
diff --git a/gbl/libgbl/Cargo.toml b/gbl/libgbl/Cargo.toml
index f383fb3..8d4d65a 100644
--- a/gbl/libgbl/Cargo.toml
+++ b/gbl/libgbl/Cargo.toml
@@ -21,14 +21,12 @@ name = "gbl"
version = "0.1.0"
[features]
-default = ["sw_digest"]
+default = []
alloc = []
-sw_digest = []
[dependencies]
zbi = {version = "0.1", path = "../third_party/libzbi"}
gbl_storage = {version = "0.1", path = "../libstorage"}
-ring = "0.17"
spin = "0.9"
static_assertions = "0"
lazy_static = "1"
diff --git a/gbl/libgbl/src/digest.rs b/gbl/libgbl/src/digest.rs
index 2505e42..c0435a1 100644
--- a/gbl/libgbl/src/digest.rs
+++ b/gbl/libgbl/src/digest.rs
@@ -13,9 +13,6 @@
// limitations under the License.
//! GBL Digest trait that defines interface for hash computation.
-//!
-//! Software implementation available in `sw_digest` module. Specifically
-//! [SwContext] and [SwDigest].
/// List of supported algorithms
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
diff --git a/gbl/libgbl/src/error.rs b/gbl/libgbl/src/error.rs
index e7474ce..fcc4a1a 100644
--- a/gbl/libgbl/src/error.rs
+++ b/gbl/libgbl/src/error.rs
@@ -23,7 +23,7 @@ use gbl_storage::StorageError;
/// Helper type GBL functions will return.
pub type Result<T> = core::result::Result<T, IntegrationError>;
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Eq)]
/// Errors originating from GBL native logic.
pub enum Error {
ArithmeticOverflow,
@@ -133,7 +133,7 @@ macro_rules! composite_enum {
composite_enum! {
/// Top level error type that integrates errors from various dependency libraries.
- #[derive(Debug)]
+ #[derive(Debug, PartialEq, Eq)]
pub enum IntegrationError {
/// Failed to get descriptor from AvbMeta
AvbDescriptorError(DescriptorError),
diff --git a/gbl/libgbl/src/lib.rs b/gbl/libgbl/src/lib.rs
index fc619e0..a7f894a 100644
--- a/gbl/libgbl/src/lib.rs
+++ b/gbl/libgbl/src/lib.rs
@@ -20,7 +20,6 @@
//! Vendors
//!
//! # Features
-//! * `sw_digest` - enables software implementation of digests: [SwDigest], [SwContext]
//! * `alloc` - enables AVB ops related logic that relies on allocation and depends on allocation.
// This code is intended for use in bootloaders that typically will not support
@@ -45,7 +44,6 @@ use spin::Mutex;
pub mod boot_mode;
pub mod boot_reason;
-pub mod digest;
pub mod error;
pub mod fastboot;
pub mod ops;
@@ -56,19 +54,13 @@ pub mod slots;
use slots::{BootTarget, BootToken, Cursor, Manager, OneShot, SuffixBytes, UnbootableReason};
-#[cfg(feature = "sw_digest")]
-pub mod sw_digest;
-
pub use avb::Descriptor;
pub use boot_mode::BootMode;
pub use boot_reason::KnownBootReason;
-pub use digest::{Context, Digest};
pub use error::{Error, IntegrationError, Result};
pub use ops::{
AndroidBootImages, BootImages, DefaultGblOps, FuchsiaBootImages, GblOps, GblOpsError,
};
-#[cfg(feature = "sw_digest")]
-pub use sw_digest::{SwContext, SwDigest};
use ops::GblUtils;
@@ -77,9 +69,7 @@ use ops::GblUtils;
pub struct Partition {}
/// TODO: b/312607649 - placeholder type
pub struct InfoStruct {}
-/// TODO: b/312607649 - placeholder type
-pub struct AvbVerificationFlags(u32); // AvbVBMetaImageFlags from
- // external/avb/libavb/avb_vbmeta_image.h
+
/// Data structure holding verified slot data.
#[derive(Debug)]
pub struct VerifiedData<'a>(SlotVerifyData<'a>);
@@ -225,7 +215,7 @@ where
&mut self,
avb_ops: &mut impl avb::Ops<'b>,
partitions_ram_map: &mut [PartitionRamMap],
- avb_verification_flags: AvbVerificationFlags,
+ slot_verify_flags: SlotVerifyFlags,
boot_target: Option<BootTarget>,
) -> Result<VerifiedData<'b>> {
let bytes: SuffixBytes =
@@ -239,7 +229,7 @@ where
avb_ops,
&requested_partitions,
Some(avb_suffix),
- SlotVerifyFlags::AVB_SLOT_VERIFY_FLAGS_NONE,
+ slot_verify_flags,
HashtreeErrorMode::AVB_HASHTREE_ERROR_MODE_EIO,
)
.map_err(|v| v.without_verify_data())?,
@@ -414,7 +404,7 @@ where
&mut self,
avb_ops: &mut impl avb::Ops<'b>,
partitions_ram_map: &'d mut [PartitionRamMap<'b, 'c>],
- avb_verification_flags: AvbVerificationFlags,
+ slot_verify_flags: SlotVerifyFlags,
slot_cursor: Cursor<B, impl Manager>,
kernel_load_buffer: &mut [u8],
ramdisk_load_buffer: &mut [u8],
@@ -431,7 +421,7 @@ where
&mut ramdisk,
kernel_load_buffer,
partitions_ram_map,
- avb_verification_flags,
+ slot_verify_flags,
slot_cursor,
)?;
@@ -463,7 +453,7 @@ where
ramdisk: &mut Ramdisk,
kernel_load_buffer: &'e mut [u8],
partitions_ram_map: &'d mut [PartitionRamMap<'b, 'c>],
- avb_verification_flags: AvbVerificationFlags,
+ slot_verify_flags: SlotVerifyFlags,
mut slot_cursor: Cursor<B, impl Manager>,
) -> Result<(KernelImage<'e>, BootToken)> {
let mut oneshot_status = slot_cursor.ctx.get_oneshot_status();
@@ -486,7 +476,7 @@ where
.load_and_verify_image(
avb_ops,
partitions_ram_map,
- AvbVerificationFlags(0),
+ slot_verify_flags,
Some(boot_target),
)
.map_err(|e: IntegrationError| {
@@ -558,13 +548,6 @@ where
}
}
-#[cfg(feature = "sw_digest")]
-impl<'a> Default for Gbl<'a, DefaultGblOps> {
- fn default() -> Self {
- GblBuilder::new(DefaultGblOps::new()).build()
- }
-}
-
/// Builder for GBL object
#[derive(Debug)]
pub struct GblBuilder<'a, G>
@@ -610,15 +593,14 @@ where
#[cfg(test)]
mod tests {
+ extern crate avb_sysdeps;
extern crate avb_test;
use super::*;
use avb::IoError;
use avb::IoResult as AvbIoResult;
use avb::PublicKeyForPartitionInfo;
- #[cfg(feature = "sw_digest")]
- use avb_test::TestOps;
- #[cfg(feature = "sw_digest")]
- use std::fs;
+ use avb_test::{FakeVbmetaKey, TestOps};
+ use std::{fs, path::Path};
struct AvbOpsUnimplemented {}
impl avb::Ops<'_> for AvbOpsUnimplemented {
@@ -663,68 +645,78 @@ mod tests {
}
}
- #[cfg(feature = "sw_digest")]
#[test]
fn test_load_and_verify_image_avb_io_error() {
- let mut gbl = GblBuilder::new(DefaultGblOps::new()).build();
+ let mut gbl_ops = DefaultGblOps {};
+ let mut gbl = GblBuilder::new(&mut gbl_ops).build();
let mut avb_ops = AvbOpsUnimplemented {};
let mut partitions_ram_map: [PartitionRamMap; 0] = [];
- let avb_verification_flags = AvbVerificationFlags(0);
let res = gbl.load_and_verify_image(
&mut avb_ops,
&mut partitions_ram_map,
- avb_verification_flags,
+ SlotVerifyFlags::AVB_SLOT_VERIFY_FLAGS_NONE,
None,
);
- assert_eq!(res.unwrap_err(), Error::AvbSlotVerifyError(SlotVerifyError::Io));
+ assert_eq!(res.unwrap_err(), IntegrationError::AvbSlotVerifyError(SlotVerifyError::Io));
}
- const TEST_PARTITION_NAME: &str = "test_part";
- const TEST_IMAGE_PATH: &str = "testdata/test_image.img";
- const TEST_VBMETA_PATH: &str = "testdata/test_vbmeta.img";
- const TEST_PUBLIC_KEY_PATH: &str = "testdata/testkey_rsa4096_pub.bin";
+ const TEST_ZIRCON_PARTITION_NAME: &str = "zircon_a";
+ const TEST_ZIRCON_IMAGE_PATH: &str = "zircon_a.bin";
+ const TEST_ZIRCON_VBMETA_PATH: &str = "zircon_a.vbmeta";
+ const TEST_PUBLIC_KEY_PATH: &str = "testkey_rsa4096_pub.bin";
const TEST_VBMETA_ROLLBACK_LOCATION: usize = 0; // Default value, we don't explicitly set this.
- #[cfg(feature = "sw_digest")]
+ /// Returns the contents of a test data file.
+ ///
+ /// Panicks if the requested file cannot be read.
+ ///
+ /// # Arguments
+ /// * `path`: file path relative to libgbl's `testdata/` directory.
+ fn testdata(path: &str) -> Vec<u8> {
+ let full_path = Path::new("external/gbl/libgbl/testdata").join(path);
+ fs::read(full_path).unwrap()
+ }
+
#[test]
fn test_load_and_verify_image_stub() {
- let mut gbl = GblBuilder::new(DefaultGblOps::new()).build();
+ let mut gbl_ops = DefaultGblOps {};
+ let mut gbl = GblBuilder::new(&mut gbl_ops).build();
let mut avb_ops = TestOps::default();
- avb_ops.add_partition(TEST_PARTITION_NAME, fs::read(TEST_IMAGE_PATH).unwrap());
- avb_ops.add_partition("vbmeta", fs::read(TEST_VBMETA_PATH).unwrap());
- avb_ops.add_vbmeta_key(fs::read(TEST_PUBLIC_KEY_PATH).unwrap(), None, true);
+ avb_ops.add_partition(TEST_ZIRCON_PARTITION_NAME, testdata(TEST_ZIRCON_IMAGE_PATH));
+ avb_ops.add_partition("vbmeta", testdata(TEST_ZIRCON_VBMETA_PATH));
+ avb_ops.default_vbmeta_key = Some(FakeVbmetaKey::Avb {
+ public_key: testdata(TEST_PUBLIC_KEY_PATH),
+ public_key_metadata: None,
+ });
avb_ops.rollbacks.insert(TEST_VBMETA_ROLLBACK_LOCATION, 0);
avb_ops.unlock_state = Ok(false);
let mut partitions_ram_map: [PartitionRamMap; 0] = [];
- let avb_verification_flags = AvbVerificationFlags(0);
let res = gbl.load_and_verify_image(
&mut avb_ops,
&mut partitions_ram_map,
- avb_verification_flags,
+ SlotVerifyFlags::AVB_SLOT_VERIFY_FLAGS_NONE,
None,
);
assert!(res.is_ok());
}
- #[cfg(feature = "sw_digest")]
#[test]
fn test_load_and_verify_image_avb_error() {
const TEST_ERROR: SlotVerifyError<'static> = SlotVerifyError::Verification(None);
let expected_error = SlotVerifyError::Verification(None);
- let mut gbl = GblBuilder::new(DefaultGblOps::new())
- .verify_slot(|_, _, _, _, _| Err(TEST_ERROR))
- .build();
+ let mut gbl_ops = DefaultGblOps {};
+ let mut gbl =
+ GblBuilder::new(&mut gbl_ops).verify_slot(|_, _, _, _, _| Err(TEST_ERROR)).build();
let mut avb_ops = AvbOpsUnimplemented {};
let mut partitions_ram_map: [PartitionRamMap; 0] = [];
- let avb_verification_flags = AvbVerificationFlags(0);
let res = gbl.load_and_verify_image(
&mut avb_ops,
&mut partitions_ram_map,
- avb_verification_flags,
+ SlotVerifyFlags::AVB_SLOT_VERIFY_FLAGS_NONE,
None,
);
- assert_eq!(res.unwrap_err(), Error::AvbSlotVerifyError(TEST_ERROR));
+ assert_eq!(res.unwrap_err(), IntegrationError::AvbSlotVerifyError(TEST_ERROR));
}
}
diff --git a/gbl/libgbl/src/ops.rs b/gbl/libgbl/src/ops.rs
index b89547d..6063c4c 100644
--- a/gbl/libgbl/src/ops.rs
+++ b/gbl/libgbl/src/ops.rs
@@ -19,15 +19,11 @@ extern crate alloc;
#[cfg(test)]
extern crate static_assertions;
-use crate::digest::{Algorithm, Context};
use crate::error::{Error, Result as GblResult};
-#[cfg(feature = "sw_digest")]
-use crate::sw_digest::SwContext;
#[cfg(feature = "alloc")]
use alloc::ffi::CString;
use core::{
fmt::{Debug, Write},
- ptr::NonNull,
result::Result,
};
use gbl_storage::{
@@ -57,7 +53,7 @@ pub enum BootImages<'a> {
}
/// `GblOpsError` is the error type returned by required methods in `GblOps`.
-#[derive(Default, Debug)]
+#[derive(Default, Debug, PartialEq, Eq)]
pub struct GblOpsError(Option<&'static str>);
// https://stackoverflow.com/questions/41081240/idiomatic-callbacks-in-rust
@@ -70,9 +66,6 @@ missing:
*/
/// Trait that defines callbacks that can be provided to Gbl.
pub trait GblOps {
- /// Digest context type
- type Context: Context;
-
/// Iterates block devices on the platform.
///
/// For each block device, implementation should call `f` with its 1) `BlockIo` trait
@@ -99,23 +92,13 @@ pub trait GblOps {
/// Implementation is not expected to return on success.
fn boot(&mut self, boot_images: BootImages) -> Result<(), GblOpsError>;
- /// Create digest object to use for hash computations.
- ///
- /// Context interface allows to update value adding more data to process.
- /// # Arguments
- ///
- /// * algorithm - algorithm to use for hash computation.
- fn new_digest(&self, algorithm: Algorithm) -> Self::Context {
- Context::new(algorithm)
- }
-
- /// Calculate digest of provided data with requested algorithm. Single use unlike [new_digest]
- /// flow.
- fn digest(&self, algorithm: Algorithm, data: &[u8]) -> <Self::Context as Context>::Digest {
- let mut ctx = self.new_digest(algorithm);
- ctx.update(data);
- ctx.finish()
- }
+ // TODO(b/334962570): figure out how to plumb ops-provided hash implementations into
+ // libavb. The tricky part is that libavb hashing APIs are global with no way to directly
+ // correlate the implementation to a particular [GblOps] object, so we'll probably have to
+ // create a [Context] ahead of time and store it globally for the hashing APIs to access.
+ // However this would mean that [Context] must be a standalone object and cannot hold a
+ // reference to [GblOps], which may restrict implementations.
+ // fn new_digest(&self) -> Option<Self::Context>;
/// Callback for when fastboot mode is requested.
// Nevertype could be used here when it is stable https://github.com/serde-rs/serde/issues/812
@@ -214,19 +197,23 @@ impl<T: GblOps> Write for GblUtils<'_, '_, T> {
#[derive(Debug)]
pub struct DefaultGblOps {}
-#[cfg(feature = "sw_digest")]
impl GblOps for DefaultGblOps {
- type Context = SwContext;
-}
+ fn visit_block_devices(
+ &mut self,
+ f: &mut dyn FnMut(&mut dyn BlockIo, u64, u64),
+ ) -> Result<(), GblOpsError> {
+ Err(GblOpsError(Some("unimplemented")))
+ }
-#[cfg(test)]
-static_assertions::const_assert_eq!(core::mem::size_of::<DefaultGblOps>(), 0);
-impl DefaultGblOps {
- /// Create new DefaultGblOps object
- pub fn new() -> &'static mut Self {
- let mut ptr: NonNull<Self> = NonNull::dangling();
- // SAFETY: Self is a ZST, asserted above, and ptr is appropriately aligned and nonzero by
- // NonNull::dangling()
- unsafe { ptr.as_mut() }
+ fn console_put_char(&mut self, ch: u8) -> Result<(), GblOpsError> {
+ Err(GblOpsError(Some("unimplemented")))
+ }
+
+ fn should_stop_in_fastboot(&mut self) -> Result<bool, GblOpsError> {
+ Err(GblOpsError(Some("unimplemented")))
+ }
+
+ fn boot(&mut self, boot_images: BootImages) -> Result<(), GblOpsError> {
+ Err(GblOpsError(Some("unimplemented")))
}
}
diff --git a/gbl/libgbl/src/sw_digest.rs b/gbl/libgbl/src/sw_digest.rs
deleted file mode 100644
index 5e745f1..0000000
--- a/gbl/libgbl/src/sw_digest.rs
+++ /dev/null
@@ -1,125 +0,0 @@
-// Copyright 2024, 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.
-
-//! Software implementation for GBL Digest trait.
-//!
-//! `sw_digest` feature is needed to use this implementation.
-
-extern crate ring;
-
-use crate::digest::{Algorithm, Context, Digest};
-
-impl From<Algorithm> for &ring::digest::Algorithm {
- fn from(val: Algorithm) -> Self {
- match val {
- Algorithm::SHA256 => &ring::digest::SHA256,
- Algorithm::SHA512 => &ring::digest::SHA512,
- }
- }
-}
-
-/// Software implementation for digest Context
-pub struct SwContext {
- algorithm: Algorithm,
- ring_context: ring::digest::Context,
-}
-
-impl Context for SwContext {
- type Digest = SwDigest;
-
- fn new(algorithm: Algorithm) -> Self
- where
- Self: Sized,
- {
- Self { algorithm, ring_context: ring::digest::Context::new(algorithm.into()) }
- }
-
- fn update(&mut self, input: &[u8]) {
- self.ring_context.update(input)
- }
-
- fn finish(self) -> SwDigest {
- SwDigest { algorithm: self.algorithm, ring_digest: self.ring_context.finish() }
- }
-
- fn algorithm(&self) -> &Algorithm {
- &self.algorithm
- }
-}
-
-/// Software implementation of Digest.
-pub struct SwDigest {
- algorithm: Algorithm,
- ring_digest: ring::digest::Digest,
-}
-
-impl AsRef<[u8]> for SwDigest {
- fn as_ref(&self) -> &[u8] {
- self.ring_digest.as_ref()
- }
-}
-
-impl Digest for SwDigest {
- fn algorithm(&self) -> &Algorithm {
- &self.algorithm
- }
-}
-
-mod tests {
- use super::*;
-
- // Compute digest on provided input using algorithm
- fn digest(algorithm: Algorithm, input: &[u8]) -> SwDigest {
- let mut ctx = SwContext::new(algorithm);
- ctx.update(input);
- ctx.finish()
- }
-
- #[test]
- fn test_swdigest_sha256() {
- let input = b"abc";
- let expected =
- hex::decode("BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD")
- .unwrap();
- assert_eq!(digest(Algorithm::SHA256, input).as_ref(), expected);
- }
-
- #[test]
- fn test_swdigest_sha512() {
- assert_eq!(
- digest(Algorithm::SHA512, b"abc").as_ref(),
- hex::decode(concat!(
- "DDAF35A193617ABACC417349AE20413112E6FA4E89A97EA2",
- "0A9EEEE64B55D39A2192992A274FC1A836BA3C23A3FEEBBD",
- "454D4423643CE80E2A9AC94FA54CA49F",
- ))
- .unwrap()
- );
- }
-
- #[test]
- fn test_swdigest_sha_partial() {
- let input = b"abc";
- let expected =
- hex::decode("BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD")
- .unwrap();
-
- let mut ctx = SwContext::new(Algorithm::SHA256);
- for i in input.chunks(input.len()) {
- ctx.update(i);
- }
-
- assert_eq!(ctx.finish().as_ref(), expected);
- }
-}
diff --git a/gbl/libgbl/testdata/README.md b/gbl/libgbl/testdata/README.md
deleted file mode 100644
index e14ec4f..0000000
--- a/gbl/libgbl/testdata/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
-Generating test image:
-```
-echo test > file.txt
-echo "file.txt=file.txt" > manifest
-zbi -o test_image.img manifest
-rm file.txt manifest
-```
diff --git a/gbl/libgbl/testdata/gen_test_data.py b/gbl/libgbl/testdata/gen_test_data.py
index a968917..2718571 100644..100755
--- a/gbl/libgbl/testdata/gen_test_data.py
+++ b/gbl/libgbl/testdata/gen_test_data.py
@@ -17,12 +17,25 @@
import os
import pathlib
+import random
+import shutil
import subprocess
+import tempfile
+from typing import List
SCRIPT_DIR = pathlib.Path(os.path.dirname(os.path.realpath(__file__)))
GPT_TOOL = pathlib.Path(SCRIPT_DIR.parents[1]) / "tools" / "gen_gpt_disk.py"
+AVB_DIR = pathlib.Path(SCRIPT_DIR.parents[4]) / "external" / "avb"
+AVB_TOOL = AVB_DIR / "avbtool.py"
+AVB_TEST_DATA_DIR = AVB_DIR / "test" / "data"
SZ_KB = 1024
+# RNG seed values. Keep the same seed value for a given file to ensure
+# reproducibility as much as possible; this will prevent adding a bunch of
+# unnecessary test binaries to the git history.
+RNG_SEED_SPARSE_TEST_RAW = 1
+RNG_SEED_ZIRCON = {"a": 2, "b": 3, "r": 4}
+
# A helper for writing bytes to a file at a given offset.
def write_file(file, offset, data):
@@ -32,58 +45,129 @@ def write_file(file, offset, data):
# Generates sparse image for flashing test
def gen_sparse_test_file():
- sz_kb = 1024
out_file_raw = SCRIPT_DIR / "sparse_test_raw.bin"
+ random.seed(RNG_SEED_SPARSE_TEST_RAW)
with open(out_file_raw, "wb") as f:
# 4k filled with 0x78563412
write_file(f, 0, b"\x12\x34\x56\x78" * 1024)
# 8k file hole (will become dont-care with the "-s" option)
# 12k raw data
- write_file(f, 12 * sz_kb, os.urandom(12 * sz_kb))
+ write_file(f, 12 * SZ_KB, random.randbytes(12 * SZ_KB))
# 8k filled with 0x78563412
- write_file(f, 24 * sz_kb, b"\x12\x34\x56\x78" * 1024 * 2)
+ write_file(f, 24 * SZ_KB, b"\x12\x34\x56\x78" * 1024 * 2)
# 12k raw data
- write_file(f, 32 * sz_kb, os.urandom(12 * sz_kb))
+ write_file(f, 32 * SZ_KB, random.randbytes(12 * SZ_KB))
# 4k filled with 0x78563412
- write_file(f, 44 * sz_kb, b"\x12\x34\x56\x78" * 1024)
+ write_file(f, 44 * SZ_KB, b"\x12\x34\x56\x78" * 1024)
# 8k filled with 0xEFCDAB90
- write_file(f, 48 * sz_kb, b"\x90\xab\xcd\xef" * 1024 * 2)
+ write_file(f, 48 * SZ_KB, b"\x90\xab\xcd\xef" * 1024 * 2)
+ # For now this requires that img2simg exists on $PATH.
+ # It can be built from an Android checkout via `m img2simg`; the resulting
+ # binary will be at out/host/linux-x86/bin/img2simg.
+ subprocess.run(["img2simg", "-s", out_file_raw, SCRIPT_DIR / "sparse_test.bin"])
subprocess.run(
- ["img2simg", "-s", out_file_raw, SCRIPT_DIR / "sparse_test.bin"])
- subprocess.run([
- "img2simg",
- "-s",
- out_file_raw,
- SCRIPT_DIR / "sparse_test_blk1024.bin",
- "1024",
- ])
+ [
+ "img2simg",
+ "-s",
+ out_file_raw,
+ SCRIPT_DIR / "sparse_test_blk1024.bin",
+ "1024",
+ ]
+ )
# Generates GPT disk, kernel data for Zircon tests
def gen_zircon_gpt():
gen_gpt_args = []
for suffix in ["a", "b", "r"]:
- zircon = os.urandom(16 * SZ_KB)
+ random.seed(RNG_SEED_ZIRCON[suffix])
+ zircon = random.randbytes(16 * SZ_KB)
out_file = SCRIPT_DIR / f"zircon_{suffix}.bin"
out_file.write_bytes(zircon)
gen_gpt_args.append(f"--partition=zircon_{suffix},16K,{str(out_file)}")
- subprocess.run([GPT_TOOL, SCRIPT_DIR / "zircon_gpt.bin", "128K"] +
- gen_gpt_args,
- check=True)
+ subprocess.run(
+ [GPT_TOOL, SCRIPT_DIR / "zircon_gpt.bin", "128K"] + gen_gpt_args, check=True
+ )
# Generates test data for A/B slot Manager writeback test
def gen_writeback_test_bin():
- subprocess.run([
- GPT_TOOL, SCRIPT_DIR / "writeback_test_disk.bin", "64K",
- "--partition=test_partition,4k,/dev/zero"
- ],
- check=True)
+ subprocess.run(
+ [
+ GPT_TOOL,
+ SCRIPT_DIR / "writeback_test_disk.bin",
+ "64K",
+ "--partition=test_partition,4k,/dev/zero",
+ ],
+ check=True,
+ )
+
+
+def gen_vbmeta():
+ """Creates the vbmeta keys and signs some images."""
+ # Use the test vbmeta keys from libavb.
+ for name in ["testkey_rsa4096.pem", "testkey_rsa4096_pub.pem"]:
+ shutil.copyfile(AVB_TEST_DATA_DIR / name, SCRIPT_DIR / name)
+
+ # Convert the public key to raw bytes for use in verification.
+ subprocess.run(
+ [
+ AVB_TOOL,
+ "extract_public_key",
+ "--key",
+ SCRIPT_DIR / "testkey_rsa4096_pub.pem",
+ "--output",
+ SCRIPT_DIR / "testkey_rsa4096_pub.bin",
+ ],
+ check=True,
+ )
+
+ with tempfile.TemporaryDirectory() as temp_dir:
+ temp_dir = pathlib.Path(temp_dir)
+
+ # Create the hash descriptor. We only need this temporarily until we add
+ # it into the final vbmeta image.
+ hash_descriptor_path = temp_dir / "hash_descriptor.bin"
+ subprocess.run(
+ [
+ AVB_TOOL,
+ "add_hash_footer",
+ "--dynamic_partition_size",
+ "--do_not_append_vbmeta_image",
+ "--partition_name",
+ "zircon_a",
+ "--image",
+ SCRIPT_DIR / "zircon_a.bin",
+ "--output_vbmeta_image",
+ hash_descriptor_path,
+ "--salt",
+ "2000",
+ ],
+ check=True,
+ )
+
+ # Create the final signed vbmeta including the hash descriptor.
+ subprocess.run(
+ [
+ AVB_TOOL,
+ "make_vbmeta_image",
+ "--key",
+ SCRIPT_DIR / "testkey_rsa4096.pem",
+ "--algorithm",
+ "SHA512_RSA4096",
+ "--include_descriptors_from_image",
+ hash_descriptor_path,
+ "--output",
+ SCRIPT_DIR / "zircon_a.vbmeta",
+ ],
+ check=True,
+ )
-if __name__ == '__main__':
+if __name__ == "__main__":
gen_writeback_test_bin()
gen_sparse_test_file()
gen_zircon_gpt()
+ gen_vbmeta()
diff --git a/gbl/libgbl/testdata/sparse_test.bin b/gbl/libgbl/testdata/sparse_test.bin
index 009689e..f6c1a39 100644
--- a/gbl/libgbl/testdata/sparse_test.bin
+++ b/gbl/libgbl/testdata/sparse_test.bin
Binary files differ
diff --git a/gbl/libgbl/testdata/sparse_test_blk1024.bin b/gbl/libgbl/testdata/sparse_test_blk1024.bin
index e273137..c23fdf5 100644
--- a/gbl/libgbl/testdata/sparse_test_blk1024.bin
+++ b/gbl/libgbl/testdata/sparse_test_blk1024.bin
Binary files differ
diff --git a/gbl/libgbl/testdata/sparse_test_raw.bin b/gbl/libgbl/testdata/sparse_test_raw.bin
index ab13637..4ca95c7 100644
--- a/gbl/libgbl/testdata/sparse_test_raw.bin
+++ b/gbl/libgbl/testdata/sparse_test_raw.bin
Binary files differ
diff --git a/gbl/libgbl/testdata/test_image.img b/gbl/libgbl/testdata/test_image.img
deleted file mode 100644
index c988db1..0000000
--- a/gbl/libgbl/testdata/test_image.img
+++ /dev/null
Binary files differ
diff --git a/gbl/libgbl/testdata/testkey_rsa4096.pem b/gbl/libgbl/testdata/testkey_rsa4096.pem
index 6ffa543..26db5c3 100644
--- a/gbl/libgbl/testdata/testkey_rsa4096.pem
+++ b/gbl/libgbl/testdata/testkey_rsa4096.pem
@@ -1,51 +1,51 @@
-----BEGIN RSA PRIVATE KEY-----
-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
+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
-----END RSA PRIVATE KEY-----
diff --git a/gbl/libgbl/testdata/testkey_rsa4096.pub.pem b/gbl/libgbl/testdata/testkey_rsa4096.pub.pem
deleted file mode 100644
index 7ce6238..0000000
--- a/gbl/libgbl/testdata/testkey_rsa4096.pub.pem
+++ /dev/null
@@ -1,14 +0,0 @@
------BEGIN PUBLIC KEY-----
-MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxibxF3SoULtkS6RWQpuY
-H+N2JqLg4Dd5BkCueB0Ii0DGb1YN5/on+e9Czn+iaasA/DsOwpx1/+jCtPgHK08X
-w8sRxQWJ6LJ8uV+kZr1h8JMeG8XyMckBTdpEOzomuW691h+hphyHqxkv1VycnmwU
-kNz7QeEEKIZSXT07gC7cMDoJv4iDe+vrGlEh7Y5YrxkFJd86iEXFHDghoAxW/EFy
-I6bHbO7WQI38eexP1QceXyiz2YNx2krtj1pVyjQ0cLxOG/ZrRsjIffKNT5j9vLYD
-/JTybusC5G7FKuE2Y11jTPwhvsGqk8SBiGXmpPBuQXVdDYoU8pEntFfCvsHvoCml
-W0CSp6jyz/jlMeFqoydhkDQmpiP+p7SeXSwGIOdhlDQwyZg0j2THfLsr29deATvW
-kom43jllweZHDPN7Kxyyy4sCPpO3NXCMlVdaFL9F/EL6Ieptk6X1u5qOgz11f1Uw
-BKdLq/gx5wk4SwZLF1b1A2voBZvuQeJKb3iMwoWiE3sS2V2pT3eBI54nMehOgXaK
-fSLFxku7uAltHfW5i7tD5QEiHPNXUIfHRYwCucQ2lotKxSkoWB5+Q62pWHCP+1HG
-Gdfgt8nhfwsB/fdfJKkEy8MoVlCCGHxyvXgIKG8e85aVVm+Q+9/TtcJYr4osUDe9
-X5xISZ/2BTT7z5N1fLBFA4cCAwEAAQ==
------END PUBLIC KEY-----
diff --git a/gbl/libgbl/testdata/testkey_rsa4096_pub.bin b/gbl/libgbl/testdata/testkey_rsa4096_pub.bin
new file mode 100644
index 0000000..f2e8fbd
--- /dev/null
+++ b/gbl/libgbl/testdata/testkey_rsa4096_pub.bin
Binary files differ
diff --git a/gbl/libgbl/testdata/testkey_rsa4096_pub.pem b/gbl/libgbl/testdata/testkey_rsa4096_pub.pem
new file mode 100644
index 0000000..efd7144
--- /dev/null
+++ b/gbl/libgbl/testdata/testkey_rsa4096_pub.pem
@@ -0,0 +1,14 @@
+-----BEGIN PUBLIC KEY-----
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2ASv49OEbH4NiT3CjNMS
+VeliyfEPXswWcqtEfCxlSpS1FisAuwbvEwdTTPlkuSh6G4SYiNhnpCP5p0vcSg/3
+OhiuVKgV/rCtrDXaO60nvK/o0y83NNZRK2xaJ9eWBq9ruIDK+jC0sYWzTaqqwxY0
+Grjnx/r5CXerl5PrRK7PILzwgBHbIwxHcblt1ntgR4cWVpO3wiqasEwBDDDYk4fw
+7W6LvjBb9qav3YB8RV6PkZNeRP64ggfuecq/MXNiWOPNxLzCER2hSr/+J32h9jWj
+XsrcVy8+8Mldhmr4r2an7c247aFfupuFGtUJrpROO8/LXMl5gPfMpkqoatjTMRH5
+9gJjKhot0RpmGxZBvb33TcBK5SdJX39Y4yct5clmDlI4Fjj7FutTP+b96aJeJVnY
+eUX/A0wmogBajsJRoRX5e/RcgZsYRzXYLQXprQ81dBWjjovMJ9p8XeT6BNMFC7o6
+sklFL0fHDUE/l4BNP8G1u3BfpzevSCISRS71D4eS4oQB+RIPFBUkzomZ7rnEF3Bw
+Feq+xmwfYrP0LRaH+1YeRauuMuReke1TZl697a3mEjkNg8noa2wtpe7EWmaujJfX
+DWxJx/XEkjGLCe4z2qk3tkkY+A5gRcgzke8gVxC+eC2DJtbKYfkv4L8FMFJaEhwA
+p13MfC7FlYujO/BDLl7dANsCAwEAAQ==
+-----END PUBLIC KEY-----
diff --git a/gbl/libgbl/testdata/writeback_test_disk.bin b/gbl/libgbl/testdata/writeback_test_disk.bin
index ebb428d..50cbc21 100644
--- a/gbl/libgbl/testdata/writeback_test_disk.bin
+++ b/gbl/libgbl/testdata/writeback_test_disk.bin
Binary files differ
diff --git a/gbl/libgbl/testdata/zircon_a.bin b/gbl/libgbl/testdata/zircon_a.bin
index bd30d49..10e7ce4 100644
--- a/gbl/libgbl/testdata/zircon_a.bin
+++ b/gbl/libgbl/testdata/zircon_a.bin
Binary files differ
diff --git a/gbl/libgbl/testdata/zircon_a.vbmeta b/gbl/libgbl/testdata/zircon_a.vbmeta
new file mode 100644
index 0000000..13e15d1
--- /dev/null
+++ b/gbl/libgbl/testdata/zircon_a.vbmeta
Binary files differ
diff --git a/gbl/libgbl/testdata/zircon_b.bin b/gbl/libgbl/testdata/zircon_b.bin
index aa9faa9..fb38746 100644
--- a/gbl/libgbl/testdata/zircon_b.bin
+++ b/gbl/libgbl/testdata/zircon_b.bin
Binary files differ
diff --git a/gbl/libgbl/testdata/zircon_gpt.bin b/gbl/libgbl/testdata/zircon_gpt.bin
index 54624ff..f873c07 100644
--- a/gbl/libgbl/testdata/zircon_gpt.bin
+++ b/gbl/libgbl/testdata/zircon_gpt.bin
Binary files differ
diff --git a/gbl/libgbl/testdata/zircon_r.bin b/gbl/libgbl/testdata/zircon_r.bin
index 653837e..d7fd360 100644
--- a/gbl/libgbl/testdata/zircon_r.bin
+++ b/gbl/libgbl/testdata/zircon_r.bin
Binary files differ
diff --git a/gbl/libgbl/tests/integration_tests.rs b/gbl/libgbl/tests/integration_tests.rs
index e4764fe..ebbdcb4 100644
--- a/gbl/libgbl/tests/integration_tests.rs
+++ b/gbl/libgbl/tests/integration_tests.rs
@@ -14,10 +14,7 @@
use gbl_storage::BlockIo;
use gbl_storage_testlib::TestBlockIo;
-use libgbl::{
- digest::Algorithm, BootImages, Context, Digest, FuchsiaBootImages, GblBuilder, GblOps,
- GblOpsError,
-};
+use libgbl::{BootImages, FuchsiaBootImages, GblBuilder, GblOps, GblOpsError};
use std::{collections::VecDeque, vec::Vec};
extern crate avb_sysdeps;
@@ -52,8 +49,6 @@ impl TestGblOps<'_> {
}
impl GblOps for TestGblOps<'_> {
- type Context = TestDigestContext;
-
fn visit_block_devices(
&mut self,
f: &mut dyn FnMut(&mut dyn BlockIo, u64, u64),
@@ -77,44 +72,6 @@ impl GblOps for TestGblOps<'_> {
}
}
-/// Placeholder.
-struct DigestBytes(Vec<u8>);
-
-impl AsRef<[u8]> for DigestBytes {
- fn as_ref(&self) -> &[u8] {
- self.0.as_ref()
- }
-}
-
-impl Digest for DigestBytes {
- fn algorithm(&self) -> &Algorithm {
- unimplemented!();
- }
-}
-
-/// Placeholder.
-struct TestDigestContext {}
-
-impl Context for TestDigestContext {
- type Digest = DigestBytes;
-
- fn new(_: Algorithm) -> Self {
- unimplemented!();
- }
-
- fn update(&mut self, _: &[u8]) {
- unimplemented!();
- }
-
- fn finish(self) -> Self::Digest {
- unimplemented!();
- }
-
- fn algorithm(&self) -> &Algorithm {
- unimplemented!();
- }
-}
-
/// `MustUse` wraps an object and checks that it is accessed at least once before it's dropped.
/// In this integration test, it is mainly used to check that test provided ops callbacks are run.
struct MustUse<T: ?Sized> {
diff --git a/gbl/libstorage/src/lib.rs b/gbl/libstorage/src/lib.rs
index 40d4a1c..8a27836 100644
--- a/gbl/libstorage/src/lib.rs
+++ b/gbl/libstorage/src/lib.rs
@@ -122,7 +122,7 @@ pub use multi_blocks::AsMultiBlockDevices;
pub type Result<T> = core::result::Result<T, StorageError>;
/// Error code for this library.
-#[derive(Debug, Copy, Clone, PartialEq)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum StorageError {
ArithmeticOverflow(safemath::Error),
BlockDeviceNotFound,
diff --git a/gbl/tools/gen_gpt_disk.py b/gbl/tools/gen_gpt_disk.py
index 09428e7..883880d 100755
--- a/gbl/tools/gen_gpt_disk.py
+++ b/gbl/tools/gen_gpt_disk.py
@@ -25,6 +25,8 @@ The following command creates a 16mb disk file gpt.bin with two partitions:
gen_gpt_disk.py ./gpt.bin 16M
--partition "boot_a,4096K,<path to file_a>" \
--partition "boot_b,8192K,"
+
+All GUIDs will be non-deterministic for reproducibility.
"""
import argparse
@@ -37,18 +39,46 @@ import tempfile
GPT_BLOCK_SIZE = 512
+# Some GPT libraries may expect a valid GUID here, these are just pre-generated
+# valid GUIDs for reproducibility.
+DISK_GUID = "b116114b-b6ae-4186-8231-b35104cb4c9e"
+PARTITION_GUIDS = [
+ "36bc51fd-c3d6-4109-a2ac-35bddd757e2a",
+ "42aaac2e-37e3-43ba-9930-42dfa96e6334",
+ "bdadfeca-879c-43e9-8f0d-8ef7da29b5e7",
+ "8d5b90b2-0d65-476b-8691-94f74fcac271",
+ "dafe682f-3f2b-4472-a1b8-a0f217701909",
+ "7097fd78-f559-461e-bb9b-db176a8169d8",
+ "c03dd176-117b-4e65-8205-37ebec007c1a",
+ "6d9159db-9b9e-4906-8fa4-31f5ffaef50e",
+ "4cdfda9f-23aa-4b27-9fea-24bb08238135",
+ "2a0a3df9-e8ef-4627-b4ce-ef1e847924f4",
+ "3c9b64f9-c659-4e5d-9d25-72028c46e6b8",
+ "95f142f9-d1f3-41ad-96dc-b969ee8242a1",
+ "5181811b-e836-4e66-bfe2-91aa86da515f",
+ "f2dbad77-38ac-43de-b4c7-2f7432d2339e",
+ "fc172d2c-f735-49a5-8be0-a475d0fc5be9",
+ "5ad48195-8e26-4496-a7e2-669028db2dce",
+ "f49a6965-8168-4c0c-8102-7b64a8176c25",
+ "be495262-5d9b-4fcb-9240-d9e84b195abe",
+ "c5ab3a8d-f898-420f-9039-a7445760fb0f",
+ "bc79912b-44bf-4ed8-8320-796ba47714d1",
+]
+
def parse_args():
parser = argparse.ArgumentParser()
- parser.add_argument('out', help="output file")
- parser.add_argument('disk_size',
- type=str,
- help="disk size of the image. i.e. 64k, 1M etc")
- parser.add_argument("--partition",
- type=str,
- action='append',
- help="specifies a partition. Format should be"
- "--partition=<part name>,<size>,<file name>")
+ parser.add_argument("out", help="output file")
+ parser.add_argument(
+ "disk_size", type=str, help="disk size of the image. i.e. 64k, 1M etc"
+ )
+ parser.add_argument(
+ "--partition",
+ type=str,
+ action="append",
+ help="specifies a partition. Format should be"
+ "--partition=<part name>,<size>,<file name>",
+ )
return parser.parse_args()
@@ -80,13 +110,12 @@ def _append(src_file: str, offset: int, size: int, dst_file: str):
Returns:
number of bytes actually copied.
"""
- with open(src_file, 'rb') as src_f:
+ with open(src_file, "rb") as src_f:
src_f.seek(offset, 0)
data = src_f.read(size)
if len(data) != size:
- raise ValueError(
- f"Want {size} bytes from {src_file}, but got {len(data)}.")
- with open(dst_file, 'ab') as dst_f:
+ raise ValueError(f"Want {size} bytes from {src_file}, but got {len(data)}.")
+ with open(dst_file, "ab") as dst_f:
dst_f.write(data)
return size
@@ -97,26 +126,34 @@ def main() -> int:
temp_disk = pathlib.Path(temp_dir) / "temp_disk"
disk_size = parse_size_str(args.disk_size)
- temp_disk.write_bytes(disk_size * b'\x00')
+ temp_disk.write_bytes(disk_size * b"\x00")
part_start = 34 * GPT_BLOCK_SIZE # MBR + GPT header + entries
partition_info = []
sgdisk_command = [
"sgdisk",
- str(temp_disk), "--clear", "--set-alignment", "1"
+ str(temp_disk),
+ "--clear",
+ "--set-alignment",
+ "1",
+ "--disk-guid",
+ DISK_GUID,
]
for i, part in enumerate(args.partition, start=1):
- name, size, file = part.split(',')
+ name, size, file = part.split(",")
if not size:
raise ValueError("Must provide a size")
size = parse_size_str(size)
sgdisk_command += [
"--new",
- f"{i}:{part_start // GPT_BLOCK_SIZE}:{(part_start + size) // GPT_BLOCK_SIZE - 1}"
+ f"{i}:{part_start // GPT_BLOCK_SIZE}:{(part_start + size) // GPT_BLOCK_SIZE - 1}",
+ "--partition-guid",
+ f"{i}:{PARTITION_GUIDS[i]}",
+ "--change-name",
+ f"{i}:{name}",
]
- sgdisk_command += ["--change-name", f"{i}:{name}"]
partition_info.append((name, part_start, size, file))
part_start += size
@@ -125,13 +162,14 @@ def main() -> int:
# Create the final disk with partition content
dest_file = pathlib.Path(args.out)
- dest_file.write_bytes(0 * b'\x00')
+ dest_file.write_bytes(0 * b"\x00")
append_offset = 0
for name, start, size, file in partition_info:
end = start + size
# Fill gap
- append_offset += _append(str(temp_disk), append_offset,
- start - append_offset, args.out)
+ append_offset += _append(
+ str(temp_disk), append_offset, start - append_offset, args.out
+ )
# Copy over file
if file:
@@ -142,15 +180,17 @@ def main() -> int:
# If partition size greater than file size, copy the remaining
# partition content from `temp_disk` (zeroes)
- append_offset += _append(str(temp_disk), append_offset,
- end - append_offset, args.out)
+ append_offset += _append(
+ str(temp_disk), append_offset, end - append_offset, args.out
+ )
# Copy the remaining disk from `temp_disk` (zeroes + back up header/entries)
- append_offset += _append(str(temp_disk), append_offset,
- disk_size - append_offset, args.out)
+ append_offset += _append(
+ str(temp_disk), append_offset, disk_size - append_offset, args.out
+ )
return 0
-if __name__ == '__main__':
+if __name__ == "__main__":
sys.exit(main())