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