• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! Derives microdroid vendor dice node.
16 
17 use anyhow::{bail, Context, Result};
18 use clap::Parser;
19 use dice_driver::DiceDriver;
20 use diced_open_dice::{
21     hash, retry_bcc_format_config_descriptor, DiceConfigValues, OwnedDiceArtifacts, HIDDEN_SIZE,
22 };
23 use dm::util::blkgetsize64;
24 use std::fs::{read_link, File};
25 use std::path::{Path, PathBuf};
26 use vbmeta::VbMetaImage;
27 
28 const AVF_STRICT_BOOT: &str = "/proc/device-tree/chosen/avf,strict-boot";
29 
30 #[derive(Parser)]
31 struct Args {
32     /// Path to the dice driver (e.g. /dev/open-dice0)
33     #[arg(long)]
34     dice_driver: PathBuf,
35     /// Path to the microdroid-vendor.img disk image.
36     #[arg(long)]
37     microdroid_vendor_disk_image: PathBuf,
38     /// File to save resulting dice chain to.
39     #[arg(long)]
40     output: PathBuf,
41 }
42 
43 // TODO(ioffe): move to a library to reuse same code here, in microdroid_manager and in
44 // first_stage_init.
is_strict_boot() -> bool45 fn is_strict_boot() -> bool {
46     Path::new(AVF_STRICT_BOOT).exists()
47 }
48 
49 // See dice_for_avf_guest.cddl for CDDL of Configuration Descriptor of VM components.
build_descriptor(vbmeta: &VbMetaImage) -> Result<Vec<u8>>50 fn build_descriptor(vbmeta: &VbMetaImage) -> Result<Vec<u8>> {
51     let values = DiceConfigValues {
52         component_name: Some(c"Microdroid vendor"),
53         security_version: Some(vbmeta.rollback_index()),
54         ..Default::default()
55     };
56     Ok(retry_bcc_format_config_descriptor(&values)?)
57 }
58 
59 // TODO(ioffe): move to libvbmeta.
find_root_digest(vbmeta: &VbMetaImage) -> Result<Option<Vec<u8>>>60 fn find_root_digest(vbmeta: &VbMetaImage) -> Result<Option<Vec<u8>>> {
61     for descriptor in vbmeta.descriptors()?.iter() {
62         if let vbmeta::Descriptor::Hashtree(_) = descriptor {
63             return Ok(Some(descriptor.to_hashtree()?.root_digest().to_vec()));
64         }
65     }
66     Ok(None)
67 }
68 
dice_derivation(dice: DiceDriver, vbmeta: &VbMetaImage) -> Result<OwnedDiceArtifacts>69 fn dice_derivation(dice: DiceDriver, vbmeta: &VbMetaImage) -> Result<OwnedDiceArtifacts> {
70     let authority_hash = if let Some(pubkey) = vbmeta.public_key() {
71         hash(pubkey).context("hash pubkey")?
72     } else {
73         bail!("no public key")
74     };
75     let code_hash = if let Some(root_digest) = find_root_digest(vbmeta)? {
76         hash(root_digest.as_ref()).context("hash root_digest")?
77     } else {
78         bail!("no hashtree")
79     };
80     let desc = build_descriptor(vbmeta).context("build descriptor")?;
81     let hidden = [0; HIDDEN_SIZE];
82     // The microdroid vendor partition doesn't contribute to the debuggability of the VM, and it is
83     // a bit tricky to propagate the info on whether the VM is debuggable to
84     // derive_microdroid_dice_node binary. Given these, we just always set `is_debuggable: false`
85     // for the "Microdroid vendor" dice node. The adjacent dice nodes (pvmfw & payload) provide the
86     // accurate information on whether VM is debuggable.
87     dice.derive(code_hash, &desc, authority_hash, /* debug= */ false, hidden)
88 }
89 
extract_vbmeta(block_dev: &Path) -> Result<VbMetaImage>90 fn extract_vbmeta(block_dev: &Path) -> Result<VbMetaImage> {
91     let size = blkgetsize64(block_dev).context("blkgetsize64  failed")?;
92     let file = File::open(block_dev).context("open failed")?;
93     let vbmeta = VbMetaImage::verify_reader_region(file, 0, size)?;
94     Ok(vbmeta)
95 }
96 
try_main() -> Result<()>97 fn try_main() -> Result<()> {
98     let args = Args::parse();
99     let dice =
100         DiceDriver::new(&args.dice_driver, is_strict_boot()).context("Failed to load DICE")?;
101     let path = read_link(args.microdroid_vendor_disk_image).context("failed to read symlink")?;
102     let vbmeta = extract_vbmeta(&path).context("failed to extract vbmeta")?;
103     let dice_artifacts = dice_derivation(dice, &vbmeta).context("failed to derive dice chain")?;
104     let file = File::create(&args.output).context("failed to create output")?;
105     serde_cbor::to_writer(file, &dice_artifacts).context("failed to write dice artifacts")?;
106     Ok(())
107 }
108 
main()109 fn main() {
110     if let Err(e) = try_main() {
111         eprintln!("failed with {:?}", e);
112         std::process::exit(1);
113     }
114 }
115