Skip to content

Commit 1359aac

Browse files
committed
Block rollback fallback in non-flash update paths
F/2254
1 parent 91e0b16 commit 1359aac

7 files changed

Lines changed: 79 additions & 14 deletions

File tree

src/libwolfboot.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1395,6 +1395,15 @@ int wolfBoot_dualboot_candidate(void)
13951395
(wolfBoot_get_partition_state(candidate, &p_state) == 0) &&
13961396
(p_state == IMG_STATE_TESTING))
13971397
{
1398+
#ifndef ALLOW_DOWNGRADE
1399+
uint32_t candidate_v = (candidate == PART_BOOT) ? boot_v : update_v;
1400+
uint32_t fallback_v = (candidate == PART_BOOT) ? update_v : boot_v;
1401+
1402+
if (fallback_v < candidate_v) {
1403+
wolfBoot_printf("Rollback to lower version not allowed\n");
1404+
return -1;
1405+
}
1406+
#endif
13981407
wolfBoot_erase_partition(candidate);
13991408
candidate ^= 1; /* switch to other partition if available */
14001409
}

src/update_disk.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ void RAMFUNCTION wolfBoot_start(void)
259259
uint32_t *load_address;
260260
int failures = 0;
261261
uint32_t load_off;
262+
uint32_t max_ver;
262263
const uint8_t *hdr_ptr = NULL;
263264
#ifdef MMU
264265
uint8_t *dts_addr = NULL;
@@ -346,6 +347,7 @@ void RAMFUNCTION wolfBoot_start(void)
346347
}
347348

348349
wolfBoot_printf("Versions, A:%u B:%u\r\n", pA_ver, pB_ver);
350+
max_ver = (pB_ver > pA_ver) ? (uint32_t)pB_ver : (uint32_t)pA_ver;
349351

350352
/* Choose partition with higher version */
351353
selected = (pB_ver > pA_ver) ? 1: 0;
@@ -368,6 +370,15 @@ void RAMFUNCTION wolfBoot_start(void)
368370
cur_part = BOOT_PART_B;
369371
else
370372
cur_part = BOOT_PART_A;
373+
#ifndef ALLOW_DOWNGRADE
374+
{
375+
uint32_t cur_ver = selected ? (uint32_t)pB_ver : (uint32_t)pA_ver;
376+
if ((max_ver > 0U) && (cur_ver < max_ver)) {
377+
wolfBoot_printf("Rollback to lower version not allowed\r\n");
378+
break;
379+
}
380+
}
381+
#endif
371382

372383
part_name[2] = 'A' + selected;
373384

src/update_flash_hwswap.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,24 @@ void RAMFUNCTION wolfBoot_start(void)
4545
int active;
4646
struct wolfBoot_image fw_image;
4747
uint8_t p_state;
48+
#ifndef ALLOW_DOWNGRADE
49+
uint32_t boot_v = wolfBoot_current_firmware_version();
50+
uint32_t update_v = wolfBoot_update_firmware_version();
51+
uint32_t max_v = (boot_v > update_v) ? boot_v : update_v;
52+
#endif
4853
active = wolfBoot_dualboot_candidate();
4954

5055
if (active < 0) /* panic if no images available */
5156
boot_panic();
5257

