cbfstool: MediaTek: Hash bootblock.bin for CBFS_VERIFICATION
MediaTek's bootROM expects a SHA256 of the bootblock data at the end of bootblock.bin (see util/mtkheader/gen-bl-img.py). To support CBFS verification (CONFIG_CBFS_VERIFICATION) on MediaTek platforms, we need to re-generate the hash whenever a file is added to or removed from CBFS. BUG=b:229670703 TEST=sudo emerge coreboot-utils TEST=emerge-corsola coreboot chromeos-bootimage TEST=Kingler booted with CONFIG_CBFS_VERIFICATION=y Change-Id: Iaf5900df605899af699b25266e87b5d557c4e830 Signed-off-by: Yu-Ping Wu <yupingso@chromium.org> Reviewed-on: https://review.coreboot.org/c/coreboot/+/63925 Reviewed-by: Arthur Heymans <arthur@aheymans.xyz> Reviewed-by: Julius Werner <jwerner@chromium.org> Reviewed-by: Paul Menzel <paulepanter@mailbox.org> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
parent
198cc26e49
commit
f1a8dde147
|
@ -1,5 +1,8 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
|
|
||||||
|
#include <commonlib/endian.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "cbfs.h"
|
#include "cbfs.h"
|
||||||
#include "cbfs_sections.h"
|
#include "cbfs_sections.h"
|
||||||
#include "elfparsing.h"
|
#include "elfparsing.h"
|
||||||
|
@ -105,12 +108,105 @@ static int qualcomm_fixup(struct buffer *buffer, size_t offset)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MediaTek bootblock.bin layout (see util/mtkheader/gen-bl-img.py):
|
||||||
|
* header 2048 bytes
|
||||||
|
* gfh info 176 bytes, where bytes 32-35 (in little endian) is the
|
||||||
|
* total size excluding the header (gfh info + data + hash)
|
||||||
|
* data `data_size` bytes
|
||||||
|
* hash 32 bytes, SHA256 of "gfh info + data"
|
||||||
|
* padding
|
||||||
|
*/
|
||||||
|
#define MEDIATEK_BOOTBLOCK_HEADER_SIZE 2048
|
||||||
|
#define MEDIATEK_BOOTBLOCK_GFH_SIZE 176
|
||||||
|
static void *mediatek_find_hash(struct buffer *bootblock, struct vb2_hash *real_hash)
|
||||||
|
{
|
||||||
|
struct buffer buffer;
|
||||||
|
size_t data_size;
|
||||||
|
const char emmc_magic[] = "EMMC_BOOT";
|
||||||
|
const char sf_magic[] = "SF_BOOT";
|
||||||
|
const char brlyt_magic[] = "BRLYT";
|
||||||
|
const size_t brlyt_offset = 512;
|
||||||
|
|
||||||
|
buffer_clone(&buffer, bootblock);
|
||||||
|
|
||||||
|
/* Doesn't seem to be MediaTek image */
|
||||||
|
if (buffer_size(&buffer) <
|
||||||
|
MEDIATEK_BOOTBLOCK_HEADER_SIZE + MEDIATEK_BOOTBLOCK_GFH_SIZE)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Check header magic */
|
||||||
|
if (!buffer_check_magic(&buffer, emmc_magic, strlen(emmc_magic)) &&
|
||||||
|
!buffer_check_magic(&buffer, sf_magic, strlen(sf_magic)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Check "BRLYT" */
|
||||||
|
buffer_seek(&buffer, brlyt_offset);
|
||||||
|
if (!buffer_check_magic(&buffer, brlyt_magic, strlen(brlyt_magic)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
buffer_seek(&buffer, MEDIATEK_BOOTBLOCK_HEADER_SIZE - brlyt_offset);
|
||||||
|
data_size = read_le32(buffer_get(&buffer) + 32);
|
||||||
|
if (data_size <= MEDIATEK_BOOTBLOCK_GFH_SIZE + VB2_SHA256_DIGEST_SIZE) {
|
||||||
|
ERROR("fixups: MediaTek: data size too small: %zu\n", data_size);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
data_size -= MEDIATEK_BOOTBLOCK_GFH_SIZE + VB2_SHA256_DIGEST_SIZE;
|
||||||
|
|
||||||
|
if (buffer_size(&buffer) <
|
||||||
|
MEDIATEK_BOOTBLOCK_GFH_SIZE + data_size + VB2_SHA256_DIGEST_SIZE) {
|
||||||
|
ERROR("fixups: MediaTek: not enough data: %zu\n", buffer_size(&buffer));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vb2_hash_calculate(buffer_get(&buffer),
|
||||||
|
MEDIATEK_BOOTBLOCK_GFH_SIZE + data_size,
|
||||||
|
VB2_HASH_SHA256, real_hash)) {
|
||||||
|
ERROR("fixups: MediaTek: vboot digest error\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer_seek(&buffer, MEDIATEK_BOOTBLOCK_GFH_SIZE + data_size);
|
||||||
|
return buffer_get(&buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool mediatek_probe(struct buffer *buffer)
|
||||||
|
{
|
||||||
|
struct vb2_hash real_hash;
|
||||||
|
void *hash = mediatek_find_hash(buffer, &real_hash);
|
||||||
|
if (!hash)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (memcmp(real_hash.raw, hash, VB2_SHA256_DIGEST_SIZE)) {
|
||||||
|
ERROR("fixups: Found MediaTek bootblock, but existing hash doesn't match!\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mediatek_fixup(struct buffer *buffer, unused size_t offset)
|
||||||
|
{
|
||||||
|
struct vb2_hash real_hash;
|
||||||
|
void *hash = mediatek_find_hash(buffer, &real_hash);
|
||||||
|
if (!hash) {
|
||||||
|
ERROR("fixups: Cannot find MediaTek header anymore!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(hash, real_hash.raw, VB2_SHA256_DIGEST_SIZE);
|
||||||
|
INFO("fixups: Updated MediaTek bootblock hash.\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
platform_fixup_func platform_fixups_probe(struct buffer *buffer, size_t offset,
|
platform_fixup_func platform_fixups_probe(struct buffer *buffer, size_t offset,
|
||||||
const char *region_name)
|
const char *region_name)
|
||||||
{
|
{
|
||||||
if (!strcmp(region_name, SECTION_NAME_BOOTBLOCK)) {
|
if (!strcmp(region_name, SECTION_NAME_BOOTBLOCK)) {
|
||||||
if (qualcomm_probe(buffer, offset))
|
if (qualcomm_probe(buffer, offset))
|
||||||
return qualcomm_fixup;
|
return qualcomm_fixup;
|
||||||
|
else if (mediatek_probe(buffer))
|
||||||
|
return mediatek_fixup;
|
||||||
} else if (!strcmp(region_name, SECTION_NAME_PRIMARY_CBFS)) {
|
} else if (!strcmp(region_name, SECTION_NAME_PRIMARY_CBFS)) {
|
||||||
/* TODO: add fixups for primary CBFS bootblock platforms, if needed */
|
/* TODO: add fixups for primary CBFS bootblock platforms, if needed */
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue