Merge "Logging improvements"
diff --git a/libs/avb/Android.bp b/libs/avb/Android.bp
index 1d257bc..c173f1c 100644
--- a/libs/avb/Android.bp
+++ b/libs/avb/Android.bp
@@ -20,7 +20,7 @@
"--ctypes-prefix=core::ffi",
],
static_libs: [
- "libavb",
+ "libavb_non_debug",
],
shared_libs: [
"libcrypto",
diff --git a/libs/dice/src/lib.rs b/libs/dice/src/lib.rs
index 9bbacc6..5332092 100644
--- a/libs/dice/src/lib.rs
+++ b/libs/dice/src/lib.rs
@@ -23,15 +23,12 @@
use core::ptr;
use core::result;
+pub use open_dice_cbor_bindgen::DiceMode;
+
use open_dice_cbor_bindgen::DiceConfigType_kDiceConfigTypeDescriptor as DICE_CONFIG_TYPE_DESCRIPTOR;
use open_dice_cbor_bindgen::DiceConfigType_kDiceConfigTypeInline as DICE_CONFIG_TYPE_INLINE;
use open_dice_cbor_bindgen::DiceHash;
use open_dice_cbor_bindgen::DiceInputValues;
-use open_dice_cbor_bindgen::DiceMode;
-use open_dice_cbor_bindgen::DiceMode_kDiceModeDebug as DICE_MODE_DEBUG;
-use open_dice_cbor_bindgen::DiceMode_kDiceModeMaintenance as DICE_MODE_MAINTENANCE;
-use open_dice_cbor_bindgen::DiceMode_kDiceModeNormal as DICE_MODE_NORMAL;
-use open_dice_cbor_bindgen::DiceMode_kDiceModeNotInitialized as DICE_MODE_NOT_INITIALIZED;
use open_dice_cbor_bindgen::DiceResult;
use open_dice_cbor_bindgen::DiceResult_kDiceResultBufferTooSmall as DICE_RESULT_BUFFER_TOO_SMALL;
use open_dice_cbor_bindgen::DiceResult_kDiceResultInvalidInput as DICE_RESULT_INVALID_INPUT;
@@ -90,26 +87,6 @@
}
}
-/// DICE mode values.
-#[derive(Clone, Copy, Debug)]
-pub enum Mode {
- /// At least one security mechanism has not been configured. Also acts as a catch-all.
- /// Invalid mode values should be treated like this mode.
- NotInitialized = DICE_MODE_NOT_INITIALIZED as _,
- /// Indicates the device is operating normally under secure configuration.
- Normal = DICE_MODE_NORMAL as _,
- /// Indicates at least one criteria for Normal mode is not met.
- Debug = DICE_MODE_DEBUG as _,
- /// Indicates a recovery or maintenance mode of some kind.
- Maintenance = DICE_MODE_MAINTENANCE as _,
-}
-
-impl From<Mode> for DiceMode {
- fn from(mode: Mode) -> Self {
- mode as Self
- }
-}
-
/// DICE configuration input type.
#[derive(Debug)]
pub enum ConfigType<'a> {
@@ -132,7 +109,7 @@
config: &ConfigType,
auth_hash: Option<&Hash>,
auth_descriptor: Option<&[u8]>,
- mode: Mode,
+ mode: DiceMode,
hidden: Option<&Hidden>,
) -> Self {
const ZEROED_INLINE_CONFIG: InlineConfig = [0; INLINE_CONFIG_SIZE];
@@ -157,7 +134,7 @@
authority_hash: auth_hash.map_or([0; mem::size_of::<Hash>()], |h| *h),
authority_descriptor,
authority_descriptor_size,
- mode: mode.into(),
+ mode,
hidden: hidden.map_or([0; mem::size_of::<Hidden>()], |h| *h),
})
}
diff --git a/libs/libfdt/src/lib.rs b/libs/libfdt/src/lib.rs
index 8fd1879..29d7abe 100644
--- a/libs/libfdt/src/lib.rs
+++ b/libs/libfdt/src/lib.rs
@@ -388,6 +388,23 @@
fdt_err_expect_zero(ret)
}
+ /// Create or change a property name-value pair to the given node.
+ pub fn setprop(&mut self, name: &CStr, value: &[u8]) -> Result<()> {
+ // SAFETY - New value size is constrained to the DT totalsize
+ // (validated by underlying libfdt).
+ let ret = unsafe {
+ libfdt_bindgen::fdt_setprop(
+ self.fdt.as_mut_ptr(),
+ self.offset,
+ name.as_ptr(),
+ value.as_ptr().cast::<c_void>(),
+ value.len().try_into().map_err(|_| FdtError::BadValue)?,
+ )
+ };
+
+ fdt_err_expect_zero(ret)
+ }
+
/// Get reference to the containing device tree.
pub fn fdt(&mut self) -> &mut Fdt {
self.fdt
diff --git a/microdroid_manager/src/dice.rs b/microdroid_manager/src/dice.rs
index 499835f..e740ed4 100644
--- a/microdroid_manager/src/dice.rs
+++ b/microdroid_manager/src/dice.rs
@@ -17,7 +17,7 @@
use anyhow::{bail, Context, Error, Result};
use byteorder::{NativeEndian, ReadBytesExt};
use diced_open_dice_cbor::{
- Config, ContextImpl, InputValuesOwned, Mode, OpenDiceCborContext, CDI_SIZE, HASH_SIZE,
+ Config, ContextImpl, DiceMode, InputValuesOwned, OpenDiceCborContext, CDI_SIZE, HASH_SIZE,
HIDDEN_SIZE,
};
use keystore2_crypto::ZVec;
@@ -148,7 +148,7 @@
Config::Descriptor(config_desc),
authority_hash,
None,
- if debug { Mode::Debug } else { Mode::Normal },
+ if debug { DiceMode::kDiceModeDebug } else { DiceMode::kDiceModeNormal },
hidden,
);
let (cdi_attest, cdi_seal, bcc) = match &self {
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index f1c41b9..13bc9e3 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -53,6 +53,7 @@
use std::borrow::Cow::{Borrowed, Owned};
use std::convert::TryInto;
use std::env;
+use std::ffi::CString;
use std::fs::{self, create_dir, OpenOptions};
use std::io::Write;
use std::os::unix::process::CommandExt;
@@ -216,13 +217,21 @@
match try_run_payload(&service) {
Ok(code) => {
- info!("notifying payload finished");
- service.notifyPayloadFinished(code)?;
if code == 0 {
info!("task successfully finished");
} else {
error!("task exited with exit code: {}", code);
}
+ if let Err(e) = post_payload_work() {
+ error!(
+ "Failed to run post payload work. It is possible that certain tasks
+ like syncing encrypted store might be incomplete. Error: {:?}",
+ e
+ );
+ };
+
+ info!("notifying payload finished");
+ service.notifyPayloadFinished(code)?;
Ok(())
}
Err(err) => {
@@ -233,6 +242,28 @@
}
}
+fn post_payload_work() -> Result<()> {
+ // Sync the encrypted storage filesystem (flushes the filesystem caches).
+ if Path::new(ENCRYPTEDSTORE_BACKING_DEVICE).exists() {
+ let mountpoint = CString::new(ENCRYPTEDSTORE_MOUNTPOINT).unwrap();
+
+ let ret = unsafe {
+ let dirfd = libc::open(
+ mountpoint.as_ptr(),
+ libc::O_DIRECTORY | libc::O_RDONLY | libc::O_CLOEXEC,
+ );
+ ensure!(dirfd >= 0, "Unable to open {:?}", mountpoint);
+ let ret = libc::syncfs(dirfd);
+ libc::close(dirfd);
+ ret
+ };
+ if ret != 0 {
+ error!("failed to sync encrypted storage.");
+ return Err(anyhow!(std::io::Error::last_os_error()));
+ }
+ }
+ Ok(())
+}
fn dice_derivation(
dice: DiceDriver,
verified_data: &MicrodroidData,
diff --git a/pvmfw/avb/Android.bp b/pvmfw/avb/Android.bp
index fb950b7..0c1e392 100644
--- a/pvmfw/avb/Android.bp
+++ b/pvmfw/avb/Android.bp
@@ -12,7 +12,7 @@
"libtinyvec_nostd",
],
whole_static_libs: [
- "libavb",
+ "libavb_non_debug",
],
}
@@ -46,7 +46,9 @@
rustlibs: [
"libanyhow",
"libavb_bindgen",
+ "libhex",
"libpvmfw_avb_nostd",
+ "libopenssl",
],
enabled: false,
arch: {
diff --git a/pvmfw/avb/src/descriptor.rs b/pvmfw/avb/src/descriptor.rs
index b0598de..c54d416 100644
--- a/pvmfw/avb/src/descriptor.rs
+++ b/pvmfw/avb/src/descriptor.rs
@@ -31,7 +31,8 @@
};
use tinyvec::ArrayVec;
-const DIGEST_SIZE: usize = AVB_SHA256_DIGEST_SIZE as usize;
+/// Digest type for kernel and initrd.
+pub type Digest = [u8; AVB_SHA256_DIGEST_SIZE as usize];
/// `HashDescriptors` can have maximum one `HashDescriptor` per known partition.
#[derive(Default)]
@@ -132,9 +133,7 @@
#[derive(Default)]
pub(crate) struct HashDescriptor {
partition_name: PartitionName,
- /// TODO(b/265897559): Pass this digest to DICE.
- #[allow(dead_code)]
- pub(crate) digest: [u8; DIGEST_SIZE],
+ pub(crate) digest: Digest,
}
impl HashDescriptor {
@@ -145,7 +144,7 @@
.try_into()?;
let partition_digest =
data.get(desc.digest_range()?).ok_or(AvbIOError::RangeOutsidePartition)?;
- let mut digest = [0u8; DIGEST_SIZE];
+ let mut digest = [0u8; size_of::<Digest>()];
digest.copy_from_slice(partition_digest);
Ok(Self { partition_name, digest })
}
diff --git a/pvmfw/avb/src/lib.rs b/pvmfw/avb/src/lib.rs
index 065eca5..8fea162 100644
--- a/pvmfw/avb/src/lib.rs
+++ b/pvmfw/avb/src/lib.rs
@@ -25,5 +25,6 @@
mod utils;
mod verify;
+pub use descriptor::Digest;
pub use error::AvbSlotVerifyError;
-pub use verify::{verify_payload, DebugLevel};
+pub use verify::{verify_payload, DebugLevel, VerifiedBootData};
diff --git a/pvmfw/avb/src/partition.rs b/pvmfw/avb/src/partition.rs
index 636bfd3..bc63003 100644
--- a/pvmfw/avb/src/partition.rs
+++ b/pvmfw/avb/src/partition.rs
@@ -18,7 +18,7 @@
use crate::utils::is_not_null;
use core::ffi::{c_char, CStr};
-#[derive(Clone, Debug, Default, PartialEq, Eq)]
+#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub(crate) enum PartitionName {
/// The default `PartitionName` is needed to build the default `HashDescriptor`.
#[default]
diff --git a/pvmfw/avb/src/verify.rs b/pvmfw/avb/src/verify.rs
index 14b0e7e..1a79c83 100644
--- a/pvmfw/avb/src/verify.rs
+++ b/pvmfw/avb/src/verify.rs
@@ -14,15 +14,26 @@
//! This module handles the pvmfw payload verification.
-use crate::descriptor::HashDescriptors;
+use crate::descriptor::{Digest, HashDescriptors};
use crate::error::AvbSlotVerifyError;
use crate::ops::{Ops, Payload};
use crate::partition::PartitionName;
use avb_bindgen::{AvbPartitionData, AvbVBMetaData};
use core::ffi::c_char;
+/// Verified data returned when the payload verification succeeds.
+#[derive(Debug)]
+pub struct VerifiedBootData {
+ /// DebugLevel of the VM.
+ pub debug_level: DebugLevel,
+ /// Kernel digest.
+ pub kernel_digest: Digest,
+ /// Initrd digest if initrd exists.
+ pub initrd_digest: Option<Digest>,
+}
+
/// This enum corresponds to the `DebugLevel` in `VirtualMachineConfig`.
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DebugLevel {
/// Not debuggable at all.
None,
@@ -87,7 +98,7 @@
kernel: &[u8],
initrd: Option<&[u8]>,
trusted_public_key: &[u8],
-) -> Result<DebugLevel, AvbSlotVerifyError> {
+) -> Result<VerifiedBootData, AvbSlotVerifyError> {
let mut payload = Payload::new(kernel, initrd, trusted_public_key);
let mut ops = Ops::from(&mut payload);
let kernel_verify_result = ops.verify_partition(PartitionName::Kernel.as_cstr())?;
@@ -100,12 +111,15 @@
// which is returned by `avb_slot_verify()` when the verification succeeds. It is
// guaranteed by libavb to be non-null and to point to a valid VBMeta structure.
let hash_descriptors = unsafe { HashDescriptors::from_vbmeta(vbmeta_image)? };
- // TODO(b/265897559): Pass the digest in kernel descriptor to DICE.
- let _kernel_descriptor = hash_descriptors.find(PartitionName::Kernel)?;
+ let kernel_descriptor = hash_descriptors.find(PartitionName::Kernel)?;
if initrd.is_none() {
verify_vbmeta_has_only_one_hash_descriptor(&hash_descriptors)?;
- return Ok(DebugLevel::None);
+ return Ok(VerifiedBootData {
+ debug_level: DebugLevel::None,
+ kernel_digest: kernel_descriptor.digest,
+ initrd_digest: None,
+ });
}
let initrd = initrd.unwrap();
@@ -123,5 +137,10 @@
initrd_partition_name,
initrd.len(),
)?;
- Ok(debug_level)
+ let initrd_descriptor = hash_descriptors.find(initrd_partition_name)?;
+ Ok(VerifiedBootData {
+ debug_level,
+ kernel_digest: kernel_descriptor.digest,
+ initrd_digest: Some(initrd_descriptor.digest),
+ })
}
diff --git a/pvmfw/avb/tests/api_test.rs b/pvmfw/avb/tests/api_test.rs
index 4f00f1e..261d8a8 100644
--- a/pvmfw/avb/tests/api_test.rs
+++ b/pvmfw/avb/tests/api_test.rs
@@ -16,9 +16,9 @@
mod utils;
-use anyhow::Result;
+use anyhow::{anyhow, Result};
use avb_bindgen::{AvbFooter, AvbVBMetaImageHeader};
-use pvmfw_avb::{AvbSlotVerifyError, DebugLevel};
+use pvmfw_avb::{verify_payload, AvbSlotVerifyError, DebugLevel};
use std::{fs, mem::size_of, ptr};
use utils::*;
@@ -35,121 +35,125 @@
/// the latest payload can be verified successfully.
#[test]
fn latest_normal_payload_passes_verification() -> Result<()> {
- assert_payload_verification_with_initrd_eq(
- &load_latest_signed_kernel()?,
+ assert_latest_payload_verification_passes(
&load_latest_initrd_normal()?,
- &load_trusted_public_key()?,
- Ok(DebugLevel::None),
+ b"initrd_normal",
+ DebugLevel::None,
)
}
#[test]
fn latest_debug_payload_passes_verification() -> Result<()> {
- assert_payload_verification_with_initrd_eq(
- &load_latest_signed_kernel()?,
+ assert_latest_payload_verification_passes(
&load_latest_initrd_debug()?,
- &load_trusted_public_key()?,
- Ok(DebugLevel::Full),
+ b"initrd_debug",
+ DebugLevel::Full,
)
}
#[test]
fn payload_expecting_no_initrd_passes_verification_with_no_initrd() -> Result<()> {
- assert_payload_verification_eq(
+ let verified_boot_data = verify_payload(
&fs::read(TEST_IMG_WITH_ONE_HASHDESC_PATH)?,
/*initrd=*/ None,
&load_trusted_public_key()?,
- Ok(DebugLevel::None),
)
+ .map_err(|e| anyhow!("Verification failed. Error: {}", e))?;
+
+ assert_eq!(DebugLevel::None, verified_boot_data.debug_level);
+ let digest = hash(&[&hex::decode("1111")?, &fs::read(UNSIGNED_TEST_IMG_PATH)?]);
+ assert_eq!(digest, verified_boot_data.kernel_digest);
+ assert!(verified_boot_data.initrd_digest.is_none());
+ Ok(())
}
#[test]
fn payload_with_non_initrd_descriptor_fails_verification_with_no_initrd() -> Result<()> {
- assert_payload_verification_eq(
+ assert_payload_verification_fails(
&fs::read(TEST_IMG_WITH_NON_INITRD_HASHDESC_PATH)?,
/*initrd=*/ None,
&load_trusted_public_key()?,
- Err(AvbSlotVerifyError::InvalidMetadata),
+ AvbSlotVerifyError::InvalidMetadata,
)
}
#[test]
fn payload_with_non_initrd_descriptor_fails_verification_with_initrd() -> Result<()> {
- assert_payload_verification_with_initrd_eq(
+ assert_payload_verification_with_initrd_fails(
&fs::read(TEST_IMG_WITH_INITRD_AND_NON_INITRD_DESC_PATH)?,
&load_latest_initrd_normal()?,
&load_trusted_public_key()?,
- Err(AvbSlotVerifyError::InvalidMetadata),
+ AvbSlotVerifyError::InvalidMetadata,
)
}
#[test]
fn payload_with_prop_descriptor_fails_verification_with_no_initrd() -> Result<()> {
- assert_payload_verification_eq(
+ assert_payload_verification_fails(
&fs::read(TEST_IMG_WITH_PROP_DESC_PATH)?,
/*initrd=*/ None,
&load_trusted_public_key()?,
- Err(AvbSlotVerifyError::InvalidMetadata),
+ AvbSlotVerifyError::InvalidMetadata,
)
}
#[test]
fn payload_expecting_initrd_fails_verification_with_no_initrd() -> Result<()> {
- assert_payload_verification_eq(
+ assert_payload_verification_fails(
&load_latest_signed_kernel()?,
/*initrd=*/ None,
&load_trusted_public_key()?,
- Err(AvbSlotVerifyError::InvalidMetadata),
+ AvbSlotVerifyError::InvalidMetadata,
)
}
#[test]
fn payload_with_empty_public_key_fails_verification() -> Result<()> {
- assert_payload_verification_with_initrd_eq(
+ assert_payload_verification_with_initrd_fails(
&load_latest_signed_kernel()?,
&load_latest_initrd_normal()?,
/*trusted_public_key=*/ &[0u8; 0],
- Err(AvbSlotVerifyError::PublicKeyRejected),
+ AvbSlotVerifyError::PublicKeyRejected,
)
}
#[test]
fn payload_with_an_invalid_public_key_fails_verification() -> Result<()> {
- assert_payload_verification_with_initrd_eq(
+ assert_payload_verification_with_initrd_fails(
&load_latest_signed_kernel()?,
&load_latest_initrd_normal()?,
/*trusted_public_key=*/ &[0u8; 512],
- Err(AvbSlotVerifyError::PublicKeyRejected),
+ AvbSlotVerifyError::PublicKeyRejected,
)
}
#[test]
fn payload_with_a_different_valid_public_key_fails_verification() -> Result<()> {
- assert_payload_verification_with_initrd_eq(
+ assert_payload_verification_with_initrd_fails(
&load_latest_signed_kernel()?,
&load_latest_initrd_normal()?,
&fs::read(PUBLIC_KEY_RSA2048_PATH)?,
- Err(AvbSlotVerifyError::PublicKeyRejected),
+ AvbSlotVerifyError::PublicKeyRejected,
)
}
#[test]
fn payload_with_an_invalid_initrd_fails_verification() -> Result<()> {
- assert_payload_verification_with_initrd_eq(
+ assert_payload_verification_with_initrd_fails(
&load_latest_signed_kernel()?,
/*initrd=*/ &fs::read(UNSIGNED_TEST_IMG_PATH)?,
&load_trusted_public_key()?,
- Err(AvbSlotVerifyError::Verification),
+ AvbSlotVerifyError::Verification,
)
}
#[test]
fn unsigned_kernel_fails_verification() -> Result<()> {
- assert_payload_verification_with_initrd_eq(
+ assert_payload_verification_with_initrd_fails(
&fs::read(UNSIGNED_TEST_IMG_PATH)?,
&load_latest_initrd_normal()?,
&load_trusted_public_key()?,
- Err(AvbSlotVerifyError::Io),
+ AvbSlotVerifyError::Io,
)
}
@@ -158,11 +162,11 @@
let mut kernel = load_latest_signed_kernel()?;
kernel[1] = !kernel[1]; // Flip the bits
- assert_payload_verification_with_initrd_eq(
+ assert_payload_verification_with_initrd_fails(
&kernel,
&load_latest_initrd_normal()?,
&load_trusted_public_key()?,
- Err(AvbSlotVerifyError::Verification),
+ AvbSlotVerifyError::Verification,
)
}
@@ -191,11 +195,11 @@
// footer is unaligned; copy vbmeta_offset to local variable
let vbmeta_offset = footer.vbmeta_offset;
assert_eq!(wrong_offset, vbmeta_offset);
- assert_payload_verification_with_initrd_eq(
+ assert_payload_verification_with_initrd_fails(
&kernel,
&load_latest_initrd_normal()?,
&load_trusted_public_key()?,
- Err(AvbSlotVerifyError::Io),
+ AvbSlotVerifyError::Io,
)?;
}
Ok(())
@@ -207,11 +211,11 @@
let avb_footer_index = kernel.len() - size_of::<AvbFooter>() + RANDOM_FOOTER_POS;
kernel[avb_footer_index] = !kernel[avb_footer_index];
- assert_payload_verification_with_initrd_eq(
+ assert_payload_verification_with_initrd_fails(
&kernel,
&load_latest_initrd_normal()?,
&load_trusted_public_key()?,
- Err(AvbSlotVerifyError::InvalidMetadata),
+ AvbSlotVerifyError::InvalidMetadata,
)
}
@@ -220,11 +224,11 @@
let mut initrd = load_latest_initrd_normal()?;
initrd.extend(b"androidboot.vbmeta.digest=1111");
- assert_payload_verification_with_initrd_eq(
+ assert_payload_verification_with_initrd_fails(
&load_latest_signed_kernel()?,
&initrd,
&load_trusted_public_key()?,
- Err(AvbSlotVerifyError::Verification),
+ AvbSlotVerifyError::Verification,
)
}
@@ -236,11 +240,11 @@
kernel[vbmeta_index] = !kernel[vbmeta_index]; // Flip the bits
- assert_payload_verification_with_initrd_eq(
+ assert_payload_verification_with_initrd_fails(
&kernel,
&load_latest_initrd_normal()?,
&load_trusted_public_key()?,
- Err(AvbSlotVerifyError::InvalidMetadata),
+ AvbSlotVerifyError::InvalidMetadata,
)
}
@@ -259,17 +263,17 @@
kernel[public_key_offset..(public_key_offset + public_key_size)]
.copy_from_slice(&empty_public_key);
- assert_payload_verification_with_initrd_eq(
+ assert_payload_verification_with_initrd_fails(
&kernel,
&load_latest_initrd_normal()?,
&empty_public_key,
- Err(AvbSlotVerifyError::Verification),
+ AvbSlotVerifyError::Verification,
)?;
- assert_payload_verification_with_initrd_eq(
+ assert_payload_verification_with_initrd_fails(
&kernel,
&load_latest_initrd_normal()?,
&load_trusted_public_key()?,
- Err(AvbSlotVerifyError::Verification),
+ AvbSlotVerifyError::Verification,
)
}
@@ -303,10 +307,10 @@
AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED, vbmeta_header_flags,
"VBMeta verification flag should be disabled now."
);
- assert_payload_verification_with_initrd_eq(
+ assert_payload_verification_with_initrd_fails(
&kernel,
&load_latest_initrd_normal()?,
&load_trusted_public_key()?,
- Err(AvbSlotVerifyError::Verification),
+ AvbSlotVerifyError::Verification,
)
}
diff --git a/pvmfw/avb/tests/utils.rs b/pvmfw/avb/tests/utils.rs
index 0a2eac6..8756d06 100644
--- a/pvmfw/avb/tests/utils.rs
+++ b/pvmfw/avb/tests/utils.rs
@@ -16,12 +16,13 @@
//! Utility functions used by API tests.
-use anyhow::Result;
+use anyhow::{anyhow, Result};
use avb_bindgen::{
avb_footer_validate_and_byteswap, avb_vbmeta_image_header_to_host_byte_order, AvbFooter,
AvbVBMetaImageHeader,
};
-use pvmfw_avb::{verify_payload, AvbSlotVerifyError, DebugLevel};
+use openssl::sha;
+use pvmfw_avb::{verify_payload, AvbSlotVerifyError, DebugLevel, Digest};
use std::{
fs,
mem::{size_of, transmute, MaybeUninit},
@@ -34,22 +35,22 @@
pub const PUBLIC_KEY_RSA2048_PATH: &str = "data/testkey_rsa2048_pub.bin";
-pub fn assert_payload_verification_with_initrd_eq(
+pub fn assert_payload_verification_with_initrd_fails(
kernel: &[u8],
initrd: &[u8],
trusted_public_key: &[u8],
- expected_result: Result<DebugLevel, AvbSlotVerifyError>,
+ expected_error: AvbSlotVerifyError,
) -> Result<()> {
- assert_payload_verification_eq(kernel, Some(initrd), trusted_public_key, expected_result)
+ assert_payload_verification_fails(kernel, Some(initrd), trusted_public_key, expected_error)
}
-pub fn assert_payload_verification_eq(
+pub fn assert_payload_verification_fails(
kernel: &[u8],
initrd: Option<&[u8]>,
trusted_public_key: &[u8],
- expected_result: Result<DebugLevel, AvbSlotVerifyError>,
+ expected_error: AvbSlotVerifyError,
) -> Result<()> {
- assert_eq!(expected_result, verify_payload(kernel, initrd, trusted_public_key));
+ assert_eq!(expected_error, verify_payload(kernel, initrd, trusted_public_key).unwrap_err());
Ok(())
}
@@ -95,3 +96,34 @@
};
Ok(vbmeta_header)
}
+
+pub fn assert_latest_payload_verification_passes(
+ initrd: &[u8],
+ initrd_salt: &[u8],
+ expected_debug_level: DebugLevel,
+) -> Result<()> {
+ let kernel = load_latest_signed_kernel()?;
+ let verified_boot_data = verify_payload(&kernel, Some(initrd), &load_trusted_public_key()?)
+ .map_err(|e| anyhow!("Verification failed. Error: {}", e))?;
+
+ assert_eq!(expected_debug_level, verified_boot_data.debug_level);
+
+ let footer = extract_avb_footer(&kernel)?;
+ assert_eq!(
+ hash(&[&hash(&[b"bootloader"]), &kernel[..usize::try_from(footer.original_image_size)?]]),
+ verified_boot_data.kernel_digest,
+ "Kernel digest is not equal to the expected."
+ );
+ assert_eq!(
+ hash(&[&hash(&[initrd_salt]), initrd,]),
+ verified_boot_data.initrd_digest.unwrap(),
+ "initrd digest is not equal to the expected."
+ );
+ Ok(())
+}
+
+pub fn hash(inputs: &[&[u8]]) -> Digest {
+ let mut digester = sha::Sha256::new();
+ inputs.iter().for_each(|input| digester.update(input));
+ digester.finish()
+}
diff --git a/pvmfw/src/debug_policy.rs b/pvmfw/src/debug_policy.rs
new file mode 100644
index 0000000..37e2af8
--- /dev/null
+++ b/pvmfw/src/debug_policy.rs
@@ -0,0 +1,152 @@
+// Copyright 2023, 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.
+
+//! Support for the debug policy overlay in pvmfw
+
+use alloc::vec;
+use core::ffi::CStr;
+use core::fmt;
+use libfdt::FdtError;
+use log::info;
+
+#[derive(Debug, Clone)]
+pub enum DebugPolicyError {
+ /// The provided baseline FDT was invalid or malformed, so cannot access certain node/prop
+ Fdt(&'static str, FdtError),
+ /// The provided debug policy FDT was invalid or malformed.
+ DebugPolicyFdt(&'static str, FdtError),
+ /// The overlaid result FDT is invalid or malformed, and may be corrupted.
+ OverlaidFdt(&'static str, FdtError),
+}
+
+impl fmt::Display for DebugPolicyError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ Self::Fdt(s, e) => write!(f, "Invalid baseline FDT. {s}: {e}"),
+ Self::DebugPolicyFdt(s, e) => write!(f, "Invalid overlay FDT. {s}: {e}"),
+ Self::OverlaidFdt(s, e) => write!(f, "Invalid overlaid FDT. {s}: {e}"),
+ }
+ }
+}
+
+/// Applies the debug policy device tree overlay to the pVM DT.
+///
+/// # Safety
+///
+/// When an error is returned by this function, the input `Fdt` should be
+/// discarded as it may have have been partially corrupted during the overlay
+/// application process.
+unsafe fn apply_debug_policy(
+ fdt: &mut libfdt::Fdt,
+ debug_policy: &mut [u8],
+) -> Result<(), DebugPolicyError> {
+ let overlay = libfdt::Fdt::from_mut_slice(debug_policy)
+ .map_err(|e| DebugPolicyError::DebugPolicyFdt("Failed to load debug policy overlay", e))?;
+
+ fdt.unpack().map_err(|e| DebugPolicyError::Fdt("Failed to unpack", e))?;
+
+ let fdt = fdt
+ .apply_overlay(overlay)
+ .map_err(|e| DebugPolicyError::DebugPolicyFdt("Failed to apply overlay", e))?;
+
+ fdt.pack().map_err(|e| DebugPolicyError::OverlaidFdt("Failed to re-pack", e))
+}
+
+/// Dsiables ramdump by removing crashkernel from bootargs in /chosen.
+///
+/// # Safety
+///
+/// This may corrupt the input `Fdt` when error happens while editing prop value.
+unsafe fn disable_ramdump(fdt: &mut libfdt::Fdt) -> Result<(), DebugPolicyError> {
+ let chosen_path = CStr::from_bytes_with_nul(b"/chosen\0").unwrap();
+ let bootargs_name = CStr::from_bytes_with_nul(b"bootargs\0").unwrap();
+
+ let chosen = match fdt
+ .node(chosen_path)
+ .map_err(|e| DebugPolicyError::Fdt("Failed to find /chosen", e))?
+ {
+ Some(node) => node,
+ None => return Ok(()),
+ };
+
+ let bootargs = match chosen
+ .getprop_str(bootargs_name)
+ .map_err(|e| DebugPolicyError::Fdt("Failed to find bootargs prop", e))?
+ {
+ Some(value) if !value.to_bytes().is_empty() => value,
+ _ => return Ok(()),
+ };
+
+ // TODO: Improve add 'crashkernel=17MB' only when it's unnecessary.
+ // Currently 'crashkernel=17MB' in virtualizationservice and passed by
+ // chosen node, because it's not exactly a debug policy but a
+ // configuration. However, it's actually microdroid specific
+ // so we need a way to generalize it.
+ let mut args = vec![];
+ for arg in bootargs.to_bytes().split(|byte| byte.is_ascii_whitespace()) {
+ if arg.is_empty() || arg.starts_with(b"crashkernel=") {
+ continue;
+ }
+ args.push(arg);
+ }
+ let mut new_bootargs = args.as_slice().join(&b" "[..]);
+ new_bootargs.push(b'\0');
+
+ // We've checked existence of /chosen node at the beginning.
+ let mut chosen_mut = fdt.node_mut(chosen_path).unwrap().unwrap();
+ chosen_mut.setprop(bootargs_name, new_bootargs.as_slice()).map_err(|e| {
+ DebugPolicyError::OverlaidFdt("Failed to remove crashkernel. FDT might be corrupted", e)
+ })
+}
+
+/// Returns true only if fdt has ramdump prop in the /avf/guest/common node with value <1>
+fn is_ramdump_enabled(fdt: &libfdt::Fdt) -> Result<bool, DebugPolicyError> {
+ let common = match fdt
+ .node(CStr::from_bytes_with_nul(b"/avf/guest/common\0").unwrap())
+ .map_err(|e| DebugPolicyError::DebugPolicyFdt("Failed to find /avf/guest/common node", e))?
+ {
+ Some(node) => node,
+ None => return Ok(false),
+ };
+
+ match common
+ .getprop_u32(CStr::from_bytes_with_nul(b"ramdump\0").unwrap())
+ .map_err(|e| DebugPolicyError::DebugPolicyFdt("Failed to find ramdump prop", e))?
+ {
+ Some(1) => Ok(true),
+ _ => Ok(false),
+ }
+}
+
+/// Handles debug policies.
+///
+/// # Safety
+///
+/// This may corrupt the input `Fdt` when overlaying debug policy or applying
+/// ramdump configuration.
+pub unsafe fn handle_debug_policy(
+ fdt: &mut libfdt::Fdt,
+ debug_policy: Option<&mut [u8]>,
+) -> Result<(), DebugPolicyError> {
+ if let Some(dp) = debug_policy {
+ apply_debug_policy(fdt, dp)?;
+ }
+
+ // Handles ramdump in the debug policy
+ if is_ramdump_enabled(fdt)? {
+ info!("ramdump is enabled by debug policy");
+ return Ok(());
+ }
+ disable_ramdump(fdt)
+}
diff --git a/pvmfw/src/dice.rs b/pvmfw/src/dice.rs
index b322850..49218b0 100644
--- a/pvmfw/src/dice.rs
+++ b/pvmfw/src/dice.rs
@@ -15,24 +15,41 @@
//! Support for DICE derivation and BCC generation.
use core::ffi::CStr;
-
+use core::mem::size_of;
use dice::bcc::format_config_descriptor;
use dice::bcc::Handover;
use dice::hash;
use dice::ConfigType;
+use dice::DiceMode;
use dice::InputValues;
+use pvmfw_avb::{DebugLevel, Digest, VerifiedBootData};
+
+fn to_dice_mode(debug_level: DebugLevel) -> DiceMode {
+ match debug_level {
+ DebugLevel::None => DiceMode::kDiceModeNormal,
+ DebugLevel::Full => DiceMode::kDiceModeDebug,
+ }
+}
+
+fn to_dice_hash(verified_boot_data: &VerifiedBootData) -> dice::Result<dice::Hash> {
+ let mut digests = [0u8; size_of::<Digest>() * 2];
+ digests[..size_of::<Digest>()].copy_from_slice(&verified_boot_data.kernel_digest);
+ if let Some(initrd_digest) = verified_boot_data.initrd_digest {
+ digests[size_of::<Digest>()..].copy_from_slice(&initrd_digest);
+ }
+ hash(&digests)
+}
/// Derive the VM-specific secrets and certificate through DICE.
pub fn derive_next_bcc(
bcc: &Handover,
next_bcc: &mut [u8],
- code: &[u8],
- debug_mode: bool,
+ verified_boot_data: &VerifiedBootData,
authority: &[u8],
) -> dice::Result<usize> {
- let code_hash = hash(code)?;
+ let code_hash = to_dice_hash(verified_boot_data)?;
let auth_hash = hash(authority)?;
- let mode = if debug_mode { dice::Mode::Debug } else { dice::Mode::Normal };
+ let mode = to_dice_mode(verified_boot_data.debug_level);
let component_name = CStr::from_bytes_with_nul(b"vm_entry\0").unwrap();
let mut config_descriptor_buffer = [0; 128];
let config_descriptor_size = format_config_descriptor(
diff --git a/pvmfw/src/entry.rs b/pvmfw/src/entry.rs
index 4f30902..530449c 100644
--- a/pvmfw/src/entry.rs
+++ b/pvmfw/src/entry.rs
@@ -15,6 +15,7 @@
//! Low-level entry and exit points of pvmfw.
use crate::config;
+use crate::debug_policy::{handle_debug_policy, DebugPolicyError};
use crate::fdt;
use crate::heap;
use crate::helpers;
@@ -52,6 +53,16 @@
SecretDerivationError,
}
+impl From<DebugPolicyError> for RebootReason {
+ fn from(error: DebugPolicyError) -> Self {
+ match error {
+ DebugPolicyError::Fdt(_, _) => RebootReason::InvalidFdt,
+ DebugPolicyError::DebugPolicyFdt(_, _) => RebootReason::InvalidConfig,
+ DebugPolicyError::OverlaidFdt(_, _) => RebootReason::InternalError,
+ }
+ }
+}
+
main!(start);
/// Entry point for pVM firmware.
@@ -61,7 +72,7 @@
// - can't access MMIO (therefore, no logging)
match main_wrapper(fdt_address as usize, payload_start as usize, payload_size as usize) {
- Ok(_) => jump_to_payload(fdt_address, payload_start),
+ Ok(entry) => jump_to_payload(fdt_address, entry.try_into().unwrap()),
Err(_) => reboot(), // TODO(b/220071963) propagate the reason back to the host.
}
@@ -178,42 +189,11 @@
}
}
-/// Applies the debug policy device tree overlay to the pVM DT.
-///
-/// # Safety
-///
-/// When an error is returned by this function, the input `Fdt` should be discarded as it may have
-/// have been partially corrupted during the overlay application process.
-unsafe fn apply_debug_policy(
- fdt: &mut libfdt::Fdt,
- debug_policy: &mut [u8],
-) -> Result<(), RebootReason> {
- let overlay = libfdt::Fdt::from_mut_slice(debug_policy).map_err(|e| {
- error!("Failed to load the debug policy overlay: {e}");
- RebootReason::InvalidConfig
- })?;
-
- fdt.unpack().map_err(|e| {
- error!("Failed to unpack DT for debug policy: {e}");
- RebootReason::InternalError
- })?;
-
- let fdt = fdt.apply_overlay(overlay).map_err(|e| {
- error!("Failed to apply the debug policy overlay: {e}");
- RebootReason::InvalidConfig
- })?;
-
- fdt.pack().map_err(|e| {
- error!("Failed to re-pack DT after debug policy: {e}");
- RebootReason::InternalError
- })
-}
-
/// Sets up the environment for main() and wraps its result for start().
///
/// Provide the abstractions necessary for start() to abort the pVM boot and for main() to run with
/// the assumption that its environment has been properly configured.
-fn main_wrapper(fdt: usize, payload: usize, payload_size: usize) -> Result<(), RebootReason> {
+fn main_wrapper(fdt: usize, payload: usize, payload_size: usize) -> Result<usize, RebootReason> {
// Limitations in this function:
// - only access MMIO once (and while) it has been mapped and configured
// - only perform logging once the logger has been initialized
@@ -283,9 +263,12 @@
helpers::flushed_zeroize(bcc_slice);
helpers::flush(slices.fdt.as_slice());
- if let Some(debug_policy) = appended.get_debug_policy() {
- // SAFETY - As we `?` the result, there is no risk of re-using a bad `slices.fdt`.
- unsafe { apply_debug_policy(slices.fdt, debug_policy) }?;
+ // SAFETY - As we `?` the result, there is no risk of using a bad `slices.fdt`.
+ unsafe {
+ handle_debug_policy(slices.fdt, appended.get_debug_policy()).map_err(|e| {
+ error!("Unexpected error when handling debug policy: {e:?}");
+ RebootReason::from(e)
+ })?;
}
info!("Expecting a bug making MMIO_GUARD_UNMAP return NOT_SUPPORTED on success");
@@ -298,7 +281,7 @@
RebootReason::InternalError
})?;
- Ok(())
+ Ok(slices.kernel.as_ptr() as usize)
}
fn jump_to_payload(fdt_address: u64, payload_start: u64) -> ! {
diff --git a/pvmfw/src/main.rs b/pvmfw/src/main.rs
index eabdfe8..be5a16a 100644
--- a/pvmfw/src/main.rs
+++ b/pvmfw/src/main.rs
@@ -21,6 +21,7 @@
extern crate alloc;
mod config;
+mod debug_policy;
mod dice;
mod entry;
mod exceptions;
@@ -78,28 +79,11 @@
let mut pci_root = pci::initialise(pci_info, memory)?;
find_virtio_devices(&mut pci_root).map_err(handle_pci_error)?;
- verify_payload(signed_kernel, ramdisk, PUBLIC_KEY).map_err(|e| {
+ let verified_boot_data = verify_payload(signed_kernel, ramdisk, PUBLIC_KEY).map_err(|e| {
error!("Failed to verify the payload: {e}");
RebootReason::PayloadVerificationError
})?;
- let debug_mode = false; // TODO(b/256148034): Derive the DICE mode from the received initrd.
- const HASH_SIZE: usize = 64;
- let mut hashes = [0; HASH_SIZE * 2]; // TODO(b/256148034): Extract AvbHashDescriptor digests.
- hashes[..HASH_SIZE].copy_from_slice(&::dice::hash(signed_kernel).map_err(|_| {
- error!("Failed to hash the kernel");
- RebootReason::InternalError
- })?);
- // Note: Using signed_kernel currently makes the DICE code input depend on its VBMeta fields.
- let code_hash = if let Some(rd) = ramdisk {
- hashes[HASH_SIZE..].copy_from_slice(&::dice::hash(rd).map_err(|_| {
- error!("Failed to hash the ramdisk");
- RebootReason::InternalError
- })?);
- &hashes[..]
- } else {
- &hashes[..HASH_SIZE]
- };
let next_bcc = heap::aligned_boxed_slice(NEXT_BCC_SIZE, GUEST_PAGE_SIZE).ok_or_else(|| {
error!("Failed to allocate the next-stage BCC");
RebootReason::InternalError
@@ -107,7 +91,7 @@
// By leaking the slice, its content will be left behind for the next stage.
let next_bcc = Box::leak(next_bcc);
let next_bcc_size =
- derive_next_bcc(bcc, next_bcc, code_hash, debug_mode, PUBLIC_KEY).map_err(|e| {
+ derive_next_bcc(bcc, next_bcc, &verified_boot_data, PUBLIC_KEY).map_err(|e| {
error!("Failed to derive next-stage DICE secrets: {e:?}");
RebootReason::SecretDerivationError
})?;
diff --git a/tests/aidl/com/android/microdroid/testservice/ITestService.aidl b/tests/aidl/com/android/microdroid/testservice/ITestService.aidl
index 7ee1f01..4611134 100644
--- a/tests/aidl/com/android/microdroid/testservice/ITestService.aidl
+++ b/tests/aidl/com/android/microdroid/testservice/ITestService.aidl
@@ -55,4 +55,10 @@
/* get the content of the specified file. */
String readFromFile(String path);
+
+ /**
+ * Request the service to exit, triggering the termination of the VM. This may cause any
+ * requests in flight to fail.
+ */
+ oneway void quit();
}
diff --git a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
index c6915e5..9cafd68 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -1520,15 +1520,34 @@
throws Exception {
CompletableFuture<Boolean> payloadStarted = new CompletableFuture<>();
CompletableFuture<Boolean> payloadReady = new CompletableFuture<>();
+ CompletableFuture<Boolean> payloadFinished = new CompletableFuture<>();
TestResults testResults = new TestResults();
VmEventListener listener =
new VmEventListener() {
- private void testVMService(VirtualMachine vm) {
+ ITestService mTestService = null;
+
+ private void initializeTestService(VirtualMachine vm) {
try {
- ITestService testService =
+ mTestService =
ITestService.Stub.asInterface(
vm.connectToVsockServer(ITestService.SERVICE_PORT));
- testsToRun.runTests(testService, testResults);
+ } catch (Exception e) {
+ testResults.mException = e;
+ }
+ }
+
+ private void testVMService(VirtualMachine vm) {
+ try {
+ if (mTestService == null) initializeTestService(vm);
+ testsToRun.runTests(mTestService, testResults);
+ } catch (Exception e) {
+ testResults.mException = e;
+ }
+ }
+
+ private void quitVMService(VirtualMachine vm) {
+ try {
+ mTestService.quit();
} catch (Exception e) {
testResults.mException = e;
}
@@ -1539,7 +1558,7 @@
Log.i(TAG, "onPayloadReady");
payloadReady.complete(true);
testVMService(vm);
- forceStop(vm);
+ quitVMService(vm);
}
@Override
@@ -1547,10 +1566,19 @@
Log.i(TAG, "onPayloadStarted");
payloadStarted.complete(true);
}
+
+ @Override
+ public void onPayloadFinished(VirtualMachine vm, int exitCode) {
+ Log.i(TAG, "onPayloadFinished: " + exitCode);
+ payloadFinished.complete(true);
+ forceStop(vm);
+ }
};
+
listener.runToFinish(TAG, vm);
assertThat(payloadStarted.getNow(false)).isTrue();
assertThat(payloadReady.getNow(false)).isTrue();
+ assertThat(payloadFinished.getNow(false)).isTrue();
return testResults;
}
diff --git a/tests/testapk/src/native/testbinary.cpp b/tests/testapk/src/native/testbinary.cpp
index 4ba502a..365ea75 100644
--- a/tests/testapk/src/native/testbinary.cpp
+++ b/tests/testapk/src/native/testbinary.cpp
@@ -240,9 +240,6 @@
return ScopedAStatus::fromExceptionCodeWithMessage(EX_SERVICE_SPECIFIC,
msg.c_str());
}
- // TODO(b/264520098): Remove sync() once TestService supports quit() method
- // and Microdroid manager flushes filesystem caches on shutdown.
- sync();
return ScopedAStatus::ok();
}
@@ -255,6 +252,8 @@
}
return ScopedAStatus::ok();
}
+
+ ScopedAStatus quit() override { exit(0); }
};
auto testService = ndk::SharedRefBase::make<TestService>();
diff --git a/vmbase/common.h b/vmbase/common.h
index 788dcf0..0f73b36 100644
--- a/vmbase/common.h
+++ b/vmbase/common.h
@@ -30,9 +30,13 @@
movk \reg, :abs_g0_nc:\imm
.endm
+.macro hvc_call func_id:req
+ mov_i x0, \func_id
+ hvc 0
+.endm
+
.macro reset_or_hang
- mov_i x0, PSCI_SYSTEM_RESET
- hvc 0
+ hvc_call PSCI_SYSTEM_RESET
999: wfi
b 999b
.endm
diff --git a/vmbase/entry.S b/vmbase/entry.S
index 5f0a2ce..ab46465 100644
--- a/vmbase/entry.S
+++ b/vmbase/entry.S
@@ -63,13 +63,71 @@
.set .Lsctlrval, .L_SCTLR_ELx_M | .L_SCTLR_ELx_C | .L_SCTLR_ELx_SA | .L_SCTLR_EL1_ITD | .L_SCTLR_EL1_SED
.set .Lsctlrval, .Lsctlrval | .L_SCTLR_ELx_I | .L_SCTLR_EL1_SPAN | .L_SCTLR_EL1_RES1 | .L_SCTLR_EL1_WXN
+/* SMC function IDs */
+.set .L_SMCCC_VERSION_ID, 0x80000000
+.set .L_SMCCC_TRNG_VERSION_ID, 0x84000050
+.set .L_SMCCC_TRNG_FEATURES_ID, 0x84000051
+.set .L_SMCCC_TRNG_RND64_ID, 0xc4000053
+
+/* SMC function versions */
+.set .L_SMCCC_VERSION_1_1, 0x0101
+.set .L_SMCCC_TRNG_VERSION_1_0, 0x0100
+
/* Bionic-compatible stack protector */
.section .data.stack_protector, "aw"
__bionic_tls:
.zero 40
.global __stack_chk_guard
__stack_chk_guard:
- .quad 0x23d6d3f3c3b84098 /* TODO: randomize */
+ .quad 0
+
+/**
+ * This macro stores a random value into a register.
+ * If a TRNG backed is not present or if an error occurs, the value remains unchanged.
+ */
+.macro rnd_reg reg:req
+ mov x20, x0
+ mov x21, x1
+ mov x22, x2
+ mov x23, x3
+
+ /* Verify SMCCC version >=1.1 */
+ hvc_call .L_SMCCC_VERSION_ID
+ cmp w0, 0
+ b.lt 100f
+ cmp w0, .L_SMCCC_VERSION_1_1
+ b.lt 100f
+
+ /* Verify TRNG ABI version 1.x */
+ hvc_call .L_SMCCC_TRNG_VERSION_ID
+ cmp w0, 0
+ b.lt 100f
+ cmp w0, .L_SMCCC_TRNG_VERSION_1_0
+ b.lt 100f
+
+ /* Call TRNG_FEATURES, ensure TRNG_RND is implemented */
+ mov_i x1, .L_SMCCC_TRNG_RND64_ID
+ hvc_call .L_SMCCC_TRNG_FEATURES_ID
+ cmp w0, 0
+ b.lt 100f
+
+ /* Call TRNG_RND, request 64 bits of entropy */
+ mov x1, #64
+ hvc_call .L_SMCCC_TRNG_RND64_ID
+ cmp x0, 0
+ b.lt 100f
+
+ mov \reg, x3
+ b 101f
+
+100:
+ reset_or_hang
+101:
+ mov x0, x20
+ mov x1, x21
+ mov x2, x22
+ mov x3, x23
+.endm
/**
* This is a generic entry point for an image. It carries out the operations required to prepare the
@@ -162,9 +220,15 @@
adr_l x30, __bionic_tls
msr tpidr_el0, x30
+ /* Randomize stack protector. */
+ rnd_reg x29
+ adr_l x30, __stack_chk_guard
+ str x29, [x30]
+
/* Call into Rust code. */
bl rust_entry
/* Loop forever waiting for interrupts. */
4: wfi
b 4b
+