Merge "Validate setOs and --gki when creating a VM" into main
diff --git a/microdroid/README.md b/microdroid/README.md
index dd1505f..c82ef0b 100644
--- a/microdroid/README.md
+++ b/microdroid/README.md
@@ -138,6 +138,53 @@
If you are looking for an example usage of the APIs, you may refer to the [demo
app](https://android.googlesource.com/platform/packages/modules/Virtualization/+/refs/heads/master/demo/).
+
+## Running Microdroid with vendor image
+
+With using `vm` tool, execute the following commands to launch a VM with vendor
+partition.
+
+```sh
+adb shell /apex/com.android.virt/bin/vm run-microdroid \
+--vendor $VENDOR_IMAGE
+```
+
+### Verification of vendor image
+
+Since vendor image of Microdroid is not part of `com.android.virt` APEX, the
+verification process of vendor partition is different from others.
+
+Vendor image uses its hashtree digest for the verifying its data, generated
+by `add_hashtree_footer` in `avbtool`. The value could be seen with following
+command:
+
+```sh
+avbtool info_image --image $VENDOR_IMAGE
+```
+
+Fixed path in VM for vendor hashtree digest is written in [fstab.microdroid].
+During first stage init of VM, [dm-verity] is set up based on vendor hashtree
+digest by reading [fstab.microdroid].
+
+For non-pVM, virtualizationmanager creates [DTBO] containing vendor hashtree
+digest, and passes to the VM via crosvm option. The vendor hashtree digest is
+obtained by virtualizationmanager from the host Android DT under
+`/avf/reference/`, which may be populated by the [bootloader].
+
+For pVM, VM reference DT included in [pvmfw config data] is additionally used
+for validating vendor hashtree digest. [Bootloader][bootloader] should append
+vendor hashtree digest into VM reference DT based on [fstab.microdroid]. Vendor
+hashtree digest could be appended as property into descriptors in host Android's
+vendor image by [Makefile] when Microdroid vendor image module is defined, so
+that a [bootloader] can extract the value and populate into VM reference DT.
+
+[fstab.microdroid]: fstab.microdroid
+[dm-verity]: https://source.android.com/docs/security/features/verifiedboot/dm-verity
+[DTBO]: https://android.googlesource.com/platform/external/dtc/+/refs/heads/main/Documentation/dt-object-internal.txt
+[pvmfw config data]: ../pvmfw/README.md#configuration-data-format
+[bootloader]: https://source.android.com/docs/core/architecture/bootloader
+[Makefile]: https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile
+
## Debugging Microdroid
Refer to [Debugging protected VMs](../docs/debug/README.md).
diff --git a/microdroid/kernel/README.md b/microdroid/kernel/README.md
index 78ac81b..92b7cfe 100644
--- a/microdroid/kernel/README.md
+++ b/microdroid/kernel/README.md
@@ -19,13 +19,13 @@
For ARM64
```bash
tools/bazel clean
-tools/bazel run --config=fast --lto=thin //common-modules/virtual-device:microdroid_aarch64_dist -- --dist_dir=out/dist
+tooln/bazel run --config=fast //common:kernel_aarch64_microdroid_dist -- --dist_dir=out/dist
```
For x86\_64,
```bash
tools/bazel clean
-tools/bazel run --config=fast --lto=thin //common-modules/virtual-device:microdroid_x86_64_dist -- --dist_dir=out/dist
+tools/bazel run --config=fast //common:kernel_x86_64_microdroid_dist -- --dist_dir=out/dist
```
Note that
@@ -39,12 +39,12 @@
For ARM64
```bash
-tools/bazel run //common-modules/virtual-device:microdroid_aarch64_config -- menuconfig
+tools/bazel run //common:kernel_aarch64_microdroid_config -- menuconfig
```
For x86\_64
```bash
-tools/bazel run //common-modules/virtual-device:microdroid_x86_64_config -- menuconfig
+tools/bazel run //common:kernel_x86_64_microdroid_config -- menuconfig
```
## How to update Microdroid kernel prebuilts
diff --git a/pvmfw/README.md b/pvmfw/README.md
index 124ef89..795bb05 100644
--- a/pvmfw/README.md
+++ b/pvmfw/README.md
@@ -141,7 +141,11 @@
+-------------------------------+
| [Entry 2] | <-- Entry 2 is present since version 1.1
| offset = (THIRD - HEAD) |
-| size = (THIRD_END - SECOND) |
+| size = (THIRD_END - THIRD) |
++-------------------------------+
+| [Entry 3] | <-- Entry 3 is present since version 1.2
+| offset = (FOURTH - HEAD) |
+| size = (FOURTH_END - FOURTH) |
+-------------------------------+
| ... |
+-------------------------------+
@@ -149,17 +153,21 @@
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
| (Padding to 8-byte alignment) |
+===============================+ <-- FIRST
-| {First blob: BCC} |
+| {First blob: BCC} |
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ <-- FIRST_END
| (Padding to 8-byte alignment) |
+===============================+ <-- SECOND
-| {Second blob: DP} |
+| {Second blob: DP} |
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ <-- SECOND_END
| (Padding to 8-byte alignment) |
+===============================+ <-- THIRD
-| {Third blob: VM DTBO} |
+| {Third blob: VM DTBO} |
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ <-- THIRD_END
| (Padding to 8-byte alignment) |
++===============================+ <-- FOURTH
+| {Fourth blob: VM reference DT}|
++~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ <-- FOURTH_END
+| (Padding to 8-byte alignment) |
+===============================+
| ... |
+===============================+ <-- TAIL
@@ -185,14 +193,38 @@
- entry 1 may point to a [DTBO] to be applied to the pVM device tree. See
[debug policy][debug_policy] for an example.
-In version 1.1, new blob is added.
+In version 1.1, a third blob is added.
- entry 2 may point to a [DTBO] that describes VM DTBO for device assignment.
pvmfw will provision assigned devices with the VM DTBO.
+In version 1.2, a fourth blob is added.
+
+- entry 3 if present contains the VM reference DT. This defines properties that
+ may be included in the device tree passed to a protected VM. pvmfw validates
+ that if any of these properties is included in the VM's device tree, the
+ property value exactly matches what is in the VM reference DT.
+
+ The bootloader should ensure that the same properties, with the same values,
+ are added under the "/avf/reference" node in the host Android device tree.
+
+ This provides a mechanism to allow configuration information to be securely
+ passed to the VM via the host. pvmfw does not interpret the content of VM
+ reference DT, nor does it apply it to the VM's device tree, it just ensures
+ that if matching properties are present in the VM device tree they contain the
+ correct values.
+
+ One use case for this mechanism is passing the [public key of the
+ Secretkeeper][secretkeeper_key] HAL implementation to each VM.
+
+<!--
+ TODO(b/319192461): Attach link explaining about Microdroid vendor partition
+-->
+
[header]: src/config.rs
[DTBO]: https://android.googlesource.com/platform/external/dtc/+/refs/heads/main/Documentation/dt-object-internal.txt
[debug_policy]: ../docs/debug/README.md#debug-policy
+[secretkeeper_key]: https://android.googlesource.com/platform/system/secretkeeper/+/refs/heads/main/README.md#secretkeeper-public-key
#### Virtual Platform Boot Certificate Chain Handover
diff --git a/pvmfw/src/config.rs b/pvmfw/src/config.rs
index 7b548ce..5a3d138 100644
--- a/pvmfw/src/config.rs
+++ b/pvmfw/src/config.rs
@@ -141,7 +141,7 @@
pub bcc: &'a mut [u8],
pub debug_policy: Option<&'a [u8]>,
pub vm_dtbo: Option<&'a mut [u8]>,
- pub vm_base_dtbo: Option<&'a [u8]>,
+ pub vm_ref_dt: Option<&'a [u8]>,
}
#[repr(packed)]
@@ -290,15 +290,15 @@
entries[i] = Some(chunk);
}
}
- let [bcc, debug_policy, vm_dtbo, vm_base_dtbo] = entries;
+ let [bcc, debug_policy, vm_dtbo, vm_ref_dt] = entries;
// The platform BCC has always been required.
let bcc = bcc.unwrap();
// We have no reason to mutate so drop the `mut`.
let debug_policy = debug_policy.map(|x| &*x);
- let vm_base_dtbo = vm_base_dtbo.map(|x| &*x);
+ let vm_ref_dt = vm_ref_dt.map(|x| &*x);
- Entries { bcc, debug_policy, vm_dtbo, vm_base_dtbo }
+ Entries { bcc, debug_policy, vm_dtbo, vm_ref_dt }
}
}
diff --git a/pvmfw/src/entry.rs b/pvmfw/src/entry.rs
index 8eca7a1..253604b 100644
--- a/pvmfw/src/entry.rs
+++ b/pvmfw/src/entry.rs
@@ -88,7 +88,7 @@
kernel: usize,
kernel_size: usize,
vm_dtbo: Option<&mut [u8]>,
- vm_base_dtbo: Option<&[u8]>,
+ vm_ref_dt: Option<&[u8]>,
) -> Result<Self, RebootReason> {
let fdt_size = NonZeroUsize::new(crosvm::FDT_MAX_SIZE).unwrap();
// TODO - Only map the FDT as read-only, until we modify it right before jump_to_payload()
@@ -102,7 +102,7 @@
// SAFETY: The tracker validated the range to be in main memory, mapped, and not overlap.
let fdt = unsafe { slice::from_raw_parts_mut(range.start as *mut u8, range.len()) };
- let info = fdt::sanitize_device_tree(fdt, vm_dtbo, vm_base_dtbo)?;
+ let info = fdt::sanitize_device_tree(fdt, vm_dtbo, vm_ref_dt)?;
let fdt = libfdt::Fdt::from_mut_slice(fdt).map_err(|e| {
error!("Failed to load sanitized FDT: {e}");
RebootReason::InvalidFdt
@@ -233,7 +233,7 @@
payload,
payload_size,
config_entries.vm_dtbo,
- config_entries.vm_base_dtbo,
+ config_entries.vm_ref_dt,
)?;
// This wrapper allows main() to be blissfully ignorant of platform details.
diff --git a/pvmfw/src/fdt.rs b/pvmfw/src/fdt.rs
index 33a5055..2ea4599 100644
--- a/pvmfw/src/fdt.rs
+++ b/pvmfw/src/fdt.rs
@@ -202,7 +202,7 @@
}
/// Read candidate properties' names from DT which could be overlaid
-fn parse_vm_base_dtbo(fdt: &Fdt) -> libfdt::Result<BTreeMap<CString, Vec<u8>>> {
+fn parse_vm_ref_dt(fdt: &Fdt) -> libfdt::Result<BTreeMap<CString, Vec<u8>>> {
let mut property_map = BTreeMap::new();
if let Some(avf_node) = fdt.node(cstr!("/avf"))? {
for property in avf_node.properties()? {
@@ -217,29 +217,28 @@
Ok(property_map)
}
-/// Overlay VM base DTBO into VM DT based on the props_info. Property is overlaid in vm_dt only
-/// when it exists both in vm_base_dtbo and props_info. If the values mismatch, it returns error.
-fn apply_vm_base_dtbo(
+/// Overlay VM reference DT into VM DT based on the props_info. Property is overlaid in vm_dt only
+/// when it exists both in vm_ref_dt and props_info. If the values mismatch, it returns error.
+fn validate_vm_ref_dt(
vm_dt: &mut Fdt,
- vm_base_dtbo: &Fdt,
+ vm_ref_dt: &Fdt,
props_info: &BTreeMap<CString, Vec<u8>>,
) -> libfdt::Result<()> {
let mut root_vm_dt = vm_dt.root_mut()?;
let mut avf_vm_dt = root_vm_dt.add_subnode(cstr!("avf"))?;
- // TODO(b/318431677): Validate nodes beyond /fragment@0/__overlay__/avf and use apply_overlay.
- let avf_vm_base_dtbo =
- vm_base_dtbo.node(cstr!("/fragment@0/__overlay__/avf"))?.ok_or(FdtError::NotFound)?;
+ // TODO(b/318431677): Validate nodes beyond /avf.
+ let avf_node = vm_ref_dt.node(cstr!("/avf"))?.ok_or(FdtError::NotFound)?;
for (name, value) in props_info.iter() {
- if let Some(value_in_vm_base_dtbo) = avf_vm_base_dtbo.getprop(name)? {
- if value != value_in_vm_base_dtbo {
+ if let Some(ref_value) = avf_node.getprop(name)? {
+ if value != ref_value {
error!(
- "Property mismatches while applying overlay VM base DTBO. \
- Name:{:?}, Value from host as hex:{:x?}, Value from VM base DTBO as hex:{:x?}",
- name, value, value_in_vm_base_dtbo
+ "Property mismatches while applying overlay VM reference DT. \
+ Name:{:?}, Value from host as hex:{:x?}, Value from VM reference DT as hex:{:x?}",
+ name, value, ref_value
);
return Err(FdtError::BadValue);
}
- avf_vm_dt.setprop(name, value_in_vm_base_dtbo)?;
+ avf_vm_dt.setprop(name, ref_value)?;
}
}
Ok(())
@@ -637,7 +636,7 @@
serial_info: SerialInfo,
pub swiotlb_info: SwiotlbInfo,
device_assignment: Option<DeviceAssignmentInfo>,
- vm_base_dtbo_props_info: BTreeMap<CString, Vec<u8>>,
+ vm_ref_dt_props_info: BTreeMap<CString, Vec<u8>>,
}
impl DeviceTreeInfo {
@@ -651,7 +650,7 @@
pub fn sanitize_device_tree(
fdt: &mut [u8],
vm_dtbo: Option<&mut [u8]>,
- vm_base_dtbo: Option<&[u8]>,
+ vm_ref_dt: Option<&[u8]>,
) -> Result<DeviceTreeInfo, RebootReason> {
let fdt = Fdt::from_mut_slice(fdt).map_err(|e| {
error!("Failed to load FDT: {e}");
@@ -695,14 +694,14 @@
}
}
- if let Some(vm_base_dtbo) = vm_base_dtbo {
- let vm_base_dtbo = Fdt::from_slice(vm_base_dtbo).map_err(|e| {
- error!("Failed to load VM base DTBO: {e}");
+ if let Some(vm_ref_dt) = vm_ref_dt {
+ let vm_ref_dt = Fdt::from_slice(vm_ref_dt).map_err(|e| {
+ error!("Failed to load VM reference DT: {e}");
RebootReason::InvalidFdt
})?;
- apply_vm_base_dtbo(fdt, vm_base_dtbo, &info.vm_base_dtbo_props_info).map_err(|e| {
- error!("Failed to apply VM base DTBO: {e}");
+ validate_vm_ref_dt(fdt, vm_ref_dt, &info.vm_ref_dt_props_info).map_err(|e| {
+ error!("Failed to apply VM reference DT: {e}");
RebootReason::InvalidFdt
})?;
}
@@ -780,7 +779,7 @@
None => None,
};
- let vm_base_dtbo_props_info = parse_vm_base_dtbo(fdt).map_err(|e| {
+ let vm_ref_dt_props_info = parse_vm_ref_dt(fdt).map_err(|e| {
error!("Failed to read names of properties under /avf from DT: {e}");
RebootReason::InvalidFdt
})?;
@@ -795,7 +794,7 @@
serial_info,
swiotlb_info,
device_assignment,
- vm_base_dtbo_props_info,
+ vm_ref_dt_props_info,
})
}