vmbase: Configure stack guard from Rust
Move the thorough validation of the availability of TRNG that was
performed in assembly to Rust and call rand::init() from the entry code
of vmbase to unify the implementations.
Use TRNG from rust_entry() to configure the stack guard (see the comment
about rust_entry() ever returning). As a result, failing to configure
it will now result in a logged error message as, previously,
vmbase-based code would silently reboot, making it impossible to find
out which check had failed (see b/267262026#comment89).
Furthermore, failing to read the entropy for the u64 stack guard due to
NO_ENTROPY will now result in vmbase retrying the HVC where it
previously would abort the VM's boot.
This implementation now only accepts versions of SMCCC between 1.1 and
2.0 (excl.) and TRNG between 1.0 and 2.0 (excl.) instead of resp. 1.1
and above and 1.0 and above.
Bug: 274561905
Test: atest DebugPolicyHostTests#testNoAdbInDebugPolicy_withDebugLevelNone_boots
Test: atest rialto_test vmbase_example.integration_test
Change-Id: I5b95e77732e10ddfbc4476b6d7c698c5dc5f3b6e
diff --git a/vmbase/src/rand.rs b/vmbase/src/rand.rs
index 26fb51a..a5a5f5f 100644
--- a/vmbase/src/rand.rs
+++ b/vmbase/src/rand.rs
@@ -17,15 +17,28 @@
use crate::hvc;
use core::fmt;
use core::mem::size_of;
+use smccc::{self, Hvc};
/// Error type for rand operations.
pub enum Error {
+ /// No source of entropy found.
+ NoEntropySource,
+ /// Error during architectural SMCCC call.
+ Smccc(smccc::arch::Error),
/// Error during SMCCC TRNG call.
Trng(hvc::trng::Error),
+ /// Unsupported SMCCC version.
+ UnsupportedSmcccVersion(smccc::arch::Version),
/// Unsupported SMCCC TRNG version.
UnsupportedVersion((u16, u16)),
}
+impl From<smccc::arch::Error> for Error {
+ fn from(e: smccc::arch::Error) -> Self {
+ Self::Smccc(e)
+ }
+}
+
impl From<hvc::trng::Error> for Error {
fn from(e: hvc::trng::Error) -> Self {
Self::Trng(e)
@@ -38,7 +51,10 @@
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
+ Self::NoEntropySource => write!(f, "No source of entropy available"),
+ Self::Smccc(e) => write!(f, "Architectural SMCCC error: {e}"),
Self::Trng(e) => write!(f, "SMCCC TRNG error: {e}"),
+ Self::UnsupportedSmcccVersion(v) => write!(f, "Unsupported SMCCC version {v}"),
Self::UnsupportedVersion((x, y)) => {
write!(f, "Unsupported SMCCC TRNG version v{x}.{y}")
}
@@ -53,14 +69,34 @@
}
/// Configure the source of entropy.
-pub fn init() -> Result<()> {
- match hvc::trng_version()? {
- (1, _) => Ok(()),
- version => Err(Error::UnsupportedVersion(version)),
+pub(crate) fn init() -> Result<()> {
+ // SMCCC TRNG requires SMCCC v1.1.
+ match smccc::arch::version::<Hvc>()? {
+ smccc::arch::Version { major: 1, minor } if minor >= 1 => (),
+ version => return Err(Error::UnsupportedSmcccVersion(version)),
}
+
+ // TRNG_RND requires SMCCC TRNG v1.0.
+ match hvc::trng_version()? {
+ (1, _) => (),
+ version => return Err(Error::UnsupportedVersion(version)),
+ }
+
+ // TRNG_RND64 doesn't define any special capabilities so ignore the successful result.
+ let _ = hvc::trng_features(hvc::ARM_SMCCC_TRNG_RND64).map_err(|e| {
+ if e == hvc::trng::Error::NotSupported {
+ // SMCCC TRNG is currently our only source of entropy.
+ Error::NoEntropySource
+ } else {
+ e.into()
+ }
+ })?;
+
+ Ok(())
}
-fn fill_with_entropy(s: &mut [u8]) -> Result<()> {
+/// Fills a slice of bytes with true entropy.
+pub fn fill_with_entropy(s: &mut [u8]) -> Result<()> {
const MAX_BYTES_PER_CALL: usize = size_of::<hvc::TrngRng64Entropy>();
let (aligned, remainder) = s.split_at_mut(s.len() - s.len() % MAX_BYTES_PER_CALL);