blob: 417e8733cdcddcbdffac0ca4052d370191ef00e9 [file] [log] [blame]
David Brown5c9e0f12019-01-09 16:34:33 -07001use log::{info, warn, error};
2use rand::{
3 distributions::{IndependentSample, Range},
4 Rng, SeedableRng, XorShiftRng,
5};
6use std::{
7 mem,
8 slice,
9};
10use aes_ctr::{
11 Aes128Ctr,
12 stream_cipher::{
13 generic_array::GenericArray,
14 NewFixStreamCipher,
15 StreamCipherCore,
16 },
17};
18
19use simflash::{Flash, SimFlashMap};
20use mcuboot_sys::{c, AreaDesc};
21use crate::caps::Caps;
22use crate::tlv::{TlvGen, TlvFlags, AES_SEC_KEY};
23
24impl Images {
25 /// A simple upgrade without forced failures.
26 ///
27 /// Returns the number of flash operations which can later be used to
28 /// inject failures at chosen steps.
29 pub fn run_basic_upgrade(&self) -> Result<i32, ()> {
30 let (flashmap, total_count) = try_upgrade(&self.flashmap, &self, None);
31 info!("Total flash operation count={}", total_count);
32
33 if !verify_image(&flashmap, &self.slots, 0, &self.upgrades) {
34 warn!("Image mismatch after first boot");
35 Err(())
36 } else {
37 Ok(total_count)
38 }
39 }
40
David Brown5c9e0f12019-01-09 16:34:33 -070041 pub fn run_basic_revert(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -070042 if Caps::OverwriteUpgrade.present() {
43 return false;
44 }
David Brown5c9e0f12019-01-09 16:34:33 -070045
David Brown5c9e0f12019-01-09 16:34:33 -070046 let mut fails = 0;
47
48 // FIXME: this test would also pass if no swap is ever performed???
49 if Caps::SwapUpgrade.present() {
50 for count in 2 .. 5 {
51 info!("Try revert: {}", count);
52 let flashmap = try_revert(&self.flashmap, &self.areadesc, count);
53 if !verify_image(&flashmap, &self.slots, 0, &self.primaries) {
54 error!("Revert failure on count {}", count);
55 fails += 1;
56 }
57 }
58 }
59
60 fails > 0
61 }
62
63 pub fn run_perm_with_fails(&self) -> bool {
64 let mut fails = 0;
65 let total_flash_ops = self.total_count.unwrap();
66
67 // Let's try an image halfway through.
68 for i in 1 .. total_flash_ops {
69 info!("Try interruption at {}", i);
70 let (flashmap, count) = try_upgrade(&self.flashmap, &self, Some(i));
71 info!("Second boot, count={}", count);
72 if !verify_image(&flashmap, &self.slots, 0, &self.upgrades) {
73 warn!("FAIL at step {} of {}", i, total_flash_ops);
74 fails += 1;
75 }
76
77 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
78 BOOT_FLAG_SET, BOOT_FLAG_SET) {
79 warn!("Mismatched trailer for Slot 0");
80 fails += 1;
81 }
82
83 if !verify_trailer(&flashmap, &self.slots, 1, BOOT_MAGIC_UNSET,
84 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
85 warn!("Mismatched trailer for Slot 1");
86 fails += 1;
87 }
88
89 if Caps::SwapUpgrade.present() {
90 if !verify_image(&flashmap, &self.slots, 1, &self.primaries) {
91 warn!("Slot 1 FAIL at step {} of {}", i, total_flash_ops);
92 fails += 1;
93 }
94 }
95 }
96
97 if fails > 0 {
98 error!("{} out of {} failed {:.2}%", fails, total_flash_ops,
99 fails as f32 * 100.0 / total_flash_ops as f32);
100 }
101
102 fails > 0
103 }
104
105 pub fn run_perm_with_random_fails_5(&self) -> bool {
106 self.run_perm_with_random_fails(5)
107 }
108
109 pub fn run_perm_with_random_fails(&self, total_fails: usize) -> bool {
110 let mut fails = 0;
111 let total_flash_ops = self.total_count.unwrap();
112 let (flashmap, total_counts) = try_random_fails(&self.flashmap, &self,
113 total_flash_ops, total_fails);
114 info!("Random interruptions at reset points={:?}", total_counts);
115
116 let slot0_ok = verify_image(&flashmap, &self.slots, 0, &self.upgrades);
117 let slot1_ok = if Caps::SwapUpgrade.present() {
118 verify_image(&flashmap, &self.slots, 1, &self.primaries)
119 } else {
120 true
121 };
122 if !slot0_ok || !slot1_ok {
123 error!("Image mismatch after random interrupts: slot0={} slot1={}",
124 if slot0_ok { "ok" } else { "fail" },
125 if slot1_ok { "ok" } else { "fail" });
126 fails += 1;
127 }
128 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
129 BOOT_FLAG_SET, BOOT_FLAG_SET) {
130 error!("Mismatched trailer for Slot 0");
131 fails += 1;
132 }
133 if !verify_trailer(&flashmap, &self.slots, 1, BOOT_MAGIC_UNSET,
134 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
135 error!("Mismatched trailer for Slot 1");
136 fails += 1;
137 }
138
139 if fails > 0 {
140 error!("Error testing perm upgrade with {} fails", total_fails);
141 }
142
143 fails > 0
144 }
145
David Brown5c9e0f12019-01-09 16:34:33 -0700146 pub fn run_revert_with_fails(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700147 if Caps::OverwriteUpgrade.present() {
148 return false;
149 }
David Brown5c9e0f12019-01-09 16:34:33 -0700150
David Brown5c9e0f12019-01-09 16:34:33 -0700151 let mut fails = 0;
152
153 if Caps::SwapUpgrade.present() {
154 for i in 1 .. (self.total_count.unwrap() - 1) {
155 info!("Try interruption at {}", i);
156 if try_revert_with_fail_at(&self.flashmap, &self, i) {
157 error!("Revert failed at interruption {}", i);
158 fails += 1;
159 }
160 }
161 }
162
163 fails > 0
164 }
165
David Brown5c9e0f12019-01-09 16:34:33 -0700166 pub fn run_norevert(&self) -> bool {
David Brown3910ab12019-01-11 12:02:26 -0700167 if Caps::OverwriteUpgrade.present() {
168 return false;
169 }
David Brown5c9e0f12019-01-09 16:34:33 -0700170
David Brown5c9e0f12019-01-09 16:34:33 -0700171 let mut flashmap = self.flashmap.clone();
172 let mut fails = 0;
173
174 info!("Try norevert");
175
176 // First do a normal upgrade...
177 let (result, _) = c::boot_go(&mut flashmap, &self.areadesc, None, false);
178 if result != 0 {
179 warn!("Failed first boot");
180 fails += 1;
181 }
182
183 //FIXME: copy_done is written by boot_go, is it ok if no copy
184 // was ever done?
185
186 if !verify_image(&flashmap, &self.slots, 0, &self.upgrades) {
187 warn!("Slot 0 image verification FAIL");
188 fails += 1;
189 }
190 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
191 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
192 warn!("Mismatched trailer for Slot 0");
193 fails += 1;
194 }
195 if !verify_trailer(&flashmap, &self.slots, 1, BOOT_MAGIC_UNSET,
196 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
197 warn!("Mismatched trailer for Slot 1");
198 fails += 1;
199 }
200
201 // Marks image in slot0 as permanent, no revert should happen...
202 mark_permanent_upgrade(&mut flashmap, &self.slots[0]);
203
204 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
205 BOOT_FLAG_SET, BOOT_FLAG_SET) {
206 warn!("Mismatched trailer for Slot 0");
207 fails += 1;
208 }
209
210 let (result, _) = c::boot_go(&mut flashmap, &self.areadesc, None, false);
211 if result != 0 {
212 warn!("Failed second boot");
213 fails += 1;
214 }
215
216 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
217 BOOT_FLAG_SET, BOOT_FLAG_SET) {
218 warn!("Mismatched trailer for Slot 0");
219 fails += 1;
220 }
221 if !verify_image(&flashmap, &self.slots, 0, &self.upgrades) {
222 warn!("Failed image verification");
223 fails += 1;
224 }
225
226 if fails > 0 {
227 error!("Error running upgrade without revert");
228 }
229
230 fails > 0
231 }
232
233 // Tests a new image written to slot0 that already has magic and image_ok set
234 // while there is no image on slot1, so no revert should ever happen...
235 pub fn run_norevert_newimage(&self) -> bool {
236 let mut flashmap = self.flashmap.clone();
237 let mut fails = 0;
238
239 info!("Try non-revert on imgtool generated image");
240
241 mark_upgrade(&mut flashmap, &self.slots[0]);
242
243 // This simulates writing an image created by imgtool to Slot 0
244 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
245 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
246 warn!("Mismatched trailer for Slot 0");
247 fails += 1;
248 }
249
250 // Run the bootloader...
251 let (result, _) = c::boot_go(&mut flashmap, &self.areadesc, None, false);
252 if result != 0 {
253 warn!("Failed first boot");
254 fails += 1;
255 }
256
257 // State should not have changed
258 if !verify_image(&flashmap, &self.slots, 0, &self.primaries) {
259 warn!("Failed image verification");
260 fails += 1;
261 }
262 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
263 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
264 warn!("Mismatched trailer for Slot 0");
265 fails += 1;
266 }
267 if !verify_trailer(&flashmap, &self.slots, 1, BOOT_MAGIC_UNSET,
268 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
269 warn!("Mismatched trailer for Slot 1");
270 fails += 1;
271 }
272
273 if fails > 0 {
274 error!("Expected a non revert with new image");
275 }
276
277 fails > 0
278 }
279
280 // Tests a new image written to slot0 that already has magic and image_ok set
281 // while there is no image on slot1, so no revert should ever happen...
282 pub fn run_signfail_upgrade(&self) -> bool {
283 let mut flashmap = self.flashmap.clone();
284 let mut fails = 0;
285
286 info!("Try upgrade image with bad signature");
287
288 mark_upgrade(&mut flashmap, &self.slots[0]);
289 mark_permanent_upgrade(&mut flashmap, &self.slots[0]);
290 mark_upgrade(&mut flashmap, &self.slots[1]);
291
292 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
293 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
294 warn!("Mismatched trailer for Slot 0");
295 fails += 1;
296 }
297
298 // Run the bootloader...
299 let (result, _) = c::boot_go(&mut flashmap, &self.areadesc, None, false);
300 if result != 0 {
301 warn!("Failed first boot");
302 fails += 1;
303 }
304
305 // State should not have changed
306 if !verify_image(&flashmap, &self.slots, 0, &self.primaries) {
307 warn!("Failed image verification");
308 fails += 1;
309 }
310 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
311 BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
312 warn!("Mismatched trailer for Slot 0");
313 fails += 1;
314 }
315
316 if fails > 0 {
317 error!("Expected an upgrade failure when image has bad signature");
318 }
319
320 fails > 0
321 }
322
David Brown5c9e0f12019-01-09 16:34:33 -0700323 fn trailer_sz(&self, align: usize) -> usize {
324 c::boot_trailer_sz(align as u8) as usize
325 }
326
327 // FIXME: could get status sz from bootloader
David Brown5c9e0f12019-01-09 16:34:33 -0700328 fn status_sz(&self, align: usize) -> usize {
David Brown9930a3e2019-01-11 12:28:26 -0700329 let bias = if Caps::EncRsa.present() || Caps::EncKw.present() {
330 32
331 } else {
332 0
333 };
David Brown5c9e0f12019-01-09 16:34:33 -0700334
David Brown9930a3e2019-01-11 12:28:26 -0700335 self.trailer_sz(align) - (16 + 24 + bias)
David Brown5c9e0f12019-01-09 16:34:33 -0700336 }
337
338 /// This test runs a simple upgrade with no fails in the images, but
339 /// allowing for fails in the status area. This should run to the end
340 /// and warn that write fails were detected...
341 #[cfg(not(feature = "validate-slot0"))]
342 pub fn run_with_status_fails_complete(&self) -> bool { false }
343
344 #[cfg(feature = "validate-slot0")]
345 pub fn run_with_status_fails_complete(&self) -> bool {
346 let mut flashmap = self.flashmap.clone();
347 let mut fails = 0;
348
349 info!("Try swap with status fails");
350
351 mark_permanent_upgrade(&mut flashmap, &self.slots[1]);
352 self.mark_bad_status_with_rate(&mut flashmap, 0, 1.0);
353
354 let (result, asserts) = c::boot_go(&mut flashmap, &self.areadesc, None, true);
355 if result != 0 {
356 warn!("Failed!");
357 fails += 1;
358 }
359
360 // Failed writes to the marked "bad" region don't assert anymore.
361 // Any detected assert() is happening in another part of the code.
362 if asserts != 0 {
363 warn!("At least one assert() was called");
364 fails += 1;
365 }
366
367 if !verify_trailer(&flashmap, &self.slots, 0, BOOT_MAGIC_GOOD,
368 BOOT_FLAG_SET, BOOT_FLAG_SET) {
369 warn!("Mismatched trailer for Slot 0");
370 fails += 1;
371 }
372
373 if !verify_image(&flashmap, &self.slots, 0, &self.upgrades) {
374 warn!("Failed image verification");
375 fails += 1;
376 }
377
378 info!("validate slot0 enabled; re-run of boot_go should just work");
379 let (result, _) = c::boot_go(&mut flashmap, &self.areadesc, None, false);
380 if result != 0 {
381 warn!("Failed!");
382 fails += 1;
383 }
384
385 if fails > 0 {
386 error!("Error running upgrade with status write fails");
387 }
388
389 fails > 0
390 }
391
392 /// This test runs a simple upgrade with no fails in the images, but
393 /// allowing for fails in the status area. This should run to the end
394 /// and warn that write fails were detected...
395 #[cfg(feature = "validate-slot0")]
396 pub fn run_with_status_fails_with_reset(&self) -> bool {
397 let mut flashmap = self.flashmap.clone();
398 let mut fails = 0;
399 let mut count = self.total_count.unwrap() / 2;
400
401 //info!("count={}\n", count);
402
403 info!("Try interrupted swap with status fails");
404
405 mark_permanent_upgrade(&mut flashmap, &self.slots[1]);
406 self.mark_bad_status_with_rate(&mut flashmap, 0, 0.5);
407
408 // Should not fail, writing to bad regions does not assert
409 let (_, asserts) = c::boot_go(&mut flashmap, &self.areadesc, Some(&mut count), true);
410 if asserts != 0 {
411 warn!("At least one assert() was called");
412 fails += 1;
413 }
414
415 self.reset_bad_status(&mut flashmap, 0);
416
417 info!("Resuming an interrupted swap operation");
418 let (_, asserts) = c::boot_go(&mut flashmap, &self.areadesc, None, true);
419
420 // This might throw no asserts, for large sector devices, where
421 // a single failure writing is indistinguishable from no failure,
422 // or throw a single assert for small sector devices that fail
423 // multiple times...
424 if asserts > 1 {
425 warn!("Expected single assert validating slot0, more detected {}", asserts);
426 fails += 1;
427 }
428
429 if fails > 0 {
430 error!("Error running upgrade with status write fails");
431 }
432
433 fails > 0
434 }
435
436 /// Adds a new flash area that fails statistically
437 #[cfg(not(feature = "overwrite-only"))]
438 fn mark_bad_status_with_rate(&self, flashmap: &mut SimFlashMap, slot: usize,
439 rate: f32) {
440 let dev_id = &self.slots[slot].dev_id;
441 let flash = flashmap.get_mut(&dev_id).unwrap();
442 let align = flash.align();
443 let off = &self.slots[0].base_off;
444 let len = &self.slots[0].len;
445 let status_off = off + len - self.trailer_sz(align);
446
447 // Mark the status area as a bad area
448 let _ = flash.add_bad_region(status_off, self.status_sz(align), rate);
449 }
450
451 #[cfg(feature = "validate-slot0")]
452 fn reset_bad_status(&self, flashmap: &mut SimFlashMap, slot: usize) {
453 let dev_id = &self.slots[slot].dev_id;
454 let flash = flashmap.get_mut(&dev_id).unwrap();
455 flash.reset_bad_regions();
456
457 // Disabling write verification the only assert triggered by
458 // boot_go should be checking for integrity of status bytes.
459 flash.set_verify_writes(false);
460 }
461
462 #[cfg(not(feature = "validate-slot0"))]
463 #[cfg(not(feature = "overwrite-only"))]
464 pub fn run_with_status_fails_with_reset(&self) -> bool {
465 let mut flashmap = self.flashmap.clone();
466 let mut fails = 0;
467
468 info!("Try interrupted swap with status fails");
469
470 mark_permanent_upgrade(&mut flashmap, &self.slots[1]);
471 self.mark_bad_status_with_rate(&mut flashmap, 0, 1.0);
472
473 // This is expected to fail while writing to bad regions...
474 let (_, asserts) = c::boot_go(&mut flashmap, &self.areadesc, None, true);
475 if asserts == 0 {
476 warn!("No assert() detected");
477 fails += 1;
478 }
479
480 fails > 0
481 }
482
483 #[cfg(feature = "overwrite-only")]
484 pub fn run_with_status_fails_with_reset(&self) -> bool {
485 false
486 }
487}
488
489/// Test a boot, optionally stopping after 'n' flash options. Returns a count
490/// of the number of flash operations done total.
491fn try_upgrade(flashmap: &SimFlashMap, images: &Images,
492 stop: Option<i32>) -> (SimFlashMap, i32) {
493 // Clone the flash to have a new copy.
494 let mut flashmap = flashmap.clone();
495
496 mark_permanent_upgrade(&mut flashmap, &images.slots[1]);
497
498 let mut counter = stop.unwrap_or(0);
499
500 let (first_interrupted, count) = match c::boot_go(&mut flashmap, &images.areadesc, Some(&mut counter), false) {
501 (-0x13579, _) => (true, stop.unwrap()),
502 (0, _) => (false, -counter),
503 (x, _) => panic!("Unknown return: {}", x),
504 };
505
506 counter = 0;
507 if first_interrupted {
508 // fl.dump();
509 match c::boot_go(&mut flashmap, &images.areadesc, Some(&mut counter), false) {
510 (-0x13579, _) => panic!("Shouldn't stop again"),
511 (0, _) => (),
512 (x, _) => panic!("Unknown return: {}", x),
513 }
514 }
515
516 (flashmap, count - counter)
517}
518
David Brown5c9e0f12019-01-09 16:34:33 -0700519fn try_revert(flashmap: &SimFlashMap, areadesc: &AreaDesc, count: usize) -> SimFlashMap {
520 let mut flashmap = flashmap.clone();
521
522 // fl.write_file("image0.bin").unwrap();
523 for i in 0 .. count {
524 info!("Running boot pass {}", i + 1);
525 assert_eq!(c::boot_go(&mut flashmap, &areadesc, None, false), (0, 0));
526 }
527 flashmap
528}
529
David Brown5c9e0f12019-01-09 16:34:33 -0700530fn try_revert_with_fail_at(flashmap: &SimFlashMap, images: &Images,
531 stop: i32) -> bool {
532 let mut flashmap = flashmap.clone();
533 let mut fails = 0;
534
535 let mut counter = stop;
536 let (x, _) = c::boot_go(&mut flashmap, &images.areadesc, Some(&mut counter), false);
537 if x != -0x13579 {
538 warn!("Should have stopped at interruption point");
539 fails += 1;
540 }
541
542 if !verify_trailer(&flashmap, &images.slots, 0, None, None, BOOT_FLAG_UNSET) {
543 warn!("copy_done should be unset");
544 fails += 1;
545 }
546
547 let (x, _) = c::boot_go(&mut flashmap, &images.areadesc, None, false);
548 if x != 0 {
549 warn!("Should have finished upgrade");
550 fails += 1;
551 }
552
553 if !verify_image(&flashmap, &images.slots, 0, &images.upgrades) {
554 warn!("Image in slot 0 before revert is invalid at stop={}", stop);
555 fails += 1;
556 }
557 if !verify_image(&flashmap, &images.slots, 1, &images.primaries) {
558 warn!("Image in slot 1 before revert is invalid at stop={}", stop);
559 fails += 1;
560 }
561 if !verify_trailer(&flashmap, &images.slots, 0, BOOT_MAGIC_GOOD,
562 BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
563 warn!("Mismatched trailer for Slot 0 before revert");
564 fails += 1;
565 }
566 if !verify_trailer(&flashmap, &images.slots, 1, BOOT_MAGIC_UNSET,
567 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
568 warn!("Mismatched trailer for Slot 1 before revert");
569 fails += 1;
570 }
571
572 // Do Revert
573 let (x, _) = c::boot_go(&mut flashmap, &images.areadesc, None, false);
574 if x != 0 {
575 warn!("Should have finished a revert");
576 fails += 1;
577 }
578
579 if !verify_image(&flashmap, &images.slots, 0, &images.primaries) {
580 warn!("Image in slot 0 after revert is invalid at stop={}", stop);
581 fails += 1;
582 }
583 if !verify_image(&flashmap, &images.slots, 1, &images.upgrades) {
584 warn!("Image in slot 1 after revert is invalid at stop={}", stop);
585 fails += 1;
586 }
587 if !verify_trailer(&flashmap, &images.slots, 0, BOOT_MAGIC_GOOD,
588 BOOT_FLAG_SET, BOOT_FLAG_SET) {
589 warn!("Mismatched trailer for Slot 1 after revert");
590 fails += 1;
591 }
592 if !verify_trailer(&flashmap, &images.slots, 1, BOOT_MAGIC_UNSET,
593 BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
594 warn!("Mismatched trailer for Slot 1 after revert");
595 fails += 1;
596 }
597
598 fails > 0
599}
600
601fn try_random_fails(flashmap: &SimFlashMap, images: &Images,
602 total_ops: i32, count: usize) -> (SimFlashMap, Vec<i32>) {
603 let mut flashmap = flashmap.clone();
604
605 mark_permanent_upgrade(&mut flashmap, &images.slots[1]);
606
607 let mut rng = rand::thread_rng();
608 let mut resets = vec![0i32; count];
609 let mut remaining_ops = total_ops;
610 for i in 0 .. count {
611 let ops = Range::new(1, remaining_ops / 2);
612 let reset_counter = ops.ind_sample(&mut rng);
613 let mut counter = reset_counter;
614 match c::boot_go(&mut flashmap, &images.areadesc, Some(&mut counter), false) {
615 (0, _) | (-0x13579, _) => (),
616 (x, _) => panic!("Unknown return: {}", x),
617 }
618 remaining_ops -= reset_counter;
619 resets[i] = reset_counter;
620 }
621
622 match c::boot_go(&mut flashmap, &images.areadesc, None, false) {
623 (-0x13579, _) => panic!("Should not be have been interrupted!"),
624 (0, _) => (),
625 (x, _) => panic!("Unknown return: {}", x),
626 }
627
628 (flashmap, resets)
629}
630
631/// Show the flash layout.
632#[allow(dead_code)]
633fn show_flash(flash: &dyn Flash) {
634 println!("---- Flash configuration ----");
635 for sector in flash.sector_iter() {
636 println!(" {:3}: 0x{:08x}, 0x{:08x}",
637 sector.num, sector.base, sector.size);
638 }
639 println!("");
640}
641
642/// Install a "program" into the given image. This fakes the image header, or at least all of the
643/// fields used by the given code. Returns a copy of the image that was written.
644pub fn install_image(flashmap: &mut SimFlashMap, slots: &[SlotInfo], slot: usize, len: usize,
645 bad_sig: bool) -> [Option<Vec<u8>>; 2] {
646 let offset = slots[slot].base_off;
647 let slot_len = slots[slot].len;
648 let dev_id = slots[slot].dev_id;
649
650 let mut tlv = make_tlv();
651
652 const HDR_SIZE: usize = 32;
653
654 // Generate a boot header. Note that the size doesn't include the header.
655 let header = ImageHeader {
656 magic: 0x96f3b83d,
657 load_addr: 0,
658 hdr_size: HDR_SIZE as u16,
659 _pad1: 0,
660 img_size: len as u32,
661 flags: tlv.get_flags(),
662 ver: ImageVersion {
663 major: (offset / (128 * 1024)) as u8,
664 minor: 0,
665 revision: 1,
666 build_num: offset as u32,
667 },
668 _pad2: 0,
669 };
670
671 let mut b_header = [0; HDR_SIZE];
672 b_header[..32].clone_from_slice(header.as_raw());
673 assert_eq!(b_header.len(), HDR_SIZE);
674
675 tlv.add_bytes(&b_header);
676
677 // The core of the image itself is just pseudorandom data.
678 let mut b_img = vec![0; len];
679 splat(&mut b_img, offset);
680
681 // TLV signatures work over plain image
682 tlv.add_bytes(&b_img);
683
684 // Generate encrypted images
685 let flag = TlvFlags::ENCRYPTED as u32;
686 let is_encrypted = (tlv.get_flags() & flag) == flag;
687 let mut b_encimg = vec![];
688 if is_encrypted {
689 let key = GenericArray::from_slice(AES_SEC_KEY);
690 let nonce = GenericArray::from_slice(&[0; 16]);
691 let mut cipher = Aes128Ctr::new(&key, &nonce);
692 b_encimg = b_img.clone();
693 cipher.apply_keystream(&mut b_encimg);
694 }
695
696 // Build the TLV itself.
697 let mut b_tlv = if bad_sig {
698 let good_sig = &mut tlv.make_tlv();
699 vec![0; good_sig.len()]
700 } else {
701 tlv.make_tlv()
702 };
703
704 // Pad the block to a flash alignment (8 bytes).
705 while b_tlv.len() % 8 != 0 {
706 //FIXME: should be erase_val?
707 b_tlv.push(0xFF);
708 }
709
710 let mut buf = vec![];
711 buf.append(&mut b_header.to_vec());
712 buf.append(&mut b_img);
713 buf.append(&mut b_tlv.clone());
714
715 let mut encbuf = vec![];
716 if is_encrypted {
717 encbuf.append(&mut b_header.to_vec());
718 encbuf.append(&mut b_encimg);
719 encbuf.append(&mut b_tlv);
720 }
721
722 let result: [Option<Vec<u8>>; 2];
723
724 // Since images are always non-encrypted in slot0, we first write an
725 // encrypted image, re-read to use for verification, erase + flash
726 // un-encrypted. In slot1 the image is written un-encrypted, and if
727 // encryption is requested, it follows an erase + flash encrypted.
728
729 let flash = flashmap.get_mut(&dev_id).unwrap();
730
731 if slot == 0 {
732 let enc_copy: Option<Vec<u8>>;
733
734 if is_encrypted {
735 flash.write(offset, &encbuf).unwrap();
736
737 let mut enc = vec![0u8; encbuf.len()];
738 flash.read(offset, &mut enc).unwrap();
739
740 enc_copy = Some(enc);
741
742 flash.erase(offset, slot_len).unwrap();
743 } else {
744 enc_copy = None;
745 }
746
747 flash.write(offset, &buf).unwrap();
748
749 let mut copy = vec![0u8; buf.len()];
750 flash.read(offset, &mut copy).unwrap();
751
752 result = [Some(copy), enc_copy];
753 } else {
754
755 flash.write(offset, &buf).unwrap();
756
757 let mut copy = vec![0u8; buf.len()];
758 flash.read(offset, &mut copy).unwrap();
759
760 let enc_copy: Option<Vec<u8>>;
761
762 if is_encrypted {
763 flash.erase(offset, slot_len).unwrap();
764
765 flash.write(offset, &encbuf).unwrap();
766
767 let mut enc = vec![0u8; encbuf.len()];
768 flash.read(offset, &mut enc).unwrap();
769
770 enc_copy = Some(enc);
771 } else {
772 enc_copy = None;
773 }
774
775 result = [Some(copy), enc_copy];
776 }
777
778 result
779}
780
781#[cfg(feature = "sig-rsa")]
782#[cfg(feature = "enc-kw")]
783fn make_tlv() -> TlvGen {
784 TlvGen::new_rsa_kw()
785}
786
787#[cfg(feature = "sig-rsa")]
788#[cfg(not(feature = "enc-rsa"))]
789#[cfg(not(feature = "enc-kw"))]
790fn make_tlv() -> TlvGen {
791 TlvGen::new_rsa_pss()
792}
793
794#[cfg(feature = "sig-ecdsa")]
795#[cfg(feature = "enc-kw")]
796fn make_tlv() -> TlvGen {
797 TlvGen::new_ecdsa_kw()
798}
799
800#[cfg(feature = "sig-ecdsa")]
801#[cfg(not(feature = "enc-kw"))]
802fn make_tlv() -> TlvGen {
803 TlvGen::new_ecdsa()
804}
805
806#[cfg(not(feature = "sig-rsa"))]
807#[cfg(feature = "enc-rsa")]
808fn make_tlv() -> TlvGen {
809 TlvGen::new_enc_rsa()
810}
811
812#[cfg(feature = "sig-rsa")]
813#[cfg(feature = "enc-rsa")]
814fn make_tlv() -> TlvGen {
815 TlvGen::new_sig_enc_rsa()
816}
817
818#[cfg(not(feature = "sig-rsa"))]
819#[cfg(not(feature = "sig-ecdsa"))]
820#[cfg(feature = "enc-kw")]
821fn make_tlv() -> TlvGen {
822 TlvGen::new_enc_kw()
823}
824
825#[cfg(not(feature = "sig-rsa"))]
826#[cfg(not(feature = "sig-ecdsa"))]
827#[cfg(not(feature = "enc-rsa"))]
828#[cfg(not(feature = "enc-kw"))]
829fn make_tlv() -> TlvGen {
830 TlvGen::new_hash_only()
831}
832
833#[cfg(feature = "enc-rsa")]
834fn find_image(images: &[Option<Vec<u8>>; 2], slot: usize) -> &Vec<u8> {
835 match &images[slot] {
836 Some(image) => return image,
837 None => panic!("Invalid image"),
838 }
839}
840
841#[cfg(feature = "enc-kw")]
842fn find_image(images: &[Option<Vec<u8>>; 2], slot: usize) -> &Vec<u8> {
843 match &images[slot] {
844 Some(image) => return image,
845 None => panic!("Invalid image"),
846 }
847}
848
849#[cfg(not(feature = "enc-rsa"))]
850#[cfg(not(feature = "enc-kw"))]
851fn find_image(images: &[Option<Vec<u8>>; 2], _slot: usize) -> &Vec<u8> {
852 match &images[0] {
853 Some(image) => return image,
854 None => panic!("Invalid image"),
855 }
856}
857
858/// Verify that given image is present in the flash at the given offset.
859fn verify_image(flashmap: &SimFlashMap, slots: &[SlotInfo], slot: usize,
860 images: &[Option<Vec<u8>>; 2]) -> bool {
861 let image = find_image(images, slot);
862 let buf = image.as_slice();
863 let dev_id = slots[slot].dev_id;
864
865 let mut copy = vec![0u8; buf.len()];
866 let offset = slots[slot].base_off;
867 let flash = flashmap.get(&dev_id).unwrap();
868 flash.read(offset, &mut copy).unwrap();
869
870 if buf != &copy[..] {
871 for i in 0 .. buf.len() {
872 if buf[i] != copy[i] {
873 info!("First failure for slot{} at {:#x} {:#x}!={:#x}",
874 slot, offset + i, buf[i], copy[i]);
875 break;
876 }
877 }
878 false
879 } else {
880 true
881 }
882}
883
884#[cfg(feature = "overwrite-only")]
885#[allow(unused_variables)]
886// overwrite-only doesn't employ trailer management
887fn verify_trailer(flashmap: &SimFlashMap, slots: &[SlotInfo], slot: usize,
888 magic: Option<u8>, image_ok: Option<u8>,
889 copy_done: Option<u8>) -> bool {
890 true
891}
892
893#[cfg(not(feature = "overwrite-only"))]
894fn verify_trailer(flashmap: &SimFlashMap, slots: &[SlotInfo], slot: usize,
895 magic: Option<u8>, image_ok: Option<u8>,
896 copy_done: Option<u8>) -> bool {
897 let offset = slots[slot].trailer_off;
898 let dev_id = slots[slot].dev_id;
899 let mut copy = vec![0u8; c::boot_magic_sz() + c::boot_max_align() * 2];
900 let mut failed = false;
901
902 let flash = flashmap.get(&dev_id).unwrap();
903 let erased_val = flash.erased_val();
904 flash.read(offset, &mut copy).unwrap();
905
906 failed |= match magic {
907 Some(v) => {
908 if v == 1 && &copy[16..] != MAGIC.unwrap() {
909 warn!("\"magic\" mismatch at {:#x}", offset);
910 true
911 } else if v == 3 {
912 let expected = [erased_val; 16];
913 if &copy[16..] != expected {
914 warn!("\"magic\" mismatch at {:#x}", offset);
915 true
916 } else {
917 false
918 }
919 } else {
920 false
921 }
922 },
923 None => false,
924 };
925
926 failed |= match image_ok {
927 Some(v) => {
928 if (v == 1 && copy[8] != v) || (v == 3 && copy[8] != erased_val) {
929 warn!("\"image_ok\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[8]);
930 true
931 } else {
932 false
933 }
934 },
935 None => false,
936 };
937
938 failed |= match copy_done {
939 Some(v) => {
940 if (v == 1 && copy[0] != v) || (v == 3 && copy[0] != erased_val) {
941 warn!("\"copy_done\" mismatch at {:#x} v={} val={:#x}", offset, v, copy[0]);
942 true
943 } else {
944 false
945 }
946 },
947 None => false,
948 };
949
950 !failed
951}
952
953/// The image header
954#[repr(C)]
955pub struct ImageHeader {
956 magic: u32,
957 load_addr: u32,
958 hdr_size: u16,
959 _pad1: u16,
960 img_size: u32,
961 flags: u32,
962 ver: ImageVersion,
963 _pad2: u32,
964}
965
966impl AsRaw for ImageHeader {}
967
968#[repr(C)]
969pub struct ImageVersion {
970 major: u8,
971 minor: u8,
972 revision: u16,
973 build_num: u32,
974}
975
976#[derive(Clone)]
977pub struct SlotInfo {
978 pub base_off: usize,
979 pub trailer_off: usize,
980 pub len: usize,
981 pub dev_id: u8,
982}
983
984pub struct Images {
985 pub flashmap: SimFlashMap,
986 pub areadesc: AreaDesc,
987 pub slots: [SlotInfo; 2],
988 pub primaries: [Option<Vec<u8>>; 2],
989 pub upgrades: [Option<Vec<u8>>; 2],
990 pub total_count: Option<i32>,
991}
992
993const MAGIC: Option<&[u8]> = Some(&[0x77, 0xc2, 0x95, 0xf3,
994 0x60, 0xd2, 0xef, 0x7f,
995 0x35, 0x52, 0x50, 0x0f,
996 0x2c, 0xb6, 0x79, 0x80]);
997
998// Replicates defines found in bootutil.h
999const BOOT_MAGIC_GOOD: Option<u8> = Some(1);
1000const BOOT_MAGIC_UNSET: Option<u8> = Some(3);
1001
1002const BOOT_FLAG_SET: Option<u8> = Some(1);
1003const BOOT_FLAG_UNSET: Option<u8> = Some(3);
1004
1005/// Write out the magic so that the loader tries doing an upgrade.
1006pub fn mark_upgrade(flashmap: &mut SimFlashMap, slot: &SlotInfo) {
1007 let flash = flashmap.get_mut(&slot.dev_id).unwrap();
1008 let offset = slot.trailer_off + c::boot_max_align() * 2;
1009 flash.write(offset, MAGIC.unwrap()).unwrap();
1010}
1011
1012/// Writes the image_ok flag which, guess what, tells the bootloader
1013/// the this image is ok (not a test, and no revert is to be performed).
1014fn mark_permanent_upgrade(flashmap: &mut SimFlashMap, slot: &SlotInfo) {
1015 let flash = flashmap.get_mut(&slot.dev_id).unwrap();
1016 let mut ok = [flash.erased_val(); 8];
1017 ok[0] = 1u8;
1018 let off = slot.trailer_off + c::boot_max_align();
1019 let align = flash.align();
1020 flash.write(off, &ok[..align]).unwrap();
1021}
1022
1023// Drop some pseudo-random gibberish onto the data.
1024fn splat(data: &mut [u8], seed: usize) {
1025 let seed_block = [0x135782ea, 0x92184728, data.len() as u32, seed as u32];
1026 let mut rng: XorShiftRng = SeedableRng::from_seed(seed_block);
1027 rng.fill_bytes(data);
1028}
1029
1030/// Return a read-only view into the raw bytes of this object
1031trait AsRaw : Sized {
1032 fn as_raw<'a>(&'a self) -> &'a [u8] {
1033 unsafe { slice::from_raw_parts(self as *const _ as *const u8,
1034 mem::size_of::<Self>()) }
1035 }
1036}
1037
1038pub fn show_sizes() {
1039 // This isn't panic safe.
1040 for min in &[1, 2, 4, 8] {
1041 let msize = c::boot_trailer_sz(*min);
1042 println!("{:2}: {} (0x{:x})", min, msize, msize);
1043 }
1044}