vboot: Explicitly return rollback error from vb2api_load_kernel
Previously, vb2api_load_kernel() collapsed all kernel loading errors
into generic VB2_ERROR_LK_INVALID_KERNEL_FOUND or
VB2_ERROR_LK_NO_KERNEL_FOUND. This prevented the caller from
identifying rollback protection failures.
Modify vb2api_load_kernel() to specifically translate
VB2_ERROR_AVB_ERROR_ROLLBACK_INDEX into a new VB2_ERROR_LK_ROLLBACK
error code. This allows the UI layer to display a specific error
message for rollback violations (e.g., "Outdated recovery image")
instead of a generic failure screen.
BUG=b:488131983
BRANCH=none
TEST=Verified that the "Outdated recovery image" screen is displayed
when a rollback error occurs during recovery.
Cq-Depend: chromium:7666120
Change-Id: I9c0c090730fdad7dd4acc06bd83fb04919c2e1b7
Signed-off-by: Grzegorz Bernacki <bernacki@google.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/7666079
Reviewed-by: Julius Werner <jwerner@chromium.org>
Reviewed-by: Yu-Ping Wu <yupingso@chromium.org>
Tested-by: Tomasz Michalec <tmichalec@google.com>
Reviewed-by: Konrad Adamczyk <konrada@google.com>
Commit-Queue: Tomasz Michalec <tmichalec@google.com>
diff --git a/firmware/2lib/2load_kernel.c b/firmware/2lib/2load_kernel.c
index eec806e..c64f1bf 100644
--- a/firmware/2lib/2load_kernel.c
+++ b/firmware/2lib/2load_kernel.c
@@ -674,6 +674,7 @@
int found_partitions = 0;
uint32_t kernel_version;
vb2_error_t rv = VB2_ERROR_LK_NO_KERNEL_FOUND;
+ vb2_error_t active_slot_rv = VB2_ERROR_LK_NO_KERNEL_FOUND;
/* Read GPT data */
GptData gpt;
@@ -735,6 +736,10 @@
rv = VB2_ERROR_LK_INVALID_KERNEL_FOUND;
}
+ /* Store error from active slot */
+ if (found_partitions == 1)
+ active_slot_rv = rv;
+
if (rv == VB2_SUCCESS)
break;
@@ -743,7 +748,9 @@
}
if (rv) {
- if (found_partitions > 0)
+ if (active_slot_rv == VB2_ERROR_AVB_ERROR_ROLLBACK_INDEX)
+ rv = VB2_ERROR_LK_ROLLBACK;
+ else if (found_partitions > 0)
rv = VB2_ERROR_LK_INVALID_KERNEL_FOUND;
else
rv = VB2_ERROR_LK_NO_KERNEL_FOUND;
diff --git a/firmware/2lib/2recovery_reasons.c b/firmware/2lib/2recovery_reasons.c
index 7590bf6..ce2e92c 100644
--- a/firmware/2lib/2recovery_reasons.c
+++ b/firmware/2lib/2recovery_reasons.c
@@ -164,6 +164,8 @@
return "Attempt to escape from NO_BOOT mode was detected";
/* 0x65 */ case VB2_RECOVERY_WIDEVINE_PREPARE:
return "Failed to prepare widevine";
+ /* 0x66 */ case VB2_RECOVERY_KERNEL_ROLLBACK:
+ return "Kernel version too old (rollback protection)";
/* 0x7f */ case VB2_RECOVERY_RW_UNSPECIFIED:
return "Unspecified/unknown error in RW firmware";
/* 0x81 */ case VB2_RECOVERY_DEPRECATED_KE_DM_VERITY:
diff --git a/firmware/2lib/include/2recovery_reasons.h b/firmware/2lib/include/2recovery_reasons.h
index 4dd2eaf..fb6c0dd 100644
--- a/firmware/2lib/include/2recovery_reasons.h
+++ b/firmware/2lib/include/2recovery_reasons.h
@@ -283,6 +283,9 @@
/* Failed to prepare the widevine functionality */
VB2_RECOVERY_WIDEVINE_PREPARE = 0x65,
+ /* Kernel version too old */
+ VB2_RECOVERY_KERNEL_ROLLBACK = 0x66,
+
/* Unspecified/unknown error in rewritable firmware */
VB2_RECOVERY_RW_UNSPECIFIED = 0x7f,
diff --git a/firmware/2lib/include/2return_codes.h b/firmware/2lib/include/2return_codes.h
index ec8a436..c35745c 100644
--- a/firmware/2lib/include/2return_codes.h
+++ b/firmware/2lib/include/2return_codes.h
@@ -785,6 +785,9 @@
/* No working block devices were found */
VB2_ERROR_LK_NO_DISK_FOUND = 0x100b3000,
+ /* Invalid kernel version (Rollback Protection) */
+ VB2_ERROR_LK_ROLLBACK = 0x100b4000,
+
/**********************************************************************
* UI errors
*/
diff --git a/tests/vb2_load_android_tests.c b/tests/vb2_load_android_tests.c
index 2e7a67f..2e66922 100644
--- a/tests/vb2_load_android_tests.c
+++ b/tests/vb2_load_android_tests.c
@@ -42,8 +42,10 @@
struct vendor_boot_img_hdr_v4 vendor_boot_hdr;
struct boot_img_hdr_v4 init_boot_hdr;
+enum avb_fail {NO_FAIL, VERIFY_FAIL, ROLLBACK_FAIL};
+
uint64_t rollback_value;
-bool avb_verification_fails;
+enum avb_fail avb_verification_fails;
bool init_boot_missing, vendor_boot_missing;
uint64_t sector_to_read;
uint64_t ota_recovery_sector;
@@ -119,10 +121,15 @@
verify_data->cmdline = (char *)"";
*out_data = verify_data;
- if (avb_verification_fails)
+ switch (avb_verification_fails) {
+ case VERIFY_FAIL:
return AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION;
- else
+ case ROLLBACK_FAIL:
+ return AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX;
+ case NO_FAIL:
+ default:
return AVB_SLOT_VERIFY_RESULT_OK;
+ }
}
void avb_slot_verify_data_free(AvbSlotVerifyData *data)
@@ -179,7 +186,7 @@
static void reset_mocks(void)
{
rollback_value = 0x1;
- avb_verification_fails = false;
+ avb_verification_fails = NO_FAIL;
init_boot_missing = false;
vendor_boot_missing = false;
ota_recovery_sector = OTA_RECOVERY_A_PART;
@@ -267,17 +274,31 @@
// AVB verification fails
reset_mocks();
- avb_verification_fails = true;
+ avb_verification_fails = VERIFY_FAIL;
TEST_EQ(vb2api_load_kernel(ctx, &lkp, &disk_info), VB2_ERROR_LK_INVALID_KERNEL_FOUND,
"AVB verification fails");
// AVB verification fails in developer mode
reset_mocks();
- avb_verification_fails = true;
+ avb_verification_fails = VERIFY_FAIL;
SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER);
TEST_EQ(vb2api_load_kernel(ctx, &lkp, &disk_info), VB2_SUCCESS,
"AVB verification fails in developer mode");
+ // Rollback protection in developer mode
+ reset_mocks();
+ avb_verification_fails = ROLLBACK_FAIL;
+ SET_BOOT_MODE(ctx, VB2_BOOT_MODE_DEVELOPER);
+ TEST_EQ(vb2api_load_kernel(ctx, &lkp, &disk_info), VB2_SUCCESS,
+ "Rollback protection in developer mode");
+
+ // Rollback protection in normal mode
+ reset_mocks();
+ avb_verification_fails = ROLLBACK_FAIL;
+ TEST_EQ(vb2api_load_kernel(ctx, &lkp, &disk_info), VB2_ERROR_LK_ROLLBACK,
+ "Rollback protection in normal mode");
+
+
// Missing init_boot partition
reset_mocks();
init_boot_missing = true;
@@ -323,6 +344,11 @@
TEST_PTR_EQ(lkp.disk_handle, (void *)CHILD_HANDLE, " fill disk_handle when success");
reset_mocks();
+ avb_verification_fails = ROLLBACK_FAIL;
+ TEST_EQ(vb2api_load_nbr_kernel(ctx, &lkp, &disk_info, 0), VB2_ERROR_LK_NO_KERNEL_FOUND,
+ "Boot ota_recovery_a");
+
+ reset_mocks();
ota_recovery_sector = OTA_RECOVERY_B_PART;
TEST_EQ(vb2api_load_nbr_kernel(ctx, &lkp, &disk_info, 0), VB2_SUCCESS,
"Boot ota_recovery_b");