Merge "virtmgr: don't depend on crosvm's libbase_rust module" into main
diff --git a/android/LinuxInstaller/linux_image_builder/setup_x86_64.sh b/android/LinuxInstaller/linux_image_builder/setup_x86_64.sh
index 9748ce2..c543b2a 100755
--- a/android/LinuxInstaller/linux_image_builder/setup_x86_64.sh
+++ b/android/LinuxInstaller/linux_image_builder/setup_x86_64.sh
@@ -4,7 +4,7 @@
tempdir=$(mktemp -d)
echo Get Debian image and dependencies...
wget https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-nocloud-amd64.raw -O ${tempdir}/debian.img
-wget https://github.com/tsl0922/ttyd/releases/download/1.7.7/ttyd.tyd.x86_64 -O ${tempdir}/ttyd
+wget https://github.com/tsl0922/ttyd/releases/download/1.7.7/ttyd.x86_64 -O ${tempdir}/ttyd
echo Customize the image...
virt-customize --commands-from-file <(sed "s|/tmp|$tempdir|g" commands) -a ${tempdir}/debian.img
diff --git a/android/vm/Android.bp b/android/vm/Android.bp
index c1d9b6b..ba8b416 100644
--- a/android/vm/Android.bp
+++ b/android/vm/Android.bp
@@ -16,6 +16,7 @@
"libbinder_rs",
"libclap",
"libenv_logger",
+ "libcfg_if",
"libglob",
"libhypervisor_props",
"liblibc",
diff --git a/android/vm/src/main.rs b/android/vm/src/main.rs
index f2c2fa4..609bbdf 100644
--- a/android/vm/src/main.rs
+++ b/android/vm/src/main.rs
@@ -75,14 +75,14 @@
}
impl CommonConfig {
- #[cfg(network)]
fn network_supported(&self) -> bool {
- self.network_supported
- }
-
- #[cfg(not(network))]
- fn network_supported(&self) -> bool {
- false
+ cfg_if::cfg_if! {
+ if #[cfg(network)] {
+ self.network_supported
+ } else {
+ false
+ }
+ }
}
}
@@ -117,14 +117,14 @@
}
impl DebugConfig {
- #[cfg(debuggable_vms_improvements)]
fn enable_earlycon(&self) -> bool {
- self.enable_earlycon
- }
-
- #[cfg(not(debuggable_vms_improvements))]
- fn enable_earlycon(&self) -> bool {
- false
+ cfg_if::cfg_if! {
+ if #[cfg(debuggable_vms_improvements)] {
+ self.enable_earlycon
+ } else {
+ false
+ }
+ }
}
}
@@ -158,34 +158,34 @@
}
impl MicrodroidConfig {
- #[cfg(vendor_modules)]
fn vendor(&self) -> Option<&PathBuf> {
- self.vendor.as_ref()
+ cfg_if::cfg_if! {
+ if #[cfg(vendor_modules)] {
+ self.vendor.as_ref()
+ } else {
+ None
+ }
+ }
}
- #[cfg(not(vendor_modules))]
- fn vendor(&self) -> Option<&PathBuf> {
- None
- }
-
- #[cfg(vendor_modules)]
fn gki(&self) -> Option<&str> {
- self.gki.as_deref()
+ cfg_if::cfg_if! {
+ if #[cfg(vendor_modules)] {
+ self.gki.as_deref()
+ } else {
+ None
+ }
+ }
}
- #[cfg(not(vendor_modules))]
- fn gki(&self) -> Option<&str> {
- None
- }
-
- #[cfg(device_assignment)]
fn devices(&self) -> &[PathBuf] {
- &self.devices
- }
-
- #[cfg(not(device_assignment))]
- fn devices(&self) -> &[PathBuf] {
- &[]
+ cfg_if::cfg_if! {
+ if #[cfg(device_assignment)] {
+ &self.devices
+ } else {
+ &[]
+ }
+ }
}
}
@@ -236,35 +236,36 @@
}
impl RunAppConfig {
- #[cfg(multi_tenant)]
fn extra_apks(&self) -> &[PathBuf] {
- &self.extra_apks
+ cfg_if::cfg_if! {
+ if #[cfg(multi_tenant)] {
+ &self.extra_apks
+ } else {
+ &[]
+ }
+ }
}
- #[cfg(not(multi_tenant))]
- fn extra_apks(&self) -> &[PathBuf] {
- &[]
- }
-
- #[cfg(llpvm_changes)]
fn instance_id(&self) -> Result<PathBuf, Error> {
- Ok(self.instance_id.clone())
+ cfg_if::cfg_if! {
+ if #[cfg(llpvm_changes)] {
+ Ok(self.instance_id.clone())
+ } else {
+ Err(anyhow!("LLPVM feature is disabled, --instance_id flag not supported"))
+ }
+ }
}
- #[cfg(not(llpvm_changes))]
- fn instance_id(&self) -> Result<PathBuf, Error> {
- Err(anyhow!("LLPVM feature is disabled, --instance_id flag not supported"))
- }
-
- #[cfg(llpvm_changes)]
fn set_instance_id(&mut self, instance_id_file: PathBuf) -> Result<(), Error> {
- self.instance_id = instance_id_file;
- Ok(())
- }
-
- #[cfg(not(llpvm_changes))]
- fn set_instance_id(&mut self, _: PathBuf) -> Result<(), Error> {
- Err(anyhow!("LLPVM feature is disabled, --instance_id flag not supported"))
+ cfg_if::cfg_if! {
+ if #[cfg(llpvm_changes)] {
+ self.instance_id = instance_id_file;
+ Ok(())
+ } else {
+ let _ = instance_id_file;
+ Err(anyhow!("LLPVM feature is disabled, --instance_id flag not supported"))
+ }
+ }
}
}
diff --git a/build/apex/Android.bp b/build/apex/Android.bp
index f493202..be62d18 100644
--- a/build/apex/Android.bp
+++ b/build/apex/Android.bp
@@ -107,6 +107,7 @@
filesystems: microdroid_filesystem_images,
prebuilts: [
"rialto_bin",
+ "android_bootloader_crosvm_aarch64",
],
},
x86_64: {
@@ -125,6 +126,9 @@
default: [],
}),
filesystems: microdroid_filesystem_images,
+ prebuilts: [
+ "android_bootloader_crosvm_x86_64",
+ ],
},
},
binaries: [
@@ -138,7 +142,6 @@
"microdroid.json",
"microdroid_kernel",
"com.android.virt.init.rc",
- "android_bootloader_crosvm_aarch64",
] + select(soong_config_variable("ANDROID", "avf_microdroid_guest_gki_version"), {
"android15_66": [
"microdroid_gki-android15-6.6_initrd_debuggable",
diff --git a/docs/device_assignment.md b/docs/device_assignment.md
index 4b2296c..6011d8f 100644
--- a/docs/device_assignment.md
+++ b/docs/device_assignment.md
@@ -205,6 +205,18 @@
* `<sysfs_path>`: Sysfs path of the device in host, used to bind to the VFIO
driver. Must be non-empty and unique in the XML.
+### List support assignable devices
+
+In order to query list of the devices that can be assigned to a pVM, run the
+following command:
+
+```bash
+adb shell /apex/com.android.virt/bin/vm info
+```
+
+All supported assignable devices will be located under the "Assignable devices:"
+section of the output.
+
## Boot with VM DTBO
Bootloader should provide VM DTBO to both Android and pvmfw.
diff --git a/docs/img/rkpvm-dice-chain.png b/docs/img/rkpvm-dice-chain.png
new file mode 100644
index 0000000..6847f7f
--- /dev/null
+++ b/docs/img/rkpvm-dice-chain.png
Binary files differ
diff --git a/docs/vm_remote_attestation.md b/docs/vm_remote_attestation.md
index 79f44b9..ee20591 100644
--- a/docs/vm_remote_attestation.md
+++ b/docs/vm_remote_attestation.md
@@ -46,17 +46,17 @@
spec.
[open-dice]: https://android.googlesource.com/platform/external/open-dice/+/main/docs/android.md
-[rkpvm-marker]: https://android.googlesource.com/platform/external/open-dice/+/main/docs/android.md#Configuration-descriptor
-[rkp-hal]: https://android.googlesource.com/platform/hardware/interfaces/+/main/security/rkp/README.md
### pVM attestation
Once the RKP VM is successfully attested, it acts as a trusted platform to
attest pVMs. Leveraging its trusted status, the RKP VM validates the integrity
-of each pVM's DICE chain by comparing it against its own DICE chain. This
-validation process ensures that the pVMs are running in the expected VM
-environment and certifies the payload executed within each pVM. Currently, only
-Microdroid VMs are supported.
+of each [pVM DICE chain][pvm-dice-chain] by comparing it against its own DICE
+chain. This validation process ensures that the pVMs are running in the expected
+VM environment and certifies the payload executed within each pVM. Currently,
+only Microdroid VMs are supported.
+
+[pvm-dice-chain]: ./pvm_dice_chain.md
## API
@@ -113,13 +113,37 @@
## To Support It
-VM remote attestation is a strongly recommended feature from Android V. To support
-it, you only need to provide a valid VM DICE chain satisfying the following
-requirements:
+VM remote attestation is a strongly recommended feature from Android V. To
+support it, you only need to provide a valid VM DICE chain satisfying the
+following requirements:
-- The DICE chain must have a UDS-rooted public key registered at the RKP factory.
-- The DICE chain should have RKP VM markers that help identify RKP VM as required
- by the [remote provisioning HAL][rkp-hal-markers].
+- The DICE chain must have a UDS-rooted public key registered at the RKP
+ factory.
+- The DICE chain must use [RKP VM markers][rkpvm-marker] to help identify the
+ RKP VM as required by the [remote provisioning HAL][rkp-hal].
+
+### RKP VM marker
+
+To support VM remote attestation, vendors must include an RKP VM marker in their
+DICE certificates. This marker should be present from the early boot stage
+within the TEE and continue through to the last DICE certificate before
+[pvmfw][pvmfw] takes over.
+
+![RKP VM DICE chain][rkpvm-dice-chain]
+
+Pvmfw will add an RKP VM marker when it's launching an RKP VM. The __continuous
+presence__ of this marker throughout the chain allows the RKP server to clearly
+identify legitimate RKP VM DICE chains.
+
+This mechanism also serves as a security measure. If an attacker tries to launch
+a malicious guest OS or payload, their DICE chain will be rejected by the RKP
+server because it will lack the RKP VM marker that pvmfw would have added in a
+genuine RKP VM boot process.
+
+[pvmfw]: ../guest/pvmfw/README.md
+[rkpvm-dice-chain]: img/rkpvm-dice-chain.png
+
+## To Disable It
The feature is enabled by default. To disable it, you have two options:
@@ -133,4 +157,5 @@
If you don't set any of these variables, VM remote attestation will be enabled
by default.
-[rkp-hal-markers]: https://android.googlesource.com/platform/hardware/interfaces/+/main/security/rkp/README.md#hal
+[rkpvm-marker]: https://pigweed.googlesource.com/open-dice/+/HEAD/docs/android.md#configuration-descriptor
+[rkp-hal]: https://android.googlesource.com/platform/hardware/interfaces/+/main/security/rkp/README.md#hal
diff --git a/guest/microdroid_manager/src/main.rs b/guest/microdroid_manager/src/main.rs
index 7352a2c..8186e9d 100644
--- a/guest/microdroid_manager/src/main.rs
+++ b/guest/microdroid_manager/src/main.rs
@@ -654,7 +654,7 @@
if requested {
let status = Command::new("/system/bin/kexec_load").status()?;
if !status.success() {
- return Err(anyhow!("Failed to load crashkernel: {:?}", status));
+ return Err(anyhow!("Failed to load crashkernel: {status}"));
}
info!("ramdump is loaded: debuggable={debuggable}, ramdump={ramdump}");
}
diff --git a/guest/pvmfw/Android.bp b/guest/pvmfw/Android.bp
index 144e81e..b502af6 100644
--- a/guest/pvmfw/Android.bp
+++ b/guest/pvmfw/Android.bp
@@ -13,7 +13,6 @@
rustlibs: [
"libaarch64_paging",
"libbssl_avf_nostd",
- "libbssl_sys_nostd",
"libcbor_util_nostd",
"libciborium_nostd",
"libciborium_io_nostd",
diff --git a/guest/pvmfw/src/entry.rs b/guest/pvmfw/src/entry.rs
index 8f9340b..945ad6a 100644
--- a/guest/pvmfw/src/entry.rs
+++ b/guest/pvmfw/src/entry.rs
@@ -17,7 +17,6 @@
use crate::config;
use crate::fdt;
use crate::memory;
-use bssl_sys::CRYPTO_library_init;
use core::arch::asm;
use core::mem::{drop, size_of};
use core::num::NonZeroUsize;
@@ -216,12 +215,6 @@
// - only access non-pvmfw memory once (and while) it has been mapped
log::set_max_level(LevelFilter::Info);
- // TODO(https://crbug.com/boringssl/35): Remove this init when BoringSSL can handle this
- // internally.
- // SAFETY: Configures the internal state of the library - may be called multiple times.
- unsafe {
- CRYPTO_library_init();
- }
let page_table = memory::init_page_table().map_err(|e| {
error!("Failed to set up the dynamic page tables: {e}");
diff --git a/guest/rialto/Android.bp b/guest/rialto/Android.bp
index b26a1c4..4c18bf9 100644
--- a/guest/rialto/Android.bp
+++ b/guest/rialto/Android.bp
@@ -10,7 +10,6 @@
rustlibs: [
"libaarch64_paging",
"libbssl_avf_nostd",
- "libbssl_sys_nostd",
"libciborium_io_nostd",
"libciborium_nostd",
"libcstr",
diff --git a/guest/rialto/src/main.rs b/guest/rialto/src/main.rs
index 7de8718..9265775 100644
--- a/guest/rialto/src/main.rs
+++ b/guest/rialto/src/main.rs
@@ -28,7 +28,6 @@
use crate::error::{Error, Result};
use crate::fdt::{read_dice_range_from, read_is_strict_boot, read_vendor_hashtree_root_digest};
use alloc::boxed::Box;
-use bssl_sys::CRYPTO_library_init;
use ciborium_io::Write;
use core::num::NonZeroUsize;
use core::slice;
@@ -133,12 +132,6 @@
})?;
}
- // Initializes the crypto library before any crypto operations and after the heap is
- // initialized.
- // SAFETY: It is safe to call this function multiple times and concurrently.
- unsafe {
- CRYPTO_library_init();
- }
let bcc_handover: Box<dyn DiceArtifacts> = match vm_type(fdt)? {
VmType::ProtectedVm => {
let dice_range = read_dice_range_from(fdt)?;
@@ -228,6 +221,28 @@
}
}
+/// Flushes data caches over the provided address range.
+///
+/// # Safety
+///
+/// The provided address and size must be to an address range that is valid for read and write
+/// (typically on the stack, .bss, .data, or provided BCC) from a single allocation
+/// (e.g. stack array).
+#[no_mangle]
+unsafe extern "C" fn DiceClearMemory(
+ _ctx: *mut core::ffi::c_void,
+ size: usize,
+ addr: *mut core::ffi::c_void,
+) {
+ use core::slice;
+ use vmbase::memory::flushed_zeroize;
+
+ // SAFETY: We require our caller to provide a valid range within a single object. The open-dice
+ // always calls this on individual stack-allocated arrays which ensures that.
+ let region = unsafe { slice::from_raw_parts_mut(addr as *mut u8, size) };
+ flushed_zeroize(region)
+}
+
generate_image_header!();
main!(main);
configure_heap!(SIZE_128KB * 2);
diff --git a/libs/dice/open_dice/Android.bp b/libs/dice/open_dice/Android.bp
index efe350f..d1129fb 100644
--- a/libs/dice/open_dice/Android.bp
+++ b/libs/dice/open_dice/Android.bp
@@ -22,7 +22,6 @@
"alloc",
],
whole_static_libs: [
- "libopen_dice_cbor",
"libcrypto_baremetal",
],
visibility: [
@@ -55,6 +54,7 @@
"//packages/modules/Virtualization:__subpackages__",
"//system/authgraph/tests:__subpackages__",
"//system/secretkeeper/client:__subpackages__",
+ "//system/software_defined_vehicle:__subpackages__",
],
apex_available: [
"//apex_available:platform",
diff --git a/libs/dice/sample_inputs/tests/api_test.rs b/libs/dice/sample_inputs/tests/api_test.rs
index 0823f16..d713168 100644
--- a/libs/dice/sample_inputs/tests/api_test.rs
+++ b/libs/dice/sample_inputs/tests/api_test.rs
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#![cfg_attr(not(feature = "std"), no_std)]
+
use anyhow::Result;
use diced_open_dice::{derive_cdi_leaf_priv, sign, DiceArtifacts};
use diced_sample_inputs::make_sample_bcc_and_cdis;
@@ -144,3 +146,21 @@
let public_key = chain.leaf().subject_public_key();
public_key.verify(&signature, MESSAGE)
}
+
+/// Flushes data caches over the provided address range in open-dice.
+///
+/// # Safety
+///
+/// The provided address and size must be to an address range that is valid for read and write
+/// (typically on the stack, .bss, .data, or provided BCC) from a single allocation
+/// (e.g. stack array).
+#[cfg(not(feature = "std"))]
+#[no_mangle]
+unsafe extern "C" fn DiceClearMemory(
+ _ctx: *mut core::ffi::c_void,
+ size: usize,
+ addr: *mut core::ffi::c_void,
+) {
+ // SAFETY: The caller ensures that the address and size are valid for write.
+ unsafe { core::ptr::write_bytes(addr as *mut u8, 0, size) };
+}
diff --git a/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java b/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java
index cb21ccf..de1b081 100644
--- a/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java
+++ b/libs/framework-virtualization/src/android/system/virtualmachine/VirtualMachineConfig.java
@@ -78,7 +78,8 @@
private static final String TAG = "VirtualMachineConfig";
private static String[] EMPTY_STRING_ARRAY = {};
- private static final String U_BOOT_PREBUILT_PATH = "/apex/com.android.virt/etc/u-boot.bin";
+ private static final String U_BOOT_PREBUILT_PATH_ARM = "/apex/com.android.virt/etc/u-boot.bin";
+ private static final String U_BOOT_PREBUILT_PATH_X86 = "/apex/com.android.virt/etc/u-boot.rom";
// These define the schema of the config file persisted on disk.
// Please bump up the version number when adding a new key.
@@ -668,7 +669,11 @@
.orElse(null);
if (config.kernel == null && config.bootloader == null) {
- config.bootloader = openOrNull(new File(U_BOOT_PREBUILT_PATH), MODE_READ_ONLY);
+ if (Arrays.stream(Build.SUPPORTED_ABIS).anyMatch("x86_64"::equals)) {
+ config.bootloader = openOrNull(new File(U_BOOT_PREBUILT_PATH_X86), MODE_READ_ONLY);
+ } else {
+ config.bootloader = openOrNull(new File(U_BOOT_PREBUILT_PATH_ARM), MODE_READ_ONLY);
+ }
}
config.params =
diff --git a/tests/hostside/helper/java/com/android/microdroid/test/host/KvmHypTracer.java b/tests/hostside/helper/java/com/android/microdroid/test/host/KvmHypTracer.java
index 3814cdd..8604553 100644
--- a/tests/hostside/helper/java/com/android/microdroid/test/host/KvmHypTracer.java
+++ b/tests/hostside/helper/java/com/android/microdroid/test/host/KvmHypTracer.java
@@ -78,9 +78,9 @@
/** This class provides utilities to interact with the hyp tracing subsystem */
public final class KvmHypTracer {
- private static final String HYP_TRACING_ROOT = "/sys/kernel/tracing/hyp/";
private static final int DEFAULT_BUF_SIZE_KB = 4 * 1024;
+ private final String mHypTracingRoot;
private final CommandRunner mRunner;
private final ITestDevice mDevice;
private final int mNrCpus;
@@ -88,17 +88,41 @@
private final ArrayList<File> mTraces;
- private void setNode(String node, int val) throws Exception {
- mRunner.run("echo " + val + " > " + HYP_TRACING_ROOT + node);
+ private static String getHypTracingRoot(ITestDevice device) throws Exception {
+ String legacy = "/sys/kernel/tracing/hyp/";
+ String path = "/sys/kernel/tracing/hypervisor/";
+
+ if (device.doesFileExist(path)) {
+ return path;
+ }
+
+ if (device.doesFileExist(legacy)) {
+ return legacy;
+ }
+
+ throw new Exception("Hypervisor tracing not found");
}
- private static String eventDir(String event) {
- return "events/hyp/" + event + "/";
+ private static String getHypEventsDir(String root) {
+ if (root.endsWith("/hypervisor/"))
+ return "events/hypervisor/";
+
+ return "events/hyp/";
}
public static boolean isSupported(ITestDevice device, String[] events) throws Exception {
- for (String event : events) {
- if (!device.doesFileExist(HYP_TRACING_ROOT + eventDir(event) + "/enable")) return false;
+ String dir;
+
+ try {
+ dir = getHypTracingRoot(device);
+ dir += getHypEventsDir(dir);
+ } catch (Exception e) {
+ return false;
+ }
+
+ for (String event: events) {
+ if (!device.doesFileExist(dir + event + "/enable"))
+ return false;
}
return true;
}
@@ -108,6 +132,7 @@
.that(isSupported(device, events))
.isTrue();
+ mHypTracingRoot = getHypTracingRoot(device);
mDevice = device;
mRunner = new CommandRunner(mDevice);
mTraces = new ArrayList<File>();
@@ -115,17 +140,25 @@
mHypEvents = events;
}
+ private void setNode(String node, int val) throws Exception {
+ mRunner.run("echo " + val + " > " + mHypTracingRoot + node);
+ }
+
public String run(String payload_cmd) throws Exception {
mTraces.clear();
setNode("tracing_on", 0);
- mRunner.run("echo 0 | tee " + HYP_TRACING_ROOT + "events/*/*/enable");
+ mRunner.run("echo 0 | tee " + mHypTracingRoot + "events/*/*/enable");
setNode("buffer_size_kb", DEFAULT_BUF_SIZE_KB);
- for (String event : mHypEvents) setNode(eventDir(event) + "/enable", 1);
+
+ for (String event: mHypEvents) {
+ setNode(getHypEventsDir(mHypTracingRoot) + event + "/enable", 1);
+ }
+
setNode("trace", 0);
/* Cat each per-cpu trace_pipe in its own tmp file in the background */
- String cmd = "cd " + HYP_TRACING_ROOT + ";";
+ String cmd = "cd " + mHypTracingRoot + ";";
String trace_pipes[] = new String[mNrCpus];
for (int i = 0; i < mNrCpus; i++) {
trace_pipes[i] = mRunner.run("mktemp -t trace_pipe.cpu" + i + ".XXXXXXXXXX");