5358
for (;;) {
59+
#ifndef ALLOW_DOWNGRADE
60+
uint32_t active_v = (active == PART_UPDATE) ? update_v : boot_v;
61+
if ((max_v > 0U) && (active_v < max_v)) {
62+
wolfBoot_printf("Rollback to lower version not allowed\n");
63+
boot_panic();
64+
}
65+
#endif
5466
if ((wolfBoot_open_image(&fw_image, active) < 0)
5567
#ifndef WOLFBOOT_SKIP_BOOT_VERIFY
5668
|| (wolfBoot_verify_integrity(&fw_image) < 0)

src/update_ram.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@ void RAMFUNCTION wolfBoot_start(void)
138138
uint8_t *dts_addr = NULL;
139139
uint32_t dts_size = 0;
140140
#endif
141+
#ifndef ALLOW_DOWNGRADE
142+
uint32_t boot_v = wolfBoot_current_firmware_version();
143+
uint32_t update_v = wolfBoot_update_firmware_version();
144+
uint32_t max_v = (boot_v > update_v) ? boot_v : update_v;
145+
#endif
141146

142147
memset(&os_image, 0, sizeof(struct wolfBoot_image));
143148

@@ -162,6 +167,16 @@ void RAMFUNCTION wolfBoot_start(void)
162167
wolfBoot_panic();
163168
break;
164169
}
170+
#ifndef ALLOW_DOWNGRADE
171+
{
172+
uint32_t active_v = (active == PART_UPDATE) ? update_v : boot_v;
173+
if ((max_v > 0U) && (active_v < max_v)) {
174+
wolfBoot_printf("Rollback to lower version not allowed\n");
175+
wolfBoot_panic();
176+
break;
177+
}
178+
}
179+
#endif
165180

166181
#if defined(WOLFBOOT_DUALBOOT) && defined(WOLFBOOT_FIXED_PARTITIONS)
167182
wolfBoot_printf("Trying %s partition at %p\n",

tools/unit-tests/unit-update-disk.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ static int mock_disk_init_ret;
3333
static int mock_disk_close_called;
3434
static int mock_do_boot_called;
3535
static const uint32_t *mock_boot_address;
36+
static int mock_fail_payload_part;
3637

3738
ChaCha chacha;
3839

@@ -72,6 +73,7 @@ static void reset_mocks(void)
7273
mock_disk_close_called = 0;
7374
mock_do_boot_called = 0;
7475
mock_boot_address = NULL;
76+
mock_fail_payload_part = -1;
7577
wolfBoot_panicked = 0;
7678
}
7779

@@ -140,6 +142,8 @@ int disk_part_read(int drv, int part, uint64_t off, uint64_t sz, uint8_t *buf)
140142

141143
(void)drv;
142144
image = (part == BOOT_PART_B) ? part_b_image : part_a_image;
145+
if ((mock_fail_payload_part == part) && (off >= IMAGE_HEADER_SIZE))
146+
return -1;
143147
if ((off > max) || (sz > (max - off)))
144148
return -1;
145149
memcpy(buf, image + off, (size_t)sz);
@@ -288,6 +292,19 @@ START_TEST(test_get_decrypted_blob_version_rejects_truncated_version_tlv)
288292
}
289293
END_TEST
290294

295+
START_TEST(test_update_disk_rejects_rollback_after_higher_image_failure)
296+
{
297+
reset_mocks();
298+
build_image(part_a_image, 7, 0xA1);
299+
build_image(part_b_image, 5, 0xB2);
300+
mock_fail_payload_part = BOOT_PART_A;
301+
302+
wolfBoot_start();
303+
304+
ck_assert_int_eq(wolfBoot_panicked, 1);
305+
}
306+
END_TEST
307+
291308
Suite *wolfboot_suite(void)
292309
{
293310
Suite *s = suite_create("wolfBoot");
@@ -297,6 +314,7 @@ Suite *wolfboot_suite(void)
297314
tcase_add_test(tc, test_update_disk_zeroizes_key_material_before_boot);
298315
tcase_add_test(tc, test_update_disk_prefers_primary_partition_when_versions_equal);
299316
tcase_add_test(tc, test_get_decrypted_blob_version_rejects_truncated_version_tlv);
317+
tcase_add_test(tc, test_update_disk_rejects_rollback_after_higher_image_failure);
300318
suite_add_tcase(s, tc);
301319

302320
return s;

tools/unit-tests/unit-update-ram-nofixed.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ static int add_payload(uint8_t part, uint32_t version, uint32_t size)
191191
return 0;
192192
}
193193

