summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-05-26 07:00:21 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-05-26 07:00:21 +0000
commit0118ae892029a0b39603683a99f8ea57f7b7b5f7 (patch)
tree10061290ba3cfbc5eca190ca3b3460a67e39df01
parent1426942d34a7a9d9b8bb9a5212ec0c6ad52adbcf (diff)
parent8ea03b70f66dc598fa0bd65f73668b614823c610 (diff)
downloadlibbootloader-busytown-mac-infra-release.tar.gz
Snap for 11878398 from 8ea03b70f66dc598fa0bd65f73668b614823c610 to busytown-mac-infra-releasebusytown-mac-infra-release
Change-Id: I49f82e1868092398ae8497b29055b048d9731c4b
-rw-r--r--gbl/BUILD37
-rw-r--r--gbl/README.md4
-rw-r--r--gbl/docs/efi_protocols.md65
-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
-rw-r--r--gbl/readme.bzl117
-rw-r--r--gbl/tests/BUILD1
-rwxr-xr-xgbl/tools/gen_gpt_disk.py92
31 files changed, 537 insertions, 389 deletions
diff --git a/gbl/BUILD b/gbl/BUILD
index e69de29..96485a3 100644
--- a/gbl/BUILD
+++ b/gbl/BUILD
@@ -0,0 +1,37 @@
+# Copyright (C) 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.
+
+load(":readme.bzl", "readme_test")
+
+readme_test(
+ name = "readme_test",
+ readme = "docs/efi_protocols.md",
+ # Note: can't read files in subpackages, not sure how to add a dependency on all,
+ # globbed, subpackages and all the rust_lib targets they contain.
+ deps = [
+ "@gbl//efi:main",
+ "@gbl//libavb:sysdeps",
+ "@gbl//libboot",
+ "@gbl//libbootconfig",
+ "@gbl//libbootimg",
+ "@gbl//libc",
+ "@gbl//libefi",
+ "@gbl//libfastboot",
+ "@gbl//libfdt",
+ "@gbl//libgbl",
+ "@gbl//libmisc",
+ "@gbl//libsafemath",
+ "@gbl//libstorage",
+ ],
+)
diff --git a/gbl/README.md b/gbl/README.md
index 430040a..d0b33c4 100644
--- a/gbl/README.md
+++ b/gbl/README.md
@@ -96,3 +96,7 @@ configurations:
-drive format=raw,file=fat:rw:/tmp/esp,id=blk0 \
-device virtio-blk-device,drive=blk0
```
+
+## EFI Protocols
+
+List of EFI protocols used by GBL and a brief description of each [here](./docs/efi_protocols.md).
diff --git a/gbl/docs/efi_protocols.md b/gbl/docs/efi_protocols.md
new file mode 100644
index 0000000..32d09f3
--- /dev/null
+++ b/gbl/docs/efi_protocols.md
@@ -0,0 +1,65 @@
+The EFI application of GBL requires certain EFI protocols in order to boot,
+and can require other protocols for certain targets or to enable optional features.
+
+### Required Protocols
+
+#### BlockIoProtocol
+
+The BlockIo protocol is required for loading system images from disk.
+If a target supports Fastboot mode, it is also used for writing images to disk.
+
+#### SimpleTextOutputProtocol
+
+The SimpleTextOutput protocol is used for logging
+and the text-based interface of Fastboot.
+On systems where there is no output functionality,
+this can be implemented as a series of no-op functions.
+
+### Conditionally Required Protocols
+
+#### RiscvBootProtocol
+
+Determines the boot hart ID which is then passed to the kernel.
+Only required for RISC-V targets.
+
+### Optional Protocols
+
+#### AndroidBootProtocol
+
+This is a custom protocol intended to provide
+specific functionality needed to boot Android.
+A full description is available [here](./EFI_ANDROID_BOOT_PROTOCOL.md).
+
+#### DevicePathProtocol
+
+The DevicePath protocol is a variable length binary structure
+made of variable length Device Path nodes.
+A handle representing a hardware resource is mapped
+to the protocol and provides specific data about that resource.
+
+If all three of DevicePath protocol, DevicePathToText protocol,
+and LoadedImage protocol are present, the GBL image path is logged
+to the console on load.
+
+This is a useful proof of concept for development to demonstrate
+that GBL is running and can interact with the UEFI environment.
+
+#### DevicePathToTextProtocol
+
+The DevicePathToText protocol converts device paths and nodes to text.
+
+#### LoadedImageProtocol
+
+The LoadedImage protocol can be used on the handle of an image to provide
+information about the image, including its device handle and device path.
+
+#### SimpleNetworkProtocol
+
+If present, the SimpleNetwork protocol is used to provide Fastboot over TCP.
+No other EFI protocols are required: GBL wraps SimpleNetwork to provide TCP.
+
+Note: for security reasons, Fastboot over TCP is only available in dev builds.
+
+#### SimpleTextInputProtocol
+
+TODO: remove this protocol
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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
+MIIJKQIBAAKCAgEA2ASv49OEbH4NiT3CjNMSVeliyfEPXswWcqtEfCxlSpS1FisA
+uwbvEwdTTPlkuSh6G4SYiNhnpCP5p0vcSg/3OhiuVKgV/rCtrDXaO60nvK/o0y83
+NNZRK2xaJ9eWBq9ruIDK+jC0sYWzTaqqwxY0Grjnx/r5CXerl5PrRK7PILzwgBHb
+IwxHcblt1ntgR4cWVpO3wiqasEwBDDDYk4fw7W6LvjBb9qav3YB8RV6PkZNeRP64
+ggfuecq/MXNiWOPNxLzCER2hSr/+J32h9jWjXsrcVy8+8Mldhmr4r2an7c247aFf
+upuFGtUJrpROO8/LXMl5gPfMpkqoatjTMRH59gJjKhot0RpmGxZBvb33TcBK5SdJ
+X39Y4yct5clmDlI4Fjj7FutTP+b96aJeJVnYeUX/A0wmogBajsJRoRX5e/RcgZsY
+RzXYLQXprQ81dBWjjovMJ9p8XeT6BNMFC7o6sklFL0fHDUE/l4BNP8G1u3Bfpzev
+SCISRS71D4eS4oQB+RIPFBUkzomZ7rnEF3BwFeq+xmwfYrP0LRaH+1YeRauuMuRe
+ke1TZl697a3mEjkNg8noa2wtpe7EWmaujJfXDWxJx/XEkjGLCe4z2qk3tkkY+A5g
+Rcgzke8gVxC+eC2DJtbKYfkv4L8FMFJaEhwAp13MfC7FlYujO/BDLl7dANsCAwEA
+AQKCAgAWoL8P/WsktjuSwb5sY/vKtgzcHH1Ar942GsysuTXPDy686LpF3R8T/jNy
+n7k2UBAia8xSoWCR6BbRuHeV5oA+PLGeOpE7QaSfonB+yc+cy0x3Or3ssfqEsu/q
+toGHp75/8DXS6WE0K04x94u1rdC9b9sPrrGBlWCLGzqM0kbuJfyHXdd3n2SofAUO
+b5QRSgxD+2tHUpEroHqHnWJCaf4J0QegX45yktlfOYNK/PHLDQXV8ly/ejc32M4Y
+Tv7hUtOOJTuq8VCg9OWZm2Zo1QuM9XEJTPCp5l3+o5vzO6yhk2gotDvD32CdA+3k
+tLJRP54M1Sn+IXb1gGKN9rKAtGJbenWIPlNObhQgkbwG89Qd+5rfMXsiPv1Hl1tK
++tqwjD82/H3/ElaaMnwHCpeoGSp95OblAoBjzjMP2KsbvKSdL8O/rf1c3uOw9+DF
+cth0SA8y3ZzI11gJtb2QMGUrCny5n4sPGGbc3x38NdLhwbkPKZy60OiT4g2kNpdY
+dIitmAML2otttiF4AJM6AraPk8YVzkPLTksoL3azPBya5lIoDI2H3QvTtSvpXkXP
+yKchsDSWYbdqfplqC/X0Djp2/Zd8jpN5I6+1aSmpTmbwx/JTllY1N89FRZLIdxoh
+2k81LPiXhE6uRbjioJUlbnEWIpY2y2N2Clmxpjh0/IcXd1XImQKCAQEA7Zai+yjj
+8xit24aO9Tf3mZBXBjSaDodjC2KS1yCcAIXp6S7aH0wZipyZpQjys3zaBQyMRYFG
+bQqIfVAa6inWyDoofbAJHMu5BVcHFBPZvSS5YhDjc8XZ5dqSCxzIz9opIqAbm+b4
+aEV/3A3Jki5Dy8y/5j21GAK4Y4mqQOYzne7bDGi3Hyu041MGM4qfIcIkS5N1eHW4
+sDZJh6+K5tuxN5TX3nDZSpm9luNH8mLGgKAZ15b1LqXAtM5ycoBY9Hv082suPPom
+O+r0ybdRX6nDSH8+11y2KiP2kdVIUHCGkwlqgrux5YZyjCZPwOvEPhzSoOS+vBiF
+UVXA8idnxNLk1QKCAQEA6MIihDSXx+350fWqhQ/3Qc6gA/t2C15JwJ9+uFWA+gjd
+c/hn5HcmnmBJN4R04nLG/aU9SQur87a4mnC/Mp9JIARjHlZ/WNT4U0sJyPEVRg5U
+Z9VajAucWwi0JyJYCO1EMMy68Jp8qlTriK/L7nbD86JJ5ASxjojiN/0psK/Pk60F
+Rr+shKPi3jRQ1BDjDtAxOfo4ctf/nFbUM4bY0FNPQMP7WesoSKU0NBCRR6d0d2tq
+YflMjIQHx+N74P5jEdSCHTVGQm+dj47pUt3lLPLWc0bX1G/GekwXP4NUsR/70Hsi
+bwxkNnK2TSGzkt2rcOnutP125rJu6WpV7SNrq9rm7wKCAQAfMROcnbWviKHqnDPQ
+hdR/2K9UJTvEhInASOS2UZWpi+s1rez9BuSjigOx4wbaAZ4t44PW7C3uyt84dHfU
+HkIQb3I5bg8ENMrJpK9NN33ykwuzkDwMSwFcZ+Gci97hSubzoMl/IkeiiN1MapL4
+GhLUgsD+3UMVL+Y9SymK8637IgyoCGdiND6/SXsa8SwLJo3VTjqx4eKpX7cvlSBL
+RrRxc50TmwUsAhsd4CDl9YnSATLjVvJBeYlfM2tbFPaYwl1aR8v+PWkfnK0efm60
+fHki33HEnGteBPKuGq4vwVYpn6bYGwQz+f6335/A2DMfZHFSpjVURHPcRcHbCMla
+0cUxAoIBAQC25eYNkO478mo+bBbEXJlkoqLmvjAyGrNFo48F9lpVH6Y0vNuWkXJN
+PUgLUhAu6RYotjGENqG17rz8zt/PPY9Ok2P3sOx8t00y1mIn/hlDZXs55FM0fOMu
+PZaiscAPs7HDzvyOmDah+fzi+ZD8H2M3DS2W+YE0iaeJa2vZJS2t02W0BGXiDI33
+IZDqMyLYvwwPjOnShJydEzXID4xLl0tNjzLxo3GSNA7jYqlmbtV8CXIc7rMSL6WV
+ktIDKKJcnmpn3TcKeX6MEjaSIT82pNOS3fY3PmXuL+CMzfw8+u77Eecq78fHaTiL
+P5JGM93F6mzi19EY0tmInUBMCWtQLcENAoIBAQCg0KaOkb8T36qzPrtgbfou0E2D
+ufdpL1ugmD4edOFKQB5fDFQhLnSEVSJq3KUg4kWsXapQdsBd6kLdxS+K6MQrLBzr
+4tf0c7UCF1AzWk6wXMExZ8mRb2RkGZYQB2DdyhFB3TPmnq9CW8JCq+6kxg/wkU4s
+vM4JXzgcqVoSf42QJl+B9waeWhg0BTWx01lal4ds88HvEKmE0ik5GwiDbr7EvDDw
+E6UbZtQcIoSTIIZDgYqVFfR2DAho3wXJRsOXh433lEJ8X7cCDzrngFbQnlKrpwML
+Xgm0SIUc+Nf5poMM3rfLFK77t/ob4w+5PwRKcoSniyAxrHd6bwykYA8Vuydv
-----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/readme.bzl b/gbl/readme.bzl
new file mode 100644
index 0000000..cc8bdc9
--- /dev/null
+++ b/gbl/readme.bzl
@@ -0,0 +1,117 @@
+# Copyright (C) 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.
+
+"""
+Action that verifies all EFI protocols used by GBL are explicitly listed in README.md
+"""
+
+load("@rules_rust//rust/private:providers.bzl", "CrateInfo")
+
+def _readme_test_rule_impl(ctx):
+ shell_script = """
+while [[ $# -gt 0 ]]; do
+ case $1 in
+ --in)
+ INPUT=$2
+ shift
+ shift
+ ;;
+ --out)
+ OUTPUT=$2
+ shift
+ shift
+ ;;
+ --readme)
+ README=$2
+ shift
+ shift
+ ;;
+ *)
+ echo "Unexpected argument: $1"
+ exit 1
+ ;;
+ esac
+done
+
+if [ ! -f $README ]; then
+ echo "README file doesn't exist: ${README}"
+ exit 1
+fi
+
+ALL_INPUTS=$(echo ${INPUT} | sed 's/,/ /g')
+
+DOCLESS_PROTOCOLS=""
+PROTOCOLS=($(grep -hE 'impl ProtocolInfo for .* \\{' ${ALL_INPUTS} | awk '{print $4}' | sort))
+for P in ${PROTOCOLS[@]}
+do
+ grep -Lq $P ${README} || DOCLESS_PROTOCOLS+="\n\t$P"
+done
+
+if [ ! -z "${DOCLESS_PROTOCOLS}" ]; then
+ echo -e "Missing documentation for protocol(s):$DOCLESS_PROTOCOLS"
+ exit 1
+fi
+
+UNUSED_PROTOCOLS=""
+README_PROTOCOLS=($(grep -P " ?.*?Protocol$" ${README} | awk '{print $NF}' | sort | uniq))
+for P in ${README_PROTOCOLS[@]}
+do
+ grep -qhE "impl ProtocolInfo for $P" ${ALL_INPUTS} || UNUSED_PROTOCOLS+="\n\t$P"
+done
+
+if [ ! -z "${UNUSED_PROTOCOLS}" ]; then
+ echo -e "Unused protocol(s) found in documentation:$UNUSED_PROTOCOLS"
+ exit 1
+fi
+
+touch $OUTPUT
+"""
+
+ out_file = ctx.actions.declare_file("%s.script" % ctx.attr.name)
+ in_files = [s for d in ctx.attr.deps for s in d[CrateInfo].srcs.to_list()]
+ readme = ctx.attr.readme
+ args = ctx.actions.args()
+ args.add_joined(
+ "--in",
+ in_files,
+ join_with = ",",
+ )
+ args.add(
+ "--out",
+ out_file,
+ )
+ args.add(
+ "--readme",
+ readme[DefaultInfo].files.to_list()[0],
+ )
+ ctx.actions.run_shell(
+ inputs = in_files + readme[DefaultInfo].files.to_list(),
+ outputs = [out_file],
+ arguments = [args],
+ command = shell_script,
+ )
+ return [DefaultInfo(executable = out_file)]
+
+readme_test = rule(
+ implementation = _readme_test_rule_impl,
+ attrs = {
+ "deps": attr.label_list(
+ providers = [CrateInfo],
+ ),
+ "readme": attr.label(
+ allow_single_file = [".md"],
+ ),
+ },
+ test = True,
+)
diff --git a/gbl/tests/BUILD b/gbl/tests/BUILD
index 3a9fbda..e51b5cd 100644
--- a/gbl/tests/BUILD
+++ b/gbl/tests/BUILD
@@ -15,6 +15,7 @@
test_suite(
name = "tests",
tests = [
+ "@gbl//:readme_test",
"@gbl//libabr:libabr_tests",
"@gbl//libbootconfig:libbootconfig_test",
"@gbl//libbootimg:libbootimg_test",
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())