• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022, 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 //! pVM firmware.
16 
17 #![no_main]
18 #![no_std]
19 
20 extern crate alloc;
21 
22 mod bcc;
23 mod bootargs;
24 mod config;
25 mod crypto;
26 mod dice;
27 mod entry;
28 mod exceptions;
29 mod fdt;
30 mod gpt;
31 mod heap;
32 mod helpers;
33 mod hvc;
34 mod instance;
35 mod memory;
36 mod mmu;
37 mod rand;
38 mod virtio;
39 
40 use crate::bcc::Bcc;
41 use crate::dice::PartialInputs;
42 use crate::entry::RebootReason;
43 use crate::fdt::modify_for_next_stage;
44 use crate::helpers::flush;
45 use crate::helpers::GUEST_PAGE_SIZE;
46 use crate::instance::get_or_generate_instance_salt;
47 use crate::memory::MemoryTracker;
48 use crate::virtio::pci;
49 use alloc::boxed::Box;
50 use core::ops::Range;
51 use diced_open_dice::{bcc_handover_main_flow, bcc_handover_parse, DiceArtifacts};
52 use fdtpci::{PciError, PciInfo};
53 use libfdt::Fdt;
54 use log::{debug, error, info, trace, warn};
55 use pvmfw_avb::verify_payload;
56 use pvmfw_avb::DebugLevel;
57 use pvmfw_embedded_key::PUBLIC_KEY;
58 
59 const NEXT_BCC_SIZE: usize = GUEST_PAGE_SIZE;
60 
main( fdt: &mut Fdt, signed_kernel: &[u8], ramdisk: Option<&[u8]>, current_bcc_handover: &[u8], mut debug_policy: Option<&mut [u8]>, memory: &mut MemoryTracker, ) -> Result<Range<usize>, RebootReason>61 fn main(
62     fdt: &mut Fdt,
63     signed_kernel: &[u8],
64     ramdisk: Option<&[u8]>,
65     current_bcc_handover: &[u8],
66     mut debug_policy: Option<&mut [u8]>,
67     memory: &mut MemoryTracker,
68 ) -> Result<Range<usize>, RebootReason> {
69     info!("pVM firmware");
70     debug!("FDT: {:?}", fdt.as_ptr());
71     debug!("Signed kernel: {:?} ({:#x} bytes)", signed_kernel.as_ptr(), signed_kernel.len());
72     debug!("AVB public key: addr={:?}, size={:#x} ({1})", PUBLIC_KEY.as_ptr(), PUBLIC_KEY.len());
73     if let Some(rd) = ramdisk {
74         debug!("Ramdisk: {:?} ({:#x} bytes)", rd.as_ptr(), rd.len());
75     } else {
76         debug!("Ramdisk: None");
77     }
78 
79     let bcc_handover = bcc_handover_parse(current_bcc_handover).map_err(|e| {
80         error!("Invalid BCC Handover: {e:?}");
81         RebootReason::InvalidBcc
82     })?;
83     trace!("BCC: {bcc_handover:x?}");
84 
85     let cdi_seal = bcc_handover.cdi_seal();
86 
87     let bcc = Bcc::new(bcc_handover.bcc()).map_err(|e| {
88         error!("{e}");
89         RebootReason::InvalidBcc
90     })?;
91 
92     // The bootloader should never pass us a debug policy when the boot is secure (the bootloader
93     // is locked). If it gets it wrong, disregard it & log it, to avoid it causing problems.
94     if debug_policy.is_some() && !bcc.is_debug_mode() {
95         warn!("Ignoring debug policy, BCC does not indicate Debug mode");
96         debug_policy = None;
97     }
98 
99     // Set up PCI bus for VirtIO devices.
100     let pci_info = PciInfo::from_fdt(fdt).map_err(handle_pci_error)?;
101     debug!("PCI: {:#x?}", pci_info);
102     let mut pci_root = pci::initialise(pci_info, memory)?;
103 
104     let verified_boot_data = verify_payload(signed_kernel, ramdisk, PUBLIC_KEY).map_err(|e| {
105         error!("Failed to verify the payload: {e}");
106         RebootReason::PayloadVerificationError
107     })?;
108 
109     let next_bcc = heap::aligned_boxed_slice(NEXT_BCC_SIZE, GUEST_PAGE_SIZE).ok_or_else(|| {
110         error!("Failed to allocate the next-stage BCC");
111         RebootReason::InternalError
112     })?;
113     // By leaking the slice, its content will be left behind for the next stage.
114     let next_bcc = Box::leak(next_bcc);
115 
116     let dice_inputs = PartialInputs::new(&verified_boot_data).map_err(|e| {
117         error!("Failed to compute partial DICE inputs: {e:?}");
118         RebootReason::InternalError
119     })?;
120     let (new_instance, salt) = get_or_generate_instance_salt(&mut pci_root, &dice_inputs, cdi_seal)
121         .map_err(|e| {
122             error!("Failed to get instance.img salt: {e}");
123             RebootReason::InternalError
124         })?;
125     trace!("Got salt from instance.img: {salt:x?}");
126 
127     let mut config_descriptor_buffer = [0; 128];
128     let dice_inputs =
129         dice_inputs.into_input_values(&salt, &mut config_descriptor_buffer).map_err(|e| {
130             error!("Failed to generate DICE inputs: {e:?}");
131             RebootReason::InternalError
132         })?;
133 
134     // It is possible that the DICE chain we were given is rooted in the UDS. We do not want to give
135     // such a chain to the payload, or even the associated CDIs. So remove the entire chain we
136     // were given and taint the CDIs. Note that the resulting CDIs are still deterministically
137     // derived from those we received, so will vary iff they do.
138     // TODO(b/280405545): Remove this post Android 14.
139     let truncated_bcc_handover = bcc::truncate(bcc_handover).map_err(|e| {
140         error!("{e}");
141         RebootReason::InternalError
142     })?;
143 
144     let _ = bcc_handover_main_flow(truncated_bcc_handover.as_slice(), &dice_inputs, next_bcc)
145         .map_err(|e| {
146             error!("Failed to derive next-stage DICE secrets: {e:?}");
147             RebootReason::SecretDerivationError
148         })?;
149     flush(next_bcc);
150 
151     let kaslr_seed = u64::from_ne_bytes(rand::random_array().map_err(|e| {
152         error!("Failed to generated guest KASLR seed: {e}");
153         RebootReason::InternalError
154     })?);
155     let strict_boot = true;
156     let debuggable = verified_boot_data.debug_level != DebugLevel::None;
157     modify_for_next_stage(
158         fdt,
159         next_bcc,
160         new_instance,
161         strict_boot,
162         debug_policy,
163         debuggable,
164         kaslr_seed,
165     )
166     .map_err(|e| {
167         error!("Failed to configure device tree: {e}");
168         RebootReason::InternalError
169     })?;
170 
171     info!("Starting payload...");
172 
173     let bcc_range = {
174         let r = next_bcc.as_ptr_range();
175         (r.start as usize)..(r.end as usize)
176     };
177 
178     Ok(bcc_range)
179 }
180 
181 /// Logs the given PCI error and returns the appropriate `RebootReason`.
handle_pci_error(e: PciError) -> RebootReason182 fn handle_pci_error(e: PciError) -> RebootReason {
183     error!("{}", e);
184     match e {
185         PciError::FdtErrorPci(_)
186         | PciError::FdtNoPci
187         | PciError::FdtErrorReg(_)
188         | PciError::FdtMissingReg
189         | PciError::FdtRegEmpty
190         | PciError::FdtRegMissingSize
191         | PciError::CamWrongSize(_)
192         | PciError::FdtErrorRanges(_)
193         | PciError::FdtMissingRanges
194         | PciError::RangeAddressMismatch { .. }
195         | PciError::NoSuitableRange => RebootReason::InvalidFdt,
196     }
197 }
198