194-
START_TEST(test_invalid_update_falls_back_to_boot_without_reselect_loop)
194+
START_TEST(test_invalid_update_rollback_to_older_boot_is_denied)
195195
{
196196
uint8_t bad_digest[SHA256_DIGEST_SIZE];
197197

@@ -208,8 +208,8 @@ START_TEST(test_invalid_update_falls_back_to_boot_without_reselect_loop)
208208

209209
wolfBoot_start();
210210

211-
ck_assert_int_eq(wolfBoot_staged_ok, 1);
212-
ck_assert_ptr_eq(wolfBoot_stage_address, (const uint32_t *)WOLFBOOT_LOAD_ADDRESS);
211+
ck_assert_int_eq(wolfBoot_staged_ok, 0);
212+
ck_assert_int_eq(wolfBoot_panicked, 1);
213213
cleanup_flash();
214214
}
215215
END_TEST
@@ -219,7 +219,7 @@ static Suite *wolfboot_suite(void)
219219
Suite *s = suite_create("wolfboot-update-ram-nofixed");
220220
TCase *tc = tcase_create("fallback");
221221

222-
tcase_add_test(tc, test_invalid_update_falls_back_to_boot_without_reselect_loop);
222+
tcase_add_test(tc, test_invalid_update_rollback_to_older_boot_is_denied);
223223
tcase_set_timeout(tc, 5);
224224
suite_add_tcase(s, tc);
225225

tools/unit-tests/unit-update-ram.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -378,8 +378,8 @@ START_TEST (test_invalid_update_type) {
378378
ext_flash_lock();
379379
wolfBoot_update_trigger();
380380
wolfBoot_start();
381-
ck_assert(wolfBoot_staged_ok);
382-
ck_assert(get_version_ramloaded() == 1);
381+
ck_assert(!wolfBoot_staged_ok);
382+
ck_assert_int_eq(wolfBoot_panicked, 1);
383383
cleanup_flash();
384384
}
385385

@@ -396,8 +396,8 @@ START_TEST (test_update_toolarge) {
396396

397397
wolfBoot_update_trigger();
398398
wolfBoot_start();
399-
ck_assert(wolfBoot_staged_ok);
400-
ck_assert(get_version_ramloaded() == 1);
399+
ck_assert(!wolfBoot_staged_ok);
400+
ck_assert_int_eq(wolfBoot_panicked, 1);
401401
cleanup_flash();
402402
}
403403

@@ -414,12 +414,12 @@ START_TEST (test_invalid_sha) {
414414
ext_flash_lock();
415415
wolfBoot_update_trigger();
416416
wolfBoot_start();
417-
ck_assert(wolfBoot_staged_ok);
418-
ck_assert(get_version_ramloaded() == 1);
417+
ck_assert(!wolfBoot_staged_ok);
418+
ck_assert_int_eq(wolfBoot_panicked, 1);
419419
cleanup_flash();
420420
}
421421

422-
START_TEST (test_emergency_rollback) {
422+
START_TEST (test_emergency_rollback_to_older_version_denied) {
423423
uint8_t testing_flags[5] = { IMG_STATE_TESTING, 'B', 'O', 'O', 'T' };
424424
reset_mock_stats();
425425
prepare_flash();
@@ -432,8 +432,8 @@ START_TEST (test_emergency_rollback) {
432432
ext_flash_lock();
433433

434434
wolfBoot_start();
435-
ck_assert(wolfBoot_staged_ok);
436-
ck_assert(get_version_ramloaded() == 1);
435+
ck_assert(!wolfBoot_staged_ok);
436+
ck_assert_int_eq(wolfBoot_panicked, 1);
437437
cleanup_flash();
438438
}
439439

@@ -532,7 +532,7 @@ Suite *wolfboot_suite(void)
532532
tcase_add_test(invalid_update_type, test_invalid_update_type);
533533
tcase_add_test(update_toolarge, test_update_toolarge);
534534
tcase_add_test(invalid_sha, test_invalid_sha);
535-
tcase_add_test(emergency_rollback, test_emergency_rollback);
535+
tcase_add_test(emergency_rollback, test_emergency_rollback_to_older_version_denied);
536536
tcase_add_test(emergency_rollback_failure_due_to_bad_update, test_emergency_rollback_failure_due_to_bad_update);
537537
tcase_add_test(empty_boot_partition_update, test_empty_boot_partition_update);
538538
tcase_add_test(empty_boot_but_update_sha_corrupted_denied, test_empty_boot_but_update_sha_corrupted_denied);

0 commit comments

Comments
 (0)