Merge "pvmfw: Parse incoming <reg> and <iommus>" into main
diff --git a/apex/Android.bp b/apex/Android.bp
index acbc0a1..b09cf58 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -143,10 +143,10 @@
},
release_avf_enable_vendor_modules: {
prebuilts: [
- "microdroid_gki-6.1_initrd_debuggable",
- "microdroid_gki-6.1_initrd_normal",
- "microdroid_gki-6.1_kernel",
- "microdroid_gki-6.1.json",
+ "microdroid_gki-android14-6.1_initrd_debuggable",
+ "microdroid_gki-android14-6.1_initrd_normal",
+ "microdroid_gki-android14-6.1_kernel",
+ "microdroid_gki-android14-6.1.json",
],
},
release_avf_enable_remote_attestation: {
diff --git a/apex/sign_virt_apex.py b/apex/sign_virt_apex.py
index 0c5bc72..a975be0 100644
--- a/apex/sign_virt_apex.py
+++ b/apex/sign_virt_apex.py
@@ -411,7 +411,7 @@
RunCommand(args, cmd)
-gki_versions = ['6.1']
+gki_versions = ['android14-6.1']
# dict of (key, file) for re-sign/verification. keys are un-versioned for readability.
virt_apex_non_gki_files = {
diff --git a/libs/bssl/error/src/lib.rs b/libs/bssl/error/src/lib.rs
index 7f01c6c..82a2d5e 100644
--- a/libs/bssl/error/src/lib.rs
+++ b/libs/bssl/error/src/lib.rs
@@ -91,6 +91,7 @@
ECDSA_sign,
ECDSA_size,
ECDSA_verify,
+ ED25519_verify,
EVP_AEAD_CTX_new,
EVP_AEAD_CTX_open,
EVP_AEAD_CTX_seal,
diff --git a/libs/bssl/src/curve25519.rs b/libs/bssl/src/curve25519.rs
new file mode 100644
index 0000000..499a3d0
--- /dev/null
+++ b/libs/bssl/src/curve25519.rs
@@ -0,0 +1,39 @@
+// 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.
+
+//! Wrappers of the Curve25519 related functions in BoringSSL curve25519.h.
+
+use crate::util::check_int_result;
+use bssl_avf_error::{ApiName, Result};
+
+const ED25519_PUBLIC_KEY_LEN: usize = bssl_ffi::ED25519_PUBLIC_KEY_LEN as usize;
+const ED25519_SIGNATURE_LEN: usize = bssl_ffi::ED25519_SIGNATURE_LEN as usize;
+
+/// Verifies the signature of a message with the given ED25519 public key.
+pub fn ed25519_verify(
+ message: &[u8],
+ signature: &[u8; ED25519_SIGNATURE_LEN],
+ public_key: &[u8; ED25519_PUBLIC_KEY_LEN],
+) -> Result<()> {
+ // SAFETY: The function only reads the parameters within their bounds.
+ let ret = unsafe {
+ bssl_ffi::ED25519_verify(
+ message.as_ptr(),
+ message.len(),
+ signature.as_ptr(),
+ public_key.as_ptr(),
+ )
+ };
+ check_int_result(ret, ApiName::ED25519_verify)
+}
diff --git a/libs/bssl/src/lib.rs b/libs/bssl/src/lib.rs
index a420168..ad51b61 100644
--- a/libs/bssl/src/lib.rs
+++ b/libs/bssl/src/lib.rs
@@ -21,6 +21,7 @@
mod aead;
mod cbb;
mod cbs;
+mod curve25519;
mod digest;
mod ec_key;
mod err;
@@ -36,6 +37,7 @@
pub use aead::{Aead, AeadContext, AES_GCM_NONCE_LENGTH};
pub use cbb::CbbFixed;
pub use cbs::Cbs;
+pub use curve25519::ed25519_verify;
pub use digest::Digester;
pub use ec_key::{EcKey, ZVec};
pub use evp::{PKey, PKeyType};
diff --git a/libs/dice/open_dice/Android.bp b/libs/dice/open_dice/Android.bp
index 646080d..2d0f52c 100644
--- a/libs/dice/open_dice/Android.bp
+++ b/libs/dice/open_dice/Android.bp
@@ -27,12 +27,14 @@
],
visibility: [
"//packages/modules/Virtualization:__subpackages__",
+ "//system/authgraph/tests:__subpackages__",
],
}
rust_library {
name: "libdiced_open_dice",
defaults: ["libdiced_open_dice_defaults"],
+ host_supported: true,
vendor_available: true,
rustlibs: [
"libopen_dice_android_bindgen",
@@ -54,6 +56,7 @@
],
visibility: [
"//packages/modules/Virtualization:__subpackages__",
+ "//system/authgraph/tests:__subpackages__",
],
apex_available: [
"//apex_available:platform",
diff --git a/microdroid/Android.bp b/microdroid/Android.bp
index c1caa56..f98f3af 100644
--- a/microdroid/Android.bp
+++ b/microdroid/Android.bp
@@ -557,17 +557,17 @@
}
///////////////////////////////////////
-// GKI-6.1 modules
+// GKI-android14-6.1 modules
///////////////////////////////////////
prebuilt_etc {
- name: "microdroid_gki-6.1.json",
- src: "microdroid_gki-6.1.json",
+ name: "microdroid_gki-android14-6.1.json",
+ src: "microdroid_gki-android14-6.1.json",
}
avb_add_hash_footer {
- name: "microdroid_gki-6.1_kernel_signed",
+ name: "microdroid_gki-android14-6.1_kernel_signed",
defaults: ["microdroid_kernel_signed_defaults"],
- filename: "microdroid_gki-6.1_kernel",
+ filename: "microdroid_gki-android14-6.1_kernel",
arch: {
arm64: {
src: ":microdroid_gki_kernel_prebuilts-6.1-arm64",
@@ -577,33 +577,33 @@
},
},
include_descriptors_from_images: [
- ":microdroid_gki-6.1_initrd_normal_hashdesc",
- ":microdroid_gki-6.1_initrd_debug_hashdesc",
+ ":microdroid_gki-android14-6.1_initrd_normal_hashdesc",
+ ":microdroid_gki-android14-6.1_initrd_debug_hashdesc",
],
}
prebuilt_etc {
- name: "microdroid_gki-6.1_kernel",
+ name: "microdroid_gki-android14-6.1_kernel",
src: ":empty_file",
relative_install_path: "fs",
arch: {
arm64: {
- src: ":microdroid_gki-6.1_kernel_signed",
+ src: ":microdroid_gki-android14-6.1_kernel_signed",
},
x86_64: {
- src: ":microdroid_gki-6.1_kernel_signed",
+ src: ":microdroid_gki-android14-6.1_kernel_signed",
},
},
}
avb_gen_vbmeta_image {
- name: "microdroid_gki-6.1_initrd_normal_hashdesc",
+ name: "microdroid_gki-android14-6.1_initrd_normal_hashdesc",
defaults: ["microdroid_initrd_normal_defaults"],
- src: ":microdroid_gki-6.1_initrd_normal",
+ src: ":microdroid_gki-android14-6.1_initrd_normal",
}
avb_gen_vbmeta_image {
- name: "microdroid_gki-6.1_initrd_debug_hashdesc",
+ name: "microdroid_gki-android14-6.1_initrd_debug_hashdesc",
defaults: ["microdroid_initrd_debug_defaults"],
- src: ":microdroid_gki-6.1_initrd_debuggable",
+ src: ":microdroid_gki-android14-6.1_initrd_debuggable",
}
diff --git a/microdroid/initrd/Android.bp b/microdroid/initrd/Android.bp
index 8df4c0f..ec971fa 100644
--- a/microdroid/initrd/Android.bp
+++ b/microdroid/initrd/Android.bp
@@ -41,7 +41,7 @@
}
genrule {
- name: "microdroid_gki-6.1_initrd_gen_arm64",
+ name: "microdroid_gki-android14-6.1_initrd_gen_arm64",
srcs: [
":microdroid_ramdisk",
":microdroid_fstab_ramdisk",
@@ -52,7 +52,7 @@
}
genrule {
- name: "microdroid_gki-6.1_initrd_gen_x86_64",
+ name: "microdroid_gki-android14-6.1_initrd_gen_x86_64",
srcs: [
":microdroid_ramdisk",
":microdroid_fstab_ramdisk",
@@ -96,13 +96,13 @@
}
genrule {
- name: "microdroid_gki-6.1_initrd_debuggable_arm64",
+ name: "microdroid_gki-android14-6.1_initrd_debuggable_arm64",
tools: ["initrd_bootconfig"],
srcs: [
- ":microdroid_gki-6.1_initrd_gen_arm64",
+ ":microdroid_gki-android14-6.1_initrd_gen_arm64",
":microdroid_bootconfig_debuggable_src",
] + bootconfigs_arm64,
- out: ["microdroid_gki-6.1_initrd_debuggable_arm64"],
+ out: ["microdroid_gki-android14-6.1_initrd_debuggable_arm64"],
cmd: "$(location initrd_bootconfig) attach --output $(out) $(in)",
}
@@ -118,13 +118,13 @@
}
genrule {
- name: "microdroid_gki-6.1_initrd_debuggable_x86_64",
+ name: "microdroid_gki-android14-6.1_initrd_debuggable_x86_64",
tools: ["initrd_bootconfig"],
srcs: [
- ":microdroid_gki-6.1_initrd_gen_x86_64",
+ ":microdroid_gki-android14-6.1_initrd_gen_x86_64",
":microdroid_bootconfig_debuggable_src",
] + bootconfigs_x86_64,
- out: ["microdroid_gki-6.1_initrd_debuggable_x86_64"],
+ out: ["microdroid_gki-android14-6.1_initrd_debuggable_x86_64"],
cmd: "$(location initrd_bootconfig) attach --output $(out) $(in)",
}
@@ -140,13 +140,13 @@
}
genrule {
- name: "microdroid_gki-6.1_initrd_normal_arm64",
+ name: "microdroid_gki-android14-6.1_initrd_normal_arm64",
tools: ["initrd_bootconfig"],
srcs: [
- ":microdroid_gki-6.1_initrd_gen_arm64",
+ ":microdroid_gki-android14-6.1_initrd_gen_arm64",
":microdroid_bootconfig_normal_src",
] + bootconfigs_arm64,
- out: ["microdroid_gki-6.1_initrd_normal_arm64"],
+ out: ["microdroid_gki-android14-6.1_initrd_normal_arm64"],
cmd: "$(location initrd_bootconfig) attach --output $(out) $(in)",
}
@@ -162,13 +162,13 @@
}
genrule {
- name: "microdroid_gki-6.1_initrd_normal_x86_64",
+ name: "microdroid_gki-android14-6.1_initrd_normal_x86_64",
tools: ["initrd_bootconfig"],
srcs: [
- ":microdroid_gki-6.1_initrd_gen_x86_64",
+ ":microdroid_gki-android14-6.1_initrd_gen_x86_64",
":microdroid_bootconfig_normal_src",
] + bootconfigs_x86_64,
- out: ["microdroid_gki-6.1_initrd_normal_x86_64"],
+ out: ["microdroid_gki-android14-6.1_initrd_normal_x86_64"],
cmd: "$(location initrd_bootconfig) attach --output $(out) $(in)",
}
@@ -188,18 +188,18 @@
}
prebuilt_etc {
- name: "microdroid_gki-6.1_initrd_debuggable",
+ name: "microdroid_gki-android14-6.1_initrd_debuggable",
// We don't have ramdisk for architectures other than x86_64 & arm64
src: ":empty_file",
arch: {
x86_64: {
- src: ":microdroid_gki-6.1_initrd_debuggable_x86_64",
+ src: ":microdroid_gki-android14-6.1_initrd_debuggable_x86_64",
},
arm64: {
- src: ":microdroid_gki-6.1_initrd_debuggable_arm64",
+ src: ":microdroid_gki-android14-6.1_initrd_debuggable_arm64",
},
},
- filename: "microdroid_gki-6.1_initrd_debuggable.img",
+ filename: "microdroid_gki-android14-6.1_initrd_debuggable.img",
}
prebuilt_etc {
@@ -218,16 +218,16 @@
}
prebuilt_etc {
- name: "microdroid_gki-6.1_initrd_normal",
+ name: "microdroid_gki-android14-6.1_initrd_normal",
// We don't have ramdisk for architectures other than x86_64 & arm64
src: ":empty_file",
arch: {
x86_64: {
- src: ":microdroid_gki-6.1_initrd_normal_x86_64",
+ src: ":microdroid_gki-android14-6.1_initrd_normal_x86_64",
},
arm64: {
- src: ":microdroid_gki-6.1_initrd_normal_arm64",
+ src: ":microdroid_gki-android14-6.1_initrd_normal_arm64",
},
},
- filename: "microdroid_gki-6.1_initrd_normal.img",
+ filename: "microdroid_gki-android14-6.1_initrd_normal.img",
}
diff --git a/microdroid/microdroid_gki-6.1.json b/microdroid/microdroid_gki-android14-6.1.json
similarity index 82%
rename from microdroid/microdroid_gki-6.1.json
rename to microdroid/microdroid_gki-android14-6.1.json
index 2115e51..9392fae 100644
--- a/microdroid/microdroid_gki-6.1.json
+++ b/microdroid/microdroid_gki-android14-6.1.json
@@ -1,5 +1,5 @@
{
- "kernel": "/apex/com.android.virt/etc/fs/microdroid_gki-6.1_kernel",
+ "kernel": "/apex/com.android.virt/etc/fs/microdroid_gki-android14-6.1_kernel",
"disks": [
{
"partitions": [
diff --git a/pvmfw/Android.bp b/pvmfw/Android.bp
index aa9942c..37d8ac9 100644
--- a/pvmfw/Android.bp
+++ b/pvmfw/Android.bp
@@ -26,6 +26,7 @@
"libpvmfw_avb_nostd",
"libpvmfw_embedded_key",
"libpvmfw_fdt_template",
+ "libservice_vm_version",
"libsmccc",
"libstatic_assertions",
"libtinyvec_nostd",
diff --git a/pvmfw/src/config.rs b/pvmfw/src/config.rs
index 4957df2..2fe4ec9 100644
--- a/pvmfw/src/config.rs
+++ b/pvmfw/src/config.rs
@@ -131,6 +131,13 @@
const COUNT: usize = Self::_VARIANT_COUNT as usize;
}
+#[derive(Default)]
+pub struct Entries<'a> {
+ pub bcc: &'a mut [u8],
+ pub debug_policy: Option<&'a mut [u8]>,
+ pub vm_dtbo: Option<&'a mut [u8]>,
+}
+
#[repr(packed)]
#[derive(Clone, Copy, Debug, FromZeroes, FromBytes)]
struct HeaderEntry {
@@ -260,7 +267,7 @@
}
/// Get slice containing the platform BCC.
- pub fn get_entries(&mut self) -> (&mut [u8], Option<&mut [u8]>, Option<&mut [u8]>) {
+ pub fn get_entries(&mut self) -> Entries<'_> {
// This assumes that the blobs are in-order w.r.t. the entries.
let bcc_range = self.get_entry_range(Entry::Bcc);
let dp_range = self.get_entry_range(Entry::DebugPolicy);
@@ -270,16 +277,17 @@
info!("Found VM DTBO at {:?}", vm_dtbo_range);
}
- // SAFETY: When instantiate, ranges are validated to be in the body range without
+ // SAFETY: When instantiated, ranges are validated to be in the body range without
// overlapping.
- unsafe {
+ let (bcc, debug_policy, vm_dtbo) = unsafe {
let ptr = self.body.as_mut_ptr() as usize;
(
Self::from_raw_range_mut(ptr, bcc_range.unwrap()),
dp_range.map(|dp_range| Self::from_raw_range_mut(ptr, dp_range)),
vm_dtbo_range.map(|vm_dtbo_range| Self::from_raw_range_mut(ptr, vm_dtbo_range)),
)
- }
+ };
+ Entries { bcc, debug_policy, vm_dtbo }
}
fn get_entry_range(&self, entry: Entry) -> Option<NonEmptyRange> {
diff --git a/pvmfw/src/entry.rs b/pvmfw/src/entry.rs
index ed73bc9..f4078a3 100644
--- a/pvmfw/src/entry.rs
+++ b/pvmfw/src/entry.rs
@@ -212,7 +212,7 @@
RebootReason::InvalidConfig
})?;
- let (bcc_slice, debug_policy, vm_dtbo) = appended.get_entries();
+ let config_entries = appended.get_entries();
// Up to this point, we were using the built-in static (from .rodata) page tables.
MEMORY.lock().replace(MemoryTracker::new(
@@ -222,13 +222,19 @@
Some(memory::appended_payload_range()),
));
- let slices = MemorySlices::new(fdt, payload, payload_size, vm_dtbo)?;
+ let slices = MemorySlices::new(fdt, payload, payload_size, config_entries.vm_dtbo)?;
// This wrapper allows main() to be blissfully ignorant of platform details.
- let next_bcc = crate::main(slices.fdt, slices.kernel, slices.ramdisk, bcc_slice, debug_policy)?;
+ let next_bcc = crate::main(
+ slices.fdt,
+ slices.kernel,
+ slices.ramdisk,
+ config_entries.bcc,
+ config_entries.debug_policy,
+ )?;
// Writable-dirty regions will be flushed when MemoryTracker is dropped.
- bcc_slice.zeroize();
+ config_entries.bcc.zeroize();
info!("Expecting a bug making MMIO_GUARD_UNMAP return NOT_SUPPORTED on success");
MEMORY.lock().as_mut().unwrap().mmio_unmap_all().map_err(|e| {
@@ -432,10 +438,10 @@
}
}
- fn get_entries(&mut self) -> (&mut [u8], Option<&mut [u8]>, Option<&mut [u8]>) {
+ fn get_entries(&mut self) -> config::Entries<'_> {
match self {
- Self::Config(ref mut cfg) => cfg.get_entries(),
- Self::LegacyBcc(ref mut bcc) => (bcc, None, None),
+ Self::Config(cfg) => cfg.get_entries(),
+ Self::LegacyBcc(bcc) => config::Entries { bcc, ..Default::default() },
}
}
}
diff --git a/pvmfw/src/fdt.rs b/pvmfw/src/fdt.rs
index 628296a..2cd1061 100644
--- a/pvmfw/src/fdt.rs
+++ b/pvmfw/src/fdt.rs
@@ -643,6 +643,11 @@
RebootReason::InvalidFdt
})?;
+ fdt.unpack().map_err(|e| {
+ error!("Failed to unpack DT for patching: {e}");
+ RebootReason::InvalidFdt
+ })?;
+
if let Some(device_assignment_info) = &info.device_assignment {
let vm_dtbo = vm_dtbo.unwrap();
device_assignment_info.filter(vm_dtbo).map_err(|e| {
@@ -662,6 +667,11 @@
patch_device_tree(fdt, &info)?;
+ fdt.pack().map_err(|e| {
+ error!("Failed to unpack DT after patching: {e}");
+ RebootReason::InvalidFdt
+ })?;
+
Ok(info)
}
@@ -753,11 +763,6 @@
}
fn patch_device_tree(fdt: &mut Fdt, info: &DeviceTreeInfo) -> Result<(), RebootReason> {
- fdt.unpack().map_err(|e| {
- error!("Failed to unpack DT for patching: {e}");
- RebootReason::InvalidFdt
- })?;
-
if let Some(initrd_range) = &info.initrd_range {
patch_initrd_range(fdt, initrd_range).map_err(|e| {
error!("Failed to patch initrd range to DT: {e}");
@@ -813,11 +818,6 @@
})?;
}
- fdt.pack().map_err(|e| {
- error!("Failed to pack DT after patching: {e}");
- RebootReason::InvalidFdt
- })?;
-
Ok(())
}
diff --git a/pvmfw/src/instance.rs b/pvmfw/src/instance.rs
index f2cd6a3..a998bfb 100644
--- a/pvmfw/src/instance.rs
+++ b/pvmfw/src/instance.rs
@@ -141,6 +141,17 @@
let decrypted = aead.open(&mut entry, payload).map_err(Error::FailedOpen)?;
let body = EntryBody::read_from(decrypted).unwrap();
+ if dice_inputs.rkp_vm_marker {
+ // The RKP VM is allowed to run if it has passed the verified boot check and
+ // contains the expected version in its AVB footer.
+ // The comparison below with the previous boot information is skipped to enable the
+ // simultaneous update of the pvmfw and RKP VM.
+ // For instance, when both the pvmfw and RKP VM are updated, the code hash of the
+ // RKP VM will differ from the one stored in the instance image. In this case, the
+ // RKP VM is still allowed to run.
+ // This ensures that the updated RKP VM will retain the same CDIs in the next stage.
+ return Ok((false, body.salt));
+ }
if body.code_hash != dice_inputs.code_hash {
Err(Error::RecordedCodeHashMismatch)
} else if body.auth_hash != dice_inputs.auth_hash {
diff --git a/pvmfw/src/main.rs b/pvmfw/src/main.rs
index 8aa5274..1d55a84 100644
--- a/pvmfw/src/main.rs
+++ b/pvmfw/src/main.rs
@@ -115,6 +115,17 @@
if verified_boot_data.has_capability(Capability::RemoteAttest) {
info!("Service VM capable of remote attestation detected");
+ if service_vm_version::VERSION != verified_boot_data.rollback_index {
+ // For RKP VM, we only boot if the version in the AVB footer of its kernel matches
+ // the one embedded in pvmfw at build time.
+ // This prevents the pvmfw from booting a roll backed RKP VM.
+ error!(
+ "Service VM version mismatch: expected {}, found {}",
+ service_vm_version::VERSION,
+ verified_boot_data.rollback_index
+ );
+ return Err(RebootReason::InvalidPayload);
+ }
}
if verified_boot_data.has_capability(Capability::SecretkeeperProtection) {
diff --git a/rialto/Android.bp b/rialto/Android.bp
index bbb5e54..5e7fe1f 100644
--- a/rialto/Android.bp
+++ b/rialto/Android.bp
@@ -63,6 +63,28 @@
srcs: [":avb_testkey_rsa4096"],
}
+// Both SERVICE_VM_VERSION and SERVICE_VM_VERSION_STRING should represent the
+// same version number for the service VM.
+SERVICE_VM_VERSION = 1
+SERVICE_VM_VERSION_STRING = "1"
+
+genrule {
+ name: "service_vm_version_rs",
+ out: ["lib.rs"],
+ cmd: "(" +
+ " echo '#![no_std]';" +
+ " echo '#![allow(missing_docs)]';" +
+ " echo 'pub const VERSION: u64 = " + SERVICE_VM_VERSION_STRING + ";'" +
+ ") > $(out)",
+}
+
+rust_library_rlib {
+ name: "libservice_vm_version",
+ crate_name: "service_vm_version",
+ defaults: ["vmbase_rlib_defaults"],
+ srcs: [":service_vm_version_rs"],
+}
+
avb_add_hash_footer {
name: "rialto_signed",
src: ":empty_file",
@@ -70,6 +92,7 @@
partition_name: "boot",
private_key: ":rialto_sign_key",
salt: rialto_salt,
+ rollback_index: SERVICE_VM_VERSION,
props: [
{
name: "com.android.virt.cap",
diff --git a/service_vm/fake_chain/Android.bp b/service_vm/fake_chain/Android.bp
index ebc185d..2bc7b4e 100644
--- a/service_vm/fake_chain/Android.bp
+++ b/service_vm/fake_chain/Android.bp
@@ -24,6 +24,7 @@
visibility: [
"//packages/modules/Virtualization/rialto:__subpackages__",
],
+ prefer_rlib: true,
rustlibs: [
"libcstr",
],
@@ -40,6 +41,7 @@
"libcoset",
"libdiced_open_dice",
"liblog_rust",
+ "libmicrodroid_kernel_hashes",
],
}
diff --git a/service_vm/fake_chain/src/client_vm.rs b/service_vm/fake_chain/src/client_vm.rs
index eb8654b..44ea898 100644
--- a/service_vm/fake_chain/src/client_vm.rs
+++ b/service_vm/fake_chain/src/client_vm.rs
@@ -24,21 +24,16 @@
use coset::CborSerializable;
use cstr::cstr;
use diced_open_dice::{
- retry_bcc_format_config_descriptor, retry_bcc_main_flow, Config, DiceArtifacts,
+ hash, retry_bcc_format_config_descriptor, retry_bcc_main_flow, Config, DiceArtifacts,
DiceConfigValues, DiceError, DiceMode, InputValues, OwnedDiceArtifacts, Result, HASH_SIZE,
HIDDEN_SIZE,
};
use log::error;
+use microdroid_kernel_hashes::{INITRD_DEBUG_HASH, KERNEL_HASH};
type CborResult<T> = result::Result<T, ciborium::value::Error>;
/// All the following data are generated with urandom.
-const CODE_HASH_KERNEL: [u8; HASH_SIZE] = [
- 0xc8, 0x54, 0x6c, 0xad, 0x9d, 0xe7, 0x25, 0xc7, 0x2b, 0xed, 0x07, 0xe1, 0xe9, 0x1a, 0xb0, 0xd0,
- 0xa7, 0x7f, 0x43, 0xb9, 0xe4, 0x56, 0x79, 0x0d, 0x7d, 0xd8, 0xc5, 0xdd, 0xad, 0x0d, 0x31, 0x85,
- 0xaf, 0x94, 0x02, 0xd8, 0x9d, 0x70, 0xab, 0xba, 0xac, 0xc7, 0x12, 0x80, 0xec, 0x7b, 0x9b, 0x65,
- 0xec, 0x6b, 0xdd, 0x64, 0x94, 0xd0, 0x9a, 0x3a, 0x09, 0xf2, 0x49, 0xdb, 0x60, 0x3c, 0x50, 0x30,
-];
const CODE_HASH_PAYLOAD: [u8; HASH_SIZE] = [
0x08, 0x78, 0xc2, 0x5b, 0xe7, 0xea, 0x3d, 0x62, 0x70, 0x22, 0xd9, 0x1c, 0x4f, 0x3c, 0x2e, 0x2f,
0x0f, 0x97, 0xa4, 0x6f, 0x6d, 0xd5, 0xe6, 0x4a, 0x6d, 0xbe, 0x34, 0x2e, 0x56, 0x04, 0xaf, 0xef,
@@ -111,7 +106,7 @@
// so the authority hash is the same.
let authority_hash = service_vm::AUTHORITY_HASH_SERVICE_VM;
let input_values = InputValues::new(
- CODE_HASH_KERNEL,
+ kernel_code_hash()?,
Config::Descriptor(config_descriptor.as_slice()),
authority_hash,
DiceMode::kDiceModeDebug,
@@ -179,3 +174,8 @@
},
]
}
+
+fn kernel_code_hash() -> Result<[u8; HASH_SIZE]> {
+ let code_hash = [KERNEL_HASH, INITRD_DEBUG_HASH].concat();
+ hash(&code_hash)
+}
diff --git a/service_vm/kernel/Android.bp b/service_vm/kernel/Android.bp
new file mode 100644
index 0000000..79158e6
--- /dev/null
+++ b/service_vm/kernel/Android.bp
@@ -0,0 +1,31 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+python_binary_host {
+ name: "extract_microdroid_kernel_hashes",
+ srcs: ["extract_microdroid_kernel_hashes.py"],
+}
+
+genrule {
+ name: "microdroid_kernel_hashes_rs",
+ srcs: [":microdroid_kernel"],
+ out: ["lib.rs"],
+ tools: [
+ "extract_microdroid_kernel_hashes",
+ "avbtool",
+ ],
+ cmd: "$(location extract_microdroid_kernel_hashes) $(location avbtool) $(in) > $(out)",
+}
+
+rust_library_rlib {
+ name: "libmicrodroid_kernel_hashes",
+ srcs: [":microdroid_kernel_hashes_rs"],
+ crate_name: "microdroid_kernel_hashes",
+ prefer_rlib: true,
+ no_stdlibs: true,
+ stdlibs: [
+ "libcompiler_builtins.rust_sysroot",
+ "libcore.rust_sysroot",
+ ],
+}
diff --git a/service_vm/kernel/extract_microdroid_kernel_hashes.py b/service_vm/kernel/extract_microdroid_kernel_hashes.py
new file mode 100644
index 0000000..148e8be
--- /dev/null
+++ b/service_vm/kernel/extract_microdroid_kernel_hashes.py
@@ -0,0 +1,73 @@
+"""Extracts the following hashes from the AVB footer of Microdroid's kernel:
+
+- kernel hash
+- initrd_normal hash
+- initrd_debug hash
+
+The hashes are written to stdout as a Rust file.
+
+In unsupportive environments such as x86, when the kernel is just an empty file,
+the output Rust file has the same hash constant fields for compatibility
+reasons, but all of them are empty.
+"""
+#!/usr/bin/env python3
+
+import sys
+import subprocess
+from typing import Dict
+
+PARTITION_NAME_BOOT = 'boot'
+PARTITION_NAME_INITRD_NORMAL = 'initrd_normal'
+PARTITION_NAME_INITRD_DEBUG = 'initrd_debug'
+
+def main(args):
+ """Main function."""
+ avbtool = args[0]
+ kernel_image_path = args[1]
+ hashes = collect_hashes(avbtool, kernel_image_path)
+
+ print("//! This file is generated by extract_microdroid_kernel_hashes.py.")
+ print("//! It contains the hashes of the kernel and initrds.\n")
+ print("#![no_std]\n#![allow(missing_docs)]\n")
+
+ # Microdroid's kernel is just an empty file in unsupportive environments
+ # such as x86, in this case the hashes should be empty.
+ if hashes.keys() != {PARTITION_NAME_BOOT,
+ PARTITION_NAME_INITRD_NORMAL,
+ PARTITION_NAME_INITRD_DEBUG}:
+ print("/// The kernel is empty, no hashes are available.")
+ hashes[PARTITION_NAME_BOOT] = ""
+ hashes[PARTITION_NAME_INITRD_NORMAL] = ""
+ hashes[PARTITION_NAME_INITRD_DEBUG] = ""
+
+ print("pub const KERNEL_HASH: &[u8] = &["
+ f"{format_hex_string(hashes[PARTITION_NAME_BOOT])}];\n")
+ print("pub const INITRD_NORMAL_HASH: &[u8] = &["
+ f"{format_hex_string(hashes[PARTITION_NAME_INITRD_NORMAL])}];\n")
+ print("pub const INITRD_DEBUG_HASH: &[u8] = &["
+ f"{format_hex_string(hashes[PARTITION_NAME_INITRD_DEBUG])}];")
+
+def collect_hashes(avbtool: str, kernel_image_path: str) -> Dict[str, str]:
+ """Collects the hashes from the AVB footer of the kernel image."""
+ hashes = {}
+ with subprocess.Popen(
+ [avbtool, 'print_partition_digests', '--image', kernel_image_path],
+ stdout=subprocess.PIPE, stderr=subprocess.STDOUT) as proc:
+ stdout, _ = proc.communicate()
+ for line in stdout.decode("utf-8").split("\n"):
+ line = line.replace(" ", "").split(":")
+ if len(line) == 2:
+ partition_name, hash_ = line
+ hashes[partition_name] = hash_
+ return hashes
+
+def format_hex_string(hex_string: str) -> str:
+ """Formats a hex string into a Rust array."""
+ assert len(hex_string) % 2 == 0, \
+ "Hex string must have even length: " + hex_string
+ return ", ".join(["\n0x" + hex_string[i:i+2] if i % 32 == 0
+ else "0x" + hex_string[i:i+2]
+ for i in range(0, len(hex_string), 2)])
+
+if __name__ == '__main__':
+ main(sys.argv[1:])
diff --git a/service_vm/requests/Android.bp b/service_vm/requests/Android.bp
index 52b54b4..57da012 100644
--- a/service_vm/requests/Android.bp
+++ b/service_vm/requests/Android.bp
@@ -24,6 +24,7 @@
"libder_nostd",
"libdiced_open_dice_nostd",
"liblog_rust_nostd",
+ "libmicrodroid_kernel_hashes",
"libserde_nostd",
"libservice_vm_comm_nostd",
"libspki_nostd",
diff --git a/service_vm/requests/src/client_vm.rs b/service_vm/requests/src/client_vm.rs
index cfdac2d..c2f39e7 100644
--- a/service_vm/requests/src/client_vm.rs
+++ b/service_vm/requests/src/client_vm.rs
@@ -16,20 +16,26 @@
//! client VM.
use crate::cert;
-use crate::dice::{validate_client_vm_dice_chain_prefix_match, ClientVmDiceChain};
+use crate::dice::{
+ validate_client_vm_dice_chain_prefix_match, ClientVmDiceChain, DiceChainEntryPayload,
+};
use crate::keyblob::decrypt_private_key;
use alloc::vec::Vec;
-use bssl_avf::{rand_bytes, sha256, EcKey, PKey};
+use bssl_avf::{rand_bytes, sha256, Digester, EcKey, PKey};
+use cbor_util::value_to_array;
+use ciborium::value::Value;
use core::result;
-use coset::{CborSerializable, CoseSign};
+use coset::{AsCborValue, CborSerializable, CoseSign, CoseSign1};
use der::{Decode, Encode};
-use diced_open_dice::DiceArtifacts;
+use diced_open_dice::{DiceArtifacts, HASH_SIZE};
use log::error;
+use microdroid_kernel_hashes::{INITRD_DEBUG_HASH, INITRD_NORMAL_HASH, KERNEL_HASH};
use service_vm_comm::{ClientVmAttestationParams, Csr, CsrPayload, RequestProcessingError};
use x509_cert::{certificate::Certificate, name::Name};
type Result<T> = result::Result<T, RequestProcessingError>;
+const DICE_CDI_LEAF_SIGNATURE_INDEX: usize = 0;
const ATTESTATION_KEY_SIGNATURE_INDEX: usize = 1;
pub(super) fn request_attestation(
@@ -47,19 +53,29 @@
// Validates the prefix of the Client VM DICE chain in the CSR.
let service_vm_dice_chain =
dice_artifacts.bcc().ok_or(RequestProcessingError::MissingDiceChain)?;
+ let service_vm_dice_chain =
+ value_to_array(Value::from_slice(service_vm_dice_chain)?, "service_vm_dice_chain")?;
let client_vm_dice_chain =
- validate_client_vm_dice_chain_prefix_match(&csr.dice_cert_chain, service_vm_dice_chain)?;
+ value_to_array(Value::from_slice(&csr.dice_cert_chain)?, "client_vm_dice_chain")?;
+ validate_client_vm_dice_chain_prefix_match(&client_vm_dice_chain, &service_vm_dice_chain)?;
// Validates the signatures in the Client VM DICE chain and extracts the partially decoded
// DiceChainEntryPayloads.
let client_vm_dice_chain =
ClientVmDiceChain::validate_signatures_and_parse_dice_chain(client_vm_dice_chain)?;
+ // The last entry in the service VM DICE chain describes the service VM, which should
+ // be signed with the same key as the kernel image.
+ let service_vm_entry = service_vm_dice_chain.last().unwrap();
+ validate_kernel_authority_hash(client_vm_dice_chain.microdroid_kernel(), service_vm_entry)?;
+ validate_kernel_code_hash(&client_vm_dice_chain)?;
+
// AAD is empty as defined in service_vm/comm/client_vm_csr.cddl.
let aad = &[];
// Verifies the first signature with the leaf private key in the DICE chain.
- // TODO(b/310931749): Verify the first signature with CDI_Leaf_Pub of
- // the DICE chain in `cose_sign`.
+ cose_sign.verify_signature(DICE_CDI_LEAF_SIGNATURE_INDEX, aad, |signature, message| {
+ client_vm_dice_chain.microdroid_payload().subject_public_key.verify(signature, message)
+ })?;
// Verifies the second signature with the public key in the CSR payload.
let ec_public_key = EcKey::from_cose_public_key_slice(&csr_payload.public_key)?;
@@ -121,3 +137,60 @@
let digest = sha256(message)?;
key.ecdsa_sign(&digest)
}
+
+/// Validates that the authority hash of the Microdroid kernel in the Client VM DICE chain
+/// matches the authority hash of the service VM entry in the service VM DICE chain, because
+/// the Microdroid kernel is signed with the same key as the one used for the service VM.
+fn validate_kernel_authority_hash(
+ kernel: &DiceChainEntryPayload,
+ service_vm_entry: &Value,
+) -> Result<()> {
+ if expected_kernel_authority_hash(service_vm_entry)? == kernel.authority_hash {
+ Ok(())
+ } else {
+ error!("The authority hash of the Microdroid kernel does not match the expected value");
+ Err(RequestProcessingError::InvalidDiceChain)
+ }
+}
+
+/// Validates that the kernel code hash in the Client VM DICE chain matches the code hashes
+/// embedded during the build time.
+fn validate_kernel_code_hash(dice_chain: &ClientVmDiceChain) -> Result<()> {
+ let kernel = dice_chain.microdroid_kernel();
+ if expected_kernel_code_hash_normal()? == kernel.code_hash {
+ return Ok(());
+ }
+ if expected_kernel_code_hash_debug()? == kernel.code_hash {
+ if dice_chain.all_entries_are_secure() {
+ error!("The Microdroid kernel has debug initrd but the DICE chain is secure");
+ return Err(RequestProcessingError::InvalidDiceChain);
+ }
+ return Ok(());
+ }
+ error!("The kernel code hash in the Client VM DICE chain does not match any expected values");
+ Err(RequestProcessingError::InvalidDiceChain)
+}
+
+fn expected_kernel_code_hash_normal() -> bssl_avf::Result<Vec<u8>> {
+ let mut code_hash = [0u8; 64];
+ code_hash[0..32].copy_from_slice(KERNEL_HASH);
+ code_hash[32..].copy_from_slice(INITRD_NORMAL_HASH);
+ Digester::sha512().digest(&code_hash)
+}
+
+fn expected_kernel_code_hash_debug() -> bssl_avf::Result<Vec<u8>> {
+ let mut code_hash = [0u8; 64];
+ code_hash[0..32].copy_from_slice(KERNEL_HASH);
+ code_hash[32..].copy_from_slice(INITRD_DEBUG_HASH);
+ Digester::sha512().digest(&code_hash)
+}
+
+fn expected_kernel_authority_hash(service_vm_entry: &Value) -> Result<[u8; HASH_SIZE]> {
+ let cose_sign1 = CoseSign1::from_cbor_value(service_vm_entry.clone())?;
+ let payload = cose_sign1.payload.ok_or_else(|| {
+ error!("No payload found in the service VM DICE chain entry");
+ RequestProcessingError::InternalError
+ })?;
+ let service_vm = DiceChainEntryPayload::from_slice(&payload)?;
+ Ok(service_vm.authority_hash)
+}
diff --git a/service_vm/requests/src/dice.rs b/service_vm/requests/src/dice.rs
index 557b678..657e482 100644
--- a/service_vm/requests/src/dice.rs
+++ b/service_vm/requests/src/dice.rs
@@ -16,15 +16,19 @@
use alloc::string::String;
use alloc::vec::Vec;
+use bssl_avf::{ed25519_verify, Digester, EcKey};
use cbor_util::{
- cbor_value_type, value_to_array, value_to_byte_array, value_to_bytes, value_to_map,
- value_to_num, value_to_text,
+ cbor_value_type, get_label_value, get_label_value_as_bytes, value_to_array,
+ value_to_byte_array, value_to_bytes, value_to_map, value_to_num, value_to_text,
};
use ciborium::value::Value;
use core::cell::OnceCell;
use core::result;
use coset::{
- self, iana, AsCborValue, CborSerializable, CoseError, CoseKey, CoseSign1, KeyOperation,
+ self,
+ iana::{self, EnumI64},
+ Algorithm, AsCborValue, CborSerializable, CoseError, CoseKey, CoseSign1, KeyOperation, KeyType,
+ Label,
};
use diced_open_dice::{DiceMode, HASH_SIZE};
use log::error;
@@ -58,7 +62,7 @@
/// ]
#[derive(Debug, Clone)]
pub(crate) struct ClientVmDiceChain {
- pub(crate) payloads: Vec<DiceChainEntryPayload>,
+ payloads: Vec<DiceChainEntryPayload>,
}
impl ClientVmDiceChain {
@@ -126,11 +130,11 @@
Ok(())
}
- fn microdroid_kernel(&self) -> &DiceChainEntryPayload {
+ pub(crate) fn microdroid_kernel(&self) -> &DiceChainEntryPayload {
&self.payloads[self.payloads.len() - 2]
}
- fn microdroid_payload(&self) -> &DiceChainEntryPayload {
+ pub(crate) fn microdroid_payload(&self) -> &DiceChainEntryPayload {
&self.payloads[self.payloads.len() - 1]
}
@@ -147,15 +151,11 @@
/// Validates that the `client_vm_dice_chain` matches the `service_vm_dice_chain` up to the pvmfw
/// entry.
///
-/// Returns a CBOR value array of the client VM's DICE chain if the verification succeeds.
+/// Returns `Ok(())` if the verification succeeds.
pub(crate) fn validate_client_vm_dice_chain_prefix_match(
- client_vm_dice_chain: &[u8],
- service_vm_dice_chain: &[u8],
-) -> Result<Vec<Value>> {
- let client_vm_dice_chain =
- value_to_array(Value::from_slice(client_vm_dice_chain)?, "client_vm_dice_chain")?;
- let service_vm_dice_chain =
- value_to_array(Value::from_slice(service_vm_dice_chain)?, "service_vm_dice_chain")?;
+ client_vm_dice_chain: &[Value],
+ service_vm_dice_chain: &[Value],
+) -> Result<()> {
if service_vm_dice_chain.len() < 3 {
// The service VM's DICE chain must contain the root key and at least two other entries
// that describe:
@@ -180,7 +180,7 @@
);
return Err(RequestProcessingError::InvalidDiceChain);
}
- Ok(client_vm_dice_chain)
+ Ok(())
}
#[derive(Debug, Clone)]
@@ -198,21 +198,72 @@
}
}
+impl PublicKey {
+ /// Verifies the signature of the provided message with the public key.
+ ///
+ /// This function supports the following key/algorithm types as specified in
+ /// hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/
+ /// generateCertificateRequestV2.cddl:
+ ///
+ /// PubKeyEd25519 / PubKeyECDSA256 / PubKeyECDSA384
+ pub(crate) fn verify(&self, signature: &[u8], message: &[u8]) -> Result<()> {
+ match &self.0.kty {
+ KeyType::Assigned(iana::KeyType::EC2) => {
+ let public_key = EcKey::from_cose_public_key(&self.0)?;
+ let Some(Algorithm::Assigned(alg)) = self.0.alg else {
+ error!("Invalid algorithm in COSE key {:?}", self.0.alg);
+ return Err(RequestProcessingError::InvalidDiceChain);
+ };
+ let digester = match alg {
+ iana::Algorithm::ES256 => Digester::sha256(),
+ iana::Algorithm::ES384 => Digester::sha384(),
+ _ => {
+ error!("Unsupported algorithm in EC2 key: {:?}", alg);
+ return Err(RequestProcessingError::InvalidDiceChain);
+ }
+ };
+ let digest = digester.digest(message)?;
+ Ok(public_key.ecdsa_verify(signature, &digest)?)
+ }
+ KeyType::Assigned(iana::KeyType::OKP) => {
+ let curve_type =
+ get_label_value(&self.0, Label::Int(iana::OkpKeyParameter::Crv.to_i64()))?;
+ if curve_type != &Value::from(iana::EllipticCurve::Ed25519.to_i64()) {
+ error!("Unsupported curve type in OKP COSE key: {:?}", curve_type);
+ return Err(RequestProcessingError::OperationUnimplemented);
+ }
+ let x = get_label_value_as_bytes(
+ &self.0,
+ Label::Int(iana::OkpKeyParameter::X.to_i64()),
+ )?;
+ let public_key = x.try_into().map_err(|_| {
+ error!("Invalid ED25519 public key size: {}", x.len());
+ RequestProcessingError::InvalidDiceChain
+ })?;
+ let signature = signature.try_into().map_err(|_| {
+ error!("Invalid ED25519 signature size: {}", signature.len());
+ RequestProcessingError::InvalidDiceChain
+ })?;
+ Ok(ed25519_verify(message, signature, public_key)?)
+ }
+ kty => {
+ error!("Unsupported key type in COSE key: {:?}", kty);
+ Err(RequestProcessingError::OperationUnimplemented)
+ }
+ }
+ }
+}
+
/// Represents a partially decoded `DiceChainEntryPayload`. The whole payload is defined in:
///
/// hardware/interfaces/security/rkp/aidl/android/hardware/security/keymint/
/// generateCertificateRequestV2.cddl
#[derive(Debug, Clone)]
pub(crate) struct DiceChainEntryPayload {
- /// TODO(b/310931749): Verify the DICE chain entry using the subject public key.
- #[allow(dead_code)]
- subject_public_key: PublicKey,
+ pub(crate) subject_public_key: PublicKey,
mode: DiceMode,
- /// TODO(b/271275206): Verify Microdroid kernel authority and code hashes.
- #[allow(dead_code)]
- code_hash: [u8; HASH_SIZE],
- #[allow(dead_code)]
- authority_hash: [u8; HASH_SIZE],
+ pub(crate) code_hash: [u8; HASH_SIZE],
+ pub(crate) authority_hash: [u8; HASH_SIZE],
config_descriptor: ConfigDescriptor,
}
@@ -221,51 +272,54 @@
/// extracts payload from the value.
fn validate_cose_signature_and_extract_payload(
value: Value,
- _authority_public_key: &PublicKey,
+ authority_public_key: &PublicKey,
) -> Result<Self> {
let cose_sign1 = CoseSign1::from_cbor_value(value)?;
- // TODO(b/310931749): Verify the DICE chain entry using `authority_public_key`.
+ let aad = &[]; // AAD is not used in DICE chain entry.
+ cose_sign1.verify_signature(aad, |signature, message| {
+ authority_public_key.verify(signature, message)
+ })?;
let payload = cose_sign1.payload.ok_or_else(|| {
error!("No payload found in the DICE chain entry");
RequestProcessingError::InvalidDiceChain
})?;
- let entries = value_to_map(Value::from_slice(&payload)?, "DiceChainEntryPayload")?;
- build_payload(entries)
+ Self::from_slice(&payload)
}
-}
-fn build_payload(entries: Vec<(Value, Value)>) -> Result<DiceChainEntryPayload> {
- let mut builder = PayloadBuilder::default();
- for (key, value) in entries.into_iter() {
- let key: i64 = value_to_num(key, "DiceChainEntryPayload key")?;
- match key {
- SUBJECT_PUBLIC_KEY => {
- let subject_public_key = value_to_bytes(value, "subject_public_key")?;
- let subject_public_key = CoseKey::from_slice(&subject_public_key)?.try_into()?;
- builder.subject_public_key(subject_public_key)?;
+ pub(crate) fn from_slice(data: &[u8]) -> Result<Self> {
+ let entries = value_to_map(Value::from_slice(data)?, "DiceChainEntryPayload")?;
+ let mut builder = PayloadBuilder::default();
+ for (key, value) in entries.into_iter() {
+ let key: i64 = value_to_num(key, "DiceChainEntryPayload key")?;
+ match key {
+ SUBJECT_PUBLIC_KEY => {
+ let subject_public_key = value_to_bytes(value, "subject_public_key")?;
+ let subject_public_key =
+ CoseKey::from_slice(&subject_public_key)?.try_into()?;
+ builder.subject_public_key(subject_public_key)?;
+ }
+ MODE => builder.mode(to_mode(value)?)?,
+ CODE_HASH => {
+ let code_hash = value_to_byte_array(value, "DiceChainEntryPayload code_hash")?;
+ builder.code_hash(code_hash)?;
+ }
+ AUTHORITY_HASH => {
+ let authority_hash =
+ value_to_byte_array(value, "DiceChainEntryPayload authority_hash")?;
+ builder.authority_hash(authority_hash)?;
+ }
+ CONFIG_DESC => {
+ let config_descriptor = value_to_bytes(value, "config_descriptor")?;
+ let config_descriptor = ConfigDescriptor::from_slice(&config_descriptor)?;
+ builder.config_descriptor(config_descriptor)?;
+ }
+ _ => {}
}
- MODE => builder.mode(to_mode(value)?)?,
- CODE_HASH => {
- let code_hash = value_to_byte_array(value, "DiceChainEntryPayload code_hash")?;
- builder.code_hash(code_hash)?;
- }
- AUTHORITY_HASH => {
- let authority_hash =
- value_to_byte_array(value, "DiceChainEntryPayload authority_hash")?;
- builder.authority_hash(authority_hash)?;
- }
- CONFIG_DESC => {
- let config_descriptor = value_to_bytes(value, "config_descriptor")?;
- let config_descriptor = ConfigDescriptor::from_slice(&config_descriptor)?;
- builder.config_descriptor(config_descriptor)?;
- }
- _ => {}
}
+ builder.build()
}
- builder.build()
}
-
/// Represents a partially decoded `ConfigurationDescriptor`.
///
/// The whole `ConfigurationDescriptor` is defined in:
diff --git a/virtualizationmanager/src/aidl.rs b/virtualizationmanager/src/aidl.rs
index c63ed4c..7f98fe8 100644
--- a/virtualizationmanager/src/aidl.rs
+++ b/virtualizationmanager/src/aidl.rs
@@ -115,7 +115,7 @@
wait_for_interface(BINDER_SERVICE_IDENTIFIER)
.expect("Could not connect to VirtualizationServiceInternal");
static ref MICRODROID_GKI_OS_NAME_PATTERN: Regex =
- Regex::new(r"^microdroid_gki-\d+\.\d+$").expect("Failed to construct Regex");
+ Regex::new(r"^microdroid_gki-android\d+-\d+\.\d+$").expect("Failed to construct Regex");
}
fn create_or_update_idsig_file(
diff --git a/virtualizationservice/aidl/Android.bp b/virtualizationservice/aidl/Android.bp
index 91d91aa..c69fe8f 100644
--- a/virtualizationservice/aidl/Android.bp
+++ b/virtualizationservice/aidl/Android.bp
@@ -61,7 +61,7 @@
unstable: true,
backend: {
java: {
- sdk_version: "module_current",
+ enabled: false,
},
rust: {
enabled: true,
diff --git a/vmclient/src/lib.rs b/vmclient/src/lib.rs
index 9f1d7d1..a2a88d8 100644
--- a/vmclient/src/lib.rs
+++ b/vmclient/src/lib.rs
@@ -74,11 +74,7 @@
// Create new POSIX socketpair, suitable for use with RpcBinder UDS bootstrap
// transport. Make it O_CLOEXEC to align with how Rust creates file
// descriptors (expected by SharedChild).
- let (raw1, raw2) =
- socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::SOCK_CLOEXEC)?;
-
- // SAFETY: Taking ownership of brand new FDs.
- unsafe { Ok((OwnedFd::from_raw_fd(raw1), OwnedFd::from_raw_fd(raw2))) }
+ Ok(socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::SOCK_CLOEXEC)?)
}
/// A running instance of virtmgr which is hosting a VirtualizationService