Get apexd to verify manifest data
Send the name and version we read from the manifest to apexd to make
sure it doesn't change.
Remove image hash since we have no use for it.
Put the manifest extraction & verification behind a flag since it now
has the potential to change behavior.
Expand on the comment for verify(), to make it clearer what it does
and doesn't verify.
Bug: 313042092
Test: atest ApexTestCases
Test: atest MicrodroidTests
Test: atest libapexutil_rust.test
Change-Id: Ida6d9e11b3bce5676b744dc945eadb09aa9a822f
diff --git a/libs/apexutil/src/lib.rs b/libs/apexutil/src/lib.rs
index f483bb8..639135f 100644
--- a/libs/apexutil/src/lib.rs
+++ b/libs/apexutil/src/lib.rs
@@ -67,25 +67,23 @@
ApexPubkeyMismatch,
}
-/// Information extracted from the APEX during verification.
+/// Information extracted from the APEX during AVB verification.
#[derive(Debug)]
pub struct ApexVerificationResult {
- /// The name of the APEX, from its manifest. Unverified, but apexd will reject
- /// an APEX where the unsigned manifest isn't the same as the signed one.
- pub name: String,
- /// The version of the APEX, from its manifest. Unverified, but apexd will reject
- /// an APEX where the unsigned manifest isn't the same as the signed one.
- pub version: i64,
+ /// The name of the APEX, from its manifest.
+ pub name: Option<String>,
+ /// The version of the APEX, from its manifest.
+ pub version: Option<i64>,
/// The public key that verifies the payload signature.
pub public_key: Vec<u8>,
/// The root digest of the payload hashtree.
pub root_digest: Vec<u8>,
- /// The hash of the verified VBMeta image data.
- /// TODO(alanstokes): Delete this if we don't have a use for it.
- pub image_hash: Vec<u8>,
}
/// Verify APEX payload by AVB verification and return information about the APEX.
+/// This verifies that the VBMeta is correctly signed by the public key specified in the APEX.
+/// It doesn't verify that that is the correct key, nor does it verify that the payload matches
+/// the signed root hash - that is handled by dm-verity once apexd has mounted the APEX.
pub fn verify(path: &str) -> Result<ApexVerificationResult, ApexVerificationError> {
let apex_file = File::open(path).map_err(ApexParseError::Io)?;
let ApexZipInfo { public_key, image_offset, image_size, manifest } =
@@ -97,10 +95,13 @@
if vbmeta_public_key != public_key {
return Err(ApexVerificationError::ApexPubkeyMismatch);
}
- let image_hash = vbmeta.hash().ok_or(ApexParseError::VbmetaMissingData("hash"))?.to_vec();
- let ApexManifestInfo { name, version } = decode_manifest(&manifest)?;
-
- Ok(ApexVerificationResult { name, version, public_key, root_digest, image_hash })
+ let (name, version) = if cfg!(dice_changes) {
+ let ApexManifestInfo { name, version } = decode_manifest(&manifest)?;
+ (Some(name), Some(version))
+ } else {
+ (None, None)
+ };
+ Ok(ApexVerificationResult { name, version, public_key, root_digest })
}
fn find_root_digest(vbmeta: &VbMetaImage) -> Result<Vec<u8>, ApexParseError> {
@@ -168,18 +169,19 @@
#[test]
fn apex_verification_returns_valid_result() {
let res = verify("apex.apexd_test.apex").unwrap();
- assert_eq!(res.name, "com.android.apex.test_package");
- assert_eq!(res.version, 1);
+ let (expected_name, expected_version) = if cfg!(dice_changes) {
+ (Some("com.android.apex.test_package"), Some(1))
+ } else {
+ (None, None)
+ };
+ assert_eq!(res.name.as_deref(), expected_name);
+ assert_eq!(res.version, expected_version);
// The expected hex values were generated when we ran the method the first time.
assert_eq!(
hex::encode(res.root_digest),
"54265da77ae1fd619e39809ad99fedc576bb20c0c7a8002190fa64438436299f"
);
assert_eq!(
- hex::encode(res.image_hash),
- "cd6d8670ac6e1fd4c095f6fcfb8bb9bf4b67a67d58976fc83ab2371d2886ca0d"
- );
- assert_eq!(
hex::encode(res.public_key),
"\
00001000963a5527aaf0145b3bb5f899a05034ccc76dafdd671dbf4e42c04df2eeba15\
diff --git a/microdroid/payload/metadata.proto b/microdroid/payload/metadata.proto
index 6b999af..b03d466 100644
--- a/microdroid/payload/metadata.proto
+++ b/microdroid/payload/metadata.proto
@@ -37,14 +37,18 @@
}
message ApexPayload {
+ // Next id: 9
+
// Required.
string name = 1;
string partition_name = 2;
// Optional.
- // When specified, apex payload should be verified with the public key and root digest.
+ // When specified, apex payload should be verified against these values.
bytes public_key = 3;
bytes root_digest = 4;
+ int64 manifest_version = 7;
+ string manifest_name = 8;
// Required.
// The timestamp in seconds when the APEX was last updated. This should match the value in
diff --git a/microdroid_manager/src/instance.rs b/microdroid_manager/src/instance.rs
index 6c9e245..b0fc03d 100644
--- a/microdroid_manager/src/instance.rs
+++ b/microdroid_manager/src/instance.rs
@@ -304,6 +304,8 @@
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct ApexData {
pub name: String,
+ pub manifest_name: Option<String>,
+ pub manifest_version: Option<i64>,
pub public_key: Vec<u8>,
pub root_digest: Vec<u8>,
pub last_update_seconds: u64,
diff --git a/microdroid_manager/src/payload.rs b/microdroid_manager/src/payload.rs
index 87f690b..98fe24b 100644
--- a/microdroid_manager/src/payload.rs
+++ b/microdroid_manager/src/payload.rs
@@ -17,7 +17,7 @@
use crate::instance::ApexData;
use crate::ioutil::wait_for_file;
use anyhow::Result;
-use log::info;
+use log::{info, warn};
use microdroid_metadata::{read_metadata, ApexPayload, Metadata};
use std::time::Duration;
@@ -37,13 +37,19 @@
.apexes
.iter()
.map(|apex| {
- let name = apex.name.clone();
let apex_path = format!("/dev/block/by-name/{}", apex.partition_name);
- let result = apexutil::verify(&apex_path)?;
+ let extracted = apexutil::verify(&apex_path)?;
+ if let Some(manifest_name) = &extracted.name {
+ if &apex.name != manifest_name {
+ warn!("Apex named {} is named {} in its manifest", apex.name, manifest_name);
+ }
+ };
Ok(ApexData {
- name,
- public_key: result.public_key,
- root_digest: result.root_digest,
+ name: apex.name.clone(),
+ manifest_name: extracted.name,
+ manifest_version: extracted.version,
+ public_key: extracted.public_key,
+ root_digest: extracted.root_digest,
last_update_seconds: apex.last_update_seconds,
is_factory: apex.is_factory,
})
@@ -60,6 +66,8 @@
name: data.name.clone(),
public_key: data.public_key.clone(),
root_digest: data.root_digest.clone(),
+ manifest_name: data.manifest_name.clone().unwrap_or_default(),
+ manifest_version: data.manifest_version.unwrap_or_default(),
last_update_seconds: data.last_update_seconds,
is_factory: data.is_factory,
..Default::default()