• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 mod utils;
18 
19 use anyhow::{anyhow, Result};
20 use avb_bindgen::{AvbFooter, AvbVBMetaImageHeader};
21 use pvmfw_avb::{verify_payload, AvbSlotVerifyError, DebugLevel, VerifiedBootData};
22 use std::{fs, mem::size_of, ptr};
23 use utils::*;
24 
25 const TEST_IMG_WITH_ONE_HASHDESC_PATH: &str = "test_image_with_one_hashdesc.img";
26 const TEST_IMG_WITH_PROP_DESC_PATH: &str = "test_image_with_prop_desc.img";
27 const TEST_IMG_WITH_NON_INITRD_HASHDESC_PATH: &str = "test_image_with_non_initrd_hashdesc.img";
28 const TEST_IMG_WITH_INITRD_AND_NON_INITRD_DESC_PATH: &str =
29     "test_image_with_initrd_and_non_initrd_desc.img";
30 const UNSIGNED_TEST_IMG_PATH: &str = "unsigned_test.img";
31 
32 const RANDOM_FOOTER_POS: usize = 30;
33 
34 /// This test uses the Microdroid payload compiled on the fly to check that
35 /// the latest payload can be verified successfully.
36 #[test]
latest_normal_payload_passes_verification() -> Result<()>37 fn latest_normal_payload_passes_verification() -> Result<()> {
38     assert_latest_payload_verification_passes(
39         &load_latest_initrd_normal()?,
40         b"initrd_normal",
41         DebugLevel::None,
42     )
43 }
44 
45 #[test]
latest_debug_payload_passes_verification() -> Result<()>46 fn latest_debug_payload_passes_verification() -> Result<()> {
47     assert_latest_payload_verification_passes(
48         &load_latest_initrd_debug()?,
49         b"initrd_debug",
50         DebugLevel::Full,
51     )
52 }
53 
54 #[test]
payload_expecting_no_initrd_passes_verification_with_no_initrd() -> Result<()>55 fn payload_expecting_no_initrd_passes_verification_with_no_initrd() -> Result<()> {
56     let public_key = load_trusted_public_key()?;
57     let verified_boot_data = verify_payload(
58         &fs::read(TEST_IMG_WITH_ONE_HASHDESC_PATH)?,
59         /*initrd=*/ None,
60         &public_key,
61     )
62     .map_err(|e| anyhow!("Verification failed. Error: {}", e))?;
63 
64     let kernel_digest = hash(&[&hex::decode("1111")?, &fs::read(UNSIGNED_TEST_IMG_PATH)?]);
65     let expected_boot_data = VerifiedBootData {
66         debug_level: DebugLevel::None,
67         kernel_digest,
68         initrd_digest: None,
69         public_key: &public_key,
70     };
71     assert_eq!(expected_boot_data, verified_boot_data);
72 
73     Ok(())
74 }
75 
76 #[test]
payload_with_non_initrd_descriptor_fails_verification_with_no_initrd() -> Result<()>77 fn payload_with_non_initrd_descriptor_fails_verification_with_no_initrd() -> Result<()> {
78     assert_payload_verification_fails(
79         &fs::read(TEST_IMG_WITH_NON_INITRD_HASHDESC_PATH)?,
80         /*initrd=*/ None,
81         &load_trusted_public_key()?,
82         AvbSlotVerifyError::InvalidMetadata,
83     )
84 }
85 
86 #[test]
payload_with_non_initrd_descriptor_fails_verification_with_initrd() -> Result<()>87 fn payload_with_non_initrd_descriptor_fails_verification_with_initrd() -> Result<()> {
88     assert_payload_verification_with_initrd_fails(
89         &fs::read(TEST_IMG_WITH_INITRD_AND_NON_INITRD_DESC_PATH)?,
90         &load_latest_initrd_normal()?,
91         &load_trusted_public_key()?,
92         AvbSlotVerifyError::InvalidMetadata,
93     )
94 }
95 
96 #[test]
payload_with_prop_descriptor_fails_verification_with_no_initrd() -> Result<()>97 fn payload_with_prop_descriptor_fails_verification_with_no_initrd() -> Result<()> {
98     assert_payload_verification_fails(
99         &fs::read(TEST_IMG_WITH_PROP_DESC_PATH)?,
100         /*initrd=*/ None,
101         &load_trusted_public_key()?,
102         AvbSlotVerifyError::InvalidMetadata,
103     )
104 }
105 
106 #[test]
payload_expecting_initrd_fails_verification_with_no_initrd() -> Result<()>107 fn payload_expecting_initrd_fails_verification_with_no_initrd() -> Result<()> {
108     assert_payload_verification_fails(
109         &load_latest_signed_kernel()?,
110         /*initrd=*/ None,
111         &load_trusted_public_key()?,
112         AvbSlotVerifyError::InvalidMetadata,
113     )
114 }
115 
116 #[test]
payload_with_empty_public_key_fails_verification() -> Result<()>117 fn payload_with_empty_public_key_fails_verification() -> Result<()> {
118     assert_payload_verification_with_initrd_fails(
119         &load_latest_signed_kernel()?,
120         &load_latest_initrd_normal()?,
121         /*trusted_public_key=*/ &[0u8; 0],
122         AvbSlotVerifyError::PublicKeyRejected,
123     )
124 }
125 
126 #[test]
payload_with_an_invalid_public_key_fails_verification() -> Result<()>127 fn payload_with_an_invalid_public_key_fails_verification() -> Result<()> {
128     assert_payload_verification_with_initrd_fails(
129         &load_latest_signed_kernel()?,
130         &load_latest_initrd_normal()?,
131         /*trusted_public_key=*/ &[0u8; 512],
132         AvbSlotVerifyError::PublicKeyRejected,
133     )
134 }
135 
136 #[test]
payload_with_a_different_valid_public_key_fails_verification() -> Result<()>137 fn payload_with_a_different_valid_public_key_fails_verification() -> Result<()> {
138     assert_payload_verification_with_initrd_fails(
139         &load_latest_signed_kernel()?,
140         &load_latest_initrd_normal()?,
141         &fs::read(PUBLIC_KEY_RSA2048_PATH)?,
142         AvbSlotVerifyError::PublicKeyRejected,
143     )
144 }
145 
146 #[test]
payload_with_an_invalid_initrd_fails_verification() -> Result<()>147 fn payload_with_an_invalid_initrd_fails_verification() -> Result<()> {
148     assert_payload_verification_with_initrd_fails(
149         &load_latest_signed_kernel()?,
150         /*initrd=*/ &fs::read(UNSIGNED_TEST_IMG_PATH)?,
151         &load_trusted_public_key()?,
152         AvbSlotVerifyError::Verification,
153     )
154 }
155 
156 #[test]
unsigned_kernel_fails_verification() -> Result<()>157 fn unsigned_kernel_fails_verification() -> Result<()> {
158     assert_payload_verification_with_initrd_fails(
159         &fs::read(UNSIGNED_TEST_IMG_PATH)?,
160         &load_latest_initrd_normal()?,
161         &load_trusted_public_key()?,
162         AvbSlotVerifyError::Io,
163     )
164 }
165 
166 #[test]
tampered_kernel_fails_verification() -> Result<()>167 fn tampered_kernel_fails_verification() -> Result<()> {
168     let mut kernel = load_latest_signed_kernel()?;
169     kernel[1] = !kernel[1]; // Flip the bits
170 
171     assert_payload_verification_with_initrd_fails(
172         &kernel,
173         &load_latest_initrd_normal()?,
174         &load_trusted_public_key()?,
175         AvbSlotVerifyError::Verification,
176     )
177 }
178 
179 #[test]
kernel_footer_with_vbmeta_offset_overwritten_fails_verification() -> Result<()>180 fn kernel_footer_with_vbmeta_offset_overwritten_fails_verification() -> Result<()> {
181     // Arrange.
182     let mut kernel = load_latest_signed_kernel()?;
183     let total_len = kernel.len() as u64;
184     let footer = extract_avb_footer(&kernel)?;
185     assert!(footer.vbmeta_offset < total_len);
186     let vbmeta_offset_addr = ptr::addr_of!(footer.vbmeta_offset) as *const u8;
187     // SAFETY: It is safe as both raw pointers `vbmeta_offset_addr` and `footer` are not null.
188     let vbmeta_offset_start =
189         unsafe { vbmeta_offset_addr.offset_from(ptr::addr_of!(footer) as *const u8) };
190     let footer_start = kernel.len() - size_of::<AvbFooter>();
191     let vbmeta_offset_start = footer_start + usize::try_from(vbmeta_offset_start)?;
192 
193     let wrong_offsets = [total_len, u64::MAX];
194     for &wrong_offset in wrong_offsets.iter() {
195         // Act.
196         kernel[vbmeta_offset_start..(vbmeta_offset_start + size_of::<u64>())]
197             .copy_from_slice(&wrong_offset.to_be_bytes());
198 
199         // Assert.
200         let footer = extract_avb_footer(&kernel)?;
201         // footer is unaligned; copy vbmeta_offset to local variable
202         let vbmeta_offset = footer.vbmeta_offset;
203         assert_eq!(wrong_offset, vbmeta_offset);
204         assert_payload_verification_with_initrd_fails(
205             &kernel,
206             &load_latest_initrd_normal()?,
207             &load_trusted_public_key()?,
208             AvbSlotVerifyError::Io,
209         )?;
210     }
211     Ok(())
212 }
213 
214 #[test]
tampered_kernel_footer_fails_verification() -> Result<()>215 fn tampered_kernel_footer_fails_verification() -> Result<()> {
216     let mut kernel = load_latest_signed_kernel()?;
217     let avb_footer_index = kernel.len() - size_of::<AvbFooter>() + RANDOM_FOOTER_POS;
218     kernel[avb_footer_index] = !kernel[avb_footer_index];
219 
220     assert_payload_verification_with_initrd_fails(
221         &kernel,
222         &load_latest_initrd_normal()?,
223         &load_trusted_public_key()?,
224         AvbSlotVerifyError::InvalidMetadata,
225     )
226 }
227 
228 #[test]
extended_initrd_fails_verification() -> Result<()>229 fn extended_initrd_fails_verification() -> Result<()> {
230     let mut initrd = load_latest_initrd_normal()?;
231     initrd.extend(b"androidboot.vbmeta.digest=1111");
232 
233     assert_payload_verification_with_initrd_fails(
234         &load_latest_signed_kernel()?,
235         &initrd,
236         &load_trusted_public_key()?,
237         AvbSlotVerifyError::Verification,
238     )
239 }
240 
241 #[test]
tampered_vbmeta_fails_verification() -> Result<()>242 fn tampered_vbmeta_fails_verification() -> Result<()> {
243     let mut kernel = load_latest_signed_kernel()?;
244     let footer = extract_avb_footer(&kernel)?;
245     let vbmeta_index: usize = (footer.vbmeta_offset + 1).try_into()?;
246 
247     kernel[vbmeta_index] = !kernel[vbmeta_index]; // Flip the bits
248 
249     assert_payload_verification_with_initrd_fails(
250         &kernel,
251         &load_latest_initrd_normal()?,
252         &load_trusted_public_key()?,
253         AvbSlotVerifyError::InvalidMetadata,
254     )
255 }
256 
257 #[test]
vbmeta_with_public_key_overwritten_fails_verification() -> Result<()>258 fn vbmeta_with_public_key_overwritten_fails_verification() -> Result<()> {
259     let mut kernel = load_latest_signed_kernel()?;
260     let footer = extract_avb_footer(&kernel)?;
261     let vbmeta_header = extract_vbmeta_header(&kernel, &footer)?;
262     let public_key_offset = footer.vbmeta_offset as usize
263         + size_of::<AvbVBMetaImageHeader>()
264         + vbmeta_header.authentication_data_block_size as usize
265         + vbmeta_header.public_key_offset as usize;
266     let public_key_size: usize = vbmeta_header.public_key_size.try_into()?;
267     let empty_public_key = vec![0u8; public_key_size];
268 
269     kernel[public_key_offset..(public_key_offset + public_key_size)]
270         .copy_from_slice(&empty_public_key);
271 
272     assert_payload_verification_with_initrd_fails(
273         &kernel,
274         &load_latest_initrd_normal()?,
275         &empty_public_key,
276         AvbSlotVerifyError::Verification,
277     )?;
278     assert_payload_verification_with_initrd_fails(
279         &kernel,
280         &load_latest_initrd_normal()?,
281         &load_trusted_public_key()?,
282         AvbSlotVerifyError::Verification,
283     )
284 }
285 
286 #[test]
vbmeta_with_verification_flag_disabled_fails_verification() -> Result<()>287 fn vbmeta_with_verification_flag_disabled_fails_verification() -> Result<()> {
288     // From external/avb/libavb/avb_vbmeta_image.h
289     const AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED: u32 = 2;
290 
291     // Arrange.
292     let mut kernel = load_latest_signed_kernel()?;
293     let footer = extract_avb_footer(&kernel)?;
294     let vbmeta_header = extract_vbmeta_header(&kernel, &footer)?;
295 
296     // vbmeta_header is unaligned; copy flags to local variable
297     let vbmeta_header_flags = vbmeta_header.flags;
298     assert_eq!(0, vbmeta_header_flags, "The disable flag should not be set in the latest kernel.");
299     let flags_addr = ptr::addr_of!(vbmeta_header.flags) as *const u8;
300     // SAFETY: It is safe as both raw pointers `flags_addr` and `vbmeta_header` are not null.
301     let flags_offset = unsafe { flags_addr.offset_from(ptr::addr_of!(vbmeta_header) as *const u8) };
302     let flags_offset = usize::try_from(footer.vbmeta_offset)? + usize::try_from(flags_offset)?;
303 
304     // Act.
305     kernel[flags_offset..(flags_offset + size_of::<u32>())]
306         .copy_from_slice(&AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED.to_be_bytes());
307 
308     // Assert.
309     let vbmeta_header = extract_vbmeta_header(&kernel, &footer)?;
310     // vbmeta_header is unaligned; copy flags to local variable
311     let vbmeta_header_flags = vbmeta_header.flags;
312     assert_eq!(
313         AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED, vbmeta_header_flags,
314         "VBMeta verification flag should be disabled now."
315     );
316     assert_payload_verification_with_initrd_fails(
317         &kernel,
318         &load_latest_initrd_normal()?,
319         &load_trusted_public_key()?,
320         AvbSlotVerifyError::Verification,
321     )
322 }
323