From d81a1aca72fb1bf68c1b340b4b5e9f60c208f40b Mon Sep 17 00:00:00 2001 From: Konrad Adamczyk Date: Wed, 13 Sep 2023 12:24:34 +0000 Subject: [PATCH 001/102] cgptlib: Add helper define for partition NAME_SIZE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BUG=none TEST=With consecutive CLs applied build FW and run android BRANCH=main Change-Id: I723b4ba56ea8c6f4c2cbdd6840cc58f5f1b50085 Signed-off-by: Konrad Adamczyk Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5716698 Reviewed-by: Jakub Czapiga Commit-Queue: Grzegorz Bernacki Reviewed-by: Kornel Dulęba Tested-by: Grzegorz Bernacki Tested-by: Jakub Czapiga Reviewed-by: Jan Dąbroś --- firmware/include/gpt.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/firmware/include/gpt.h b/firmware/include/gpt.h index 4f4c245d..f31307ad 100644 --- a/firmware/include/gpt.h +++ b/firmware/include/gpt.h @@ -60,6 +60,7 @@ extern "C" { #define UUID_NODE_LEN 6 #define GUID_SIZE 16 +#define NAME_SIZE 36 /* GUID definition. Defined in appendix A of UEFI standard. */ typedef struct { @@ -128,7 +129,7 @@ typedef struct { } __attribute__((packed)) fields; uint64_t whole; } attrs; - uint16_t name[36]; /* UTF-16 encoded partition name */ + uint16_t name[NAME_SIZE]; /* UTF-16 encoded partition name */ /* Remainder of entry is reserved and should be 0 */ } __attribute__((packed)) GptEntry; From 99c202064bf17aa1098c7816b61a204444685f49 Mon Sep 17 00:00:00 2001 From: Konrad Adamczyk Date: Wed, 13 Sep 2023 12:23:33 +0000 Subject: [PATCH 002/102] cgptlib: Incorporate macros to specify android GPT partition names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BUG=none TEST=With consecutive CLs applied build FW and run android BRANCH=main Change-Id: Iae62b79a986eb7a3c0ce02642b9b5aeb171b90a8 Signed-off-by: Konrad Adamczyk Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5716699 Reviewed-by: Kornel Dulęba Commit-Queue: Grzegorz Bernacki Tested-by: Jakub Czapiga Reviewed-by: Jakub Czapiga Reviewed-by: Jan Dąbroś Tested-by: Grzegorz Bernacki --- firmware/include/gpt.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/firmware/include/gpt.h b/firmware/include/gpt.h index f31307ad..65c0666e 100644 --- a/firmware/include/gpt.h +++ b/firmware/include/gpt.h @@ -62,6 +62,16 @@ extern "C" { #define GUID_SIZE 16 #define NAME_SIZE 36 +/* + * Macros for Android partition names + */ +#define GPT_ENT_NAME_ANDROID_VBMETA "vbmeta" +#define GPT_ENT_NAME_ANDROID_INIT_BOOT "init_boot" +#define GPT_ENT_NAME_ANDROID_VENDOR_BOOT "vendor_boot" +#define GPT_ENT_NAME_ANDROID_BOOT "boot" +#define GPT_ENT_NAME_ANDROID_A_SUFFIX "_a" +#define GPT_ENT_NAME_ANDROID_B_SUFFIX "_b" + /* GUID definition. Defined in appendix A of UEFI standard. */ typedef struct { union { From ccdd44c3d4fa67ae234679f546a34b58275e03bf Mon Sep 17 00:00:00 2001 From: Konrad Adamczyk Date: Mon, 21 Aug 2023 09:29:54 +0000 Subject: [PATCH 003/102] cgptlib: Add string manipulation functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BUG=none TEST=With consecutive CLs applied build FW and run android BRANCH=main Change-Id: I412ace211bb8c193bb2662be976e55e3855b8d93 Signed-off-by: Konrad Adamczyk Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5716700 Tested-by: Grzegorz Bernacki Reviewed-by: Jan Dąbroś Commit-Queue: Grzegorz Bernacki Reviewed-by: Jakub Czapiga Tested-by: Jakub Czapiga --- firmware/lib/cgptlib/cgptlib_internal.c | 60 +++++++++++++++++++ .../lib/cgptlib/include/cgptlib_internal.h | 16 +++++ 2 files changed, 76 insertions(+) diff --git a/firmware/lib/cgptlib/cgptlib_internal.c b/firmware/lib/cgptlib/cgptlib_internal.c index 17931370..a3859302 100644 --- a/firmware/lib/cgptlib/cgptlib_internal.c +++ b/firmware/lib/cgptlib/cgptlib_internal.c @@ -12,6 +12,13 @@ static const int MIN_SECTOR_SIZE = 512; +#define UTF8_4BYTES_MASK 0xf8 +#define UTF8_4BYTES_START 0xf0 +#define UTF8_3BYTES_MASK 0xf0 +#define UTF8_3BYTES_START 0xe0 +#define UTF8_2BYTES_MASK 0xe0 +#define UTF8_2BYTES_START 0xc0 + size_t CalculateEntriesSectors(GptHeader* h, uint32_t sector_bytes) { size_t bytes = h->number_of_entries * h->size_of_entry; @@ -19,6 +26,59 @@ size_t CalculateEntriesSectors(GptHeader* h, uint32_t sector_bytes) return ret; } +char *JoinStr(const char *a, const char *b) +{ + size_t len = strlen(a) + strlen(b) + 1; + char *ret = (char *)malloc(len); + if (ret == NULL) + return NULL; + + strcpy(ret, a); + return strcat(ret, b); +} + +int UTF8ToUCS2(const uint8_t *utf8_data, + uint16_t *ucs2_data, + size_t ucs2_data_capacity_num_bytes) +{ + uint32_t idx8 = 0; + uint32_t idx2 = 0; + + if (!utf8_data) + return -1; + + do { + if (idx2 >= ucs2_data_capacity_num_bytes) + break; + + if ((utf8_data[idx8] & UTF8_4BYTES_MASK) == UTF8_4BYTES_START) { + /* There are no meaningful UCS characters in that range */ + return -1; + } else if ((utf8_data[idx8] & UTF8_3BYTES_MASK) == UTF8_3BYTES_START) { + ucs2_data[idx2] = + (uint16_t)((uint16_t)utf8_data[idx8] << 12) | + (uint16_t)(((uint16_t)utf8_data[idx8 + 1] << 6) & 0x0FC0) | + (uint16_t)((uint16_t)utf8_data[idx8 + 2] & 0x003F); + idx8 += 3; + } else if ((utf8_data[idx8] & UTF8_2BYTES_MASK) == UTF8_2BYTES_START) { + ucs2_data[idx2] = + (uint16_t)(((uint16_t)utf8_data[idx8] << 6) & 0x07C0) | + (uint16_t)((uint16_t)utf8_data[idx8 + 1] & 0x003F); + idx8 += 2; + } else if (!(utf8_data[idx8] >> 7)) { + ucs2_data[idx2] = (uint16_t)((uint16_t)utf8_data[idx8] & 0x00FF); + idx8++; + } else { + // invalid utf-8 + return -1; + } + idx2++; + } while (utf8_data[idx8] != 0); + + /* Success */ + return idx2; +} + int CheckParameters(GptData *gpt) { /* Only support 512-byte or larger sectors that are a power of 2 */ diff --git a/firmware/lib/cgptlib/include/cgptlib_internal.h b/firmware/lib/cgptlib/include/cgptlib_internal.h index 29f84f0f..32f7347b 100644 --- a/firmware/lib/cgptlib/include/cgptlib_internal.h +++ b/firmware/lib/cgptlib/include/cgptlib_internal.h @@ -175,4 +175,20 @@ const char *GptErrorText(int error_code); */ size_t CalculateEntriesSectors(GptHeader* h, uint32_t sector_bytes); +/** + * Convert UTF8 string to UCS2. The UTF8 string must be null-terminated. + * Caller must prepare enough space for UTF16, including a terminating 0x0000. + * The caller just needs to prepare the byte length of UTF8 plus the terminating + * 0x0000. + */ +int UTF8ToUCS2(const uint8_t *utf8_data, + uint16_t *ucs2_data, + size_t ucs2_data_capacity_num_bytes); + +/** + * This function combines strings a and b into new one. + * Caller is responsible for freeing returned string. + */ +char *JoinStr(const char *a, const char *b); + #endif /* VBOOT_REFERENCE_CGPTLIB_INTERNAL_H_ */ From 01987a6791c3b5c24ba9040ab6099e70314133b1 Mon Sep 17 00:00:00 2001 From: Konrad Adamczyk Date: Fri, 15 Sep 2023 10:07:55 +0000 Subject: [PATCH 004/102] cgptlib: Add helper functions for A/B selection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BUG=none TEST=With consecutive CLs applied build FW and run android BRANCH=main Change-Id: I0cd222f5dbf157603a0b5038c37717c408ca46ca Signed-off-by: Konrad Adamczyk Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5716701 Tested-by: Grzegorz Bernacki Tested-by: Jakub Czapiga Commit-Queue: Grzegorz Bernacki Reviewed-by: Jakub Czapiga Reviewed-by: Jan Dąbroś --- firmware/include/gpt_misc.h | 17 +++ firmware/lib/cgptlib/cgptlib.c | 127 ++++++++++++++++++ firmware/lib/cgptlib/cgptlib_internal.c | 30 +++++ firmware/lib/cgptlib/include/cgptlib.h | 22 +++ .../lib/cgptlib/include/cgptlib_internal.h | 5 + tests/vb2_inject_kernel_subkey_tests.c | 10 ++ tests/vb2_load_kernel_tests.c | 10 ++ 7 files changed, 221 insertions(+) diff --git a/firmware/include/gpt_misc.h b/firmware/include/gpt_misc.h index 776ed230..5787f870 100644 --- a/firmware/include/gpt_misc.h +++ b/firmware/include/gpt_misc.h @@ -199,6 +199,23 @@ int GptUpdateKernelWithEntry(GptData *gpt, GptEntry *e, uint32_t update_type); */ int GptUpdateKernelEntry(GptData *gpt, uint32_t update_type); +/** + * Get kernel partition suffix of active current_kernel. + * + * Returns GPT_SUCCESS if successful, else + * GPT_ERROR_NO_VALID_KERNEL. + */ +int GptGetActiveKernelPartitionSuffix(GptData *gpt, char **suffix); + +/** + * Provides start_sector and size for given partition by its UTF16LE name. + * + * Returns GPT_SUCCESS if successful, else + * GPT_ERROR_NO_SUCH_ENTRY. + */ +int GptFindOffsetByName(GptData *gpt, const char *name, + uint64_t *start_sector, uint64_t *size); + /* Getters and setters for partition attribute fields. */ int GetEntryRequired(const GptEntry *e); diff --git a/firmware/lib/cgptlib/cgptlib.c b/firmware/lib/cgptlib/cgptlib.c index ccae204b..d7943510 100644 --- a/firmware/lib/cgptlib/cgptlib.c +++ b/firmware/lib/cgptlib/cgptlib.c @@ -29,6 +29,44 @@ int GptInit(GptData *gpt) return GPT_SUCCESS; } +int GptGetActiveKernelPartitionSuffix(GptData *gpt, char **suffix) +{ + GptEntry *entries = (GptEntry *)gpt->primary_entries; + GptEntry *e; + const char suffix_a[] = GPT_ENT_NAME_ANDROID_A_SUFFIX; + const char suffix_b[] = GPT_ENT_NAME_ANDROID_B_SUFFIX; + const char *tmp = NULL; + int max_suffix_len; + + if (gpt->current_kernel == CGPT_KERNEL_ENTRY_NOT_FOUND) { + VB2_DEBUG("Kernel not selected\n"); + return GPT_ERROR_NO_VALID_KERNEL; + } + + max_suffix_len = (sizeof(suffix_a) > sizeof(suffix_b)) ? + sizeof(suffix_a) : sizeof(suffix_b); + + *suffix = malloc(max_suffix_len); + if (*suffix == NULL) { + VB2_DEBUG("Cannot allocate memory for suffix\n"); + return GPT_ERROR_NO_VALID_KERNEL; + } + + e = &entries[gpt->current_kernel]; + if (IsAndroidBootPartition(e, suffix_a)) { + tmp = suffix_a; + } else if (IsAndroidBootPartition(e, suffix_b)) { + tmp = suffix_b; + } else { + free(suffix); + return GPT_ERROR_NO_VALID_KERNEL; + } + + strncpy(*suffix, tmp, max_suffix_len); + + return GPT_SUCCESS; +} + int GptNextKernelEntry(GptData *gpt, uint64_t *start_sector, uint64_t *size) { GptHeader *header = (GptHeader *)gpt->primary_header; @@ -229,3 +267,92 @@ GptEntry *GptFindNthEntry(GptData *gpt, const Guid *guid, unsigned int n) return NULL; } + +int GptFindOffsetByName(GptData *gpt, const char *name, + uint64_t *start_sector, uint64_t *size) +{ + GptHeader *header = (GptHeader *)gpt->primary_header; + GptEntry *entries = (GptEntry *)gpt->primary_entries; + GptEntry *e; + int i; + uint16_t *name_ucs2; + int size_ucs2; + int ret = GPT_ERROR_NO_SUCH_ENTRY; + + name_ucs2 = calloc(NAME_SIZE, sizeof(*name_ucs2)); + if (name_ucs2 == NULL) + return ret; + + size_ucs2 = UTF8ToUCS2((const uint8_t *)name, name_ucs2, NAME_SIZE - 1); + if (size_ucs2 < 0) + goto out; + + for (i = 0, e = entries; i < header->number_of_entries; i++, e++) { + if (!memcmp(&e->name, name_ucs2, size_ucs2)) { + *start_sector = e->starting_lba; + *size = e->ending_lba - e->starting_lba + 1; + ret = GPT_SUCCESS; + break; + } + } + +out: + free(name_ucs2); + return ret; +} + +int GptFindInitBoot(GptData *gpt, uint64_t *start_sector, uint64_t *size) +{ + int ret; + char *name; + char *suffix = NULL; + + ret = GptGetActiveKernelPartitionSuffix(gpt, &suffix); + if (ret != GPT_SUCCESS) { + VB2_DEBUG("Unable to get kernel partition suffix\n"); + return ret; + } + + /* Construct name */ + name = JoinStr(GPT_ENT_NAME_ANDROID_INIT_BOOT, suffix); + free(suffix); + if (name == NULL) { + VB2_DEBUG("Unable to construct init_boot partition name\n"); + return GPT_ERROR_INVALID_ENTRIES; + } + + ret = GptFindOffsetByName(gpt, name, start_sector, size); + if (ret != GPT_SUCCESS) + VB2_DEBUG("Unable to find the %s partition\n", name); + + free(name); + return ret; +} + +int GptFindVendorBoot(GptData *gpt, uint64_t *start_sector, uint64_t *size) +{ + int ret; + char *name; + char *suffix = NULL; + + ret = GptGetActiveKernelPartitionSuffix(gpt, &suffix); + if (ret != GPT_SUCCESS) { + VB2_DEBUG("Unable to get kernel partition suffix\n"); + return ret; + } + + /* Construct name */ + name = JoinStr(GPT_ENT_NAME_ANDROID_VENDOR_BOOT, suffix); + free(suffix); + if (name == NULL) { + VB2_DEBUG("Unable to construct vendor_boot partition name\n"); + return GPT_ERROR_INVALID_ENTRIES; + } + + ret = GptFindOffsetByName(gpt, name, start_sector, size); + if (ret != GPT_SUCCESS) + VB2_DEBUG("Unable to find the %s partition\n", name); + + free(name); + return ret; +} diff --git a/firmware/lib/cgptlib/cgptlib_internal.c b/firmware/lib/cgptlib/cgptlib_internal.c index a3859302..13187c8b 100644 --- a/firmware/lib/cgptlib/cgptlib_internal.c +++ b/firmware/lib/cgptlib/cgptlib_internal.c @@ -213,6 +213,36 @@ int CheckHeader(GptHeader *h, int is_secondary, return 0; } +bool IsAndroidBootPartition(const GptEntry *e, const char *suffix) +{ + bool is_android_boot_part = false; + uint16_t *name_ucs2; + int size_ucs2; + char *name; + + name = JoinStr(GPT_ENT_NAME_ANDROID_BOOT, suffix); + if (name == NULL) + return is_android_boot_part; + + name_ucs2 = calloc(NAME_SIZE, sizeof(*name_ucs2)); + if (name_ucs2 == NULL) + goto cleanup; + + size_ucs2 = UTF8ToUCS2((const uint8_t *)name, name_ucs2, NAME_SIZE - 1); + if (size_ucs2 < 0) + goto cleanup; + + if (memcmp(&e->name, name_ucs2, size_ucs2)) + goto cleanup; + + is_android_boot_part = true; + +cleanup: + free(name); + free(name_ucs2); + return is_android_boot_part; +} + int IsKernelEntry(const GptEntry *e) { static Guid chromeos_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL; diff --git a/firmware/lib/cgptlib/include/cgptlib.h b/firmware/lib/cgptlib/include/cgptlib.h index 6561ccb5..b49930f5 100644 --- a/firmware/lib/cgptlib/include/cgptlib.h +++ b/firmware/lib/cgptlib/include/cgptlib.h @@ -22,4 +22,26 @@ * GPT_ERROR_NO_VALID_KERNEL, no avaliable kernel, enters recovery mode */ int GptNextKernelEntry(GptData *gpt, uint64_t *start_sector, uint64_t *size); +/** + * Find init_boot partition for selected slot. + * Must be called after GptNextKernelEntry. + * + * On return the start_sector parameter contains the LBA sector for the start + * of the init_boot partition, and the size parameter contains the size of the + * init_boot partition in LBA sectors. + * Returns GPT_SUCCESS if successful. + */ +int GptFindInitBoot(GptData *gpt, uint64_t *start_sector, uint64_t *size); + +/** + * Find vendor_boot partition for selected slot. + * Must be called after GptNextKernelEntry. + * + * On return the start_sector parameter contains the LBA sector for the start + * of the init_boot partition, and the size parameter contains the size of the + * init_boot partition in LBA sectors. + * Returns GPT_SUCCESS if successful. + */ +int GptFindVendorBoot(GptData *gpt, uint64_t *start_sector, uint64_t *size); + #endif /* VBOOT_REFERENCE_CGPTLIB_H_ */ diff --git a/firmware/lib/cgptlib/include/cgptlib_internal.h b/firmware/lib/cgptlib/include/cgptlib_internal.h index 32f7347b..6fa9dd03 100644 --- a/firmware/lib/cgptlib/include/cgptlib_internal.h +++ b/firmware/lib/cgptlib/include/cgptlib_internal.h @@ -159,6 +159,11 @@ void GptModified(GptData *gpt); */ int IsKernelEntry(const GptEntry *e); +/** + * Return true if the entry is a Android OS boot partition, else false. + */ +bool IsAndroidBootPartition(const GptEntry *e, const char *suffix); + /** * Copy the current kernel partition's UniquePartitionGuid to the dest. */ diff --git a/tests/vb2_inject_kernel_subkey_tests.c b/tests/vb2_inject_kernel_subkey_tests.c index ba2eafa4..c975dc26 100644 --- a/tests/vb2_inject_kernel_subkey_tests.c +++ b/tests/vb2_inject_kernel_subkey_tests.c @@ -158,6 +158,16 @@ void GetCurrentKernelUniqueGuid(GptData *gpt, void *dest) memcpy(dest, fake_guid, sizeof(fake_guid)); } +int GptFindInitBoot(GptData *gpt, uint64_t *start_sector, uint64_t *size) +{ + return GPT_SUCCESS; +} + +int GptFindVendorBoot(GptData *gpt, uint64_t *start_sector, uint64_t *size) +{ + return GPT_SUCCESS; +} + vb2_error_t vb2_unpack_key_buffer(struct vb2_public_key *key, const uint8_t *buf, uint32_t size) { diff --git a/tests/vb2_load_kernel_tests.c b/tests/vb2_load_kernel_tests.c index ea796a3c..f755c269 100644 --- a/tests/vb2_load_kernel_tests.c +++ b/tests/vb2_load_kernel_tests.c @@ -204,6 +204,16 @@ int WriteAndFreeGptData(vb2ex_disk_handle_t disk_handle, GptData *gptdata) return GPT_SUCCESS; } +int GptFindInitBoot(GptData *gpt, uint64_t *start_sector, uint64_t *size) +{ + return GPT_SUCCESS; +} + +int GptFindVendorBoot(GptData *gpt, uint64_t *start_sector, uint64_t *size) +{ + return GPT_SUCCESS; +} + void GetCurrentKernelUniqueGuid(GptData *gpt, void *dest) { static char fake_guid[] = "FakeGuid"; From ee076e05a093484e528f9225e69d202d2238e618 Mon Sep 17 00:00:00 2001 From: Konrad Adamczyk Date: Wed, 23 Aug 2023 14:29:39 +0000 Subject: [PATCH 005/102] 2lib: Define android GKI image type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BUG=none TEST=With consecutive CLs applied build FW and boot android BRANCH=main Change-Id: Ifd859e3090f6e4793188cc74fc61efdd470ebdaa Signed-off-by: Konrad Adamczyk Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5716702 Reviewed-by: Jakub Czapiga Commit-Queue: Grzegorz Bernacki Reviewed-by: Jan Dąbroś Tested-by: Grzegorz Bernacki --- firmware/2lib/include/2api.h | 8 ++++++++ firmware/2lib/include/2struct.h | 16 +++------------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/firmware/2lib/include/2api.h b/firmware/2lib/include/2api.h index 945d823a..945d65b4 100644 --- a/firmware/2lib/include/2api.h +++ b/firmware/2lib/include/2api.h @@ -32,6 +32,14 @@ #include "2rsa.h" #include "2secdata_struct.h" +/* Kernel image type */ +#define VB2_KERNEL_TYPE_MASK 0x00000003 +#define VB2_KERNEL_TYPE_CROS 0 +#define VB2_KERNEL_TYPE_BOOTIMG 1 +#define VB2_KERNEL_TYPE_MULTIBOOT 2 +#define VB2_KERNEL_TYPE_ANDROID_GKI 3 + + #define _VB2_TRY_IMPL(expr, ctx, recovery_reason, ...) do { \ vb2_error_t _vb2_try_rv = (expr); \ struct vb2_context *_vb2_try_ctx = (ctx); \ diff --git a/firmware/2lib/include/2struct.h b/firmware/2lib/include/2struct.h index ac9ad4ca..9c2760d0 100644 --- a/firmware/2lib/include/2struct.h +++ b/firmware/2lib/include/2struct.h @@ -509,14 +509,6 @@ _Static_assert(EXPECTED_VB2_FW_PREAMBLE_SIZE == sizeof(struct vb2_fw_preamble), #define VB2_KERNEL_PREAMBLE_HEADER_VERSION_MAJOR 2 #define VB2_KERNEL_PREAMBLE_HEADER_VERSION_MINOR 2 -/* Flags for vb2_kernel_preamble.flags */ -/* Kernel image type = bits 1:0 */ -#define VB2_KERNEL_PREAMBLE_KERNEL_TYPE_MASK 0x00000003 -#define VB2_KERNEL_PREAMBLE_KERNEL_TYPE_CROS 0 -#define VB2_KERNEL_PREAMBLE_KERNEL_TYPE_BOOTIMG 1 -#define VB2_KERNEL_PREAMBLE_KERNEL_TYPE_MULTIBOOT 2 -/* Kernel type 3 is reserved for future use */ - /* * Preamble block for kernel, version 2.2 * @@ -592,12 +584,10 @@ struct vb2_kernel_preamble { */ /* - * Flags; see VB2_KERNEL_PREAMBLE_*. Readers should return 0 for - * header version < 2.2. Flags field is currently defined as: + * Flags. Readers should return 0 for header version < 2.2. + * Flags field is currently defined as: * [31:2] - Reserved (for future use) - * [1:0] - Kernel image type (0b00 - CrOS, - * 0b01 - bootimg, - * 0b10 - multiboot) + * [1:0] - Kernel image type; see VB2_KERNEL_TYPE_*. */ uint32_t flags; } __attribute__((packed)); From 0a691808c4e78de152c9072d36ec3cb006ec09cf Mon Sep 17 00:00:00 2001 From: Konrad Adamczyk Date: Tue, 7 Nov 2023 07:24:47 +0000 Subject: [PATCH 006/102] 2lib: Expand vb2_kernel_params for GKI purposes Introduce four new parameters to vb2_kernel_params API: 1. vendor_boot_offset 2. init_boot_offset 3. init_boot_size 4. vboot_cmdline_offset First two parameters are offsets in the kernel_buffer to the loaded {vendor/init}_boot partitions, respectively. Regarding items 3 and 4 - with enabling AVB in vboot it may be necessary to convey cmdline updates to the bootloader. Put this data in kernel buffer and add a field with offset of this region to the struct. Furthermore, add init_boot_size which will be used later on for verification if regions don't overlap in memory layout. BUG=none TEST=With consecutive CLs applied build FW and boot android BRANCH=main Change-Id: Ifd363db67a7d93cf0399799235fa6b7b9dd13673 Signed-off-by: Konrad Adamczyk Signed-off-by: Jan Dabros Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5716703 Commit-Queue: Grzegorz Bernacki Reviewed-by: Jakub Czapiga Tested-by: Grzegorz Bernacki --- firmware/2lib/include/2api.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/firmware/2lib/include/2api.h b/firmware/2lib/include/2api.h index 945d65b4..278a22e7 100644 --- a/firmware/2lib/include/2api.h +++ b/firmware/2lib/include/2api.h @@ -623,6 +623,14 @@ struct vb2_kernel_params { uint8_t partition_guid[16]; /* Flags set by signer. */ uint32_t flags; + /* Android vendor_boot partition offset (in bytes) in kernel_buffer. */ + uint32_t vendor_boot_offset; + /* Android init_boot partition offset (in bytes) in kernel_buffer. */ + uint32_t init_boot_offset; + /* Size of init boot partition in bytes. */ + uint32_t init_boot_size; + /* Offset (in bytes) to the region with vboot cmdline parameters. */ + uint32_t vboot_cmdline_offset; }; /*****************************************************************************/ From cdd425eb5f219e7659018f434d17058422d1e853 Mon Sep 17 00:00:00 2001 From: Grzegorz Bernacki Date: Tue, 16 Jul 2024 11:28:20 +0000 Subject: [PATCH 007/102] android: Port image headers definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This file was ported from: Repo: https://android.googlesource.com/platform/system/tools/mkbootimg File: include/bootimg/bootimg.h as of commit 2fe7d1583e874b45eb678d10e1450a6e70ff4cb4 Following changes were introduced to this file: - Removed C++ syntax, to be able to compile it successfully - Removed header definitions for versions < 4 (which we don't plan to support). BUG=None TEST=`emerge-brya/corsola depthcharge chromeos-bootimage` BRANCH=main Change-Id: I654f0fbd0f0b66079ce822b57eccca66b0b96ffa Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5716704 Tested-by: Grzegorz Bernacki Commit-Queue: Grzegorz Bernacki Reviewed-by: Jan Dąbroś Reviewed-by: Jakub Czapiga --- firmware/avb/android_image_hdr.h | 190 +++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 firmware/avb/android_image_hdr.h diff --git a/firmware/avb/android_image_hdr.h b/firmware/avb/android_image_hdr.h new file mode 100644 index 00000000..64e1cece --- /dev/null +++ b/firmware/avb/android_image_hdr.h @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * This is from the Android Project, + * Repository: https://android.googlesource.com/platform/system/tools/mkbootimg + * File: include/bootimg/bootimg.h + * Commit: 2fe7d1583e874b45eb678d10e1450a6e70ff4cb4 + * + * Copyright (C) 2007 The Android Open Source Project + */ + +#ifndef ANDROID_IMAGE_HDR +#define ANDROID_IMAGE_HDR + +#include + +#define BOOT_MAGIC "ANDROID!" +#define BOOT_MAGIC_SIZE 8 +#define BOOT_NAME_SIZE 16 +#define BOOT_ARGS_SIZE 512 +#define BOOT_EXTRA_ARGS_SIZE 1024 + +#define VENDOR_BOOT_MAGIC "VNDRBOOT" +#define VENDOR_BOOT_MAGIC_SIZE 8 +#define VENDOR_BOOT_ARGS_SIZE 2048 +#define VENDOR_BOOT_NAME_SIZE 16 + +#define VENDOR_RAMDISK_TYPE_NONE 0 +#define VENDOR_RAMDISK_TYPE_PLATFORM 1 +#define VENDOR_RAMDISK_TYPE_RECOVERY 2 +#define VENDOR_RAMDISK_TYPE_DLKM 3 +#define VENDOR_RAMDISK_NAME_SIZE 32 +#define VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE 16 + +/* When the boot image header has a version of 4, the structure of the boot + * image is as follows: + * + * +---------------------+ + * | boot header | 4096 bytes + * +---------------------+ + * | kernel | m pages + * +---------------------+ + * | ramdisk | n pages + * +---------------------+ + * | boot signature | g pages + * +---------------------+ + * + * m = (kernel_size + 4096 - 1) / 4096 + * n = (ramdisk_size + 4096 - 1) / 4096 + * g = (signature_size + 4096 - 1) / 4096 + * + * Note that in version 4 of the boot image header, page size is fixed at 4096 + * bytes. + * + * The structure of the vendor boot image version 4, which is required to be + * present when a version 4 boot image is used, is as follows: + * + * +------------------------+ + * | vendor boot header | o pages + * +------------------------+ + * | vendor ramdisk section | p pages + * +------------------------+ + * | dtb | q pages + * +------------------------+ + * | vendor ramdisk table | r pages + * +------------------------+ + * | bootconfig | s pages + * +------------------------+ + * + * o = (2128 + page_size - 1) / page_size + * p = (vendor_ramdisk_size + page_size - 1) / page_size + * q = (dtb_size + page_size - 1) / page_size + * r = (vendor_ramdisk_table_size + page_size - 1) / page_size + * s = (vendor_bootconfig_size + page_size - 1) / page_size + * + * Note that in version 4 of the vendor boot image, multiple vendor ramdisks can + * be included in the vendor boot image. The bootloader can select a subset of + * ramdisks to load at runtime. To help the bootloader select the ramdisks, each + * ramdisk is tagged with a type tag and a set of hardware identifiers + * describing the board, soc or platform that this ramdisk is intended for. + * + * The vendor ramdisk section is consist of multiple ramdisk images concatenated + * one after another, and vendor_ramdisk_size is the size of the section, which + * is the total size of all the ramdisks included in the vendor boot image. + * + * The vendor ramdisk table holds the size, offset, type, name and hardware + * identifiers of each ramdisk. The type field denotes the type of its content. + * The vendor ramdisk names are unique. The hardware identifiers are specified + * in the board_id field in each table entry. The board_id field is consist of a + * vector of unsigned integer words, and the encoding scheme is defined by the + * hardware vendor. + * + * For the different type of ramdisks, there are: + * - VENDOR_RAMDISK_TYPE_NONE indicates the value is unspecified. + * - VENDOR_RAMDISK_TYPE_PLATFORM ramdisks contain platform specific bits, so + * the bootloader should always load these into memory. + * - VENDOR_RAMDISK_TYPE_RECOVERY ramdisks contain recovery resources, so + * the bootloader should load these when booting into recovery. + * - VENDOR_RAMDISK_TYPE_DLKM ramdisks contain dynamic loadable kernel + * modules. + * + * Version 4 of the vendor boot image also adds a bootconfig section to the end + * of the image. This section contains Boot Configuration parameters known at + * build time. The bootloader is responsible for placing this section directly + * after the generic ramdisk, followed by the bootconfig trailer, before + * entering the kernel. + * + * 0. all entities in the boot image are 4096-byte aligned in flash, all + * entities in the vendor boot image are page_size (determined by the vendor + * and specified in the vendor boot image header) aligned in flash + * 1. kernel, ramdisk, and DTB are required (size != 0) + * 2. load the kernel and DTB at the specified physical address (kernel_addr, + * dtb_addr) + * 3. load the vendor ramdisks at ramdisk_addr + * 4. load the generic ramdisk immediately following the vendor ramdisk in + * memory + * 5. load the bootconfig immediately following the generic ramdisk. Add + * additional bootconfig parameters followed by the bootconfig trailer. + * 6. set up registers for kernel entry as required by your architecture + * 7. if the platform has a second stage bootloader jump to it (must be + * contained outside boot and vendor boot partitions), otherwise + * jump to kernel_addr + */ +struct boot_img_hdr_v4 { + // Must be BOOT_MAGIC. + uint8_t magic[BOOT_MAGIC_SIZE]; + + uint32_t kernel_size; /* size in bytes */ + uint32_t ramdisk_size; /* size in bytes */ + + // Operating system version and security patch level. + // For version "A.B.C" and patch level "Y-M-D": + // (7 bits for each of A, B, C; 7 bits for (Y-2000), 4 bits for M) + // os_version = A[31:25] B[24:18] C[17:11] (Y-2000)[10:4] M[3:0] + uint32_t os_version; + + uint32_t header_size; + + uint32_t reserved[4]; + + // Version of the boot image header. + uint32_t header_version; + + // Asciiz kernel commandline. + uint8_t cmdline[BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE]; + uint32_t signature_size; /* size in bytes */ +} __attribute__((packed)); + +struct vendor_boot_img_hdr_v4 { + // Must be VENDOR_BOOT_MAGIC. + uint8_t magic[VENDOR_BOOT_MAGIC_SIZE]; + + // Version of the vendor boot image header. + uint32_t header_version; + + uint32_t page_size; /* flash page size we assume */ + + uint32_t kernel_addr; /* physical load addr */ + uint32_t ramdisk_addr; /* physical load addr */ + + uint32_t vendor_ramdisk_size; /* size in bytes */ + + uint8_t cmdline[VENDOR_BOOT_ARGS_SIZE]; /* asciiz kernel commandline */ + + uint32_t tags_addr; /* physical addr for kernel tags (if required) */ + uint8_t name[VENDOR_BOOT_NAME_SIZE]; /* asciiz product name */ + + uint32_t header_size; + + uint32_t dtb_size; /* size in bytes for DTB image */ + uint64_t dtb_addr; /* physical load address for DTB image */ + + uint32_t vendor_ramdisk_table_size; /* size in bytes for the vendor ramdisk table */ + uint32_t vendor_ramdisk_table_entry_num; /* number of entries in the vendor ramdisk table */ + uint32_t vendor_ramdisk_table_entry_size; /* size in bytes for a vendor ramdisk table entry */ + uint32_t bootconfig_size; /* size in bytes for the bootconfig section */ +} __attribute__((packed)); + +struct vendor_ramdisk_table_entry_v4 { + uint32_t ramdisk_size; /* size in bytes for the ramdisk image */ + uint32_t ramdisk_offset; /* offset to the ramdisk image in vendor ramdisk section */ + uint32_t ramdisk_type; /* type of the ramdisk */ + uint8_t ramdisk_name[VENDOR_RAMDISK_NAME_SIZE]; /* asciiz ramdisk name */ + + // Hardware identifiers describing the board, soc or platform which this + // ramdisk is intended to be loaded on. + uint32_t board_id[VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE]; +} __attribute__((packed)); + +#endif /* ANDROID_IMAGE_HDR */ From 2f18d5a2fc9c986e9f273ab04385b270d91abeaa Mon Sep 17 00:00:00 2001 From: Jan Dabros Date: Wed, 24 Jan 2024 14:38:33 +0000 Subject: [PATCH 008/102] avb: Implement basic AVB callbacks Formulate base for enablement of AVB build within vboot. Implement basic callbacks which allows platforms to alter generic libavb behavior. These will be further improved in consecutive commits. Because libavb is using Android.bp format instead of Makefiles, need to add a Makefile for building AVB library from vboot build system. This gives us another benefit which is simplicity in adding our quirks/modifications to the way how we want to build libavb. BUG=b:309426555 TEST=With consecutive CLs applied build FW and boot android. BRANCH=main Cq-Depend: chromium:5716732 Change-Id: I9fb2333dcdf97ac14e8e44493992e0fe788fb192 Signed-off-by: Jan Dabros Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5716705 Tested-by: Grzegorz Bernacki Reviewed-by: Jakub Czapiga Commit-Queue: Grzegorz Bernacki --- firmware/avb/Makefile | 50 +++++++++++++ firmware/avb/vboot_avb_ops.c | 118 +++++++++++++++++++++++++++++++ firmware/avb/vboot_avb_ops.h | 27 +++++++ firmware/avb/vboot_avb_sysdeps.c | 70 ++++++++++++++++++ 4 files changed, 265 insertions(+) create mode 100644 firmware/avb/Makefile create mode 100644 firmware/avb/vboot_avb_ops.c create mode 100644 firmware/avb/vboot_avb_ops.h create mode 100644 firmware/avb/vboot_avb_sysdeps.c diff --git a/firmware/avb/Makefile b/firmware/avb/Makefile new file mode 100644 index 00000000..d2ec1d92 --- /dev/null +++ b/firmware/avb/Makefile @@ -0,0 +1,50 @@ +# Copyright 2024 The ChromiumOS Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +# +# Simple Makefile to integrate libavb build with vboot build system + + +# Add file with callbacks implementation +FWLIB_SRCS += \ + firmware/avb/vboot_avb_ops.c \ + firmware/avb/vboot_avb_sysdeps.c + +# Compile necessary libavb srcs +LIBAVB_SRCS += \ + ${LIBAVB_SRCDIR}/libavb/avb_chain_partition_descriptor.c \ + ${LIBAVB_SRCDIR}/libavb/avb_cmdline.c \ + ${LIBAVB_SRCDIR}/libavb/avb_crc32.c \ + ${LIBAVB_SRCDIR}/libavb/avb_crypto.c \ + ${LIBAVB_SRCDIR}/libavb/avb_descriptor.c \ + ${LIBAVB_SRCDIR}/libavb/avb_footer.c \ + ${LIBAVB_SRCDIR}/libavb/avb_hash_descriptor.c \ + ${LIBAVB_SRCDIR}/libavb/avb_hashtree_descriptor.c \ + ${LIBAVB_SRCDIR}/libavb/avb_kernel_cmdline_descriptor.c \ + ${LIBAVB_SRCDIR}/libavb/avb_property_descriptor.c \ + ${LIBAVB_SRCDIR}/libavb/avb_rsa.c \ + ${LIBAVB_SRCDIR}/libavb/avb_slot_verify.c \ + ${LIBAVB_SRCDIR}/libavb/avb_util.c \ + ${LIBAVB_SRCDIR}/libavb/avb_vbmeta_image.c \ + ${LIBAVB_SRCDIR}/libavb/avb_version.c \ + ${LIBAVB_SRCDIR}/libavb/sha/sha256_impl.c \ + ${LIBAVB_SRCDIR}/libavb/sha/sha512_impl.c + +CFLAGS += -DUSE_LIBAVB -Ifirmware/avb -I${LIBAVB_SRCDIR} -I${LIBAVB_SRCDIR}/libavb +AVB_CFLAGS += -DAVB_COMPILATION -I${LIBAVB_SRCDIR}/libavb/sha + +# TODO(b/329135129): Fix maybe uninitialized variables in upstream libavb +AVB_CFLAGS += -Wno-maybe-uninitialized + +# TODO(b/329411445): Fix func declaration without a prototype in upstream libavb +AVB_CFLAGS += -Wno-strict-prototypes + +# Add avb-related objects to the fwlib library +LIBAVB_OBJS = ${LIBAVB_SRCS:${LIBAVB_SRCDIR}/libavb/%.c=${BUILD}/libavb/%.o} +FWLIB_OBJS += ${LIBAVB_OBJS} + +# Catch all avb-related objects and append extra cflags +${BUILD}/libavb/%.o: $(addprefix ${LIBAVB_SRCDIR}/libavb/,%.c) + @${PRINTF} " CC $(subst ${BUILD}/,,$@)\n" + ${Q}mkdir -p $(dir $@) + ${Q}${CC} ${CFLAGS} ${AVB_CFLAGS} ${INCLUDES} -c -o $@ $< diff --git a/firmware/avb/vboot_avb_ops.c b/firmware/avb/vboot_avb_ops.c new file mode 100644 index 00000000..83e38a2c --- /dev/null +++ b/firmware/avb/vboot_avb_ops.c @@ -0,0 +1,118 @@ +/* Copyright 2024 The ChromiumOS Authors + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Implementation of callbacks needed by libavb library +*/ + +#include + +#include "2common.h" +#include "2nvstorage.h" +#include "2secdata.h" +#include "vboot_avb_ops.h" +#include "cgptlib.h" +#include "cgptlib_internal.h" + +struct vboot_avb_data { + struct vb2_context *vb2_ctx; +}; + +void vboot_avb_ops_free(AvbOps *ops) +{ + if (ops == NULL) + return; + + avb_free(ops->user_data); + avb_free(ops); +} + +static AvbIOResult vboot_avb_read_is_device_unlocked(AvbOps *ops, bool *out_is_unlocked) +{ + struct vboot_avb_data *ctx = (struct vboot_avb_data *)ops->user_data; + + *out_is_unlocked = false; + + int dev_mode = ctx->vb2_ctx->flags & VB2_CONTEXT_DEVELOPER_MODE; + + /* FWMP can require developer mode to use signed images */ + int fwmp_locked = vb2_secdata_fwmp_get_flag( + ctx->vb2_ctx, VB2_SECDATA_FWMP_DEV_ENABLE_OFFICIAL_ONLY); + + /* Developers may require signed images */ + int nv_dev_locked = vb2_nv_get(ctx->vb2_ctx, VB2_NV_DEV_BOOT_SIGNED_ONLY); + + /* + * If developer mode is enabled and signed image is not required, + * then unlocked is TRUE + */ + if (dev_mode && !fwmp_locked && !nv_dev_locked) + *out_is_unlocked = true; + + return AVB_IO_RESULT_OK; +} + +static AvbIOResult vboot_avb_read_rollback_index(AvbOps *ops, + size_t rollback_index_slot, + uint64_t *out_rollback_index) { + /* + * TODO(b/324230492): Implement rollback protection + * For now we always return 0 as the stored rollback index. + */ + avb_debug("TODO: implement read_rollback_index().\n"); + if (out_rollback_index != NULL) + *out_rollback_index = 0; + + return AVB_IO_RESULT_OK; +} + +static AvbIOResult get_unique_guid_for_partition(AvbOps *ops, + const char *partition, + char *guid_buf, + size_t guid_buf_size) +{ + /* TODO(b/324233168): Implement getter for vbmeta partition GUID */ + /* + * Use test UUID from android codebase as a placeholder for now. As it + * is informational only, there is no harm. Leaving it empty may cause + * issues with cmdline properties formatting. + */ + char tmp[] = "aa08f1a4-c7c9-402e-9a66-9707cafa9ceb"; + memcpy(guid_buf, &tmp, sizeof(tmp)); + avb_debug("TODO: function not implemented yet\n"); + return AVB_IO_RESULT_OK; +} + +/* + * Initialize platform callbacks used within libavb. + * + * @param vb2_ctx Vboot context + * @return pointer to AvbOps structure which should be used for invocation of + * libavb methods. This should be freed using vboot_avb_ops_free(). + * NULL in case of error. + */ +AvbOps *vboot_avb_ops_new(struct vb2_context *vb2_ctx) +{ + struct vboot_avb_data *data; + AvbOps *ops; + + ops = avb_calloc(sizeof(AvbOps)); + if (ops == NULL) + return NULL; + + data = avb_calloc(sizeof(struct vboot_avb_data)); + if (data == NULL) { + avb_free(ops); + return NULL; + } + + ops->user_data = data; + + data->vb2_ctx = vb2_ctx; + + ops->read_is_device_unlocked = vboot_avb_read_is_device_unlocked; + ops->read_rollback_index = vboot_avb_read_rollback_index; + ops->get_unique_guid_for_partition = get_unique_guid_for_partition; + + return ops; +} diff --git a/firmware/avb/vboot_avb_ops.h b/firmware/avb/vboot_avb_ops.h new file mode 100644 index 00000000..7865d20b --- /dev/null +++ b/firmware/avb/vboot_avb_ops.h @@ -0,0 +1,27 @@ +/* Copyright 2024 The ChromiumOS Authors + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef VBOOT_AVB_OPS_H_ +#define VBOOT_AVB_OPS_H_ + +#include "2common.h" +#include "gpt_misc.h" +#include "vboot_api.h" + +#include + +/* + * Initialize platform callbacks used within libavb. + * + * @param vb2_ctx Vboot context + * @return pointer to AvbOps structure which should be used for invocation of + * libavb methods. This should be freed using vboot_avb_ops_free(). + * NULL in case of error. + */ +AvbOps *vboot_avb_ops_new(struct vb2_context *vb2_ctx); + +void vboot_avb_ops_free(AvbOps *ops); + +#endif // VBOOT_AVB_OPS_H_ diff --git a/firmware/avb/vboot_avb_sysdeps.c b/firmware/avb/vboot_avb_sysdeps.c new file mode 100644 index 00000000..12ce6887 --- /dev/null +++ b/firmware/avb/vboot_avb_sysdeps.c @@ -0,0 +1,70 @@ +/* Copyright 2024 The ChromiumOS Authors + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Implementation of system dependencies required by libavb +*/ + +#include + +#include "2common.h" +#include "stdarg.h" +#include "stdlib.h" +#include "string.h" + +int avb_memcmp(const void *src1, const void *src2, size_t n) { + return memcmp(src1, src2, n); +} + +void *avb_memcpy(void *dest, const void *src, size_t n) { + return memcpy(dest, src, n); +} + +void *avb_memset(void *dest, const int c, size_t n) { + return memset(dest, c, n); +} + +int avb_strcmp(const char *s1, const char *s2) { + return strcmp(s1, s2); +} + +int avb_strncmp(const char *s1, const char *s2, size_t n) { + return strncmp(s1, s2, n); +} + +size_t avb_strlen(const char *str) { + return strlen(str); +} + +void avb_abort(void) { + abort(); +} + +void avb_print(const char *message) { + vb2ex_printf(NULL, message); +} + +void avb_printv(const char *message, ...) { + va_list ap; + const char *m; + + va_start(ap, message); + for (m = message; m != NULL; m = va_arg(ap, const char*)) + vb2ex_printf(NULL, m); + + va_end(ap); +} + +void *avb_malloc_(size_t size) { + return malloc(size); +} + +void avb_free(void *ptr) { + free(ptr); +} + +uint32_t avb_div_by_10(uint64_t *dividend) { + uint32_t rem = (uint32_t)(*dividend % 10); + *dividend /= 10; + return rem; +} From 63c06705a046da6a4a6fa7b06969cda1a01fcc16 Mon Sep 17 00:00:00 2001 From: Jan Dabros Date: Sun, 28 Jan 2024 23:52:12 +0000 Subject: [PATCH 009/102] avb: Add avb_ops for IO operations Implement callbacks for reading partitions size and content. For read operation with offset value below 0, it means the offset from the end of the partitions, thus needs to do correct operations in the driver. BUG=b:309426555 TEST=With consecutive CLs applied build FW and boot android BRANCH=main Change-Id: If8e1b31131cd17af4e252d0171e5700efc15aa16 Signed-off-by: Jan Dabros Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5716706 Commit-Queue: Grzegorz Bernacki Tested-by: Grzegorz Bernacki Reviewed-by: Jakub Czapiga --- firmware/avb/vboot_avb_ops.c | 119 ++++++++++++++++++++++++++++++++++- firmware/avb/vboot_avb_ops.h | 10 ++- 2 files changed, 127 insertions(+), 2 deletions(-) diff --git a/firmware/avb/vboot_avb_ops.c b/firmware/avb/vboot_avb_ops.c index 83e38a2c..1ff00eab 100644 --- a/firmware/avb/vboot_avb_ops.c +++ b/firmware/avb/vboot_avb_ops.c @@ -15,6 +15,10 @@ #include "cgptlib_internal.h" struct vboot_avb_data { + struct vb2_kernel_params *params; + GptData *gpt; + VbExStream_t stream; /* Stream opened for kernel partition read */ + vb2ex_disk_handle_t disk_handle; struct vb2_context *vb2_ctx; }; @@ -27,6 +31,105 @@ void vboot_avb_ops_free(AvbOps *ops) avb_free(ops); } +static AvbIOResult vboot_avb_read_from_partition(AvbOps *ops, + const char *partition_name, + int64_t offset_from_partition, + size_t num_bytes, + void *buf, + size_t *out_num_read) +{ + struct vboot_avb_data *ctx = (struct vboot_avb_data *)ops->user_data; + VbExStream_t stream; + uint64_t part_start, part_size; + uint64_t start_sector, sectors_to_read, pre_misalign; + uint8_t *tmp_buf; + + if (GptFindOffsetByName(ctx->gpt, partition_name, &part_start, &part_size) != + GPT_SUCCESS) { + VB2_DEBUG("Unable to find %s partition\n", partition_name); + return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; + } + + if (offset_from_partition >= 0) { + start_sector = (offset_from_partition / ctx->gpt->sector_bytes) + part_start; + pre_misalign = offset_from_partition % ctx->gpt->sector_bytes; + } else { + if (-offset_from_partition > part_size * ctx->gpt->sector_bytes) + return AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION; + + start_sector = part_start + + (part_size * ctx->gpt->sector_bytes + offset_from_partition) / + ctx->gpt->sector_bytes; + pre_misalign = ctx->gpt->sector_bytes - + (-offset_from_partition % ctx->gpt->sector_bytes); + if (pre_misalign == ctx->gpt->sector_bytes) + pre_misalign = 0; + } + + sectors_to_read = (pre_misalign + num_bytes) / ctx->gpt->sector_bytes; + if ((pre_misalign + num_bytes) % ctx->gpt->sector_bytes) + sectors_to_read += 1; + + if (sectors_to_read > part_size) { + VB2_DEBUG("Read request bigger than available data\n"); + return AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION; + } + + if (VbExStreamOpen(ctx->disk_handle, start_sector, sectors_to_read, + &stream)) { + VB2_DEBUG("Unable to open disk handle.\n"); + return AVB_IO_RESULT_ERROR_IO; + } + + if (pre_misalign != 0 || (num_bytes % ctx->gpt->sector_bytes)) { + tmp_buf = malloc(sectors_to_read * ctx->gpt->sector_bytes); + if (tmp_buf == NULL) { + VB2_DEBUG("Cannot allocate buffer for unaligned read\n"); + return AVB_IO_RESULT_ERROR_OOM; + } + } else { + tmp_buf = buf; + } + + if (VbExStreamRead(stream, sectors_to_read * ctx->gpt->sector_bytes, tmp_buf)) { + VB2_DEBUG("Unable to read ramdisk partition\n"); + return AVB_IO_RESULT_ERROR_IO; + } + + /* + * TODO(b/331881159): "Add support for non-sector size reads in + * depthcharge block driver + */ + if (pre_misalign != 0 || (num_bytes % ctx->gpt->sector_bytes)) { + memcpy(buf, tmp_buf + pre_misalign, num_bytes); + free(tmp_buf); + } + *out_num_read = num_bytes; + + VbExStreamClose(stream); + + return AVB_IO_RESULT_OK; +} + + +static AvbIOResult vboot_avb_get_size_of_partition(AvbOps *ops, + const char *partition_name, + uint64_t *out_size) +{ + struct vboot_avb_data *ctx = (struct vboot_avb_data *)ops->user_data; + uint64_t part_start, part_size; + + if (GptFindOffsetByName(ctx->gpt, partition_name, &part_start, &part_size) != + GPT_SUCCESS) { + VB2_DEBUG("Unable to find %s partition\n", partition_name); + return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; + } + + *out_size = ctx->gpt->sector_bytes * part_size; + + return AVB_IO_RESULT_OK; +} + static AvbIOResult vboot_avb_read_is_device_unlocked(AvbOps *ops, bool *out_is_unlocked) { struct vboot_avb_data *ctx = (struct vboot_avb_data *)ops->user_data; @@ -87,11 +190,19 @@ static AvbIOResult get_unique_guid_for_partition(AvbOps *ops, * Initialize platform callbacks used within libavb. * * @param vb2_ctx Vboot context + * @param params Vboot kernel parameters + * @param stream Open stream to kernel partition + * @param gpt Pointer to gpt struct correlated with boot disk + * @param disk_handle Handle to boot disk * @return pointer to AvbOps structure which should be used for invocation of * libavb methods. This should be freed using vboot_avb_ops_free(). * NULL in case of error. */ -AvbOps *vboot_avb_ops_new(struct vb2_context *vb2_ctx) +AvbOps *vboot_avb_ops_new(struct vb2_context *vb2_ctx, + struct vb2_kernel_params *params, + VbExStream_t stream, + GptData *gpt, + vb2ex_disk_handle_t disk_handle) { struct vboot_avb_data *data; AvbOps *ops; @@ -108,8 +219,14 @@ AvbOps *vboot_avb_ops_new(struct vb2_context *vb2_ctx) ops->user_data = data; + data->gpt = gpt; + data->params = params; + data->stream = stream; data->vb2_ctx = vb2_ctx; + data->disk_handle = disk_handle; + ops->read_from_partition = vboot_avb_read_from_partition; + ops->get_size_of_partition = vboot_avb_get_size_of_partition; ops->read_is_device_unlocked = vboot_avb_read_is_device_unlocked; ops->read_rollback_index = vboot_avb_read_rollback_index; ops->get_unique_guid_for_partition = get_unique_guid_for_partition; diff --git a/firmware/avb/vboot_avb_ops.h b/firmware/avb/vboot_avb_ops.h index 7865d20b..a7282bc9 100644 --- a/firmware/avb/vboot_avb_ops.h +++ b/firmware/avb/vboot_avb_ops.h @@ -16,11 +16,19 @@ * Initialize platform callbacks used within libavb. * * @param vb2_ctx Vboot context + * @param params Vboot kernel parameters + * @param stream Open stream to kernel partition + * @param gpt Pointer to gpt struct correlated with boot disk + * @param disk_handle Handle to boot disk * @return pointer to AvbOps structure which should be used for invocation of * libavb methods. This should be freed using vboot_avb_ops_free(). * NULL in case of error. */ -AvbOps *vboot_avb_ops_new(struct vb2_context *vb2_ctx); +AvbOps *vboot_avb_ops_new(struct vb2_context *vb2_ctx, + struct vb2_kernel_params *params, + VbExStream_t stream, + GptData *gpt, + vb2ex_disk_handle_t disk_handle); void vboot_avb_ops_free(AvbOps *ops); From 083aef74158bf2fe4fa0f981a0ee3c4cdfe4beae Mon Sep 17 00:00:00 2001 From: Jan Dabros Date: Sun, 28 Jan 2024 23:56:56 +0000 Subject: [PATCH 010/102] avb: Add callback for public key verification In order to establish secure link between platform and software it is necessary to embed public part of the signing key within the persistent storage (in our case flash memory). During boot & verification process, this key is compared by AVB library to the one used to sign vbmeta partition. BUG=b:309426555 TEST=With consecutive CLs applied build FW and boot android BRANCH=main Change-Id: I6eab7a9935c634e92aad28f722945fd32335d846 Signed-off-by: Jan Dabros Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5716707 Reviewed-by: Jakub Czapiga Tested-by: Grzegorz Bernacki Commit-Queue: Grzegorz Bernacki --- firmware/avb/vboot_avb_ops.c | 77 ++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/firmware/avb/vboot_avb_ops.c b/firmware/avb/vboot_avb_ops.c index 1ff00eab..8cbfbc7f 100644 --- a/firmware/avb/vboot_avb_ops.c +++ b/firmware/avb/vboot_avb_ops.c @@ -186,6 +186,82 @@ static AvbIOResult get_unique_guid_for_partition(AvbOps *ops, return AVB_IO_RESULT_OK; } +static AvbIOResult validate_vbmeta_public_key(AvbOps *ops, + const uint8_t *public_key_data, + size_t public_key_length, + const uint8_t *public_key_metadata, + size_t public_key_metadata_length, + bool *out_key_is_trusted) +{ + struct vboot_avb_data *ctx = (struct vboot_avb_data *)ops->user_data; + struct vb2_shared_data *sd = vb2_get_sd(ctx->vb2_ctx); + struct vb2_public_key kernel_key; + AvbRSAPublicKeyHeader h; + uint8_t *key_data; + uint32_t key_size; + uint32_t avb_key_len; + const uint8_t *n, *rr; + uint32_t *tmp_buf = NULL; + + if (out_key_is_trusted == NULL) + return AVB_IO_RESULT_ERROR_NO_SUCH_VALUE; + + *out_key_is_trusted = false; + key_data = vb2_member_of(sd, sd->kernel_key_offset); + key_size = sd->kernel_key_size; + vb2_unpack_key_buffer(&kernel_key, key_data, key_size); + + /* + * Convert key format stored in the vbmeta image - it has different + * endianness and size units compared to the kernel_subkey stored in + * flash + */ + if (!avb_rsa_public_key_header_validate_and_byteswap( + (const AvbRSAPublicKeyHeader *)public_key_data, &h)) { + avb_error("Invalid vbmeta pulic key\n"); + goto out; + } + + /* Kernel key length is stored as number of uint32_t */ + avb_key_len = h.key_num_bits / 32; + + if (kernel_key.arrsize != avb_key_len) { + avb_error("Mismatch in key length!\n"); + goto out; + } + + if (kernel_key.n0inv != h.n0inv) { + avb_error("Mismatch in n0inv value!\n"); + goto out; + } + + tmp_buf = malloc(h.key_num_bits / 8); + + n = public_key_data + sizeof(AvbRSAPublicKeyHeader); + for (int i = 0; i < avb_key_len; i++) + tmp_buf[i] = avb_be32toh(((uint32_t *)n)[avb_key_len - 1 - i]); + + if (memcmp(kernel_key.n, tmp_buf, kernel_key.arrsize)) { + avb_error("Mismatch in n key component!\n"); + goto out; + } + + rr = public_key_data + sizeof(AvbRSAPublicKeyHeader) + h.key_num_bits / 8; + for (int i = 0; i < avb_key_len; i++) + tmp_buf[i] = avb_be32toh(((uint32_t *)rr)[avb_key_len - 1 - i]); + + if (memcmp(kernel_key.rr, tmp_buf, kernel_key.arrsize)) { + avb_error("Mismatch in rr key component!\n"); + goto out; + } + + *out_key_is_trusted = true; + +out: + free(tmp_buf); + return AVB_IO_RESULT_OK; +} + /* * Initialize platform callbacks used within libavb. * @@ -230,6 +306,7 @@ AvbOps *vboot_avb_ops_new(struct vb2_context *vb2_ctx, ops->read_is_device_unlocked = vboot_avb_read_is_device_unlocked; ops->read_rollback_index = vboot_avb_read_rollback_index; ops->get_unique_guid_for_partition = get_unique_guid_for_partition; + ops->validate_vbmeta_public_key = validate_vbmeta_public_key; return ops; } From 3d0826add08fecc07a5511b8f5c2fe911ca6183f Mon Sep 17 00:00:00 2001 From: Jan Dabros Date: Mon, 29 Jan 2024 00:00:32 +0000 Subject: [PATCH 011/102] avb: get preloaded partitions In order to speed up boot process and limit number of memcopy it is beneficial to make use of get_preloaded* callback. Instead of IO operations, one just need to provide pointer to the memory block which is already there. In order to store ramdisks content properly in the buffer provided to bootloader, load both vendor_boot and init_boot partition simultanously. BUG=b:309426555 TEST=With consecutive CLs applied build FW and boot android BRANCH=main Change-Id: I49abdf26a8693f5a0dacdc405b4228b41e3d8110 Signed-off-by: Konrad Adamczyk Signed-off-by: Jan Dabros Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5716728 Commit-Queue: Grzegorz Bernacki Tested-by: Grzegorz Bernacki Reviewed-by: Jakub Czapiga --- firmware/avb/vboot_avb_ops.c | 256 +++++++++++++++++++++++++++++++++++ 1 file changed, 256 insertions(+) diff --git a/firmware/avb/vboot_avb_ops.c b/firmware/avb/vboot_avb_ops.c index 8cbfbc7f..b9e1a554 100644 --- a/firmware/avb/vboot_avb_ops.c +++ b/firmware/avb/vboot_avb_ops.c @@ -13,6 +13,7 @@ #include "vboot_avb_ops.h" #include "cgptlib.h" #include "cgptlib_internal.h" +#include "android_image_hdr.h" struct vboot_avb_data { struct vb2_kernel_params *params; @@ -262,6 +263,260 @@ static AvbIOResult validate_vbmeta_public_key(AvbOps *ops, return AVB_IO_RESULT_OK; } +static vb2_error_t vb2_load_ramdisk(GptData *gpt, struct vb2_kernel_params *params, + vb2ex_disk_handle_t disk_handle, + uint64_t *part_start, uint64_t *part_size, + uint32_t *bytes_used) +{ + VbExStream_t stream; + uint32_t read_ms = 0, start_ts; + uint64_t part_bytes; + uint8_t *part_ramdisk_buf; + vb2_error_t res = VB2_ERROR_LOAD_PARTITION_READ_BODY; + + if (VbExStreamOpen(disk_handle, *part_start, *part_size, + &stream)) { + VB2_DEBUG("Unable to open disk handle.\n"); + return res; + } + + part_bytes = gpt->sector_bytes * *part_size; + if (part_bytes > (params->kernel_buffer_size - *bytes_used)) { + VB2_DEBUG("No space left to load ramdisk partition\n"); + goto out; + } + + part_ramdisk_buf = params->kernel_buffer + *bytes_used; + /* Load partition to memory */ + start_ts = vb2ex_mtime(); + if (VbExStreamRead(stream, part_bytes, part_ramdisk_buf)) { + VB2_DEBUG("Unable to read ramdisk partition\n"); + goto out; + } + read_ms += vb2ex_mtime() - start_ts; + + if (read_ms == 0) /* Avoid division by 0 in speed calculation */ + read_ms = 1; + VB2_DEBUG("read %u KB in %u ms at %u KB/s.\n", + (uint32_t)(part_bytes) / 1024, read_ms, + (uint32_t)(((part_bytes) * VB2_MSEC_PER_SEC) / + (read_ms * 1024))); + + *bytes_used += part_bytes; + + res = VB2_SUCCESS; +out: + VbExStreamClose(stream); + return res; +} + +static vb2_error_t vb2_load_vendor_boot_ramdisk(struct vb2_context *ctx, GptData *gpt, + struct vb2_kernel_params *params, + vb2ex_disk_handle_t disk_handle, + uint32_t *bytes_used) +{ + uint64_t part_start, part_size; + + if (GptFindVendorBoot(gpt, &part_start, &part_size) != GPT_SUCCESS) { + VB2_DEBUG("Unable to find vendor_boot partition\n"); + return VB2_ERROR_LOAD_PARTITION_READ_BODY; + } + + params->vendor_boot_offset = *bytes_used; + + if (vb2_load_ramdisk(gpt, params, disk_handle, &part_start, + &part_size, bytes_used)) { + VB2_DEBUG("Unable to load vendor_boot partition\n"); + return VB2_ERROR_LOAD_PARTITION_READ_BODY; + } + + return VB2_SUCCESS; +} + +static vb2_error_t vb2_load_init_boot_ramdisk(struct vb2_context *ctx, GptData *gpt, + struct vb2_kernel_params *params, + vb2ex_disk_handle_t disk_handle, + uint32_t *bytes_used) +{ + uint64_t part_start, part_size; + + if (GptFindInitBoot(gpt, &part_start, &part_size) != GPT_SUCCESS) { + VB2_DEBUG("Unable to find init_boot partition\n"); + return VB2_ERROR_LOAD_PARTITION_READ_BODY; + } + + params->init_boot_offset = *bytes_used; + + if (vb2_load_ramdisk(gpt, params, disk_handle, &part_start, + &part_size, bytes_used)) { + VB2_DEBUG("Unable to load init_boot partition\n"); + return VB2_ERROR_LOAD_PARTITION_READ_BODY; + } + + return VB2_SUCCESS; +} + +static vb2_error_t vb2_load_android_ramdisks(struct vb2_context *ctx, GptData *gpt, + struct vb2_kernel_params *params, + vb2ex_disk_handle_t disk_handle, + uint32_t *bytes_used) +{ + vb2_error_t ret; + + ret = vb2_load_vendor_boot_ramdisk(ctx, gpt, params, disk_handle, bytes_used); + if (ret != VB2_SUCCESS) { + VB2_DEBUG("Unable to read vendor_boot partition\n"); + return ret; + } + + ret = vb2_load_init_boot_ramdisk(ctx, gpt, params, disk_handle, bytes_used); + if (ret != VB2_SUCCESS) { + VB2_DEBUG("Unable to read init_boot partition\n"); + return ret; + } + + /* Update flags to mark loaded GKI image */ + params->flags &= ~VB2_KERNEL_TYPE_MASK; + params->flags |= VB2_KERNEL_TYPE_ANDROID_GKI; + + return VB2_SUCCESS; +} + +static vb2_error_t load_android_kernel(struct vb2_kernel_params *params, + VbExStream_t stream, uint32_t num_bytes) +{ + uint32_t read_ms, start_ts; + uint8_t *kernbuf; + uint32_t kernbuf_size; + struct boot_img_hdr_v4 *hdr; + + kernbuf = params->kernel_buffer; + kernbuf_size = params->kernel_buffer_size; + if (!kernbuf || !kernbuf_size) { + VB2_DEBUG("Caller have not defined kernel_buffer and it's size\n"); + return VB2_ERROR_LOAD_PARTITION_BODY_SIZE; + } + + if (kernbuf_size < num_bytes) { + VB2_DEBUG("Not enough space for kernel\n"); + return VB2_ERROR_LOAD_PARTITION_BODY_SIZE; + } + + /* Read kernel data starting from kernel header till end of partition */ + start_ts = vb2ex_mtime(); + if (VbExStreamRead(stream, num_bytes, kernbuf)) { + VB2_DEBUG("Unable to read kernel data.\n"); + return VB2_ERROR_LOAD_PARTITION_READ_BODY; + } + + read_ms = vb2ex_mtime() - start_ts; + if (read_ms == 0) /* Avoid division by 0 in speed calculation */ + read_ms = 1; + VB2_DEBUG("read %u KB in %u ms at %u KB/s.\n", + (uint32_t)(num_bytes / 1024), read_ms, + (uint32_t)((num_bytes * + VB2_MSEC_PER_SEC) / (read_ms * 1024))); + + /* Validate read partition */ + hdr = (struct boot_img_hdr_v4 *)kernbuf; + if (memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) { + VB2_DEBUG("BOOT_MAGIC mismatch!\n"); + return VB2_ERROR_LK_NO_KERNEL_FOUND; + } + if (hdr->header_version != 4) { + VB2_DEBUG("Unsupported header version %d\n", hdr->header_version); + return VB2_ERROR_LK_NO_KERNEL_FOUND; + } + + return VB2_SUCCESS; +} + +/* + * Do all the heavy lifting here. Instead of using heap (huge + * allocations) lets use the buffer which is intended to have kernel and + * ramdisk images anyway. + * */ +static AvbIOResult vboot_avb_get_preloaded_partition(AvbOps *ops, + const char *partition, + size_t num_bytes, + uint8_t **out_pointer, + size_t *out_num_bytes_preloaded) +{ + + /* Keep this through the invocation of this function to properly lay + * content in memory */ + static uint32_t bytes_used; + static bool ramdisk_preloaded = false; + struct vboot_avb_data *avb_data = (struct vboot_avb_data *)ops->user_data; + char *suffix = NULL; + char *short_partition_name; + int ret; + + /* + * Only load the partitions with suffix matching to the currently + * selected slot. + */ + ret = GptGetActiveKernelPartitionSuffix(avb_data->gpt, &suffix); + if (ret != GPT_SUCCESS) { + VB2_DEBUG("Unable to get kernel partition suffix\n"); + return ret; + } + if (strcmp(&partition[strlen(partition) - strlen(suffix)], suffix)) { + free(suffix); + return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; + } + + /* + * Below we only need to compare partition name without suffix, since + * the suffix is already verified above. + */ + short_partition_name = malloc(strlen(partition) - strlen(suffix) + 1); + memcpy(short_partition_name, partition, strlen(partition) - strlen(suffix)); + short_partition_name[strlen(partition) - strlen(suffix)] = '\0'; + free(suffix); + + *out_pointer = NULL; + if (!strcmp(short_partition_name, "boot")) { + if (load_android_kernel(avb_data->params, avb_data->stream, num_bytes)) { + ret = AVB_IO_RESULT_ERROR_IO; + goto out; + } + bytes_used = num_bytes; + *out_num_bytes_preloaded = num_bytes; + *out_pointer = (uint8_t *)avb_data->params->kernel_buffer; + + ret = AVB_IO_RESULT_OK; + } else if (!strcmp(short_partition_name, "vendor_boot") || + !strcmp(short_partition_name, "init_boot")) { + + if (!ramdisk_preloaded) { + ret = vb2_load_android_ramdisks(avb_data->vb2_ctx, + avb_data->gpt, avb_data->params, + avb_data->disk_handle, &bytes_used); + if (ret) { + ret = AVB_IO_RESULT_ERROR_IO; + goto out; + } + ramdisk_preloaded = true; + } + + *out_num_bytes_preloaded = num_bytes; + if (!strcmp(short_partition_name, "vendor_boot")) + *out_pointer = (uint8_t *)avb_data->params->kernel_buffer + + avb_data->params->vendor_boot_offset; + if (!strcmp(short_partition_name, "init_boot")) + *out_pointer = (uint8_t *)avb_data->params->kernel_buffer + + avb_data->params->init_boot_offset; + + ret = AVB_IO_RESULT_OK; + } + +out: + free(short_partition_name); + return ret; + +} + /* * Initialize platform callbacks used within libavb. * @@ -307,6 +562,7 @@ AvbOps *vboot_avb_ops_new(struct vb2_context *vb2_ctx, ops->read_rollback_index = vboot_avb_read_rollback_index; ops->get_unique_guid_for_partition = get_unique_guid_for_partition; ops->validate_vbmeta_public_key = validate_vbmeta_public_key; + ops->get_preloaded_partition = vboot_avb_get_preloaded_partition; return ops; } From b6532e5feb1b153a1ca22bb4ef1a6152977ba731 Mon Sep 17 00:00:00 2001 From: Konrad Adamczyk Date: Mon, 21 Aug 2023 10:05:15 +0000 Subject: [PATCH 012/102] 2lib: Load and verify android partitions Make use of the libavb library for loading and verification of android images. Verify partitions necessary for booting - "boot", "init_boot" and "vendor_boot". BUG=b:309426555 TEST=Build FW and boot android TEST=Use description from b/309426555#comment3 BRANCH=main Change-Id: I4312986620e671d0e0201b8204bdc66a4abdc072 Signed-off-by: Konrad Adamczyk Signed-off-by: Jan Dabros Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5716729 Reviewed-by: Jakub Czapiga Commit-Queue: Grzegorz Bernacki Tested-by: Grzegorz Bernacki --- Makefile | 8 ++ firmware/2lib/2load_kernel.c | 142 ++++++++++++++++++++++++++++++++--- firmware/avb/vboot_avb_ops.c | 2 + 3 files changed, 143 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 76149d6c..81880eaa 100644 --- a/Makefile +++ b/Makefile @@ -39,6 +39,7 @@ SRCDIR := $(shell pwd) BUILD = ${SRCDIR}/build export BUILD +LIBAVB_SRCDIR ?= firmware/avb/libavb # Stuff for 'make install' INSTALL = install @@ -458,6 +459,13 @@ FWLIB_OBJS = ${FWLIB_SRCS:%.c=${BUILD}/%.o} ${FWLIB_ASMS:%.S=${BUILD}/%.o} TLCL_OBJS = ${TLCL_SRCS:%.c=${BUILD}/%.o} ALL_OBJS += ${FWLIB_OBJS} ${TLCL_OBJS} +# We are adding libavb objs to FWLIB_OBJS thus need to include this file here. +# Since libavb sources are stored in external library, this needs to be moved +# into expected location beforehand. +ifneq (${USE_AVB},) +include firmware/avb/Makefile +endif + # Maintain behaviour of default on. USE_FLASHROM ?= 1 diff --git a/firmware/2lib/2load_kernel.c b/firmware/2lib/2load_kernel.c index 3f6b333b..2771f631 100644 --- a/firmware/2lib/2load_kernel.c +++ b/firmware/2lib/2load_kernel.c @@ -18,12 +18,21 @@ #include "gpt_misc.h" #include "vboot_api.h" +#ifdef USE_LIBAVB +#include "vboot_avb_ops.h" + +/* Size of the buffer to convey cmdline properties to bootloader */ +#define AVB_CMDLINE_BUF_SIZE 1024 +#endif + enum vb2_load_partition_flags { VB2_LOAD_PARTITION_FLAG_VBLOCK_ONLY = (1 << 0), VB2_LOAD_PARTITION_FLAG_MINIOS = (1 << 1), }; #define KBUF_SIZE 65536 /* Bytes to read at start of kernel partition */ +/* Bytes to read at start of the boot/init_boot/vendor_boot partitions */ +#define BOOT_HDR_GKI_SIZE 4096 /* Minimum context work buffer size needed for vb2_load_partition() */ #define VB2_LOAD_PARTITION_WORKBUF_BYTES \ @@ -342,7 +351,7 @@ static vb2_error_t vb2_verify_kernel_vblock(struct vb2_context *ctx, } /** - * Load and verify a partition from the stream. + * Load and verify a ChromeOS kernel partition from the stream. * * @param ctx Vboot context * @param params Load-kernel parameters @@ -351,10 +360,9 @@ static vb2_error_t vb2_verify_kernel_vblock(struct vb2_context *ctx, * @param kernel_version The kernel version of this partition. * @return VB2_SUCCESS, or non-zero error code. */ -static vb2_error_t vb2_load_partition(struct vb2_context *ctx, - struct vb2_kernel_params *params, - VbExStream_t stream, uint32_t lpflags, - uint32_t *kernel_version) +static vb2_error_t vb2_load_chromeos_kernel_partition( + struct vb2_context *ctx, struct vb2_kernel_params *params, + VbExStream_t stream, uint32_t lpflags, uint32_t *kernel_version) { uint32_t read_ms = 0, start_ts; struct vb2_workbuf wb; @@ -467,6 +475,114 @@ static vb2_error_t vb2_load_partition(struct vb2_context *ctx, return VB2_SUCCESS; } +#ifdef USE_LIBAVB +static vb2_error_t vb2_load_avb_android_partition( + struct vb2_context *ctx, struct vb2_kernel_params *params, + VbExStream_t stream, GptData *gpt, vb2ex_disk_handle_t disk_handle) +{ + char *ab_suffix = NULL; + AvbSlotVerifyData *verify_data = NULL; + AvbOps *avb_ops; + static const char * const boot_partitions[] = { + GPT_ENT_NAME_ANDROID_BOOT, + GPT_ENT_NAME_ANDROID_INIT_BOOT, + GPT_ENT_NAME_ANDROID_VENDOR_BOOT, + NULL, + }; + AvbSlotVerifyFlags avb_flags; + AvbSlotVerifyResult result; + vb2_error_t ret; + int need_keyblock_valid = need_valid_keyblock(ctx); + + ret = GptGetActiveKernelPartitionSuffix(gpt, &ab_suffix); + if (ret != GPT_SUCCESS) { + VB2_DEBUG("Unable to get kernel partition suffix\n"); + return VB2_ERROR_LK_NO_KERNEL_FOUND; + } + + avb_ops = vboot_avb_ops_new(ctx, params, stream, gpt, disk_handle); + if (avb_ops == NULL) { + free(ab_suffix); + VB2_DEBUG("Cannot allocate memory for AVB ops\n"); + return VB2_ERROR_LK_NO_KERNEL_FOUND; + } + + avb_flags = AVB_SLOT_VERIFY_FLAGS_NONE; + if (!need_keyblock_valid) + avb_flags |= AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR; + + result = avb_slot_verify(avb_ops, + boot_partitions, + ab_suffix, + avb_flags, + AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, + &verify_data); + vboot_avb_ops_free(avb_ops); + free(ab_suffix); + + /* Ignore verification errors in developer mode */ + if (ctx->flags & VB2_CONTEXT_DEVELOPER_MODE) { + switch (result) { + case AVB_SLOT_VERIFY_RESULT_OK: + case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION: + case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX: + case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED: + ret = AVB_SLOT_VERIFY_RESULT_OK; + break; + default: + ret = VB2_ERROR_LK_NO_KERNEL_FOUND; + } + } else { + ret = result; + } + + /* + * Return from this function early so that caller can try fallback to + * other partition in case of error. + */ + if (ret != AVB_SLOT_VERIFY_RESULT_OK) { + if (verify_data != NULL) + avb_slot_verify_data_free(verify_data); + return ret; + } + + /* + * Use a buffer before the GKI header for copying avb cmdline string for + * bootloader. + */ + params->vboot_cmdline_offset = params->kernel_buffer_size - + BOOT_HDR_GKI_SIZE - AVB_CMDLINE_BUF_SIZE; + + if ((params->init_boot_offset + params->init_boot_size) > + params->vboot_cmdline_offset) + return VB2_ERROR_LOAD_PARTITION_WORKBUF; + + if (strlen(verify_data->cmdline) >= AVB_CMDLINE_BUF_SIZE) + return VB2_ERROR_LOAD_PARTITION_WORKBUF; + + strcpy((char *)(params->kernel_buffer + params->vboot_cmdline_offset), + verify_data->cmdline); + + /* No need for slot data, partitions should be already at correct + * locations in memory since we are using "get_preloaded_partitions" + * callbacks. + */ + avb_slot_verify_data_free(verify_data); + + /* + * Bootloader expects kernel image at the very beginning of + * kernel_buffer, but verification requires boot header before + * kernel. Since the verification is done, we need to move kernel + * at proper address. + */ + memmove((uint8_t *)params->kernel_buffer, + (uint8_t *)params->kernel_buffer + BOOT_HDR_GKI_SIZE, + params->vendor_boot_offset - BOOT_HDR_GKI_SIZE); + + return ret; +} +#endif /* USE_LIBAVB */ + static vb2_error_t try_minios_kernel(struct vb2_context *ctx, struct vb2_kernel_params *params, struct vb2_disk_info *disk_info, @@ -485,8 +601,11 @@ static vb2_error_t try_minios_kernel(struct vb2_context *ctx, return rv; } - rv = vb2_load_partition(ctx, params, stream, lpflags, &kernel_version); - VB2_DEBUG("vb2_load_partition returned: %d\n", rv); + /* We are looking for ChromeOS partitions */ + rv = vb2_load_chromeos_kernel_partition(ctx, params, + stream, lpflags, + &kernel_version); + VB2_DEBUG("vb2_load_chromeos_kernel_partition returned: %d\n", rv); VbExStreamClose(stream); @@ -675,8 +794,13 @@ vb2_error_t vb2api_load_kernel(struct vb2_context *ctx, } uint32_t kernel_version = 0; - rv = vb2_load_partition(ctx, params, stream, lpflags, - &kernel_version); +#ifdef USE_LIBAVB + rv = vb2_load_avb_android_partition(ctx, params, stream, &gpt, + disk_info->handle); +#else + /* Don't allow to boot android without AVB */ + rv = VB2_ERROR_LK_INVALID_KERNEL_FOUND; +#endif VbExStreamClose(stream); if (rv) { diff --git a/firmware/avb/vboot_avb_ops.c b/firmware/avb/vboot_avb_ops.c index b9e1a554..8e76b2d1 100644 --- a/firmware/avb/vboot_avb_ops.c +++ b/firmware/avb/vboot_avb_ops.c @@ -353,6 +353,8 @@ static vb2_error_t vb2_load_init_boot_ramdisk(struct vb2_context *ctx, GptData * return VB2_ERROR_LOAD_PARTITION_READ_BODY; } + params->init_boot_size = params->init_boot_offset - *bytes_used; + return VB2_SUCCESS; } From f58cfea18d1587db83844ef3a7dddc5b86e85822 Mon Sep 17 00:00:00 2001 From: Jan Dabros Date: Fri, 17 May 2024 19:33:01 +0000 Subject: [PATCH 013/102] 2lib: Implement fallback for dual-boot with ChromeOS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For development purposes, there's a need to be able to dual-boot with ChromeOS. For this purpose, implement fallback mechanism, prioritizing android boot partition. BUG=b:325991478 TEST=Follow b/325981327#comment8. BRANCH=main Change-Id: I3f8ad7df128cc0fcbd861ce8476172889c998361 Signed-off-by: Konrad Adamczyk Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5716730 Tested-by: Grzegorz Bernacki Reviewed-by: Jakub Czapiga Commit-Queue: Grzegorz Bernacki Reviewed-by: Jan Dąbroś --- firmware/2lib/2load_kernel.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/firmware/2lib/2load_kernel.c b/firmware/2lib/2load_kernel.c index 2771f631..e30e8f4a 100644 --- a/firmware/2lib/2load_kernel.c +++ b/firmware/2lib/2load_kernel.c @@ -762,6 +762,9 @@ vb2_error_t vb2api_load_kernel(struct vb2_context *ctx, goto gpt_done; } + /* Store context flags for fallback */ + const uint64_t ctx_flags = ctx->flags; + /* Loop over candidate kernel partitions */ uint64_t part_start, part_size; while (GptNextKernelEntry(&gpt, &part_start, &part_size) == @@ -803,9 +806,41 @@ vb2_error_t vb2api_load_kernel(struct vb2_context *ctx, #endif VbExStreamClose(stream); + /* If there's an error with GKI boot, + * then try to fallback to ChromeOS + */ + if (rv) { + /* Set up and reopen the stream again */ + stream = NULL; + if (VbExStreamOpen(disk_info->handle, + part_start, part_size, &stream)) { + VB2_DEBUG("Cros fallback - unable to reopen stream\n"); + VB2_DEBUG("Marking kernel as invalid.\n"); + GptUpdateKernelEntry(&gpt, GPT_UPDATE_ENTRY_BAD); + continue; + } + + lpflags = 0; + if (params->partition_number > 0) { + /* + * If we already have a good kernel, we only needed to + * look at the vblock versions to check for rollback. + */ + lpflags |= VB2_LOAD_PARTITION_FLAG_VBLOCK_ONLY; + } + + /* Append status and try to load chromeos partition */ + rv = vb2_load_chromeos_kernel_partition(ctx, params, stream, + lpflags, &kernel_version); + + VbExStreamClose(stream); + } + if (rv) { VB2_DEBUG("Marking kernel as invalid (err=%x).\n", rv); GptUpdateKernelEntry(&gpt, GPT_UPDATE_ENTRY_BAD); + /* Restore original ctx->flags */ + ctx->flags = ctx_flags; continue; } From 9dca22c6108a4650342dd42b9cfe13555ac5fa74 Mon Sep 17 00:00:00 2001 From: Jan Dabros Date: Fri, 19 Apr 2024 22:54:15 +0000 Subject: [PATCH 014/102] 2lib: Fill verifiedbootstate property Android requires bootloader to provide verifiedbootstate property which informs about UNLOCKED -"orange", LOCKED(with dev keys) - "yellow" or LOCKED(with MP keys) - "green" state. Currently support "orange" and "green" states only, need to add logic to differentiate between MP and user keys - b/335901799. BUG=b:309426555 TEST=Build FW and boot android. Switch between developer and normal mode and verify content of verifiedbootstate variable `getprop | grep verifiedboot`. Note that verifiedbootstate needs to be removed from cmdline arguments BRANCH=main Change-Id: Idf0f1e850697bfe4b21cc5cfdb53b99ea417d183 Signed-off-by: Jan Dabros Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5716731 Tested-by: Grzegorz Bernacki Commit-Queue: Grzegorz Bernacki Reviewed-by: Jakub Czapiga --- firmware/2lib/2load_kernel.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/firmware/2lib/2load_kernel.c b/firmware/2lib/2load_kernel.c index e30e8f4a..d9c32a48 100644 --- a/firmware/2lib/2load_kernel.c +++ b/firmware/2lib/2load_kernel.c @@ -476,6 +476,9 @@ static vb2_error_t vb2_load_chromeos_kernel_partition( } #ifdef USE_LIBAVB + +#define VERIFIED_BOOT_PROPERTY_NAME "androidboot.verifiedbootstate=" + static vb2_error_t vb2_load_avb_android_partition( struct vb2_context *ctx, struct vb2_kernel_params *params, VbExStream_t stream, GptData *gpt, vb2ex_disk_handle_t disk_handle) @@ -493,6 +496,7 @@ static vb2_error_t vb2_load_avb_android_partition( AvbSlotVerifyResult result; vb2_error_t ret; int need_keyblock_valid = need_valid_keyblock(ctx); + char *verified_str; ret = GptGetActiveKernelPartitionSuffix(gpt, &ab_suffix); if (ret != GPT_SUCCESS) { @@ -546,6 +550,16 @@ static vb2_error_t vb2_load_avb_android_partition( return ret; } + /* TODO(b/335901799): Add support for marking verifiedbootstate yellow */ + /* Possible values for this property are "yellow", "orange" and "green" + * so allocate 6 bytes plus 1 byte for NULL terminator. + */ + verified_str = malloc(strlen(VERIFIED_BOOT_PROPERTY_NAME) + 7); + if (verified_str == NULL) + return VB2_ERROR_LK_NO_KERNEL_FOUND; + sprintf(verified_str, "%s%s", VERIFIED_BOOT_PROPERTY_NAME, + (ctx->flags & VB2_CONTEXT_DEVELOPER_MODE) ? "orange" : "green"); + /* * Use a buffer before the GKI header for copying avb cmdline string for * bootloader. @@ -557,12 +571,21 @@ static vb2_error_t vb2_load_avb_android_partition( params->vboot_cmdline_offset) return VB2_ERROR_LOAD_PARTITION_WORKBUF; - if (strlen(verify_data->cmdline) >= AVB_CMDLINE_BUF_SIZE) + if ((strlen(verify_data->cmdline) + strlen(verified_str) + 1) >= + AVB_CMDLINE_BUF_SIZE) return VB2_ERROR_LOAD_PARTITION_WORKBUF; strcpy((char *)(params->kernel_buffer + params->vboot_cmdline_offset), verify_data->cmdline); + /* Append verifiedbootstate property to cmdline */ + strcat((char *)(params->kernel_buffer + params->vboot_cmdline_offset), + " "); + strcat((char *)(params->kernel_buffer + params->vboot_cmdline_offset), + verified_str); + + free(verified_str); + /* No need for slot data, partitions should be already at correct * locations in memory since we are using "get_preloaded_partitions" * callbacks. From 980cbdaba40201a62fb54db99345a354fc10c1d4 Mon Sep 17 00:00:00 2001 From: Grzegorz Bernacki Date: Fri, 2 Aug 2024 12:28:27 +0000 Subject: [PATCH 015/102] cgptlib: Fix problem with strcat() function. Coreboot build complains about strcat() functions. This patch brings back original code from main which uses strcpy(). BUG=none TEST=build FW and run android BRANCH=main Cq-Depend: chromium:5741234 Change-Id: Ib16b820f28bbf6de9be8580800ddc29efb6e8273 Signed-off-by: Grzegorz Bernacki Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5757203 Reviewed-by: Jakub Czapiga --- firmware/lib/cgptlib/cgptlib_internal.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/firmware/lib/cgptlib/cgptlib_internal.c b/firmware/lib/cgptlib/cgptlib_internal.c index 13187c8b..5204cfc8 100644 --- a/firmware/lib/cgptlib/cgptlib_internal.c +++ b/firmware/lib/cgptlib/cgptlib_internal.c @@ -34,7 +34,8 @@ char *JoinStr(const char *a, const char *b) return NULL; strcpy(ret, a); - return strcat(ret, b); + strcpy(&ret[strlen(a)], b); + return ret; } int UTF8ToUCS2(const uint8_t *utf8_data, From 2081feb1b10c3610bafff8d42de0e8d7bd898197 Mon Sep 17 00:00:00 2001 From: Varun Somani Date: Wed, 3 Jul 2024 21:45:23 +0000 Subject: [PATCH 016/102] Android: Explicitly disable v1/v2 signing when using apksigner * This explicitly disables v1/v2 signing when we sign using apksigner. We no longer need to worry about v1/v2 as b/132818552 is resolved. ArcAPKCache supports both v2 and v3 signature format and we want this to be mandated to v3 only. BUG=b:349826228 TEST=Some manual testing with the parameters BRANCH=none (cherry picked from commit ca2d42d16531dd8d572e7fee47f709cc0952ec6b) Change-Id: I88b67793ed5fd7a1fe25b936601b9a3d44e991ec Original-Signed-off-by: Varun Somani Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5676946 Original-Reviewed-by: Josh Horwich Original-Reviewed-by: George Engelbrecht GitOrigin-RevId: ca2d42d16531dd8d572e7fee47f709cc0952ec6b Cr-Build-Id: 8740088178291783777 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8740088178291783777 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5773713 Tested-by: Jonathon Murphy Commit-Queue: Subrata Banik Reviewed-by: Subrata Banik Reviewed-by: Jakub Czapiga Tested-by: ChromeOS Prod (Robot) --- scripts/image_signing/sign_android_image.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/image_signing/sign_android_image.sh b/scripts/image_signing/sign_android_image.sh index 76fcdbc5..1d2d9dea 100755 --- a/scripts/image_signing/sign_android_image.sh +++ b/scripts/image_signing/sign_android_image.sh @@ -135,8 +135,6 @@ build flavor '${flavor_prop}'." # apksigner rotate --out media.lineage --old-signer --key old-media.pk8 # --cert old-media.x509.pem --new-signer --key new-media.pk8 --cert # new-media.x509.pem - # - # TODO(b/132818552): disable v1 signing once a check is removed. local extra_flags local lineage_file="${key_dir}/${keyname}.lineage" @@ -164,8 +162,10 @@ build flavor '${flavor_prop}'." --in "${temp_zipaligned_apk}" --out "${signed_apk}" \ ${extra_flags} else + # b/349826228: explicitly disabling v1/v2 signing due to lineage error apksigner sign --key "${key_dir}/${keyname}.pk8" \ --cert "${key_dir}/${keyname}.x509.pem" \ + --v1-signing-enabled false --v2-signing-enabled false \ --in "${temp_zipaligned_apk}" --out "${signed_apk}" \ ${extra_flags} fi From 40235e7f6f6543c61a5d6cde5cb01a14be5742bb Mon Sep 17 00:00:00 2001 From: Yu-Ping Wu Date: Thu, 4 Jul 2024 15:37:17 +0800 Subject: [PATCH 017/102] 2ec_sync: Reactivate VB2_CONTEXT_EC_SYNC_SLOW With EFS2, the boot flow for EC sync is usually: Boot 0: Initial boot with EC in RW. AP requests EC reset for EC sync. Boot 1: EC reboots to RO. AP wants to perform EC sync, but display isn't initialized. Therefore, AP sets VB2_NV_DISPLAY_REQUEST and reboot. Boot 2: EC is still in RO. AP sees VB2_NV_DISPLAY_REQUEST and initializes display. Then, AP shows EC sync screen and performs EC sync. The reboot for VB2_NV_DISPLAY_REQUEST can actually be avoided, because in boot 0 above it's already known that we're going to do EC sync in the next boot. To save us one reboot, reactivate the VB2_CONTEXT_EC_SYNC_SLOW flag. When the flag is set, VB2_NV_DISPLAY_REQUEST will be set at the end of boot 0, right before EC reset. BUG=b:350885214 TEST=make run2tests TEST=emerge-geralt libpayload depthcharge BRANCH=none (cherry picked from commit e529f947d27700fb4209eaeee2d8eb355051eb72) Change-Id: I1eaae4a7219f4e755e83e3478684b74f894cbfc2 Original-Signed-off-by: Yu-Ping Wu Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5676957 Original-Reviewed-by: Julius Werner GitOrigin-RevId: e529f947d27700fb4209eaeee2d8eb355051eb72 Cr-Build-Id: 8740088178291783777 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8740088178291783777 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5773714 Commit-Queue: Subrata Banik Reviewed-by: Subrata Banik Tested-by: ChromeOS Prod (Robot) Reviewed-by: Jakub Czapiga Tested-by: Jonathon Murphy --- firmware/2lib/2ec_sync.c | 4 ++++ firmware/2lib/2misc.c | 1 + firmware/2lib/include/2context.h | 4 ++-- tests/vb2_ec_sync_tests.c | 33 ++++++++++++++++++++++++++++++-- 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/firmware/2lib/2ec_sync.c b/firmware/2lib/2ec_sync.c index d04bc9cc..6475dc45 100644 --- a/firmware/2lib/2ec_sync.c +++ b/firmware/2lib/2ec_sync.c @@ -287,6 +287,10 @@ static vb2_error_t ec_sync_phase1(struct vb2_context *ctx) */ if ((sd->flags & SYNC_FLAG(VB_SELECT_FIRMWARE_EC_ACTIVE)) && (sd->flags & VB2_SD_FLAG_ECSYNC_EC_IN_RW) && !EC_EFS) { + if (ctx->flags & VB2_CONTEXT_EC_SYNC_SLOW) { + /* Ignore the return value. */ + vb2api_need_reboot_for_display(ctx); + } return VB2_REQUEST_REBOOT_EC_TO_RO; } diff --git a/firmware/2lib/2misc.c b/firmware/2lib/2misc.c index 807ffbc7..77ff3994 100644 --- a/firmware/2lib/2misc.c +++ b/firmware/2lib/2misc.c @@ -492,6 +492,7 @@ void vb2api_clear_recovery(struct vb2_context *ctx) } } +test_mockable int vb2api_need_reboot_for_display(struct vb2_context *ctx) { if (!(vb2_get_sd(ctx)->flags & VB2_SD_FLAG_DISPLAY_AVAILABLE)) { diff --git a/firmware/2lib/include/2context.h b/firmware/2lib/include/2context.h index eee45b80..4d365857 100644 --- a/firmware/2lib/include/2context.h +++ b/firmware/2lib/include/2context.h @@ -107,9 +107,9 @@ enum vb2_context_flags { /* * EC software sync is slow to update; warning screen should be * displayed. Caller may set this flag at any time before calling - * vb2api_kernel_phase2(). Deprecated as part of chromium:1038259. + * vb2api_kernel_phase2(). */ - VB2_CONTEXT_DEPRECATED_EC_SYNC_SLOW = (1 << 16), + VB2_CONTEXT_EC_SYNC_SLOW = (1 << 16), /* * EC firmware supports early firmware selection; two EC images exist, diff --git a/tests/vb2_ec_sync_tests.c b/tests/vb2_ec_sync_tests.c index c3a9d2cb..a60f93ae 100644 --- a/tests/vb2_ec_sync_tests.c +++ b/tests/vb2_ec_sync_tests.c @@ -30,6 +30,7 @@ static vb2_error_t ec_vboot_done_retval; static int ec_vboot_done_calls; static int mock_display_available; +static int need_display_called; static uint8_t mock_ec_ro_hash[32]; static uint8_t mock_ec_rw_hash[32]; static uint8_t hmir[32]; @@ -58,6 +59,7 @@ static void ResetMocks(void) memset(&gbb, 0, sizeof(gbb)); mock_display_available = 1; + need_display_called = 0; ec_ro_updated = 0; ec_rw_updated = 0; @@ -108,6 +110,12 @@ struct vb2_gbb_header *vb2_get_gbb(struct vb2_context *c) return &gbb; } +int vb2api_need_reboot_for_display(struct vb2_context *c) +{ + need_display_called = 1; + return !mock_display_available; +} + vb2_error_t vb2ex_ec_running_rw(int *in_rw) { *in_rw = ec_run_image; @@ -161,8 +169,9 @@ vb2_error_t vb2ex_ec_update_image(enum vb2_firmware_selection select) if (update_retval) return update_retval; - if (!mock_display_available) - return VB2_REQUEST_REBOOT; + if (ctx->flags & VB2_CONTEXT_EC_SYNC_SLOW) + if (vb2api_need_reboot_for_display(ctx)) + return VB2_REQUEST_REBOOT; if (select == VB_SELECT_FIRMWARE_READONLY) { ec_ro_updated = 1; @@ -335,6 +344,22 @@ static void VbSoftwareSyncTest(void) TEST_EQ(ec_rw_protected, 0, " ec rw protected"); TEST_EQ(ec_run_image, 1, " ec run image"); + /* Hexp != Hmir == Heff (display not available) */ + ResetMocks(); + hmir[0] = 43; + vb2_secdata_kernel_set_ec_hash(ctx, hmir); + ec_run_image = 1; + mock_ec_rw_hash[0] = 43; + mock_display_available = 0; + ctx->flags |= VB2_CONTEXT_EC_SYNC_SLOW; + test_ssync(VB2_REQUEST_REBOOT_EC_TO_RO, + 0, "Reboot after synching Hmir (display not available)"); + TEST_EQ(ec_ro_updated, 0, " ec ro updated"); + TEST_EQ(ec_rw_updated, 0, " ec rw updated"); + TEST_EQ(ec_rw_protected, 0, " ec rw protected"); + TEST_EQ(ec_run_image, 1, " ec run image"); + TEST_TRUE(need_display_called, " need display"); + /* Hexp == Hmir != Heff */ ResetMocks(); ec_run_image = 0; @@ -448,24 +473,28 @@ static void VbSoftwareSyncTest(void) ResetMocks(); mock_ec_rw_hash[0]++; mock_display_available = 0; + ctx->flags |= VB2_CONTEXT_EC_SYNC_SLOW; test_ssync(VB2_REQUEST_REBOOT, 0, "Reboot for display - ec rw"); TEST_EQ(ec_ro_updated, 0, " ec ro updated"); TEST_EQ(ec_rw_updated, 0, " ec rw updated"); TEST_EQ(ec_rw_protected, 0, " ec rw protected"); TEST_EQ(ec_run_image, 0, " ec run image"); + TEST_TRUE(need_display_called, " need display"); /* Display not available - RO */ ResetMocks(); vb2_nv_set(ctx, VB2_NV_TRY_RO_SYNC, 1); mock_ec_ro_hash[0]++; mock_display_available = 0; + ctx->flags |= VB2_CONTEXT_EC_SYNC_SLOW; test_ssync(VB2_REQUEST_REBOOT, 0, "Reboot for display - ec ro"); TEST_EQ(ec_ro_updated, 0, " ec ro updated"); TEST_EQ(ec_rw_updated, 0, " ec rw updated"); TEST_EQ(ec_rw_protected, 0, " ec rw protected"); TEST_EQ(ec_run_image, 1, " ec run image"); + TEST_TRUE(need_display_called, " need display"); /* RW cases, no update */ ResetMocks(); From bd9bc0e5d6054a4d0959eb6b8aa0de4f4fd07d5a Mon Sep 17 00:00:00 2001 From: Yu-Ping Wu Date: Thu, 4 Jul 2024 16:39:54 +0800 Subject: [PATCH 018/102] 2auxfw_sync: Clear display request before EC reset After auxfw sync, AP will request an EC reset, so that the chips that had firmware update will get reset to a clean state. In the next boot, however, another reboot may be needed to disable the display request, if the device is in normal boot mode. To avoid the extra reboot, clear the display request in advance before returning VB2_REQUEST_REBOOT_EC_TO_RO from vb2api_auxfw_sync(). BUG=b:350885214 TEST=make run2tests TEST=emerge-geralt libpayload depthcharge BRANCH=none (cherry picked from commit 17a45712e6c3cc92a5934a7279b501d93251675b) Change-Id: I77e0a9c72f2b6832296e391b735c9ddf15bf501e Original-Signed-off-by: Yu-Ping Wu Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5676958 Original-Reviewed-by: Julius Werner GitOrigin-RevId: 17a45712e6c3cc92a5934a7279b501d93251675b Cr-Build-Id: 8740088178291783777 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8740088178291783777 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5773715 Reviewed-by: Subrata Banik Reviewed-by: Jakub Czapiga Tested-by: Jonathon Murphy Tested-by: ChromeOS Prod (Robot) Commit-Queue: Subrata Banik --- firmware/2lib/2auxfw_sync.c | 14 +++++++++++--- tests/vb2_auxfw_sync_tests.c | 3 +++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/firmware/2lib/2auxfw_sync.c b/firmware/2lib/2auxfw_sync.c index a526e521..67ddc22e 100644 --- a/firmware/2lib/2auxfw_sync.c +++ b/firmware/2lib/2auxfw_sync.c @@ -8,6 +8,7 @@ #include "2api.h" #include "2common.h" #include "2misc.h" +#include "2nvstorage.h" /** * Determine if we are allowed to update auxfw. @@ -61,9 +62,16 @@ vb2_error_t vb2api_auxfw_sync(struct vb2_context *ctx) VB2_DEBUG("Updating auxfw\n"); VB2_TRY(vb2ex_auxfw_update(), ctx, VB2_RECOVERY_AUXFW_UPDATE); /* - * auxfw update is applied successfully. Request EC reboot to - * RO, so that the chips that had FW update get reset to a - * clean state. + * EC sync (if any) happens before auxfw sync. Now that auxfw + * sync is applied successfully, we are almost sure there will + * be no EC/auxfw sync in the next boot. Therefore, clear + * DISPLAY_REQUEST in advance so that the device can boot to + * kernel in normal mode where DISPLAY_REQUEST is not allowed. + */ + vb2_nv_set(ctx, VB2_NV_DISPLAY_REQUEST, 0); + /* + * Request EC reboot to RO, so that the chips that had FW update + * get reset to a clean state. */ return VB2_REQUEST_REBOOT_EC_TO_RO; } diff --git a/tests/vb2_auxfw_sync_tests.c b/tests/vb2_auxfw_sync_tests.c index 65256c4c..5591ec71 100644 --- a/tests/vb2_auxfw_sync_tests.c +++ b/tests/vb2_auxfw_sync_tests.c @@ -145,11 +145,14 @@ static void VbSoftwareSyncTest(void) "Slow auxfw update needed - reboot for display"); ResetMocks(); + vb2_nv_set(ctx, VB2_NV_DISPLAY_REQUEST, 1); auxfw_mock_severity = VB2_AUXFW_SLOW_UPDATE; test_auxsync(VB2_REQUEST_REBOOT_EC_TO_RO, 0, "Slow auxfw update needed"); TEST_EQ(auxfw_update_req, 1, " auxfw update requested"); TEST_EQ(auxfw_protected, 0, " auxfw protected"); + TEST_FALSE(vb2_nv_get(ctx, VB2_NV_DISPLAY_REQUEST), + " display request cleared"); ResetMocks(); auxfw_mock_severity = VB2_AUXFW_FAST_UPDATE; From 83e80176caba78fea6c276d66e1cfc620af447ab Mon Sep 17 00:00:00 2001 From: Yu-Ping Wu Date: Thu, 11 Jul 2024 06:30:23 +0800 Subject: [PATCH 019/102] treewide: Ensure a space after if/for/while keywords There are only whitespace changes in this patch. BUG=none TEST=cq BRANCH=none (cherry picked from commit f63e088ec7163a38390b67742c7da7cc1f51690d) Change-Id: I266b4f789d5c554471c9e47d6c9f97809b15f4b3 Original-Signed-off-by: Yu-Ping Wu Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5692979 Original-Commit-Queue: Yidi Lin Original-Reviewed-by: Yidi Lin GitOrigin-RevId: f63e088ec7163a38390b67742c7da7cc1f51690d Cr-Build-Id: 8740088178291783777 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8740088178291783777 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5773716 Tested-by: Jonathon Murphy Reviewed-by: Subrata Banik Tested-by: ChromeOS Prod (Robot) Reviewed-by: Jakub Czapiga Commit-Queue: Subrata Banik --- cgpt/cgpt_boot.c | 2 +- cgpt/cgpt_common.c | 4 ++-- cgpt/cmd_find.c | 2 +- firmware/2lib/2crc8.c | 2 +- firmware/2lib/2load_kernel.c | 2 +- firmware/2lib/2sha1.c | 6 +++--- firmware/2lib/2struct.c | 8 ++++---- host/arch/x86/lib/crossystem_arch.c | 10 +++++----- host/lib/file_keys.c | 2 +- host/lib/host_misc.c | 2 +- host/lib21/host_misc.c | 2 +- tests/cgptlib_test.c | 4 ++-- tests/sha_benchmark.c | 2 +- utility/load_kernel_test.c | 2 +- utility/pad_digest_utility.c | 2 +- utility/signature_digest_utility.c | 2 +- utility/verify_data.c | 2 +- 17 files changed, 28 insertions(+), 28 deletions(-) diff --git a/cgpt/cgpt_boot.c b/cgpt/cgpt_boot.c index 002f8df8..cb4e7be5 100644 --- a/cgpt/cgpt_boot.c +++ b/cgpt/cgpt_boot.c @@ -43,7 +43,7 @@ int CgptGetBootPartitionNumber(CgptBootParams *params) { int numEntries = GetNumberOfEntries(&drive); int i; - for(i = 0; i < numEntries; i++) { + for (i = 0; i < numEntries; i++) { GptEntry *entry = GetEntry(&drive.gpt, ANY_VALID, i); if (GuidEqual(&entry->unique, &drive.pmbr.boot_guid)) { diff --git a/cgpt/cgpt_common.c b/cgpt/cgpt_common.c index f1f939dc..b7366fc8 100644 --- a/cgpt/cgpt_common.c +++ b/cgpt/cgpt_common.c @@ -263,7 +263,7 @@ static int GptSave(struct drive *drive) { // Only start writing secondary GPT if primary was written correctly. if (!errors && !(drive->gpt.ignored & MASK_SECONDARY)) { if (drive->gpt.modified & GPT_MODIFIED_HEADER2) { - if(CGPT_OK != Save(drive, drive->gpt.secondary_header, + if (CGPT_OK != Save(drive, drive->gpt.secondary_header, drive->gpt.gpt_drive_sectors - GPT_PMBR_SECTORS, drive->gpt.sector_bytes, GPT_HEADER_SECTORS)) { errors++; @@ -1071,7 +1071,7 @@ int CgptGetNumNonEmptyPartitions(CgptShowParams *params) { params->num_partitions = 0; int numEntries = GetNumberOfEntries(&drive); int i; - for(i = 0; i < numEntries; i++) { + for (i = 0; i < numEntries; i++) { GptEntry *entry = GetEntry(&drive.gpt, ANY_VALID, i); if (GuidIsZero(&entry->type)) continue; diff --git a/cgpt/cmd_find.c b/cgpt/cmd_find.c index 6db5a2e6..0c927559 100644 --- a/cgpt/cmd_find.c +++ b/cgpt/cmd_find.c @@ -60,7 +60,7 @@ static uint8_t *ReadFile(const char *filename, uint64_t *size) { return NULL; } - if(1 != fread(buf, *size, 1, f)) { + if (1 != fread(buf, *size, 1, f)) { fclose(f); free(buf); return NULL; diff --git a/firmware/2lib/2crc8.c b/firmware/2lib/2crc8.c index 678f5877..2e31a676 100644 --- a/firmware/2lib/2crc8.c +++ b/firmware/2lib/2crc8.c @@ -20,7 +20,7 @@ uint8_t vb2_crc8(const void *vptr, uint32_t size) but for only a few bytes it isn't worth the code size. */ for (j = size; j; j--, data++) { crc ^= (*data << 8); - for(i = 8; i; i--) { + for (i = 8; i; i--) { if (crc & 0x8000) crc ^= (0x1070 << 3); crc <<= 1; diff --git a/firmware/2lib/2load_kernel.c b/firmware/2lib/2load_kernel.c index d9c32a48..bde929c1 100644 --- a/firmware/2lib/2load_kernel.c +++ b/firmware/2lib/2load_kernel.c @@ -928,7 +928,7 @@ vb2_error_t vb2api_load_kernel(struct vb2_context *ctx, VB2_DEBUG("Same kernel version\n"); break; } - } /* while(GptNextKernelEntry) */ + } /* while (GptNextKernelEntry) */ gpt_done: /* Write and free GPT data */ diff --git a/firmware/2lib/2sha1.c b/firmware/2lib/2sha1.c index 7acda305..ca5c5de7 100644 --- a/firmware/2lib/2sha1.c +++ b/firmware/2lib/2sha1.c @@ -194,7 +194,7 @@ static void sha1_transform(struct vb2_sha1_context *ctx) uint8_t *p = ctx->buf; int t; - for(t = 0; t < 16; ++t) { + for (t = 0; t < 16; ++t) { uint32_t tmp = (uint32_t)*p++ << 24; tmp |= *p++ << 16; tmp |= *p++ << 8; @@ -202,7 +202,7 @@ static void sha1_transform(struct vb2_sha1_context *ctx) W[t] = tmp; } - for(; t < 80; t++) { + for (; t < 80; t++) { W[t] = rol(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); } @@ -212,7 +212,7 @@ static void sha1_transform(struct vb2_sha1_context *ctx) D = ctx->state[3]; E = ctx->state[4]; - for(t = 0; t < 80; t++) { + for (t = 0; t < 80; t++) { uint32_t tmp = rol(5,A) + E + W[t]; if (t < 20) diff --git a/firmware/2lib/2struct.c b/firmware/2lib/2struct.c index 19684590..57069918 100644 --- a/firmware/2lib/2struct.c +++ b/firmware/2lib/2struct.c @@ -11,7 +11,7 @@ vb2_error_t vb2_check_keyblock(const struct vb2_keyblock *block, uint32_t size, const struct vb2_signature *sig) { - if(size < sizeof(*block)) { + if (size < sizeof(*block)) { VB2_DEBUG("Not enough space for keyblock header.\n"); return VB2_ERROR_KEYBLOCK_TOO_SMALL_FOR_HEADER; } @@ -95,7 +95,7 @@ vb2_error_t vb2_verify_fw_preamble(struct vb2_fw_preamble *preamble, VB2_DEBUG("Verifying preamble.\n"); /* Validity checks before attempting signature of data */ - if(size < sizeof(*preamble)) { + if (size < sizeof(*preamble)) { VB2_DEBUG("Not enough data for preamble header\n"); return VB2_ERROR_PREAMBLE_TOO_SMALL_FOR_HEADER; } @@ -204,7 +204,7 @@ vb2_error_t vb2_verify_kernel_preamble(struct vb2_kernel_preamble *preamble, VB2_DEBUG("Verifying kernel preamble.\n"); /* Make sure it's even safe to look at the struct */ - if(size < min_size) { + if (size < min_size) { VB2_DEBUG("Not enough data for preamble header.\n"); return VB2_ERROR_PREAMBLE_TOO_SMALL_FOR_HEADER; } @@ -218,7 +218,7 @@ vb2_error_t vb2_verify_kernel_preamble(struct vb2_kernel_preamble *preamble, min_size = EXPECTED_VB2_KERNEL_PREAMBLE_2_2_SIZE; else if (preamble->header_version_minor == 1) min_size = EXPECTED_VB2_KERNEL_PREAMBLE_2_1_SIZE; - if(preamble->preamble_size < min_size) { + if (preamble->preamble_size < min_size) { VB2_DEBUG("Preamble size too small for header.\n"); return VB2_ERROR_PREAMBLE_TOO_SMALL_FOR_HEADER; } diff --git a/host/arch/x86/lib/crossystem_arch.c b/host/arch/x86/lib/crossystem_arch.c index 48871e0f..c61f1163 100644 --- a/host/arch/x86/lib/crossystem_arch.c +++ b/host/arch/x86/lib/crossystem_arch.c @@ -371,7 +371,7 @@ static uint8_t* VbGetBuffer(const char* filename, int* buffer_size) if (buffer_size) *buffer_size = parsed_size; } - } while(0); + } while (0); /* wrap up */ if (f) @@ -575,7 +575,7 @@ static int FindGpioChipOffset(unsigned *gpio_num, unsigned *offset, return 0; } - while(0 != (ent = readdir(dir))) { + while (0 != (ent = readdir(dir))) { if (1 == sscanf(ent->d_name, "gpiochip%u", offset)) { match++; } @@ -605,7 +605,7 @@ static int FindGpioChipOffsetByLabel(unsigned *gpio_num, unsigned *offset, return 0; } - while(0 != (ent = readdir(dir))) { + while (0 != (ent = readdir(dir))) { if (1 == sscanf(ent->d_name, "gpiochip%u", &controller_offset)) { /* @@ -655,7 +655,7 @@ static int FindGpioChipOffsetByNumber(unsigned *gpio_num, unsigned *offset, break; } data++; - } while(1); + } while (1); if (data->uid == 0) { return 0; @@ -666,7 +666,7 @@ static int FindGpioChipOffsetByNumber(unsigned *gpio_num, unsigned *offset, return 0; } - while(0 != (ent = readdir(dir))) { + while (0 != (ent = readdir(dir))) { /* For every gpiochip entry determine uid. */ if (1 == sscanf(ent->d_name, "gpiochip%u", offset)) { char uid_file[128]; diff --git a/host/lib/file_keys.c b/host/lib/file_keys.c index cd51a075..2b7807d6 100644 --- a/host/lib/file_keys.c +++ b/host/lib/file_keys.c @@ -27,7 +27,7 @@ vb2_error_t DigestFile(char *input_file, enum vb2_hash_algorithm alg, uint8_t data[VB2_SHA1_BLOCK_SIZE]; struct vb2_digest_context ctx; - if( (input_fd = open(input_file, O_RDONLY)) == -1 ) { + if ((input_fd = open(input_file, O_RDONLY)) == -1) { fprintf(stderr, "Couldn't open %s\n", input_file); return VB2_ERROR_UNKNOWN; } diff --git a/host/lib/host_misc.c b/host/lib/host_misc.c index cba3fa9a..e09b7080 100644 --- a/host/lib/host_misc.c +++ b/host/lib/host_misc.c @@ -47,7 +47,7 @@ uint8_t* ReadFile(const char* filename, uint64_t* sizeptr) return NULL; } - if(1 != fread(buf, size, 1, f)) { + if (1 != fread(buf, size, 1, f)) { fprintf(stderr, "Unable to read from file %s\n", filename); fclose(f); free(buf); diff --git a/host/lib21/host_misc.c b/host/lib21/host_misc.c index 66a0abee..cd5acc0e 100644 --- a/host/lib21/host_misc.c +++ b/host/lib21/host_misc.c @@ -49,7 +49,7 @@ vb2_error_t vb2_read_file(const char *filename, uint8_t **data_ptr, } buf[size] = '\0'; - if(1 != fread(buf, size, 1, f)) { + if (1 != fread(buf, size, 1, f)) { VB2_DEBUG("Unable to read file %s\n", filename); fclose(f); free(buf); diff --git a/tests/cgptlib_test.c b/tests/cgptlib_test.c index 3871da12..91fe320f 100644 --- a/tests/cgptlib_test.c +++ b/tests/cgptlib_test.c @@ -832,7 +832,7 @@ static int OverlappedPartitionTest(void) { for (i = 0; i < ARRAY_SIZE(cases); ++i) { BuildTestGptData(gpt); ZeroEntries(gpt); - for(j = 0; j < ARRAY_SIZE(cases[0].entries); ++j) { + for (j = 0; j < ARRAY_SIZE(cases[0].entries); ++j) { if (!cases[i].entries[j].starting_lba) break; @@ -1492,7 +1492,7 @@ static int DuplicateUniqueGuidTest(void) for (i = 0; i < ARRAY_SIZE(cases); ++i) { BuildTestGptData(gpt); ZeroEntries(gpt); - for(j = 0; j < ARRAY_SIZE(cases[0].entries); ++j) { + for (j = 0; j < ARRAY_SIZE(cases[0].entries); ++j) { if (!cases[i].entries[j].starting_lba) break; diff --git a/tests/sha_benchmark.c b/tests/sha_benchmark.c index 523e940d..3c56e039 100644 --- a/tests/sha_benchmark.c +++ b/tests/sha_benchmark.c @@ -24,7 +24,7 @@ int main(int argc, char *argv[]) { ClockTimerState ct; /* Iterate through all the hash functions. */ - for(i = VB2_HASH_SHA1; i < VB2_HASH_ALG_COUNT; i++) { + for (i = VB2_HASH_SHA1; i < VB2_HASH_ALG_COUNT; i++) { StartTimer(&ct); vb2_hash_calculate(false, buffer, TEST_BUFFER_SIZE, i, &hash); StopTimer(&ct); diff --git a/utility/load_kernel_test.c b/utility/load_kernel_test.c index 8046fb4d..f8611156 100644 --- a/utility/load_kernel_test.c +++ b/utility/load_kernel_test.c @@ -205,7 +205,7 @@ int main(int argc, char* argv[]) /* Allocate a buffer for the kernel */ lkp.kernel_buffer = malloc(KERNEL_BUFFER_SIZE); - if(!lkp.kernel_buffer) { + if (!lkp.kernel_buffer) { fprintf(stderr, "Unable to allocate kernel buffer.\n"); return 1; } diff --git a/utility/pad_digest_utility.c b/utility/pad_digest_utility.c index c281e463..16a27b2b 100644 --- a/utility/pad_digest_utility.c +++ b/utility/pad_digest_utility.c @@ -59,7 +59,7 @@ int main(int argc, char* argv[]) } padded_digest = PrependDigestInfo(hash_alg, digest); - if(padded_digest && + if (padded_digest && fwrite(padded_digest, padded_digest_len, 1, stdout) == 1) error_code = 0; diff --git a/utility/signature_digest_utility.c b/utility/signature_digest_utility.c index e57700e9..ad43375f 100644 --- a/utility/signature_digest_utility.c +++ b/utility/signature_digest_utility.c @@ -50,7 +50,7 @@ int main(int argc, char* argv[]) uint32_t signature_digest_len = digest_size + digestinfo_size; signature_digest = SignatureDigest(buf, len, algorithm); - if(signature_digest && + if (signature_digest && fwrite(signature_digest, signature_digest_len, 1, stdout) == 1) error_code = 0; diff --git a/utility/verify_data.c b/utility/verify_data.c index a996d1ce..b9bbeafc 100644 --- a/utility/verify_data.c +++ b/utility/verify_data.c @@ -48,7 +48,7 @@ int main(int argc, char* argv[]) fprintf(stderr, "where depends on the signature algorithm" " used:\n"); - for(i = 0; i < VB2_ALG_COUNT; i++) + for (i = 0; i < VB2_ALG_COUNT; i++) fprintf(stderr, "\t%d for %s\n", i, vb2_get_crypto_algorithm_name(i)); return -1; From 73c0aeb2328490efd74b09025705241dab8fe241 Mon Sep 17 00:00:00 2001 From: Yu-Ping Wu Date: Thu, 11 Jul 2024 06:54:10 +0800 Subject: [PATCH 020/102] futility: updater: Increase try count from 10 to 11 CL:5666540 mentioned that the maximum try count needed for Rex is 9, but didn't consider auxfw sync and GSC update. On the other hand, in CL:5671642 we've reduced 2 unnecessary reboots about display request, so right now the maximum number of reboots becomes 11, as shown below. - Boot 0: Initial reboot with CSE in RW. To allow CSE update, reboot to switch to CSE RO. - Boot 1: Update CSE RW. Reboot to switch to CSE RW. - Boot 2: GSC needs update. Reset GSC to switch to the other partition. - Boot 3: CSE is back in RO due to GSC reset. Reboot to switch to RW. - Boot 4: EC needs update. Reboot to EC RO to allow EC sync. - Boot 5: CSE is back in RO due to EC reset. Reboot to switch to RW. - Boot 6: Perform EC sync. Under EFS2 NO_BOOT mode, reboot to EC RO to allow jumping to RW. - Boot 7: CSE is back in RO due to EC reset. Reboot to switch to RW. - Boot 8: Perform auxfw sync and reboot to EC RO. - Boot 9: CSE is back in RO due to EC reset. Reboot to switch to RW. - Boot 10: Boot to kernel, finally! In above, Boots 3, 5, 7, 9 are all caused by CSE booting back to RO due to system reset. There's a plan (b/259659012) to improve that from Panther Lake onwards, but right now those reboots are still needed for Rex, unfortunately. BUG=b:350885214 TEST=cq BRANCH=none (cherry picked from commit 033d7bfab8ac8f81a768ba66f933e346b6acb51d) Change-Id: I00fc96047277bb7dcbc8dbaf638f48df33a465e4 Original-Signed-off-by: Yu-Ping Wu Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5690663 Original-Reviewed-by: Julius Werner Original-Commit-Queue: Julius Werner GitOrigin-RevId: 033d7bfab8ac8f81a768ba66f933e346b6acb51d Cr-Build-Id: 8740088178291783777 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8740088178291783777 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5773717 Reviewed-by: Jakub Czapiga Commit-Queue: Subrata Banik Tested-by: ChromeOS Prod (Robot) Tested-by: Jonathon Murphy Reviewed-by: Subrata Banik --- futility/updater.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/futility/updater.c b/futility/updater.c index 9a4ee0c3..31de6ef7 100644 --- a/futility/updater.c +++ b/futility/updater.c @@ -250,7 +250,7 @@ static const char *decide_rw_target(struct updater_config *cfg, static int set_try_cookies(struct updater_config *cfg, const char *target, int has_update) { - int tries = 10; + int tries = 11; const char *slot; if (!has_update) From 687414fac324198ddaa1078bb63ff56a714f6fa3 Mon Sep 17 00:00:00 2001 From: Raul E Rangel Date: Tue, 16 Jul 2024 15:30:23 -0600 Subject: [PATCH 021/102] scripts: Add a script to convert a vbprivk to a PEM This script allows converting a `vbprivk` file into a PEM file that can be consumed by openssl. BUG=b:349468704 BRANCH=none TEST=./scripts/keygeneration/vbprivk_to_pem.sh < tests/devkeys/kernel_subkey.vbprivk | $HOME/android/prebuilts/build-tools/linux-x86/bin/openssl pkey -pubout (cherry picked from commit 4b12d392e5b12de29c582df4e717b1228e9f1594) Change-Id: I80d4a7187698bbcfcbe02c3b667bc89227e498e4 Original-Signed-off-by: Raul E Rangel Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5715316 Original-Reviewed-by: Julius Werner Original-Commit-Queue: Julius Werner GitOrigin-RevId: 4b12d392e5b12de29c582df4e717b1228e9f1594 Cr-Build-Id: 8740088178291783777 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8740088178291783777 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5773718 Tested-by: Jonathon Murphy Reviewed-by: Jakub Czapiga Tested-by: ChromeOS Prod (Robot) Commit-Queue: Subrata Banik Reviewed-by: Raul Rangel Reviewed-by: Subrata Banik --- scripts/keygeneration/vbprivk_to_pem.sh | 87 +++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100755 scripts/keygeneration/vbprivk_to_pem.sh diff --git a/scripts/keygeneration/vbprivk_to_pem.sh b/scripts/keygeneration/vbprivk_to_pem.sh new file mode 100755 index 00000000..79c9a60b --- /dev/null +++ b/scripts/keygeneration/vbprivk_to_pem.sh @@ -0,0 +1,87 @@ +#!/bin/bash +# Copyright 2024 The ChromiumOS Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +# +# Generates PEM encoded private key from a .vbprivk + +# Load common constants and functions. +# shellcheck source=common.sh +# shellcheck disable=SC1091 +. "$(dirname "$0")/common.sh" + +set -eu -o pipefail + +usage() { + cat < vbprivk private key (default: stdin) + --output PEM encoded private key (default: stdout) +EOF + + if [[ $# -ne 0 ]]; then + die "unknown option $*" + else + exit 0 + fi +} + +# Reads a signed 64 bit integer from stdin +readi64() { + local output + output="$(od --address-radix=none --read-bytes=8 --format=d8)" + # Drop leading padding and zeros + echo "$(("${output}"))" +} + +main() { + local input_fd=0 # stdin + local output_fd=1 # stdout + while [[ $# -gt 0 ]]; do + case $1 in + --input) + if ! exec 3< "$2"; then + die "Failed to open input file '$2'" + fi + input_fd=3 + shift + ;; + --output) + if ! exec 4> "$2"; then + die "Failed to open output file '$2'" + fi + output_fd=4 + shift + ;; + -h|--help) + usage + ;; + *) + usage "$1" + ;; + esac + shift + done + + # A `vbprivk` is comprised of an 8 byte header followed by a DER encoded + # PKCS#1 RSA Private Key. We read the 8 byte header from the input_fd + # (which increments file position) and verify that it's a sane value. + # + # See /vboot_reference/firmware/2lib/include/2crypto.h + local vb2_crypto_algorithm + vb2_crypto_algorithm="$(readi64 <&"${input_fd}")" + + if [[ "${vb2_crypto_algorithm}" -lt 0 || \ + "${vb2_crypto_algorithm}" -gt 17 ]]; then + die "Unknown vbprivk format" + fi + + # Convert the remainder of the input_fd to base64. + echo -n "-----BEGIN RSA PRIVATE KEY----- +$(base64 --wrap=64 <&"${input_fd}") +-----END RSA PRIVATE KEY----- +" >&"${output_fd}" +} +main "$@" From 78a0c4dd02f9912aadb5ade46374d25267b959d8 Mon Sep 17 00:00:00 2001 From: Jeremy Bettis Date: Thu, 25 Jul 2024 16:09:49 +0000 Subject: [PATCH 022/102] Deprecate GBB flag RUNNING_FAFT There is no correct use of this flag at any time, and FAFT tests do not normally set this GBB flag when tests are running. BUG=None TEST=None (cherry picked from commit e4977a64a8f55b513b4e7a06b15b8a44491d7eec) Change-Id: Ibfddb5e306fbbe1db6007534690ed6f73d89d734 Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5708050 Original-Reviewed-by: Julius Werner Original-Tested-by: Jeremy Bettis Original-Commit-Queue: Julius Werner Original-Auto-Submit: Jeremy Bettis GitOrigin-RevId: e4977a64a8f55b513b4e7a06b15b8a44491d7eec Cr-Build-Id: 8740088178291783777 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8740088178291783777 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5773719 Tested-by: ChromeOS Prod (Robot) Reviewed-by: Subrata Banik Commit-Queue: Subrata Banik Tested-by: Jonathon Murphy Reviewed-by: Jakub Czapiga --- firmware/2lib/2gbb.c | 6 +++--- firmware/2lib/include/2gbb_flags.h | 11 ++++++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/firmware/2lib/2gbb.c b/firmware/2lib/2gbb.c index d5c46dce..3612bef6 100644 --- a/firmware/2lib/2gbb.c +++ b/firmware/2lib/2gbb.c @@ -156,9 +156,9 @@ vb2_error_t vb2_get_gbb_flag_description(enum vb2_gbb_flag flag, *description = "Allow booting Legacy OSes even if dev_boot_altfw=0."; break; - case VB2_GBB_FLAG_RUNNING_FAFT: - *name = "VB2_GBB_FLAG_RUNNING_FAFT"; - *description = "Currently running FAFT tests."; + case VB2_GBB_FLAG_DEPRECATED_RUNNING_FAFT: + *name = "VB2_GBB_FLAG_DEPRECATED_RUNNING_FAFT"; + *description = "Deprecated, do not use."; break; case VB2_GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC: *name = "VB2_GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC"; diff --git a/firmware/2lib/include/2gbb_flags.h b/firmware/2lib/include/2gbb_flags.h index 5c92950b..ad95cd5c 100644 --- a/firmware/2lib/include/2gbb_flags.h +++ b/firmware/2lib/include/2gbb_flags.h @@ -59,12 +59,13 @@ enum vb2_gbb_flag { VB2_GBB_FLAG_FORCE_DEV_BOOT_ALTFW = 1 << 7, /* - * Currently running FAFT tests. May be used as a hint to disable - * other debug features which may interfere with tests. However, this - * should never be used to modify Chrome OS behaviour on specific - * devices with the goal of passing a test. See chromium:965914 for - * more information. + * This flag must never be used by anyone for any reason. It was created to + * disable certain debugging features in vendor provided blobs so that they + * could be used while running FAFT, but the flag has been misused elsewhere + * and is now deprecated. + * TODO: Remove VB2_GBB_FLAG_RUNNING_FAFT */ + VB2_GBB_FLAG_DEPRECATED_RUNNING_FAFT = 1 << 8, VB2_GBB_FLAG_RUNNING_FAFT = 1 << 8, /* Disable EC software sync */ From 66f50512772da795f2e7b8f768bae39cdd3a8fcb Mon Sep 17 00:00:00 2001 From: Dinesh Gehlot Date: Thu, 18 Jul 2024 15:08:52 +0530 Subject: [PATCH 023/102] 2lib: Add gbb flag to enforce CSE sync The CSE sync process executes a CSE upgrade exclusively when the CSE version stored in CBFS CSE differs from the current CSE. Given the infrequency of CSE upgrades, we may not always able to test the cse sync flow. This patch incorporates a GBB flag, which, when enabled, enforces CSE sync even if the current CSE version matches the version in CBFS. BUG=b:353053317 TEST=Able to build google/rex0. (cherry picked from commit f1f70f46dc5482bb7c654e53ed58d4001e386df2) Change-Id: I4d3b56b2bd259ffd6b8b8c57ab35ad6a0f080de9 Original-Signed-off-by: Dinesh Gehlot Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5718196 Original-Reviewed-by: Yu-Ping Wu Original-Reviewed-by: Subrata Banik Original-Commit-Queue: Yu-Ping Wu Original-Tested-by: Subrata Banik GitOrigin-RevId: f1f70f46dc5482bb7c654e53ed58d4001e386df2 Cr-Build-Id: 8740088178291783777 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8740088178291783777 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5773720 Reviewed-by: Jakub Czapiga Tested-by: ChromeOS Prod (Robot) Reviewed-by: Subrata Banik Tested-by: Jonathon Murphy Commit-Queue: Subrata Banik --- firmware/2lib/2gbb.c | 4 ++++ firmware/2lib/include/2gbb_flags.h | 3 +++ 2 files changed, 7 insertions(+) diff --git a/firmware/2lib/2gbb.c b/firmware/2lib/2gbb.c index 3612bef6..1c7b4e0e 100644 --- a/firmware/2lib/2gbb.c +++ b/firmware/2lib/2gbb.c @@ -193,6 +193,10 @@ vb2_error_t vb2_get_gbb_flag_description(enum vb2_gbb_flag flag, *name = "VB2_GBB_FLAG_ENABLE_UDC"; *description = "Enable USB Device Controller."; break; + case VB2_GBB_FLAG_FORCE_CSE_SYNC: + *name = "VB2_GBB_FLAG_FORCE_CSE_SYNC"; + *description = "Always sync CSE, even if it is same as CBFS CSE"; + break; default: *name = NULL; *description = NULL; diff --git a/firmware/2lib/include/2gbb_flags.h b/firmware/2lib/include/2gbb_flags.h index ad95cd5c..df17633a 100644 --- a/firmware/2lib/include/2gbb_flags.h +++ b/firmware/2lib/include/2gbb_flags.h @@ -94,6 +94,9 @@ enum vb2_gbb_flag { /* Enable USB Device Controller */ VB2_GBB_FLAG_ENABLE_UDC = 1 << 16, + + /* Enforce CSE SYNC, even if current CSE is same as CBFS CSE */ + VB2_GBB_FLAG_FORCE_CSE_SYNC = 1 << 17, }; vb2_error_t vb2_get_gbb_flag_description(enum vb2_gbb_flag flag, From e843fe0721706d324b9b416c33fe34725c234541 Mon Sep 17 00:00:00 2001 From: Ting Shen Date: Wed, 31 Jul 2024 16:30:02 +0800 Subject: [PATCH 024/102] futility/load_fmap: use WARN() on non-critical error File size less than section size is not a critical error. The wording causes user panic (e.g. b/356495697). Change ERROR() to WARN() to make the output message less scary. BRANCH=none BUG=none TEST=build spikyrock EC, verify that the command output changed to "WARNING: copy_to_area: ..." (cherry picked from commit b76d74dc08acd4f0905cd6baa2493a952f974b1a) Change-Id: Id1fc9050c9fdd95a12f605476b422921c0f4a751 Original-Signed-off-by: Ting Shen Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5751247 Original-Commit-Queue: Ting Shen Original-Tested-by: Ting Shen Original-Reviewed-by: Julius Werner GitOrigin-RevId: b76d74dc08acd4f0905cd6baa2493a952f974b1a Cr-Build-Id: 8740088178291783777 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8740088178291783777 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5773721 Tested-by: ChromeOS Prod (Robot) Tested-by: Jonathon Murphy Commit-Queue: Subrata Banik Reviewed-by: Subrata Banik Reviewed-by: Jakub Czapiga --- futility/cmd_load_fmap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/futility/cmd_load_fmap.c b/futility/cmd_load_fmap.c index 9aaebb78..7c89a78a 100644 --- a/futility/cmd_load_fmap.c +++ b/futility/cmd_load_fmap.c @@ -75,8 +75,8 @@ static int copy_to_area(const char *file, uint8_t *buf, area, file, strerror(errno)); retval = 1; } else if (n < len) { - ERROR("Warning on area %s: only read %zu " - "(not %d) from %s\n", area, n, len, file); + WARN("area %s: only read %zu (not %d) from %s\n", + area, n, len, file); } if (fclose(fp)) { From cbab8cd928c6c3027f3eb5d0e8de440311f04466 Mon Sep 17 00:00:00 2001 From: Jack Rosenthal Date: Thu, 1 Aug 2024 13:40:23 -0600 Subject: [PATCH 025/102] swap_ec_rw: Search for keyset in source tree too When executing this script outside the SDK from the source tree, /usr/share/vboot/devkeys (the typical default for --keyset) won't be available. Search for the devkeys inside vboot_reference too. BUG=b:352556657 BRANCH=none TEST=Script executes outside the SDK (cherry picked from commit ec01126c04cd6ff985139d52f2c9eac486a2ae4c) Original-Signed-off-by: Jack Rosenthal Change-Id: I1b7c8161acbd1d144208682cb7c035fa5f8d6e8d Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5757739 Original-Reviewed-by: Yu-Ping Wu GitOrigin-RevId: ec01126c04cd6ff985139d52f2c9eac486a2ae4c Cr-Build-Id: 8740088178291783777 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8740088178291783777 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5774542 Tested-by: ChromeOS Prod (Robot) Reviewed-by: Subrata Banik Reviewed-by: Jakub Czapiga Commit-Queue: Subrata Banik Tested-by: Jonathon Murphy --- scripts/image_signing/swap_ec_rw | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/image_signing/swap_ec_rw b/scripts/image_signing/swap_ec_rw index fd570ecc..b57bd81a 100755 --- a/scripts/image_signing/swap_ec_rw +++ b/scripts/image_signing/swap_ec_rw @@ -76,8 +76,13 @@ swap_ecrw() { -c none -f "${ecrw_version_file}" -n "${CBFS_ECRW_VERSION_NAME}" done + local keyset + for keyset in /usr/share/vboot/devkeys "${SCRIPT_BASE}/../../tests/devkeys"; do + [[ -d "${keyset}" ]] && break + done + # 'futility sign' will call 'cbfstool truncate' if needed - futility sign "${ap_file}" + futility sign "${ap_file}" --keyset "${keyset}" ecrw_version=$(futility update --manifest -e "${ec_file}" \ | jq -r '.default.ec.versions.rw') From c99c3ad7aa5cc137b73246b9e7f185b6afd91904 Mon Sep 17 00:00:00 2001 From: Jon Murphy Date: Tue, 20 Aug 2024 16:19:11 -0600 Subject: [PATCH 026/102] vboot: Add owners for android branch. BUG=None TEST=CQ BRANCH=firmware-android-15949.B Change-Id: I0ff73cc5f14637f5066dd160d021d9ef3637b1b8 Signed-off-by: Jon Murphy Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5801511 Reviewed-by: Subrata Banik Commit-Queue: Subrata Banik Reviewed-by: Yu-Ping Wu --- OWNERS | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/OWNERS b/OWNERS index 76c3e8a0..8c7c08cf 100644 --- a/OWNERS +++ b/OWNERS @@ -1,5 +1 @@ -jwerner@chromium.org -yupingso@chromium.org -hungte@chromium.org -roccochen@chromium.org -czapiga@google.com +include chromiumos/owners:v1:/firmware/OWNERS.android From 2114c7c7774ee374fad11995dcb2086537db4424 Mon Sep 17 00:00:00 2001 From: Grzegorz Bernacki Date: Mon, 2 Sep 2024 13:11:28 +0000 Subject: [PATCH 027/102] cgptlib: Fix problem with finding partition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Function GptFindOffsetByName() finds partition based on name parameter, which is encoded as USC-2. It uses 2 bytes per character, so memcmp() which is used for comparison should use name length multiplied by 2. BUG=None TEST=None BRANCH=firmware-android-15949.B Change-Id: Ide316e92fb342237deea436b3e87ab82f1efae33 Signed-off-by: Grzegorz Bernacki Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5828869 Reviewed-by: Jan Dąbroś Reviewed-by: Yu-Ping Wu --- firmware/lib/cgptlib/cgptlib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/lib/cgptlib/cgptlib.c b/firmware/lib/cgptlib/cgptlib.c index d7943510..4784a780 100644 --- a/firmware/lib/cgptlib/cgptlib.c +++ b/firmware/lib/cgptlib/cgptlib.c @@ -288,7 +288,7 @@ int GptFindOffsetByName(GptData *gpt, const char *name, goto out; for (i = 0, e = entries; i < header->number_of_entries; i++, e++) { - if (!memcmp(&e->name, name_ucs2, size_ucs2)) { + if (!memcmp(&e->name, name_ucs2, size_ucs2 * sizeof(*name_ucs2))) { *start_sector = e->starting_lba; *size = e->ending_lba - e->starting_lba + 1; ret = GPT_SUCCESS; From d3cc3a10e3e72f9d77aef983ab08a4a2bb8f1e06 Mon Sep 17 00:00:00 2001 From: Yu-Ping Wu Date: Wed, 7 Aug 2024 09:57:31 +0800 Subject: [PATCH 028/102] futility/load_fmap: Erase remaining bytes if file smaller than area The `futility load_fmap` subcommand allows the passed file to be smaller than the corresponding FMAP area size. That's convenient for some use cases (such as EC's KEY_RO), because the caller doesn't need to have an extra step of enlarging the file to match the area size. However, the current implementation is to keep the remaining data in the area unmodified, which is often not the intention of the caller. Therefore, change the behavior by erasing the remaining bytes to 0xff. BUG=none TEST=make runfutiltests BRANCH=none (cherry picked from commit 8365d546ce0698faffd22cf3cb44c0c854f74637) Change-Id: Ib6575023801d995b7b25110bb411ec74d9a240f0 Original-Signed-off-by: Yu-Ping Wu Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5768173 Original-Reviewed-by: Julius Werner GitOrigin-RevId: 8365d546ce0698faffd22cf3cb44c0c854f74637 Cr-Build-Id: 8737823253384683697 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8737823253384683697 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5785625 Reviewed-by: Yu-Ping Wu Commit-Queue: Yu-Ping Wu Tested-by: ChromeOS Prod (Robot) --- futility/cmd_load_fmap.c | 6 ++++-- tests/futility/test_load_fmap.sh | 12 ++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/futility/cmd_load_fmap.c b/futility/cmd_load_fmap.c index 7c89a78a..4578e413 100644 --- a/futility/cmd_load_fmap.c +++ b/futility/cmd_load_fmap.c @@ -75,8 +75,10 @@ static int copy_to_area(const char *file, uint8_t *buf, area, file, strerror(errno)); retval = 1; } else if (n < len) { - WARN("area %s: only read %zu (not %d) from %s\n", - area, n, len, file); + WARN("area %s: %s size (%zu) smaller than area size %u; " + "erasing remaining data to 0xff\n", + area, file, n, len); + memset(buf + n, 0xff, len - n); } if (fclose(fp)) { diff --git a/tests/futility/test_load_fmap.sh b/tests/futility/test_load_fmap.sh index dabd46d4..3ae30c55 100755 --- a/tests/futility/test_load_fmap.sh +++ b/tests/futility/test_load_fmap.sh @@ -38,6 +38,18 @@ for a in "${AREAS[@]}"; do cmp "$a" "$a.rand" done +# File size smaller than area size +cp -f "${IN}" "${BIOS}" +"${FUTILITY}" dump_fmap -x "${BIOS}" VBLOCK_A +cp -f VBLOCK_A VBLOCK_A.truncated +truncate --size=-5 VBLOCK_A.truncated +cp -f VBLOCK_A.truncated VBLOCK_A.new +printf '\xFF%.s' {1..5} >> VBLOCK_A.new +cmp -s VBLOCK_A.new VBLOCK_A && error "VBLOCK_A.new is the same as VBLOCK_A" +"${FUTILITY}" load_fmap "${BIOS}" VBLOCK_A:VBLOCK_A.truncated +"${FUTILITY}" dump_fmap -x "${BIOS}" VBLOCK_A:VBLOCK_A.readback +cmp VBLOCK_A.readback VBLOCK_A.new + # cleanup rm -f "${TMP}"* "${AREAS[@]}" ./*.rand ./*.good exit 0 From 69b577e35b0578787dda343925f9a6038b08be58 Mon Sep 17 00:00:00 2001 From: Yu-Ping Wu Date: Fri, 16 Aug 2024 13:13:17 +0800 Subject: [PATCH 029/102] futility: Skip printing EC RW version if non-printable The "ecrw.version" CBFS file may contain non-printable characters, for example in Wilco (sarien & drallion) images. To make sure `futility update --manifest` produces valid JSON format, skip printing EC RW version for those images. BUG=b:360198909 TEST=make runtests -j BRANCH=none (cherry picked from commit 7cc2ce4c902b9ff1d6b725e72b0f7d152fe09e40) Change-Id: I072cb1a7aa2430ba180314ba876cb8b544ea228a Original-Signed-off-by: Yu-Ping Wu Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5792922 Original-Reviewed-by: Hung-Te Lin GitOrigin-RevId: 7cc2ce4c902b9ff1d6b725e72b0f7d152fe09e40 Cr-Build-Id: 8737823253384683697 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8737823253384683697 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5832130 Tested-by: ChromeOS Prod (Robot) Reviewed-by: Yu-Ping Wu Commit-Queue: Yu-Ping Wu --- futility/updater.h | 1 + futility/updater_utils.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/futility/updater.h b/futility/updater.h index d4a7f0fa..1ea0cb5f 100644 --- a/futility/updater.h +++ b/futility/updater.h @@ -32,6 +32,7 @@ static const char * const FMAP_RO = "WP_RO", * const FMAP_RW_SHARED = "RW_SHARED", * const FMAP_RW_LEGACY = "RW_LEGACY", * const FMAP_RW_VPD = "RW_VPD", + * const FMAP_RW_DIAG_NVRAM = "DIAG_NVRAM", * const FMAP_SI_DESC = "SI_DESC", * const FMAP_SI_ME = "SI_ME"; diff --git a/futility/updater_utils.c b/futility/updater_utils.c index 02a30125..356a8d11 100644 --- a/futility/updater_utils.c +++ b/futility/updater_utils.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -111,6 +112,16 @@ static int load_firmware_version(struct firmware_image *image, return 0; } +static bool has_printable_ecrw_version(const struct firmware_image *image) +{ + /* + * Wilco family (sarien & drallion) has binary ecrw version which may + * contain non-printable characters. Those images can be identified by + * checking if the DIAG_NVRAM FMAP section exists or not. + */ + return !firmware_section_exists(image, FMAP_RW_DIAG_NVRAM); +} + /* * Loads the version of "ecrw" CBFS file within `section_name` of `image_file`. * Returns the version string on success; otherwise an empty string. @@ -126,6 +137,9 @@ static char *load_ecrw_version(const struct firmware_image *image, if (!firmware_section_exists(image, section_name)) goto done; + if (!has_printable_ecrw_version(image)) + goto done; + const char *ecrw_version_file = create_temp_file(&tempfile_head); if (!ecrw_version_file) goto done; From e5f12287066422097a59c1ab055e6e47f9b392d4 Mon Sep 17 00:00:00 2001 From: Yu-Ping Wu Date: Thu, 8 Aug 2024 10:49:40 +0800 Subject: [PATCH 030/102] 2lib/2load_kernel: Remove unused VB2_LOAD_PARTITION_WORKBUF_BYTES In CL:2882527 we've removed the `wb` argument from vb2_load_partition(). Now the workbuf is allocated from that function. Therefore, remove the unused macro VB2_LOAD_PARTITION_WORKBUF_BYTES. BUG=none TEST=cq BRANCH=none (cherry picked from commit 47658f3c89e2c1585e95ef47b3c19cb05b4be586) Change-Id: I70540ea40bac4fa6dd0f18ca7e0fbfbae34c09b1 Original-Signed-off-by: Yu-Ping Wu Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5772312 Original-Reviewed-by: Julius Werner GitOrigin-RevId: 47658f3c89e2c1585e95ef47b3c19cb05b4be586 Cr-Build-Id: 8737823253384683697 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8737823253384683697 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5832131 Reviewed-by: Yu-Ping Wu Tested-by: ChromeOS Prod (Robot) Commit-Queue: Yu-Ping Wu --- firmware/2lib/2load_kernel.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/firmware/2lib/2load_kernel.c b/firmware/2lib/2load_kernel.c index bde929c1..9943bf71 100644 --- a/firmware/2lib/2load_kernel.c +++ b/firmware/2lib/2load_kernel.c @@ -34,10 +34,6 @@ enum vb2_load_partition_flags { /* Bytes to read at start of the boot/init_boot/vendor_boot partitions */ #define BOOT_HDR_GKI_SIZE 4096 -/* Minimum context work buffer size needed for vb2_load_partition() */ -#define VB2_LOAD_PARTITION_WORKBUF_BYTES \ - (VB2_VERIFY_KERNEL_PREAMBLE_WORKBUF_BYTES + KBUF_SIZE) - #define LOWEST_TPM_VERSION 0xffffffff /** From 4a2ec0996649354d0ebe36d7af1f176228d530e7 Mon Sep 17 00:00:00 2001 From: Madeleine Hardt Date: Wed, 21 Aug 2024 09:20:33 -0600 Subject: [PATCH 031/102] sign_official_build: Include full loem.ini path For easier troubleshooting. BUG=b:356700724 TEST=None BRANCH=None (cherry picked from commit 2fc6815bf6b50ae2fce305ed45f8f2dc6692514b) Change-Id: I581abb60b5da87b42bb7135afa68b8a932778ff8 Original-Signed-off-by: Madeleine Hardt Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5804351 Original-Reviewed-by: Benjamin Shai Original-Reviewed-by: George Engelbrecht GitOrigin-RevId: 2fc6815bf6b50ae2fce305ed45f8f2dc6692514b Cr-Build-Id: 8737823253384683697 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8737823253384683697 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5832132 Tested-by: ChromeOS Prod (Robot) Reviewed-by: George Engelbrecht Reviewed-by: Yu-Ping Wu Commit-Queue: Yu-Ping Wu Reviewed-by: Madeleine Hardt --- scripts/image_signing/sign_official_build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/image_signing/sign_official_build.sh b/scripts/image_signing/sign_official_build.sh index c9251fb4..0c7bd308 100755 --- a/scripts/image_signing/sign_official_build.sh +++ b/scripts/image_signing/sign_official_build.sh @@ -557,7 +557,7 @@ resign_firmware_shellball() { # loem.ini has the format KEY_ID_VALUE = KEY_INDEX if ! match="$(grep -E "^[0-9]+ *= *${key_id}$" "${KEY_DIR}/loem.ini")"; then - die "The loem key_id ${key_id} not found in loem.ini!" + die "The loem key_id ${key_id} not found in loem.ini! (${KEY_DIR}/loem.ini)" fi # shellcheck disable=SC2001 From 2c63166433e9bf0ac3d4fb2dadfd74ea07e3552c Mon Sep 17 00:00:00 2001 From: Nehemiah Dureus Date: Mon, 24 Jun 2024 17:58:50 +0000 Subject: [PATCH 032/102] vboot: Only execute TPM clear on nonchrome FW Prevent devices that are running ChromeOS FW from executing a TPM clear request (designed for Flex), as it does not have the HW to do so. BUG=b:328654919 BRANCH=none TEST=Deploy new changes to a flex liveboot and run the installer on a cb (cherry picked from commit 060efa0cf64d4b7ccbe3e88140c9da5f747355ee) Original-Signed-off-by: Nehemiah Dureus Change-Id: Ia50d9065edaf1d398ce58bd6e189d9cac7eda38d Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5656183 Original-Reviewed-by: Julius Werner Original-Reviewed-by: Yi Chou GitOrigin-RevId: 060efa0cf64d4b7ccbe3e88140c9da5f747355ee Cr-Build-Id: 8737823253384683697 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8737823253384683697 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5832133 Tested-by: ChromeOS Prod (Robot) Reviewed-by: Yu-Ping Wu Commit-Queue: Yu-Ping Wu --- host/lib/crossystem.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/host/lib/crossystem.c b/host/lib/crossystem.c index 740834af..184979d5 100644 --- a/host/lib/crossystem.c +++ b/host/lib/crossystem.c @@ -119,6 +119,21 @@ static int ReleaseCrossystemLock(int lock_fd) return 0; } +/* Check if system FW type is equivalent to a given name */ +static bool CheckFwType(const char *name) +{ + char fwtype_buf[VB_MAX_STRING_PROPERTY]; + int fwtype_ret; + + fwtype_ret = VbGetSystemPropertyString("mainfw_type", + fwtype_buf, sizeof(fwtype_buf)); + + if (fwtype_ret == 0 && !strcasecmp(fwtype_buf, name)) + return true; + + return false; +} + static struct vb2_context *get_fake_context(void) { static uint8_t fake_workbuf[sizeof(struct vb2_shared_data) + 16] @@ -444,7 +459,7 @@ int VbGetSystemPropertyInt(const char *name) } else if (!strcasecmp(name,"disable_dev_request")) { value = vb2_get_nv_storage(VB2_NV_DISABLE_DEV_REQUEST); } else if (!strcasecmp(name,"clear_tpm_owner_request")) { - if (EXTERNAL_TPM_CLEAR_REQUEST) { + if (EXTERNAL_TPM_CLEAR_REQUEST && CheckFwType("nonchrome")) { const char *const argv[] = { TPM_CLEAR_REQUEST_EXEC_NAME, NULL, @@ -666,7 +681,7 @@ static int VbSetSystemPropertyIntInternal(const char *name, int value) } else if (!strcasecmp(name,"disable_dev_request")) { return vb2_set_nv_storage(VB2_NV_DISABLE_DEV_REQUEST, value); } else if (!strcasecmp(name,"clear_tpm_owner_request")) { - if (EXTERNAL_TPM_CLEAR_REQUEST) { + if (EXTERNAL_TPM_CLEAR_REQUEST && CheckFwType("nonchrome")) { const char *const argv[] = { TPM_CLEAR_REQUEST_EXEC_NAME, value ? "1" : "0", From 0070c48622d858f657f1d72cd5a21d32bd9c14fb Mon Sep 17 00:00:00 2001 From: Hung-Te Lin Date: Thu, 29 Aug 2024 15:29:40 +0800 Subject: [PATCH 033/102] futility: updater: cleanup: Remove duplicated comments Removed the comments above the public functions in the C files that have the same comments in the header files. No real code changes. BUG=None TEST=make BRANCH=None (cherry picked from commit 7e2828a1bacfbcbe3480378bf5482004c3901698) Change-Id: I4846620584274985ae104bbe6c232fa66a711420 Original-Signed-off-by: Hung-Te Lin Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5822730 Original-Commit-Queue: Yu-Ping Wu Original-Reviewed-by: Yu-Ping Wu Original-Tested-by: Yu-Ping Wu GitOrigin-RevId: 7e2828a1bacfbcbe3480378bf5482004c3901698 Cr-Build-Id: 8737823253384683697 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8737823253384683697 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5832134 Reviewed-by: Yu-Ping Wu Tested-by: ChromeOS Prod (Robot) Commit-Queue: Yu-Ping Wu Commit-Queue: Hung-Te Lin --- futility/updater.c | 16 -------- futility/updater_archive.c | 42 --------------------- futility/updater_dut.c | 16 -------- futility/updater_quirks.c | 15 -------- futility/updater_utils.c | 76 +------------------------------------- 5 files changed, 1 insertion(+), 164 deletions(-) diff --git a/futility/updater.c b/futility/updater.c index 31de6ef7..cf741229 100644 --- a/futility/updater.c +++ b/futility/updater.c @@ -113,14 +113,12 @@ static void override_properties_from_list(const char *override_list, } } -/* Gets the value (setting) of specified quirks from updater configuration. */ int get_config_quirk(enum quirk_types quirk, const struct updater_config *cfg) { assert(quirk < QUIRK_MAX); return cfg->quirks[quirk].value; } -/* Prints the name and description from all supported quirks. */ void updater_list_config_quirks(const struct updater_config *cfg) { const struct quirk_entry *entry = cfg->quirks; @@ -580,9 +578,6 @@ static int check_compatible_platform(struct updater_config *cfg) return strncasecmp(image_from->ro_version, image_to->ro_version, len); } -/* - * Returns a valid root key from GBB header, or NULL on failure. - */ const struct vb2_packed_key *get_rootkey( const struct vb2_gbb_header *gbb) { @@ -1132,10 +1127,6 @@ static enum updater_error_codes update_whole_firmware( return UPDATE_ERR_DONE; } -/* - * The main updater to update system firmware using the configuration parameter. - * Returns UPDATE_ERR_DONE if success, otherwise failure. - */ enum updater_error_codes update_firmware(struct updater_config *cfg) { bool done = false; @@ -1243,10 +1234,6 @@ enum updater_error_codes update_firmware(struct updater_config *cfg) return r; } -/* - * Allocates and initializes a updater_config object with default values. - * Returns the newly allocated object, or NULL on error. - */ struct updater_config *updater_new_config(void) { struct updater_config *cfg = (struct updater_config *)calloc( @@ -1846,9 +1833,6 @@ int handle_flash_argument(struct updater_config_arguments *args, int opt, return 1; } -/* - * Releases all resources in an updater configuration object. - */ void updater_delete_config(struct updater_config *cfg) { assert(cfg); diff --git a/futility/updater_archive.c b/futility/updater_archive.c index 4f472e07..3d22cc5b 100644 --- a/futility/updater_archive.c +++ b/futility/updater_archive.c @@ -540,12 +540,6 @@ static int archive_zip_write_file(void *handle, const char *fname, * -- The public functions for using u_archive. -- */ -/* - * Opens an archive from given path. - * The type of archive will be determined automatically. - * Returns a pointer to reference to archive (must be released by archive_close - * when not used), otherwise NULL on error. - */ struct u_archive *archive_open(const char *path) { struct stat path_stat; @@ -622,10 +616,6 @@ struct u_archive *archive_open(const char *path) return ar; } -/* - * Closes an archive reference. - * Returns 0 on success, otherwise non-zero as failure. - */ int archive_close(struct u_archive *ar) { int r = ar->close(ar->handle); @@ -633,12 +623,6 @@ int archive_close(struct u_archive *ar) return r; } -/* - * Checks if an entry (either file or directory) exists in archive. - * If entry name (fname) is an absolute path (/file), always check - * with real file system. - * Returns 1 if exists, otherwise 0 - */ int archive_has_entry(struct u_archive *ar, const char *name) { if (!ar || *name == '/') @@ -646,13 +630,6 @@ int archive_has_entry(struct u_archive *ar, const char *name) return ar->has_entry(ar->handle, name); } -/* - * Traverses all files within archive (directories are ignored). - * For every entry, the path (relative the archive root) will be passed to - * callback function, until the callback returns non-zero. - * The arg argument will also be passed to callback. - * Returns 0 on success otherwise non-zero as failure. - */ int archive_walk(struct u_archive *ar, void *arg, int (*callback)(const char *path, void *arg)) { @@ -661,15 +638,6 @@ int archive_walk(struct u_archive *ar, void *arg, return ar->walk(ar->handle, arg, callback); } -/* - * Reads a file from archive. - * If entry name (fname) is an absolute path (/file), always read - * from real file system. - * The returned data must always have one extra (not included by size) '\0' in - * the end of the allocated buffer for C string processing. - * Returns 0 on success (data and size reflects the file content), - * otherwise non-zero as failure. - */ int archive_read_file(struct u_archive *ar, const char *fname, uint8_t **data, uint32_t *size, int64_t *mtime) { @@ -678,12 +646,6 @@ int archive_read_file(struct u_archive *ar, const char *fname, return ar->read_file(ar->handle, fname, data, size, mtime); } -/* - * Writes a file into archive. - * If entry name (fname) is an absolute path (/file), always write into real - * file system. - * Returns 0 on success, otherwise non-zero as failure. - */ int archive_write_file(struct u_archive *ar, const char *fname, uint8_t *data, uint32_t size, int64_t mtime) { @@ -716,10 +678,6 @@ static int archive_copy_callback(const char *path, void *_arg) return r; } -/* - * Copies all entries from one archive to another. - * Returns 0 on success, otherwise non-zero as failure. - */ int archive_copy(struct u_archive *from, struct u_archive *to) { struct _copy_arg arg = { .from = from, .to = to }; diff --git a/futility/updater_dut.c b/futility/updater_dut.c index dd2e7310..5179481f 100644 --- a/futility/updater_dut.c +++ b/futility/updater_dut.c @@ -13,16 +13,6 @@ #include "crossystem.h" #include "updater.h" -/** - * dut_get_manifest_key() - Wrapper to get the firmware manifest key from crosid - * - * @manifest_key_out - Output parameter of the firmware manifest key. - * - * Returns: - * - <0 if libcrosid is unavailable or there was an error reading - * device data - * - >=0 (the matched device index) success - */ int dut_get_manifest_key(char **manifest_key_out, struct updater_config *cfg) { if (cfg->dut_is_remote) { @@ -148,12 +138,6 @@ static inline int dut_get_wp_sw_ec(struct updater_config *cfg) /* Helper functions to use or configure the DUT properties. */ -/* - * Gets the DUT system property by given type. - * If the property was not loaded yet, invoke the property getter function - * and cache the result. - * Returns the property value. - */ int dut_get_property(enum dut_property_type property_type, struct updater_config *cfg) { diff --git a/futility/updater_quirks.c b/futility/updater_quirks.c index 24a4aa60..e84063f0 100644 --- a/futility/updater_quirks.c +++ b/futility/updater_quirks.c @@ -422,9 +422,6 @@ static int quirk_no_verify(struct updater_config *cfg) return 0; } -/* - * Registers known quirks to a updater_config object. - */ void updater_register_quirks(struct updater_config *cfg) { struct quirk_entry *quirks; @@ -502,10 +499,6 @@ void updater_register_quirks(struct updater_config *cfg) quirks->apply = quirk_clear_mrc_data; } -/* - * Gets the default quirk config string from target image name. - * Returns a string (in same format as --quirks) to load or NULL if no quirks. - */ const char * const updater_get_model_quirks(struct updater_config *cfg) { const char *pattern = cfg->image.ro_version; @@ -526,10 +519,6 @@ const char * const updater_get_model_quirks(struct updater_config *cfg) return NULL; } -/* - * Gets the quirk config string from target image CBFS. - * Returns a string (in same format as --quirks) to load or NULL if no quirks. - */ char *updater_get_cbfs_quirks(struct updater_config *cfg) { const char *entry_name = "updater_quirks"; @@ -575,10 +564,6 @@ char *updater_get_cbfs_quirks(struct updater_config *cfg) return (char *)data; } -/* - * Overrides signature id if the device was shipped with known - * special rootkey. - */ int quirk_override_signature_id(struct updater_config *cfg, struct model_config *model, const char **signature_id) diff --git a/futility/updater_utils.c b/futility/updater_utils.c index 356a8d11..c581f0cd 100644 --- a/futility/updater_utils.c +++ b/futility/updater_utils.c @@ -24,11 +24,6 @@ #define COMMAND_BUFFER_SIZE 256 -/* - * Strips a string (usually from shell execution output) by removing all the - * trailing characters in pattern. If pattern is NULL, match by space type - * characters (space, new line, tab, ... etc). - */ void strip_string(char *s, const char *pattern) { int len; @@ -47,10 +42,6 @@ void strip_string(char *s, const char *pattern) } } -/* - * Saves everything from stdin to given output file. - * Returns 0 on success, otherwise failure. - */ int save_file_from_stdin(const char *output) { FILE *in = stdin, *out = fopen(output, "wb"); @@ -270,11 +261,6 @@ void check_firmware_versions(const struct firmware_image *image) FMAP_RW_FW_MAIN_B, image->ecrw_version_b); } -/* - * Generates a temporary file for snapshot of firmware image contents. - * - * Returns a file path if success, otherwise NULL. - */ const char *get_firmware_image_temp_file(const struct firmware_image *image, struct tempfile *tempfiles) { @@ -291,9 +277,6 @@ const char *get_firmware_image_temp_file(const struct firmware_image *image, return tmp_path; } -/* - * Frees the allocated resource from a firmware image object. - */ void free_firmware_image(struct firmware_image *image) { /* @@ -319,11 +302,6 @@ int reload_firmware_image(const char *file_path, struct firmware_image *image) return load_firmware_image(image, file_path, NULL); } -/* - * Finds a firmware section by given name in the firmware image. - * If successful, return zero and *section argument contains the address and - * size of the section; otherwise failure. - */ int find_firmware_section(struct firmware_section *section, const struct firmware_image *image, const char *section_name) @@ -343,9 +321,6 @@ int find_firmware_section(struct firmware_section *section, return 0; } -/* - * Returns true if the given FMAP section exists in the firmware image. - */ int firmware_section_exists(const struct firmware_image *image, const char *section_name) { @@ -354,14 +329,6 @@ int firmware_section_exists(const struct firmware_image *image, return section.data != NULL; } -/* - * Preserves (copies) the given section (by name) from image_from to image_to. - * The offset may be different, and the section data will be directly copied. - * If the section does not exist on either images, return as failure. - * If the source section is larger, contents on destination be truncated. - * If the source section is smaller, the remaining area is not modified. - * Returns 0 if success, non-zero if error. - */ int preserve_firmware_section(const struct firmware_image *image_from, struct firmware_image *image_to, const char *section_name) @@ -384,10 +351,6 @@ int preserve_firmware_section(const struct firmware_image *image_from, return 0; } -/* - * Finds the GBB (Google Binary Block) header on a given firmware image. - * Returns a pointer to valid GBB header, or NULL on not found. - */ const struct vb2_gbb_header *find_gbb(const struct firmware_image *image) { struct firmware_section section; @@ -418,27 +381,16 @@ static bool is_write_protection_enabled(struct updater_config *cfg, return wp_enabled; } -/* - * Returns true if the AP write protection is enabled on current system. - */ inline bool is_ap_write_protection_enabled(struct updater_config *cfg) { return is_write_protection_enabled(cfg, cfg->image.programmer, DUT_PROP_WP_SW_AP); } -/* - * Returns true if the EC write protection is enabled on current system. - */ inline bool is_ec_write_protection_enabled(struct updater_config *cfg) { return is_write_protection_enabled(cfg, cfg->ec_image.programmer, DUT_PROP_WP_SW_EC); } -/* - * Executes a command on current host and returns stripped command output. - * If the command has failed (exit code is not zero), returns an empty string. - * The caller is responsible for releasing the returned string. - */ char *host_shell(const char *command) { /* Currently all commands we use do not have large output. */ @@ -480,10 +432,6 @@ void prepare_servo_control(const char *control_name, bool on) free(cmd); } -/* - * Helper function to detect type of Servo board attached to host. - * Returns a string as programmer parameter on success, otherwise NULL. - */ char *host_detect_servo(const char **prepare_ctrl_name) { const char *servo_port = getenv(ENV_SERVOD_PORT); @@ -576,6 +524,7 @@ char *host_detect_servo(const char **prepare_ctrl_name) return ret; } + /* * Returns 1 if the programmers in image1 and image2 are the same. */ @@ -617,12 +566,6 @@ int load_system_firmware(struct updater_config *cfg, return r; } -/* - * Writes sections from a given firmware image to the system firmware. - * Regions should be NULL for writing the whole image, or a list of - * FMAP section names (and ended with a NULL). - * Returns 0 if success, non-zero if error. - */ int write_system_firmware(struct updater_config *cfg, const struct firmware_image *image, const char * const regions[], @@ -659,11 +602,6 @@ int write_system_firmware(struct updater_config *cfg, return r; } -/* - * Helper function to create a new temporary file. - * All files created will be removed remove_all_temp_files(). - * Returns the path of new file, or NULL on failure. - */ const char *create_temp_file(struct tempfile *head) { struct tempfile *new_temp; @@ -697,10 +635,6 @@ const char *create_temp_file(struct tempfile *head) return new_temp->filepath; } -/* - * Helper function to remove all files created by create_temp_file(). - * This is intended to be called only once at end of program execution. - */ void remove_all_temp_files(struct tempfile *head) { /* head itself is dummy and should not be removed. */ @@ -718,9 +652,6 @@ void remove_all_temp_files(struct tempfile *head) } } -/* - * Returns rootkey hash of firmware image, or NULL on failure. - */ const char *get_firmware_rootkey_hash(const struct firmware_image *image) { const struct vb2_gbb_header *gbb = NULL; @@ -743,11 +674,6 @@ const char *get_firmware_rootkey_hash(const struct firmware_image *image) return packed_key_sha1_string(rootkey); } -/* - * Overwrite the given offset of a section in the firmware image with the - * given values. - * Returns 0 on success, otherwise failure. - */ int overwrite_section(struct firmware_image *image, const char *fmap_section, size_t offset, size_t size, const uint8_t *new_values) From 92fb7b8d126d640a50ab19f9049905b221643c47 Mon Sep 17 00:00:00 2001 From: Yu-Ping Wu Date: Fri, 30 Aug 2024 20:38:25 +0800 Subject: [PATCH 034/102] tests/futility/test_update: Fix --sys_props argument The 0x10001 value is supposed to be for the tpm_fwver property, which is the second element of the --sys_props argument. The error was introduced in CL:1189249, but has never been noticed because the test case happens to still pass with the incorrectly specified argument. BUG=none TEST=make runfutiltests -j BRANCH=none (cherry picked from commit e56f3686526c54c45bf0044ab4068387a92e1cef) Change-Id: Ia05d441daa8848531892f686575ecd813e7ff916 Original-Signed-off-by: Yu-Ping Wu Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5822915 Original-Reviewed-by: Hung-Te Lin GitOrigin-RevId: e56f3686526c54c45bf0044ab4068387a92e1cef Cr-Build-Id: 8737823253384683697 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8737823253384683697 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5832135 Reviewed-by: Yu-Ping Wu Commit-Queue: Yu-Ping Wu Tested-by: ChromeOS Prod (Robot) --- tests/futility/test_update.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/futility/test_update.sh b/tests/futility/test_update.sh index 4337141a..80f21b1c 100755 --- a/tests/futility/test_update.sh +++ b/tests/futility/test_update.sh @@ -348,7 +348,7 @@ test_update "RW update -> fallback to RO+RW Full update" \ -i "${TO_IMAGE}" -t --wp=0 --sys_props 1,0x10002 test_update "RW update (incompatible platform)" \ "${FROM_IMAGE}" "!platform is not compatible" \ - -i "${LINK_BIOS}" -t --wp=1 --sys_props 0x10001 + -i "${LINK_BIOS}" -t --wp=1 --sys_props 0,0x10001 test_update "RW update (incompatible rootkey)" \ "${FROM_DIFFERENT_ROOTKEY_IMAGE}" "!RW signed by incompatible root key" \ From 88c49e9308e819e5151aa24c8b0f1605ba1d58c0 Mon Sep 17 00:00:00 2001 From: Yu-Ping Wu Date: Mon, 26 Aug 2024 11:59:12 +0800 Subject: [PATCH 035/102] futility: updater: Provide default DUT properties for emulation When --emulate is specified, all the dut_get_property() calls would fail. The option --sys_props exists to allow overriding the DUT properties. However, it's bothersome to specify it every time we want to run the updater with emulation. Therefore, provide default DUT properties for emulation. The active firmware slot is set to A. The TPM firmware version is set to 0x10001 (to pass TPM key compatibility check). The platform version is set to 0. Both hardware and software write protect states are assumed to be disabled for convenience. Some of the --sys_props arguments in test_update.sh are simplified or omitted. BUG=none TEST=make runfutiltests -j TEST=futility update --emulate image.bin -i new.bin --mode=factory BRANCH=none (cherry picked from commit 16e6aa8907fcfeaebfb479110abe1317b9111b2a) Change-Id: I25202ad05a5c2e671b416c42951be8cdafee5689 Original-Signed-off-by: Yu-Ping Wu Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5807011 Original-Reviewed-by: Hung-Te Lin GitOrigin-RevId: 16e6aa8907fcfeaebfb479110abe1317b9111b2a Cr-Build-Id: 8737823253384683697 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8737823253384683697 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5832136 Reviewed-by: Yu-Ping Wu Commit-Queue: Yu-Ping Wu Tested-by: ChromeOS Prod (Robot) --- futility/updater.c | 20 +++++++ tests/futility/test_update.sh | 101 +++++++++++++++++----------------- 2 files changed, 69 insertions(+), 52 deletions(-) diff --git a/futility/updater.c b/futility/updater.c index cf741229..2cef2bc5 100644 --- a/futility/updater.c +++ b/futility/updater.c @@ -70,6 +70,24 @@ static void override_dut_property(enum dut_property_type property_type, prop->value = value; } +/* + * Overrides DUT properties with default values. + * With emulation, dut_get_property() calls would fail without specifying the + * fake DUT properties via --sys_props. Therefore, this function provides + * reasonable default values for emulation. + */ +static void override_properties_with_default(struct updater_config *cfg) +{ + assert(cfg->emulation); + + override_dut_property(DUT_PROP_MAINFW_ACT, cfg, SLOT_A); + override_dut_property(DUT_PROP_TPM_FWVER, cfg, 0x10001); + override_dut_property(DUT_PROP_PLATFORM_VER, cfg, 0); + override_dut_property(DUT_PROP_WP_HW, cfg, 0); + override_dut_property(DUT_PROP_WP_SW_AP, cfg, 0); + override_dut_property(DUT_PROP_WP_SW_EC, cfg, 0); +} + /* * Overrides DUT properties from a given list. * The list should be string of integers eliminated by comma and/or space. @@ -1675,6 +1693,8 @@ int updater_setup_config(struct updater_config *cfg, if (prog_arg_emulation(cfg, arg, &check_single_image) < 0) return 1; + if (arg->emulation) + override_properties_with_default(cfg); if (arg->sys_props) override_properties_from_list(arg->sys_props, cfg); if (arg->write_protection) { diff --git a/tests/futility/test_update.sh b/tests/futility/test_update.sh index 80f21b1c..405ba493 100755 --- a/tests/futility/test_update.sh +++ b/tests/futility/test_update.sh @@ -261,11 +261,11 @@ test_update() { # Test Full update. test_update "Full update" \ "${FROM_IMAGE}" "${TMP}.expected.full" \ - -i "${TO_IMAGE}" --wp=0 --sys_props 0,0x10001 + -i "${TO_IMAGE}" --wp=0 test_update "Full update (incompatible platform)" \ "${FROM_IMAGE}" "!platform is not compatible" \ - -i "${LINK_BIOS}" --wp=0 --sys_props 0,0x10001 + -i "${LINK_BIOS}" --wp=0 test_update "Full update (TPM Anti-rollback: data key)" \ "${FROM_IMAGE}" "!Data key version rollback detected (2->1)" \ @@ -277,54 +277,53 @@ test_update "Full update (TPM Anti-rollback: kernel key)" \ test_update "Full update (TPM Anti-rollback: 0 as tpm_fwver)" \ "${FROM_IMAGE}" "${TMP}.expected.full" \ - -i "${TO_IMAGE}" --wp=0 --sys_props 0,0x0 + -i "${TO_IMAGE}" --wp=0 --sys_props ,0x0 test_update "Full update (TPM check failure due to invalid tpm_fwver)" \ "${FROM_IMAGE}" "!Invalid tpm_fwver: -1" \ - -i "${TO_IMAGE}" --wp=0 --sys_props 0,-1 + -i "${TO_IMAGE}" --wp=0 --sys_props ,-1 test_update "Full update (Skip TPM check with --force)" \ "${FROM_IMAGE}" "${TMP}.expected.full" \ - -i "${TO_IMAGE}" --wp=0 --sys_props 0,-1 --force + -i "${TO_IMAGE}" --wp=0 --sys_props ,-1 --force test_update "Full update (from stdin)" \ "${FROM_IMAGE}" "${TMP}.expected.full" \ - -i - --wp=0 --sys_props 0,-1 --force <"${TO_IMAGE}" + -i - --wp=0 --sys_props ,-1 --force <"${TO_IMAGE}" test_update "Full update (GBB=0 -> 0)" \ "${FROM_IMAGE}.gbb0" "${TMP}.expected.full.gbb0" \ - -i "${TO_IMAGE}" --wp=0 --sys_props 0,0x10001 + -i "${TO_IMAGE}" --wp=0 test_update "Full update (GBB flags -> 0x27)" \ "${FROM_IMAGE}" "${TMP}.expected.full.gbb0x27" \ - -i "${TO_IMAGE}" --gbb_flags=0x27 --wp=0 --sys_props 0,0x10001 + -i "${TO_IMAGE}" --gbb_flags=0x27 --wp=0 test_update "Full update (--host_only)" \ "${FROM_IMAGE}" "${TMP}.expected.full" \ - -i "${TO_IMAGE}" --wp=0 --sys_props 0,0x10001 \ - --host_only --ec_image non-exist.bin + -i "${TO_IMAGE}" --wp=0 --host_only --ec_image non-exist.bin test_update "Full update (GBB1.2 hwid digest)" \ "${FROM_IMAGE}" "${TMP}.expected.full.gbb12" \ - -i "${TO_IMAGE_GBB12}" --wp=0 --sys_props 0,0x10001 + -i "${TO_IMAGE_GBB12}" --wp=0 test_update "Full update (Preserve VPD using FMAP_AREA_PRESERVE)" \ "${FROM_IMAGE}" "${TMP}.expected.full.empty_rw_vpd" \ - -i "${TO_IMAGE_WIPE_RW_VPD}" --wp=0 --sys_props 0,0x10001 + -i "${TO_IMAGE_WIPE_RW_VPD}" --wp=0 # Test RW-only update. test_update "RW update" \ "${FROM_IMAGE}" "${TMP}.expected.rw" \ - -i "${TO_IMAGE}" --wp=1 --sys_props 0,0x10001 + -i "${TO_IMAGE}" --wp=1 test_update "RW update (incompatible platform)" \ "${FROM_IMAGE}" "!platform is not compatible" \ - -i "${LINK_BIOS}" --wp=1 --sys_props 0,0x10001 + -i "${LINK_BIOS}" --wp=1 test_update "RW update (incompatible rootkey)" \ "${FROM_DIFFERENT_ROOTKEY_IMAGE}" "!RW signed by incompatible root key" \ - -i "${TO_IMAGE}" --wp=1 --sys_props 0,0x10001 + -i "${TO_IMAGE}" --wp=1 test_update "RW update (TPM Anti-rollback: data key)" \ "${FROM_IMAGE}" "!Data key version rollback detected (2->1)" \ @@ -337,22 +336,22 @@ test_update "RW update (TPM Anti-rollback: kernel key)" \ # Test Try-RW update (vboot2). test_update "RW update (A->B)" \ "${FROM_IMAGE}" "${TMP}.expected.b" \ - -i "${TO_IMAGE}" -t --wp=1 --sys_props 0,0x10001 + -i "${TO_IMAGE}" -t --wp=1 --sys_props 0 test_update "RW update (B->A)" \ "${FROM_IMAGE}" "${TMP}.expected.a" \ - -i "${TO_IMAGE}" -t --wp=1 --sys_props 1,0x10001 + -i "${TO_IMAGE}" -t --wp=1 --sys_props 1 test_update "RW update -> fallback to RO+RW Full update" \ "${FROM_IMAGE}" "${TMP}.expected.full" \ -i "${TO_IMAGE}" -t --wp=0 --sys_props 1,0x10002 test_update "RW update (incompatible platform)" \ "${FROM_IMAGE}" "!platform is not compatible" \ - -i "${LINK_BIOS}" -t --wp=1 --sys_props 0,0x10001 + -i "${LINK_BIOS}" -t --wp=1 test_update "RW update (incompatible rootkey)" \ "${FROM_DIFFERENT_ROOTKEY_IMAGE}" "!RW signed by incompatible root key" \ - -i "${TO_IMAGE}" -t --wp=1 --sys_props 0,0x10001 + -i "${TO_IMAGE}" -t --wp=1 test_update "RW update (TPM Anti-rollback: data key)" \ "${FROM_IMAGE}" "!Data key version rollback detected (2->1)" \ @@ -369,36 +368,36 @@ test_update "RW update -> fallback to RO+RW Full update (TPM Anti-rollback)" \ # Test 'factory mode' test_update "Factory mode update (WP=0)" \ "${FROM_IMAGE}" "${TMP}.expected.full" \ - -i "${TO_IMAGE}" --wp=0 --sys_props 0,0x10001 --mode=factory + -i "${TO_IMAGE}" --wp=0 --mode=factory test_update "Factory mode update (WP=0)" \ "${FROM_IMAGE}" "${TMP}.expected.full" \ - --factory -i "${TO_IMAGE}" --wp=0 --sys_props 0,0x10001 + --factory -i "${TO_IMAGE}" --wp=0 test_update "Factory mode update (WP=1)" \ "${FROM_IMAGE}" "!remove write protection for factory mode" \ - -i "${TO_IMAGE}" --wp=1 --sys_props 0,0x10001 --mode=factory + -i "${TO_IMAGE}" --wp=1 --mode=factory test_update "Factory mode update (WP=1)" \ "${FROM_IMAGE}" "!remove write protection for factory mode" \ - --factory -i "${TO_IMAGE}" --wp=1 --sys_props 0,0x10001 + --factory -i "${TO_IMAGE}" --wp=1 test_update "Factory mode update (GBB=0 -> 0x39)" \ "${FROM_IMAGE}.gbb0" "${TMP}.expected.full" \ - --factory -i "${TO_IMAGE}" --wp=0 --sys_props 0,0x10001 + --factory -i "${TO_IMAGE}" --wp=0 # Test 'AP RO locked with verification turned on' test_update "AP RO locked update (locked, SI_DESC is different)" \ "${FROM_IMAGE}.locked" "${TMP}.expected.rw.locked" \ - -i "${TO_IMAGE}" --wp=0 --debug --sys_props 0,0x10001 + -i "${TO_IMAGE}" --wp=0 --debug test_update "AP RO locked update (locked, SI_DESC is the same)" \ "${FROM_IMAGE}.locked_same_desc" "${TMP}.expected.full" \ - -i "${TO_IMAGE}" --wp=0 --debug --sys_props 0,0x10001 + -i "${TO_IMAGE}" --wp=0 --debug test_update "AP RO locked update (unlocked)" \ "${FROM_IMAGE}.unlocked" "${TMP}.expected.full" \ - -i "${TO_IMAGE}" --wp=0 --debug --sys_props 0,0x10001 + -i "${TO_IMAGE}" --wp=0 --debug # Test legacy update test_update "Legacy update" \ @@ -408,67 +407,67 @@ test_update "Legacy update" \ # Test quirks test_update "Full update (wrong size)" \ "${FROM_IMAGE}.large" "!Failed writing firmware" \ - -i "${TO_IMAGE}" --wp=0 --sys_props 0,0x10001 \ + -i "${TO_IMAGE}" --wp=0 \ --quirks unlock_csme_eve,eve_smm_store test_update "Full update (--quirks enlarge_image)" \ "${FROM_IMAGE}.large" "${TMP}.expected.large" --quirks enlarge_image \ - -i "${TO_IMAGE}" --wp=0 --sys_props 0,0x10001 + -i "${TO_IMAGE}" --wp=0 test_update "Full update (multi-line --quirks enlarge_image)" \ "${FROM_IMAGE}.large" "${TMP}.expected.large" --quirks ' enlarge_image - ' -i "${TO_IMAGE}" --wp=0 --sys_props 0,0x10001 + ' -i "${TO_IMAGE}" --wp=0 test_update "Full update (--quirks unlock_csme_eve)" \ "${FROM_IMAGE}" "${TMP}.expected.me_unlocked_eve" \ --quirks unlock_csme_eve \ - -i "${TO_IMAGE}" --wp=0 --sys_props 0,0x10001 + -i "${TO_IMAGE}" --wp=0 test_update "Full update (failure by --quirks min_platform_version)" \ "${FROM_IMAGE}" "!Need platform version >= 3 (current is 2)" \ --quirks min_platform_version=3 \ - -i "${TO_IMAGE}" --wp=0 --sys_props 0,0x10001,2 + -i "${TO_IMAGE}" --wp=0 --sys_props ,,2 test_update "Full update (--quirks min_platform_version)" \ "${FROM_IMAGE}" "${TMP}.expected.full" \ --quirks min_platform_version=3 \ - -i "${TO_IMAGE}" --wp=0 --sys_props 0,0x10001,3 + -i "${TO_IMAGE}" --wp=0 --sys_props ,,3 test_update "Full update (incompatible platform)" \ "${FROM_IMAGE}".unpatched "!platform is not compatible" \ - -i "${TO_IMAGE}" --wp=0 --sys_props 0,0x10001 + -i "${TO_IMAGE}" --wp=0 test_update "Full update (--quirks no_check_platform)" \ "${FROM_IMAGE}".unpatched "${TMP}.expected.full" \ --quirks no_check_platform \ - -i "${TO_IMAGE}" --wp=0 --sys_props 0,0x10001 + -i "${TO_IMAGE}" --wp=0 test_update "Full update (--quirks preserve_me with non-host programmer)" \ "${FROM_IMAGE}" "${TMP}.expected.full" \ --quirks preserve_me \ - -i "${TO_IMAGE}" --wp=0 --sys_props 0,0x10001 \ + -i "${TO_IMAGE}" --wp=0 \ -p raiden_debug_spi:target=AP test_update "Full update (--quirks preserve_me)" \ "${FROM_IMAGE}" "${TMP}.expected.full" \ --quirks preserve_me \ - -i "${TO_IMAGE}" --wp=0 --sys_props 0,0x10001 + -i "${TO_IMAGE}" --wp=0 test_update "Full update (--quirks preserve_me, autoupdate)" \ "${FROM_IMAGE}" "${TMP}.expected.me_preserved" \ --quirks preserve_me -m autoupdate \ - -i "${TO_IMAGE}" --wp=0 --sys_props 0,0x10001 + -i "${TO_IMAGE}" --wp=0 test_update "Full update (--quirks preserve_me, deferupdate_hold)" \ "${FROM_IMAGE}" "${TMP}.expected.me_preserved" \ --quirks preserve_me -m deferupdate_hold \ - -i "${TO_IMAGE}" --wp=0 --sys_props 0,0x10001 + -i "${TO_IMAGE}" --wp=0 test_update "Full update (--quirks preserve_me, factory)" \ "${FROM_IMAGE}" "${TMP}.expected.full" \ --quirks preserve_me -m factory \ - -i "${TO_IMAGE}" --wp=0 --sys_props 0,0x10001 + -i "${TO_IMAGE}" --wp=0 # Test manifest. echo "TEST: Manifest (--manifest, -i, image.bin)" @@ -502,7 +501,7 @@ cmp \ cp -f "${TO_IMAGE}" "${A}/image.bin" test_update "Full update (--archive, single package)" \ "${FROM_IMAGE}" "${TMP}.expected.full" \ - -a "${A}" --wp=0 --sys_props 0,0x10001,3 + -a "${A}" --wp=0 --sys_props ,,3 echo "TEST: Output (--mode=output)" mkdir -p "${TMP}.output" @@ -521,25 +520,25 @@ cp -f "${TMP}.to/VBLOCK_B" "${A}/keyset/vblock_B.CL" test_update "Full update (--archive, custom label, no VPD)" \ "${A}/image.bin" "!Need VPD set for custom" \ - -a "${A}" --wp=0 --sys_props 0,0x10001,3 + -a "${A}" --wp=0 --sys_props ,,3 test_update "Full update (--archive, custom label, no VPD - factory mode)" \ "${LINK_BIOS}" "${A}/image.bin" \ - -a "${A}" --wp=0 --sys_props 0,0x10001,3 --mode=factory + -a "${A}" --wp=0 --sys_props ,,3 --mode=factory test_update "Full update (--archive, custom label, no VPD - quirk mode)" \ "${LINK_BIOS}" "${A}/image.bin" \ - -a "${A}" --wp=0 --sys_props 0,0x10001,3 \ + -a "${A}" --wp=0 --sys_props ,,3 \ --quirks=allow_empty_custom_label_tag test_update "Full update (--archive, custom label, single package)" \ "${A}/image.bin" "${LINK_BIOS}" \ - -a "${A}" --wp=0 --sys_props 0,0x10001,3 --signature_id=CL + -a "${A}" --wp=0 --sys_props ,,3 --signature_id=CL CL_TAG="CL" PATH="${A}/bin:${PATH}" \ test_update "Full update (--archive, custom label, fake vpd)" \ "${A}/image.bin" "${LINK_BIOS}" \ - -a "${A}" --wp=0 --sys_props 0,0x10001,3 + -a "${A}" --wp=0 --sys_props ,,3 echo "TEST: Output (-a, --mode=output)" mkdir -p "${TMP}.outa" @@ -631,7 +630,7 @@ if type cbfstool >/dev/null 2>&1; then -f "${TMP}.smm" -t raw -b 0x1bf000 test_update "Legacy update (--quirks eve_smm_store)" \ "${TMP}.from.smm" "${TMP}.expected.full_smm" \ - -i "${TO_IMAGE}" --wp=0 --sys_props 0,0x10001 \ + -i "${TO_IMAGE}" --wp=0 \ --quirks eve_smm_store echo "min_platform_version=3" >"${TMP}.quirk" @@ -650,17 +649,15 @@ fi if type ifdtool >/dev/null 2>&1; then test_update "Full update (--quirks unlock_csme, IFD chipset)" \ "${FROM_IMAGE}" "${TMP}.expected.me_unlocked.ifd_chipset" \ - --quirks unlock_csme -i "${TO_IMAGE}.ifd_chipset" \ - --wp=0 --sys_props 0,0x10001 + --quirks unlock_csme -i "${TO_IMAGE}.ifd_chipset" --wp=0 test_update "Full update (--quirks unlock_csme, IFD bin path)" \ "${FROM_IMAGE}" "${TMP}.expected.me_unlocked.ifd_path" \ - --quirks unlock_csme -i "${TO_IMAGE}.ifd_path" \ - --wp=0 --sys_props 0,0x10001 + --quirks unlock_csme -i "${TO_IMAGE}.ifd_path" --wp=0 test_update "Full update (--unlock_me)" \ "${FROM_IMAGE}" "${TMP}.expected.me_unlocked.ifd_chipset" \ - --unlock_me -i "${TO_IMAGE}.ifd_chipset" --wp=0 --sys_props 0,0x10001 + --unlock_me -i "${TO_IMAGE}.ifd_chipset" --wp=0 echo "TEST: Output (--mode=output, --quirks unlock_csme)" "${FUTILITY}" update -i "${TMP}.expected.ifd_chipset" --mode=output \ From f8bfa28ca4624adc6d05d2ab5f49a24cb17e2cfa Mon Sep 17 00:00:00 2001 From: Benjamin Shai Date: Tue, 3 Sep 2024 20:39:53 +0000 Subject: [PATCH 036/102] signing: miniOS signing in docker. For some reason, lsblk reports null partition types in docker, even in privileged (https://forums.docker.com/t/why-does-lsblk-report-partition-as-null-from-within-a-docker-container/139393). Prefer cgpt for checking the partition type, which appears to work, and fallback on lsblk (because the legacy signers only have that). This commit also removed the check for the private key on disk because the key lives in Cloud KMS, adds a newline to an info statement that was getting concatenated to the previous log message, and unrolls the loop over all loop devices (opting to just explicitly check the two minios loop devices). BUG=b:363466852 BRANCH=None TEST=manual (cherry picked from commit dc5102f2f0614ec62924fa69cc1e364a9b73e391) Change-Id: I044c626dfac5ae7115b9f6b7e65e8303595544fb Original-Signed-off-by: Benjamin Shai Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5833916 Original-Reviewed-by: Jae Hoon Kim Original-Reviewed-by: George Engelbrecht GitOrigin-RevId: dc5102f2f0614ec62924fa69cc1e364a9b73e391 Cr-Build-Id: 8737642059976117361 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8737642059976117361 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5837673 Commit-Queue: Yu-Ping Wu Tested-by: ChromeOS Prod (Robot) Reviewed-by: Yu-Ping Wu --- scripts/image_signing/sign_official_build.sh | 109 +++++++++++-------- 1 file changed, 64 insertions(+), 45 deletions(-) diff --git a/scripts/image_signing/sign_official_build.sh b/scripts/image_signing/sign_official_build.sh index 0c7bd308..6fa621eb 100755 --- a/scripts/image_signing/sign_official_build.sh +++ b/scripts/image_signing/sign_official_build.sh @@ -23,7 +23,7 @@ set -e # Our random local constants. -MINIOS_KERNEL_GUID="09845860-705f-4bb5-b16c-8a8a099caf52" +MINIOS_KERNEL_GUID="09845860-705F-4BB5-B16C-8A8A099CAF52" FIRMWARE_VERSION=1 KERNEL_VERSION=1 @@ -1038,53 +1038,24 @@ update_recovery_kernel_hash() { --config "${new_kernel_config}" } -# Re-sign miniOS kernels with new keys. -# Args: LOOPDEV MINIOS_A_KEYBLOCK MINIOS_B_KEYBLOCK PRIVKEY -resign_minios_kernels() { - local loopdev="$1" - local minios_a_keyblock="$2" - local minios_b_keyblock="$3" - local priv_key="$4" - - info "Searching for miniOS kernels to resign..." - - local loop_minios - for loop_minios in "${loopdev}p"*; do - local part_type_guid - part_type_guid=$(sudo lsblk -rnb -o PARTTYPE "${loop_minios}") - if [[ "${part_type_guid}" != "${MINIOS_KERNEL_GUID}" ]]; then - continue - fi - - local keyblock - if [[ "${loop_minios}" == "${loopdev}p9" ]]; then - keyblock="${minios_a_keyblock}" - elif [[ "${loop_minios}" == "${loopdev}p10" ]]; then - keyblock="${minios_b_keyblock}" - else - error "Unexpected miniOS partition ${loop_minios}" - return 1 - fi - - # Skip miniOS partitions which are empty. This happens when miniOS - # kernels aren't written to the partitions because the feature is not - # enabled. - if ! sudo_futility dump_kernel_config "${loop_minios}"; then - info "Skipping empty miniOS partition ${loop_minios}." - continue - fi - - # Delay checking that keyblock and private key exist until we are certain - # of a valid miniOS partition. Images that don't support miniOS might not - # provide these. (This check is repeated twice, but that's okay.) +# Resign a single miniOS kernel partition. +# Args: LOOP_MINIOS KEYBLOCK PRIVKEY +resign_minios_kernel() { + local loop_minios="$1" + local keyblock="$2" + local priv_key="$3" + + if sudo_futility dump_kernel_config "${loop_minios}"; then + # Delay checking that keyblock exists until we are certain of a valid miniOS + # partition. Images that don't support miniOS might not provide these. + # (This check is repeated twice, but that's okay.) + # Update (9/3/24): we no longer check if the private key exists on disk + # because it may live in Cloud KMS instead, opting instead to let futility + # below fail if the key is missing. if [[ ! -e "${keyblock}" ]]; then error "Resign miniOS: keyblock doesn't exist: ${keyblock}" return 1 fi - if [[ ! -e "${priv_key}" ]]; then - error "Resign miniOS: private key doesn't exist: ${priv_key}" - return 1 - fi # Assume this is a miniOS kernel. local minios_kernel_version=$((KERNEL_VERSION >> 24)) @@ -1093,12 +1064,60 @@ resign_minios_kernels() { --signprivate "${priv_key}" \ --version "${minios_kernel_version}" \ --oldblob "${loop_minios}"; then + echo info "Resign miniOS ${loop_minios}: done" else error "Resign miniOS ${loop_minios}: failed" return 1 fi - done + else + info "Skipping empty miniOS partition ${loop_minios}." + fi +} + +# Get the partition type of the loop device. +get_partition_type() { + local loopdev=$1 + local device=$2 + # Prefer cgpt, fall back on lsblk. + if command -v cgpt &> /dev/null; then + echo "$(cgpt show -i "${device}" -t "${loopdev}")" + else + echo "$(sudo lsblk -rnb -o PARTTYPE "${loopdev}p${device}")" + fi +} + +# Re-sign miniOS kernels with new keys. +# Args: LOOPDEV MINIOS_A_KEYBLOCK MINIOS_B_KEYBLOCK PRIVKEY +resign_minios_kernels() { + local loopdev="$1" + local minios_a_keyblock="$2" + local minios_b_keyblock="$3" + local priv_key="$4" + + info "Searching for miniOS kernels to resign..." + + # Attempt to sign miniOS A and miniOS B partitions, one at a time. + # miniOS A - loop device 9. + local loop_minios_a="${loopdev}p9" + local part_type_a + part_type_a="$(get_partition_type "${loopdev}" 9)" + # miniOS B - loop device 10. + local loop_minios_b="${loopdev}p10" + local part_type_b + part_type_b="$(get_partition_type "${loopdev}" 9)" + + # Make sure the loop devices have a miniOS partition type. + if [[ "${part_type_a^^}" == "${MINIOS_KERNEL_GUID}" ]]; then + if ! resign_minios_kernel "${loop_minios_a}" "${minios_a_keyblock}" "${priv_key}"; then + return 1 + fi + fi + if [[ "${part_type_b^^}" == "${MINIOS_KERNEL_GUID}" ]]; then + if ! resign_minios_kernel "${loop_minios_b}" "${minios_b_keyblock}" "${priv_key}"; then + return 1 + fi + fi } # Update the legacy bootloader templates in EFI partition if available. From 0abb99b3f67de40b2b59ec7b2003312e596532f3 Mon Sep 17 00:00:00 2001 From: Benjamin Shai Date: Thu, 5 Sep 2024 19:01:54 +0000 Subject: [PATCH 037/102] signing: clean up owners Remove googlers no longer working here and add bshai@. BUG=None BRANCH=None TEST=None (cherry picked from commit 83f845b3b5dadec27307cb772490d0203d42a78e) Change-Id: I2195ceea2e94a7659784453e60a46099d61b183d Original-Signed-off-by: Benjamin Shai Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5840434 Original-Reviewed-by: George Engelbrecht Original-Commit-Queue: George Engelbrecht Original-Tested-by: George Engelbrecht GitOrigin-RevId: 83f845b3b5dadec27307cb772490d0203d42a78e Cr-Build-Id: 8737551462803103057 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8737551462803103057 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5841357 Tested-by: ChromeOS Prod (Robot) Commit-Queue: Jae Hoon Kim Reviewed-by: George Engelbrecht --- scripts/OWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/OWNERS b/scripts/OWNERS index 77bc0a0a..12be07bb 100644 --- a/scripts/OWNERS +++ b/scripts/OWNERS @@ -1,4 +1,4 @@ vapier@chromium.org engeg@google.com -roydsouza@chromium.org allenwebb@google.com +bshai@google.com From 2772b574c8bc6e53adddc1f4faf9513242e74d13 Mon Sep 17 00:00:00 2001 From: Jae Hoon Kim Date: Thu, 5 Sep 2024 17:50:32 +0000 Subject: [PATCH 038/102] Fix partition type check for miniOS B .. this should use partition 10 rather than 9. BUG=b:363466852 TEST=none BRANCH=None (cherry picked from commit f5924321909da88879e053a61a5b823de8858c44) Change-Id: I15364511f982c9410af0a5e3397655da4fd49d4c Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5837192 Original-Tested-by: George Engelbrecht Original-Auto-Submit: Jae Hoon Kim Original-Commit-Queue: Jae Hoon Kim Original-Commit-Queue: George Engelbrecht Original-Tested-by: Jae Hoon Kim Original-Commit-Queue: Benjamin Shai Original-Reviewed-by: Benjamin Shai Original-Reviewed-by: George Engelbrecht GitOrigin-RevId: f5924321909da88879e053a61a5b823de8858c44 Cr-Build-Id: 8737551462803103057 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8737551462803103057 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5841358 Reviewed-by: George Engelbrecht Tested-by: Jae Hoon Kim Tested-by: ChromeOS Prod (Robot) Commit-Queue: Jae Hoon Kim --- scripts/image_signing/sign_official_build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/image_signing/sign_official_build.sh b/scripts/image_signing/sign_official_build.sh index 6fa621eb..0f31bcf9 100755 --- a/scripts/image_signing/sign_official_build.sh +++ b/scripts/image_signing/sign_official_build.sh @@ -1105,7 +1105,7 @@ resign_minios_kernels() { # miniOS B - loop device 10. local loop_minios_b="${loopdev}p10" local part_type_b - part_type_b="$(get_partition_type "${loopdev}" 9)" + part_type_b="$(get_partition_type "${loopdev}" 10)" # Make sure the loop devices have a miniOS partition type. if [[ "${part_type_a^^}" == "${MINIOS_KERNEL_GUID}" ]]; then From 6cada6496a77337185d6f8bcc9a9c3e4937dea65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Grzesik?= Date: Fri, 23 Aug 2024 14:25:36 +0000 Subject: [PATCH 039/102] avb: fix subtraction overflow in init boot offset calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This small patch swaps subtraction operants in init_boot_size. The later operant always had a greater value than the left operant. This causes the value to overflow and reach the values in neighborhood of ~4GB, which is invalid. This is a nit rather than fix, since the sole use of the value is added back to init_boot_offset, which overflows back to a correct value. BUG=b:359340876 TEST=Build FW and boot android BRANCH=firmware-android-15949.B Change-Id: I838675bed8dfb94dfdce4f9c1e147cc3128a04b6 Signed-off-by: Bartłomiej Grzesik Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5809178 Reviewed-by: Konrad Adamczyk Reviewed-by: Jakub Czapiga Reviewed-by: Grzegorz Bernacki --- firmware/avb/vboot_avb_ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/avb/vboot_avb_ops.c b/firmware/avb/vboot_avb_ops.c index 8e76b2d1..55b158f9 100644 --- a/firmware/avb/vboot_avb_ops.c +++ b/firmware/avb/vboot_avb_ops.c @@ -353,7 +353,7 @@ static vb2_error_t vb2_load_init_boot_ramdisk(struct vb2_context *ctx, GptData * return VB2_ERROR_LOAD_PARTITION_READ_BODY; } - params->init_boot_size = params->init_boot_offset - *bytes_used; + params->init_boot_size = *bytes_used - params->init_boot_offset; return VB2_SUCCESS; } From 07270417d3824db7233b4a85cf2c8363744d873d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Grzesik?= Date: Tue, 27 Aug 2024 13:25:54 +0000 Subject: [PATCH 040/102] cgptlib: Add helper function for finding pvmfw MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This changes add a new function for finding pvmfw partition from disk. This function will used by the following patches. BUG=b:354045389 BUG=b:359340876 TEST=Check if the contents matches with partition BRANCH=firmware-android-15949.B Change-Id: I4814c62a52cb2cdc0682964527d214a94f6375e3 Signed-off-by: Bartłomiej Grzesik Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5816953 Reviewed-by: Konrad Adamczyk Reviewed-by: Jakub Czapiga --- firmware/include/gpt.h | 1 + firmware/lib/cgptlib/cgptlib.c | 28 ++++++++++++++++++++++++++ firmware/lib/cgptlib/include/cgptlib.h | 11 ++++++++++ 3 files changed, 40 insertions(+) diff --git a/firmware/include/gpt.h b/firmware/include/gpt.h index 65c0666e..0c7eff5d 100644 --- a/firmware/include/gpt.h +++ b/firmware/include/gpt.h @@ -69,6 +69,7 @@ extern "C" { #define GPT_ENT_NAME_ANDROID_INIT_BOOT "init_boot" #define GPT_ENT_NAME_ANDROID_VENDOR_BOOT "vendor_boot" #define GPT_ENT_NAME_ANDROID_BOOT "boot" +#define GPT_ENT_NAME_ANDROID_PVMFW "pvmfw" #define GPT_ENT_NAME_ANDROID_A_SUFFIX "_a" #define GPT_ENT_NAME_ANDROID_B_SUFFIX "_b" diff --git a/firmware/lib/cgptlib/cgptlib.c b/firmware/lib/cgptlib/cgptlib.c index 4784a780..73fe80ef 100644 --- a/firmware/lib/cgptlib/cgptlib.c +++ b/firmware/lib/cgptlib/cgptlib.c @@ -356,3 +356,31 @@ int GptFindVendorBoot(GptData *gpt, uint64_t *start_sector, uint64_t *size) free(name); return ret; } + +int GptFindPvmfw(GptData *gpt, uint64_t *start_sector, uint64_t *size) +{ + int ret; + char *name; + char *suffix = NULL; + + ret = GptGetActiveKernelPartitionSuffix(gpt, &suffix); + if (ret != GPT_SUCCESS) { + VB2_DEBUG("Unable to get kernel partition suffix\n"); + return ret; + } + + /* Construct name */ + name = JoinStr(GPT_ENT_NAME_ANDROID_PVMFW, suffix); + free(suffix); + if (name == NULL) { + VB2_DEBUG("Unable to construct pvmfw partition name\n"); + return GPT_ERROR_INVALID_ENTRIES; + } + + ret = GptFindOffsetByName(gpt, name, start_sector, size); + if (ret != GPT_SUCCESS) + VB2_DEBUG("Unable to find the %s partition\n", name); + + free(name); + return ret; +} diff --git a/firmware/lib/cgptlib/include/cgptlib.h b/firmware/lib/cgptlib/include/cgptlib.h index b49930f5..f5f2e1f1 100644 --- a/firmware/lib/cgptlib/include/cgptlib.h +++ b/firmware/lib/cgptlib/include/cgptlib.h @@ -44,4 +44,15 @@ int GptFindInitBoot(GptData *gpt, uint64_t *start_sector, uint64_t *size); */ int GptFindVendorBoot(GptData *gpt, uint64_t *start_sector, uint64_t *size); +/** + * Find pvmfw partition for selected slot. + * Must be called after GptNextKernelEntry. + * + * On return the start_sector parameter contains the LBA sector for the start + * of the pvmfw partition, and the size parameter contains the size of the + * pvmfw partition in LBA sectors. + * Returns GPT_SUCCESS if successful. + */ +int GptFindPvmfw(GptData *gpt, uint64_t *start_sector, uint64_t *size); + #endif /* VBOOT_REFERENCE_CGPTLIB_H_ */ From aaa4f962b63b416eec54a3dee9125f3638adc2ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Grzesik?= Date: Tue, 27 Aug 2024 13:31:34 +0000 Subject: [PATCH 041/102] 2api: Expand vb2_kernel_params for pvmfw loading MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change expands vb2_kernel_params struct with two new fields that are going to used by following patches in both vboot and depthcharge. The fields include the offset of the pvmfw in the kernel_buffer and its size. BUG=b:354045389 BUG=b:359340876 TEST=Build BRANCH=firmware-android-15949.B Change-Id: Ia9cc02a66b4f8d774dfd6846c995fcfc984a69ec Signed-off-by: Bartłomiej Grzesik Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5816954 Reviewed-by: Konrad Adamczyk Reviewed-by: Jakub Czapiga --- firmware/2lib/include/2api.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/firmware/2lib/include/2api.h b/firmware/2lib/include/2api.h index 278a22e7..ba7b52b0 100644 --- a/firmware/2lib/include/2api.h +++ b/firmware/2lib/include/2api.h @@ -607,6 +607,14 @@ struct vb2_kernel_params { void *kernel_buffer; /* Size of kernel buffer in bytes. */ uint32_t kernel_buffer_size; + /* Destination buffer for pvmfw. Shall be ignored if pvmfw_size is 0 */ + void *pvmfw_buffer; + /* + * Size of pvmfw buffer in bytes. If non-zero then implementation shall + * try to load pvmfw to the pvmfw buffer. If successful the pvmfw_size + * shall be set to the correct non-zero value. + */ + uint32_t pvmfw_buffer_size; /* * Outputs from vb2api_load_kernel(); valid only if it returns success. @@ -631,6 +639,9 @@ struct vb2_kernel_params { uint32_t init_boot_size; /* Offset (in bytes) to the region with vboot cmdline parameters. */ uint32_t vboot_cmdline_offset; + + /* Size of pvmfw partition in bytes in pvmfw buffer. */ + uint32_t pvmfw_size; }; /*****************************************************************************/ From 5a174c68cd1a610aff5d470cc7261dbb5af2ee27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Grzesik?= Date: Tue, 27 Aug 2024 13:33:59 +0000 Subject: [PATCH 042/102] avb: Add pvmfw verification and loading to memory. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change extends avb to load and verify pvmfw into provided buffer. BUG=b:354045389 BUG=b:359340876 TEST=Check if the contents of the memory matches BRANCH=firmware-android-15949.B Cq-Depend: chromium:5816953 Cq-Depend: chromium:5816954 Change-Id: Id60362b83b91b3ec80153c557dc57266f9801903 Signed-off-by: Bartłomiej Grzesik Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5816955 Reviewed-by: Konrad Adamczyk Reviewed-by: Jakub Czapiga --- firmware/2lib/2load_kernel.c | 19 +++++++++- firmware/avb/vboot_avb_ops.c | 69 ++++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/firmware/2lib/2load_kernel.c b/firmware/2lib/2load_kernel.c index 9943bf71..abe444ef 100644 --- a/firmware/2lib/2load_kernel.c +++ b/firmware/2lib/2load_kernel.c @@ -482,10 +482,11 @@ static vb2_error_t vb2_load_avb_android_partition( char *ab_suffix = NULL; AvbSlotVerifyData *verify_data = NULL; AvbOps *avb_ops; - static const char * const boot_partitions[] = { + const char *boot_partitions[] = { GPT_ENT_NAME_ANDROID_BOOT, GPT_ENT_NAME_ANDROID_INIT_BOOT, GPT_ENT_NAME_ANDROID_VENDOR_BOOT, + GPT_ENT_NAME_ANDROID_PVMFW, NULL, }; AvbSlotVerifyFlags avb_flags; @@ -494,6 +495,22 @@ static vb2_error_t vb2_load_avb_android_partition( int need_keyblock_valid = need_valid_keyblock(ctx); char *verified_str; + /* + * Check if the buffer is zero sized (ie. pvmfw loading is not + * requested) or the pvmfw partition does not exist. If so skip + * loading and verifying it. + */ + uint64_t pvmfw_start; + uint64_t pvmfw_size; + if (params->pvmfw_buffer_size == 0 || + GptFindPvmfw(gpt, &pvmfw_start, &pvmfw_size) != GPT_SUCCESS) { + if (params->pvmfw_buffer_size != 0) + VB2_DEBUG("Couldn't find pvmfw partition. Ignoring.\n"); + + boot_partitions[3] = NULL; + params->pvmfw_size = 0; + } + ret = GptGetActiveKernelPartitionSuffix(gpt, &ab_suffix); if (ret != GPT_SUCCESS) { VB2_DEBUG("Unable to get kernel partition suffix\n"); diff --git a/firmware/avb/vboot_avb_ops.c b/firmware/avb/vboot_avb_ops.c index 55b158f9..4ab8f878 100644 --- a/firmware/avb/vboot_avb_ops.c +++ b/firmware/avb/vboot_avb_ops.c @@ -263,6 +263,65 @@ static AvbIOResult validate_vbmeta_public_key(AvbOps *ops, return AVB_IO_RESULT_OK; } +static vb2_error_t vb2_load_pvmfw(struct vb2_context *ctx, GptData *gpt, + struct vb2_kernel_params *params, + vb2ex_disk_handle_t disk_handle) +{ + VbExStream_t stream; + uint64_t part_start, part_size; + uint32_t read_ms = 0, start_ts; + uint64_t part_bytes; + uint8_t *part_pvmfw_buf = (uint8_t *) params->pvmfw_buffer; + vb2_error_t res = VB2_ERROR_LOAD_PARTITION_READ_BODY; + + if (params->pvmfw_buffer_size == 0) { + VB2_DEBUG("No buffer for pvmfw partition\n"); + return VB2_ERROR_INVALID_PARAMETER; + } + + /* Fail there is no pvmfw partition */ + if (GptFindPvmfw(gpt, &part_start, &part_size) != GPT_SUCCESS) { + VB2_DEBUG("Unable to find pvmfw partition\n"); + return VB2_ERROR_LOAD_PARTITION_READ_BODY; + } + + if (VbExStreamOpen(disk_handle, part_start, part_size, + &stream)) { + VB2_DEBUG("Unable to open disk handle.\n"); + return res; + } + + part_bytes = gpt->sector_bytes * part_size; + /* Check if the pvmfw buffer is big enough */ + if (part_bytes > params->pvmfw_buffer_size) { + VB2_DEBUG("No space left to load pvmfw partition\n"); + res = VB2_ERROR_LOAD_PARTITION_BODY_SIZE; + goto out; + } + + /* Load partition to the buffer */ + start_ts = vb2ex_mtime(); + if (VbExStreamRead(stream, part_bytes, part_pvmfw_buf)) { + VB2_DEBUG("Unable to read pvmfw partition\n"); + goto out; + } + read_ms += vb2ex_mtime() - start_ts; + + if (read_ms == 0) /* Avoid division by 0 in speed calculation */ + read_ms = 1; + VB2_DEBUG("read %u KB in %u ms at %u KB/s.\n", + (uint32_t)(part_bytes) / 1024, read_ms, + (uint32_t)(((part_bytes) * VB2_MSEC_PER_SEC) / + (read_ms * 1024))); + + params->pvmfw_size = part_bytes; + + res = VB2_SUCCESS; +out: + VbExStreamClose(stream); + return res; +} + static vb2_error_t vb2_load_ramdisk(GptData *gpt, struct vb2_kernel_params *params, vb2ex_disk_handle_t disk_handle, uint64_t *part_start, uint64_t *part_size, @@ -510,6 +569,16 @@ static AvbIOResult vboot_avb_get_preloaded_partition(AvbOps *ops, *out_pointer = (uint8_t *)avb_data->params->kernel_buffer + avb_data->params->init_boot_offset; + ret = AVB_IO_RESULT_OK; + } else if (!strcmp(short_partition_name, "pvmfw")) { + if (vb2_load_pvmfw(avb_data->vb2_ctx, avb_data->gpt, avb_data->params, + avb_data->disk_handle)) { + return AVB_IO_RESULT_ERROR_IO; + } + + *out_pointer = (uint8_t *)avb_data->params->pvmfw_buffer; + *out_num_bytes_preloaded = avb_data->params->pvmfw_size; + ret = AVB_IO_RESULT_OK; } From 8c6df3a88ce8c844e8d0199023f07a7a2c40223c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kope=C4=87?= Date: Mon, 8 Jul 2024 11:25:54 +0200 Subject: [PATCH 043/102] futility/file_type_bios.c: Skip keyblock checks if magic is invalid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The following warning messages appear every time upstream coreboot is built with Vboot enabled: ``` ``` This patch ensures that the warnings are not printed, by skipping checks if the keyblock magic is invalid. A new keyblock will be generated without extraneous warnings. (cherry picked from commit 2190262902561e5e57b088235f6e7302003f1c3b) Original-WARNING: prepare_slot: VBLOCK_A keyblock is invalid. Original-WARNING: prepare_slot: VBLOCK_B keyblock is invalid. Change-Id: If8e653036b4ca1d10f28bc3bab105b38b152edcd Original-Signed-off-by: Michał Kopeć Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5682443 Original-Tested-by: Julius Werner Original-Reviewed-by: Yu-Ping Wu Original-Commit-Queue: Julius Werner GitOrigin-RevId: 2190262902561e5e57b088235f6e7302003f1c3b Cr-Build-Id: 8736283100860560977 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8736283100860560977 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5860915 Reviewed-by: Grzegorz Bernacki Commit-Queue: Grzegorz Bernacki Tested-by: ChromeOS Prod (Robot) --- futility/file_type_bios.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/futility/file_type_bios.c b/futility/file_type_bios.c index c4da9a19..6cb3d731 100644 --- a/futility/file_type_bios.c +++ b/futility/file_type_bios.c @@ -409,6 +409,11 @@ static int prepare_slot(uint8_t *buf, uint32_t len, enum bios_component fw_c, (struct vb2_keyblock *)state->area[vblock_c].buf; int vblock_valid = 0; + if (keyblock->magic[0] == 0xff) { + /* Keyblock does not exist yet. Skip directly to creating a new one. */ + goto end; + } + if (vb2_verify_keyblock_hash(keyblock, state->area[vblock_c].len, &wb) != VB2_SUCCESS) { WARN("%s keyblock is invalid.\n", vblock_name); From 604d7e4c7952b037f82e8c3c301cf701f153efc4 Mon Sep 17 00:00:00 2001 From: DennisYeh Date: Mon, 16 Sep 2024 17:07:54 +0800 Subject: [PATCH 044/102] tests/futility: Add test cases for unmodified RO Test the futility 'autoupdate' mode when the RO section is the same in both the old and new firmware versions. Regardless of whether write protection (WP) is true or false, futility should only update the inactive firmware (RWB). BUG=b:194910959 TEST=manual on tentacruel. TEST=unit tests passed. (cherry picked from commit ed4556edb968be5781237353eb0db56fcadaec1c) Change-Id: I35f9017f891e12bee8aff121d1eed8a008fbe4ae Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5869471 Original-Reviewed-by: Yu-Ping Wu Original-Tested-by: Yu-Ping Wu Original-Reviewed-by: Jeremy Bettis Original-Tested-by: Dennis Yeh Original-Commit-Queue: Dennis Yeh GitOrigin-RevId: ed4556edb968be5781237353eb0db56fcadaec1c Cr-Build-Id: 8736283100860560977 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8736283100860560977 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5874415 Tested-by: ChromeOS Prod (Robot) Commit-Queue: Grzegorz Bernacki Reviewed-by: Grzegorz Bernacki --- tests/futility/test_update.sh | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/futility/test_update.sh b/tests/futility/test_update.sh index 405ba493..f4000195 100755 --- a/tests/futility/test_update.sh +++ b/tests/futility/test_update.sh @@ -104,6 +104,12 @@ cp -f "${FROM_IMAGE}" "${FROM_DIFFERENT_ROOTKEY_IMAGE}" cp -f "${FROM_IMAGE}" "${FROM_IMAGE}.large" truncate -s $((8388608 * 2)) "${FROM_IMAGE}.large" +# Create the FROM_SAME_RO_IMAGE using the RO from TO_IMAGE." +FROM_SAME_RO_IMAGE="${FROM_IMAGE}.same_ro" +cp -f "${FROM_IMAGE}" "${FROM_SAME_RO_IMAGE}" +"${FUTILITY}" load_fmap "${FROM_SAME_RO_IMAGE}" \ + "RO_SECTION:${TMP}.to/RO_SECTION" + # Create GBB v1.2 images (for checking digest) GBB_OUTPUT="$("${FUTILITY}" gbb --digest "${TO_IMAGE}")" [ "${GBB_OUTPUT}" = "digest: " ] @@ -131,6 +137,7 @@ cp -f "${TO_IMAGE}" "${TMP}.expected.full" cp -f "${FROM_IMAGE}" "${TMP}.expected.rw" cp -f "${FROM_IMAGE}" "${TMP}.expected.a" cp -f "${FROM_IMAGE}" "${TMP}.expected.b" +cp -f "${FROM_SAME_RO_IMAGE}" "${TMP}.FROM_SAME_RO_IMAGE.expected.b" cp -f "${FROM_IMAGE}" "${TMP}.expected.legacy" "${FUTILITY}" gbb -s --hwid="${FROM_HWID}" "${TMP}.expected.full" "${FUTILITY}" load_fmap "${TMP}.expected.full" \ @@ -145,6 +152,8 @@ cp -f "${FROM_IMAGE}" "${TMP}.expected.legacy" "RW_SECTION_A:${TMP}.to/RW_SECTION_A" "${FUTILITY}" load_fmap "${TMP}.expected.b" \ "RW_SECTION_B:${TMP}.to/RW_SECTION_B" +"${FUTILITY}" load_fmap "${TMP}.FROM_SAME_RO_IMAGE.expected.b" \ + "RW_SECTION_B:${TMP}.to/RW_SECTION_B" "${FUTILITY}" load_fmap "${TMP}.expected.legacy" \ "RW_LEGACY:${TMP}.to/RW_LEGACY" cp -f "${TMP}.expected.full" "${TMP}.expected.full.gbb12" @@ -342,6 +351,14 @@ test_update "RW update (B->A)" \ "${FROM_IMAGE}" "${TMP}.expected.a" \ -i "${TO_IMAGE}" -t --wp=1 --sys_props 1 +test_update "RW update, same RO, wp=0 (A->B)" \ + "${FROM_SAME_RO_IMAGE}" "${TMP}.FROM_SAME_RO_IMAGE.expected.b" \ + -i "${TO_IMAGE}" -t --wp=0 --sys_props 0 + +test_update "RW update, same RO, wp=1 (A->B)" \ + "${FROM_SAME_RO_IMAGE}" "${TMP}.FROM_SAME_RO_IMAGE.expected.b" \ + -i "${TO_IMAGE}" -t --wp=1 --sys_props 0 + test_update "RW update -> fallback to RO+RW Full update" \ "${FROM_IMAGE}" "${TMP}.expected.full" \ -i "${TO_IMAGE}" -t --wp=0 --sys_props 1,0x10002 From 8213da7d87ad62ec0202d04447f0607f87c03674 Mon Sep 17 00:00:00 2001 From: Tomasz Michalec Date: Fri, 9 Aug 2024 09:46:09 +0200 Subject: [PATCH 045/102] 2lib: Parse Android misc partition Parse misc partition and set force_normal_boot to proper value based on expected boot command from BCB. BUG=b:349304841 TEST=Boot into Android and request wipe (e.g. Settings > System > Reset options > Erase all data (factory reset)). Device reboots into Android recovery and wipes user data partition and reboots back to normal mode. Note that force_normal_boot needs to be removed from cmdline and recovery.fstab needs to be present on ramdisk. BRANCH=main Cq-Depend: chromium:5832753 Signed-off-by: Tomasz Michalec Change-Id: I20276bc90045452a6f3c592d3518fa75341f6b4b Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5776502 Reviewed-by: Jakub Czapiga --- firmware/2lib/2load_kernel.c | 60 ++++++++++++++++++++++++++++++++++++ firmware/2lib/include/2api.h | 9 ++++++ firmware/include/gpt.h | 1 + 3 files changed, 70 insertions(+) diff --git a/firmware/2lib/2load_kernel.c b/firmware/2lib/2load_kernel.c index abe444ef..3b5e20e1 100644 --- a/firmware/2lib/2load_kernel.c +++ b/firmware/2lib/2load_kernel.c @@ -23,6 +23,22 @@ /* Size of the buffer to convey cmdline properties to bootloader */ #define AVB_CMDLINE_BUF_SIZE 1024 + +/* BCB structure from Android recovery bootloader_message.h */ +struct bootloader_message { + char command[32]; + char status[32]; + char recovery[768]; + char stage[32]; + char reserved[1184]; +}; +_Static_assert(sizeof(struct bootloader_message) == 2048, + "bootloader_message size is incorrect"); + +/* Possible values of BCB command */ +#define BCB_CMD_BOOTONCE_BOOTLOADER "bootonce-bootloader" +#define BCB_CMD_BOOT_RECOVERY "boot-recovery" + #endif enum vb2_load_partition_flags { @@ -475,6 +491,48 @@ static vb2_error_t vb2_load_chromeos_kernel_partition( #define VERIFIED_BOOT_PROPERTY_NAME "androidboot.verifiedbootstate=" +static enum vb2_boot_command vb2_bcb_command(AvbOps *ops) +{ + struct bootloader_message bcb; + AvbIOResult io_ret; + size_t num_bytes_read; + enum vb2_boot_command cmd; + + io_ret = ops->read_from_partition(ops, + GPT_ENT_NAME_ANDROID_MISC, + 0, + sizeof(struct bootloader_message), + &bcb, + &num_bytes_read); + if (io_ret != AVB_IO_RESULT_OK || + num_bytes_read != sizeof(struct bootloader_message)) { + /* + * TODO(b/349304841): Handle IO errors, for now just try to boot + * normally + */ + VB2_DEBUG("Cannot read misc partition.\n"); + return VB2_BOOT_CMD_NORMAL_BOOT; + } + + /* BCB command field is for the bootloader */ + if (!strncmp(bcb.command, BCB_CMD_BOOT_RECOVERY, + VB2_MIN(sizeof(BCB_CMD_BOOT_RECOVERY) - 1, sizeof(bcb.command)))) { + cmd = VB2_BOOT_CMD_RECOVERY_BOOT; + } else if (!strncmp(bcb.command, BCB_CMD_BOOTONCE_BOOTLOADER, + VB2_MIN(sizeof(BCB_CMD_BOOTONCE_BOOTLOADER) - 1, + sizeof(bcb.command)))) { + cmd = VB2_BOOT_CMD_BOOTLOADER_BOOT; + } else { + /* If empty or unknown command, just boot normally */ + if (bcb.command[0] != '\0') + VB2_DEBUG("Unknown boot command \"%.*s\". Use normal boot.", + (int)sizeof(bcb.command), bcb.command); + cmd = VB2_BOOT_CMD_NORMAL_BOOT; + } + + return cmd; +} + static vb2_error_t vb2_load_avb_android_partition( struct vb2_context *ctx, struct vb2_kernel_params *params, VbExStream_t stream, GptData *gpt, vb2ex_disk_handle_t disk_handle) @@ -563,6 +621,8 @@ static vb2_error_t vb2_load_avb_android_partition( return ret; } + params->boot_command = vb2_bcb_command(avb_ops); + /* TODO(b/335901799): Add support for marking verifiedbootstate yellow */ /* Possible values for this property are "yellow", "orange" and "green" * so allocate 6 bytes plus 1 byte for NULL terminator. diff --git a/firmware/2lib/include/2api.h b/firmware/2lib/include/2api.h index ba7b52b0..f2a5f710 100644 --- a/firmware/2lib/include/2api.h +++ b/firmware/2lib/include/2api.h @@ -601,6 +601,13 @@ vb2_error_t vb2api_kernel_phase2(struct vb2_context *ctx); */ vb2_error_t vb2api_kernel_finalize(struct vb2_context *ctx); +/* Android BCB commands */ +enum vb2_boot_command { + VB2_BOOT_CMD_NORMAL_BOOT = 0, + VB2_BOOT_CMD_RECOVERY_BOOT = 1, + VB2_BOOT_CMD_BOOTLOADER_BOOT = 2, +}; + struct vb2_kernel_params { /* Inputs to vb2api_load_kernel(). */ /* Destination buffer for kernel (normally at 0x100000 on x86). */ @@ -639,6 +646,8 @@ struct vb2_kernel_params { uint32_t init_boot_size; /* Offset (in bytes) to the region with vboot cmdline parameters. */ uint32_t vboot_cmdline_offset; + /* Boot command from Android BCB on misc partition. */ + enum vb2_boot_command boot_command; /* Size of pvmfw partition in bytes in pvmfw buffer. */ uint32_t pvmfw_size; diff --git a/firmware/include/gpt.h b/firmware/include/gpt.h index 0c7eff5d..b4ca5c9d 100644 --- a/firmware/include/gpt.h +++ b/firmware/include/gpt.h @@ -70,6 +70,7 @@ extern "C" { #define GPT_ENT_NAME_ANDROID_VENDOR_BOOT "vendor_boot" #define GPT_ENT_NAME_ANDROID_BOOT "boot" #define GPT_ENT_NAME_ANDROID_PVMFW "pvmfw" +#define GPT_ENT_NAME_ANDROID_MISC "misc" #define GPT_ENT_NAME_ANDROID_A_SUFFIX "_a" #define GPT_ENT_NAME_ANDROID_B_SUFFIX "_b" From 70589868cb83990d5f08ccf2de25a2652e8118c8 Mon Sep 17 00:00:00 2001 From: Tomasz Michalec Date: Thu, 19 Sep 2024 14:00:17 +0200 Subject: [PATCH 046/102] 2lib: Extract Android specific functions to separate file Extract Android related functions in 2load_kernel.c file to new 2load_android_kernel.c file. BUG=None TEST=Boot Android kernel BRANCH=main Change-Id: I6d8e657412d6f4d6bc12d8cc3742a56eba435401 Signed-off-by: Tomasz Michalec Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5872874 Reviewed-by: Yu-Ping Wu --- Makefile | 2 + firmware/2lib/2load_android_kernel.c | 225 +++++++++++++++++++ firmware/2lib/2load_kernel.c | 222 +----------------- firmware/2lib/include/2load_android_kernel.h | 32 +++ 4 files changed, 263 insertions(+), 218 deletions(-) create mode 100644 firmware/2lib/2load_android_kernel.c create mode 100644 firmware/2lib/include/2load_android_kernel.h diff --git a/Makefile b/Makefile index 81880eaa..45d74114 100644 --- a/Makefile +++ b/Makefile @@ -464,6 +464,8 @@ ALL_OBJS += ${FWLIB_OBJS} ${TLCL_OBJS} # into expected location beforehand. ifneq (${USE_AVB},) include firmware/avb/Makefile +FWLIB_SRCS += \ + firmware/2lib/2load_android_kernel.c endif # Maintain behaviour of default on. diff --git a/firmware/2lib/2load_android_kernel.c b/firmware/2lib/2load_android_kernel.c new file mode 100644 index 00000000..7a99906c --- /dev/null +++ b/firmware/2lib/2load_android_kernel.c @@ -0,0 +1,225 @@ +/* Copyright 2024 The ChromiumOS Authors + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Functions to load and verify an Android kernel. + */ + +#include "2api.h" +#include "2common.h" +#include "2load_android_kernel.h" +#include "cgptlib.h" +#include "cgptlib_internal.h" +#include "gpt_misc.h" +#include "vboot_api.h" +#include "vboot_avb_ops.h" + +/* Size of the buffer to convey cmdline properties to bootloader */ +#define AVB_CMDLINE_BUF_SIZE 1024 + +/* Bytes to read at start of the boot/init_boot/vendor_boot partitions */ +#define BOOT_HDR_GKI_SIZE 4096 + +/* BCB structure from Android recovery bootloader_message.h */ +struct bootloader_message { + char command[32]; + char status[32]; + char recovery[768]; + char stage[32]; + char reserved[1184]; +}; +_Static_assert(sizeof(struct bootloader_message) == 2048, + "bootloader_message size is incorrect"); + +/* Possible values of BCB command */ +#define BCB_CMD_BOOTONCE_BOOTLOADER "bootonce-bootloader" +#define BCB_CMD_BOOT_RECOVERY "boot-recovery" + +#define VERIFIED_BOOT_PROPERTY_NAME "androidboot.verifiedbootstate=" + +static enum vb2_boot_command vb2_bcb_command(AvbOps *ops) +{ + struct bootloader_message bcb; + AvbIOResult io_ret; + size_t num_bytes_read; + enum vb2_boot_command cmd; + + io_ret = ops->read_from_partition(ops, + GPT_ENT_NAME_ANDROID_MISC, + 0, + sizeof(struct bootloader_message), + &bcb, + &num_bytes_read); + if (io_ret != AVB_IO_RESULT_OK || + num_bytes_read != sizeof(struct bootloader_message)) { + /* + * TODO(b/349304841): Handle IO errors, for now just try to boot + * normally + */ + VB2_DEBUG("Cannot read misc partition.\n"); + return VB2_BOOT_CMD_NORMAL_BOOT; + } + + /* BCB command field is for the bootloader */ + if (!strncmp(bcb.command, BCB_CMD_BOOT_RECOVERY, + VB2_MIN(sizeof(BCB_CMD_BOOT_RECOVERY) - 1, sizeof(bcb.command)))) { + cmd = VB2_BOOT_CMD_RECOVERY_BOOT; + } else if (!strncmp(bcb.command, BCB_CMD_BOOTONCE_BOOTLOADER, + VB2_MIN(sizeof(BCB_CMD_BOOTONCE_BOOTLOADER) - 1, + sizeof(bcb.command)))) { + cmd = VB2_BOOT_CMD_BOOTLOADER_BOOT; + } else { + /* If empty or unknown command, just boot normally */ + if (bcb.command[0] != '\0') + VB2_DEBUG("Unknown boot command \"%.*s\". Use normal boot.", + (int)sizeof(bcb.command), bcb.command); + cmd = VB2_BOOT_CMD_NORMAL_BOOT; + } + + return cmd; +} + +vb2_error_t vb2_load_android_kernel( + struct vb2_context *ctx, struct vb2_kernel_params *params, + VbExStream_t stream, GptData *gpt, vb2ex_disk_handle_t disk_handle, + int need_keyblock_valid) +{ + char *ab_suffix = NULL; + AvbSlotVerifyData *verify_data = NULL; + AvbOps *avb_ops; + const char *boot_partitions[] = { + GPT_ENT_NAME_ANDROID_BOOT, + GPT_ENT_NAME_ANDROID_INIT_BOOT, + GPT_ENT_NAME_ANDROID_VENDOR_BOOT, + GPT_ENT_NAME_ANDROID_PVMFW, + NULL, + }; + AvbSlotVerifyFlags avb_flags; + AvbSlotVerifyResult result; + vb2_error_t ret; + char *verified_str; + + /* + * Check if the buffer is zero sized (ie. pvmfw loading is not + * requested) or the pvmfw partition does not exist. If so skip + * loading and verifying it. + */ + uint64_t pvmfw_start; + uint64_t pvmfw_size; + if (params->pvmfw_buffer_size == 0 || + GptFindPvmfw(gpt, &pvmfw_start, &pvmfw_size) != GPT_SUCCESS) { + if (params->pvmfw_buffer_size != 0) + VB2_DEBUG("Couldn't find pvmfw partition. Ignoring.\n"); + + boot_partitions[3] = NULL; + params->pvmfw_size = 0; + } + + ret = GptGetActiveKernelPartitionSuffix(gpt, &ab_suffix); + if (ret != GPT_SUCCESS) { + VB2_DEBUG("Unable to get kernel partition suffix\n"); + return VB2_ERROR_LK_NO_KERNEL_FOUND; + } + + avb_ops = vboot_avb_ops_new(ctx, params, stream, gpt, disk_handle); + if (avb_ops == NULL) { + free(ab_suffix); + VB2_DEBUG("Cannot allocate memory for AVB ops\n"); + return VB2_ERROR_LK_NO_KERNEL_FOUND; + } + + avb_flags = AVB_SLOT_VERIFY_FLAGS_NONE; + if (!need_keyblock_valid) + avb_flags |= AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR; + + result = avb_slot_verify(avb_ops, + boot_partitions, + ab_suffix, + avb_flags, + AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, + &verify_data); + vboot_avb_ops_free(avb_ops); + free(ab_suffix); + + /* Ignore verification errors in developer mode */ + if (ctx->flags & VB2_CONTEXT_DEVELOPER_MODE) { + switch (result) { + case AVB_SLOT_VERIFY_RESULT_OK: + case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION: + case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX: + case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED: + ret = AVB_SLOT_VERIFY_RESULT_OK; + break; + default: + ret = VB2_ERROR_LK_NO_KERNEL_FOUND; + } + } else { + ret = result; + } + + /* + * Return from this function early so that caller can try fallback to + * other partition in case of error. + */ + if (ret != AVB_SLOT_VERIFY_RESULT_OK) { + if (verify_data != NULL) + avb_slot_verify_data_free(verify_data); + return ret; + } + + params->boot_command = vb2_bcb_command(avb_ops); + + /* TODO(b/335901799): Add support for marking verifiedbootstate yellow */ + /* Possible values for this property are "yellow", "orange" and "green" + * so allocate 6 bytes plus 1 byte for NULL terminator. + */ + verified_str = malloc(strlen(VERIFIED_BOOT_PROPERTY_NAME) + 7); + if (verified_str == NULL) + return VB2_ERROR_LK_NO_KERNEL_FOUND; + sprintf(verified_str, "%s%s", VERIFIED_BOOT_PROPERTY_NAME, + (ctx->flags & VB2_CONTEXT_DEVELOPER_MODE) ? "orange" : "green"); + + /* + * Use a buffer before the GKI header for copying avb cmdline string for + * bootloader. + */ + params->vboot_cmdline_offset = params->kernel_buffer_size - + BOOT_HDR_GKI_SIZE - AVB_CMDLINE_BUF_SIZE; + + if ((params->init_boot_offset + params->init_boot_size) > + params->vboot_cmdline_offset) + return VB2_ERROR_LOAD_PARTITION_WORKBUF; + + if ((strlen(verify_data->cmdline) + strlen(verified_str) + 1) >= + AVB_CMDLINE_BUF_SIZE) + return VB2_ERROR_LOAD_PARTITION_WORKBUF; + + strcpy((char *)(params->kernel_buffer + params->vboot_cmdline_offset), + verify_data->cmdline); + + /* Append verifiedbootstate property to cmdline */ + strcat((char *)(params->kernel_buffer + params->vboot_cmdline_offset), + " "); + strcat((char *)(params->kernel_buffer + params->vboot_cmdline_offset), + verified_str); + + free(verified_str); + + /* No need for slot data, partitions should be already at correct + * locations in memory since we are using "get_preloaded_partitions" + * callbacks. + */ + avb_slot_verify_data_free(verify_data); + + /* + * Bootloader expects kernel image at the very beginning of + * kernel_buffer, but verification requires boot header before + * kernel. Since the verification is done, we need to move kernel + * at proper address. + */ + memmove((uint8_t *)params->kernel_buffer, + (uint8_t *)params->kernel_buffer + BOOT_HDR_GKI_SIZE, + params->vendor_boot_offset - BOOT_HDR_GKI_SIZE); + + return ret; +} diff --git a/firmware/2lib/2load_kernel.c b/firmware/2lib/2load_kernel.c index 3b5e20e1..68a0b1ed 100644 --- a/firmware/2lib/2load_kernel.c +++ b/firmware/2lib/2load_kernel.c @@ -8,6 +8,7 @@ #include "2api.h" #include "2common.h" +#include "2load_android_kernel.h" #include "2misc.h" #include "2nvstorage.h" #include "2packed_key.h" @@ -18,28 +19,6 @@ #include "gpt_misc.h" #include "vboot_api.h" -#ifdef USE_LIBAVB -#include "vboot_avb_ops.h" - -/* Size of the buffer to convey cmdline properties to bootloader */ -#define AVB_CMDLINE_BUF_SIZE 1024 - -/* BCB structure from Android recovery bootloader_message.h */ -struct bootloader_message { - char command[32]; - char status[32]; - char recovery[768]; - char stage[32]; - char reserved[1184]; -}; -_Static_assert(sizeof(struct bootloader_message) == 2048, - "bootloader_message size is incorrect"); - -/* Possible values of BCB command */ -#define BCB_CMD_BOOTONCE_BOOTLOADER "bootonce-bootloader" -#define BCB_CMD_BOOT_RECOVERY "boot-recovery" - -#endif enum vb2_load_partition_flags { VB2_LOAD_PARTITION_FLAG_VBLOCK_ONLY = (1 << 0), @@ -47,8 +26,6 @@ enum vb2_load_partition_flags { }; #define KBUF_SIZE 65536 /* Bytes to read at start of kernel partition */ -/* Bytes to read at start of the boot/init_boot/vendor_boot partitions */ -#define BOOT_HDR_GKI_SIZE 4096 #define LOWEST_TPM_VERSION 0xffffffff @@ -487,198 +464,6 @@ static vb2_error_t vb2_load_chromeos_kernel_partition( return VB2_SUCCESS; } -#ifdef USE_LIBAVB - -#define VERIFIED_BOOT_PROPERTY_NAME "androidboot.verifiedbootstate=" - -static enum vb2_boot_command vb2_bcb_command(AvbOps *ops) -{ - struct bootloader_message bcb; - AvbIOResult io_ret; - size_t num_bytes_read; - enum vb2_boot_command cmd; - - io_ret = ops->read_from_partition(ops, - GPT_ENT_NAME_ANDROID_MISC, - 0, - sizeof(struct bootloader_message), - &bcb, - &num_bytes_read); - if (io_ret != AVB_IO_RESULT_OK || - num_bytes_read != sizeof(struct bootloader_message)) { - /* - * TODO(b/349304841): Handle IO errors, for now just try to boot - * normally - */ - VB2_DEBUG("Cannot read misc partition.\n"); - return VB2_BOOT_CMD_NORMAL_BOOT; - } - - /* BCB command field is for the bootloader */ - if (!strncmp(bcb.command, BCB_CMD_BOOT_RECOVERY, - VB2_MIN(sizeof(BCB_CMD_BOOT_RECOVERY) - 1, sizeof(bcb.command)))) { - cmd = VB2_BOOT_CMD_RECOVERY_BOOT; - } else if (!strncmp(bcb.command, BCB_CMD_BOOTONCE_BOOTLOADER, - VB2_MIN(sizeof(BCB_CMD_BOOTONCE_BOOTLOADER) - 1, - sizeof(bcb.command)))) { - cmd = VB2_BOOT_CMD_BOOTLOADER_BOOT; - } else { - /* If empty or unknown command, just boot normally */ - if (bcb.command[0] != '\0') - VB2_DEBUG("Unknown boot command \"%.*s\". Use normal boot.", - (int)sizeof(bcb.command), bcb.command); - cmd = VB2_BOOT_CMD_NORMAL_BOOT; - } - - return cmd; -} - -static vb2_error_t vb2_load_avb_android_partition( - struct vb2_context *ctx, struct vb2_kernel_params *params, - VbExStream_t stream, GptData *gpt, vb2ex_disk_handle_t disk_handle) -{ - char *ab_suffix = NULL; - AvbSlotVerifyData *verify_data = NULL; - AvbOps *avb_ops; - const char *boot_partitions[] = { - GPT_ENT_NAME_ANDROID_BOOT, - GPT_ENT_NAME_ANDROID_INIT_BOOT, - GPT_ENT_NAME_ANDROID_VENDOR_BOOT, - GPT_ENT_NAME_ANDROID_PVMFW, - NULL, - }; - AvbSlotVerifyFlags avb_flags; - AvbSlotVerifyResult result; - vb2_error_t ret; - int need_keyblock_valid = need_valid_keyblock(ctx); - char *verified_str; - - /* - * Check if the buffer is zero sized (ie. pvmfw loading is not - * requested) or the pvmfw partition does not exist. If so skip - * loading and verifying it. - */ - uint64_t pvmfw_start; - uint64_t pvmfw_size; - if (params->pvmfw_buffer_size == 0 || - GptFindPvmfw(gpt, &pvmfw_start, &pvmfw_size) != GPT_SUCCESS) { - if (params->pvmfw_buffer_size != 0) - VB2_DEBUG("Couldn't find pvmfw partition. Ignoring.\n"); - - boot_partitions[3] = NULL; - params->pvmfw_size = 0; - } - - ret = GptGetActiveKernelPartitionSuffix(gpt, &ab_suffix); - if (ret != GPT_SUCCESS) { - VB2_DEBUG("Unable to get kernel partition suffix\n"); - return VB2_ERROR_LK_NO_KERNEL_FOUND; - } - - avb_ops = vboot_avb_ops_new(ctx, params, stream, gpt, disk_handle); - if (avb_ops == NULL) { - free(ab_suffix); - VB2_DEBUG("Cannot allocate memory for AVB ops\n"); - return VB2_ERROR_LK_NO_KERNEL_FOUND; - } - - avb_flags = AVB_SLOT_VERIFY_FLAGS_NONE; - if (!need_keyblock_valid) - avb_flags |= AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR; - - result = avb_slot_verify(avb_ops, - boot_partitions, - ab_suffix, - avb_flags, - AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, - &verify_data); - vboot_avb_ops_free(avb_ops); - free(ab_suffix); - - /* Ignore verification errors in developer mode */ - if (ctx->flags & VB2_CONTEXT_DEVELOPER_MODE) { - switch (result) { - case AVB_SLOT_VERIFY_RESULT_OK: - case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION: - case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX: - case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED: - ret = AVB_SLOT_VERIFY_RESULT_OK; - break; - default: - ret = VB2_ERROR_LK_NO_KERNEL_FOUND; - } - } else { - ret = result; - } - - /* - * Return from this function early so that caller can try fallback to - * other partition in case of error. - */ - if (ret != AVB_SLOT_VERIFY_RESULT_OK) { - if (verify_data != NULL) - avb_slot_verify_data_free(verify_data); - return ret; - } - - params->boot_command = vb2_bcb_command(avb_ops); - - /* TODO(b/335901799): Add support for marking verifiedbootstate yellow */ - /* Possible values for this property are "yellow", "orange" and "green" - * so allocate 6 bytes plus 1 byte for NULL terminator. - */ - verified_str = malloc(strlen(VERIFIED_BOOT_PROPERTY_NAME) + 7); - if (verified_str == NULL) - return VB2_ERROR_LK_NO_KERNEL_FOUND; - sprintf(verified_str, "%s%s", VERIFIED_BOOT_PROPERTY_NAME, - (ctx->flags & VB2_CONTEXT_DEVELOPER_MODE) ? "orange" : "green"); - - /* - * Use a buffer before the GKI header for copying avb cmdline string for - * bootloader. - */ - params->vboot_cmdline_offset = params->kernel_buffer_size - - BOOT_HDR_GKI_SIZE - AVB_CMDLINE_BUF_SIZE; - - if ((params->init_boot_offset + params->init_boot_size) > - params->vboot_cmdline_offset) - return VB2_ERROR_LOAD_PARTITION_WORKBUF; - - if ((strlen(verify_data->cmdline) + strlen(verified_str) + 1) >= - AVB_CMDLINE_BUF_SIZE) - return VB2_ERROR_LOAD_PARTITION_WORKBUF; - - strcpy((char *)(params->kernel_buffer + params->vboot_cmdline_offset), - verify_data->cmdline); - - /* Append verifiedbootstate property to cmdline */ - strcat((char *)(params->kernel_buffer + params->vboot_cmdline_offset), - " "); - strcat((char *)(params->kernel_buffer + params->vboot_cmdline_offset), - verified_str); - - free(verified_str); - - /* No need for slot data, partitions should be already at correct - * locations in memory since we are using "get_preloaded_partitions" - * callbacks. - */ - avb_slot_verify_data_free(verify_data); - - /* - * Bootloader expects kernel image at the very beginning of - * kernel_buffer, but verification requires boot header before - * kernel. Since the verification is done, we need to move kernel - * at proper address. - */ - memmove((uint8_t *)params->kernel_buffer, - (uint8_t *)params->kernel_buffer + BOOT_HDR_GKI_SIZE, - params->vendor_boot_offset - BOOT_HDR_GKI_SIZE); - - return ret; -} -#endif /* USE_LIBAVB */ - static vb2_error_t try_minios_kernel(struct vb2_context *ctx, struct vb2_kernel_params *params, struct vb2_disk_info *disk_info, @@ -894,8 +679,9 @@ vb2_error_t vb2api_load_kernel(struct vb2_context *ctx, uint32_t kernel_version = 0; #ifdef USE_LIBAVB - rv = vb2_load_avb_android_partition(ctx, params, stream, &gpt, - disk_info->handle); + rv = vb2_load_android_kernel(ctx, params, stream, &gpt, + disk_info->handle, + need_valid_keyblock(ctx)); #else /* Don't allow to boot android without AVB */ rv = VB2_ERROR_LK_INVALID_KERNEL_FOUND; diff --git a/firmware/2lib/include/2load_android_kernel.h b/firmware/2lib/include/2load_android_kernel.h new file mode 100644 index 00000000..8fb536ce --- /dev/null +++ b/firmware/2lib/include/2load_android_kernel.h @@ -0,0 +1,32 @@ +/* Copyright 2024 The ChromiumOS Authors + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Functions to load and verify an Android kernel. + */ + +#ifndef VBOOT_REFERENCE_2LOAD_ANDROID_KERNEL_H_ +#define VBOOT_REFERENCE_2LOAD_ANDROID_KERNEL_H_ + +#include "2api.h" +#include "gpt_misc.h" +#include "vboot_api.h" + +/** + * Load and verify Android kernel partitions (boot, init_boot, vendor_boot, + * pvmfw) from the stream. + * + * @param ctx Vboot context + * @param params Load-kernel parameters + * @param stream Stream to load kernel from + * @param gpt Partition table from the disk + * @param disk_handle Handle to the disk containing kernel + * @param need_keyblock_valid Controls if successful verification is required + * @return VB2_SUCCESS, or non-zero error code. + */ +vb2_error_t vb2_load_android_kernel( + struct vb2_context *ctx, struct vb2_kernel_params *params, + VbExStream_t stream, GptData *gpt, vb2ex_disk_handle_t disk_handle, + int need_keyblock_valid); + +#endif /* VBOOT_REFERENCE_2LOAD_ANDROID_KERNEL_H_ */ From 94a062d377539ea7b53c7f8dc8285264aa076839 Mon Sep 17 00:00:00 2001 From: Hung-Te Lin Date: Fri, 30 Aug 2024 21:39:31 +0800 Subject: [PATCH 047/102] futility: updater: Remove the legacy 'setvars.sh' manifest The `setvars.sh` has been deprecated by `signer_config.csv` for a while (M118~) and it is time to drop the setvars.sh from the updater. BUG=b:251040363 TEST=make runfutiltests -j BRANCH=none (cherry picked from commit f770c7d074a231c533c2ca0608eccfab8c807adb) Cq-Depend: chromium:5826250 Change-Id: I071f72c67a9aacd9d238c735d2a148fa8cd74cbd Original-Signed-off-by: Hung-Te Lin Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5826440 Original-Reviewed-by: Yu-Ping Wu Original-Commit-Queue: Yu-Ping Wu GitOrigin-RevId: f770c7d074a231c533c2ca0608eccfab8c807adb Cr-Build-Id: 8735377134969615841 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8735377134969615841 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5881953 Commit-Queue: Yu-Ping Wu Tested-by: ChromeOS Prod (Robot) Reviewed-by: Yu-Ping Wu Reviewed-by: Grzegorz Bernacki --- futility/updater_manifest.c | 194 +++--------------------------------- 1 file changed, 15 insertions(+), 179 deletions(-) diff --git a/futility/updater_manifest.c b/futility/updater_manifest.c index 30edacfc..7775bd64 100644 --- a/futility/updater_manifest.c +++ b/futility/updater_manifest.c @@ -46,31 +46,14 @@ * - rootkey.$MANIFEST_KEY * - vblock_A.$MANIFEST_KEY * - vblock_B.$MANIFEST_KEY - * - * Historically (the original design in Unified Build) there should also be a - * models/ folder, and each model should appear as a sub folder, with - * a 'setvars.sh' file inside. The 'setvars.sh' is a shell script - * describing what files should be used and the signature ID ($SIGID) to - * use as firmware manifest key. If $SIGID starts with 'sig-id-in-*' then we - * have to replace it by VPD value 'custom_label_tag' as '$MODEL-$CLTAG'. - * - * The current implementation is to try `signer_config.csv` approach first, and - * then fallback to `setvars.sh` on failure. */ -static const char * const SETVARS_IMAGE_MAIN = "IMAGE_MAIN", - * const SETVARS_IMAGE_EC = "IMAGE_EC", - * const SETVARS_SIGNATURE_ID = "SIGNATURE_ID", - * const SIG_ID_IN_VPD_PREFIX = "sig-id-in", - * const DIR_MODELS = "models", - * const DEFAULT_MODEL_NAME = "default", +static const char * const DEFAULT_MODEL_NAME = "default", * const VPD_CUSTOM_LABEL_TAG = "custom_label_tag", * const VPD_CUSTOM_LABEL_TAG_LEGACY = "whitelabel_tag", * const VPD_CUSTOMIZATION_ID = "customization_id", - * const ENV_VAR_MODEL_DIR = "${MODEL_DIR}", * const PATH_KEYSET_FOLDER = "keyset/", - * const PATH_SIGNER_CONFIG = "signer_config.csv", - * const PATH_ENDSWITH_SETVARS = "/setvars.sh"; + * const PATH_SIGNER_CONFIG = "signer_config.csv"; /* Utility function to convert a string. */ static void str_convert(char *s, int (*convert)(int c)) @@ -85,21 +68,6 @@ static void str_convert(char *s, int (*convert)(int c)) } } -/* Returns 1 if name ends by given pattern, otherwise 0. */ -static int str_endswith(const char *name, const char *pattern) -{ - size_t name_len = strlen(name), pattern_len = strlen(pattern); - if (name_len < pattern_len) - return 0; - return strcmp(name + name_len - pattern_len, pattern) == 0; -} - -/* Returns 1 if name starts by given pattern, otherwise 0. */ -static int str_startswith(const char *name, const char *pattern) -{ - return strncmp(name, pattern, strlen(pattern)) == 0; -} - /* Returns the VPD value by given key name, or NULL on error (or no value). */ static char *vpd_get_value(const char *fpath, const char *key) { @@ -117,66 +85,6 @@ static char *vpd_get_value(const char *fpath, const char *key) return result; } -/* - * Reads and parses a setvars type file from archive, then stores into config. - * Returns 0 on success (at least one entry found), otherwise failure. - */ -static int model_config_parse_setvars_file( - struct model_config *cfg, struct u_archive *archive, - const char *fpath) -{ - uint8_t *data; - uint32_t len; - - char *ptr_line = NULL, *ptr_token = NULL; - char *line, *k, *v; - int valid = 0; - - if (archive_read_file(archive, fpath, &data, &len, NULL) != 0) { - ERROR("Failed reading: %s\n", fpath); - return -1; - } - - /* Valid content should end with \n, or \"; ensure ASCIIZ for parsing */ - if (len) - data[len - 1] = '\0'; - - for (line = strtok_r((char *)data, "\n\r", &ptr_line); line; - line = strtok_r(NULL, "\n\r", &ptr_line)) { - char *expand_path = NULL; - int found_valid = 1; - - /* Format: KEY="value" */ - k = strtok_r(line, "=", &ptr_token); - if (!k) - continue; - v = strtok_r(NULL, "\"", &ptr_token); - if (!v) - continue; - - /* Some legacy updaters may be still using ${MODEL_DIR}. */ - if (str_startswith(v, ENV_VAR_MODEL_DIR)) { - ASPRINTF(&expand_path, "%s/%s%s", DIR_MODELS, cfg->name, - v + strlen(ENV_VAR_MODEL_DIR)); - } - - if (strcmp(k, SETVARS_IMAGE_MAIN) == 0) - cfg->image = strdup(v); - else if (strcmp(k, SETVARS_IMAGE_EC) == 0) - cfg->ec_image = strdup(v); - else if (strcmp(k, SETVARS_SIGNATURE_ID) == 0) { - cfg->signature_id = strdup(v); - if (str_startswith(v, SIG_ID_IN_VPD_PREFIX)) - cfg->is_custom_label = 1; - } else - found_valid = 0; - free(expand_path); - valid += found_valid; - } - free(data); - return valid == 0; -} - /* * Changes the rootkey in firmware GBB to given new key. * Returns 0 on success, otherwise failure. @@ -342,46 +250,6 @@ static struct model_config *manifest_add_model( return model; } -/* - * A callback function for manifest to scan files in archive. - * Returns 0 to keep scanning, or non-zero to stop. - */ -static int manifest_scan_entries(const char *name, void *arg) -{ - struct manifest *manifest = (struct manifest *)arg; - struct u_archive *archive = manifest->archive; - struct model_config model = {0}; - char *slash; - - if (!str_endswith(name, PATH_ENDSWITH_SETVARS)) - return 0; - - /* name: models/$MODEL/setvars.sh */ - model.name = strdup(strchr(name, '/') + 1); - slash = strchr(model.name, '/'); - if (slash) - *slash = '\0'; - - VB2_DEBUG("Found model <%s> setvars: %s\n", model.name, name); - if (model_config_parse_setvars_file(&model, archive, name)) { - ERROR("Invalid setvars file: %s\n", name); - return 0; - } - - /* In legacy setvars.sh, the ec_image may not exist. */ - if (model.ec_image && !archive_has_entry(archive, model.ec_image)) { - VB2_DEBUG("Ignore non-exist EC image: %s\n", model.ec_image); - free(model.ec_image); - model.ec_image = NULL; - } - - /* Find patch files. */ - if (model.signature_id) - find_patches_for_model(&model, archive, model.signature_id); - - return !manifest_add_model(manifest, &model); -} - /* * A callback function for manifest to scan files in raw /firmware archive. * Returns 0 to keep scanning, or non-zero to stop. @@ -519,22 +387,24 @@ static int manifest_from_signer_config(struct manifest *manifest) base_model_config->is_custom_label = 1; /* * Rewriting signature_id is not necessary, - * but in order to generate the same manifest - * from setvars, we want to temporarily use - * the special value. + * but currently the special signature_id (from + * legacy setvars) is still the only way to + * identify custom label models. + * TODO(hungte) Remove the rewriting when we + * have changed the custom label models to real + * models. */ free(base_model_config->signature_id); base_model_config->signature_id = strdup( "sig-id-in-customization-id"); /* - * Historically (e.g., setvars.sh), custom label - * devices will have signature ID set to - * 'sig-id-in-*' so the patch files will be - * discovered later from VPD. We want to - * follow that behavior until fully migrated. + * Currently we are merging all custom label + * models into one single model in the manifest, + * and will discover the patches later from VPD. + * As a result, the existing patches should be + * cleared. */ - clear_patch_config( - &base_model_config->patches); + clear_patch_config(&base_model_config->patches); } } @@ -812,31 +682,6 @@ int model_apply_custom_label( return r; } -/* - * b/251040363: Checks if the archive must be parsed using setvars.sh. - */ -static bool manifest_must_enforce_setvars(struct manifest *manifest) -{ - int i; - const char *setvars_list[] = { - "setvars_sh_only", - }; - - for (i = 0; i < ARRAY_SIZE(setvars_list); i++) { - if (archive_has_entry(manifest->archive, setvars_list[i])) { - INFO("Detected %s, will use *%s.\n", - setvars_list[i], PATH_ENDSWITH_SETVARS); - return true; - } - } - return false; -} - -static int manifest_from_setvars_sh(struct manifest *manifest) { - VB2_DEBUG("Try to build the manifest from *%s\n", PATH_ENDSWITH_SETVARS); - return archive_walk(manifest->archive, manifest, manifest_scan_entries); -} - static int manifest_from_build_artifacts(struct manifest *manifest) { VB2_DEBUG("Try to build the manifest from a */firmware folder\n"); return archive_walk(manifest->archive, manifest, manifest_scan_raw_entries); @@ -850,10 +695,8 @@ struct manifest *new_manifest_from_archive(struct u_archive *archive) { int i; struct manifest manifest = {0}, *new_manifest; - bool try_builders = true; int (*manifest_builders[])(struct manifest *) = { manifest_from_signer_config, - manifest_from_setvars_sh, manifest_from_build_artifacts, manifest_from_simple_folder, }; @@ -864,12 +707,7 @@ struct manifest *new_manifest_from_archive(struct u_archive *archive) manifest.has_keyset = 1; VB2_DEBUG("Has keyset: %s\n", manifest.has_keyset ? "True" : "False"); - if (manifest_must_enforce_setvars(&manifest)) { - try_builders = false; - manifest_from_setvars_sh(&manifest); - } - - for (i = 0; try_builders && i < ARRAY_SIZE(manifest_builders); i++) { + for (i = 0; !manifest.num && i < ARRAY_SIZE(manifest_builders); i++) { /* * For archives manually updated (for testing), it is possible a * builder can successfully scan the archive but no valid models @@ -877,8 +715,6 @@ struct manifest *new_manifest_from_archive(struct u_archive *archive) * Only stop when manifest.num is non-zero. */ (void) manifest_builders[i](&manifest); - if (manifest.num) - try_builders = false; } VB2_DEBUG("%d model(s) loaded.\n", manifest.num); From d4d540467415f1fa9a7e5fe90304ee787f07f464 Mon Sep 17 00:00:00 2001 From: Hung-Te Lin Date: Thu, 5 Sep 2024 01:02:43 +0800 Subject: [PATCH 048/102] futility: updater: Remove signature_id from manifest The `signature_id` was a legacy data from `setvars.sh` and was not available in the `signer_config.csv` data. Since we have fully deprecated the `setvars.sh`, it is time to remove the unused data. BUG=b:251040363 TEST=make runfutiltests -j BRANCH=none (cherry picked from commit 13400d696a5edaff2b28c1305ca1069e6bbb9669) Cq-Depend: chromium:5874495 Change-Id: I7cb690b2bc4e0de96e062c7087b92483d440cda4 Original-Signed-off-by: Hung-Te Lin Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5837957 Original-Reviewed-by: Yu-Ping Wu Original-Commit-Queue: Yu-Ping Wu GitOrigin-RevId: 13400d696a5edaff2b28c1305ca1069e6bbb9669 Cr-Build-Id: 8735377134969615841 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8735377134969615841 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5881954 Reviewed-by: Yu-Ping Wu Reviewed-by: Grzegorz Bernacki Commit-Queue: Yu-Ping Wu Tested-by: ChromeOS Prod (Robot) --- futility/updater.h | 3 +-- futility/updater_manifest.c | 25 ++++--------------------- 2 files changed, 5 insertions(+), 23 deletions(-) diff --git a/futility/updater.h b/futility/updater.h index 1ea0cb5f..ef57bd2e 100644 --- a/futility/updater.h +++ b/futility/updater.h @@ -167,8 +167,7 @@ struct model_config { char *name; char *image, *ec_image; struct patch_config patches; - char *signature_id; - int is_custom_label; + bool is_custom_label, is_unibuild; }; struct manifest { diff --git a/futility/updater_manifest.c b/futility/updater_manifest.c index 7775bd64..48c8be5b 100644 --- a/futility/updater_manifest.c +++ b/futility/updater_manifest.c @@ -350,7 +350,7 @@ static int manifest_from_signer_config(struct manifest *manifest) for (s = strtok_r(NULL, "\n", &tok_ptr); s != NULL; s = strtok_r(NULL, "\n", &tok_ptr)) { - struct model_config model = {0}; + struct model_config model = { .is_unibuild = true, }; int discard_model = 0; /* @@ -384,19 +384,7 @@ static int manifest_from_signer_config(struct manifest *manifest) if (!base_model_config) { ERROR("Invalid CL-model: %s\n", base_model); } else if (!base_model_config->is_custom_label) { - base_model_config->is_custom_label = 1; - /* - * Rewriting signature_id is not necessary, - * but currently the special signature_id (from - * legacy setvars) is still the only way to - * identify custom label models. - * TODO(hungte) Remove the rewriting when we - * have changed the custom label models to real - * models. - */ - free(base_model_config->signature_id); - base_model_config->signature_id = strdup( - "sig-id-in-customization-id"); + base_model_config->is_custom_label = true; /* * Currently we are merging all custom label * models into one single model in the manifest, @@ -418,7 +406,6 @@ static int manifest_from_signer_config(struct manifest *manifest) /* Find patch files. */ find_patches_for_model(&model, archive, model.name); - model.signature_id = strdup(model.name); if (!manifest_add_model(manifest, &model)) break; } @@ -468,7 +455,7 @@ static int manifest_from_simple_folder(struct manifest *manifest) if (!model.name) model.name = strdup(DEFAULT_MODEL_NAME); if (manifest->has_keyset) - model.is_custom_label = 1; + model.is_custom_label = true; manifest_add_model(manifest, &model); manifest->default_model = manifest->num - 1; @@ -598,7 +585,7 @@ manifest_detect_model_from_frid(struct updater_config *cfg, */ static char *resolve_signature_id(struct model_config *model, const char *image) { - int is_unibuild = model->signature_id ? 1 : 0; + bool is_unibuild = model->is_unibuild; char *tag = vpd_get_value(image, VPD_CUSTOM_LABEL_TAG); char *sig_id = NULL; @@ -740,7 +727,6 @@ void delete_manifest(struct manifest *manifest) for (i = 0; i < manifest->num; i++) { struct model_config *model = &manifest->models[i]; free(model->name); - free(model->signature_id); free(model->image); free(model->ec_image); clear_patch_config(&model->patches); @@ -846,9 +832,6 @@ void print_json_manifest(const struct manifest *manifest) printf(", \"gscvd\": \"%s\"", p->gscvd); printf(" }"); } - if (m->signature_id) - printf(",\n%*s\"signature_id\": \"%s\"", indent, "", - m->signature_id); printf("\n }"); indent -= 2; assert(indent == 2); From ded931d188bf8e9450eeca5260a6cf3dcc758674 Mon Sep 17 00:00:00 2001 From: Hung-Te Lin Date: Sat, 21 Sep 2024 01:20:35 +0800 Subject: [PATCH 049/102] futility: updater: Process custom label as standard models One advantage of switching to signer_config.csv and getting rid of setvars.sh is we finally can know what custom label devices are supported. In `setvars.sh` or the pre-Unified-Build single package format, we have to scan the 'keyset/' folder to figure out what custom label tags may be available. But when using signer_config.csv, all the custom label names are already included in the signer information. As a result, we can finally remove the hacky way of patching custom label devices. One downside is we can no longer support custom label in non-Unified-Build systems, but all active Chromebooks are now Unified Build so that is not a problem. And for development using simple archive without `signer_config.csv`, there is no need to support custom label because we usually don't have signed keys. This is also the first step to remove the custom label logic from the firmware updater - preparation to let crosid handle custom label matching for us. This also implies `--signature_id` is now equivalent to `--model` and can be deprecated in the follow up changes. BUG=b:251040363 TEST=make runfutiltests -j BRANCH=none (cherry picked from commit 7ad2b0ab50350df901de329a75aa40d189ef6f94) Change-Id: Ib4c62ba4d01b276472575625ea19397fc21b1589 Original-Signed-off-by: Hung-Te Lin Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5872452 Original-Commit-Queue: Yu-Ping Wu Original-Reviewed-by: Yu-Ping Wu GitOrigin-RevId: 7ad2b0ab50350df901de329a75aa40d189ef6f94 Cr-Build-Id: 8735377134969615841 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8735377134969615841 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5886254 Reviewed-by: Grzegorz Bernacki Tested-by: ChromeOS Prod (Robot) Reviewed-by: Yu-Ping Wu Commit-Queue: Yu-Ping Wu --- futility/updater.c | 84 ++++------ futility/updater.h | 26 +-- futility/updater_manifest.c | 232 ++++++++++++-------------- futility/updater_quirks.c | 6 +- tests/futility/data/signer_config.csv | 1 + tests/futility/test_update.sh | 89 ++++------ 6 files changed, 186 insertions(+), 252 deletions(-) diff --git a/futility/updater.c b/futility/updater.c index 2cef2bc5..ca1d0161 100644 --- a/futility/updater.c +++ b/futility/updater.c @@ -1354,37 +1354,6 @@ static int updater_output_image(const struct firmware_image *image, return !!r; } -/* - * Applies custom label information to an existing model config. - * Returns 0 on success, otherwise failure. - */ -static int updater_apply_custom_label(struct updater_config *cfg, - struct model_config *model, - const char *signature_id) -{ - const char *tmp_image = NULL; - - assert(model->is_custom_label); - if (!signature_id) { - if (!cfg->image_current.data) { - INFO("Loading system firmware for custom label...\n"); - load_system_firmware(cfg, &cfg->image_current); - } - tmp_image = get_firmware_image_temp_file( - &cfg->image_current, &cfg->tempfiles); - if (!tmp_image) { - ERROR("Failed to get system current firmware\n"); - return 1; - } - if (get_config_quirk(QUIRK_OVERRIDE_SIGNATURE_ID, cfg) && - is_ap_write_protection_enabled(cfg)) - quirk_override_signature_id( - cfg, model, &signature_id); - } - return !!model_apply_custom_label( - model, cfg->archive, signature_id, tmp_image); -} - /* * Setup what the updater has to do against an archive. * Returns number of failures, or 0 on success. @@ -1417,29 +1386,44 @@ static int updater_setup_archive( errorcnt += updater_load_images( cfg, arg, model->image, model->ec_image); - if (model->is_custom_label && !manifest->has_keyset) { + if (model->has_custom_label) { + + if (!cfg->image_current.data) { + INFO("Loading system firmware for custom label...\n"); + load_system_firmware(cfg, &cfg->image_current); + } + + const char *signature_id = arg->signature_id; + const struct model_config *base_model = model; + + if (!signature_id && + get_config_quirk(QUIRK_OVERRIDE_SIGNATURE_ID, cfg) && + is_ap_write_protection_enabled(cfg)) + quirk_override_signature_id( + cfg, model, &signature_id); + /* - * Developers running unsigned updaters (usually local build) - * won't be able match any custom label tags. + * For custom label devices, manifest_find_model may return the + * base model instead of the custom label ones so we have to + * look up again using the signature_id. */ - WARN("No keysets found - this is probably a local build of \n" - "unsigned firmware updater. Skip applying custom label."); - } else if (model->is_custom_label) { + model = manifest_find_custom_label_model( + cfg, manifest, base_model, signature_id); + if (!model) + return ++errorcnt; /* - * It is fine to fail in updater_apply_custom_label for factory - * mode so we are not checking the return value; instead we - * verify if the patches do contain new root key. + * All custom label models should share the same image, so we + * don't need to reload again - just pick up the new config and + * patch later. We don't care about EC images because that will + * be updated by software sync in the end. + * Here we want to double check if that assumption is correct. */ - updater_apply_custom_label(cfg, (struct model_config *)model, - arg->signature_id); - if (!model->patches.rootkey) { - if (is_factory || - is_ap_write_protection_enabled(cfg) || - get_config_quirk(QUIRK_ALLOW_EMPTY_CUSTOM_LABEL_TAG, - cfg)) { - WARN("No VPD for custom label.\n"); - } else { - ERROR("Need VPD set for custom label.\n"); + if (base_model->image) { + if (!model->image || + strcmp(base_model->image, model->image)) { + ERROR("The firmware image for custom label [%s] " + "does not match its base model [%s]\n", + base_model->name, model->name); return ++errorcnt; } } diff --git a/futility/updater.h b/futility/updater.h index ef57bd2e..0396390c 100644 --- a/futility/updater.h +++ b/futility/updater.h @@ -167,7 +167,7 @@ struct model_config { char *name; char *image, *ec_image; struct patch_config patches; - bool is_custom_label, is_unibuild; + bool has_custom_label; }; struct manifest { @@ -175,7 +175,6 @@ struct manifest { struct model_config *models; struct u_archive *archive; int default_model; - int has_keyset; }; enum updater_error_codes { @@ -270,8 +269,8 @@ char * updater_get_cbfs_quirks(struct updater_config *cfg); * Overrides signature id if the device was shipped with known * special rootkey. */ -int quirk_override_signature_id(struct updater_config *cfg, - struct model_config *model, +int quirk_override_signature_id(const struct updater_config *cfg, + const struct model_config *model, const char **signature_id); /* Functions from updater_archive.c */ @@ -368,15 +367,16 @@ manifest_detect_model_from_frid(struct updater_config *cfg, struct manifest *manifest); /* - * Applies custom label information to an existing model configuration. - * Collects signature ID information from either parameter signature_id or - * image file (via VPD) and updates model.patches for key files. - * Returns 0 on success, otherwise failure. + * Finds the custom label model config from the base model + system tag. + * The system tag came from the firmware VPD section. + * We may also override model+tag by the 'signature' parameter. + * Returns the matched model_config, base if no applicable custom label data, + * or NULL for any critical error. */ -int model_apply_custom_label( - struct model_config *model, - struct u_archive *archive, - const char *signature_id, - const char *image); +const struct model_config *manifest_find_custom_label_model( + struct updater_config *cfg, + const struct manifest *manifest, + const struct model_config *base_model, + const char *signature); #endif /* VBOOT_REFERENCE_FUTILITY_UPDATER_H_ */ diff --git a/futility/updater_manifest.c b/futility/updater_manifest.c index 48c8be5b..91eff5ef 100644 --- a/futility/updater_manifest.c +++ b/futility/updater_manifest.c @@ -22,30 +22,36 @@ * image files in the top folder: * - host: 'image.bin' * - ec: 'ec.bin' - * - pd: 'pd.bin' * - * If custom label is supported, a 'keyset/' folder will be available, with key - * files in it: - * - rootkey.$CLTAG - * - vblock_A.$CLTAG - * - vblock_B.$CLTAG + * A package for Unified Build is more complicated. * - * The $CLTAG should come from VPD value 'custom_label_tag'. For legacy devices, - * the VPD name may be 'whitelabel_tag', or 'customization_id'. - * The 'customization_id' has a different format: LOEM[-VARIANT] and we can only - * take LOEM as $CLTAG, for example A-B => $CLTAG=A. + * You need to look at the signer_config.csv file to find the columns of + * model_name, image files (firmware_image, ec_image) and then search for + * patch files (root key, vblock files, GSC verification data, ...) in the + * keyset/ folder: * - * A package for Unified Build is more complicated. + * - rootkey.$MODEL_NAME + * - vblock_A.$MODEL_NAME + * - vblock_B.$MODEL_NAME + * - gscvd.$MODEL_NAME + * + * In the runtime, the updater should query for firmware manifest key ( + * `crosid -f FIRMWARE_MANIFEST_KEY`) and use that to match the 'model_name' + * in the manifest database. * - * You need to look at the signer_config.csv file to find image files and their - * firmware manifest key (usually the same as the model name), then search for - * patch files in the keyset/ folder. + * If the model_name in `signer_config.csv` contains '-' then it is a custom + * label device. Today the FIRMWARE_MANIFEST_KEY from crosid won't handle custom + * label information and we have to add the custom label tag in the matching + * process. * - * Similar to custom label in non-Unified-Build, the keys and vblock files will - * be available in the 'keyset/' folder: - * - rootkey.$MANIFEST_KEY - * - vblock_A.$MANIFEST_KEY - * - vblock_B.$MANIFEST_KEY + * To do that, find the custom label tag from the VPD. + * - Newer devices: model_name = FIRMWARE_MANIFEST_KEY-$custom_label_tag + * - Old devices: model_name = FIRMWARE_MANIFEST_KEY-$whitelabel_tag + * + * For legacy devices manufactured before Unified Build, they have the VPD + * 'customization_id' in a special format: LOEM[-VARIANT]. + * For example: "A-B" => LOEM="A". + * - Legacy devices: model_name = FIRMWARE_MANIFEST_KEY-$LOEM */ static const char * const DEFAULT_MODEL_NAME = "default", @@ -350,8 +356,7 @@ static int manifest_from_signer_config(struct manifest *manifest) for (s = strtok_r(NULL, "\n", &tok_ptr); s != NULL; s = strtok_r(NULL, "\n", &tok_ptr)) { - struct model_config model = { .is_unibuild = true, }; - int discard_model = 0; + struct model_config model = {0}; /* * Both keyid (%3) and ec_image (%4) are optional so we want to @@ -360,47 +365,37 @@ static int manifest_from_signer_config(struct manifest *manifest) if (sscanf(s, "%m[^,],%m[^,],%*[^,],%m[^,]", &model.name, &model.image, &model.ec_image) < 2) { ERROR("Invalid entry(%s): %s\n", PATH_SIGNER_CONFIG, s); - discard_model = 1; - } else if (strchr(model.name, '-')) { - /* format: BaseModel-CustomLabel */ + free(model.name); + free(model.image); + free(model.ec_image); + continue; + } + + if (strchr(model.name, '-')) { + /* format: BaseModelName-CustomLabelTag */ + struct model_config *base_model; char *tok_dash; - char *base_model; - struct model_config *base_model_config; + char *base_name = strdup(model.name); VB2_DEBUG("Found custom-label: %s\n", model.name); - discard_model = 1; - base_model = strtok_r(model.name, "-", &tok_dash); - assert(base_model); + base_name = strtok_r(base_name, "-", &tok_dash); + assert(base_name); /* - * Currently we assume the base model (e.g., base_model) + * Currently we assume the base model (e.g., base_name) * is always listed before CL models in the CSV file - * this is based on how the signerbot and the * chromeos-config works today (validated on octopus). */ - base_model_config = manifest_get_model_config( - manifest, base_model); - - if (!base_model_config) { - ERROR("Invalid CL-model: %s\n", base_model); - } else if (!base_model_config->is_custom_label) { - base_model_config->is_custom_label = true; - /* - * Currently we are merging all custom label - * models into one single model in the manifest, - * and will discover the patches later from VPD. - * As a result, the existing patches should be - * cleared. - */ - clear_patch_config(&base_model_config->patches); + base_model = manifest_get_model_config(manifest, base_name); + + if (!base_model) { + ERROR("Invalid base model for custom label: %s\n", base_name); + } else if (!base_model->has_custom_label) { + base_model->has_custom_label = true; } - } - if (discard_model) { - free(model.name); - free(model.image); - free(model.ec_image); - continue; + free(base_name); } /* Find patch files. */ @@ -454,8 +449,6 @@ static int manifest_from_simple_folder(struct manifest *manifest) } if (!model.name) model.name = strdup(DEFAULT_MODEL_NAME); - if (manifest->has_keyset) - model.is_custom_label = true; manifest_add_model(manifest, &model); manifest->default_model = manifest->num - 1; @@ -579,94 +572,78 @@ manifest_detect_model_from_frid(struct updater_config *cfg, } /* - * Determines the signature ID to use for custom label. - * Returns the signature ID for looking up rootkey and vblock files. + * Determines the custom label tag. + * Returns the tag string, or NULL if not found. * Caller must free the returned string. */ -static char *resolve_signature_id(struct model_config *model, const char *image) +static char *get_custom_label_tag(const char *image_file) { - bool is_unibuild = model->is_unibuild; - char *tag = vpd_get_value(image, VPD_CUSTOM_LABEL_TAG); - char *sig_id = NULL; - - if (tag == NULL) - tag = vpd_get_value(image, VPD_CUSTOM_LABEL_TAG_LEGACY); + /* TODO(hungte) Switch to look at /sys/firmware/vpd/ro/$KEY. */ + char *tag; - /* - * All active non-unibuild devices have now migrated to run unibuild - * software, so we have to check customization_id first for those - * devices (in particular, 'haha'). - */ - /* The tag should be the LOEM part of the customization_id. */ - if (!tag) { - char *cid = vpd_get_value(image, VPD_CUSTOMIZATION_ID); - if (cid) { - /* customization_id in format LOEM[-VARIANT]. */ - char *dash = strchr(cid, '-'); - if (dash) - *dash = '\0'; - tag = cid; - WARN("From %s: tag=%s\n", VPD_CUSTOMIZATION_ID, tag); - } - } + tag = vpd_get_value(image_file, VPD_CUSTOM_LABEL_TAG); + if (tag) + return tag; - /* Unified build: $model.$tag, or $model (b/126800200). */ - if (is_unibuild) { - if (!tag) { - WARN("No VPD '%s' set for custom label. " - "Use model name '%s' as default.\n", - VPD_CUSTOM_LABEL_TAG, model->name); - return strdup(model->name); - } + tag = vpd_get_value(image_file, VPD_CUSTOM_LABEL_TAG_LEGACY); + if (tag) + return tag; - ASPRINTF(&sig_id, "%s-%s", model->name, tag); - free(tag); - return sig_id; - } + tag = vpd_get_value(image_file, VPD_CUSTOMIZATION_ID); + /* VPD_CUSTOMIZATION_ID is complicated and can't be returned directly. */ + if (!tag) + return NULL; - /* Non-unibuilds are always upper cased. */ - if (tag) - str_convert(tag, toupper); + /* For VPD_CUSTOMIZATION_ID=LOEM[-VARIANT], we need only capitalized LOEM. */ + INFO("Using deprecated custom label tag: %s=%s\n", VPD_CUSTOMIZATION_ID, tag); + char *dash = strchr(tag, '-'); + if (dash) + *dash = '\0'; + str_convert(tag, toupper); + VB2_DEBUG("Applied tag from %s: %s\n", tag, VPD_CUSTOMIZATION_ID); return tag; } -/* - * Applies custom label information to an existing model configuration. - * Collects signature ID information from either parameter signature_id or - * image file (via VPD) and updates model.patches for key files. - * Returns 0 on success, otherwise failure. - */ -int model_apply_custom_label( - struct model_config *model, - struct u_archive *archive, - const char *signature_id, - const char *image) +const struct model_config *manifest_find_custom_label_model( + struct updater_config *cfg, + const struct manifest *manifest, + const struct model_config *base_model, + const char *signature) { - char *sig_id = NULL; - int r = 0; - - if (!signature_id) { - sig_id = resolve_signature_id(model, image); - signature_id = sig_id; + const struct model_config *model = base_model; + char *new_sig = NULL; + + if (!signature) { + assert(cfg->image_current.data); + const char *tmp_image = get_firmware_image_temp_file( + &cfg->image_current, &cfg->tempfiles); + if (!tmp_image) { + ERROR("Failed to save the system firmware to a file.\n"); + return NULL; + } + char *tag = get_custom_label_tag(tmp_image); + if (!tag) { + WARN("No custom label tag (VPD '%s'). " + "Use default keys from the base model.\n", + VPD_CUSTOM_LABEL_TAG); + return base_model; + } + VB2_DEBUG("Found custom label tag: %s\n", tag); + ASPRINTF(&new_sig, "%s-%s", base_model->name, tag); + free(tag); + signature = new_sig; } + INFO("Find custom label model info using '%s'...\n", signature); + model = manifest_find_model(cfg, manifest, signature); - if (signature_id) { - VB2_DEBUG("Find custom label patches by signature ID: '%s'.\n", - signature_id); - find_patches_for_model(model, archive, signature_id); + if (model) { + INFO("Applied custom label model: %s\n", signature); } else { - signature_id = ""; - WARN("No VPD '%s' set for custom label - use default keys.\n", - VPD_CUSTOM_LABEL_TAG); + ERROR("Invalid custom label model: %s\n", signature); } - if (!model->patches.rootkey) { - ERROR("No keys found for signature_id: '%s'\n", signature_id); - r = 1; - } else { - INFO("Applied for custom label: %s\n", signature_id); - } - free(sig_id); - return r; + + free(new_sig); + return model; } static int manifest_from_build_artifacts(struct manifest *manifest) { @@ -690,9 +667,6 @@ struct manifest *new_manifest_from_archive(struct u_archive *archive) manifest.archive = archive; manifest.default_model = -1; - if (archive_has_entry(archive, PATH_KEYSET_FOLDER)) - manifest.has_keyset = 1; - VB2_DEBUG("Has keyset: %s\n", manifest.has_keyset ? "True" : "False"); for (i = 0; !manifest.num && i < ARRAY_SIZE(manifest_builders); i++) { /* diff --git a/futility/updater_quirks.c b/futility/updater_quirks.c index e84063f0..db76d387 100644 --- a/futility/updater_quirks.c +++ b/futility/updater_quirks.c @@ -564,8 +564,8 @@ char *updater_get_cbfs_quirks(struct updater_config *cfg) return (char *)data; } -int quirk_override_signature_id(struct updater_config *cfg, - struct model_config *model, +int quirk_override_signature_id(const struct updater_config *cfg, + const struct model_config *model, const char **signature_id) { const char * const DOPEFISH_KEY_HASH = @@ -574,7 +574,7 @@ int quirk_override_signature_id(struct updater_config *cfg, /* b/146876241 */ assert(model); if (strcmp(model->name, "phaser360") == 0) { - struct firmware_image *image = &cfg->image_current; + const struct firmware_image *image = &cfg->image_current; const char *key_hash = get_firmware_rootkey_hash(image); if (key_hash && strcmp(key_hash, DOPEFISH_KEY_HASH) == 0) { const char * const sig_dopefish = "phaser360-dopefish"; diff --git a/tests/futility/data/signer_config.csv b/tests/futility/data/signer_config.csv index d232073a..b2602fd0 100644 --- a/tests/futility/data/signer_config.csv +++ b/tests/futility/data/signer_config.csv @@ -1,5 +1,6 @@ model_name,firmware_image,key_id,ec_image,brand_code customtip,images/bios_coral.bin,DEFAULT,,ZZCR customtip-cl,images/bios_coral.bin,CL,,ZZCR +customtip-bad,images/bios_link.bin,CL,,ZZCR link,images/bios_link.bin,LINK,images/ec_link.bin,ZZCR peppy,images/bios_peppy.bin,PEPPY,images/ec_peppy.bin,ZZCR diff --git a/tests/futility/test_update.sh b/tests/futility/test_update.sh index f4000195..9eee1059 100755 --- a/tests/futility/test_update.sh +++ b/tests/futility/test_update.sh @@ -520,55 +520,20 @@ test_update "Full update (--archive, single package)" \ "${FROM_IMAGE}" "${TMP}.expected.full" \ -a "${A}" --wp=0 --sys_props ,,3 -echo "TEST: Output (--mode=output)" -mkdir -p "${TMP}.output" -"${FUTILITY}" update -i "${LINK_BIOS}" --mode=output \ - --output_dir="${TMP}.output" -cmp "${LINK_BIOS}" "${TMP}.output/image.bin" - -mkdir -p "${A}/keyset" +echo "TEST: Output (--archive, --mode=output)" +TMP_OUTPUT="${TMP}.out_archive" && mkdir -p "${TMP_OUTPUT}" +"${FUTILITY}" update -a "${A}" --mode=output \ + --output_dir="${TMP_OUTPUT}" +cmp "${TMP_OUTPUT}/image.bin" "${TO_IMAGE}" + +# Test Unified Build archives. +mkdir -p "${A}/keyset" "${A}/images" +cp -f "${SIGNER_CONFIG}" "${A}/" cp -f "${LINK_BIOS}" "${A}/image.bin" -cp -f "${TMP}.to/rootkey" "${A}/keyset/rootkey.CL" -cp -f "${TMP}.to/VBLOCK_A" "${A}/keyset/vblock_A.CL" -cp -f "${TMP}.to/VBLOCK_B" "${A}/keyset/vblock_B.CL" "${FUTILITY}" gbb -s --rootkey="${TMP}.from/rootkey" "${A}/image.bin" "${FUTILITY}" load_fmap "${A}/image.bin" VBLOCK_A:"${TMP}.from/VBLOCK_A" "${FUTILITY}" load_fmap "${A}/image.bin" VBLOCK_B:"${TMP}.from/VBLOCK_B" - -test_update "Full update (--archive, custom label, no VPD)" \ - "${A}/image.bin" "!Need VPD set for custom" \ - -a "${A}" --wp=0 --sys_props ,,3 - -test_update "Full update (--archive, custom label, no VPD - factory mode)" \ - "${LINK_BIOS}" "${A}/image.bin" \ - -a "${A}" --wp=0 --sys_props ,,3 --mode=factory - -test_update "Full update (--archive, custom label, no VPD - quirk mode)" \ - "${LINK_BIOS}" "${A}/image.bin" \ - -a "${A}" --wp=0 --sys_props ,,3 \ - --quirks=allow_empty_custom_label_tag - -test_update "Full update (--archive, custom label, single package)" \ - "${A}/image.bin" "${LINK_BIOS}" \ - -a "${A}" --wp=0 --sys_props ,,3 --signature_id=CL - -CL_TAG="CL" PATH="${A}/bin:${PATH}" \ - test_update "Full update (--archive, custom label, fake vpd)" \ - "${A}/image.bin" "${LINK_BIOS}" \ - -a "${A}" --wp=0 --sys_props ,,3 - -echo "TEST: Output (-a, --mode=output)" -mkdir -p "${TMP}.outa" -cp -f "${A}/image.bin" "${TMP}.emu" -CL_TAG="CL" PATH="${A}/bin:${PATH}" \ - "${FUTILITY}" update -a "${A}" --mode=output --emu="${TMP}.emu" \ - --output_dir="${TMP}.outa" -cmp "${LINK_BIOS}" "${TMP}.outa/image.bin" - -# Test archive with Unified Build contents. -cp -f "${SIGNER_CONFIG}" "${A}/" -mkdir -p "${A}/images" -mv "${A}/image.bin" "${A}/images/bios_coral.bin" +mv -f "${A}/image.bin" "${A}/images/bios_coral.bin" cp -f "${PEPPY_BIOS}" "${A}/images/bios_peppy.bin" cp -f "${LINK_BIOS}" "${A}/images/bios_link.bin" cp -f "${TMP}.to/rootkey" "${A}/keyset/rootkey.customtip-cl" @@ -589,10 +554,6 @@ test_update "Full update (--archive, model=peppy)" \ test_update "Full update (--archive, model=unknown)" \ "${FROM_IMAGE}.ap" "!Unsupported model: 'unknown'" \ -a "${A}" --wp=0 --sys_props 0,0x10001,3 --model=unknown -test_update "Full update (--archive, model=customtip, signature_id=CL)" \ - "${FROM_IMAGE}.al" "${LINK_BIOS}" \ - -a "${A}" --wp=0 --sys_props 0,0x10001,3 --model=customtip \ - --signature_id=customtip-cl test_update "Full update (--archive, detect-model)" \ "${FROM_IMAGE}.ap" "${PEPPY_BIOS}" \ @@ -608,21 +569,33 @@ echo "*** Test Item: Detect model (--archive, --detect-model-only)" --emulate "${FROM_IMAGE}.ap" --detect-model-only >"${TMP}.model.out" cmp "${TMP}.model.out" <(echo peppy) +test_update "Full update (--archive, custom label, signature_id=customtip-cl)" \ + "${FROM_IMAGE}.al" "${LINK_BIOS}" \ + -a "${A}" --wp=0 --sys_props 0,0x10001,3 --model=customtip \ + --signature_id=customtip-cl +CL_TAG="bad" PATH="${A}/bin:${PATH}" \ + test_update "Full update (--archive, custom label, wrong image)" \ + "${FROM_IMAGE}.al" "!The firmware image for custom label" \ + -a "${A}" --wp=0 --sys_props 0,0x10001,3 --debug --model=customtip CL_TAG="cl" PATH="${A}/bin:${PATH}" \ - test_update "Full update (-a, model=customtip, fake VPD)" \ + test_update "Full update (--archive, custom label, fake VPD)" \ "${FROM_IMAGE}.al" "${LINK_BIOS}" \ -a "${A}" --wp=0 --sys_props 0,0x10001,3 --model=customtip -# Custom label + Unibuild without default keys -test_update "Full update (--a, model=customtip, no VPD, no default keys)" \ - "${FROM_IMAGE}.al" "!Need VPD set for custom" \ - -a "${A}" --wp=0 --sys_props 0,0x10001,3 --model=customtip +# The output mode (without specifying signature id) for custom label would still +# need a source (emulate) image to decide the VPD, which is not a real use case. +echo "TEST: Output (--archive, --mode=output, custom label, signature_id)" +TMP_OUTPUT="${TMP}.out_custom_label" && mkdir -p "${TMP_OUTPUT}" +"${FUTILITY}" update -a "${A}" --mode=output \ + --output_dir="${TMP_OUTPUT}" --model=customtip \ + --signature_id=customtip-cl +cmp "${TMP_OUTPUT}/image.bin" "${LINK_BIOS}" # Custom label + Unibuild with default keys as model name cp -f "${TMP}.to/rootkey" "${A}/keyset/rootkey.customtip" cp -f "${TMP}.to/VBLOCK_A" "${A}/keyset/vblock_A.customtip" cp -f "${TMP}.to/VBLOCK_B" "${A}/keyset/vblock_B.customtip" -test_update "Full update (-a, model=customtip, no VPD, default keys)" \ +test_update "Full update (--archive, custom label, no VPD, default keys)" \ "${FROM_IMAGE}.al" "${LINK_BIOS}" \ -a "${A}" --wp=0 --sys_props 0,0x10001,3 --model=customtip @@ -677,9 +650,11 @@ if type ifdtool >/dev/null 2>&1; then --unlock_me -i "${TO_IMAGE}.ifd_chipset" --wp=0 echo "TEST: Output (--mode=output, --quirks unlock_csme)" + TMP_OUTPUT="${TMP}.out_csme" && mkdir -p "${TMP_OUTPUT}" + mkdir -p "${TMP_OUTPUT}" "${FUTILITY}" update -i "${TMP}.expected.ifd_chipset" --mode=output \ - --output_dir="${TMP}.output" --quirks unlock_csme - cmp "${TMP}.expected.me_unlocked.ifd_chipset" "${TMP}.output/image.bin" + --output_dir="${TMP_OUTPUT}" --quirks unlock_csme + cmp "${TMP_OUTPUT}/image.bin" "${TMP}.expected.me_unlocked.ifd_chipset" fi rm -rf "${TMP}"* From 7157a097757f1cc61e6690c10761b78268e45fac Mon Sep 17 00:00:00 2001 From: Hung-Te Lin Date: Sun, 22 Sep 2024 09:40:46 +0800 Subject: [PATCH 050/102] futility: updater: Remove 'allow_empty_custom_label_tag' quirk The 'allow_empty_custom_label_tag' quirk was introduced for non-unified builds to support custom label devices without a tag (customization_id) set. The only device use it is Hana, which is now a unified build. After CL:5872452, we are now able to directly load the default keys using the information provided by `signer_config.csv` even for Hana (and removed where the quirk was previously used), so this quirk is no longer needed. BUG=b:251040363 TEST=make runfutiltests -j BRANCH=None (cherry picked from commit 80955816aee0bcac10628c1f574b1a2a9b06f1c5) Change-Id: I14edd5f89d3518a4ba936a6c4df5e91368d03783 Original-Signed-off-by: Hung-Te Lin Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5879037 Original-Commit-Queue: ChromeOS Auto Retry Original-Reviewed-by: Yu-Ping Wu GitOrigin-RevId: 80955816aee0bcac10628c1f574b1a2a9b06f1c5 Cr-Build-Id: 8735377134969615841 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8735377134969615841 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5886255 Commit-Queue: Yu-Ping Wu Reviewed-by: Grzegorz Bernacki Reviewed-by: Yu-Ping Wu Tested-by: ChromeOS Prod (Robot) --- futility/updater.h | 1 - futility/updater_quirks.c | 8 -------- 2 files changed, 9 deletions(-) diff --git a/futility/updater.h b/futility/updater.h index 0396390c..051b8935 100644 --- a/futility/updater.h +++ b/futility/updater.h @@ -56,7 +56,6 @@ enum quirk_types { QUIRK_CLEAR_MRC_DATA, QUIRK_PRESERVE_ME, /* Platform-specific quirks (removed after AUE) */ - QUIRK_ALLOW_EMPTY_CUSTOM_LABEL_TAG, QUIRK_OVERRIDE_SIGNATURE_ID, QUIRK_EVE_SMM_STORE, QUIRK_UNLOCK_CSME_EVE, diff --git a/futility/updater_quirks.c b/futility/updater_quirks.c index db76d387..cbf495b6 100644 --- a/futility/updater_quirks.c +++ b/futility/updater_quirks.c @@ -40,8 +40,6 @@ static const struct quirks_record quirks_records[] = { { .match = "Google_Trogdor.", .quirks = "min_platform_version=2" }, /* Legacy custom label units. */ - /* reference design: oak */ - { .match = "Google_Hana.", .quirks = "allow_empty_custom_label_tag" }, /* reference design: octopus */ { .match = "Google_Phaser.", .quirks = "override_signature_id" }, @@ -455,12 +453,6 @@ void updater_register_quirks(struct updater_config *cfg) "dedicated FMAP section."; quirks->apply = quirk_eve_smm_store; - quirks = &cfg->quirks[QUIRK_ALLOW_EMPTY_CUSTOM_LABEL_TAG]; - quirks->name = "allow_empty_custom_label_tag"; - quirks->help = "chromium/906962; allow devices without custom label " - "tags set to use default keys."; - quirks->apply = NULL; /* Simple config. */ - quirks = &cfg->quirks[QUIRK_EC_PARTIAL_RECOVERY]; quirks->name = "ec_partial_recovery"; quirks->help = "chromium/1024401; recover EC by partial RO update."; From 57938c0d186729207593bbfc00552a71d315a9af Mon Sep 17 00:00:00 2001 From: Jakub Czapiga Date: Thu, 12 Sep 2024 13:05:53 +0000 Subject: [PATCH 051/102] Move futility and cgpt to vendor partition This patch is a cherrypick of: commit ef8f3c8635a6 ("Move futility and cgpt to vendor partition") Cherry-picked to synchronize ChromeOS and Android repos. BUG=b:366170141 TEST=m BRANCH=None (cherry picked from commit da1d153b4eed5f53f40e89b4f8a706711cf0f0eb) Original-Test: m Original-Bug: b:366170141 Change-Id: I96b9b86868540d20e7d8488fbcb38e91b3d3b40e Original-Signed-off-by: Jakub Czapiga Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5882100 Original-Reviewed-by: Hung-Te Lin GitOrigin-RevId: da1d153b4eed5f53f40e89b4f8a706711cf0f0eb Cr-Build-Id: 8735377134969615841 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8735377134969615841 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5886256 Reviewed-by: Yu-Ping Wu Tested-by: ChromeOS Prod (Robot) Commit-Queue: Yu-Ping Wu Reviewed-by: Grzegorz Bernacki --- Android.bp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Android.bp b/Android.bp index fb6391b9..8e08185e 100644 --- a/Android.bp +++ b/Android.bp @@ -81,6 +81,7 @@ cc_library_static { name: "tlcl", defaults: ["vboot_defaults"], host_supported: true, + vendor_available: true, srcs: [":tlcl_srcs"], } @@ -133,6 +134,7 @@ cc_library_static { name: "vboot_fw", defaults: ["vboot_defaults"], host_supported: true, + vendor_available: true, srcs: [":vboot_fw_srcs"], } @@ -167,6 +169,7 @@ cc_library_static { name: "libvboot_util", defaults: ["libvboot_defaults"], host_supported: true, + vendor_available: true, srcs: [ ":cgpt_common", @@ -221,6 +224,7 @@ cc_library_static { name: "libvboot_host", defaults: ["libvboot_defaults"], host_supported: true, + vendor_available: true, srcs: [ ":cgpt_common", @@ -283,6 +287,7 @@ cc_binary { name: "cgpt", defaults: ["vboot_defaults"], host_supported: true, + vendor: true, srcs: [ "cgpt/cgpt.c", @@ -374,6 +379,7 @@ cc_binary { name: "futility", defaults: ["vboot_defaults"], host_supported: true, + vendor: true, srcs: [":futility_srcs"], generated_sources: ["futility_cmds"], @@ -387,6 +393,7 @@ cc_binary { name: "crossystem", defaults: ["vboot_defaults"], host_supported: true, + vendor: true, srcs: ["utility/crossystem.c"], static_libs: ["libvboot_util"], From 40c6a5368d9d73edc3bf11e0bfe3544770055b10 Mon Sep 17 00:00:00 2001 From: Luzanne Batoon Date: Tue, 27 Aug 2024 21:18:24 -0700 Subject: [PATCH 052/102] sign_android_image: calculate and store the vb meta digest For verified boot, one of the boot parameters is the vb meta digest. The vb meta digest will be set to the hash of the hashes of the system and vendor images. The hash will be calculated and stored in a file in the same directory as the images. Later, the file will be read to retrieve the value for vb meta digest. ARC Keymint CL: https://crrev.com/c/5809618 BUG=b:350826304 TEST=./sign_android_unittests.sh TEST=manually compare arcvm_vbmeta_digest.sha256 and sha256sum output on dut with locally signed image BRANCH=none (cherry picked from commit 86b42b6a930c61e23b1df25c9994b75ef3bf48fb) Change-Id: Icab0a5002a6b0f6537c75b5124587b0a92270f26 Original-Signed-off-by: Luzanne Batoon Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5826996 Original-Reviewed-by: Vaibhav Raheja Original-Reviewed-by: Julius Werner GitOrigin-RevId: 86b42b6a930c61e23b1df25c9994b75ef3bf48fb Cr-Build-Id: 8735377134969615841 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8735377134969615841 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5892839 Tested-by: ChromeOS Prod (Robot) Reviewed-by: Yu-Ping Wu Commit-Queue: Yu-Ping Wu Reviewed-by: Grzegorz Bernacki --- scripts/image_signing/sign_android_image.sh | 60 +++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/scripts/image_signing/sign_android_image.sh b/scripts/image_signing/sign_android_image.sh index 1d2d9dea..48793765 100755 --- a/scripts/image_signing/sign_android_image.sh +++ b/scripts/image_signing/sign_android_image.sh @@ -417,6 +417,57 @@ list_files_in_squashfs_image() { "${unsquashfs}" -l "${system_img}" | grep ^squashfs-root } +# This function is needed to set the VB meta digest parameter for +# Verified Boot. The value is calculated by calculating the hash +# of hashes of the system and vendor images. It will be written +# to a file in the same directory as the system image and will be +# read by ARC Keymint. See ​​go/arc-vboot-param-design for more details. +write_arcvm_vbmeta_digest() { + local android_dir=$1 + local system_img_path=$2 + local vendor_img_path=$3 + + local vbmeta_digest_path="${android_dir}/arcvm_vbmeta_digest.sha256" + + # Calculate hashes of the system and vendor images. + local system_img_hash vendor_img_hash combined_hash vbmeta_digest + if ! system_img_hash=$(sha256sum -b "${system_img_path}"); then + warn "Error calculating system image hash" + return 1 + fi + if ! vendor_img_hash=$(sha256sum -b "${vendor_img_path}"); then + warn "Error calculating vendor image hash" + return 1 + fi + + # Cut off the end of sha256sum output since it includes the file name. + system_img_hash="$(echo -n "${system_img_hash}" | awk '{print $1}')" + vendor_img_hash="$(echo -n "${vendor_img_hash}" | awk '{print $1}')" + + # Combine the two hashes and calculate the hash of that value. + combined_hash=$(printf "%s%s" "${system_img_hash}" "${vendor_img_hash}") + if ! vbmeta_digest=$(echo -n "${combined_hash}" | sha256sum -b); then + warn "Error calculating the hash of the combined hash of the images" + return 1 + fi + + vbmeta_digest="$(echo -n "${vbmeta_digest}" | awk '{print $1}')" + + # If there is an existing digest, compare the two values. + if [[ -f "${vbmeta_digest_path}" ]]; then + local prev_vbmeta_digest + prev_vbmeta_digest=$(cat "${vbmeta_digest_path}") + if [[ "${vbmeta_digest}" == "${prev_vbmeta_digest}" ]]; then + warn "Error: existing and re-calculated digests are the same" + return 1 + fi + fi + + info "Writing re-calculated VB meta digest to arcvm_vbmeta_digest.sha256" + echo -n "${vbmeta_digest}" > "${vbmeta_digest_path}" + return 0 +} + sign_android_internal() { local root_fs_dir=$1 local key_dir=$2 @@ -691,6 +742,15 @@ sign_android_internal() { new_size=$(stat -c '%s' "${system_img}") info "Android system image size change: ${old_size} -> ${new_size}" + # Calculate the hash of the system and vendor images and store the value + # in a file. The digest was initially calculated and written when the + # image was built. This recalculates the digest of the signed image and + # replaces the original value. + # Any changes to the images must occur before this method. + if ! write_arcvm_vbmeta_digest "${android_dir}" "${system_img}" "${vendor_img}"; then + warn "ARCVM vbmeta digest was not overwritten" + fi + if d=$(grep -v -F -x -f "${working_dir}"/image_file_list.{new,orig}); then # If we have a line in image_file_list.orig which does not appear in # image_file_list.new, it means some files are removed during signing From c521087b9e6a0b3f4ec3b9681c6e772cdca99c4e Mon Sep 17 00:00:00 2001 From: Jakub Czapiga Date: Mon, 23 Sep 2024 14:15:53 +0000 Subject: [PATCH 053/102] host/lib/crossystem: Make CROSSYSTEM_LOCK_PATH configurable Android (and other systems) do not have `/run/lock` directory, which is used by crossystem by default to create a lockfile for its `set` operations. This issue can be circumvented by providing a way to configure this path via a define and making it configurable by `make` variable. For Android the `/data/local/tmp` was picked as it seems to be a default location for tools for this purpose. (See: Android gdbclient.py debug_socket and server_remote_path). Although this directory is persistent across reboots, the lock file is not required to be and path an be changed later to other one with e.g. tmpfs. Linux uses /run/lock starting from Filesystem Hierarchy Standard 3.0. Darwin/Mac use /tmp ad there is no direct equivalent of /run/lock. Windows uses C:\windows\temp. IMPORTANT!!!: Windows and Darwin were not tested. BUG=b:369294243, b:369290629 BRANCH=None TEST=crossystem dev_boot_usb=1 # On Android (cherry picked from commit 640fe19f5f9290be94cfc89634495e0f7b30ccee) Change-Id: I847f782fb5994185fbaf8f5dd23b60fc74a2c882 Original-Signed-off-by: Jakub Czapiga Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5882099 Original-Reviewed-by: Julius Werner Original-Commit-Queue: Julius Werner GitOrigin-RevId: 640fe19f5f9290be94cfc89634495e0f7b30ccee Cr-Build-Id: 8735377134969615841 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8735377134969615841 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5895562 Tested-by: ChromeOS Prod (Robot) Reviewed-by: Yu-Ping Wu Commit-Queue: Yu-Ping Wu --- Android.bp | 14 +++++++++++++- Makefile | 4 ++++ host/lib/crossystem.c | 2 +- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Android.bp b/Android.bp index 8e08185e..eae97950 100644 --- a/Android.bp +++ b/Android.bp @@ -63,8 +63,20 @@ cc_defaults { ], target: { + android: { + cflags: ["-DCROSSYSTEM_LOCK_DIR=\"/data/local/tmp\""], + }, darwin: { - cflags: ["-DHAVE_MACOS"], + cflags: [ + "-DHAVE_MACOS", + "-DCROSSYSTEM_LOCK_DIR=\"/tmp\"", + ], + }, + linux: { + cflags: ["-DCROSSYSTEM_LOCK_DIR=\"/run/lock\""], + }, + windows: { + cflags: ["-DCROSSYSTEM_LOCK_DIR=\"c:\\windows\\temp\""], }, }, } diff --git a/Makefile b/Makefile index 45d74114..b5c03309 100644 --- a/Makefile +++ b/Makefile @@ -218,6 +218,10 @@ else CFLAGS += -DEXTERNAL_TPM_CLEAR_REQUEST=0 endif +# Directory used by crossystem to create a lock file +CROSSYSTEM_LOCK_DIR := /run/lock +CFLAGS += -DCROSSYSTEM_LOCK_DIR=\"${CROSSYSTEM_LOCK_DIR}\" + # NOTE: We don't use these files but they are useful for other packages to # query about required compiling/linking flags. PC_IN_FILES = vboot_host.pc.in diff --git a/host/lib/crossystem.c b/host/lib/crossystem.c index 184979d5..7a19c779 100644 --- a/host/lib/crossystem.c +++ b/host/lib/crossystem.c @@ -25,7 +25,7 @@ #include "vboot_struct.h" /* Filename for crossystem lock */ -#define CROSSYSTEM_LOCK_PATH "/run/lock/crossystem.lock" +#define CROSSYSTEM_LOCK_PATH (CROSSYSTEM_LOCK_DIR "/crossystem.lock") /* Filename for kernel command line */ #define KERNEL_CMDLINE_PATH "/proc/cmdline" From 1ecb4857d54ffe269264670c3706c77ae8c70037 Mon Sep 17 00:00:00 2001 From: Arthur Heymans Date: Thu, 22 Aug 2024 19:58:35 +0200 Subject: [PATCH 054/102] Build thin archives The clang linker frontend, which is required for LTO only works with thin archives: https://github.com/llvm/llvm-project/issues/98290 (cherry picked from commit ac49f1ca939bbe4df7a29d3cf9a7cce543e12fd6) Change-Id: Ifcb7145a13718acb3f249455672c1d5033054414 Original-Signed-off-by: Arthur Heymans Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5803590 Original-Reviewed-by: Julius Werner Original-Commit-Queue: Julius Werner Original-Tested-by: Julius Werner GitOrigin-RevId: ac49f1ca939bbe4df7a29d3cf9a7cce543e12fd6 Cr-Build-Id: 8735377134969615841 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8735377134969615841 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5895563 Tested-by: ChromeOS Prod (Robot) Reviewed-by: Yu-Ping Wu Commit-Queue: Yu-Ping Wu --- Makefile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index b5c03309..abb54b60 100644 --- a/Makefile +++ b/Makefile @@ -980,7 +980,7 @@ ${FWLIB}: ${FWLIB_OBJS} @${PRINTF} " RM $(subst ${BUILD}/,,$@)\n" ${Q}rm -f $@ @${PRINTF} " AR $(subst ${BUILD}/,,$@)\n" - ${Q}ar qc $@ $^ + ${Q}ar qcT $@ $^ .PHONY: tlcl tlcl: ${TLCL} @@ -989,7 +989,7 @@ ${TLCL}: ${TLCL_OBJS} @${PRINTF} " RM $(subst ${BUILD}/,,$@)\n" ${Q}rm -f $@ @${PRINTF} " AR $(subst ${BUILD}/,,$@)\n" - ${Q}ar qc $@ $^ + ${Q}ar qcT $@ $^ # ---------------------------------------------------------------------------- # Host library(s) @@ -1008,7 +1008,7 @@ ${UTILLIB}: ${UTILLIB_OBJS} ${FWLIB_OBJS} ${TLCL_OBJS} @${PRINTF} " RM $(subst ${BUILD}/,,$@)\n" ${Q}rm -f $@ @${PRINTF} " AR $(subst ${BUILD}/,,$@)\n" - ${Q}ar qc $@ $^ + ${Q}ar qcT $@ $^ .PHONY: hostlib hostlib: ${HOSTLIB} ${HOSTLIB_STATIC} @@ -1018,7 +1018,7 @@ ${HOSTLIB_STATIC}: ${HOSTLIB_OBJS} @${PRINTF} " RM $(subst ${BUILD}/,,$@)\n" ${Q}rm -f $@ @${PRINTF} " AR $(subst ${BUILD}/,,$@)\n" - ${Q}ar qc $@ $^ + ${Q}ar qcT $@ $^ ${HOSTLIB}: ${HOSTLIB_OBJS} @${PRINTF} " RM $(subst ${BUILD}/,,$@)\n" @@ -1214,7 +1214,7 @@ ${TESTLIB}: ${TESTLIB_OBJS} @${PRINTF} " RM $(subst ${BUILD}/,,$@)\n" ${Q}rm -f $@ @${PRINTF} " AR $(subst ${BUILD}/,,$@)\n" - ${Q}ar qc $@ $^ + ${Q}ar qcT $@ $^ DUT_TEST_BINS = $(addprefix ${BUILD}/,${DUT_TEST_NAMES}) From ab3cb1a103f521f142a8d7cce57143ee7dd2622a Mon Sep 17 00:00:00 2001 From: Jakub Czapiga Date: Wed, 25 Sep 2024 09:15:08 +0000 Subject: [PATCH 055/102] host/lib/flashrom: Use flashrom provided in PATH Remove `/usr/sbin` path prefix from FLASHROM_EXEC_NAME path. The cbfstool is called this way, so there is no need to have differing requirements for other utility which needs to be provided anyway. BUG=b:369294243, b:369290629 BRANCH=None TEST=m; adb shell crossystem dev_boot_altfw=1 (cherry picked from commit 24fd715c90e89df1a90191c8ee1d3d78a29af758) Change-Id: Iff9fcfb8b40287d301bc552487c7fefa804d4a13 Original-Signed-off-by: Jakub Czapiga Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5890746 Original-Commit-Queue: Julius Werner Original-Reviewed-by: Julius Werner GitOrigin-RevId: 24fd715c90e89df1a90191c8ee1d3d78a29af758 Cr-Build-Id: 8735377134969615841 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8735377134969615841 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5895564 Tested-by: ChromeOS Prod (Robot) Commit-Queue: Yu-Ping Wu Reviewed-by: Yu-Ping Wu --- host/lib/flashrom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/host/lib/flashrom.c b/host/lib/flashrom.c index 8f0d4f91..6a802011 100644 --- a/host/lib/flashrom.c +++ b/host/lib/flashrom.c @@ -23,7 +23,7 @@ #include "flashrom.h" #include "subprocess.h" -#define FLASHROM_EXEC_NAME "/usr/sbin/flashrom" +#define FLASHROM_EXEC_NAME "flashrom" /** * Helper to create a temporary file, and optionally write some data From bc5f08fb873f3b44cf9e21e1e80f10da94f54e0b Mon Sep 17 00:00:00 2001 From: Tomasz Michalec Date: Tue, 1 Oct 2024 16:37:25 +0200 Subject: [PATCH 056/102] 2lib: Free avb_ops after reading misc partition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Free avb_ops after it last use which is calling vb2_bcb_command function. BUG=b:349304841 TEST=Boot Android kernel BRANCH=main Change-Id: I2470a1224d09af05202cf0af67a4a56cf6c010bf Signed-off-by: Tomasz Michalec Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5898677 Reviewed-by: Kornel Dulęba Reviewed-by: Grzegorz Bernacki --- firmware/2lib/2load_android_kernel.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/firmware/2lib/2load_android_kernel.c b/firmware/2lib/2load_android_kernel.c index 7a99906c..ea97f5f1 100644 --- a/firmware/2lib/2load_android_kernel.c +++ b/firmware/2lib/2load_android_kernel.c @@ -138,7 +138,6 @@ vb2_error_t vb2_load_android_kernel( avb_flags, AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, &verify_data); - vboot_avb_ops_free(avb_ops); free(ab_suffix); /* Ignore verification errors in developer mode */ @@ -164,10 +163,12 @@ vb2_error_t vb2_load_android_kernel( if (ret != AVB_SLOT_VERIFY_RESULT_OK) { if (verify_data != NULL) avb_slot_verify_data_free(verify_data); + vboot_avb_ops_free(avb_ops); return ret; } params->boot_command = vb2_bcb_command(avb_ops); + vboot_avb_ops_free(avb_ops); /* TODO(b/335901799): Add support for marking verifiedbootstate yellow */ /* Possible values for this property are "yellow", "orange" and "green" From 200b4c1d6950d5c9a68b8f96d8e8ac02e0aced46 Mon Sep 17 00:00:00 2001 From: Konrad Adamczyk Date: Fri, 4 Oct 2024 14:33:30 +0000 Subject: [PATCH 057/102] cgptlib: Fix OTA _b slot selection after update Function IsAndroidBootPartition() finds partition based on name parameter, which is encoded as USC-2. It uses 2 bytes per character, so memcmp() which is used for comparison should use name length multiplied by 2. This resulted in booting `always _a` slot, regardless of the priority/tries/successful flags on boot partition. BUG=b:368171802 TEST=`update-device brya-trunk_staging-userdebug` running the device on slot _a. `adb reboot`. Device boots successfully from new slot. BRANCH=firmware-android-15949.B Signed-off-by: Konrad Adamczyk Change-Id: Ib4ae8d969761ab3446d2b007c3f7780d4bbd52f6 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5904126 Commit-Queue: Konrad Adamczyk Tested-by: Konrad Adamczyk Tested-by: Grzegorz Bernacki Reviewed-by: Grzegorz Bernacki --- firmware/lib/cgptlib/cgptlib_internal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/lib/cgptlib/cgptlib_internal.c b/firmware/lib/cgptlib/cgptlib_internal.c index 5204cfc8..8ea68695 100644 --- a/firmware/lib/cgptlib/cgptlib_internal.c +++ b/firmware/lib/cgptlib/cgptlib_internal.c @@ -233,7 +233,7 @@ bool IsAndroidBootPartition(const GptEntry *e, const char *suffix) if (size_ucs2 < 0) goto cleanup; - if (memcmp(&e->name, name_ucs2, size_ucs2)) + if (memcmp(&e->name, name_ucs2, size_ucs2 * sizeof(*name_ucs2))) goto cleanup; is_android_boot_part = true; From 84dd90ec8f7bc8594e45734b130f3b08aed9676c Mon Sep 17 00:00:00 2001 From: Hung-Te Lin Date: Sat, 21 Sep 2024 17:55:30 +0800 Subject: [PATCH 058/102] Android Bringup: See http://go/android-fw-sync futility: updater: Deprecate `--signature_id` by `--model` The `--signature_id` was introduced to support specifying the custom label tag manually for debugging and generating pre-flash images. Before Unified Build, the argument expects only the key name and not the model name. However after Unified Build, the signature_id includes both model name and the custom label tag name, which makes it looking duplicated that you need both params: futility update --model poppy --signature_id poppy-ctl ... After CL:5872452, the custom label models are now treated like normal models so actually we can combine the `model` and `signature_id` arguments. Previously you can't specify the model + tag into `--model` but now you should do that as `--model MODEL-TAG` for the custom label devices. BUG=b:251040363 TEST=make runfutiltests -j BRANCH=None (cherry picked from commit 94d884d8a5bb0a237d24ff50423baa489be31df0) Cq-Depend: chromium:5872772 Change-Id: I16ef3f355fda246955a86e4bb415626e8762021d Original-Signed-off-by: Hung-Te Lin Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5872453 Original-Reviewed-by: Yu-Ping Wu GitOrigin-RevId: 94d884d8a5bb0a237d24ff50423baa489be31df0 Cr-Build-Id: 8734289971574337217 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8734289971574337217 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5912166 Reviewed-by: Jayvik Desai Reviewed-by: Jonathon Murphy Tested-by: ChromeOS Prod (Robot) --- futility/cmd_update.c | 17 +++++++++++++---- tests/futility/test_update.sh | 10 ++++------ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/futility/cmd_update.c b/futility/cmd_update.c index 77df9e1a..65648c6a 100644 --- a/futility/cmd_update.c +++ b/futility/cmd_update.c @@ -136,6 +136,7 @@ static void print_help(int argc, char *argv[]) " --force \tForce update (skip checking contents)\n" " --output_dir=DIR\tSpecify the target for --mode=output\n" " --unlock_me \t(deprecated) Unlock the Intel ME before flashing\n" + " --signature_id=S\t(deprecated) Same as --model\n" "\n" "Debugging and testing options:\n" " --wp=1|0 \tSpecify write protection status\n" @@ -143,7 +144,6 @@ static void print_help(int argc, char *argv[]) " --model=MODEL \tOverride system model for images\n" " --detect-model-only\tDetect model by reading the FRID and exit\n" " --gbb_flags=FLAG\tOverride new GBB flags\n" - " --signature_id=S\tOverride signature ID for key files\n" " --sys_props=LIST\tList of system properties to override\n" "-d, --debug \tPrint debugging messages\n" "-v, --verbose \tPrint verbose messages\n" @@ -158,6 +158,7 @@ static int do_update(int argc, char *argv[]) const char *prepare_ctrl_name = NULL; char *servo_programmer = NULL; char *endptr; + const char *sig = NULL; struct updater_config *cfg = updater_new_config(); assert(cfg); @@ -217,14 +218,22 @@ static int do_update(int argc, char *argv[]) args.output_dir = optarg; break; case OPT_MODEL: + if (sig) { + WARN("Ignore --model=%s because --signature_id=%s is already specified.\n", optarg, sig); + } else { + args.model = optarg; + } + break; + case OPT_SIGNATURE: + WARN("--signature_id is deprecated by --model. " + "Please change to `--model=%s` in future.\n", + optarg); + sig = optarg; args.model = optarg; break; case OPT_DETECT_MODEL_ONLY: args.detect_model_only = true; break; - case OPT_SIGNATURE: - args.signature_id = optarg; - break; case OPT_WRITE_PROTECTION: args.write_protection = optarg; break; diff --git a/tests/futility/test_update.sh b/tests/futility/test_update.sh index 9eee1059..4c0f5094 100755 --- a/tests/futility/test_update.sh +++ b/tests/futility/test_update.sh @@ -569,10 +569,9 @@ echo "*** Test Item: Detect model (--archive, --detect-model-only)" --emulate "${FROM_IMAGE}.ap" --detect-model-only >"${TMP}.model.out" cmp "${TMP}.model.out" <(echo peppy) -test_update "Full update (--archive, custom label, signature_id=customtip-cl)" \ +test_update "Full update (--archive, custom label with tag specified)" \ "${FROM_IMAGE}.al" "${LINK_BIOS}" \ - -a "${A}" --wp=0 --sys_props 0,0x10001,3 --model=customtip \ - --signature_id=customtip-cl + -a "${A}" --wp=0 --sys_props 0,0x10001,3 --model=customtip-cl CL_TAG="bad" PATH="${A}/bin:${PATH}" \ test_update "Full update (--archive, custom label, wrong image)" \ "${FROM_IMAGE}.al" "!The firmware image for custom label" \ @@ -584,11 +583,10 @@ CL_TAG="cl" PATH="${A}/bin:${PATH}" \ # The output mode (without specifying signature id) for custom label would still # need a source (emulate) image to decide the VPD, which is not a real use case. -echo "TEST: Output (--archive, --mode=output, custom label, signature_id)" +echo "TEST: Output (--archive, --mode=output, custom label with tag specified)" TMP_OUTPUT="${TMP}.out_custom_label" && mkdir -p "${TMP_OUTPUT}" "${FUTILITY}" update -a "${A}" --mode=output \ - --output_dir="${TMP_OUTPUT}" --model=customtip \ - --signature_id=customtip-cl + --output_dir="${TMP_OUTPUT}" --model=customtip-cl cmp "${TMP_OUTPUT}/image.bin" "${LINK_BIOS}" # Custom label + Unibuild with default keys as model name From e845733294b94b80eec8e7001fcb1e66fc798d0a Mon Sep 17 00:00:00 2001 From: Hung-Te Lin Date: Sun, 22 Sep 2024 11:33:10 +0800 Subject: [PATCH 059/102] Android Bringup: See http://go/android-fw-sync futility: updater: Add a new config 'output_only' There was no easy way to identify if the updater is running in output-only mode (`--mode=output`). However, some setup process (especially the custom label tag processing) will want to know if it is appropriate to read the system firmware. For example, the ODMs and factories will want to run `--mode=output` in the CrOS SDK to get the preflash image, and definitely not reading the host system firmware. After `--signature_id` is deprecated, specifying `--model` without tags will trigger reading system firmware. As a result, we need to identify if the updater is running in the output mode, and skip reading system firmware in that mode. Having the output_only will make it simpler instead of having the `strcmp(arg->mode, "output")` everywhere. BUG=b:251040363 TEST=make runfutiltests -j BRANCH=None (cherry picked from commit 90f591700475b68715f1f27fd30a0d712037cac6) Change-Id: I5181c9a31df7db12e04fdd362fe02ca08be29916 Original-Signed-off-by: Hung-Te Lin Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5879038 Original-Reviewed-by: Yu-Ping Wu GitOrigin-RevId: 90f591700475b68715f1f27fd30a0d712037cac6 Cr-Build-Id: 8734289971574337217 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8734289971574337217 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5912167 Tested-by: ChromeOS Prod (Robot) Reviewed-by: Jonathon Murphy Reviewed-by: Jayvik Desai --- futility/updater.c | 12 +++++------- futility/updater.h | 1 + 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/futility/updater.c b/futility/updater.c index ca1d0161..895dad41 100644 --- a/futility/updater.c +++ b/futility/updater.c @@ -1481,8 +1481,7 @@ static int check_arg_compatibility( } static int parse_arg_mode(struct updater_config *cfg, - const struct updater_config_arguments *arg, - bool *do_output) + const struct updater_config_arguments *arg) { if (!arg->mode) return 0; @@ -1501,7 +1500,7 @@ static int parse_arg_mode(struct updater_config *cfg, strcmp(arg->mode, "factory_install") == 0) { cfg->factory_update = 1; } else if (strcmp(arg->mode, "output") == 0) { - *do_output = 1; + cfg->output_only = true; } else { ERROR("Invalid mode: %s\n", arg->mode); return -1; @@ -1638,7 +1637,6 @@ int updater_setup_config(struct updater_config *cfg, int errorcnt = 0; int check_wp_disabled = 0; bool check_single_image = false; - bool do_output = false; const char *archive_path = arg->archive; /* Setup values that may change output or decision of other argument. */ @@ -1661,7 +1659,7 @@ int updater_setup_config(struct updater_config *cfg, if (arg->try_update) cfg->try_update = TRY_UPDATE_AUTO; - if (parse_arg_mode(cfg, arg, &do_output) < 0) + if (parse_arg_mode(cfg, arg) < 0) return 1; if (cfg->factory_update) { @@ -1752,7 +1750,7 @@ int updater_setup_config(struct updater_config *cfg, errorcnt += !!setup_config_quirks(arg->quirks, cfg); /* Additional checks. */ - if (check_single_image && !do_output && cfg->ec_image.data) { + if (check_single_image && !cfg->output_only && cfg->ec_image.data) { errorcnt++; ERROR("EC/PD images are not supported in current mode.\n"); } @@ -1771,7 +1769,7 @@ int updater_setup_config(struct updater_config *cfg, } /* The images are ready for updating. Output if needed. */ - if (!errorcnt && do_output) { + if (!errorcnt && cfg->output_only) { const char *r = arg->output_dir; if (!r) r = "."; diff --git a/futility/updater.h b/futility/updater.h index 051b8935..171aba2a 100644 --- a/futility/updater.h +++ b/futility/updater.h @@ -101,6 +101,7 @@ struct updater_config { uint32_t gbb_flags; bool detect_model; bool dut_is_remote; + bool output_only; }; struct updater_config_arguments { From f7fef79b2e36b23fd170dbce46f97a05eceeb7b8 Mon Sep 17 00:00:00 2001 From: Hung-Te Lin Date: Sat, 21 Sep 2024 22:50:57 +0800 Subject: [PATCH 060/102] Android Bringup: See http://go/android-fw-sync futility: updater: Drop `signature_id` from implementation The 'signature_id' in the updater was used for a several different use cases, including the custom label tag in pre-unibuild archives, model name (unibuild), model name + custom label tag (unibuild with custom label), firmware manifest key, ... etc. Given the `--model` has deprecated the `--signature_id`, we should also clean up the underlying implementation to prevent confusion. The quirk `override_signature_id` is now also renamed to `override_custom_label`. BUG=b:251040363 TEST=make runfutiltests -j BRANCH=None (cherry picked from commit 2a78755815d64019c581428715e960069c79ddab) Cq-Depend: chromium:5872772 Change-Id: I92adb148ca5e4b5db2fec2d9554061e11b81b6bb Original-Signed-off-by: Hung-Te Lin Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5872454 Original-Reviewed-by: Yu-Ping Wu GitOrigin-RevId: 2a78755815d64019c581428715e960069c79ddab Cr-Build-Id: 8734289971574337217 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8734289971574337217 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5915289 Reviewed-by: Jonathon Murphy Reviewed-by: Jayvik Desai Tested-by: ChromeOS Prod (Robot) --- futility/updater.c | 49 ++++++++++++++++------- futility/updater.h | 17 ++++---- futility/updater_manifest.c | 79 ++++++++++++++++++++----------------- futility/updater_quirks.c | 47 ++++++++++++++-------- 4 files changed, 116 insertions(+), 76 deletions(-) diff --git a/futility/updater.c b/futility/updater.c index 895dad41..3f05871c 100644 --- a/futility/updater.c +++ b/futility/updater.c @@ -1386,29 +1386,50 @@ static int updater_setup_archive( errorcnt += updater_load_images( cfg, arg, model->image, model->ec_image); - if (model->has_custom_label) { - + /* + * For custom label devices, we have to read the system firmware + * (image_current) to get the tag from VPD. Some quirks may also need + * the system firmware to identify if they should override the tags. + * + * The only exception is `--mode=output` (cfg->output_only), which we + * usually add `--model=MODEL` to specify the target model (note some + * people may still run without `--model` to get "the image to update + * when running on this device"). The MODEL can be either the BASEMODEL + * (has_custom_label=true) or BASEMODEL-TAG (has_custom_label=false). + * So the only case we have to warn the user that they may forget to + * provide the TAG is when has_custom_label=true (only BASEMODEL). + */ + if (cfg->output_only && arg->model && model->has_custom_label) { + printf(">> Generating output for a custom label device without tags (e.g., base model). " + "The firmware images will be signed using the base model (or DEFAULT) keys. " + "To get the images signed by the LOEM keys, " + "add the corresponding tag from one of the following list: \n"); + + size_t len = strlen(arg->model); + bool printed = false; + int i; + + for (i = 0; i < manifest->num; i++) { + const struct model_config *m = &manifest->models[i]; + if (strncmp(m->name, arg->model, len) || m->name[len] != '-') + continue; + printf("%s `--model=%s`", printed ? "," : "", m->name); + printed = true; + } + printf("\n\n"); + } else if (model->has_custom_label) { if (!cfg->image_current.data) { INFO("Loading system firmware for custom label...\n"); load_system_firmware(cfg, &cfg->image_current); } - const char *signature_id = arg->signature_id; - const struct model_config *base_model = model; - - if (!signature_id && - get_config_quirk(QUIRK_OVERRIDE_SIGNATURE_ID, cfg) && - is_ap_write_protection_enabled(cfg)) - quirk_override_signature_id( - cfg, model, &signature_id); - /* * For custom label devices, manifest_find_model may return the * base model instead of the custom label ones so we have to - * look up again using the signature_id. + * look up again. */ - model = manifest_find_custom_label_model( - cfg, manifest, base_model, signature_id); + const struct model_config *base_model = model; + model = manifest_find_custom_label_model(cfg, manifest, base_model); if (!model) return ++errorcnt; /* diff --git a/futility/updater.h b/futility/updater.h index 171aba2a..00f2c46b 100644 --- a/futility/updater.h +++ b/futility/updater.h @@ -56,7 +56,7 @@ enum quirk_types { QUIRK_CLEAR_MRC_DATA, QUIRK_PRESERVE_ME, /* Platform-specific quirks (removed after AUE) */ - QUIRK_OVERRIDE_SIGNATURE_ID, + QUIRK_OVERRIDE_CUSTOM_LABEL, QUIRK_EVE_SMM_STORE, QUIRK_UNLOCK_CSME_EVE, QUIRK_UNLOCK_CSME, @@ -108,7 +108,7 @@ struct updater_config_arguments { char *image, *ec_image; char *archive, *quirks, *mode; const char *programmer, *write_protection; - char *model, *signature_id; + char *model; char *emulation, *sys_props; char *output_dir; char *repack, *unpack; @@ -266,12 +266,13 @@ const char * const updater_get_model_quirks(struct updater_config *cfg); char * updater_get_cbfs_quirks(struct updater_config *cfg); /* - * Overrides signature id if the device was shipped with known + * Overrides the custom label config if the device was shipped with known * special rootkey. */ -int quirk_override_signature_id(const struct updater_config *cfg, - const struct model_config *model, - const char **signature_id); +const struct model_config *quirk_override_custom_label( + struct updater_config *cfg, + const struct manifest *manifest, + const struct model_config *model); /* Functions from updater_archive.c */ @@ -369,14 +370,12 @@ manifest_detect_model_from_frid(struct updater_config *cfg, /* * Finds the custom label model config from the base model + system tag. * The system tag came from the firmware VPD section. - * We may also override model+tag by the 'signature' parameter. * Returns the matched model_config, base if no applicable custom label data, * or NULL for any critical error. */ const struct model_config *manifest_find_custom_label_model( struct updater_config *cfg, const struct manifest *manifest, - const struct model_config *base_model, - const char *signature); + const struct model_config *base_model); #endif /* VBOOT_REFERENCE_FUTILITY_UPDATER_H_ */ diff --git a/futility/updater_manifest.c b/futility/updater_manifest.c index 91eff5ef..c9d8c509 100644 --- a/futility/updater_manifest.c +++ b/futility/updater_manifest.c @@ -205,8 +205,7 @@ int patch_image_by_model( * Updates `model` argument with path of patch files. */ static void find_patches_for_model(struct model_config *model, - struct u_archive *archive, - const char *signature_id) + struct u_archive *archive) { char *path; int i; @@ -227,7 +226,7 @@ static void find_patches_for_model(struct model_config *model, assert(ARRAY_SIZE(names) == ARRAY_SIZE(targets)); for (i = 0; i < ARRAY_SIZE(names); i++) { - ASPRINTF(&path, "%s%s.%s", PATH_KEYSET_FOLDER, names[i], signature_id); + ASPRINTF(&path, "%s%s.%s", PATH_KEYSET_FOLDER, names[i], model->name); if (archive_has_entry(archive, path)) *targets[i] = path; else @@ -336,8 +335,8 @@ static int manifest_from_signer_config(struct manifest *manifest) /* * CSV format: model_name,firmware_image,key_id,ec_image * - * Note the key_id is not signature_id and won't be used, and ec_image - * may be optional (for example sarien). + * Note the key_id is for signer and won't be used by the updater, + * and ec_image may be optional (for example sarien). */ if (archive_read_file(archive, PATH_SIGNER_CONFIG, &data, &size,NULL)) { @@ -399,7 +398,7 @@ static int manifest_from_signer_config(struct manifest *manifest) } /* Find patch files. */ - find_patches_for_model(&model, archive, model.name); + find_patches_for_model(&model, archive); if (!manifest_add_model(manifest, &model)) break; @@ -607,42 +606,50 @@ static char *get_custom_label_tag(const char *image_file) const struct model_config *manifest_find_custom_label_model( struct updater_config *cfg, const struct manifest *manifest, - const struct model_config *base_model, - const char *signature) + const struct model_config *base_model) { - const struct model_config *model = base_model; - char *new_sig = NULL; - - if (!signature) { - assert(cfg->image_current.data); - const char *tmp_image = get_firmware_image_temp_file( - &cfg->image_current, &cfg->tempfiles); - if (!tmp_image) { - ERROR("Failed to save the system firmware to a file.\n"); - return NULL; - } - char *tag = get_custom_label_tag(tmp_image); - if (!tag) { - WARN("No custom label tag (VPD '%s'). " - "Use default keys from the base model.\n", - VPD_CUSTOM_LABEL_TAG); - return base_model; - } - VB2_DEBUG("Found custom label tag: %s\n", tag); - ASPRINTF(&new_sig, "%s-%s", base_model->name, tag); - free(tag); - signature = new_sig; + const struct model_config *model; + + /* + * Some custom label devices shipped with wrong key and must change + * their model names to match the right data. + */ + if (get_config_quirk(QUIRK_OVERRIDE_CUSTOM_LABEL, cfg)) { + model = quirk_override_custom_label(cfg, manifest, base_model); + if (model) + return model; + } + + assert(cfg->image_current.data); + const char *tmp_image = get_firmware_image_temp_file( + &cfg->image_current, &cfg->tempfiles); + if (!tmp_image) { + ERROR("Failed to save the system firmware to a file.\n"); + return NULL; + } + + char *tag = get_custom_label_tag(tmp_image); + if (!tag) { + WARN("No custom label tag (VPD '%s'). " + "Use default keys from the base model '%s'.\n", + VPD_CUSTOM_LABEL_TAG, base_model->name); + return base_model; } - INFO("Find custom label model info using '%s'...\n", signature); - model = manifest_find_model(cfg, manifest, signature); + + VB2_DEBUG("Found custom label tag: %s (base=%s)\n", tag, base_model->name); + char *name; + ASPRINTF(&name, "%s-%s", base_model->name, tag); + free(tag); + + INFO("Find custom label model info using '%s'...\n", name); + model = manifest_find_model(cfg, manifest, name); if (model) { - INFO("Applied custom label model: %s\n", signature); + INFO("Applied custom label model: %s\n", name); } else { - ERROR("Invalid custom label model: %s\n", signature); + ERROR("Invalid custom label model: %s\n", name); } - - free(new_sig); + free(name); return model; } diff --git a/futility/updater_quirks.c b/futility/updater_quirks.c index cbf495b6..c31361dd 100644 --- a/futility/updater_quirks.c +++ b/futility/updater_quirks.c @@ -42,7 +42,7 @@ static const struct quirks_record quirks_records[] = { /* Legacy custom label units. */ /* reference design: octopus */ - { .match = "Google_Phaser.", .quirks = "override_signature_id" }, + { .match = "Google_Phaser.", .quirks = "override_custom_label" }, }; /* @@ -458,9 +458,9 @@ void updater_register_quirks(struct updater_config *cfg) quirks->help = "chromium/1024401; recover EC by partial RO update."; quirks->apply = quirk_ec_partial_recovery; - quirks = &cfg->quirks[QUIRK_OVERRIDE_SIGNATURE_ID]; - quirks->name = "override_signature_id"; - quirks->help = "chromium/146876241; override signature id for " + quirks = &cfg->quirks[QUIRK_OVERRIDE_CUSTOM_LABEL]; + quirks->name = "override_custom_label"; + quirks->help = "b/146876241; override custom label name for " "devices shipped with different root key."; quirks->apply = NULL; /* Simple config. */ @@ -556,25 +556,38 @@ char *updater_get_cbfs_quirks(struct updater_config *cfg) return (char *)data; } -int quirk_override_signature_id(const struct updater_config *cfg, - const struct model_config *model, - const char **signature_id) +const struct model_config *quirk_override_custom_label( + struct updater_config *cfg, + const struct manifest *manifest, + const struct model_config *model) { - const char * const DOPEFISH_KEY_HASH = - "9a1f2cc319e2f2e61237dc51125e35ddd4d20984"; + /* If not write protected, no need to apply the hack. */ + if (!is_ap_write_protection_enabled(cfg)) { + VB2_DEBUG("Skipped because AP not write protected.\n"); + return NULL; + } + + const struct firmware_image *image = &cfg->image_current; + assert(image && image->data); - /* b/146876241 */ - assert(model); if (strcmp(model->name, "phaser360") == 0) { - const struct firmware_image *image = &cfg->image_current; + /* b/146876241 */ const char *key_hash = get_firmware_rootkey_hash(image); + const char * const DOPEFISH_KEY_HASH = + "9a1f2cc319e2f2e61237dc51125e35ddd4d20984"; + if (key_hash && strcmp(key_hash, DOPEFISH_KEY_HASH) == 0) { - const char * const sig_dopefish = "phaser360-dopefish"; + const char * const dopefish = "phaser360-dopefish"; WARN("A Phaser360 with Dopefish rootkey - " - "override signature_id to '%s'.\n", sig_dopefish); - *signature_id = sig_dopefish; + "override custom label to '%s'.\n", dopefish); + model = manifest_find_model(cfg, manifest, dopefish); + if (model) + INFO("Model changed to '%s'.\n", model->name); + else + ERROR("No model defined for '%s'.\n", dopefish); + + return model; } } - - return 0; + return NULL; } From 6336ca6135fdac085d10b73eaff45f13dfc4b416 Mon Sep 17 00:00:00 2001 From: Hung-Te Lin Date: Mon, 7 Oct 2024 15:08:27 +0800 Subject: [PATCH 061/102] Android Bringup: See http://go/android-fw-sync futility: updater: Handle flashrom read failure in load_system_firmware In load_system_firmware, we have make sure the caller can still get the right "system current firmware image" because we may be running for the recovery mode with a broken firmware. Currently flashrom_read_image_impl will not free the allocated memory even if flashrom_image_read failed. So we should check the return value of flashrom_read_image, and release the firmware image structure on read failure. BUG=b:251040363 TEST=make runfutiltests -j BRANCH=None (cherry picked from commit 54be900d8e1ada40f384320b83c80909ab5c1d2b) Change-Id: I420625c8852796d25e5bbf4cf1920cdc27df7362 Original-Signed-off-by: Hung-Te Lin Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5905015 Original-Reviewed-by: Yu-Ping Wu GitOrigin-RevId: 54be900d8e1ada40f384320b83c80909ab5c1d2b Cr-Build-Id: 8734289971574337217 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8734289971574337217 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5915290 Reviewed-by: Jayvik Desai Reviewed-by: Jonathon Murphy Tested-by: ChromeOS Prod (Robot) --- futility/updater.c | 4 ++++ futility/updater_utils.c | 12 +++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/futility/updater.c b/futility/updater.c index 3f05871c..1196e6a7 100644 --- a/futility/updater.c +++ b/futility/updater.c @@ -1423,6 +1423,10 @@ static int updater_setup_archive( load_system_firmware(cfg, &cfg->image_current); } + if (!cfg->image_current.data) { + ERROR("Cannot read the system firmware for tags.\n"); + return ++errorcnt; + } /* * For custom label devices, manifest_find_model may return the * base model instead of the custom label ones so we have to diff --git a/futility/updater_utils.c b/futility/updater_utils.c index c581f0cd..545970eb 100644 --- a/futility/updater_utils.c +++ b/futility/updater_utils.c @@ -561,8 +561,18 @@ int load_system_firmware(struct updater_config *cfg, INFO("Reading SPI Flash..\n"); r = flashrom_read_image(image, NULL, 0, verbose); } - if (!r) + if (r) { + /* Read failure, the content cannot be trusted. */ + free_firmware_image(image); + } else { + /* + * Parse the contents. Note the image->data will remain even + * if parsing failed - this is important for system firmware + * because we may be trying to recover a device with corrupted + * firmware. + */ r = parse_firmware_image(image); + } return r; } From 05b7d4337311733975936d8100aebd1a04c6e7ee Mon Sep 17 00:00:00 2001 From: Hung-Te Lin Date: Mon, 23 Sep 2024 20:27:10 +0800 Subject: [PATCH 062/102] Android Bringup: See http://go/android-fw-sync futility: updater: Support emulation in the output mode The emulation (`--emulate`) actually can work in the output mode. Also remove the 'PD' in the help messages because we no longer supports that. BUG=None TEST=make runfutiltests -j BRANCH=None (cherry picked from commit 8494502d9f0bea4727fa6dfc7e504c99e400f568) Change-Id: I5ed39df6852769d8127d35a2aff8244de355b8d0 Original-Signed-off-by: Hung-Te Lin Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5882813 Original-Reviewed-by: Yu-Ping Wu GitOrigin-RevId: 8494502d9f0bea4727fa6dfc7e504c99e400f568 Cr-Build-Id: 8734289971574337217 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8734289971574337217 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5915291 Tested-by: ChromeOS Prod (Robot) Reviewed-by: Jayvik Desai Reviewed-by: Jonathon Murphy --- futility/cmd_update.c | 7 +++---- futility/updater.c | 8 +++++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/futility/cmd_update.c b/futility/cmd_update.c index 65648c6a..c000e70e 100644 --- a/futility/cmd_update.c +++ b/futility/cmd_update.c @@ -118,11 +118,10 @@ static void print_help(int argc, char *argv[]) " cached manifest (may be out-dated) from the archive.\n" " Works only with -a,--archive option.\n" " * Use of -p,--programmer with option other than '%s',\n" - " or with --ccd effectively disables ability to update EC and PD\n" + " or with --ccd effectively disables ability to update EC\n" " firmware images.\n" - " * Emulation works only with AP (host) firmware image, and does\n" - " not accept EC or PD firmware image, and does not work\n" - " with --mode=output\n" + " * Emulation works only with the AP (host) firmware image, and\n" + " does not support the EC firmware image.\n" " * Model detection with option --detect-model-only requires\n" " archive path -a,--archive\n" " * The --quirks provides a set of options to override the\n" diff --git a/futility/updater.c b/futility/updater.c index 1196e6a7..d21b8ae1 100644 --- a/futility/updater.c +++ b/futility/updater.c @@ -1322,11 +1322,17 @@ static int updater_load_images(struct updater_config *cfg, if (!errorcnt) errorcnt += updater_setup_quirks(cfg, arg); } - if (arg->host_only || arg->emulation) + + /* + * In emulation mode, we want to prevent unexpected writing to EC + * so we should not load EC; however in output mode that is fine. + */ + if (arg->host_only || (arg->emulation && !cfg->output_only)) return errorcnt; if (!cfg->ec_image.data && ec_image) errorcnt += !!load_firmware_image(&cfg->ec_image, ec_image, ar); + return errorcnt; } From 954b75fa6cc679af34632df34fe1ef41a519b1f7 Mon Sep 17 00:00:00 2001 From: Hung-Te Lin Date: Mon, 23 Sep 2024 20:53:31 +0800 Subject: [PATCH 063/102] Android Bringup: See http://go/android-fw-sync futility: updater: Revise the test script The `test_update.sh` was generating lots of test_update.sh.tmp* files in build/tests/futility_test_results/ that was mixed with other tests, and not really cleaned up before execution if the previous test failed. There are a few improvements here: - Change ${TMP}.XXX to ${TMP}/XXX, collecting all files in one folder. - Reset the folder before starting the tests. - Changed ${TMP}.XYZ.ABC to better names, for example ${EXPECTED}. BUG=None TEST=make runfutiltests -j BRANCH=None (cherry picked from commit 7d4b23f9a0541523debae852bbb2b22609d605ee) Change-Id: Id16d7642018a558756d5f93a0c63e1bbcada347a Original-Signed-off-by: Hung-Te Lin Original-Tested-by: Hung-Te Lin Original-Reviewed-by: Yu-Ping Wu Original-Auto-Submit: Hung-Te Lin GitOrigin-RevId: 7d4b23f9a0541523debae852bbb2b22609d605ee Cr-Build-Id: 8734289971574337217 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8734289971574337217 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5915792 Reviewed-by: Jonathon Murphy Tested-by: ChromeOS Prod (Robot) Reviewed-by: Jayvik Desai --- tests/futility/test_update.sh | 337 ++++++++++++++++++---------------- 1 file changed, 179 insertions(+), 158 deletions(-) diff --git a/tests/futility/test_update.sh b/tests/futility/test_update.sh index 4c0f5094..edea233b 100755 --- a/tests/futility/test_update.sh +++ b/tests/futility/test_update.sh @@ -40,12 +40,19 @@ RO_VPD_BLOB="${DATA_DIR}/ro_vpd.bin" SIGNER_CONFIG="${DATA_DIR}/signer_config.csv" # Work in scratch directory -cd "$OUTDIR" +cd "${OUTDIR}" set -o pipefail +# Re-create the temp folders +TMP_FROM="${TMP}/from" +TMP_TO="${TMP}/to" +EXPECTED="${TMP}/expected" +rm -rf "${TMP}" +mkdir -p "${TMP_FROM}" "${TMP_TO}" "${EXPECTED}" + # In all the test scenario, we want to test "updating from PEPPY to LINK". -TO_IMAGE="${TMP}.src.link" -FROM_IMAGE="${TMP}.src.peppy" +TO_IMAGE="${TMP}/src.link" +FROM_IMAGE="${TMP}/src.peppy" TO_HWID="X86 LINK TEST 6638" FROM_HWID="X86 PEPPY TEST 4211" cp -f "${LINK_BIOS}" "${TO_IMAGE}" @@ -84,10 +91,10 @@ patch_file "${FROM_IMAGE}" RW_FWID_B 0 Google. patch_file "${FROM_IMAGE}" RO_FRID 0 Google. unpack_image() { - local folder="${TMP}.$1" + local folder="${TMP}/$1" local image="$2" mkdir -p "${folder}" - (cd "${folder}" && "${FUTILITY}" dump_fmap -x "../${image}") + (cd "${folder}" && "${FUTILITY}" dump_fmap -x "../../${image}") "${FUTILITY}" gbb -g --rootkey="${folder}/rootkey" "${image}" } @@ -98,7 +105,7 @@ unpack_image "from" "${FROM_IMAGE}" # Hack FROM_IMAGE so it has same root key as TO_IMAGE (for RW update). FROM_DIFFERENT_ROOTKEY_IMAGE="${FROM_IMAGE}2" cp -f "${FROM_IMAGE}" "${FROM_DIFFERENT_ROOTKEY_IMAGE}" -"${FUTILITY}" gbb -s --rootkey="${TMP}.to/rootkey" "${FROM_IMAGE}" +"${FUTILITY}" gbb -s --rootkey="${TMP_TO}/rootkey" "${FROM_IMAGE}" # Hack for quirks cp -f "${FROM_IMAGE}" "${FROM_IMAGE}.large" @@ -108,7 +115,7 @@ truncate -s $((8388608 * 2)) "${FROM_IMAGE}.large" FROM_SAME_RO_IMAGE="${FROM_IMAGE}.same_ro" cp -f "${FROM_IMAGE}" "${FROM_SAME_RO_IMAGE}" "${FUTILITY}" load_fmap "${FROM_SAME_RO_IMAGE}" \ - "RO_SECTION:${TMP}.to/RO_SECTION" + "RO_SECTION:${TMP_TO}/RO_SECTION" # Create GBB v1.2 images (for checking digest) GBB_OUTPUT="$("${FUTILITY}" gbb --digest "${TO_IMAGE}")" @@ -130,61 +137,61 @@ cp -f "${FROM_IMAGE}.locked" "${FROM_IMAGE}.unlocked" patch_file "${FROM_IMAGE}.unlocked" SI_DESC 0x60 \ "\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff" "${FUTILITY}" load_fmap "${FROM_IMAGE}.locked_same_desc" \ - "SI_DESC:${TMP}.to/SI_DESC" + "SI_DESC:${TMP_TO}/SI_DESC" # Generate expected results. -cp -f "${TO_IMAGE}" "${TMP}.expected.full" -cp -f "${FROM_IMAGE}" "${TMP}.expected.rw" -cp -f "${FROM_IMAGE}" "${TMP}.expected.a" -cp -f "${FROM_IMAGE}" "${TMP}.expected.b" -cp -f "${FROM_SAME_RO_IMAGE}" "${TMP}.FROM_SAME_RO_IMAGE.expected.b" -cp -f "${FROM_IMAGE}" "${TMP}.expected.legacy" -"${FUTILITY}" gbb -s --hwid="${FROM_HWID}" "${TMP}.expected.full" -"${FUTILITY}" load_fmap "${TMP}.expected.full" \ - "RW_VPD:${TMP}.from/RW_VPD" \ - "RO_VPD:${TMP}.from/RO_VPD" -"${FUTILITY}" load_fmap "${TMP}.expected.rw" \ - "RW_SECTION_A:${TMP}.to/RW_SECTION_A" \ - "RW_SECTION_B:${TMP}.to/RW_SECTION_B" \ - "RW_SHARED:${TMP}.to/RW_SHARED" \ - "RW_LEGACY:${TMP}.to/RW_LEGACY" -"${FUTILITY}" load_fmap "${TMP}.expected.a" \ - "RW_SECTION_A:${TMP}.to/RW_SECTION_A" -"${FUTILITY}" load_fmap "${TMP}.expected.b" \ - "RW_SECTION_B:${TMP}.to/RW_SECTION_B" -"${FUTILITY}" load_fmap "${TMP}.FROM_SAME_RO_IMAGE.expected.b" \ - "RW_SECTION_B:${TMP}.to/RW_SECTION_B" -"${FUTILITY}" load_fmap "${TMP}.expected.legacy" \ - "RW_LEGACY:${TMP}.to/RW_LEGACY" -cp -f "${TMP}.expected.full" "${TMP}.expected.full.gbb12" -patch_file "${TMP}.expected.full.gbb12" GBB 6 "\x02" -"${FUTILITY}" gbb -s --hwid="${FROM_HWID}" "${TMP}.expected.full.gbb12" -cp -f "${TMP}.expected.full" "${TMP}.expected.full.gbb0" -"${FUTILITY}" gbb -s --flags=0 "${TMP}.expected.full.gbb0" +cp -f "${TO_IMAGE}" "${EXPECTED}/full" +cp -f "${FROM_IMAGE}" "${EXPECTED}/rw" +cp -f "${FROM_IMAGE}" "${EXPECTED}/a" +cp -f "${FROM_IMAGE}" "${EXPECTED}/b" +cp -f "${FROM_SAME_RO_IMAGE}" "${EXPECTED}/FROM_SAME_RO_IMAGE.b" +cp -f "${FROM_IMAGE}" "${EXPECTED}/legacy" +"${FUTILITY}" gbb -s --hwid="${FROM_HWID}" "${EXPECTED}/full" +"${FUTILITY}" load_fmap "${EXPECTED}/full" \ + "RW_VPD:${TMP_FROM}/RW_VPD" \ + "RO_VPD:${TMP_FROM}/RO_VPD" +"${FUTILITY}" load_fmap "${EXPECTED}/rw" \ + "RW_SECTION_A:${TMP_TO}/RW_SECTION_A" \ + "RW_SECTION_B:${TMP_TO}/RW_SECTION_B" \ + "RW_SHARED:${TMP_TO}/RW_SHARED" \ + "RW_LEGACY:${TMP_TO}/RW_LEGACY" +"${FUTILITY}" load_fmap "${EXPECTED}/a" \ + "RW_SECTION_A:${TMP_TO}/RW_SECTION_A" +"${FUTILITY}" load_fmap "${EXPECTED}/b" \ + "RW_SECTION_B:${TMP_TO}/RW_SECTION_B" +"${FUTILITY}" load_fmap "${EXPECTED}/FROM_SAME_RO_IMAGE.b" \ + "RW_SECTION_B:${TMP_TO}/RW_SECTION_B" +"${FUTILITY}" load_fmap "${EXPECTED}/legacy" \ + "RW_LEGACY:${TMP_TO}/RW_LEGACY" +cp -f "${EXPECTED}/full" "${EXPECTED}/full.gbb12" +patch_file "${EXPECTED}/full.gbb12" GBB 6 "\x02" +"${FUTILITY}" gbb -s --hwid="${FROM_HWID}" "${EXPECTED}/full.gbb12" +cp -f "${EXPECTED}/full" "${EXPECTED}/full.gbb0" +"${FUTILITY}" gbb -s --flags=0 "${EXPECTED}/full.gbb0" cp -f "${FROM_IMAGE}" "${FROM_IMAGE}.gbb0" "${FUTILITY}" gbb -s --flags=0 "${FROM_IMAGE}.gbb0" -cp -f "${TMP}.expected.full" "${TMP}.expected.full.gbb0x27" -"${FUTILITY}" gbb -s --flags=0x27 "${TMP}.expected.full.gbb0x27" -cp -f "${TMP}.expected.full" "${TMP}.expected.large" -dd if=/dev/zero bs=8388608 count=1 | tr '\000' '\377' >>"${TMP}.expected.large" -cp -f "${TMP}.expected.full" "${TMP}.expected.me_unlocked_eve" -patch_file "${TMP}.expected.me_unlocked_eve" SI_DESC 0x60 \ +cp -f "${EXPECTED}/full" "${EXPECTED}/full.gbb0x27" +"${FUTILITY}" gbb -s --flags=0x27 "${EXPECTED}/full.gbb0x27" +cp -f "${EXPECTED}/full" "${EXPECTED}/large" +dd if=/dev/zero bs=8388608 count=1 | tr '\000' '\377' >>"${EXPECTED}/large" +cp -f "${EXPECTED}/full" "${EXPECTED}/me_unlocked_eve" +patch_file "${EXPECTED}/me_unlocked_eve" SI_DESC 0x60 \ "\x00\xff\xff\xff\x00\xff\xff\xff\x00\xff\xff\xff" -cp -f "${TMP}.expected.full" "${TMP}.expected.me_preserved" -"${FUTILITY}" load_fmap "${TMP}.expected.me_preserved" \ - "SI_ME:${TMP}.from/SI_ME" -cp -f "${TMP}.expected.rw" "${TMP}.expected.rw.locked" -patch_file "${TMP}.expected.rw.locked" FMAP 0x0430 "RO_GSCVD\x00" +cp -f "${EXPECTED}/full" "${EXPECTED}/me_preserved" +"${FUTILITY}" load_fmap "${EXPECTED}/me_preserved" \ + "SI_ME:${TMP_FROM}/SI_ME" +cp -f "${EXPECTED}/rw" "${EXPECTED}/rw.locked" +patch_file "${EXPECTED}/rw.locked" FMAP 0x0430 "RO_GSCVD\x00" # A special set of images that only RO_VPD is preserved (RW_VPD is wiped) using # FMAP_AREA_PRESERVE (\010=0x08). TO_IMAGE_WIPE_RW_VPD="${TO_IMAGE}.wipe_rw_vpd" cp -f "${TO_IMAGE}" "${TO_IMAGE_WIPE_RW_VPD}" patch_file "${TO_IMAGE_WIPE_RW_VPD}" FMAP 0x3fc "$(printf '\010')" -cp -f "${TMP}.expected.full" "${TMP}.expected.full.empty_rw_vpd" -"${FUTILITY}" load_fmap "${TMP}.expected.full.empty_rw_vpd" \ - RW_VPD:"${TMP}.to/RW_VPD" -patch_file "${TMP}.expected.full.empty_rw_vpd" FMAP 0x3fc "$(printf '\010')" +cp -f "${EXPECTED}/full" "${EXPECTED}/full.empty_rw_vpd" +"${FUTILITY}" load_fmap "${EXPECTED}/full.empty_rw_vpd" \ + RW_VPD:"${TMP_TO}/RW_VPD" +patch_file "${EXPECTED}/full.empty_rw_vpd" FMAP 0x3fc "$(printf '\010')" # Generate images for testing --unlock_me. # There are two ways to detect the platform: @@ -194,23 +201,25 @@ patch_file "${TMP}.expected.full.empty_rw_vpd" FMAP 0x3fc "$(printf '\010')" # Rename BOOT_STUB to COREBOOT, which is the default region used by cbfstool. rename_boot_stub() { local image="$1" + local fmap_file="${TMP}/fmap" - "${FUTILITY}" dump_fmap "${image}" -x "FMAP:${TMP}.fmap" - sed -i 's/BOOT_STUB/COREBOOT\x00/g' "${TMP}.fmap" - "${FUTILITY}" load_fmap "${image}" "FMAP:${TMP}.fmap" + "${FUTILITY}" dump_fmap "${image}" -x "FMAP:${fmap_file}" + sed -i 's/BOOT_STUB/COREBOOT\x00/g' "${fmap_file}" + "${FUTILITY}" load_fmap "${image}" "FMAP:${fmap_file}" } # Add the given line to the config file in CBFS. add_config() { local image="$1" local config_line="$2" + local config_file="${TMP}/config" rename_boot_stub "${image}" - cbfstool "${image}" extract -n config -f "${TMP}.config" - echo "${config_line}" >> "${TMP}.config" + cbfstool "${image}" extract -n config -f "${config_file}" + echo "${config_line}" >>"${config_file}" cbfstool "${image}" remove -n config - cbfstool "${image}" add -n config -f "${TMP}.config" -t raw + cbfstool "${image}" add -n config -f "${config_file}" -t raw } unlock_me() { @@ -222,21 +231,21 @@ unlock_me() { "\x00\x00\x00\x00" } -IFD_CHIPSET="CONFIG_IFD_CHIPSET=\"adl\"" -IFD_PATH="CONFIG_IFD_BIN_PATH=\"3rdparty/blobs/mainboard/google/nissa/descriptor-craask.bin\"" +IFD_CHIPSET='CONFIG_IFD_CHIPSET="adl"' +IFD_PATH='CONFIG_IFD_BIN_PATH="3rdparty/blobs/mainboard/google/nissa/descriptor-craask.bin"' cp -f "${TO_IMAGE}" "${TO_IMAGE}.ifd_chipset" cp -f "${TO_IMAGE}" "${TO_IMAGE}.ifd_path" -cp -f "${TMP}.expected.full" "${TMP}.expected.ifd_chipset" -cp -f "${TMP}.expected.full" "${TMP}.expected.ifd_path" +cp -f "${EXPECTED}/full" "${EXPECTED}/ifd_chipset" +cp -f "${EXPECTED}/full" "${EXPECTED}/ifd_path" add_config "${TO_IMAGE}.ifd_chipset" "${IFD_CHIPSET}" add_config "${TO_IMAGE}.ifd_path" "${IFD_PATH}" -add_config "${TMP}.expected.ifd_chipset" "${IFD_CHIPSET}" -add_config "${TMP}.expected.ifd_path" "${IFD_PATH}" +add_config "${EXPECTED}/ifd_chipset" "${IFD_CHIPSET}" +add_config "${EXPECTED}/ifd_path" "${IFD_PATH}" -cp -f "${TMP}.expected.ifd_chipset" "${TMP}.expected.me_unlocked.ifd_chipset" -cp -f "${TMP}.expected.ifd_path" "${TMP}.expected.me_unlocked.ifd_path" -unlock_me "${TMP}.expected.me_unlocked.ifd_chipset" -unlock_me "${TMP}.expected.me_unlocked.ifd_path" +cp -f "${EXPECTED}/ifd_chipset" "${EXPECTED}/me_unlocked.ifd_chipset" +cp -f "${EXPECTED}/ifd_path" "${EXPECTED}/me_unlocked.ifd_path" +unlock_me "${EXPECTED}/me_unlocked.ifd_chipset" +unlock_me "${EXPECTED}/me_unlocked.ifd_path" # Has 3 modes: # 1. $3 = "!something", run command, expect failure, @@ -249,17 +258,18 @@ test_update() { local emu_src="$2" local expected="$3" local error_msg="${expected#!}" + local emu="${TMP}/emu" local msg shift 3 - cp -f "${emu_src}" "${TMP}.emu" + cp -f "${emu_src}" "${emu}" echo "*** Test Item: ${test_name}" if [ "${error_msg}" != "${expected}" ] && [ -n "${error_msg}" ]; then - msg="$(! "${FUTILITY}" update --emulate "${TMP}.emu" "$@" 2>&1)" + msg="$(! "${FUTILITY}" update --emulate "${emu}" "$@" 2>&1)" grep -qF -- "${error_msg}" <<<"${msg}" else - "${FUTILITY}" update --emulate "${TMP}.emu" "$@" - cmp "${TMP}.emu" "${expected}" + "${FUTILITY}" update --emulate "${emu}" "$@" + cmp "${emu}" "${expected}" fi } @@ -269,7 +279,7 @@ test_update() { # Test Full update. test_update "Full update" \ - "${FROM_IMAGE}" "${TMP}.expected.full" \ + "${FROM_IMAGE}" "${EXPECTED}/full" \ -i "${TO_IMAGE}" --wp=0 test_update "Full update (incompatible platform)" \ @@ -285,7 +295,7 @@ test_update "Full update (TPM Anti-rollback: kernel key)" \ -i "${TO_IMAGE}" --wp=0 --sys_props 1,0x10005 test_update "Full update (TPM Anti-rollback: 0 as tpm_fwver)" \ - "${FROM_IMAGE}" "${TMP}.expected.full" \ + "${FROM_IMAGE}" "${EXPECTED}/full" \ -i "${TO_IMAGE}" --wp=0 --sys_props ,0x0 test_update "Full update (TPM check failure due to invalid tpm_fwver)" \ @@ -293,37 +303,37 @@ test_update "Full update (TPM check failure due to invalid tpm_fwver)" \ -i "${TO_IMAGE}" --wp=0 --sys_props ,-1 test_update "Full update (Skip TPM check with --force)" \ - "${FROM_IMAGE}" "${TMP}.expected.full" \ + "${FROM_IMAGE}" "${EXPECTED}/full" \ -i "${TO_IMAGE}" --wp=0 --sys_props ,-1 --force test_update "Full update (from stdin)" \ - "${FROM_IMAGE}" "${TMP}.expected.full" \ + "${FROM_IMAGE}" "${EXPECTED}/full" \ -i - --wp=0 --sys_props ,-1 --force <"${TO_IMAGE}" test_update "Full update (GBB=0 -> 0)" \ - "${FROM_IMAGE}.gbb0" "${TMP}.expected.full.gbb0" \ + "${FROM_IMAGE}.gbb0" "${EXPECTED}/full.gbb0" \ -i "${TO_IMAGE}" --wp=0 test_update "Full update (GBB flags -> 0x27)" \ - "${FROM_IMAGE}" "${TMP}.expected.full.gbb0x27" \ + "${FROM_IMAGE}" "${EXPECTED}/full.gbb0x27" \ -i "${TO_IMAGE}" --gbb_flags=0x27 --wp=0 test_update "Full update (--host_only)" \ - "${FROM_IMAGE}" "${TMP}.expected.full" \ + "${FROM_IMAGE}" "${EXPECTED}/full" \ -i "${TO_IMAGE}" --wp=0 --host_only --ec_image non-exist.bin test_update "Full update (GBB1.2 hwid digest)" \ - "${FROM_IMAGE}" "${TMP}.expected.full.gbb12" \ + "${FROM_IMAGE}" "${EXPECTED}/full.gbb12" \ -i "${TO_IMAGE_GBB12}" --wp=0 test_update "Full update (Preserve VPD using FMAP_AREA_PRESERVE)" \ - "${FROM_IMAGE}" "${TMP}.expected.full.empty_rw_vpd" \ + "${FROM_IMAGE}" "${EXPECTED}/full.empty_rw_vpd" \ -i "${TO_IMAGE_WIPE_RW_VPD}" --wp=0 # Test RW-only update. test_update "RW update" \ - "${FROM_IMAGE}" "${TMP}.expected.rw" \ + "${FROM_IMAGE}" "${EXPECTED}/rw" \ -i "${TO_IMAGE}" --wp=1 test_update "RW update (incompatible platform)" \ @@ -344,23 +354,23 @@ test_update "RW update (TPM Anti-rollback: kernel key)" \ # Test Try-RW update (vboot2). test_update "RW update (A->B)" \ - "${FROM_IMAGE}" "${TMP}.expected.b" \ + "${FROM_IMAGE}" "${EXPECTED}/b" \ -i "${TO_IMAGE}" -t --wp=1 --sys_props 0 test_update "RW update (B->A)" \ - "${FROM_IMAGE}" "${TMP}.expected.a" \ + "${FROM_IMAGE}" "${EXPECTED}/a" \ -i "${TO_IMAGE}" -t --wp=1 --sys_props 1 test_update "RW update, same RO, wp=0 (A->B)" \ - "${FROM_SAME_RO_IMAGE}" "${TMP}.FROM_SAME_RO_IMAGE.expected.b" \ + "${FROM_SAME_RO_IMAGE}" "${EXPECTED}/FROM_SAME_RO_IMAGE.b" \ -i "${TO_IMAGE}" -t --wp=0 --sys_props 0 test_update "RW update, same RO, wp=1 (A->B)" \ - "${FROM_SAME_RO_IMAGE}" "${TMP}.FROM_SAME_RO_IMAGE.expected.b" \ + "${FROM_SAME_RO_IMAGE}" "${EXPECTED}/FROM_SAME_RO_IMAGE.b" \ -i "${TO_IMAGE}" -t --wp=1 --sys_props 0 test_update "RW update -> fallback to RO+RW Full update" \ - "${FROM_IMAGE}" "${TMP}.expected.full" \ + "${FROM_IMAGE}" "${EXPECTED}/full" \ -i "${TO_IMAGE}" -t --wp=0 --sys_props 1,0x10002 test_update "RW update (incompatible platform)" \ "${FROM_IMAGE}" "!platform is not compatible" \ @@ -384,11 +394,11 @@ test_update "RW update -> fallback to RO+RW Full update (TPM Anti-rollback)" \ # Test 'factory mode' test_update "Factory mode update (WP=0)" \ - "${FROM_IMAGE}" "${TMP}.expected.full" \ + "${FROM_IMAGE}" "${EXPECTED}/full" \ -i "${TO_IMAGE}" --wp=0 --mode=factory test_update "Factory mode update (WP=0)" \ - "${FROM_IMAGE}" "${TMP}.expected.full" \ + "${FROM_IMAGE}" "${EXPECTED}/full" \ --factory -i "${TO_IMAGE}" --wp=0 test_update "Factory mode update (WP=1)" \ @@ -400,25 +410,25 @@ test_update "Factory mode update (WP=1)" \ --factory -i "${TO_IMAGE}" --wp=1 test_update "Factory mode update (GBB=0 -> 0x39)" \ - "${FROM_IMAGE}.gbb0" "${TMP}.expected.full" \ + "${FROM_IMAGE}.gbb0" "${EXPECTED}/full" \ --factory -i "${TO_IMAGE}" --wp=0 # Test 'AP RO locked with verification turned on' test_update "AP RO locked update (locked, SI_DESC is different)" \ - "${FROM_IMAGE}.locked" "${TMP}.expected.rw.locked" \ + "${FROM_IMAGE}.locked" "${EXPECTED}/rw.locked" \ -i "${TO_IMAGE}" --wp=0 --debug test_update "AP RO locked update (locked, SI_DESC is the same)" \ - "${FROM_IMAGE}.locked_same_desc" "${TMP}.expected.full" \ + "${FROM_IMAGE}.locked_same_desc" "${EXPECTED}/full" \ -i "${TO_IMAGE}" --wp=0 --debug test_update "AP RO locked update (unlocked)" \ - "${FROM_IMAGE}.unlocked" "${TMP}.expected.full" \ + "${FROM_IMAGE}.unlocked" "${EXPECTED}/full" \ -i "${TO_IMAGE}" --wp=0 --debug # Test legacy update test_update "Legacy update" \ - "${FROM_IMAGE}" "${TMP}.expected.legacy" \ + "${FROM_IMAGE}" "${EXPECTED}/legacy" \ -i "${TO_IMAGE}" --mode=legacy # Test quirks @@ -428,16 +438,16 @@ test_update "Full update (wrong size)" \ --quirks unlock_csme_eve,eve_smm_store test_update "Full update (--quirks enlarge_image)" \ - "${FROM_IMAGE}.large" "${TMP}.expected.large" --quirks enlarge_image \ + "${FROM_IMAGE}.large" "${EXPECTED}/large" --quirks enlarge_image \ -i "${TO_IMAGE}" --wp=0 test_update "Full update (multi-line --quirks enlarge_image)" \ - "${FROM_IMAGE}.large" "${TMP}.expected.large" --quirks ' + "${FROM_IMAGE}.large" "${EXPECTED}/large" --quirks ' enlarge_image ' -i "${TO_IMAGE}" --wp=0 test_update "Full update (--quirks unlock_csme_eve)" \ - "${FROM_IMAGE}" "${TMP}.expected.me_unlocked_eve" \ + "${FROM_IMAGE}" "${EXPECTED}/me_unlocked_eve" \ --quirks unlock_csme_eve \ -i "${TO_IMAGE}" --wp=0 @@ -447,7 +457,7 @@ test_update "Full update (failure by --quirks min_platform_version)" \ -i "${TO_IMAGE}" --wp=0 --sys_props ,,2 test_update "Full update (--quirks min_platform_version)" \ - "${FROM_IMAGE}" "${TMP}.expected.full" \ + "${FROM_IMAGE}" "${EXPECTED}/full" \ --quirks min_platform_version=3 \ -i "${TO_IMAGE}" --wp=0 --sys_props ,,3 @@ -456,72 +466,74 @@ test_update "Full update (incompatible platform)" \ -i "${TO_IMAGE}" --wp=0 test_update "Full update (--quirks no_check_platform)" \ - "${FROM_IMAGE}".unpatched "${TMP}.expected.full" \ + "${FROM_IMAGE}".unpatched "${EXPECTED}/full" \ --quirks no_check_platform \ -i "${TO_IMAGE}" --wp=0 test_update "Full update (--quirks preserve_me with non-host programmer)" \ - "${FROM_IMAGE}" "${TMP}.expected.full" \ + "${FROM_IMAGE}" "${EXPECTED}/full" \ --quirks preserve_me \ -i "${TO_IMAGE}" --wp=0 \ -p raiden_debug_spi:target=AP test_update "Full update (--quirks preserve_me)" \ - "${FROM_IMAGE}" "${TMP}.expected.full" \ + "${FROM_IMAGE}" "${EXPECTED}/full" \ --quirks preserve_me \ -i "${TO_IMAGE}" --wp=0 test_update "Full update (--quirks preserve_me, autoupdate)" \ - "${FROM_IMAGE}" "${TMP}.expected.me_preserved" \ + "${FROM_IMAGE}" "${EXPECTED}/me_preserved" \ --quirks preserve_me -m autoupdate \ -i "${TO_IMAGE}" --wp=0 test_update "Full update (--quirks preserve_me, deferupdate_hold)" \ - "${FROM_IMAGE}" "${TMP}.expected.me_preserved" \ + "${FROM_IMAGE}" "${EXPECTED}/me_preserved" \ --quirks preserve_me -m deferupdate_hold \ -i "${TO_IMAGE}" --wp=0 test_update "Full update (--quirks preserve_me, factory)" \ - "${FROM_IMAGE}" "${TMP}.expected.full" \ + "${FROM_IMAGE}" "${EXPECTED}/full" \ --quirks preserve_me -m factory \ -i "${TO_IMAGE}" --wp=0 # Test manifest. -echo "TEST: Manifest (--manifest, -i, image.bin)" -cp -f "${GERALT_BIOS}" image.bin -"${FUTILITY}" update -i image.bin --manifest >"${TMP}.json.out" +TMP_JSON_OUT="${TMP}/json.out" +echo "TEST: Manifest (--manifest, --image)" +cp -f "${GERALT_BIOS}" "${TMP}/image.bin" +(cd "${TMP}" && + "${FUTILITY}" update -i image.bin --manifest) >"${TMP_JSON_OUT}" cmp \ - <(jq -S <"${TMP}.json.out") \ + <(jq -S <"${TMP_JSON_OUT}") \ <(jq -S <"${SCRIPT_DIR}/futility/bios_geralt_cbfs.manifest.json") # Test archive and manifest. CL_TAG is for custom_label_tag. -A="${TMP}.archive" +A="${TMP}/archive" mkdir -p "${A}/bin" -echo "echo \"\${CL_TAG}\"" >"${A}/bin/vpd" +echo 'echo "${CL_TAG}"' >"${A}/bin/vpd" chmod +x "${A}/bin/vpd" cp -f "${LINK_BIOS}" "${A}/bios.bin" echo "TEST: Manifest (--manifest, -a, bios.bin)" -"${FUTILITY}" update -a "${A}" --manifest >"${TMP}.json.out" +"${FUTILITY}" update -a "${A}" --manifest >"${TMP_JSON_OUT}" cmp \ - <(jq -S <"${TMP}.json.out") \ + <(jq -S <"${TMP_JSON_OUT}") \ <(jq -S <"${SCRIPT_DIR}/futility/link_bios.manifest.json") mv -f "${A}/bios.bin" "${A}/image.bin" echo "TEST: Manifest (--manifest, -a, image.bin)" -"${FUTILITY}" update -a "${A}" --manifest >"${TMP}.json.out" +"${FUTILITY}" update -a "${A}" --manifest >"${TMP_JSON_OUT}" cmp \ - <(jq -S <"${TMP}.json.out") \ + <(jq -S <"${TMP_JSON_OUT}") \ <(jq -S <"${SCRIPT_DIR}/futility/link_image.manifest.json") cp -f "${TO_IMAGE}" "${A}/image.bin" test_update "Full update (--archive, single package)" \ - "${FROM_IMAGE}" "${TMP}.expected.full" \ + "${FROM_IMAGE}" "${EXPECTED}/full" \ -a "${A}" --wp=0 --sys_props ,,3 echo "TEST: Output (--archive, --mode=output)" -TMP_OUTPUT="${TMP}.out_archive" && mkdir -p "${TMP_OUTPUT}" +TMP_OUTPUT="${TMP}/out_archive" && mkdir -p "${TMP_OUTPUT}" "${FUTILITY}" update -a "${A}" --mode=output \ --output_dir="${TMP_OUTPUT}" cmp "${TMP_OUTPUT}/image.bin" "${TO_IMAGE}" @@ -530,15 +542,15 @@ cmp "${TMP_OUTPUT}/image.bin" "${TO_IMAGE}" mkdir -p "${A}/keyset" "${A}/images" cp -f "${SIGNER_CONFIG}" "${A}/" cp -f "${LINK_BIOS}" "${A}/image.bin" -"${FUTILITY}" gbb -s --rootkey="${TMP}.from/rootkey" "${A}/image.bin" -"${FUTILITY}" load_fmap "${A}/image.bin" VBLOCK_A:"${TMP}.from/VBLOCK_A" -"${FUTILITY}" load_fmap "${A}/image.bin" VBLOCK_B:"${TMP}.from/VBLOCK_B" +"${FUTILITY}" gbb -s --rootkey="${TMP_FROM}/rootkey" "${A}/image.bin" +"${FUTILITY}" load_fmap "${A}/image.bin" VBLOCK_A:"${TMP_FROM}/VBLOCK_A" +"${FUTILITY}" load_fmap "${A}/image.bin" VBLOCK_B:"${TMP_FROM}/VBLOCK_B" mv -f "${A}/image.bin" "${A}/images/bios_coral.bin" cp -f "${PEPPY_BIOS}" "${A}/images/bios_peppy.bin" cp -f "${LINK_BIOS}" "${A}/images/bios_link.bin" -cp -f "${TMP}.to/rootkey" "${A}/keyset/rootkey.customtip-cl" -cp -f "${TMP}.to/VBLOCK_A" "${A}/keyset/vblock_A.customtip-cl" -cp -f "${TMP}.to/VBLOCK_B" "${A}/keyset/vblock_B.customtip-cl" +cp -f "${TMP_TO}/rootkey" "${A}/keyset/rootkey.customtip-cl" +cp -f "${TMP_TO}/VBLOCK_A" "${A}/keyset/vblock_A.customtip-cl" +cp -f "${TMP_TO}/VBLOCK_B" "${A}/keyset/vblock_B.customtip-cl" cp -f "${PEPPY_BIOS}" "${FROM_IMAGE}.ap" cp -f "${LINK_BIOS}" "${FROM_IMAGE}.al" cp -f "${VOXEL_BIOS}" "${FROM_IMAGE}.av" @@ -566,8 +578,8 @@ test_update "Full update (--archive, detect-model, unsupported FRID)" \ echo "*** Test Item: Detect model (--archive, --detect-model-only)" "${FUTILITY}" update -a "${A}" \ - --emulate "${FROM_IMAGE}.ap" --detect-model-only >"${TMP}.model.out" -cmp "${TMP}.model.out" <(echo peppy) + --emulate "${FROM_IMAGE}.ap" --detect-model-only >"${TMP}/model.out" +cmp "${TMP}/model.out" <(echo peppy) test_update "Full update (--archive, custom label with tag specified)" \ "${FROM_IMAGE}.al" "${LINK_BIOS}" \ @@ -584,76 +596,85 @@ CL_TAG="cl" PATH="${A}/bin:${PATH}" \ # The output mode (without specifying signature id) for custom label would still # need a source (emulate) image to decide the VPD, which is not a real use case. echo "TEST: Output (--archive, --mode=output, custom label with tag specified)" -TMP_OUTPUT="${TMP}.out_custom_label" && mkdir -p "${TMP_OUTPUT}" +TMP_OUTPUT="${TMP}/out_custom_label" && mkdir -p "${TMP_OUTPUT}" "${FUTILITY}" update -a "${A}" --mode=output \ --output_dir="${TMP_OUTPUT}" --model=customtip-cl cmp "${TMP_OUTPUT}/image.bin" "${LINK_BIOS}" # Custom label + Unibuild with default keys as model name -cp -f "${TMP}.to/rootkey" "${A}/keyset/rootkey.customtip" -cp -f "${TMP}.to/VBLOCK_A" "${A}/keyset/vblock_A.customtip" -cp -f "${TMP}.to/VBLOCK_B" "${A}/keyset/vblock_B.customtip" +cp -f "${TMP_TO}/rootkey" "${A}/keyset/rootkey.customtip" +cp -f "${TMP_TO}/VBLOCK_A" "${A}/keyset/vblock_A.customtip" +cp -f "${TMP_TO}/VBLOCK_B" "${A}/keyset/vblock_B.customtip" test_update "Full update (--archive, custom label, no VPD, default keys)" \ "${FROM_IMAGE}.al" "${LINK_BIOS}" \ -a "${A}" --wp=0 --sys_props 0,0x10001,3 --model=customtip # Test special programmer -if type flashrom >/dev/null 2>&1; then +test_flashrom() { echo "TEST: Full update (dummy programmer)" - cp -f "${FROM_IMAGE}" "${TMP}.emu" + local emu="${TMP}/emu" + cp -f "${FROM_IMAGE}" "${emu}" "${FUTILITY}" update --programmer \ - dummy:emulate=VARIABLE_SIZE,image="${TMP}".emu,size=8388608 \ + dummy:emulate=VARIABLE_SIZE,image="${emu}",size=8388608 \ -i "${TO_IMAGE}" --wp=0 --sys_props 0,0x10001,3 >&2 - cmp "${TMP}.emu" "${TMP}.expected.full" -fi - -if type cbfstool >/dev/null 2>&1; then - echo "SMM STORE" >"${TMP}.smm" - truncate -s 262144 "${TMP}.smm" - cp -f "${FROM_IMAGE}" "${TMP}.from.smm" - cp -f "${TMP}.expected.full" "${TMP}.expected.full_smm" - cbfstool "${TMP}.from.smm" add -r RW_LEGACY -n "smm_store" \ - -f "${TMP}.smm" -t raw - cbfstool "${TMP}.expected.full_smm" add -r RW_LEGACY -n "smm_store" \ - -f "${TMP}.smm" -t raw -b 0x1bf000 + cmp "${emu}" "${EXPECTED}/full" +} +type flashrom >/dev/null 2>&1 && test_flashrom + +test_cbfstool() { + echo "TEST: Update with cbsfstool" + local smm="${TMP}/smm" + local cbfs="${TMP}/cbfs" + local quirk="${TMP}/quirk" + + echo "SMM STORE" >"${smm}" + truncate -s 262144 "${smm}" + cp -f "${FROM_IMAGE}" "${TMP_FROM}.smm" + cp -f "${EXPECTED}/full" "${EXPECTED}/full_smm" + cbfstool "${TMP_FROM}.smm" add -r RW_LEGACY -n "smm_store" \ + -f "${smm}" -t raw + cbfstool "${EXPECTED}/full_smm" add -r RW_LEGACY -n "smm_store" \ + -f "${smm}" -t raw -b 0x1bf000 test_update "Legacy update (--quirks eve_smm_store)" \ - "${TMP}.from.smm" "${TMP}.expected.full_smm" \ + "${TMP_FROM}.smm" "${EXPECTED}/full_smm" \ -i "${TO_IMAGE}" --wp=0 \ --quirks eve_smm_store - echo "min_platform_version=3" >"${TMP}.quirk" + echo "min_platform_version=3" >"${quirk}" cp -f "${TO_IMAGE}" "${TO_IMAGE}.quirk" - "${FUTILITY}" dump_fmap -x "${TO_IMAGE}" "BOOT_STUB:${TMP}.cbfs" + "${FUTILITY}" dump_fmap -x "${TO_IMAGE}" "BOOT_STUB:${cbfs}" # Create a fake CBFS using FW_MAIN_A size. - truncate -s $((0x000dffc0)) "${TMP}.cbfs" - "${FUTILITY}" load_fmap "${TO_IMAGE}.quirk" "FW_MAIN_A:${TMP}.cbfs" + truncate -s $((0x000dffc0)) "${cbfs}" + "${FUTILITY}" load_fmap "${TO_IMAGE}.quirk" "FW_MAIN_A:${cbfs}" cbfstool "${TO_IMAGE}.quirk" add -r FW_MAIN_A -n updater_quirks \ - -f "${TMP}.quirk" -t raw + -f "${quirk}" -t raw test_update "Full update (failure by CBFS quirks)" \ "${FROM_IMAGE}" "!Need platform version >= 3 (current is 2)" \ -i "${TO_IMAGE}.quirk" --wp=0 --sys_props 0,0x10001,2 -fi +} +type cbfstool >/dev/null 2>&1 && test_cbfstool -if type ifdtool >/dev/null 2>&1; then +test_ifdtool() { test_update "Full update (--quirks unlock_csme, IFD chipset)" \ - "${FROM_IMAGE}" "${TMP}.expected.me_unlocked.ifd_chipset" \ + "${FROM_IMAGE}" "${EXPECTED}/me_unlocked.ifd_chipset" \ --quirks unlock_csme -i "${TO_IMAGE}.ifd_chipset" --wp=0 test_update "Full update (--quirks unlock_csme, IFD bin path)" \ - "${FROM_IMAGE}" "${TMP}.expected.me_unlocked.ifd_path" \ + "${FROM_IMAGE}" "${EXPECTED}/me_unlocked.ifd_path" \ --quirks unlock_csme -i "${TO_IMAGE}.ifd_path" --wp=0 test_update "Full update (--unlock_me)" \ - "${FROM_IMAGE}" "${TMP}.expected.me_unlocked.ifd_chipset" \ + "${FROM_IMAGE}" "${EXPECTED}/me_unlocked.ifd_chipset" \ --unlock_me -i "${TO_IMAGE}.ifd_chipset" --wp=0 echo "TEST: Output (--mode=output, --quirks unlock_csme)" - TMP_OUTPUT="${TMP}.out_csme" && mkdir -p "${TMP_OUTPUT}" + TMP_OUTPUT="${TMP}/out_csme" && mkdir -p "${TMP_OUTPUT}" mkdir -p "${TMP_OUTPUT}" - "${FUTILITY}" update -i "${TMP}.expected.ifd_chipset" --mode=output \ + "${FUTILITY}" update -i "${EXPECTED}/ifd_chipset" --mode=output \ --output_dir="${TMP_OUTPUT}" --quirks unlock_csme - cmp "${TMP_OUTPUT}/image.bin" "${TMP}.expected.me_unlocked.ifd_chipset" -fi + cmp "${TMP_OUTPUT}/image.bin" "${EXPECTED}/me_unlocked.ifd_chipset" +} +type ifdtool >/dev/null 2>&1 && test_ifdtool -rm -rf "${TMP}"* +rm -rf "${TMP}" exit 0 From 8b4c9e53a470e92badce514bc0b5bdccaf16105a Mon Sep 17 00:00:00 2001 From: Hsuan Ting Chen Date: Tue, 8 Oct 2024 05:07:58 +0000 Subject: [PATCH 064/102] Android Bringup: See http://go/android-fw-sync Revert "host/lib/flashrom: Use flashrom provided in PATH" This reverts commit 24fd715c90e89df1a90191c8ee1d3d78a29af758. Reason for revert: Potentially break b/370374826 Original change's description: > host/lib/flashrom: Use flashrom provided in PATH > > Remove `/usr/sbin` path prefix from FLASHROM_EXEC_NAME path. > The cbfstool is called this way, so there is no need to have differing > requirements for other utility which needs to be provided anyway. > > BUG=b:369294243, b:369290629 > BRANCH=None > TEST=m; adb shell crossystem dev_boot_altfw=1 > > Change-Id: Iff9fcfb8b40287d301bc552487c7fefa804d4a13 > Signed-off-by: Jakub Czapiga > Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5890746 > Commit-Queue: Julius Werner > Reviewed-by: Julius Werner BUG=b:369294243, b:369290629 (cherry picked from commit 38f9c255d31df24a4cc08334846ea2e6a1df4b36) Change-Id: I5414b8e323f1f9bfca222272618b2bd503a58074 Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5915173 Original-Commit-Queue: Jakub Czapiga Original-Bot-Commit: Rubber Stamper Original-Reviewed-by: Allen Webb Original-Reviewed-by: Jakub Czapiga GitOrigin-RevId: 38f9c255d31df24a4cc08334846ea2e6a1df4b36 Cr-Build-Id: 8734289971574337217 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8734289971574337217 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5918693 Reviewed-by: Jayvik Desai Reviewed-by: Jonathon Murphy Tested-by: ChromeOS Prod (Robot) --- host/lib/flashrom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/host/lib/flashrom.c b/host/lib/flashrom.c index 6a802011..8f0d4f91 100644 --- a/host/lib/flashrom.c +++ b/host/lib/flashrom.c @@ -23,7 +23,7 @@ #include "flashrom.h" #include "subprocess.h" -#define FLASHROM_EXEC_NAME "flashrom" +#define FLASHROM_EXEC_NAME "/usr/sbin/flashrom" /** * Helper to create a temporary file, and optionally write some data From 28ceea0ecbc8232b228e14345e95fc7c37bc7217 Mon Sep 17 00:00:00 2001 From: Grzegorz Bernacki Date: Tue, 27 Aug 2024 07:34:06 +0000 Subject: [PATCH 065/102] android: Remove incorrectly licensed header file That file was under Apache License which cannot be used here. BUG=None TEST=None BRANCH=firmware-android-15949.B Change-Id: I2c68696cea2b7433529ca2868cd8c10174635155 Signed-off-by: Grzegorz Bernacki Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5824439 Reviewed-by: Yu-Ping Wu --- firmware/avb/android_image_hdr.h | 190 ------------------------------- 1 file changed, 190 deletions(-) delete mode 100644 firmware/avb/android_image_hdr.h diff --git a/firmware/avb/android_image_hdr.h b/firmware/avb/android_image_hdr.h deleted file mode 100644 index 64e1cece..00000000 --- a/firmware/avb/android_image_hdr.h +++ /dev/null @@ -1,190 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -/* - * This is from the Android Project, - * Repository: https://android.googlesource.com/platform/system/tools/mkbootimg - * File: include/bootimg/bootimg.h - * Commit: 2fe7d1583e874b45eb678d10e1450a6e70ff4cb4 - * - * Copyright (C) 2007 The Android Open Source Project - */ - -#ifndef ANDROID_IMAGE_HDR -#define ANDROID_IMAGE_HDR - -#include - -#define BOOT_MAGIC "ANDROID!" -#define BOOT_MAGIC_SIZE 8 -#define BOOT_NAME_SIZE 16 -#define BOOT_ARGS_SIZE 512 -#define BOOT_EXTRA_ARGS_SIZE 1024 - -#define VENDOR_BOOT_MAGIC "VNDRBOOT" -#define VENDOR_BOOT_MAGIC_SIZE 8 -#define VENDOR_BOOT_ARGS_SIZE 2048 -#define VENDOR_BOOT_NAME_SIZE 16 - -#define VENDOR_RAMDISK_TYPE_NONE 0 -#define VENDOR_RAMDISK_TYPE_PLATFORM 1 -#define VENDOR_RAMDISK_TYPE_RECOVERY 2 -#define VENDOR_RAMDISK_TYPE_DLKM 3 -#define VENDOR_RAMDISK_NAME_SIZE 32 -#define VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE 16 - -/* When the boot image header has a version of 4, the structure of the boot - * image is as follows: - * - * +---------------------+ - * | boot header | 4096 bytes - * +---------------------+ - * | kernel | m pages - * +---------------------+ - * | ramdisk | n pages - * +---------------------+ - * | boot signature | g pages - * +---------------------+ - * - * m = (kernel_size + 4096 - 1) / 4096 - * n = (ramdisk_size + 4096 - 1) / 4096 - * g = (signature_size + 4096 - 1) / 4096 - * - * Note that in version 4 of the boot image header, page size is fixed at 4096 - * bytes. - * - * The structure of the vendor boot image version 4, which is required to be - * present when a version 4 boot image is used, is as follows: - * - * +------------------------+ - * | vendor boot header | o pages - * +------------------------+ - * | vendor ramdisk section | p pages - * +------------------------+ - * | dtb | q pages - * +------------------------+ - * | vendor ramdisk table | r pages - * +------------------------+ - * | bootconfig | s pages - * +------------------------+ - * - * o = (2128 + page_size - 1) / page_size - * p = (vendor_ramdisk_size + page_size - 1) / page_size - * q = (dtb_size + page_size - 1) / page_size - * r = (vendor_ramdisk_table_size + page_size - 1) / page_size - * s = (vendor_bootconfig_size + page_size - 1) / page_size - * - * Note that in version 4 of the vendor boot image, multiple vendor ramdisks can - * be included in the vendor boot image. The bootloader can select a subset of - * ramdisks to load at runtime. To help the bootloader select the ramdisks, each - * ramdisk is tagged with a type tag and a set of hardware identifiers - * describing the board, soc or platform that this ramdisk is intended for. - * - * The vendor ramdisk section is consist of multiple ramdisk images concatenated - * one after another, and vendor_ramdisk_size is the size of the section, which - * is the total size of all the ramdisks included in the vendor boot image. - * - * The vendor ramdisk table holds the size, offset, type, name and hardware - * identifiers of each ramdisk. The type field denotes the type of its content. - * The vendor ramdisk names are unique. The hardware identifiers are specified - * in the board_id field in each table entry. The board_id field is consist of a - * vector of unsigned integer words, and the encoding scheme is defined by the - * hardware vendor. - * - * For the different type of ramdisks, there are: - * - VENDOR_RAMDISK_TYPE_NONE indicates the value is unspecified. - * - VENDOR_RAMDISK_TYPE_PLATFORM ramdisks contain platform specific bits, so - * the bootloader should always load these into memory. - * - VENDOR_RAMDISK_TYPE_RECOVERY ramdisks contain recovery resources, so - * the bootloader should load these when booting into recovery. - * - VENDOR_RAMDISK_TYPE_DLKM ramdisks contain dynamic loadable kernel - * modules. - * - * Version 4 of the vendor boot image also adds a bootconfig section to the end - * of the image. This section contains Boot Configuration parameters known at - * build time. The bootloader is responsible for placing this section directly - * after the generic ramdisk, followed by the bootconfig trailer, before - * entering the kernel. - * - * 0. all entities in the boot image are 4096-byte aligned in flash, all - * entities in the vendor boot image are page_size (determined by the vendor - * and specified in the vendor boot image header) aligned in flash - * 1. kernel, ramdisk, and DTB are required (size != 0) - * 2. load the kernel and DTB at the specified physical address (kernel_addr, - * dtb_addr) - * 3. load the vendor ramdisks at ramdisk_addr - * 4. load the generic ramdisk immediately following the vendor ramdisk in - * memory - * 5. load the bootconfig immediately following the generic ramdisk. Add - * additional bootconfig parameters followed by the bootconfig trailer. - * 6. set up registers for kernel entry as required by your architecture - * 7. if the platform has a second stage bootloader jump to it (must be - * contained outside boot and vendor boot partitions), otherwise - * jump to kernel_addr - */ -struct boot_img_hdr_v4 { - // Must be BOOT_MAGIC. - uint8_t magic[BOOT_MAGIC_SIZE]; - - uint32_t kernel_size; /* size in bytes */ - uint32_t ramdisk_size; /* size in bytes */ - - // Operating system version and security patch level. - // For version "A.B.C" and patch level "Y-M-D": - // (7 bits for each of A, B, C; 7 bits for (Y-2000), 4 bits for M) - // os_version = A[31:25] B[24:18] C[17:11] (Y-2000)[10:4] M[3:0] - uint32_t os_version; - - uint32_t header_size; - - uint32_t reserved[4]; - - // Version of the boot image header. - uint32_t header_version; - - // Asciiz kernel commandline. - uint8_t cmdline[BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE]; - uint32_t signature_size; /* size in bytes */ -} __attribute__((packed)); - -struct vendor_boot_img_hdr_v4 { - // Must be VENDOR_BOOT_MAGIC. - uint8_t magic[VENDOR_BOOT_MAGIC_SIZE]; - - // Version of the vendor boot image header. - uint32_t header_version; - - uint32_t page_size; /* flash page size we assume */ - - uint32_t kernel_addr; /* physical load addr */ - uint32_t ramdisk_addr; /* physical load addr */ - - uint32_t vendor_ramdisk_size; /* size in bytes */ - - uint8_t cmdline[VENDOR_BOOT_ARGS_SIZE]; /* asciiz kernel commandline */ - - uint32_t tags_addr; /* physical addr for kernel tags (if required) */ - uint8_t name[VENDOR_BOOT_NAME_SIZE]; /* asciiz product name */ - - uint32_t header_size; - - uint32_t dtb_size; /* size in bytes for DTB image */ - uint64_t dtb_addr; /* physical load address for DTB image */ - - uint32_t vendor_ramdisk_table_size; /* size in bytes for the vendor ramdisk table */ - uint32_t vendor_ramdisk_table_entry_num; /* number of entries in the vendor ramdisk table */ - uint32_t vendor_ramdisk_table_entry_size; /* size in bytes for a vendor ramdisk table entry */ - uint32_t bootconfig_size; /* size in bytes for the bootconfig section */ -} __attribute__((packed)); - -struct vendor_ramdisk_table_entry_v4 { - uint32_t ramdisk_size; /* size in bytes for the ramdisk image */ - uint32_t ramdisk_offset; /* offset to the ramdisk image in vendor ramdisk section */ - uint32_t ramdisk_type; /* type of the ramdisk */ - uint8_t ramdisk_name[VENDOR_RAMDISK_NAME_SIZE]; /* asciiz ramdisk name */ - - // Hardware identifiers describing the board, soc or platform which this - // ramdisk is intended to be loaded on. - uint32_t board_id[VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE]; -} __attribute__((packed)); - -#endif /* ANDROID_IMAGE_HDR */ From 31b67eb5d79dbdad0c04dbfb34bfc463e8dc6aff Mon Sep 17 00:00:00 2001 From: Grzegorz Bernacki Date: Tue, 27 Aug 2024 07:35:55 +0000 Subject: [PATCH 066/102] android: Port image headers definition This file was ported from repo: https://android.googlesource.com/platform/system/tools/mkbootimg Path: include/bootimg/bootimg.h Commit: a306f82e5a60 Changes: - removed C++ code - expand struct inheritance - remove structures with version < 4 - use vboot coding style BUG=None TEST=Build and run firmware on redrix BRANCH=firmware-android-15949.B Change-Id: I48a922bbd7be9ff3df35aa901cc85a88e18c0239 Signed-off-by: Grzegorz Bernacki Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5824440 Reviewed-by: Yu-Ping Wu Reviewed-by: Julius Werner --- firmware/avb/android_image_hdr.h | 190 +++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 firmware/avb/android_image_hdr.h diff --git a/firmware/avb/android_image_hdr.h b/firmware/avb/android_image_hdr.h new file mode 100644 index 00000000..3f6a02f0 --- /dev/null +++ b/firmware/avb/android_image_hdr.h @@ -0,0 +1,190 @@ +/* Copyright 2007 The Android Open Source Project + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * This file was ported from repo: + * https://android.googlesource.com/platform/system/tools/mkbootimg + * Path: include/bootimg/bootimg.h + * Commit: a306f82e5a60ca1fc0be77ca2afa31a01d797295 + */ + +#ifndef ANDROID_IMAGE_HDR_H_ +#define ANDROID_IMAGE_HDR_H_ + +#include + +#define BOOT_MAGIC "ANDROID!" +#define BOOT_MAGIC_SIZE 8 +#define BOOT_NAME_SIZE 16 +#define BOOT_ARGS_SIZE 512 +#define BOOT_EXTRA_ARGS_SIZE 1024 + +#define VENDOR_BOOT_MAGIC "VNDRBOOT" +#define VENDOR_BOOT_MAGIC_SIZE 8 +#define VENDOR_BOOT_ARGS_SIZE 2048 +#define VENDOR_BOOT_NAME_SIZE 16 + +#define VENDOR_RAMDISK_TYPE_NONE 0 +#define VENDOR_RAMDISK_TYPE_PLATFORM 1 +#define VENDOR_RAMDISK_TYPE_RECOVERY 2 +#define VENDOR_RAMDISK_TYPE_DLKM 3 +#define VENDOR_RAMDISK_NAME_SIZE 32 +#define VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE 16 + +/* When the boot image header has a version of 4, the structure of the boot + * image is as follows: + * + * +---------------------+ + * | boot header | 4096 bytes + * +---------------------+ + * | kernel | m pages + * +---------------------+ + * | ramdisk | n pages + * +---------------------+ + * | boot signature | g pages + * +---------------------+ + * + * m = (kernel_size + 4096 - 1) / 4096 + * n = (ramdisk_size + 4096 - 1) / 4096 + * g = (signature_size + 4096 - 1) / 4096 + * + * Note that in version 4 of the boot image header, page size is fixed at 4096 + * bytes. + * + * The structure of the vendor boot image version 4, which is required to be + * present when a version 4 boot image is used, is as follows: + * + * +------------------------+ + * | vendor boot header | o pages + * +------------------------+ + * | vendor ramdisk section | p pages + * +------------------------+ + * | dtb | q pages + * +------------------------+ + * | vendor ramdisk table | r pages + * +------------------------+ + * | bootconfig | s pages + * +------------------------+ + * + * o = (2128 + page_size - 1) / page_size + * p = (vendor_ramdisk_size + page_size - 1) / page_size + * q = (dtb_size + page_size - 1) / page_size + * r = (vendor_ramdisk_table_size + page_size - 1) / page_size + * s = (vendor_bootconfig_size + page_size - 1) / page_size + * + * Note that in version 4 of the vendor boot image, multiple vendor ramdisks can + * be included in the vendor boot image. The bootloader can select a subset of + * ramdisks to load at runtime. To help the bootloader select the ramdisks, each + * ramdisk is tagged with a type tag and a set of hardware identifiers + * describing the board, soc or platform that this ramdisk is intended for. + * + * The vendor ramdisk section is consist of multiple ramdisk images concatenated + * one after another, and vendor_ramdisk_size is the size of the section, which + * is the total size of all the ramdisks included in the vendor boot image. + * + * The vendor ramdisk table holds the size, offset, type, name and hardware + * identifiers of each ramdisk. The type field denotes the type of its content. + * The vendor ramdisk names are unique. The hardware identifiers are specified + * in the board_id field in each table entry. The board_id field is consist of a + * vector of unsigned integer words, and the encoding scheme is defined by the + * hardware vendor. + * + * For the different type of ramdisks, there are: + * - VENDOR_RAMDISK_TYPE_NONE indicates the value is unspecified. + * - VENDOR_RAMDISK_TYPE_PLATFORM ramdisks contain platform specific bits, so + * the bootloader should always load these into memory. + * - VENDOR_RAMDISK_TYPE_RECOVERY ramdisks contain recovery resources, so + * the bootloader should load these when booting into recovery. + * - VENDOR_RAMDISK_TYPE_DLKM ramdisks contain dynamic loadable kernel + * modules. + * + * Version 4 of the vendor boot image also adds a bootconfig section to the end + * of the image. This section contains Boot Configuration parameters known at + * build time. The bootloader is responsible for placing this section directly + * after the generic ramdisk, followed by the bootconfig trailer, before + * entering the kernel. + * + * 0. all entities in the boot image are 4096-byte aligned in flash, all + * entities in the vendor boot image are page_size (determined by the vendor + * and specified in the vendor boot image header) aligned in flash + * 1. kernel, ramdisk, and DTB are required (size != 0) + * 2. load the kernel and DTB at the specified physical address (kernel_addr, + * dtb_addr) + * 3. load the vendor ramdisks at ramdisk_addr + * 4. load the generic ramdisk immediately following the vendor ramdisk in + * memory + * 5. load the bootconfig immediately following the generic ramdisk. Add + * additional bootconfig parameters followed by the bootconfig trailer. + * 6. set up registers for kernel entry as required by your architecture + * 7. if the platform has a second stage bootloader jump to it (must be + * contained outside boot and vendor boot partitions), otherwise + * jump to kernel_addr + */ +struct boot_img_hdr_v4 { + // Must be BOOT_MAGIC. + uint8_t magic[BOOT_MAGIC_SIZE]; + + uint32_t kernel_size; /* size in bytes */ + uint32_t ramdisk_size; /* size in bytes */ + + // Operating system version and security patch level. + // For version "A.B.C" and patch level "Y-M-D": + // (7 bits for each of A, B, C; 7 bits for (Y-2000), 4 bits for M) + // os_version = A[31:25] B[24:18] C[17:11] (Y-2000)[10:4] M[3:0] + uint32_t os_version; + + uint32_t header_size; + + uint32_t reserved[4]; + + // Version of the boot image header. + uint32_t header_version; + + // Asciiz kernel commandline. + uint8_t cmdline[BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE]; + uint32_t signature_size; /* size in bytes */ +} __attribute__((packed)); + +struct vendor_boot_img_hdr_v4 { + // Must be VENDOR_BOOT_MAGIC. + uint8_t magic[VENDOR_BOOT_MAGIC_SIZE]; + + // Version of the vendor boot image header. + uint32_t header_version; + + uint32_t page_size; /* flash page size we assume */ + + uint32_t kernel_addr; /* physical load addr */ + uint32_t ramdisk_addr; /* physical load addr */ + + uint32_t vendor_ramdisk_size; /* size in bytes */ + + uint8_t cmdline[VENDOR_BOOT_ARGS_SIZE]; /* asciiz kernel commandline */ + + uint32_t tags_addr; /* physical addr for kernel tags (if required) */ + uint8_t name[VENDOR_BOOT_NAME_SIZE]; /* asciiz product name */ + + uint32_t header_size; + + uint32_t dtb_size; /* size in bytes for DTB image */ + uint64_t dtb_addr; /* physical load address for DTB image */ + uint32_t vendor_ramdisk_table_size; /* size in bytes for the vendor ramdisk table */ + /* number of entries in the vendor ramdisk table */ + uint32_t vendor_ramdisk_table_entry_num; + /* size in bytes for a vendor ramdisk table entry */ + uint32_t vendor_ramdisk_table_entry_size; + uint32_t bootconfig_size; /* size in bytes for the bootconfig section */ +} __attribute__((packed)); + +struct vendor_ramdisk_table_entry_v4 { + uint32_t ramdisk_size; /* size in bytes for the ramdisk image */ + uint32_t ramdisk_offset; /* offset to the ramdisk image in vendor ramdisk section */ + uint32_t ramdisk_type; /* type of the ramdisk */ + uint8_t ramdisk_name[VENDOR_RAMDISK_NAME_SIZE]; /* asciiz ramdisk name */ + + // Hardware identifiers describing the board, soc or platform which this + // ramdisk is intended to be loaded on. + uint32_t board_id[VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE]; +} __attribute__((packed)); + +#endif /* ANDROID_IMAGE_HDR_H_ */ From 9107c6ab150b8e0119a096b093d55953eca8b672 Mon Sep 17 00:00:00 2001 From: Grzegorz Bernacki Date: Wed, 9 Oct 2024 13:51:25 +0000 Subject: [PATCH 067/102] android: Move android header file into generic include directory This allows to easily include the file by other projects. BUG=None TEST=Build FW and run on Redrix BRANCH=firmware-android-15949.B Change-Id: I78be8bc746503c9fea0d2a897531b0a532dc218e Signed-off-by: Grzegorz Bernacki Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5922818 Reviewed-by: Julius Werner Reviewed-by: Yu-Ping Wu --- firmware/avb/vboot_avb_ops.c | 2 +- .../android_image_hdr.h => include/vb2_android_bootimg.h} | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) rename firmware/{avb/android_image_hdr.h => include/vb2_android_bootimg.h} (98%) diff --git a/firmware/avb/vboot_avb_ops.c b/firmware/avb/vboot_avb_ops.c index 4ab8f878..416304ad 100644 --- a/firmware/avb/vboot_avb_ops.c +++ b/firmware/avb/vboot_avb_ops.c @@ -13,7 +13,7 @@ #include "vboot_avb_ops.h" #include "cgptlib.h" #include "cgptlib_internal.h" -#include "android_image_hdr.h" +#include "vb2_android_bootimg.h" struct vboot_avb_data { struct vb2_kernel_params *params; diff --git a/firmware/avb/android_image_hdr.h b/firmware/include/vb2_android_bootimg.h similarity index 98% rename from firmware/avb/android_image_hdr.h rename to firmware/include/vb2_android_bootimg.h index 3f6a02f0..e0ca02cd 100644 --- a/firmware/avb/android_image_hdr.h +++ b/firmware/include/vb2_android_bootimg.h @@ -8,8 +8,8 @@ * Commit: a306f82e5a60ca1fc0be77ca2afa31a01d797295 */ -#ifndef ANDROID_IMAGE_HDR_H_ -#define ANDROID_IMAGE_HDR_H_ +#ifndef VB2_ANDROID_BOOTIMG_H_ +#define VB2_ANDROID_BOOTIMG_H_ #include @@ -187,4 +187,4 @@ struct vendor_ramdisk_table_entry_v4 { uint32_t board_id[VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE]; } __attribute__((packed)); -#endif /* ANDROID_IMAGE_HDR_H_ */ +#endif /* VB2_ANDROID_BOOTIMG_H_ */ From 7d8f0b207a4e59a06566648f85fb5ee61348323a Mon Sep 17 00:00:00 2001 From: Ross Zwisler Date: Tue, 15 Oct 2024 09:44:33 -0600 Subject: [PATCH 068/102] Android Bringup: See http://go/android-fw-sync make_dev_ssd.sh: avoid page cache aliasing Per http://b/307454713 we noticed that sometimes an `fflash` operation would leave a device in a bad state where it would no longer boot. It turns out that this was due to a page cache aliasing issue that caused the kernel partition to become corrupt. That issue worked like this on my asurada system: 1. fflash writes a new kernel image to slot A using /dev/mmcblk0p2 2. Without rebooting, fflash then executes make_dev_ssd.sh to remove rootfs verification on slot A. 3. make_dev_ssd.sh reads the kernel image from slot A, with the intent of modifying it and writing it back. However, instead of reading the image from /dev/mmcblk0p2, it reads the kernel image from /dev/mmcblk0 using offset and length arguments, i.e.: dd if=/dev/mmcblk0 of=data bs=512 skip=69 count=65536 You can see that offset & length via `fdisk`: # fdisk -l /dev/mmcblk0 Device Start End Sectors Size Type /dev/mmcblk0p2 69 65604 65536 32M ChromeOS kernel 4. The page cache for /dev/mmcblk0p2 was still in the process of writing back its dirty data, so the data that make_dev_ssd.sh gets from its `dd` operation on /dev/mmcblk0 is a mix of old stale data and new data. It reads that data to a file, updates it to remove rootfs verification, and then writes it back again using the parent block device, offset and length. 5. We now have a corrupt kernel image in slot A, and will fail to boot when `fflash` tries to reboot the system. The root of this issue is that the partition /dev/mmcblk0p2 and the parent device /dev/mmcblk0 can have separate page cache entries for the same disk blocks. We can work around this issue by making sure that the writeback from the update operation is complete and that we've cleared any stale, clean cache blocks before and after we do the make_dev_ssd.sh update to remove rootfs verification. We could also potentially fix this by updating make_dev_ssd.sh use the /dev/mmcblk0p2 partition, but this seems more brittle because it requires us to keep all update utilities (fflash, `cros flash`) in sync with how they access block devices. The current solution tries to make make_dev_ssd.sh updates atomic so they can work no matter how other tools use the disk. BUG=b:307454713 BRANCH=none TEST=running these two operations in a loop: cros flash --no-stateful-update --no-reboot $DUT $DISK_IMAGE ssh $DUT "/usr/share/vboot/bin/make_dev_ssd.sh -d \ --remove_rootfs_verification --partitions $PARTITION" I was able to consistently recreate the cache aliasing issue on my asurada devices in about 5 minutes. With this fix I was able to run that same test on 2 devices overnight without any issues. (cherry picked from commit c5af1fd8490d07d28ab178364e6452da748cc320) Change-Id: I41c96534ec8f69e5968af27bd24fa2d470422d7d Original-Signed-off-by: Ross Zwisler Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5934991 Original-Reviewed-by: Allen Webb Original-Reviewed-by: Benjamin Gordon Original-Reviewed-by: Raul Rangel GitOrigin-RevId: c5af1fd8490d07d28ab178364e6452da748cc320 Cr-Build-Id: 8733927582971921713 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8733927582971921713 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5937608 Tested-by: ChromeOS Prod (Robot) Reviewed-by: Grzegorz Bernacki Commit-Queue: Grzegorz Bernacki --- scripts/image_signing/make_dev_ssd.sh | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/scripts/image_signing/make_dev_ssd.sh b/scripts/image_signing/make_dev_ssd.sh index 49d4215b..c7e1e33d 100755 --- a/scripts/image_signing/make_dev_ssd.sh +++ b/scripts/image_signing/make_dev_ssd.sh @@ -203,6 +203,14 @@ resign_ssd_kernel() { local ssd_device="$1" local bs="$(blocksize "${ssd_device}")" + # `fflash` and `cros flash` write their updates to block device partitions, + # while this script uses the parent block device plus a block offset. + # Sync and flush the page cache to avoid cache aliasing issues. + sync; sync; sync + if [ -w /proc/sys/vm/drop_caches ]; then + echo 1 > /proc/sys/vm/drop_caches + fi + # reasonable size for current kernel partition local min_kernel_size=$((8000 * 1024 / bs)) local resigned_kernels=0 @@ -385,10 +393,13 @@ resign_ssd_kernel() { fi fi - # Sometimes doing "dump_kernel_config" or other I/O now (or after return to - # shell) will get the data before modification. Not a problem now, but for - # safety, let's try to sync more. + # `fflash` and `cros flash` write their updates to block device partitions, + # while this script uses the parent block device plus a block offset. + # Sync and flush the page cache to avoid cache aliasing issues. sync; sync; sync + if [ -w /proc/sys/vm/drop_caches ]; then + echo 1 > /proc/sys/vm/drop_caches + fi info "${name}: Re-signed with developer keys successfully." done From e8fcff01491452b82fc025bed56d7d68eceb88bb Mon Sep 17 00:00:00 2001 From: Grzegorz Bernacki Date: Thu, 10 Oct 2024 11:23:23 +0000 Subject: [PATCH 069/102] cgptlib: Add function to find uuid for given partition name BUG=b:324233168 TEST=make runtests BRANCH=firmware-android-15949.B Change-Id: Ie5575bf026d63e0d8240e726f27d8de58a6351f4 Signed-off-by: Grzegorz Bernacki Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5920847 Commit-Queue: Yu-Ping Wu Reviewed-by: Yu-Ping Wu --- firmware/include/gpt_misc.h | 9 ------ firmware/lib/cgptlib/cgptlib.c | 38 +++++++++++++++++++----- firmware/lib/cgptlib/include/cgptlib.h | 18 ++++++++++++ tests/cgptlib_test.c | 40 ++++++++++++++++++++++++++ 4 files changed, 89 insertions(+), 16 deletions(-) diff --git a/firmware/include/gpt_misc.h b/firmware/include/gpt_misc.h index 5787f870..535fb04a 100644 --- a/firmware/include/gpt_misc.h +++ b/firmware/include/gpt_misc.h @@ -207,15 +207,6 @@ int GptUpdateKernelEntry(GptData *gpt, uint32_t update_type); */ int GptGetActiveKernelPartitionSuffix(GptData *gpt, char **suffix); -/** - * Provides start_sector and size for given partition by its UTF16LE name. - * - * Returns GPT_SUCCESS if successful, else - * GPT_ERROR_NO_SUCH_ENTRY. - */ -int GptFindOffsetByName(GptData *gpt, const char *name, - uint64_t *start_sector, uint64_t *size); - /* Getters and setters for partition attribute fields. */ int GetEntryRequired(const GptEntry *e); diff --git a/firmware/lib/cgptlib/cgptlib.c b/firmware/lib/cgptlib/cgptlib.c index 73fe80ef..c4bd6ec8 100644 --- a/firmware/lib/cgptlib/cgptlib.c +++ b/firmware/lib/cgptlib/cgptlib.c @@ -268,16 +268,14 @@ GptEntry *GptFindNthEntry(GptData *gpt, const Guid *guid, unsigned int n) return NULL; } -int GptFindOffsetByName(GptData *gpt, const char *name, - uint64_t *start_sector, uint64_t *size) +static GptEntry *GptFindEntryByName(GptData *gpt, const char *name) { GptHeader *header = (GptHeader *)gpt->primary_header; GptEntry *entries = (GptEntry *)gpt->primary_entries; - GptEntry *e; + GptEntry *ret = NULL, *e; int i; uint16_t *name_ucs2; int size_ucs2; - int ret = GPT_ERROR_NO_SUCH_ENTRY; name_ucs2 = calloc(NAME_SIZE, sizeof(*name_ucs2)); if (name_ucs2 == NULL) @@ -289,9 +287,7 @@ int GptFindOffsetByName(GptData *gpt, const char *name, for (i = 0, e = entries; i < header->number_of_entries; i++, e++) { if (!memcmp(&e->name, name_ucs2, size_ucs2 * sizeof(*name_ucs2))) { - *start_sector = e->starting_lba; - *size = e->ending_lba - e->starting_lba + 1; - ret = GPT_SUCCESS; + ret = e; break; } } @@ -301,6 +297,34 @@ int GptFindOffsetByName(GptData *gpt, const char *name, return ret; } +int GptFindUniqueByName(GptData *gpt, const char *name, Guid *guid) +{ + GptEntry *e; + + e = GptFindEntryByName(gpt, name); + if (e == NULL) + return GPT_ERROR_NO_SUCH_ENTRY; + + memcpy(guid, &e->unique, GUID_SIZE); + + return GPT_SUCCESS; +} + +int GptFindOffsetByName(GptData *gpt, const char *name, + uint64_t *start_sector, uint64_t *size) +{ + GptEntry *e; + + e = GptFindEntryByName(gpt, name); + if (e == NULL) + return GPT_ERROR_NO_SUCH_ENTRY; + + *start_sector = e->starting_lba; + *size = e->ending_lba - e->starting_lba + 1; + + return GPT_SUCCESS; +} + int GptFindInitBoot(GptData *gpt, uint64_t *start_sector, uint64_t *size) { int ret; diff --git a/firmware/lib/cgptlib/include/cgptlib.h b/firmware/lib/cgptlib/include/cgptlib.h index f5f2e1f1..1e3bc37c 100644 --- a/firmware/lib/cgptlib/include/cgptlib.h +++ b/firmware/lib/cgptlib/include/cgptlib.h @@ -55,4 +55,22 @@ int GptFindVendorBoot(GptData *gpt, uint64_t *start_sector, uint64_t *size); */ int GptFindPvmfw(GptData *gpt, uint64_t *start_sector, uint64_t *size); +/** + * Provides start_sector and size for given partition by its UTF16LE name. + * + * Returns GPT_SUCCESS if successful, else + * GPT_ERROR_NO_SUCH_ENTRY. + */ +int GptFindOffsetByName(GptData *gpt, const char *name, + uint64_t *start_sector, uint64_t *size); + +/** + * Find unique GUID for given partition name. + * + * On successful return the guid contains the unique GUID of partition. + * Returns GPT_SUCCESS if successful, else + * GPT_ERROR_NO_SUCH_ENTRY. + */ +int GptFindUniqueByName(GptData *gpt, const char *name, Guid *guid); + #endif /* VBOOT_REFERENCE_CGPTLIB_H_ */ diff --git a/tests/cgptlib_test.c b/tests/cgptlib_test.c index 91fe320f..80003496 100644 --- a/tests/cgptlib_test.c +++ b/tests/cgptlib_test.c @@ -51,6 +51,14 @@ static const Guid guid_rootfs = GPT_ENT_TYPE_CHROMEOS_ROOTFS; const char *progname = "CGPT-TEST"; const char *command = "TEST"; +static const uint16_t kern_a_name[] = {0x004b, 0x0045, 0x0052, 0x004e, + 0x002d, 0x0041, 0x0000}; +static const uint16_t root_a_name[] = {0x0052, 0x004f, 0x004f, 0x0054, + 0x002d, 0x0041, 0x0000}; +static const uint16_t kern_b_name[] = {0x004b, 0x0045, 0x0052, 0x004e, + 0x002d, 0x0042, 0x0000}; +static const uint16_t root_b_name[] = {0x0052, 0x004f, 0x004f, 0x0054, + 0x002d, 0x0042, 0x0000}; /* * Copy a random-for-this-program-only Guid into the dest. The num parameter * completely determines the Guid. @@ -171,18 +179,22 @@ static void BuildTestGptData(GptData *gpt) /* 512B / 128B * 32sectors = 128 entries */ header->number_of_entries = 128; header->size_of_entry = 128; /* bytes */ + memcpy(&entries[0].name, &kern_a_name, sizeof(kern_a_name)); memcpy(&entries[0].type, &chromeos_kernel, sizeof(chromeos_kernel)); SetGuid(&entries[0].unique, 0); entries[0].starting_lba = 34; entries[0].ending_lba = 133; + memcpy(&entries[1].name, &root_a_name, sizeof(root_a_name)); memcpy(&entries[1].type, &chromeos_rootfs, sizeof(chromeos_rootfs)); SetGuid(&entries[1].unique, 1); entries[1].starting_lba = 134; entries[1].ending_lba = 232; + memcpy(&entries[2].name, &root_b_name, sizeof(root_b_name)); memcpy(&entries[2].type, &chromeos_rootfs, sizeof(chromeos_rootfs)); SetGuid(&entries[2].unique, 2); entries[2].starting_lba = 234; entries[2].ending_lba = 331; + memcpy(&entries[3].name, &kern_b_name, sizeof(kern_a_name)); memcpy(&entries[3].type, &chromeos_kernel, sizeof(chromeos_kernel)); SetGuid(&entries[3].unique, 3); entries[3].starting_lba = 334; @@ -1605,6 +1617,33 @@ static int CheckHeaderOffDevice(void) return TEST_OK; } +static int FindUniqueByNameTest(void) +{ + GptData *gpt = GetEmptyGptData(); + Guid guid1, guid2; + + BuildTestGptData(gpt); + + SetGuid(&guid2, 0); + EXPECT(GptFindUniqueByName(gpt, "KERN-A", &guid1) == GPT_SUCCESS); + EXPECT(!memcmp(&guid1, &guid2, sizeof(Guid))); + + SetGuid(&guid2, 1); + EXPECT(GptFindUniqueByName(gpt, "ROOT-A", &guid1) == GPT_SUCCESS); + EXPECT(!memcmp(&guid1, &guid2, sizeof(Guid))); + + SetGuid(&guid2, 2); + EXPECT(GptFindUniqueByName(gpt, "ROOT-B", &guid1) == GPT_SUCCESS); + EXPECT(!memcmp(&guid1, &guid2, sizeof(Guid))); + + SetGuid(&guid2, 3); + EXPECT(GptFindUniqueByName(gpt, "KERN-B", &guid1) == GPT_SUCCESS); + EXPECT(!memcmp(&guid1, &guid2, sizeof(Guid))); + + EXPECT(GptFindUniqueByName(gpt, "NON-EXISTENT", &guid1) == GPT_ERROR_NO_SUCH_ENTRY); + return TEST_OK; +} + int main(int argc, char *argv[]) { int i; @@ -1645,6 +1684,7 @@ int main(int argc, char *argv[]) { TEST_CASE(GetKernelGuidTest), }, { TEST_CASE(ErrorTextTest), }, { TEST_CASE(CheckHeaderOffDevice), }, + { TEST_CASE(FindUniqueByNameTest), }, }; for (i = 0; i < sizeof(test_cases)/sizeof(test_cases[0]); ++i) { From 27d4e515486b57040e71b6914c6b38279d628afd Mon Sep 17 00:00:00 2001 From: Grzegorz Bernacki Date: Mon, 2 Sep 2024 13:16:49 +0000 Subject: [PATCH 070/102] avb: Implement get_unique_guid_for_partition() BUG=b:324233168 TEST=Build and run on Redrix, verify partition guid BRANCH=firmware-android-15949.B Change-Id: Idfc1fe327c23ba9dc6532919c0610e35afb46c87 Signed-off-by: Grzegorz Bernacki Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5844849 Commit-Queue: Yu-Ping Wu Reviewed-by: Yu-Ping Wu --- firmware/2lib/include/2sysincludes.h | 1 + firmware/avb/vboot_avb_ops.c | 39 +++++++++++++++++++++------- firmware/include/gpt.h | 1 + host/include/vboot_host.h | 1 - 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/firmware/2lib/include/2sysincludes.h b/firmware/2lib/include/2sysincludes.h index cbf39f90..550399f2 100644 --- a/firmware/2lib/include/2sysincludes.h +++ b/firmware/2lib/include/2sysincludes.h @@ -14,6 +14,7 @@ #define VBOOT_REFERENCE_2SYSINCLUDES_H_ #include +#include #include /* For PRIu64 */ #include #include diff --git a/firmware/avb/vboot_avb_ops.c b/firmware/avb/vboot_avb_ops.c index 416304ad..276bf230 100644 --- a/firmware/avb/vboot_avb_ops.c +++ b/firmware/avb/vboot_avb_ops.c @@ -175,15 +175,36 @@ static AvbIOResult get_unique_guid_for_partition(AvbOps *ops, char *guid_buf, size_t guid_buf_size) { - /* TODO(b/324233168): Implement getter for vbmeta partition GUID */ - /* - * Use test UUID from android codebase as a placeholder for now. As it - * is informational only, there is no harm. Leaving it empty may cause - * issues with cmdline properties formatting. - */ - char tmp[] = "aa08f1a4-c7c9-402e-9a66-9707cafa9ceb"; - memcpy(guid_buf, &tmp, sizeof(tmp)); - avb_debug("TODO: function not implemented yet\n"); + struct vboot_avb_data *data; + GptData *gpt; + Guid guid; + int ret; + + if (guid_buf_size < GUID_STRLEN || !ops || !ops->user_data) + return AVB_IO_RESULT_ERROR_NO_SUCH_VALUE; + + data = (struct vboot_avb_data *)ops->user_data; + gpt = data->gpt; + if (!gpt) + return AVB_IO_RESULT_ERROR_NO_SUCH_VALUE; + + if (GptFindUniqueByName(gpt, partition, &guid) != GPT_SUCCESS) + return AVB_IO_RESULT_ERROR_IO; + + ret = snprintf(guid_buf, guid_buf_size, + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + le32toh(guid.u.Uuid.time_low), + le16toh(guid.u.Uuid.time_mid), + le16toh(guid.u.Uuid.time_high_and_version), + guid.u.Uuid.clock_seq_high_and_reserved, + guid.u.Uuid.clock_seq_low, + guid.u.Uuid.node[0], guid.u.Uuid.node[1], + guid.u.Uuid.node[2], guid.u.Uuid.node[3], + guid.u.Uuid.node[4], guid.u.Uuid.node[5]); + + if (ret != (GUID_STRLEN - 1)) + return AVB_IO_RESULT_ERROR_IO; + return AVB_IO_RESULT_OK; } diff --git a/firmware/include/gpt.h b/firmware/include/gpt.h index b4ca5c9d..da76d259 100644 --- a/firmware/include/gpt.h +++ b/firmware/include/gpt.h @@ -60,6 +60,7 @@ extern "C" { #define UUID_NODE_LEN 6 #define GUID_SIZE 16 +#define GUID_STRLEN 37 #define NAME_SIZE 36 /* diff --git a/host/include/vboot_host.h b/host/include/vboot_host.h index 90d5c563..dfedd8e3 100644 --- a/host/include/vboot_host.h +++ b/host/include/vboot_host.h @@ -45,7 +45,6 @@ int CgptLegacy(CgptLegacyParams *params); * At least GUID_STRLEN bytes should be reserved in 'str' (included the tailing * '\0'). */ -#define GUID_STRLEN 37 int StrToGuid(const char *str, Guid *guid); void GuidToStr(const Guid *guid, char *str, unsigned int buflen); int GuidEqual(const Guid *guid1, const Guid *guid2); From f61887cccd62037cb7a42e5c3bdaf4535268b8d1 Mon Sep 17 00:00:00 2001 From: Grzegorz Bernacki Date: Fri, 18 Oct 2024 08:02:59 +0000 Subject: [PATCH 071/102] cgptlib: use correct variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes bug with using incorrect variable name in sizeof() operator. BUG=b:324233168 TEST=make runtests BRANCH=firmware-android-15949.B Change-Id: I42aa4062c687d2a5affefc6253ca12443cbb09a7 Signed-off-by: Grzegorz Bernacki Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5938368 Reviewed-by: Jan Dąbroś --- tests/cgptlib_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cgptlib_test.c b/tests/cgptlib_test.c index 80003496..4c5a5cde 100644 --- a/tests/cgptlib_test.c +++ b/tests/cgptlib_test.c @@ -194,7 +194,7 @@ static void BuildTestGptData(GptData *gpt) SetGuid(&entries[2].unique, 2); entries[2].starting_lba = 234; entries[2].ending_lba = 331; - memcpy(&entries[3].name, &kern_b_name, sizeof(kern_a_name)); + memcpy(&entries[3].name, &kern_b_name, sizeof(kern_b_name)); memcpy(&entries[3].type, &chromeos_kernel, sizeof(chromeos_kernel)); SetGuid(&entries[3].unique, 3); entries[3].starting_lba = 334; From 417f1cbfccc871a3e9d1d1072576d006b7a78ba5 Mon Sep 17 00:00:00 2001 From: Allen Webb Date: Fri, 18 Oct 2024 19:50:57 +0000 Subject: [PATCH 072/102] Update Rust OWNERS file to include libchromeos-rs/OWNERS BUG=None TEST=None (cherry picked from commit 3c2ef9400c0565144dc560150d2bca92a330ce6b) Change-Id: I207b4ed7ceb222a950d5acd697949d43494856c4 Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5943542 Original-Tested-by: Allen Webb Original-Reviewed-by: George Burgess Original-Auto-Submit: Allen Webb Original-Commit-Queue: George Burgess GitOrigin-RevId: 3c2ef9400c0565144dc560150d2bca92a330ce6b Cr-Build-Id: 8733021614843538449 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8733021614843538449 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5953584 Reviewed-by: Allen Webb Commit-Queue: Jonathon Murphy Tested-by: ChromeOS Prod (Robot) Reviewed-by: Yu-Ping Wu Reviewed-by: Jonathon Murphy --- rust/OWNERS | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rust/OWNERS b/rust/OWNERS index fe3921f7..268d92ef 100644 --- a/rust/OWNERS +++ b/rust/OWNERS @@ -1 +1,3 @@ -allenwebb@chromium.org +allenwebb@google.com + +include chromiumos/platform2:/libchromeos-rs/OWNERS From 6906455d47d6cb2ae7ac1713d2903e9cbe8276f8 Mon Sep 17 00:00:00 2001 From: Arnaud Ferraris Date: Mon, 21 Oct 2024 14:56:09 +0200 Subject: [PATCH 073/102] make_dev_ssd: add upstream cmdline flag for ptracers The downstream patch adding the flags allowing ptracers to write to proc/mem has been partly merged upstream. During the process, the `foll_force` cmdline option was renamed to `proc_mem.force_override`, with the `ptracer` option being now simply `ptrace`. As the upstreamed patch has been backported to all stable kernel branches, which are currently being imported into ChromeOS kernels, we need to add this option to ensure debugging can still work on dev/test images. The previous version of this option will be removed at a later point, once all ChromeOS kernels are up-to-date with the corresponding stable branches. BUG=b:325891891 TEST=Built prod/dev/test images and verify /proc/cmdline BRANCH=main (cherry picked from commit 2ab8888bddac82f94611b01f3133524f98e367ff) Change-Id: Id4e340746b2c0938c889170cd7b1cfbfde8eceb0 Original-Signed-off-by: Arnaud Ferraris Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5947523 Original-Reviewed-by: Raul Rangel GitOrigin-RevId: 2ab8888bddac82f94611b01f3133524f98e367ff Cr-Build-Id: 8733021614843538449 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8733021614843538449 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5953585 Reviewed-by: Jonathon Murphy Reviewed-by: Yu-Ping Wu Commit-Queue: Jonathon Murphy Tested-by: ChromeOS Prod (Robot) --- scripts/image_signing/make_dev_ssd.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/image_signing/make_dev_ssd.sh b/scripts/image_signing/make_dev_ssd.sh index c7e1e33d..5c453d03 100755 --- a/scripts/image_signing/make_dev_ssd.sh +++ b/scripts/image_signing/make_dev_ssd.sh @@ -99,7 +99,10 @@ remove_rootfs_verification() { rw_root_opt="s| rw | ro |" fi - local ptracer_opt="proc_mem.restrict_write=ptracer proc_mem.restrict_foll_force=ptracer" + local ptracer_opt="proc_mem.restrict_write=ptracer proc_mem.force_override=ptrace" + # This is kept for compatibility with ChromeOS kernels until all of them + # are up-to-date with the corresponding stable branch. + ptracer_opt="${ptracer_opt} proc_mem.restrict_foll_force=ptracer" if [ "${FLAGS_enable_proc_mem_ptrace}" = "${FLAGS_FALSE}" ]; then # we could set proc_mem.restrict_write=all, however that's already default # via Kconfig and we don't want to clutter the cmdline with redundant params From 04852de2085ee80871188a4a2cb6dfd19aed567d Mon Sep 17 00:00:00 2001 From: Yu-Ping Wu Date: Mon, 28 Oct 2024 17:49:24 +0800 Subject: [PATCH 074/102] futility: updater: Increase try count from 11 to 13 Android Bringup: See http://go/android-fw-sync Theoretically 11 reboots are enough for firmware update in any situation. However, a user may power off the device within 1 miniute after bootup, causing chromeos-setgoodfirmware to not run. The result is that, fw_result won't be set to "success" in that boot, so fw_try_count will be further decreased by 1 in the next boot. Given that the firmware cannot tell if the poweroff is intentional by the user or unexpected by the system, the best we can do is to take this edge case into account in the initial fw_try_count value. Increase it from 11 to 13, so that users will be less unlikely to hit this edge case. More precisely, they will need to power off the device within 1 minute for 3 consecutive boots after firmware update, in order to hit this issue. BUG=b:374893421 TEST=cq BRANCH=none (cherry picked from commit 3246e484ca08f2ab29935cb964fa52fc6d24f97b) Change-Id: Iec21a26b62bdcf6aa6ad44402cd39cebd70c24b8 Original-Signed-off-by: Yu-Ping Wu Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5970064 Original-Reviewed-by: Julius Werner Original-Reviewed-by: Hung-Te Lin GitOrigin-RevId: 3246e484ca08f2ab29935cb964fa52fc6d24f97b Cr-Build-Id: 8732659219451911521 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8732659219451911521 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5978403 Reviewed-by: Jonathon Murphy Commit-Queue: Jonathon Murphy Tested-by: ChromeOS Prod (Robot) --- futility/updater.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/futility/updater.c b/futility/updater.c index d21b8ae1..b958f435 100644 --- a/futility/updater.c +++ b/futility/updater.c @@ -266,7 +266,7 @@ static const char *decide_rw_target(struct updater_config *cfg, static int set_try_cookies(struct updater_config *cfg, const char *target, int has_update) { - int tries = 11; + int tries = 13; const char *slot; if (!has_update) From 4713a842dbd097c967ec84231094845ecbbb6be3 Mon Sep 17 00:00:00 2001 From: Rob Barnes Date: Wed, 30 Oct 2024 08:10:00 -0600 Subject: [PATCH 075/102] crossystem: Make crossystem vendor_available Android Bringup: See http://go/android-fw-sync Making crossystem `vendor_available` instead of `vendor` means it can be installed in /system/bin/ or /vendor/bin/ depending on which target is used, `crossystem` or `crossystem.vendor` respectively. BUG=b:374130759 TEST=Build BRANCH=None (cherry picked from commit 862e250e672c0ed3a801dfa274198ec88d4a186d) Change-Id: I9a27f92c975b23d95f9e8dbb9d2189a1cd7518d2 Original-Signed-off-by: Rob Barnes Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5979089 Original-Tested-by: Jakub Czapiga Original-Reviewed-by: Jakub Czapiga Original-Commit-Queue: Jakub Czapiga GitOrigin-RevId: 862e250e672c0ed3a801dfa274198ec88d4a186d Cr-Build-Id: 8732568628864283889 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8732568628864283889 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5981018 Reviewed-by: Jonathon Murphy Commit-Queue: Jonathon Murphy Tested-by: ChromeOS Prod (Robot) --- Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Android.bp b/Android.bp index eae97950..7f393ee1 100644 --- a/Android.bp +++ b/Android.bp @@ -405,7 +405,7 @@ cc_binary { name: "crossystem", defaults: ["vboot_defaults"], host_supported: true, - vendor: true, + vendor_available: true, srcs: ["utility/crossystem.c"], static_libs: ["libvboot_util"], From df8c24aa41b249489eb6bfa4055006c948426c3c Mon Sep 17 00:00:00 2001 From: Jakub Czapiga Date: Wed, 30 Oct 2024 12:08:48 +0000 Subject: [PATCH 076/102] futility: Drop futility execution logging to /tmp/futility.log Android Bringup: See http://go/android-fw-sync This functionality is not used anymore and is also a potential security vulnerability. BUG=None BRANCH=None TEST=sudo FEATURES=test emerge vboot_reference (cherry picked from commit a0f83f9f3a0cd103d0bdcf16e8868e3eb87e7b49) Change-Id: Ie1bd38a26faa240f8cd00ab7717ed58489223e31 Original-Signed-off-by: Jakub Czapiga Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5972390 Original-Reviewed-by: Julius Werner GitOrigin-RevId: a0f83f9f3a0cd103d0bdcf16e8868e3eb87e7b49 Cr-Build-Id: 8732478031531179473 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8732478031531179473 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5983892 Tested-by: ChromeOS Prod (Robot) Reviewed-by: Jonathon Murphy Commit-Queue: Jonathon Murphy --- Makefile | 4 - futility/futility.c | 157 ------------------------------------ tests/futility/test_main.sh | 9 --- 3 files changed, 170 deletions(-) diff --git a/Makefile b/Makefile index abb54b60..1740839b 100644 --- a/Makefile +++ b/Makefile @@ -184,10 +184,6 @@ ifneq ($(filter-out 0,${NDEBUG}),) CFLAGS += -DNDEBUG endif -ifneq ($(filter-out 0,${FORCE_LOGGING_ON}),) -CFLAGS += -DFORCE_LOGGING_ON=${FORCE_LOGGING_ON} -endif - ifneq ($(filter-out 0,${TPM2_MODE}),) CFLAGS += -DTPM2_MODE endif diff --git a/futility/futility.c b/futility/futility.c index 1dbded06..8bc1820c 100644 --- a/futility/futility.c +++ b/futility/futility.c @@ -16,164 +16,9 @@ #include "futility.h" -/******************************************************************************/ -/* Logging stuff */ - -/* File to use for logging, if present */ -#define LOGFILE "/tmp/futility.log" - -/* Normally logging will only happen if the logfile already exists. Uncomment - * this to force log file creation (and thus logging) always. */ - -/* #define FORCE_LOGGING_ON */ - -static int log_fd = -1; const char *ft_print_header = NULL; const char *ft_print_header2 = NULL; -/* Write the string and a newline. Silently give up on errors */ -static void log_str(const char *prefix, const char *str) -{ - int len, done, n; - - if (log_fd < 0) - return; - - if (!str) - str = "(NULL)"; - - if (prefix && *prefix) { - len = strlen(prefix); - for (done = 0; done < len; done += n) { - n = write(log_fd, prefix + done, len - done); - if (n < 0) - return; - } - } - - len = strlen(str); - if (len == 0) { - str = "(EMPTY)"; - len = strlen(str); - } - - for (done = 0; done < len; done += n) { - n = write(log_fd, str + done, len - done); - if (n < 0) - return; - } - - if (write(log_fd, "\n", 1) < 0) - return; -} - -static void log_close(void) -{ - struct flock lock; - - if (log_fd >= 0) { - memset(&lock, 0, sizeof(lock)); - lock.l_type = F_UNLCK; - lock.l_whence = SEEK_SET; - if (fcntl(log_fd, F_SETLKW, &lock)) - perror("Unable to unlock log file"); - - close(log_fd); - log_fd = -1; - } -} - -static void log_open(void) -{ - struct flock lock; - int ret; - -#ifdef FORCE_LOGGING_ON - log_fd = open(LOGFILE, O_WRONLY | O_APPEND | O_CREAT, 0666); -#else - log_fd = open(LOGFILE, O_WRONLY | O_APPEND); -#endif - if (log_fd < 0) { - - if (errno != EACCES) - return; - - /* Permission problems should improve shortly ... */ - sleep(1); - log_fd = open(LOGFILE, O_WRONLY | O_APPEND | O_CREAT, 0666); - if (log_fd < 0) /* Nope, they didn't */ - return; - } - - /* Let anyone have a turn */ - fchmod(log_fd, 0666); - - /* But only one at a time */ - memset(&lock, 0, sizeof(lock)); - lock.l_type = F_WRLCK; - lock.l_whence = SEEK_END; - - ret = fcntl(log_fd, F_SETLKW, &lock); /* this blocks */ - if (ret < 0) - log_close(); -} - -static void log_args(int argc, char *argv[]) -{ - int i; - ssize_t r; - pid_t parent; - char buf[80]; - FILE *fp; - char caller_buf[PATH_MAX]; - - log_open(); - - /* delimiter */ - log_str(NULL, "##### LOG #####"); - - /* Can we tell who called us? */ - parent = getppid(); - snprintf(buf, sizeof(buf), "/proc/%d/exe", parent); - r = readlink(buf, caller_buf, sizeof(caller_buf) - 1); - if (r >= 0) { - caller_buf[r] = '\0'; - log_str("CALLER:", caller_buf); - } - - /* From where? */ - snprintf(buf, sizeof(buf), "/proc/%d/cwd", parent); - r = readlink(buf, caller_buf, sizeof(caller_buf) - 1); - if (r >= 0) { - caller_buf[r] = '\0'; - log_str("DIR:", caller_buf); - } - - /* And maybe the args? */ - snprintf(buf, sizeof(buf), "/proc/%d/cmdline", parent); - fp = fopen(buf, "r"); - if (fp) { - memset(caller_buf, 0, sizeof(caller_buf)); - r = fread(caller_buf, 1, sizeof(caller_buf) - 1, fp); - if (r > 0) { - char *s = caller_buf; - for (i = 0; i < r && *s; ) { - log_str("CMDLINE:", s); - while (i < r && *s) - i++, s++; - i++, s++; - } - } - fclose(fp); - } - - /* Now log the stuff about ourselves */ - for (i = 0; i < argc; i++) - log_str(NULL, argv[i]); - - log_close(); -} - /******************************************************************************/ static const char *const usage = "\n" @@ -308,8 +153,6 @@ int main(int argc, char *argv[], char *envp[]) { 0, 0, 0, 0}, }; - log_args(argc, argv); - /* How were we invoked? */ progname = simple_basename(argv[0]); diff --git a/tests/futility/test_main.sh b/tests/futility/test_main.sh index 3cfee6d6..df2a8aba 100755 --- a/tests/futility/test_main.sh +++ b/tests/futility/test_main.sh @@ -16,15 +16,6 @@ cd "$OUTDIR" "${FUTILITY}" /fake/path/to/help > "$TMP" grep Usage "$TMP" -# Make sure logging does something. -LOG="/tmp/futility.log" -[ -f "${LOG}" ] && mv "${LOG}" "${LOG}.backup" -touch "${LOG}" -"${FUTILITY}" help -grep "${FUTILITY}" "${LOG}" -rm -f "${LOG}" -[ -f "${LOG}.backup" ] && mv "${LOG}.backup" "${LOG}" - # Use some known digests to verify that things work... DEVKEYS="${SRCDIR}/tests/devkeys" SHA=e78ce746a037837155388a1096212ded04fb86eb From 32d9a0666d6d1c01adfe9e006733e25521c6a302 Mon Sep 17 00:00:00 2001 From: Jakub Czapiga Date: Mon, 14 Oct 2024 07:25:22 +0000 Subject: [PATCH 077/102] Add configurable temporary directory path Android Bringup: See http://go/android-fw-sync This patch introduces common way to control the host temporary directory path via VBOOT_TMP_DIR variable. It also updates Android.bp to use correct paths on the target platforms as well as adds init script creating all needed directories. BUG=b:376284266 BRANCH=None TEST=Build and run futility on Android (cherry picked from commit 26e8011fd51765457a628c3f5317c99e8b485973) Change-Id: Idd125a4380142f87cac695ffa7d76ceec1880bce Original-Signed-off-by: Jakub Czapiga Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5976624 Original-Reviewed-by: Julius Werner Original-Reviewed-by: Yu-Ping Wu GitOrigin-RevId: 26e8011fd51765457a628c3f5317c99e8b485973 Cr-Build-Id: 8732478031531179473 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8732478031531179473 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5983893 Commit-Queue: Jonathon Murphy Tested-by: ChromeOS Prod (Robot) Reviewed-by: Jonathon Murphy --- Android.bp | 17 ++++++++++++++--- Makefile | 4 ++++ cgpt/cgpt_find.c | 2 +- cgpt/cgpt_wrapper.c | 2 +- futility/updater_utils.c | 3 ++- host/lib/flashrom.c | 7 ++----- vboot.rc | 6 ++++++ 7 files changed, 30 insertions(+), 11 deletions(-) create mode 100644 vboot.rc diff --git a/Android.bp b/Android.bp index 7f393ee1..61c63ebb 100644 --- a/Android.bp +++ b/Android.bp @@ -5,6 +5,7 @@ cc_defaults { name: "vboot_defaults", visibility: ["//visibility:public"], + init_rc: ["vboot.rc"], cflags: [ "-Wall", @@ -64,19 +65,29 @@ cc_defaults { target: { android: { - cflags: ["-DCROSSYSTEM_LOCK_DIR=\"/data/local/tmp\""], + cflags: [ + "-DCROSSYSTEM_LOCK_DIR=\"/data/vendor/vboot/tmp\"", + "-DVBOOT_TMP_DIR=\"/data/vendor/vboot/tmp\"", + ], }, darwin: { cflags: [ "-DHAVE_MACOS", "-DCROSSYSTEM_LOCK_DIR=\"/tmp\"", + "-DVBOOT_TMP_DIR=\"/tmp\"", ], }, linux: { - cflags: ["-DCROSSYSTEM_LOCK_DIR=\"/run/lock\""], + cflags: [ + "-DCROSSYSTEM_LOCK_DIR=\"/run/lock\"", + "-DVBOOT_TMP_DIR=\"/tmp\"", + ], }, windows: { - cflags: ["-DCROSSYSTEM_LOCK_DIR=\"c:\\windows\\temp\""], + cflags: [ + "-DCROSSYSTEM_LOCK_DIR=\"c:\\windows\\temp\"", + "-DVBOOT_TMP_DIR=\"c:\\windows\\temp\"", + ], }, }, } diff --git a/Makefile b/Makefile index 1740839b..bfb1e65b 100644 --- a/Makefile +++ b/Makefile @@ -214,6 +214,10 @@ else CFLAGS += -DEXTERNAL_TPM_CLEAR_REQUEST=0 endif +# Configurable temporary directory for host tools +VBOOT_TMP_DIR := /tmp +CFLAGS += -DVBOOT_TMP_DIR=\"${VBOOT_TMP_DIR}\" + # Directory used by crossystem to create a lock file CROSSYSTEM_LOCK_DIR := /run/lock CFLAGS += -DCROSSYSTEM_LOCK_DIR=\"${CROSSYSTEM_LOCK_DIR}\" diff --git a/cgpt/cgpt_find.c b/cgpt/cgpt_find.c index d807215e..258afc57 100644 --- a/cgpt/cgpt_find.c +++ b/cgpt/cgpt_find.c @@ -236,7 +236,7 @@ static int scan_spi_gpt(CgptFindParams *params) { partname, &sz, &erasesz, name) != 4) continue; if (strcmp(partname, "mtd0") == 0) { - char temp_dir[] = "/tmp/cgpt_find.XXXXXX"; + char temp_dir[] = VBOOT_TMP_DIR "/cgpt_find.XXXXXX"; if (params->drive_size == 0) { if (GetMtdSize("/dev/mtd0", ¶ms->drive_size) != 0) { perror("GetMtdSize"); diff --git a/cgpt/cgpt_wrapper.c b/cgpt/cgpt_wrapper.c index afa4940e..0fe76dd3 100644 --- a/cgpt/cgpt_wrapper.c +++ b/cgpt/cgpt_wrapper.c @@ -81,7 +81,7 @@ static int wrap_cgpt(int argc, // Create a temp dir to work in. ret++; - char temp_dir[] = "/tmp/cgpt_wrapper.XXXXXX"; + char temp_dir[] = VBOOT_TMP_DIR "/cgpt_wrapper.XXXXXX"; if (mkdtemp(temp_dir_template) == NULL) { Error("Cannot create a temporary directory.\n"); return ret; diff --git a/futility/updater_utils.c b/futility/updater_utils.c index 545970eb..493d195e 100644 --- a/futility/updater_utils.c +++ b/futility/updater_utils.c @@ -615,7 +615,8 @@ int write_system_firmware(struct updater_config *cfg, const char *create_temp_file(struct tempfile *head) { struct tempfile *new_temp; - char new_path[] = P_tmpdir "/fwupdater.XXXXXX"; + char new_path[] = VBOOT_TMP_DIR "/fwupdater.XXXXXX"; + int fd; mode_t umask_save; diff --git a/host/lib/flashrom.c b/host/lib/flashrom.c index 8f0d4f91..11121ec1 100644 --- a/host/lib/flashrom.c +++ b/host/lib/flashrom.c @@ -47,12 +47,9 @@ static vb2_error_t write_temp_file(const uint8_t *data, uint32_t data_size, char *path; mode_t umask_save; -#if defined(__FreeBSD__) -#define P_tmpdir "/tmp" -#endif - *path_out = NULL; - path = strdup(P_tmpdir "/vb2_flashrom.XXXXXX"); + + path = strdup(VBOOT_TMP_DIR "/vb2_flashrom.XXXXXX"); /* Set the umask before mkstemp for security considerations. */ umask_save = umask(077); diff --git a/vboot.rc b/vboot.rc new file mode 100644 index 00000000..959ac808 --- /dev/null +++ b/vboot.rc @@ -0,0 +1,6 @@ +# Create and mount working paths for vboot tools. +on post-fs-data-checkpointed + mkdir /data/vendor/vboot + mkdir /data/vendor/vboot/tmp + mount tmpfs tmpfs /data/vendor/vboot/tmp nosuid nodev noexec rw + restorecon /data/vendor/vboot From b335db17740c7192a5217029a067962cef4c76ca Mon Sep 17 00:00:00 2001 From: Jakub Czapiga Date: Thu, 31 Oct 2024 12:57:49 +0000 Subject: [PATCH 078/102] Reland "host/lib/flashrom: Use flashrom provided in PATH" Android Bringup: See http://go/android-fw-sync This reverts commit 38f9c255d31df24a4cc08334846ea2e6a1df4b36. Reason for revert: Fixed by crrev/c/5915176 Original change's description: > Revert "host/lib/flashrom: Use flashrom provided in PATH" > > This reverts commit 24fd715c90e89df1a90191c8ee1d3d78a29af758. > > Reason for revert: Potentially break b/370374826 > > Original change's description: > > host/lib/flashrom: Use flashrom provided in PATH > > > > Remove `/usr/sbin` path prefix from FLASHROM_EXEC_NAME path. > > The cbfstool is called this way, so there is no need to have differing > > requirements for other utility which needs to be provided anyway. > > > > BUG=b:369294243, b:369290629 > > BRANCH=None > > TEST=m; adb shell crossystem dev_boot_altfw=1 > > > > Change-Id: Iff9fcfb8b40287d301bc552487c7fefa804d4a13 > > Signed-off-by: Jakub Czapiga > > Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5890746 > > Commit-Queue: Julius Werner > > Reviewed-by: Julius Werner > > BUG=b:369294243, b:369290629 > > Change-Id: I5414b8e323f1f9bfca222272618b2bd503a58074 > Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5915173 > Commit-Queue: Jakub Czapiga > Bot-Commit: Rubber Stamper > Reviewed-by: Allen Webb > Reviewed-by: Jakub Czapiga BUG=b:369294243, b:369290629 (cherry picked from commit 3662103165a35b422552e24aeb5af0b8ec051cb6) Change-Id: I68bf753e17ecdc096768a88711920e3c955f71ab Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5982923 Original-Commit-Queue: Allen Webb Original-Auto-Submit: Jakub Czapiga Original-Commit-Queue: Jakub Czapiga Original-Tested-by: Jakub Czapiga Original-Reviewed-by: Allen Webb GitOrigin-RevId: 3662103165a35b422552e24aeb5af0b8ec051cb6 Cr-Build-Id: 8732478031531179473 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8732478031531179473 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5983894 Reviewed-by: Jonathon Murphy Tested-by: ChromeOS Prod (Robot) Commit-Queue: Jonathon Murphy --- host/lib/flashrom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/host/lib/flashrom.c b/host/lib/flashrom.c index 11121ec1..d3b44f46 100644 --- a/host/lib/flashrom.c +++ b/host/lib/flashrom.c @@ -23,7 +23,7 @@ #include "flashrom.h" #include "subprocess.h" -#define FLASHROM_EXEC_NAME "/usr/sbin/flashrom" +#define FLASHROM_EXEC_NAME "flashrom" /** * Helper to create a temporary file, and optionally write some data From f4c5a402d9f08123be84856d7c8e5df625683871 Mon Sep 17 00:00:00 2001 From: Grzegorz Bernacki Date: Tue, 29 Oct 2024 15:11:04 +0000 Subject: [PATCH 079/102] 2lib: Use cmdline address instead of offset Use the memory space allocated by depthcharge for the storage of the command line. Employing the direct address, as opposed to an offset, will both simplify the code and obviate the need for superfluous arithmetic operations. BUG=none BRANCH=firmware-android-15949.B TEST=build and boot AluminiumOS Change-Id: I3c3e40f5f91d9292145fe4cea6e9fd7f71a72e4d Signed-off-by: Grzegorz Bernacki Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5973826 Reviewed-by: Yu-Ping Wu --- firmware/2lib/2load_android_kernel.c | 25 ++++--------------------- firmware/2lib/include/2api.h | 6 ++++-- 2 files changed, 8 insertions(+), 23 deletions(-) diff --git a/firmware/2lib/2load_android_kernel.c b/firmware/2lib/2load_android_kernel.c index ea97f5f1..2f364566 100644 --- a/firmware/2lib/2load_android_kernel.c +++ b/firmware/2lib/2load_android_kernel.c @@ -14,9 +14,6 @@ #include "vboot_api.h" #include "vboot_avb_ops.h" -/* Size of the buffer to convey cmdline properties to bootloader */ -#define AVB_CMDLINE_BUF_SIZE 1024 - /* Bytes to read at start of the boot/init_boot/vendor_boot partitions */ #define BOOT_HDR_GKI_SIZE 4096 @@ -180,29 +177,15 @@ vb2_error_t vb2_load_android_kernel( sprintf(verified_str, "%s%s", VERIFIED_BOOT_PROPERTY_NAME, (ctx->flags & VB2_CONTEXT_DEVELOPER_MODE) ? "orange" : "green"); - /* - * Use a buffer before the GKI header for copying avb cmdline string for - * bootloader. - */ - params->vboot_cmdline_offset = params->kernel_buffer_size - - BOOT_HDR_GKI_SIZE - AVB_CMDLINE_BUF_SIZE; - - if ((params->init_boot_offset + params->init_boot_size) > - params->vboot_cmdline_offset) - return VB2_ERROR_LOAD_PARTITION_WORKBUF; - if ((strlen(verify_data->cmdline) + strlen(verified_str) + 1) >= - AVB_CMDLINE_BUF_SIZE) + params->kernel_cmdline_size) return VB2_ERROR_LOAD_PARTITION_WORKBUF; - strcpy((char *)(params->kernel_buffer + params->vboot_cmdline_offset), - verify_data->cmdline); + strcpy(params->kernel_cmdline_buffer, verify_data->cmdline); /* Append verifiedbootstate property to cmdline */ - strcat((char *)(params->kernel_buffer + params->vboot_cmdline_offset), - " "); - strcat((char *)(params->kernel_buffer + params->vboot_cmdline_offset), - verified_str); + strcat(params->kernel_cmdline_buffer, " "); + strcat(params->kernel_cmdline_buffer, verified_str); free(verified_str); diff --git a/firmware/2lib/include/2api.h b/firmware/2lib/include/2api.h index f2a5f710..db0c0ade 100644 --- a/firmware/2lib/include/2api.h +++ b/firmware/2lib/include/2api.h @@ -644,8 +644,10 @@ struct vb2_kernel_params { uint32_t init_boot_offset; /* Size of init boot partition in bytes. */ uint32_t init_boot_size; - /* Offset (in bytes) to the region with vboot cmdline parameters. */ - uint32_t vboot_cmdline_offset; + /* Address of the region with kernel cmdline parameters. */ + char *kernel_cmdline_buffer; + /* Size of the region with kernel cmdline parameters. */ + uint32_t kernel_cmdline_size; /* Boot command from Android BCB on misc partition. */ enum vb2_boot_command boot_command; From 1d8fbec3b8b48b1e5a54181c8128a3cb467a6ea7 Mon Sep 17 00:00:00 2001 From: Tomasz Michalec Date: Thu, 10 Oct 2024 11:56:45 +0200 Subject: [PATCH 080/102] gpt_misc: Return uint64_t from GptGetEntrySize functions Android Bringup: See http://go/android-fw-sync Change GptGetEntrySizeBytes and GptGetEntrySizeLba return type to uint64_t to prevent overflows for partitions with large size. BUG=None TEST=Print partition size using fastboot getvar all BRANCH=main (cherry picked from commit 1f7ca823da09f6c8cc451091a532b0cd60d90c34) Change-Id: I9bb5adcd727a350839638312dc97db3751d30342 Original-Signed-off-by: Tomasz Michalec Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5922816 Original-Reviewed-by: Julius Werner GitOrigin-RevId: 1f7ca823da09f6c8cc451091a532b0cd60d90c34 Cr-Build-Id: 8731843853558386257 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8731843853558386257 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6003746 Tested-by: ChromeOS Prod (Robot) Commit-Queue: Jonathon Murphy Reviewed-by: Jonathon Murphy --- firmware/include/gpt_misc.h | 4 ++-- firmware/lib/gpt_misc.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/firmware/include/gpt_misc.h b/firmware/include/gpt_misc.h index 535fb04a..b0baa2e4 100644 --- a/firmware/include/gpt_misc.h +++ b/firmware/include/gpt_misc.h @@ -171,12 +171,12 @@ int IsUnusedEntry(const GptEntry *e); /** * Return size(in lba) of a partition represented by given GPT entry. */ -size_t GptGetEntrySizeLba(const GptEntry *e); +uint64_t GptGetEntrySizeLba(const GptEntry *e); /** * Return size(in bytes) of a partition represented by given GPT entry. */ -size_t GptGetEntrySizeBytes(const GptData *gpt, const GptEntry *e); +uint64_t GptGetEntrySizeBytes(const GptData *gpt, const GptEntry *e); /** * Updates the kernel entry with the specified index, using the specified type diff --git a/firmware/lib/gpt_misc.c b/firmware/lib/gpt_misc.c index e11dd2da..79ff6cde 100644 --- a/firmware/lib/gpt_misc.c +++ b/firmware/lib/gpt_misc.c @@ -233,7 +233,7 @@ int IsUnusedEntry(const GptEntry *e) * Desc: This function returns size(in lba) of a partition represented by * given GPT entry. */ -size_t GptGetEntrySizeLba(const GptEntry *e) +uint64_t GptGetEntrySizeLba(const GptEntry *e) { return (e->ending_lba - e->starting_lba + 1); } @@ -243,7 +243,7 @@ size_t GptGetEntrySizeLba(const GptEntry *e) * Desc: This function returns size(in bytes) of a partition represented by * given GPT entry. */ -size_t GptGetEntrySizeBytes(const GptData *gpt, const GptEntry *e) +uint64_t GptGetEntrySizeBytes(const GptData *gpt, const GptEntry *e) { return GptGetEntrySizeLba(e) * gpt->sector_bytes; } From 688066ef22a229718a25bd43fa0b848a0358b0f3 Mon Sep 17 00:00:00 2001 From: Benjamin Shai Date: Tue, 5 Nov 2024 23:32:37 +0000 Subject: [PATCH 081/102] recovery_kernel: add signing type recovery_kernel Android Bringup: See http://go/android-fw-sync Taking as an input a recovery kernel, sign it with the recovery key (and make sure to handle the old recovery keys tagged v1 too). BUG=b:371248380 TEST=manual BRANCH=None (cherry picked from commit 0d49b8fdf002fa9cfa573ca1509ed8a1a0cf26d5) Change-Id: I0631f9060bc5943c384f6b128a4d2389ba29dee0 Original-Signed-off-by: Benjamin Shai Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5996750 Original-Reviewed-by: Julius Werner Original-Commit-Queue: ChromeOS Auto Runner GitOrigin-RevId: 0d49b8fdf002fa9cfa573ca1509ed8a1a0cf26d5 Cr-Build-Id: 8731843853558386257 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8731843853558386257 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6003747 Reviewed-by: Jonathon Murphy Tested-by: ChromeOS Prod (Robot) Commit-Queue: Jonathon Murphy --- scripts/image_signing/sign_official_build.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/scripts/image_signing/sign_official_build.sh b/scripts/image_signing/sign_official_build.sh index 0f31bcf9..1616d68e 100755 --- a/scripts/image_signing/sign_official_build.sh +++ b/scripts/image_signing/sign_official_build.sh @@ -26,6 +26,7 @@ set -e MINIOS_KERNEL_GUID="09845860-705F-4BB5-B16C-8A8A099CAF52" FIRMWARE_VERSION=1 KERNEL_VERSION=1 +V1_SUFFIX=".v1" # Print usage string usage() { @@ -1484,6 +1485,16 @@ main() { --private-key "${KEY_DIR}/key_hps.priv.pem" elif [[ "${TYPE}" == "uefi_kernel" ]]; then sign_uefi_kernel "${INPUT_IMAGE}" "${OUTPUT_IMAGE}" + elif [[ "${TYPE}" == "recovery_kernel" ]]; then + cp "${INPUT_IMAGE}" "${OUTPUT_IMAGE}" + if [[ -f "${KEYCFG_RECOVERY_KERNEL_V1_KEYBLOCK}" ]]; then + local output_image_v1="${OUTPUT_IMAGE}${V1_SUFFIX}" + cp "${OUTPUT_IMAGE}" "${output_image_v1}" + do_futility sign -b "${KEYCFG_RECOVERY_KERNEL_V1_KEYBLOCK}" -s \ + "${KEYCFG_RECOVERY_KERNEL_VBPRIVK}" "${output_image_v1}" + fi + do_futility sign -b "${KEYCFG_RECOVERY_KERNEL_KEYBLOCK}" -s \ + "${KEYCFG_RECOVERY_KERNEL_VBPRIVK}" "${OUTPUT_IMAGE}" else die "Invalid type ${TYPE}" fi From 1e3f3b11f4c7634a8abe2cf481d1d38dc9b5f551 Mon Sep 17 00:00:00 2001 From: Yu-Ping Wu Date: Thu, 28 Nov 2024 00:39:10 +0000 Subject: [PATCH 082/102] Makefile: Drop vboot_fw.a dependency for futility Android Bringup: See http://go/android-fw-sync The futility binary is linked with libvboot_util.a, which already contains all the objects in vboot_fw.a. Therefore, drop the unnecessary dependency vboot_fw.a for futility. BUG=none TEST=make futil BRANCH=none (cherry picked from commit f8eb37d149352190a2634fb46891e39881434322) Change-Id: I2f5a6d032bfd2807797f2effa9765824dcd233c0 Original-Signed-off-by: Yu-Ping Wu Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6055498 Original-Reviewed-by: Julius Werner GitOrigin-RevId: f8eb37d149352190a2634fb46891e39881434322 Cr-Build-Id: 8730031914062047121 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8730031914062047121 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6056958 Tested-by: ChromeOS Prod (Robot) Reviewed-by: Jonathon Murphy Commit-Queue: Jonathon Murphy --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index bfb1e65b..81e9832c 100644 --- a/Makefile +++ b/Makefile @@ -1159,7 +1159,7 @@ FUTIL_LIBS = ${CROSID_LIBS} ${CRYPTO_LIBS} ${LIBZIP_LIBS} ${LIBARCHIVE_LIBS} \ ${FLASHROM_LIBS} ${FUTIL_BIN}: LDLIBS += ${FUTIL_LIBS} -${FUTIL_BIN}: ${FUTIL_OBJS} ${UTILLIB} ${FWLIB} +${FUTIL_BIN}: ${FUTIL_OBJS} ${UTILLIB} @${PRINTF} " LD $(subst ${BUILD}/,,$@)\n" ${Q}${LD} -o $@ ${LDFLAGS} $^ ${LDLIBS} From b60c37374c5a62c5a1a838b3e165261399b6eadb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Grzesik?= Date: Mon, 4 Nov 2024 12:12:56 +0100 Subject: [PATCH 083/102] tlcl: Increase TPM buffer size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change increases the TPM message buffer size from 512 to 1024 in order to be able to fit new nvmem entry in single read command. Prior to this change the TlclRead(0x3fff0a) would fail, because the space size was too big (820 bytes) to fit into response buffer. With this change the nvmem content can be read safely. This change is required for CL:5947750. BUG=b:359340876 b:354045389 TEST=Verify that nvmem contents are read correctly. BRANCH=firmware-android-15949.B Change-Id: Id227acc5a40d47ec81c2e2ddc83503763e0c88f3 Signed-off-by: Bartłomiej Grzesik Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5987271 Reviewed-by: Yu-Ping Wu Reviewed-by: Grzegorz Bernacki --- firmware/include/tpm2_tss_constants.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/include/tpm2_tss_constants.h b/firmware/include/tpm2_tss_constants.h index 00eb116d..d164adc3 100644 --- a/firmware/include/tpm2_tss_constants.h +++ b/firmware/include/tpm2_tss_constants.h @@ -13,7 +13,7 @@ extern "C" { #endif /* __cplusplus */ -#define TPM_BUFFER_SIZE 512 +#define TPM_BUFFER_SIZE 1024 /* Tpm2 command tags. */ #define TPM_ST_NO_SESSIONS 0x8001 From cf9d499c4c69ab30bec983a7fa5aa70466c4dbc7 Mon Sep 17 00:00:00 2001 From: Yu-Ping Wu Date: Thu, 28 Nov 2024 00:36:44 +0000 Subject: [PATCH 084/102] Android.bp: Remove unused static libraries for firmware builds Android Bringup: See http://go/android-fw-sync Static libraries tlcl.a and vboot_fw.a are used only for firmware builds. As userspace tools don't need them, remove them. BUG=none TEST=mmm external/vboot_reference # From Android tree BRANCH=none (cherry picked from commit dfd2b7c7404edc2bcf977fde32a514024ead1353) Change-Id: I37bd2a3ae3a27f05aa2b895571ba08bb7db45480 Original-Signed-off-by: Yu-Ping Wu Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6055516 Original-Reviewed-by: Jakub Czapiga Original-Commit-Queue: Jakub Czapiga GitOrigin-RevId: dfd2b7c7404edc2bcf977fde32a514024ead1353 Cr-Build-Id: 8729669525805111137 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8729669525805111137 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6062839 Reviewed-by: Jonathon Murphy Tested-by: ChromeOS Prod (Robot) --- Android.bp | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/Android.bp b/Android.bp index 61c63ebb..46385252 100644 --- a/Android.bp +++ b/Android.bp @@ -100,14 +100,6 @@ filegroup { ], } -cc_library_static { - name: "tlcl", - defaults: ["vboot_defaults"], - host_supported: true, - vendor_available: true, - srcs: [":tlcl_srcs"], -} - filegroup { name: "vboot_fw_srcs", srcs: [ @@ -153,14 +145,6 @@ filegroup { ], } -cc_library_static { - name: "vboot_fw", - defaults: ["vboot_defaults"], - host_supported: true, - vendor_available: true, - srcs: [":vboot_fw_srcs"], -} - cc_defaults { name: "libvboot_defaults", defaults: ["vboot_defaults"], From 5c26445df29772757a43888584217cc108c0ae27 Mon Sep 17 00:00:00 2001 From: Yu-Ping Wu Date: Mon, 2 Dec 2024 04:07:47 +0000 Subject: [PATCH 085/102] Android.bp: Remove host_supported for crossystem Android Bringup: See http://go/android-fw-sync The crossystem tool is not needed on the host. Remove host_supported for it. BUG=none TEST=mmm external/vboot_reference # From Android tree BRANCH=none (cherry picked from commit 3ff18c08ee7d6aa005eaa9e10db0c34a1c4d3be7) Change-Id: Id9caeeec6df742a5625049d6af4572b9637a79ad Original-Signed-off-by: Yu-Ping Wu Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6055499 Original-Commit-Queue: Jakub Czapiga Original-Reviewed-by: Jakub Czapiga GitOrigin-RevId: 3ff18c08ee7d6aa005eaa9e10db0c34a1c4d3be7 Cr-Build-Id: 8729669525805111137 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8729669525805111137 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6062840 Tested-by: ChromeOS Prod (Robot) Reviewed-by: Jonathon Murphy --- Android.bp | 1 - 1 file changed, 1 deletion(-) diff --git a/Android.bp b/Android.bp index 46385252..ec1764b1 100644 --- a/Android.bp +++ b/Android.bp @@ -399,7 +399,6 @@ cc_binary { cc_binary { name: "crossystem", defaults: ["vboot_defaults"], - host_supported: true, vendor_available: true, srcs: ["utility/crossystem.c"], From 9e0da44645944d9763a2913d0a88258f46ccbefa Mon Sep 17 00:00:00 2001 From: Julius Werner Date: Thu, 5 Dec 2024 16:10:19 -0800 Subject: [PATCH 086/102] crossystem: Change cros_debug to rely on mainfw_type, not devsw_boot Android Bringup: See http://go/android-fw-sync cros_debug?1 is true either when the kernel command line indicates that we're running a developer image, or when devsw_boot indicates that the developer switch is on. It is generally used to enable insecure debugging features that we do not want to be available in secure mode. Unfortunately, devsw_boot is not the best way to test for this. It reflects the raw state of the developer switch and returns true regardless of boot mode (e.g. also in recovery mode). This means that cros_debug?1 cannot be relied upon to enable debug features in recovery images because their initramfs environment is supposed to remain secure even if the developer switch is on. mainfw_type better reflects what we want here, since it will always be `recovery` in recovery mode and only return `developer` when booting from the developer screen. This patch changes cros_debug to test this instead so it can be reliably used even in recovery contexts. BRANCH=none BUG=b:382540412 TEST=Booted CoachZ in secure, developer, recovery and dev+rec modes, confirmed that cros_debug?1 always reflects the expected state. (cherry picked from commit c57a588f8029ac83675349e75b539ecdc4bcd280) Change-Id: I5bd4ca2da081a7ed125a002a72d99f6ee4444715 Original-Signed-off-by: Julius Werner Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6073625 Original-Reviewed-by: Jae Hoon Kim Original-Owners-Override: Jae Hoon Kim GitOrigin-RevId: c57a588f8029ac83675349e75b539ecdc4bcd280 Cr-Build-Id: 8729216541951974001 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8729216541951974001 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6078248 Commit-Queue: Jonathon Murphy Tested-by: ChromeOS Prod (Robot) Reviewed-by: Jonathon Murphy --- host/lib/crossystem.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/host/lib/crossystem.c b/host/lib/crossystem.c index 7a19c779..6706f577 100644 --- a/host/lib/crossystem.c +++ b/host/lib/crossystem.c @@ -270,8 +270,11 @@ static int VbGetCrosDebug(void) return 0; } - /* Command line is silent; allow debug if the dev switch is on. */ - if (1 == VbGetSystemPropertyInt("devsw_boot")) + /* Command line is silent; allow debug if this was a developer boot. + * NOTE: This should intentionally never be true in recovery mode, + * since the recovery initramfs is supposed to remain trusted even when + * the developer switch is on. */ + if (CheckFwType("developer")) return 1; /* All other cases disallow debug. */ From 44ee97216135ef4d1595da2376a452ec8fa0c3b8 Mon Sep 17 00:00:00 2001 From: Jakub Czapiga Date: Fri, 6 Dec 2024 14:00:36 +0000 Subject: [PATCH 087/102] vboot.rc: Mount tmpfs with SELinux context Android Bringup: See http://go/android-fw-sync Mount tmpfs with SELinux context of firmware tool. Depends on ag/29952894. BRANCH=None BUG=b:382654099 TEST=update-device -f (cherry picked from commit 2935820d404e5ce5e4247b28a9056323a6fbf8df) Change-Id: Id74dfb20b9ea62861f8a6a5ae2e96ffe46a2a2ea Original-Signed-off-by: Jakub Czapiga Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6074679 Original-Reviewed-by: Konrad Adamczyk GitOrigin-RevId: 2935820d404e5ce5e4247b28a9056323a6fbf8df Cr-Build-Id: 8728854154638636641 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8728854154638636641 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6086113 Tested-by: ChromeOS Prod (Robot) Commit-Queue: Jonathon Murphy Reviewed-by: Jonathon Murphy --- vboot.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vboot.rc b/vboot.rc index 959ac808..96a20323 100644 --- a/vboot.rc +++ b/vboot.rc @@ -2,5 +2,5 @@ on post-fs-data-checkpointed mkdir /data/vendor/vboot mkdir /data/vendor/vboot/tmp - mount tmpfs tmpfs /data/vendor/vboot/tmp nosuid nodev noexec rw + mount tmpfs tmpfs /data/vendor/vboot/tmp nosuid nodev noexec rw context=u:object_r:firmware_tool_data_file:s0 restorecon /data/vendor/vboot From 35e7e858f6b4ccf089520f3817e508b1b6486090 Mon Sep 17 00:00:00 2001 From: Tomasz Michalec Date: Tue, 15 Oct 2024 18:16:19 +0200 Subject: [PATCH 088/102] 2lib: Extract misc partition layout to vb2_android_misc.h Extract misc partition layout definitions to separate header vb2_android_misc.h, so it can be shared with depthcharge. BRANCH=main BUG=b:374092472 TEST=Boot Android kernel Change-Id: If3100bef50024260cb2009857bf0efcbefbfe6b2 Signed-off-by: Tomasz Michalec Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5935450 Reviewed-by: Jakub Czapiga --- firmware/2lib/2load_android_kernel.c | 18 ++++-------------- firmware/include/vb2_android_misc.h | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+), 14 deletions(-) create mode 100644 firmware/include/vb2_android_misc.h diff --git a/firmware/2lib/2load_android_kernel.c b/firmware/2lib/2load_android_kernel.c index 2f364566..528c421b 100644 --- a/firmware/2lib/2load_android_kernel.c +++ b/firmware/2lib/2load_android_kernel.c @@ -11,23 +11,13 @@ #include "cgptlib.h" #include "cgptlib_internal.h" #include "gpt_misc.h" +#include "vb2_android_misc.h" #include "vboot_api.h" #include "vboot_avb_ops.h" /* Bytes to read at start of the boot/init_boot/vendor_boot partitions */ #define BOOT_HDR_GKI_SIZE 4096 -/* BCB structure from Android recovery bootloader_message.h */ -struct bootloader_message { - char command[32]; - char status[32]; - char recovery[768]; - char stage[32]; - char reserved[1184]; -}; -_Static_assert(sizeof(struct bootloader_message) == 2048, - "bootloader_message size is incorrect"); - /* Possible values of BCB command */ #define BCB_CMD_BOOTONCE_BOOTLOADER "bootonce-bootloader" #define BCB_CMD_BOOT_RECOVERY "boot-recovery" @@ -36,7 +26,7 @@ _Static_assert(sizeof(struct bootloader_message) == 2048, static enum vb2_boot_command vb2_bcb_command(AvbOps *ops) { - struct bootloader_message bcb; + struct vb2_bootloader_message bcb; AvbIOResult io_ret; size_t num_bytes_read; enum vb2_boot_command cmd; @@ -44,11 +34,11 @@ static enum vb2_boot_command vb2_bcb_command(AvbOps *ops) io_ret = ops->read_from_partition(ops, GPT_ENT_NAME_ANDROID_MISC, 0, - sizeof(struct bootloader_message), + sizeof(struct vb2_bootloader_message), &bcb, &num_bytes_read); if (io_ret != AVB_IO_RESULT_OK || - num_bytes_read != sizeof(struct bootloader_message)) { + num_bytes_read != sizeof(struct vb2_bootloader_message)) { /* * TODO(b/349304841): Handle IO errors, for now just try to boot * normally diff --git a/firmware/include/vb2_android_misc.h b/firmware/include/vb2_android_misc.h new file mode 100644 index 00000000..e1f5d952 --- /dev/null +++ b/firmware/include/vb2_android_misc.h @@ -0,0 +1,22 @@ +/* Copyright 2024 The ChromiumOS Authors + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Layout of an Android misc partition. + */ + +#ifndef VBOOT_REFERENCE_VB2_ANDROID_MISC_H_ +#define VBOOT_REFERENCE_VB2_ANDROID_MISC_H_ + +/* BCB structure from Android recovery bootloader_message.h */ +struct vb2_bootloader_message { + char command[32]; + char status[32]; + char recovery[768]; + char stage[32]; + char reserved[1184]; +}; +_Static_assert(sizeof(struct vb2_bootloader_message) == 2048, + "vb2_bootloader_message size is incorrect"); + +#endif /* VBOOT_REFERENCE_VB2_ANDROID_MISC_H_ */ From 64db5b1ed9d85e96d13e70c9c480e927ad00e9cf Mon Sep 17 00:00:00 2001 From: Tomasz Michalec Date: Mon, 21 Oct 2024 15:09:59 +0200 Subject: [PATCH 089/102] 2load_android_kernel: Add fastboot cmdline Add definition of fastboot_cmdline which is stored on the vendor space of the misc partition. Parameters from fastboot_cmdline are added to vboot cmdline only if the FW is in developer mode. BRANCH=firmware-android-15949.B BUG=b:374092472 TEST=Add arguments using fastboot, boot Android and check if arguments are present in bootconfig. Change-Id: I786a158a597d0551c89f69c26b9bf80a73459d14 Signed-off-by: Tomasz Michalec Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/5947525 Reviewed-by: Jakub Czapiga --- firmware/2lib/2load_android_kernel.c | 100 ++++++++++++++++++++++++++- firmware/include/vb2_android_misc.h | 41 +++++++++++ 2 files changed, 139 insertions(+), 2 deletions(-) diff --git a/firmware/2lib/2load_android_kernel.c b/firmware/2lib/2load_android_kernel.c index 528c421b..bc436f30 100644 --- a/firmware/2lib/2load_android_kernel.c +++ b/firmware/2lib/2load_android_kernel.c @@ -66,6 +66,88 @@ static enum vb2_boot_command vb2_bcb_command(AvbOps *ops) return cmd; } +static uint32_t fletcher32(const char *data, size_t len) +{ + uint32_t s0 = 0; + uint32_t s1 = 0; + + for (; len > 0; len--, data++) { + s0 = (s0 + *data) % UINT16_MAX; + s1 = (s1 + s0) % UINT16_MAX; + } + + return (s1 << 16) | s0; +} + +bool vb2_is_fastboot_cmdline_valid(struct vb2_fastboot_cmdline *fb_cmd) +{ + if (fb_cmd->version != 0) { + VB2_DEBUG("Unknown vb2_fastboot_cmdline version (%d)", fb_cmd->version); + return false; + } + + if (fb_cmd->magic != VB2_MISC_VENDOR_SPACE_FASTBOOT_CMDLINE_MAGIC) { + VB2_DEBUG("Wrong vb2_fastboot_cmdline magic (0x%x)", fb_cmd->magic); + return false; + } + + if (fb_cmd->len > sizeof(fb_cmd->cmdline)) { + VB2_DEBUG("Wrong vb2_fastboot_cmdline len (%d)", fb_cmd->len); + return false; + } + + if (fb_cmd->fletcher != fletcher32((char *)&fb_cmd->len, + sizeof(fb_cmd->len) + fb_cmd->len)) { + VB2_DEBUG("Wrong vb2_fastboot_cmdline checksum"); + return false; + } + + return true; +} + +bool vb2_update_fastboot_cmdline_checksum(struct vb2_fastboot_cmdline *fb_cmd) +{ + if (fb_cmd->len > sizeof(fb_cmd->cmdline)) { + VB2_DEBUG("Wrong vb2_fastboot_cmdline len (%d)", fb_cmd->len); + return false; + } + + fb_cmd->fletcher = fletcher32((char *)&fb_cmd->len, sizeof(fb_cmd->len) + fb_cmd->len); + + return true; +} + +static struct vb2_fastboot_cmdline *vb2_fastboot_cmdline(AvbOps *ops) +{ + struct vb2_fastboot_cmdline *fb_cmd; + AvbIOResult io_ret; + size_t num_bytes_read; + + fb_cmd = malloc(sizeof(struct vb2_fastboot_cmdline)); + if (fb_cmd == NULL) + return NULL; + + io_ret = ops->read_from_partition(ops, + GPT_ENT_NAME_ANDROID_MISC, + VB2_MISC_VENDOR_SPACE_FASTBOOT_CMDLINE_OFFSET, + sizeof(struct vb2_fastboot_cmdline), + fb_cmd, + &num_bytes_read); + if (io_ret != AVB_IO_RESULT_OK || + num_bytes_read != sizeof(struct vb2_fastboot_cmdline)) { + VB2_DEBUG("Cannot read misc partition.\n"); + free(fb_cmd); + return NULL; + } + + if (!vb2_is_fastboot_cmdline_valid(fb_cmd)) { + free(fb_cmd); + return NULL; + } + + return fb_cmd; +} + vb2_error_t vb2_load_android_kernel( struct vb2_context *ctx, struct vb2_kernel_params *params, VbExStream_t stream, GptData *gpt, vb2ex_disk_handle_t disk_handle, @@ -85,6 +167,7 @@ vb2_error_t vb2_load_android_kernel( AvbSlotVerifyResult result; vb2_error_t ret; char *verified_str; + struct vb2_fastboot_cmdline *fb_cmd = NULL; /* * Check if the buffer is zero sized (ie. pvmfw loading is not @@ -155,6 +238,11 @@ vb2_error_t vb2_load_android_kernel( } params->boot_command = vb2_bcb_command(avb_ops); + + /* Load fastboot cmdline only in developer mode */ + if (ctx->flags & VB2_CONTEXT_DEVELOPER_MODE) + fb_cmd = vb2_fastboot_cmdline(avb_ops); + vboot_avb_ops_free(avb_ops); /* TODO(b/335901799): Add support for marking verifiedbootstate yellow */ @@ -167,8 +255,8 @@ vb2_error_t vb2_load_android_kernel( sprintf(verified_str, "%s%s", VERIFIED_BOOT_PROPERTY_NAME, (ctx->flags & VB2_CONTEXT_DEVELOPER_MODE) ? "orange" : "green"); - if ((strlen(verify_data->cmdline) + strlen(verified_str) + 1) >= - params->kernel_cmdline_size) + if ((strlen(verify_data->cmdline) + strlen(verified_str) + + (fb_cmd ? fb_cmd->len : 0) + 1) >= params->kernel_cmdline_size) return VB2_ERROR_LOAD_PARTITION_WORKBUF; strcpy(params->kernel_cmdline_buffer, verify_data->cmdline); @@ -179,6 +267,14 @@ vb2_error_t vb2_load_android_kernel( free(verified_str); + if (fb_cmd) { + /* Append fastboot properties to cmdline */ + strcat(params->kernel_cmdline_buffer, " "); + strncat(params->kernel_cmdline_buffer, fb_cmd->cmdline, fb_cmd->len); + + free(fb_cmd); + } + /* No need for slot data, partitions should be already at correct * locations in memory since we are using "get_preloaded_partitions" * callbacks. diff --git a/firmware/include/vb2_android_misc.h b/firmware/include/vb2_android_misc.h index e1f5d952..a63f1b4d 100644 --- a/firmware/include/vb2_android_misc.h +++ b/firmware/include/vb2_android_misc.h @@ -8,6 +8,8 @@ #ifndef VBOOT_REFERENCE_VB2_ANDROID_MISC_H_ #define VBOOT_REFERENCE_VB2_ANDROID_MISC_H_ +#include + /* BCB structure from Android recovery bootloader_message.h */ struct vb2_bootloader_message { char command[32]; @@ -19,4 +21,43 @@ struct vb2_bootloader_message { _Static_assert(sizeof(struct vb2_bootloader_message) == 2048, "vb2_bootloader_message size is incorrect"); +/* + * Reserve space for fastboot oem cmdline on misc partition. Use for that vendor + * space which is at 2K - 16K range in misc. Skip 2K - 4K range as it may be + * optionally used as bootloader_message_ab struct. + */ +#define VB2_MISC_VENDOR_SPACE_FASTBOOT_CMDLINE_OFFSET (1024 * 4) +#define VB2_MISC_VENDOR_SPACE_FASTBOOT_CMDLINE_SIZE (1024 * 2) +/* Hex values for ASCII "FCML" */ +#define VB2_MISC_VENDOR_SPACE_FASTBOOT_CMDLINE_MAGIC 0x46434d4c +struct vb2_fastboot_cmdline { + uint8_t version; + uint32_t magic; + /* Fletcher-32 checksum of len and cmdline up to len bytes */ + uint32_t fletcher; + uint16_t len; + char cmdline[2037]; +} __attribute__((packed)); +_Static_assert(sizeof(struct vb2_fastboot_cmdline) == + VB2_MISC_VENDOR_SPACE_FASTBOOT_CMDLINE_SIZE, + "vb2_fastboot_cmdline size is incorrect"); + +/* + * Check if vb2_fastboot_cmdline structure is valid, i.e if magic is correct, + * len property doesn't exceed cmdline size, fletcher checksum is valid. + * + * @param fb_cmd Fastboot cmdline structure from misc partition. + * @returns 1 if structure data pass all checks, 0 otherwise. + */ +bool vb2_is_fastboot_cmdline_valid(struct vb2_fastboot_cmdline *fb_cmd); + +/* + * Calculate and set checksum property of given vb2_fastboot_cmdline structure. + * If len property exceed cmdline size, then checksum is not calculated. + * + * @param fb_cmd Fastboot cmdline structure from misc partition. + * @returns 1 if checksum is set, 0 otherwise. + */ +bool vb2_update_fastboot_cmdline_checksum(struct vb2_fastboot_cmdline *fb_cmd); + #endif /* VBOOT_REFERENCE_VB2_ANDROID_MISC_H_ */ From aef6ca5f321992780fc369bb82c4e3c3843d64f2 Mon Sep 17 00:00:00 2001 From: Jakub Czapiga Date: Thu, 12 Dec 2024 17:08:38 +0000 Subject: [PATCH 090/102] futility: Add shell-parseable manifest format Android Bringup: See http://go/android-fw-sync Add --parseable-manifest options to print manifest in `futility show -P` format. Example output: link::host::image::image.bin link::host::versions::ro::Google_Link.2695.1.133 link::host::versions::rw::Google_Link.2695.1.133 link::host::keys::recovery::7e74cd6d66f361da068c0419d2e0946b4d091e1c link::host::keys::root::7b5c520ceabce86f13e02b7ca363cfb509fc5b98 BRANCH=main BUG=b:356051231, b:370889644 TEST=futility update --parseable-manifest -a "${FWPATH}" TEST=sudo FEATURES="test" emerge vboot_reference (cherry picked from commit d1813a4666d7de37fa210a2197bf6ce8cf56a3d5) Change-Id: Ib4016095048ae8c306da45cd49e18da20ea2b549 Original-Signed-off-by: Jakub Czapiga Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6092873 Original-Reviewed-by: Konrad Adamczyk Original-Commit-Queue: Konrad Adamczyk GitOrigin-RevId: d1813a4666d7de37fa210a2197bf6ce8cf56a3d5 Cr-Build-Id: 8728219974753720561 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8728219974753720561 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6104494 Commit-Queue: Jonathon Murphy Tested-by: ChromeOS Prod (Robot) Reviewed-by: Jonathon Murphy --- futility/cmd_update.c | 10 ++++ futility/updater.c | 28 +++++++-- futility/updater.h | 9 +++ futility/updater_manifest.c | 59 +++++++++++++++++++ .../bios_geralt_cbfs.manifest.parseable | 6 ++ tests/futility/link_bios.manifest.parseable | 5 ++ tests/futility/link_image.manifest.parseable | 5 ++ tests/futility/test_update.sh | 19 ++++++ 8 files changed, 137 insertions(+), 4 deletions(-) create mode 100644 tests/futility/bios_geralt_cbfs.manifest.parseable create mode 100644 tests/futility/link_bios.manifest.parseable create mode 100644 tests/futility/link_image.manifest.parseable diff --git a/futility/cmd_update.c b/futility/cmd_update.c index c000e70e..b9f542e3 100644 --- a/futility/cmd_update.c +++ b/futility/cmd_update.c @@ -24,6 +24,7 @@ enum { OPT_GBB_FLAGS, OPT_HOST_ONLY, OPT_MANIFEST, + OPT_PARSEABLE_MANIFEST, OPT_MODEL, OPT_OUTPUT_DIR, OPT_QUIRKS, @@ -60,6 +61,7 @@ static struct option const long_opts[] = { {"quirks", 1, NULL, OPT_QUIRKS}, {"list-quirks", 0, NULL, OPT_QUIRKS_LIST}, {"manifest", 0, NULL, OPT_MANIFEST}, + {"parseable-manifest", 0, NULL, OPT_PARSEABLE_MANIFEST}, {"model", 1, NULL, OPT_MODEL}, {"output_dir", 1, NULL, OPT_OUTPUT_DIR}, {"repack", 1, NULL, OPT_REPACK}, @@ -108,6 +110,9 @@ static void print_help(int argc, char *argv[]) " --list-quirks \tPrint all available quirks\n" "-m, --mode=MODE \tRun updater in the specified mode\n" " --manifest \tScan the archive to print a manifest in JSON\n" + " --parseable-manifest\n" + " \tScan the archive to print a manifest\n" + " \tin shell-parseable format\n" SHARED_FLASH_ARGS_HELP "\n" " * Option --manifest requires either -a,--archive or -i,--image\n" @@ -241,6 +246,11 @@ static int do_update(int argc, char *argv[]) break; case OPT_MANIFEST: args.do_manifest = 1; + args.manifest_format = MANIFEST_PRINT_FORMAT_JSON; + break; + case OPT_PARSEABLE_MANIFEST: + args.do_manifest = 1; + args.manifest_format = MANIFEST_PRINT_FORMAT_PARSEABLE; break; case OPT_FACTORY: args.is_factory = 1; diff --git a/futility/updater.c b/futility/updater.c index b958f435..a4ec6bde 100644 --- a/futility/updater.c +++ b/futility/updater.c @@ -1475,7 +1475,7 @@ static int check_arg_compatibility( */ if (arg->detect_model_only) { if (arg->do_manifest || arg->repack || arg->unpack) { - ERROR("--manifest/--repack/--unpack" + ERROR("--manifest/--parseable-manifest/--repack/--unpack" " is not compatible with --detect-model-only.\n"); return -1; } @@ -1486,7 +1486,7 @@ static int check_arg_compatibility( } else if (arg->do_manifest) { if (arg->repack || arg->unpack) { ERROR("--repack/--unpack" - " is not compatible with --manifest.\n"); + " is not compatible with --manifest/--parseable-manifest.\n"); return -1; } if (!arg->archive && !(arg->image || arg->ec_image)) { @@ -1621,7 +1621,14 @@ static int print_manifest(const struct updater_config_arguments *arg) .num = 1, .models = &model, }; - print_json_manifest(&manifest); + if (arg->manifest_format == MANIFEST_PRINT_FORMAT_JSON) { + print_json_manifest(&manifest); + } else if (arg->manifest_format == MANIFEST_PRINT_FORMAT_PARSEABLE) { + print_parseable_manifest(&manifest); + } else { + ERROR("Unknown manifest format requested: %d", arg->manifest_format); + return 1; + } return 0; } @@ -1637,6 +1644,11 @@ static int print_manifest(const struct updater_config_arguments *arg) uint8_t *data = NULL; uint32_t size = 0; + if (arg->manifest_format != MANIFEST_PRINT_FORMAT_JSON) { + ERROR("Only manifest format supported in fast mode is JSON.\n"); + return 1; + } + if (!archive_has_entry(archive, manifest_name) || archive_read_file(archive, manifest_name, &data, &size, NULL)) { @@ -1655,7 +1667,15 @@ static int print_manifest(const struct updater_config_arguments *arg) arg->archive); return 1; } - print_json_manifest(manifest); + if (arg->manifest_format == MANIFEST_PRINT_FORMAT_JSON) { + print_json_manifest(manifest); + } else if (arg->manifest_format == MANIFEST_PRINT_FORMAT_PARSEABLE) { + print_parseable_manifest(manifest); + } else { + ERROR("Unknown manifest format requested: %d", arg->manifest_format); + delete_manifest(manifest); + return 1; + } delete_manifest(manifest); } diff --git a/futility/updater.h b/futility/updater.h index 00f2c46b..f936dac0 100644 --- a/futility/updater.h +++ b/futility/updater.h @@ -104,6 +104,11 @@ struct updater_config { bool output_only; }; +enum manifest_print_format { + MANIFEST_PRINT_FORMAT_JSON = 0, + MANIFEST_PRINT_FORMAT_PARSEABLE, +}; + struct updater_config_arguments { char *image, *ec_image; char *archive, *quirks, *mode; @@ -113,6 +118,7 @@ struct updater_config_arguments { char *output_dir; char *repack, *unpack; int is_factory, try_update, force_update, do_manifest, host_only; + enum manifest_print_format manifest_format; int fast_update; int verbosity; int override_gbb_flags; @@ -341,6 +347,9 @@ void delete_manifest(struct manifest *manifest); /* Prints the information of objects in manifest (models and images) in JSON. */ void print_json_manifest(const struct manifest *manifest); +/* Prints the manifest in parseable double-colon-separated tokens format. */ +void print_parseable_manifest(const struct manifest *manifest); + /* * Modifies a firmware image from patch information specified in model config. * Returns 0 on success, otherwise number of failures. diff --git a/futility/updater_manifest.c b/futility/updater_manifest.c index c9d8c509..f8b1ce42 100644 --- a/futility/updater_manifest.c +++ b/futility/updater_manifest.c @@ -819,3 +819,62 @@ void print_json_manifest(const struct manifest *manifest) } printf("\n}\n"); } + +static void print_parseable_image(const char *name, const char *fpath, struct model_config *m, + struct u_archive *archive, bool is_host) +{ + struct firmware_image image = {0}; + const struct vb2_gbb_header *gbb = NULL; + + if (!fpath) + return; + if (load_firmware_image(&image, fpath, archive)) + return; + + printf("%s::%s::versions::ro::%s\n", m->name, name, image.ro_version); + printf("%s::%s::versions::rw::%s\n", m->name, name, image.rw_version_a); + if (is_host) { + if (image.ecrw_version_a[0] != '\0') + printf("%s::%s::versions::ecrw::%s\n", m->name, name, + image.ecrw_version_a); + + if (patch_image_by_model(&image, m, archive)) + ERROR("Failed to patch images by model: %s\n", m->name); + else + gbb = find_gbb(&image); + + if (gbb != NULL) { + printf("%s::%s::keys::root::%s\n", m->name, name, + get_gbb_key_hash(gbb, gbb->rootkey_offset, gbb->rootkey_size)); + printf("%s::%s::keys::recovery::%s\n", m->name, name, + get_gbb_key_hash(gbb, gbb->recovery_key_offset, + gbb->recovery_key_size)); + } + } + printf("%s::%s::image::%s\n", m->name, name, fpath); + check_firmware_versions(&image); + free_firmware_image(&image); +} + +void print_parseable_manifest(const struct manifest *manifest) +{ + struct u_archive *ar = manifest->archive; + + for (int i = 0; i < manifest->num; ++i) { + struct model_config *m = &manifest->models[i]; + if (m->image) + print_parseable_image("host", m->image, m, ar, true); + + if (m->ec_image) + print_parseable_image("ec", m->ec_image, m, ar, false); + + if (m->patches.rootkey) { + struct patch_config *p = &m->patches; + printf("%s::patches::rootkey::%s\n", m->name, p->rootkey); + printf("%s::patches::vblock_a::%s\n", m->name, p->vblock_a); + printf("%s::patches::vblock_b::%s\n", m->name, p->vblock_b); + if (p->gscvd) + printf("%s::gscvd::%s\n", m->name, p->gscvd); + } + } +} diff --git a/tests/futility/bios_geralt_cbfs.manifest.parseable b/tests/futility/bios_geralt_cbfs.manifest.parseable new file mode 100644 index 00000000..d109c567 --- /dev/null +++ b/tests/futility/bios_geralt_cbfs.manifest.parseable @@ -0,0 +1,6 @@ +default::host::versions::ro::Google_Geralt.15635.0.0 +default::host::versions::rw::Google_Geralt.15635.0.0 +default::host::versions::ecrw::geralt-15857.0.0 +default::host::keys::root::b11d74edd286c144e1135b49e7f0bc20cf041f10 +default::host::keys::recovery::c14bd720b70d97394257e3e826bd8f43de48d4ed +default::host::image::image.bin diff --git a/tests/futility/link_bios.manifest.parseable b/tests/futility/link_bios.manifest.parseable new file mode 100644 index 00000000..ae5e8f6a --- /dev/null +++ b/tests/futility/link_bios.manifest.parseable @@ -0,0 +1,5 @@ +link::host::image::bios.bin +link::host::versions::ro::Google_Link.2695.1.133 +link::host::versions::rw::Google_Link.2695.1.133 +link::host::keys::recovery::7e74cd6d66f361da068c0419d2e0946b4d091e1c +link::host::keys::root::7b5c520ceabce86f13e02b7ca363cfb509fc5b98 diff --git a/tests/futility/link_image.manifest.parseable b/tests/futility/link_image.manifest.parseable new file mode 100644 index 00000000..c86a24fb --- /dev/null +++ b/tests/futility/link_image.manifest.parseable @@ -0,0 +1,5 @@ +link::host::image::image.bin +link::host::versions::ro::Google_Link.2695.1.133 +link::host::versions::rw::Google_Link.2695.1.133 +link::host::keys::recovery::7e74cd6d66f361da068c0419d2e0946b4d091e1c +link::host::keys::root::7b5c520ceabce86f13e02b7ca363cfb509fc5b98 diff --git a/tests/futility/test_update.sh b/tests/futility/test_update.sh index edea233b..8d8bcced 100755 --- a/tests/futility/test_update.sh +++ b/tests/futility/test_update.sh @@ -506,6 +506,14 @@ cmp \ <(jq -S <"${TMP_JSON_OUT}") \ <(jq -S <"${SCRIPT_DIR}/futility/bios_geralt_cbfs.manifest.json") +TMP_PARSEABLE_OUT="${TMP}/manifest.parseable" +echo "TEST: Manifest parseable (--parseable-manifest, --image)" +(cd "${TMP}" && + "${FUTILITY}" update -i image.bin --parseable-manifest) >"${TMP_PARSEABLE_OUT}" +cmp \ + <(sort "${TMP_PARSEABLE_OUT}") \ + <(sort "${SCRIPT_DIR}/futility/bios_geralt_cbfs.manifest.parseable") + # Test archive and manifest. CL_TAG is for custom_label_tag. A="${TMP}/archive" mkdir -p "${A}/bin" @@ -519,6 +527,12 @@ cmp \ <(jq -S <"${TMP_JSON_OUT}") \ <(jq -S <"${SCRIPT_DIR}/futility/link_bios.manifest.json") +echo "TEST: Manifest parseable (--parseable-manifest, -a, bios.bin)" +"${FUTILITY}" update -a "${A}" --parseable-manifest >"${TMP_PARSEABLE_OUT}" +diff -u \ + <(sort "${TMP_PARSEABLE_OUT}") \ + <(sort "${SCRIPT_DIR}/futility/link_bios.manifest.parseable") + mv -f "${A}/bios.bin" "${A}/image.bin" echo "TEST: Manifest (--manifest, -a, image.bin)" "${FUTILITY}" update -a "${A}" --manifest >"${TMP_JSON_OUT}" @@ -526,6 +540,11 @@ cmp \ <(jq -S <"${TMP_JSON_OUT}") \ <(jq -S <"${SCRIPT_DIR}/futility/link_image.manifest.json") +echo "TEST: Manifest parseable (--parseable-manifest, -a, image.bin)" +"${FUTILITY}" update -a "${A}" --parseable-manifest >"${TMP_PARSEABLE_OUT}" +diff -u \ + <(sort "${TMP_PARSEABLE_OUT}") \ + <(sort "${SCRIPT_DIR}/futility/link_image.manifest.parseable") cp -f "${TO_IMAGE}" "${A}/image.bin" test_update "Full update (--archive, single package)" \ From a2329391dd9c7294c868002c614f856edd3e72f9 Mon Sep 17 00:00:00 2001 From: Jakub Czapiga Date: Thu, 12 Dec 2024 17:15:23 +0000 Subject: [PATCH 091/102] futility/updater: Remove obsolete write protection help URL Android Bringup: See http://go/android-fw-sync BRANCH=main BUG=None TEST=None (cherry picked from commit 44c19d1893aa48e0e2abe32023c6e34e75d173be) Change-Id: I8342eb6d51482baf9a7d5c47905c67bae1a03723 Original-Signed-off-by: Jakub Czapiga Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6092872 Original-Reviewed-by: Yu-Ping Wu Original-Tested-by: Yu-Ping Wu Original-Reviewed-by: Hsuan Ting Chen GitOrigin-RevId: 44c19d1893aa48e0e2abe32023c6e34e75d173be Cr-Build-Id: 8728129374666165665 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8728129374666165665 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6108406 Tested-by: ChromeOS Prod (Robot) Reviewed-by: Jonathon Murphy Commit-Queue: Jonathon Murphy --- futility/updater.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/futility/updater.c b/futility/updater.c index a4ec6bde..07c14f00 100644 --- a/futility/updater.c +++ b/futility/updater.c @@ -17,8 +17,6 @@ #include "updater.h" #include "util_misc.h" -#define REMOVE_WP_URL "https://goo.gl/ces83U" - static const char ROOTKEY_HASH_DEV[] = "b11d74edd286c144e1135b49e7f0bc20cf041f10"; @@ -1247,7 +1245,7 @@ enum updater_error_codes update_firmware(struct updater_config *cfg) /* Providing more hints for what to do on failure. */ if (r == UPDATE_ERR_ROOT_KEY && wp_enabled) ERROR("To change keys in RO area, you must first remove " - "write protection ( " REMOVE_WP_URL " ).\n"); + "write protection.\n"); return r; } @@ -1807,8 +1805,7 @@ int updater_setup_config(struct updater_config *cfg, } if (check_wp_disabled && is_ap_write_protection_enabled(cfg)) { errorcnt++; - ERROR("Please remove write protection for factory mode \n" - "( " REMOVE_WP_URL " )."); + ERROR("Please remove write protection for factory mode\n"); } if (cfg->image.data) { From 412cc8e4d15b1cb142c0c24611001d2fa32612d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20L=C3=B3pez?= Date: Fri, 13 Dec 2024 17:08:29 +0100 Subject: [PATCH 092/102] Makefile: Allow cross-compilation for RISC-V Android Bringup: See http://go/android-fw-sync MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow setting FIRMWARE_ARCH=riscv to build vboot for the RISC-V architecture. Note that building for 32-bit RISC-V requires additional CFLAGS. (cherry picked from commit 3f94e2c7ed58c4e67d6e7dc6052ec615dbbb9bb4) Change-Id: I5c72900494f465fb625f315f550849f5b69f3cca Original-Signed-off-by: Carlos López Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6091368 Original-Tested-by: Julius Werner Original-Commit-Queue: Julius Werner Original-Reviewed-by: Yu-Ping Wu Original-Reviewed-by: Julius Werner GitOrigin-RevId: 3f94e2c7ed58c4e67d6e7dc6052ec615dbbb9bb4 Cr-Build-Id: 8728129374666165665 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8728129374666165665 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6108407 Commit-Queue: Jonathon Murphy Reviewed-by: Jonathon Murphy Tested-by: ChromeOS Prod (Robot) --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 81e9832c..128fd9c9 100644 --- a/Makefile +++ b/Makefile @@ -161,6 +161,8 @@ CFLAGS ?= -fvisibility=hidden -fomit-frame-pointer \ else ifeq (${FIRMWARE_ARCH},x86_64) CFLAGS ?= ${FIRMWARE_FLAGS} ${COMMON_FLAGS} -fvisibility=hidden \ -fomit-frame-pointer +else ifeq (${FIRMWARE_ARCH},riscv) +CC ?= riscv64-linux-gnu-gcc else ifeq (${FIRMWARE_ARCH},mock) FIRMWARE_STUB := 1 CFLAGS += ${TEST_FLAGS} From 23026278a79d29de0883a0e0965e9799dff76907 Mon Sep 17 00:00:00 2001 From: Jon Murphy Date: Thu, 19 Dec 2024 16:28:41 -0700 Subject: [PATCH 093/102] OWNERS: Update owners for copybot BUG=None TEST=CQ Change-Id: Ic8357f9fd064465328fa5b42337d6b3e502fb94a Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6112116 Auto-Submit: Jonathon Murphy Commit-Queue: Jeremy Bettis Commit-Queue: Jonathon Murphy Reviewed-by: Jeremy Bettis Tested-by: Jonathon Murphy --- OWNERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OWNERS b/OWNERS index 8c7c08cf..e1239b0b 100644 --- a/OWNERS +++ b/OWNERS @@ -1 +1,3 @@ include chromiumos/owners:v1:/firmware/OWNERS.android +# ChromeOS Prod +chromeos-ci-prod@chromeos-bot.iam.gserviceaccount.com #{LAST_RESORT_SUGGESTION} From ded4fb1dd0a88183a5d32e56bce76d175945afe5 Mon Sep 17 00:00:00 2001 From: Shou-Chieh Hsu Date: Thu, 9 Jan 2025 09:25:29 +0000 Subject: [PATCH 094/102] Makefile: Export swap_ec_rw script to OS image Android Bringup: See http://go/android-fw-sync The script could be useful for partners during device development without having complete ChromeOS SDK. BUG=b:388643063 TEST=build-packages && build-images && check /usr/share/vboot/bin/swap_ec_rw exists BRANCH=none (cherry picked from commit c3f20ccfcf304808300fff2e0d9191ca15d9116c) Change-Id: I8d9271fb17faf79f2d23e41a07ca36d20cf2953f Original-Signed-off-by: Shou-Chieh Hsu Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6162156 Original-Reviewed-by: Yu-Ping Wu GitOrigin-RevId: c3f20ccfcf304808300fff2e0d9191ca15d9116c Cr-Build-Id: 8726181543842398417 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8726181543842398417 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6164690 Tested-by: ChromeOS Prod (Robot) Bot-Commit: ChromeOS Prod (Robot) Commit-Queue: ChromeOS Prod (Robot) --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 128fd9c9..ae65c9a1 100644 --- a/Makefile +++ b/Makefile @@ -686,6 +686,7 @@ SIGNING_SCRIPTS_BOARD = \ scripts/image_signing/make_dev_firmware.sh \ scripts/image_signing/make_dev_ssd.sh \ scripts/image_signing/resign_firmwarefd.sh \ + scripts/image_signing/swap_ec_rw \ scripts/image_signing/common_minimal.sh # SDK installations have some extra scripts. From 688fc1f9edf65d51679a1f66132a161f537a8851 Mon Sep 17 00:00:00 2001 From: Benjamin Shai Date: Thu, 9 Jan 2025 10:45:54 -0800 Subject: [PATCH 095/102] signing: add condition for flexor Android Bringup: See http://go/android-fw-sync Looking at `ImageType` enum in the proto def, we use a type `IMAGE_TYPE_FLEXOR_KERNEL` for uefi signing. The old signing instructions would translate that to uefi, but new signing just strips the prefix and passes through `flexor_kernel`. Instead of having to do mapping, let's just make all the code consistent and easier to reason about. BUG=b:372702794 TEST=None (cherry picked from commit 3498c54d26a9bf7c898ef4b69c507ffa4e6dc46b) Change-Id: I90c0bfc9afe0daea23a3f4e2fc0cac6f88779fe5 Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6165423 Original-Reviewed-by: George Engelbrecht Original-Commit-Queue: ChromeOS Auto Retry Original-Reviewed-by: Madeleine Hardt Original-Tested-by: Benjamin Shai GitOrigin-RevId: 3498c54d26a9bf7c898ef4b69c507ffa4e6dc46b Cr-Build-Id: 8726143793748096865 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8726143793748096865 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6165589 Tested-by: ChromeOS Prod (Robot) Bot-Commit: ChromeOS Prod (Robot) Commit-Queue: ChromeOS Prod (Robot) --- scripts/image_signing/sign_official_build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/image_signing/sign_official_build.sh b/scripts/image_signing/sign_official_build.sh index 1616d68e..27d6c238 100755 --- a/scripts/image_signing/sign_official_build.sh +++ b/scripts/image_signing/sign_official_build.sh @@ -1483,7 +1483,7 @@ main() { elif [[ "${TYPE}" == "hps_firmware" ]]; then hps-sign-rom --input "${INPUT_IMAGE}" --output "${OUTPUT_IMAGE}" \ --private-key "${KEY_DIR}/key_hps.priv.pem" - elif [[ "${TYPE}" == "uefi_kernel" ]]; then + elif [[ "${TYPE}" == "uefi_kernel" || "${TYPE}" == "flexor_kernel" ]]; then sign_uefi_kernel "${INPUT_IMAGE}" "${OUTPUT_IMAGE}" elif [[ "${TYPE}" == "recovery_kernel" ]]; then cp "${INPUT_IMAGE}" "${OUTPUT_IMAGE}" From 4f56bc654a1dc1a9b271c686416b82b36ae1f4d8 Mon Sep 17 00:00:00 2001 From: Yu-Ping Wu Date: Fri, 10 Jan 2025 14:47:11 +0800 Subject: [PATCH 096/102] futility: updater: Increase try count from 13 to 17 Android Bringup: See http://go/android-fw-sync The current try count is 13 for two reasons: 1. As explained in CL:5690663, Rex needs 11 reboots in the worst case. 2. In CL:5970064, we added an extra 2 boots to mitigate the problem of abrupt user poweroff during firmware update process. However, Nissa needs 13 reboots in the worst case. - Boot 0: Initial reboot with CSE in RW. To allow CSE update, reboot to switch to CSE RO. - Boot 1: Update CSE RW. Reboot to switch to CSE RW. - Boot 2: GSC needs update. Reset GSC to switch to the other partition. - Boot 3: CSE is back in RO due to GSC reset. Reboot to switch to RW. - Boot 4: EC needs update. Reboot to EC RO to allow EC sync. - Boot 5: CSE is back in RO due to EC reset. Reboot to switch to RW. - Boot 6: Attempt to perform EC sync, but need display to show the EC sync screen. Reboot to init display. - Boot 7: Perform EC sync. Under EFS2 NO_BOOT mode, reboot to EC RO to allow jumping to RW. - Boot 8: CSE is back in RO due to EC reset. Reboot to switch to RW. - Boot 9: Perform auxfw sync and reboot to EC RO. - Boot 10: CSE is back in RO due to EC reset. Reboot to switch to RW. - Boot 11: Everything is updated, but need to reboot again to unset display. - Boot 12: Boot to kernel, finally! The only difference between Nissa and Rex is the display init. On Rex, the display is always initialized for the splash screen. On Nissa, 2 extra reboots are needed to enable and disable display, respectively. In addition, the 2 boots reserved for poweroff mitigation are actually not enough, because after the abrupt user poweroff, the CSE will go back to RO. For example, if the poweroff happens in Boot 9 (before auxfw sync), then the device will go back to Boot 8, resulting in 2 extra reboots. Therefore, to allow 2 cases of abrupt poweroff, we will need extra 4 boots in the try count. Together with Nissa's worst-case scenario, we will need an initial try count as large as 17. BUG=b:385224631 TEST=none BRANCH=none (cherry picked from commit 7e5bda8a8210e4b50fb80cf890a20bd9e711648b) Change-Id: I4503ef2f519f5368a4697861d1dffac5fbe1cfb5 Original-Signed-off-by: Yu-Ping Wu Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6164433 Original-Reviewed-by: Subrata Banik Original-Tested-by: Subrata Banik Original-Commit-Queue: Subrata Banik GitOrigin-RevId: 7e5bda8a8210e4b50fb80cf890a20bd9e711648b Cr-Build-Id: 8725826705970452705 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8725826705970452705 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6173175 Commit-Queue: ChromeOS Prod (Robot) Tested-by: ChromeOS Prod (Robot) Bot-Commit: ChromeOS Prod (Robot) --- futility/updater.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/futility/updater.c b/futility/updater.c index 07c14f00..7511b3d0 100644 --- a/futility/updater.c +++ b/futility/updater.c @@ -264,7 +264,7 @@ static const char *decide_rw_target(struct updater_config *cfg, static int set_try_cookies(struct updater_config *cfg, const char *target, int has_update) { - int tries = 13; + int tries = 17; const char *slot; if (!has_update) From e13ce79fcd454f90d784651c0b76bcff10a9e5e6 Mon Sep 17 00:00:00 2001 From: Yu-Ping Wu Date: Mon, 13 Jan 2025 12:31:55 +0800 Subject: [PATCH 097/102] firmware/2lib: Add a log for try_count used up Android Bringup: See http://go/android-fw-sync For bugs such as b/385224631 (where the device fails to boot up), showing a warning log when the try_count is used up might help for debugging. BUG=none TEST=emerge-geralt libpayload BRANCH=none (cherry picked from commit 2e00eae8f9a0c07abad9243c564b1b7339ad9e09) Change-Id: I295cefc2707534099e82ff0164921c0a3d1bfe5f Original-Signed-off-by: Yu-Ping Wu Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6171750 Original-Reviewed-by: Kapil Porwal Original-Reviewed-by: Subrata Banik Original-Reviewed-by: Julius Werner GitOrigin-RevId: 2e00eae8f9a0c07abad9243c564b1b7339ad9e09 Cr-Build-Id: 8725781407351328849 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8725781407351328849 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6171321 Bot-Commit: ChromeOS Prod (Robot) Commit-Queue: Jonathon Murphy Reviewed-by: Jonathon Murphy Tested-by: ChromeOS Prod (Robot) --- firmware/2lib/2misc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/firmware/2lib/2misc.c b/firmware/2lib/2misc.c index 77ff3994..ab6b3e7d 100644 --- a/firmware/2lib/2misc.c +++ b/firmware/2lib/2misc.c @@ -406,6 +406,8 @@ vb2_error_t vb2_select_fw_slot(struct vb2_context *ctx) */ sd->fw_slot = 1 - sd->fw_slot; vb2_nv_set(ctx, VB2_NV_TRY_NEXT, sd->fw_slot); + VB2_DEBUG("try_count used up; falling back to slot %s\n", + vb2_slot_string(sd->fw_slot)); } if (tries > 0) { From 16b3d5ad197d658048b5ee183bff76a494235dc4 Mon Sep 17 00:00:00 2001 From: Grzegorz Bernacki Date: Tue, 14 Jan 2025 12:13:18 +0000 Subject: [PATCH 098/102] Introduce new entry type for vbmeta Android Bringup: See http://go/android-fw-sync BUG=b:384095358 TEST=use cgpt to create new type of partition BRANCH=main (cherry picked from commit 7fdca50ac14f2358aae760d21c07adfb3285020a) Change-Id: Ic68806e3b3a85e52cd6cf5deadc69aadf2625204 Original-Signed-off-by: Grzegorz Bernacki Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6174918 Original-Reviewed-by: Julius Werner Original-Reviewed-by: Raul Rangel GitOrigin-RevId: 7fdca50ac14f2358aae760d21c07adfb3285020a Cr-Build-Id: 8725554912815068161 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8725554912815068161 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6180505 Bot-Commit: ChromeOS Prod (Robot) Tested-by: ChromeOS Prod (Robot) Commit-Queue: ChromeOS Prod (Robot) --- cgpt/cgpt.h | 3 ++- cgpt/cgpt_common.c | 7 +++++-- cgpt/cgpt_prioritize.c | 6 +++--- cgpt/cgpt_show.c | 3 ++- firmware/include/gpt.h | 2 ++ 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/cgpt/cgpt.h b/cgpt/cgpt.h index b584dc02..079c20cb 100644 --- a/cgpt/cgpt.h +++ b/cgpt/cgpt.h @@ -99,6 +99,7 @@ int Save(struct drive *drive, const uint8_t *buf, extern const Guid guid_chromeos_firmware; extern const Guid guid_chromeos_kernel; extern const Guid guid_chromeos_rootfs; +extern const Guid guid_android_vbmeta; extern const Guid guid_linux_data; extern const Guid guid_chromeos_reserved; extern const Guid guid_efi; @@ -165,7 +166,7 @@ void UpdateCrc(GptData *gpt); int IsSynonymous(const GptHeader* a, const GptHeader* b); int IsUnused(struct drive *drive, int secondary, uint32_t index); -int IsKernel(struct drive *drive, int secondary, uint32_t index); +int IsBootable(struct drive *drive, int secondary, uint32_t index); // Optional. Applications that need this must provide an implementation. // diff --git a/cgpt/cgpt_common.c b/cgpt/cgpt_common.c index b7366fc8..713d52d4 100644 --- a/cgpt/cgpt_common.c +++ b/cgpt/cgpt_common.c @@ -667,6 +667,7 @@ int UTF8ToUTF16(const uint8_t *utf8, uint16_t *utf16, unsigned int maxoutput) const Guid guid_chromeos_firmware = GPT_ENT_TYPE_CHROMEOS_FIRMWARE; const Guid guid_chromeos_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL; const Guid guid_chromeos_rootfs = GPT_ENT_TYPE_CHROMEOS_ROOTFS; +const Guid guid_android_vbmeta = GPT_ENT_TYPE_ANDROID_VBMETA; const Guid guid_basic_data = GPT_ENT_TYPE_BASIC_DATA; const Guid guid_linux_data = GPT_ENT_TYPE_LINUX_FS; const Guid guid_chromeos_reserved = GPT_ENT_TYPE_CHROMEOS_RESERVED; @@ -683,6 +684,7 @@ static const struct { {&guid_chromeos_firmware, "firmware", "ChromeOS firmware"}, {&guid_chromeos_kernel, "kernel", "ChromeOS kernel"}, {&guid_chromeos_rootfs, "rootfs", "ChromeOS rootfs"}, + {&guid_android_vbmeta, "vbmeta", "Android vbmeta"}, {&guid_linux_data, "data", "Linux data"}, {&guid_basic_data, "basicdata", "Basic data"}, {&guid_chromeos_reserved, "reserved", "ChromeOS reserved"}, @@ -875,10 +877,11 @@ int IsUnused(struct drive *drive, int secondary, uint32_t index) { return GuidIsZero(&entry->type); } -int IsKernel(struct drive *drive, int secondary, uint32_t index) { +int IsBootable(struct drive *drive, int secondary, uint32_t index) { GptEntry *entry; entry = GetEntry(&drive->gpt, secondary, index); - return GuidEqual(&entry->type, &guid_chromeos_kernel); + return (GuidEqual(&entry->type, &guid_chromeos_kernel) || + GuidEqual(&entry->type, &guid_android_vbmeta)); } diff --git a/cgpt/cgpt_prioritize.c b/cgpt/cgpt_prioritize.c index 3883be5c..d80e4bdd 100644 --- a/cgpt/cgpt_prioritize.c +++ b/cgpt/cgpt_prioritize.c @@ -133,7 +133,7 @@ int CgptPrioritize(CgptPrioritizeParams *params) { } index = params->set_partition - 1; // it must be a kernel - if (!IsKernel(&drive, PRIMARY, index)) { + if (!IsBootable(&drive, PRIMARY, index)) { Error("partition %d is not a ChromeOS kernel\n", params->set_partition); goto bad; } @@ -142,7 +142,7 @@ int CgptPrioritize(CgptPrioritizeParams *params) { // How many kernel partitions do I have? num_kernels = 0; for (i = 0; i < max_part; i++) { - if (IsKernel(&drive, PRIMARY, i)) + if (IsBootable(&drive, PRIMARY, i)) num_kernels++; } @@ -150,7 +150,7 @@ int CgptPrioritize(CgptPrioritizeParams *params) { // Determine the current priority groups groups = NewGroupList(num_kernels); for (i = 0; i < max_part; i++) { - if (!IsKernel(&drive, PRIMARY, i)) + if (!IsBootable(&drive, PRIMARY, i)) continue; priority = GetPriority(&drive, PRIMARY, i); diff --git a/cgpt/cgpt_show.c b/cgpt/cgpt_show.c index 7d481e95..fc1e3de5 100644 --- a/cgpt/cgpt_show.c +++ b/cgpt/cgpt_show.c @@ -123,7 +123,8 @@ void EntryDetails(GptEntry *entry, uint32_t index, int raw) { clen = 0; if (!raw) { - if (GuidEqual(&guid_chromeos_kernel, &entry->type)) { + if (GuidEqual(&guid_chromeos_kernel, &entry->type) || + GuidEqual(&guid_android_vbmeta, &entry->type)) { int tries = (entry->attrs.fields.gpt_att & CGPT_ATTRIBUTE_TRIES_MASK) >> CGPT_ATTRIBUTE_TRIES_OFFSET; diff --git a/firmware/include/gpt.h b/firmware/include/gpt.h index da76d259..3005852b 100644 --- a/firmware/include/gpt.h +++ b/firmware/include/gpt.h @@ -57,6 +57,8 @@ extern "C" { {{{0x09845860,0x705f,0x4bb5,0xb1,0x6c,{0x8a,0x8a,0x09,0x9c,0xaf,0x52}}}} #define GPT_ENT_TYPE_CHROMEOS_HIBERNATE \ {{{0x3f0f8318,0xf146,0x4e6b,0x82,0x22,{0xc2,0x8c,0x8f,0x02,0xe0,0xd5}}}} +#define GPT_ENT_TYPE_ANDROID_VBMETA \ + {{{0x88434509,0xd9d1,0x487d,0xb8,0x2c,{0x15,0xef,0x96,0x4c,0xbd,0x4b}}}} #define UUID_NODE_LEN 6 #define GUID_SIZE 16 From cc1cae44796e2d54e83add17587cab033cb8060d Mon Sep 17 00:00:00 2001 From: Benjamin Shai Date: Thu, 16 Jan 2025 10:30:06 -0800 Subject: [PATCH 099/102] uefi: only check for key existence in local key mode Android Bringup: See http://go/android-fw-sync When the key is a pkcs11 key, we shouldn't check for the existence of the private key on disk. BUG=b:372702794 TEST=Manual (cherry picked from commit 993ef3126919613ef9c69dfdcfda782332b6de8b) Change-Id: Icf0097c9dfd7b36a40581f19c6066f2a3c0309a8 Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6180557 Original-Tested-by: Benjamin Shai Original-Commit-Queue: Benjamin Shai Original-Reviewed-by: Madeleine Hardt Original-Reviewed-by: Nicholas Bishop GitOrigin-RevId: 993ef3126919613ef9c69dfdcfda782332b6de8b Cr-Build-Id: 8725509613852573553 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8725509613852573553 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6181146 Bot-Commit: ChromeOS Prod (Robot) Commit-Queue: Jonathon Murphy Tested-by: ChromeOS Prod (Robot) Reviewed-by: Jonathon Murphy --- scripts/image_signing/sign_uefi.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/scripts/image_signing/sign_uefi.py b/scripts/image_signing/sign_uefi.py index 6d4549fb..e387fe78 100755 --- a/scripts/image_signing/sign_uefi.py +++ b/scripts/image_signing/sign_uefi.py @@ -235,9 +235,12 @@ def sign_target_dir(target_dir: os.PathLike, keys: Keys, efi_glob: str): for efi_file in sorted(bootloader_dir.glob("crdyboot*.efi")): # This key is required to create the detached signature. - ensure_file_exists( - keys.crdyshim_private_key, "No crdyshim private key" - ) + # Only check the private keys if they are local paths rather than a + # PKCS#11 URI. + if not is_pkcs11_key_path(keys.crdyshim_private_key): + ensure_file_exists( + keys.crdyshim_private_key, "No crdyshim private key" + ) if efi_file.is_file(): inject_vbpubk(efi_file, keys) From 5a32d0f2ff30953f44cb20626b2eedcc4c83c769 Mon Sep 17 00:00:00 2001 From: Grzegorz Bernacki Date: Wed, 15 Jan 2025 12:37:18 +0000 Subject: [PATCH 100/102] vboot: modify GptNextKernelEntry function Android Bringup: See http://go/android-fw-sync The GptNextKernelEntry function returns the start & size of the boot partition. These data are required for booting ChromeOS, but to boot Android we need a partition suffix. This change modifies GptNextKernelEntry, so it returns a pointer to GptEntry now. It will allow to determine which OS is going to be booted by entry type GUID and simplify fetching data required for a given OS. BUG=b:384095358 TEST='make runtest' and verify build ChromeOS on redrix BRANCH=main (cherry picked from commit 621899d6e89f39b7e1ecb8102fe8288b41ddc06b) Change-Id: I6c3e4555db9f429cd7bcd96e29c8ab661330de55 Original-Signed-off-by: Grzegorz Bernacki Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6169943 Original-Reviewed-by: Julius Werner GitOrigin-RevId: 621899d6e89f39b7e1ecb8102fe8288b41ddc06b Cr-Build-Id: 8725509613852573553 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8725509613852573553 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6181147 Tested-by: Jonathon Murphy Reviewed-by: Aaron Massey Commit-Queue: Jonathon Murphy --- firmware/2lib/2load_kernel.c | 8 +- firmware/lib/cgptlib/cgptlib.c | 12 +-- firmware/lib/cgptlib/include/cgptlib.h | 14 ++-- tests/cgpt_fuzzer.c | 10 +-- tests/cgptlib_test.c | 104 ++++++++++++------------- tests/vb2_inject_kernel_subkey_tests.c | 43 +++++----- tests/vb2_load_kernel_tests.c | 36 +++++---- 7 files changed, 111 insertions(+), 116 deletions(-) diff --git a/firmware/2lib/2load_kernel.c b/firmware/2lib/2load_kernel.c index 68a0b1ed..ab793911 100644 --- a/firmware/2lib/2load_kernel.c +++ b/firmware/2lib/2load_kernel.c @@ -16,6 +16,7 @@ #include "2sysincludes.h" #include "cgptlib.h" #include "cgptlib_internal.h" +#include "gpt.h" #include "gpt_misc.h" #include "vboot_api.h" @@ -647,9 +648,10 @@ vb2_error_t vb2api_load_kernel(struct vb2_context *ctx, const uint64_t ctx_flags = ctx->flags; /* Loop over candidate kernel partitions */ - uint64_t part_start, part_size; - while (GptNextKernelEntry(&gpt, &part_start, &part_size) == - GPT_SUCCESS) { + GptEntry *entry; + while ((entry = GptNextKernelEntry(&gpt))) { + uint64_t part_start = entry->starting_lba; + uint64_t part_size = GptGetEntrySizeLba(entry); VB2_DEBUG("Found kernel entry at %" PRIu64 " size %" PRIu64 "\n", diff --git a/firmware/lib/cgptlib/cgptlib.c b/firmware/lib/cgptlib/cgptlib.c index c4bd6ec8..ace78289 100644 --- a/firmware/lib/cgptlib/cgptlib.c +++ b/firmware/lib/cgptlib/cgptlib.c @@ -67,7 +67,7 @@ int GptGetActiveKernelPartitionSuffix(GptData *gpt, char **suffix) return GPT_SUCCESS; } -int GptNextKernelEntry(GptData *gpt, uint64_t *start_sector, uint64_t *size) +GptEntry *GptNextKernelEntry(GptData *gpt) { GptHeader *header = (GptHeader *)gpt->primary_header; GptEntry *entries = (GptEntry *)gpt->primary_entries; @@ -96,10 +96,8 @@ int GptNextKernelEntry(GptData *gpt, uint64_t *start_sector, uint64_t *size) continue; if (GetEntryPriority(e) == gpt->current_priority) { gpt->current_kernel = i; - *start_sector = e->starting_lba; - *size = e->ending_lba - e->starting_lba + 1; VB2_DEBUG("GptNextKernelEntry likes it\n"); - return GPT_SUCCESS; + return e; } } } @@ -139,14 +137,12 @@ int GptNextKernelEntry(GptData *gpt, uint64_t *start_sector, uint64_t *size) if (CGPT_KERNEL_ENTRY_NOT_FOUND == new_kernel) { VB2_DEBUG("GptNextKernelEntry no more kernels\n"); - return GPT_ERROR_NO_VALID_KERNEL; + return NULL; } VB2_DEBUG("GptNextKernelEntry likes partition %d\n", new_kernel + 1); e = entries + new_kernel; - *start_sector = e->starting_lba; - *size = e->ending_lba - e->starting_lba + 1; - return GPT_SUCCESS; + return e; } /* diff --git a/firmware/lib/cgptlib/include/cgptlib.h b/firmware/lib/cgptlib/include/cgptlib.h index 1e3bc37c..611c5d6f 100644 --- a/firmware/lib/cgptlib/include/cgptlib.h +++ b/firmware/lib/cgptlib/include/cgptlib.h @@ -10,17 +10,15 @@ #include "gpt_misc.h" /** - * Provides the location of the next kernel partition, in order of decreasing + * Provides the location of the next bootable partition, in order of decreasing * priority. * - * On return the start_sector parameter contains the LBA sector for the start - * of the kernel partition, and the size parameter contains the size of the - * kernel partition in LBA sectors. gpt.current_kernel contains the partition - * index of the current chromeos kernel partition. + * On return gpt.current_kernel contains the partition index of the current + * bootable partition. * - * Returns GPT_SUCCESS if successful, else - * GPT_ERROR_NO_VALID_KERNEL, no avaliable kernel, enters recovery mode */ -int GptNextKernelEntry(GptData *gpt, uint64_t *start_sector, uint64_t *size); + * Returns gpt entry of partition to boot if successful, else NULL + */ +GptEntry *GptNextKernelEntry(GptData *gpt); /** * Find init_boot partition for selected slot. diff --git a/tests/cgpt_fuzzer.c b/tests/cgpt_fuzzer.c index 3d0857d0..e56e522f 100644 --- a/tests/cgpt_fuzzer.c +++ b/tests/cgpt_fuzzer.c @@ -72,11 +72,11 @@ int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { gpt.flags = params.flags; if (0 == AllocAndReadGptData(0, &gpt)) { - int result = GptInit(&gpt); - while (GPT_SUCCESS == result) { - uint64_t part_start, part_size; - result = GptNextKernelEntry(&gpt, &part_start, - &part_size); + if (GptInit(&gpt) == GPT_SUCCESS) { + GptEntry *entry = NULL; + do { + entry = GptNextKernelEntry(&gpt); + } while (entry); } } diff --git a/tests/cgptlib_test.c b/tests/cgptlib_test.c index 4c5a5cde..0f60a66b 100644 --- a/tests/cgptlib_test.c +++ b/tests/cgptlib_test.c @@ -1263,8 +1263,7 @@ static int NoValidKernelEntryTest(void) SetEntryPriority(e1 + KERNEL_A, 0); FreeEntry(e1 + KERNEL_B); RefreshCrc32(gpt); - EXPECT(GPT_ERROR_NO_VALID_KERNEL == - GptNextKernelEntry(gpt, NULL, NULL)); + EXPECT(NULL == GptNextKernelEntry(gpt)); return TEST_OK; } @@ -1273,7 +1272,7 @@ static int GetNextNormalTest(void) { GptData *gpt = GetEmptyGptData(); GptEntry *e1 = (GptEntry *)(gpt->primary_entries); - uint64_t start, size; + GptEntry *entry; /* Normal case - both kernels successful */ BuildTestGptData(gpt); @@ -1282,23 +1281,23 @@ static int GetNextNormalTest(void) RefreshCrc32(gpt); GptInit(gpt); - EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size)); + entry = GptNextKernelEntry(gpt); + EXPECT(entry); EXPECT(KERNEL_A == gpt->current_kernel); - EXPECT(34 == start); - EXPECT(100 == size); + EXPECT(34 == entry->starting_lba); + EXPECT(100 == GptGetEntrySizeLba(entry)); - EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size)); + entry = GptNextKernelEntry(gpt); + EXPECT(entry); EXPECT(KERNEL_B == gpt->current_kernel); - EXPECT(134 == start); - EXPECT(99 == size); + EXPECT(134 == entry->starting_lba); + EXPECT(99 == GptGetEntrySizeLba(entry)); - EXPECT(GPT_ERROR_NO_VALID_KERNEL == - GptNextKernelEntry(gpt, &start, &size)); + EXPECT(NULL == GptNextKernelEntry(gpt)); EXPECT(-1 == gpt->current_kernel); /* Call as many times as you want; you won't get another kernel... */ - EXPECT(GPT_ERROR_NO_VALID_KERNEL == - GptNextKernelEntry(gpt, &start, &size)); + EXPECT(NULL == GptNextKernelEntry(gpt)); EXPECT(-1 == gpt->current_kernel); return TEST_OK; @@ -1308,7 +1307,6 @@ static int GetNextPrioTest(void) { GptData *gpt = GetEmptyGptData(); GptEntry *e1 = (GptEntry *)(gpt->primary_entries); - uint64_t start, size; /* Priority 3, 4, 0, 4 - should boot order B, Y, A */ BuildTestGptData(gpt); @@ -1319,14 +1317,13 @@ static int GetNextPrioTest(void) RefreshCrc32(gpt); GptInit(gpt); - EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size)); + EXPECT(GptNextKernelEntry(gpt)); EXPECT(KERNEL_B == gpt->current_kernel); - EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size)); + EXPECT(GptNextKernelEntry(gpt)); EXPECT(KERNEL_Y == gpt->current_kernel); - EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size)); + EXPECT(GptNextKernelEntry(gpt)); EXPECT(KERNEL_A == gpt->current_kernel); - EXPECT(GPT_ERROR_NO_VALID_KERNEL == - GptNextKernelEntry(gpt, &start, &size)); + EXPECT(NULL == GptNextKernelEntry(gpt)); return TEST_OK; } @@ -1335,7 +1332,6 @@ static int GetNextTriesTest(void) { GptData *gpt = GetEmptyGptData(); GptEntry *e1 = (GptEntry *)(gpt->primary_entries); - uint64_t start, size; /* Tries=nonzero is attempted just like success, but tries=0 isn't */ BuildTestGptData(gpt); @@ -1346,12 +1342,11 @@ static int GetNextTriesTest(void) RefreshCrc32(gpt); GptInit(gpt); - EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size)); + EXPECT(GptNextKernelEntry(gpt)); EXPECT(KERNEL_X == gpt->current_kernel); - EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size)); + EXPECT(GptNextKernelEntry(gpt)); EXPECT(KERNEL_A == gpt->current_kernel); - EXPECT(GPT_ERROR_NO_VALID_KERNEL == - GptNextKernelEntry(gpt, &start, &size)); + EXPECT(NULL == GptNextKernelEntry(gpt)); return TEST_OK; } @@ -1361,7 +1356,7 @@ static int GptUpdateTest(void) GptData *gpt = GetEmptyGptData(); GptEntry *e = (GptEntry *)(gpt->primary_entries); GptEntry *e2 = (GptEntry *)(gpt->secondary_entries); - uint64_t start, size; + GptEntry *boot; /* Tries=nonzero is attempted just like success, but tries=0 isn't */ BuildTestGptData(gpt); @@ -1373,38 +1368,42 @@ static int GptUpdateTest(void) gpt->modified = 0; /* Nothing modified yet */ /* Successful kernel */ - EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size)); + boot = GptNextKernelEntry(gpt); + EXPECT(NULL != boot); EXPECT(KERNEL_A == gpt->current_kernel); - EXPECT(1 == GetEntrySuccessful(e + KERNEL_A)); - EXPECT(4 == GetEntryPriority(e + KERNEL_A)); - EXPECT(0 == GetEntryTries(e + KERNEL_A)); + EXPECT(1 == GetEntrySuccessful(boot)); + EXPECT(4 == GetEntryPriority(boot)); + EXPECT(0 == GetEntryTries(boot)); + /* Check secondary entries */ EXPECT(1 == GetEntrySuccessful(e2 + KERNEL_A)); EXPECT(4 == GetEntryPriority(e2 + KERNEL_A)); EXPECT(0 == GetEntryTries(e2 + KERNEL_A)); + /* Trying successful kernel changes nothing */ EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY)); - EXPECT(1 == GetEntrySuccessful(e + KERNEL_A)); - EXPECT(4 == GetEntryPriority(e + KERNEL_A)); - EXPECT(0 == GetEntryTries(e + KERNEL_A)); + EXPECT(1 == GetEntrySuccessful(boot)); + EXPECT(4 == GetEntryPriority(boot)); + EXPECT(0 == GetEntryTries(boot)); EXPECT(0 == gpt->modified); /* Marking it bad also does not update it. */ EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_BAD)); - EXPECT(1 == GetEntrySuccessful(e + KERNEL_A)); - EXPECT(4 == GetEntryPriority(e + KERNEL_A)); - EXPECT(0 == GetEntryTries(e + KERNEL_A)); + EXPECT(1 == GetEntrySuccessful(boot + KERNEL_A)); + EXPECT(4 == GetEntryPriority(boot + KERNEL_A)); + EXPECT(0 == GetEntryTries(boot + KERNEL_A)); EXPECT(0 == gpt->modified); /* Kernel with tries */ - EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size)); + boot = GptNextKernelEntry(gpt); + EXPECT(NULL != boot); EXPECT(KERNEL_B == gpt->current_kernel); - EXPECT(0 == GetEntrySuccessful(e + KERNEL_B)); - EXPECT(3 == GetEntryPriority(e + KERNEL_B)); - EXPECT(2 == GetEntryTries(e + KERNEL_B)); + EXPECT(0 == GetEntrySuccessful(boot)); + EXPECT(3 == GetEntryPriority(boot)); + EXPECT(2 == GetEntryTries(boot)); /* Marking it bad clears it */ EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_BAD)); - EXPECT(0 == GetEntrySuccessful(e + KERNEL_B)); - EXPECT(0 == GetEntryPriority(e + KERNEL_B)); - EXPECT(0 == GetEntryTries(e + KERNEL_B)); + EXPECT(0 == GetEntrySuccessful(boot)); + EXPECT(0 == GetEntryPriority(boot)); + EXPECT(0 == GetEntryTries(boot)); /* Which affects both copies of the partition entries */ EXPECT(0 == GetEntrySuccessful(e2 + KERNEL_B)); EXPECT(0 == GetEntryPriority(e2 + KERNEL_B)); @@ -1413,24 +1412,25 @@ static int GptUpdateTest(void) EXPECT(0x0F == gpt->modified); /* Another kernel with tries */ - EXPECT(GPT_SUCCESS == GptNextKernelEntry(gpt, &start, &size)); + boot = GptNextKernelEntry(gpt); + EXPECT(NULL != boot); EXPECT(KERNEL_X == gpt->current_kernel); - EXPECT(0 == GetEntrySuccessful(e + KERNEL_X)); - EXPECT(2 == GetEntryPriority(e + KERNEL_X)); - EXPECT(2 == GetEntryTries(e + KERNEL_X)); + EXPECT(0 == GetEntrySuccessful(boot)); + EXPECT(2 == GetEntryPriority(boot)); + EXPECT(2 == GetEntryTries(boot)); /* Trying it uses up a try */ EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY)); - EXPECT(0 == GetEntrySuccessful(e + KERNEL_X)); - EXPECT(2 == GetEntryPriority(e + KERNEL_X)); - EXPECT(1 == GetEntryTries(e + KERNEL_X)); + EXPECT(0 == GetEntrySuccessful(boot)); + EXPECT(2 == GetEntryPriority(boot)); + EXPECT(1 == GetEntryTries(boot)); EXPECT(0 == GetEntrySuccessful(e2 + KERNEL_X)); EXPECT(2 == GetEntryPriority(e2 + KERNEL_X)); EXPECT(1 == GetEntryTries(e2 + KERNEL_X)); /* Trying it again marks it inactive */ EXPECT(GPT_SUCCESS == GptUpdateKernelEntry(gpt, GPT_UPDATE_ENTRY_TRY)); - EXPECT(0 == GetEntrySuccessful(e + KERNEL_X)); - EXPECT(0 == GetEntryPriority(e + KERNEL_X)); - EXPECT(0 == GetEntryTries(e + KERNEL_X)); + EXPECT(0 == GetEntrySuccessful(boot)); + EXPECT(0 == GetEntryPriority(boot)); + EXPECT(0 == GetEntryTries(boot)); /* Can't update if entry isn't a kernel, or there isn't an entry */ memcpy(&e[KERNEL_X].type, &guid_rootfs, sizeof(guid_rootfs)); diff --git a/tests/vb2_inject_kernel_subkey_tests.c b/tests/vb2_inject_kernel_subkey_tests.c index c975dc26..98f19b3c 100644 --- a/tests/vb2_inject_kernel_subkey_tests.c +++ b/tests/vb2_inject_kernel_subkey_tests.c @@ -17,15 +17,9 @@ #include "gpt.h" #include "vboot_api.h" -/* Mock kernel partition */ -struct mock_part { - uint32_t start; - uint32_t size; -}; - /* Partition list; ends with a 0-size partition. */ #define MOCK_PART_COUNT 8 -static struct mock_part mock_parts[MOCK_PART_COUNT]; +static GptEntry mock_parts[MOCK_PART_COUNT]; static int mock_part_next; /* Mock data */ @@ -86,8 +80,8 @@ static void ResetMocks(void) kph.bootloader_size = 0x1234; memset(mock_parts, 0, sizeof(mock_parts)); - mock_parts[0].start = 100; - mock_parts[0].size = 150; /* 75 KB */ + mock_parts[0].starting_lba = 100; + mock_parts[0].ending_lba = 249; /* 75 KB */ mock_part_next = 0; memset(&kernel_packed_key_data, 0, sizeof(kernel_packed_key_data)); @@ -114,6 +108,11 @@ vb2_error_t VbExDiskRead(vb2ex_disk_handle_t h, uint64_t lba_start, return VB2_SUCCESS; } +uint64_t GptGetEntrySizeLba(const GptEntry *e) +{ + return (e->ending_lba - e->starting_lba + 1); +} + int AllocAndReadGptData(vb2ex_disk_handle_t disk_handle, GptData *gptdata) { return GPT_SUCCESS; @@ -124,21 +123,19 @@ int GptInit(GptData *gpt) return GPT_SUCCESS; } -int GptNextKernelEntry(GptData *gpt, uint64_t *start_sector, uint64_t *size) +GptEntry *GptNextKernelEntry(GptData *gpt) { - struct mock_part *p = mock_parts + mock_part_next; + GptEntry *e = mock_parts + mock_part_next; - if (!p->size) - return GPT_ERROR_NO_VALID_KERNEL; + if (!e->ending_lba) + return NULL; if (gpt->flags & GPT_FLAG_EXTERNAL) gpt_flag_external++; gpt->current_kernel = mock_part_next; - *start_sector = p->start; - *size = p->size; mock_part_next++; - return GPT_SUCCESS; + return e; } int GptUpdateKernelEntry(GptData *gpt, uint32_t update_type) @@ -262,20 +259,20 @@ static void load_kernel_tests(void) search stops at the first valid partition. */ kbh.data_key.key_version = 0; kph.kernel_version = 0; - mock_parts[1].start = 300; - mock_parts[1].size = 150; + mock_parts[1].starting_lba = 300; + mock_parts[1].ending_lba = 449; test_load_kernel(VB2_SUCCESS, "Two good kernels"); TEST_EQ(lkp.partition_number, 1, " part num"); TEST_EQ(mock_part_next, 1, " didn't read second one"); /* Fail if no kernels found */ ResetMocks(); - mock_parts[0].size = 0; + mock_parts[0].ending_lba = 0; test_load_kernel(VB2_ERROR_LK_NO_KERNEL_FOUND, "No kernels"); /* Skip kernels which are too small */ ResetMocks(); - mock_parts[0].size = 10; + mock_parts[0].ending_lba = 109; test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, "Too small"); ResetMocks(); @@ -322,8 +319,8 @@ static void load_kernel_tests(void) ResetMocks(); kbh.data_key.key_version = 3; - mock_parts[1].start = 300; - mock_parts[1].size = 150; + mock_parts[1].starting_lba = 300; + mock_parts[1].ending_lba = 449; test_load_kernel(VB2_SUCCESS, "Two kernels roll forward"); TEST_EQ(mock_part_next, 2, " read both"); TEST_EQ(sd->kernel_version, 0x30001, " SD version"); @@ -361,7 +358,7 @@ static void load_kernel_tests(void) "Kernel too big for buffer"); ResetMocks(); - mock_parts[0].size = 130; + mock_parts[0].ending_lba = 229; test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, "Kernel too big for partition"); diff --git a/tests/vb2_load_kernel_tests.c b/tests/vb2_load_kernel_tests.c index f755c269..9368e67e 100644 --- a/tests/vb2_load_kernel_tests.c +++ b/tests/vb2_load_kernel_tests.c @@ -20,8 +20,7 @@ /* Mock kernel partition */ struct mock_part { - uint32_t start; - uint32_t size; + GptEntry e; struct vb2_keyblock kbh; }; @@ -84,8 +83,8 @@ static void ResetMocks(void) disk_info.handle = (vb2ex_disk_handle_t)1; memset(mock_parts, 0, sizeof(mock_parts)); - mock_parts[0].start = 100; - mock_parts[0].size = 150; /* 75 KB */ + mock_parts[0].e.starting_lba = 100; + mock_parts[0].e.ending_lba = 249; /* 75 KB */ mock_parts[0].kbh = (struct vb2_keyblock){ .data_key.key_version = 2, .keyblock_flags = -1, @@ -175,12 +174,17 @@ int GptInit(GptData *gpt) return gpt_init_fail; } -int GptNextKernelEntry(GptData *gpt, uint64_t *start_sector, uint64_t *size) +uint64_t GptGetEntrySizeLba(const GptEntry *e) +{ + return (e->ending_lba - e->starting_lba + 1); +} + +GptEntry *GptNextKernelEntry(GptData *gpt) { struct mock_part *p = mock_parts + mock_part_next; - if (!p->size) - return GPT_ERROR_NO_VALID_KERNEL; + if (!p->e.ending_lba) + return NULL; if (gpt->flags & GPT_FLAG_EXTERNAL) gpt_flag_external++; @@ -188,10 +192,8 @@ int GptNextKernelEntry(GptData *gpt, uint64_t *start_sector, uint64_t *size) memcpy(&cur_kbh, &mock_parts[mock_part_next].kbh, sizeof(cur_kbh)); gpt->current_kernel = mock_part_next; - *start_sector = p->start; - *size = p->size; mock_part_next++; - return GPT_SUCCESS; + return &p->e; } int GptUpdateKernelEntry(GptData *gpt, uint32_t update_type) @@ -333,20 +335,20 @@ static void load_kernel_tests(void) ResetMocks(); memcpy(&mock_parts[1].kbh, &mock_parts[0].kbh, sizeof(mock_parts[0].kbh)); - mock_parts[1].start = 300; - mock_parts[1].size = 150; + mock_parts[1].e.starting_lba = 300; + mock_parts[1].e.ending_lba = 449; test_load_kernel(VB2_SUCCESS, "Two good kernels"); TEST_EQ(lkp.partition_number, 1, " part num"); TEST_EQ(mock_part_next, 1, " didn't read second one"); /* Fail if no kernels found */ ResetMocks(); - mock_parts[0].size = 0; + mock_parts[0].e.ending_lba = 0; test_load_kernel(VB2_ERROR_LK_NO_KERNEL_FOUND, "No kernels"); /* Skip kernels which are too small */ ResetMocks(); - mock_parts[0].size = 10; + mock_parts[0].e.ending_lba = 109; test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, "Too small"); ResetMocks(); @@ -504,8 +506,8 @@ static void load_kernel_tests(void) memcpy(&mock_parts[1].kbh, &mock_parts[0].kbh, sizeof(mock_parts[0].kbh)); mock_parts[0].kbh.data_key.key_version = 4; - mock_parts[1].start = 300; - mock_parts[1].size = 150; + mock_parts[1].e.starting_lba = 300; + mock_parts[1].e.ending_lba = 449; mock_parts[1].kbh.data_key.key_version = 3; test_load_kernel(VB2_SUCCESS, "Two kernels roll forward"); TEST_EQ(mock_part_next, 2, " read both"); @@ -615,7 +617,7 @@ static void load_kernel_tests(void) "Kernel too big for buffer"); ResetMocks(); - mock_parts[0].size = 130; + mock_parts[0].e.ending_lba = 229; test_load_kernel(VB2_ERROR_LK_INVALID_KERNEL_FOUND, "Kernel too big for partition"); From 026b0489ae843ac2cd38faa495f830c34ec540dc Mon Sep 17 00:00:00 2001 From: Raul E Rangel Date: Fri, 24 Jan 2025 10:16:39 -0700 Subject: [PATCH 101/102] Makefile: Remove $(shell) invocations from CFLAGS Android Bringup: See http://go/android-fw-sync CFLAGS is a recursive variable, meaning it needs to be re-evaluated every time it is referenced. By adding a `$(shell)` into CFLAGS we force `make` to invoke the shell commands every single time. This results in a lot of unnecessary pkg-config calls. I straced the process to confirm the fix: Before: ``` $ grep pkg-config /tmp/coreboot.strace| wc -l 102973 ``` After: ``` $ grep pkg-config /tmp/coreboot.fast.strace| wc -l 3937 ``` This shaves off ~30 - 60 seconds on my machine when building brya. BUG=b:392102378 BRANCH=none TEST=emerge-brya coreboot (cherry picked from commit 177c0582ad4fcc8455c2f88d734d9d5907224380) Change-Id: Ib23f1821e64f491e1a7929a8d6812c23f6ec85ad Original-Signed-off-by: Raul E Rangel Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6198687 Original-Reviewed-by: Julius Werner Original-Commit-Queue: Julius Werner GitOrigin-RevId: 177c0582ad4fcc8455c2f88d734d9d5907224380 Cr-Build-Id: 8724784839770938193 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8724784839770938193 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6199951 Tested-by: ChromeOS Prod (Robot) Commit-Queue: ChromeOS Prod (Robot) Bot-Commit: ChromeOS Prod (Robot) --- Makefile | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index ae65c9a1..751624bc 100644 --- a/Makefile +++ b/Makefile @@ -284,26 +284,30 @@ endif LIBZIP_VERSION := $(shell ${PKG_CONFIG} --modversion libzip 2>/dev/null) HAVE_LIBZIP := $(if ${LIBZIP_VERSION},1) ifneq ($(filter-out 0,${HAVE_LIBZIP}),) - CFLAGS += -DHAVE_LIBZIP $(shell ${PKG_CONFIG} --cflags libzip) + LIBZIP_CFLAGS := $(shell ${PKG_CONFIG} --cflags libzip) + CFLAGS += -DHAVE_LIBZIP $(LIBZIP_CFLAGS) LIBZIP_LIBS := $(shell ${PKG_CONFIG} --libs libzip) endif LIBARCHIVE_VERSION := $(shell ${PKG_CONFIG} --modversion libarchive 2>/dev/null) HAVE_LIBARCHIVE := $(if ${LIBARCHIVE_VERSION},1) ifneq ($(filter-out 0,${HAVE_LIBARCHIVE}),) - CFLAGS += -DHAVE_LIBARCHIVE $(shell ${PKG_CONFIG} --cflags libarchive) + LIBARCHIVE_CFLAGS := $(shell ${PKG_CONFIG} --cflags libarchive) + CFLAGS += -DHAVE_LIBARCHIVE $(LIBARCHIVE_CFLAGS) LIBARCHIVE_LIBS := $(shell ${PKG_CONFIG} --libs libarchive) endif HAVE_CROSID := $(shell ${PKG_CONFIG} --exists crosid && echo 1) ifeq ($(HAVE_CROSID),1) - CFLAGS += -DHAVE_CROSID $(shell ${PKG_CONFIG} --cflags crosid) + CROSID_CFLAGS := $(shell ${PKG_CONFIG} --cflags crosid) + CFLAGS += -DHAVE_CROSID $(CROSID_CFLAGS) CROSID_LIBS := $(shell ${PKG_CONFIG} --libs crosid) endif HAVE_NSS := $(shell ${PKG_CONFIG} --exists nss && echo 1) ifeq ($(HAVE_NSS),1) - CFLAGS += -DHAVE_NSS $(shell ${PKG_CONFIG} --cflags nss) + NSS_CFLAGS := $(shell ${PKG_CONFIG} --cflags nss) + CFLAGS += -DHAVE_NSS $(NSS_CFLAGS) # The LIBS is not needed because we only use the header. else $(warning Missing NSS. PKCS11 signing not supported. Install libnss3 to enable this feature.) From 7f7806a5dc5d68b43a481c89774f5580a2d04134 Mon Sep 17 00:00:00 2001 From: Raul E Rangel Date: Fri, 24 Jan 2025 10:30:22 -0700 Subject: [PATCH 102/102] Makefile: Optimize dirname invocation Android Bringup: See http://go/android-fw-sync Invoking `dirname` for every single source file is slow. This change switches to the `-exec dirname {} +` variant that passes multiple args to `dirname`. With this change I no longer see `dirname` in `top` when watching a build. BUG=b:392102378 BRANCH=none TEST=emerge-brya coreboot (cherry picked from commit 6f63b28162cd90215c8639aae6eb61a9d93394aa) Change-Id: I786b91df9516c70b34ff534c4144e228104bea2d Original-Signed-off-by: Raul E Rangel Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6198688 Original-Reviewed-by: Julius Werner Original-Commit-Queue: Julius Werner GitOrigin-RevId: 6f63b28162cd90215c8639aae6eb61a9d93394aa Cr-Build-Id: 8724784839770938193 Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8724784839770938193 Copybot-Job-Name: android-main-vboot_reference-copybot-downstream Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/6199952 Commit-Queue: ChromeOS Prod (Robot) Tested-by: ChromeOS Prod (Robot) Bot-Commit: ChromeOS Prod (Robot) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 751624bc..5f66b87e 100644 --- a/Makefile +++ b/Makefile @@ -917,7 +917,7 @@ FUZZ_TEST_BINS = $(addprefix ${BUILD}/,${FUZZ_TEST_NAMES}) # so it happens before trying to generate/include dependencies. SUBDIRS := firmware host cgpt utility futility tests tests/tpm_lite _dir_create := $(foreach d, \ - $(shell find ${SUBDIRS} -name '*.c' -exec dirname {} \; | sort -u), \ + $(shell find ${SUBDIRS} -name '*.c' -exec dirname {} + | sort -u), \ $(shell [ -d ${BUILD}/${d} ] || mkdir -p ${BUILD}/${d})) .PHONY: clean