/* Copyright 2019 The Chromium OS Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * * Tests for firmware management parameters (FWMP) library. */ #include "2common.h" #include "2misc.h" #include "2secdata.h" #include "2secdata_struct.h" #include "test_common.h" static uint8_t workbuf[VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE] __attribute__((aligned(VB2_WORKBUF_ALIGN))); static struct vb2_context *ctx; static struct vb2_gbb_header gbb; static struct vb2_shared_data *sd; static struct vb2_secdata_fwmp *sec; static void reset_common_data(void) { memset(workbuf, 0xaa, sizeof(workbuf)); TEST_SUCC(vb2api_init(workbuf, sizeof(workbuf), &ctx), "vb2api_init failed"); sd = vb2_get_sd(ctx); sd->status = VB2_SD_STATUS_SECDATA_FWMP_INIT; memset(&gbb, 0, sizeof(gbb)); sec = (struct vb2_secdata_fwmp *)ctx->secdata_fwmp; sec->struct_size = VB2_SECDATA_FWMP_MIN_SIZE; sec->struct_version = VB2_SECDATA_FWMP_VERSION; sec->flags = 0; sec->crc8 = vb2_secdata_fwmp_crc(sec); } /* Mocked functions */ struct vb2_gbb_header *vb2_get_gbb(struct vb2_context *c) { return &gbb; } static void check_init_test(void) { uint8_t size; /* Check size constants */ TEST_TRUE(sizeof(struct vb2_secdata_fwmp) >= VB2_SECDATA_FWMP_MIN_SIZE, "Struct min size constant"); TEST_TRUE(sizeof(struct vb2_secdata_fwmp) <= VB2_SECDATA_FWMP_MAX_SIZE, "Struct max size constant"); /* struct_size too large */ reset_common_data(); sec->struct_size = VB2_SECDATA_FWMP_MAX_SIZE + 1; sec->crc8 = vb2_secdata_fwmp_crc(sec); size = sec->struct_size; TEST_EQ(vb2api_secdata_fwmp_check(ctx, &size), VB2_ERROR_SECDATA_FWMP_SIZE, "Check struct_size too large"); TEST_EQ(vb2_secdata_fwmp_init(ctx), VB2_ERROR_SECDATA_FWMP_SIZE, "Init struct_size too large"); /* struct_size too small */ reset_common_data(); sec->struct_size = VB2_SECDATA_FWMP_MIN_SIZE - 1; sec->crc8 = vb2_secdata_fwmp_crc(sec); size = VB2_SECDATA_FWMP_MIN_SIZE; TEST_EQ(vb2api_secdata_fwmp_check(ctx, &size), VB2_ERROR_SECDATA_FWMP_SIZE, "Check struct_size too small"); /* Need more data to reach minimum size */ reset_common_data(); sec->struct_size = VB2_SECDATA_FWMP_MIN_SIZE - 1; sec->crc8 = vb2_secdata_fwmp_crc(sec); size = 0; TEST_EQ(vb2api_secdata_fwmp_check(ctx, &size), VB2_ERROR_SECDATA_FWMP_INCOMPLETE, "Check more to reach MIN"); TEST_EQ(vb2_secdata_fwmp_init(ctx), VB2_ERROR_SECDATA_FWMP_INCOMPLETE, "Init more to reach MIN"); /* Need more data to reach full size */ reset_common_data(); sec->struct_size = VB2_SECDATA_FWMP_MIN_SIZE + 1; sec->crc8 = vb2_secdata_fwmp_crc(sec); size = VB2_SECDATA_FWMP_MIN_SIZE; TEST_EQ(vb2api_secdata_fwmp_check(ctx, &size), VB2_ERROR_SECDATA_FWMP_INCOMPLETE, "Check more for full size"); /* Bad data is invalid */ reset_common_data(); memset(&ctx->secdata_fwmp, 0xa6, sizeof(ctx->secdata_fwmp)); sec->struct_size = VB2_SECDATA_FWMP_MIN_SIZE; size = sec->struct_size; TEST_EQ(vb2api_secdata_fwmp_check(ctx, &size), VB2_ERROR_SECDATA_FWMP_CRC, "Check bad data CRC"); TEST_EQ(vb2_secdata_fwmp_init(ctx), VB2_ERROR_SECDATA_FWMP_CRC, "Init bad data CRC"); /* Bad CRC with corruption past minimum size */ reset_common_data(); sec->struct_size = VB2_SECDATA_FWMP_MIN_SIZE + 1; sec->crc8 = vb2_secdata_fwmp_crc(sec); size = sec->struct_size; *((uint8_t *)sec + sec->struct_size - 1) += 1; TEST_EQ(vb2api_secdata_fwmp_check(ctx, &size), VB2_ERROR_SECDATA_FWMP_CRC, "Check corruption CRC"); TEST_EQ(vb2_secdata_fwmp_init(ctx), VB2_ERROR_SECDATA_FWMP_CRC, "Init corruption CRC"); /* Zeroed data is invalid */ reset_common_data(); memset(&ctx->secdata_fwmp, 0, sizeof(ctx->secdata_fwmp)); sec->struct_size = VB2_SECDATA_FWMP_MIN_SIZE; size = sec->struct_size; TEST_EQ(vb2api_secdata_fwmp_check(ctx, &size), VB2_ERROR_SECDATA_FWMP_VERSION, "Check zeroed data CRC"); TEST_EQ(vb2_secdata_fwmp_init(ctx), VB2_ERROR_SECDATA_FWMP_VERSION, "Init zeroed data CRC"); /* Major version too high */ reset_common_data(); sec->struct_version = ((VB2_SECDATA_FWMP_VERSION >> 4) + 1) << 4; sec->crc8 = vb2_secdata_fwmp_crc(sec); TEST_EQ(vb2api_secdata_fwmp_check(ctx, &size), VB2_ERROR_SECDATA_FWMP_VERSION, "Check major too high"); TEST_EQ(vb2_secdata_fwmp_init(ctx), VB2_ERROR_SECDATA_FWMP_VERSION, "Init major too high"); /* Major version too low */ reset_common_data(); sec->struct_version = ((VB2_SECDATA_FWMP_VERSION >> 4) - 1) << 4; sec->crc8 = vb2_secdata_fwmp_crc(sec); TEST_EQ(vb2api_secdata_fwmp_check(ctx, &size), VB2_ERROR_SECDATA_FWMP_VERSION, "Check major too low"); TEST_EQ(vb2_secdata_fwmp_init(ctx), VB2_ERROR_SECDATA_FWMP_VERSION, "Init major too low"); /* Minor version difference okay */ reset_common_data(); sec->struct_version += 1; sec->crc8 = vb2_secdata_fwmp_crc(sec); TEST_SUCC(vb2api_secdata_fwmp_check(ctx, &size), "Check minor okay"); TEST_SUCC(vb2_secdata_fwmp_init(ctx), "Init minor okay"); /* Good FWMP data at minimum size */ reset_common_data(); TEST_SUCC(vb2api_secdata_fwmp_check(ctx, &size), "Check good (min)"); TEST_SUCC(vb2_secdata_fwmp_init(ctx), "Init good (min)"); TEST_NEQ(sd->status & VB2_SD_STATUS_SECDATA_FWMP_INIT, 0, "Init flag set"); /* Good FWMP data at minimum + N size */ reset_common_data(); sec->struct_size = VB2_SECDATA_FWMP_MIN_SIZE + 1; sec->crc8 = vb2_secdata_fwmp_crc(sec); size = sec->struct_size; TEST_SUCC(vb2api_secdata_fwmp_check(ctx, &size), "Check good (min+N)"); TEST_SUCC(vb2_secdata_fwmp_init(ctx), "Init good (min+N)"); TEST_NEQ(sd->status & VB2_SD_STATUS_SECDATA_FWMP_INIT, 0, "Init flag set"); /* Skip data check when NO_SECDATA_FWMP set */ reset_common_data(); memset(&ctx->secdata_fwmp, 0xa6, sizeof(ctx->secdata_fwmp)); ctx->flags |= VB2_CONTEXT_NO_SECDATA_FWMP; TEST_EQ(vb2_secdata_fwmp_init(ctx), 0, "Init skip data check when NO_SECDATA_FWMP set"); TEST_NEQ(sd->status & VB2_SD_STATUS_SECDATA_FWMP_INIT, 0, "Init flag set"); } static void get_flag_test(void) { /* Successfully returns value */ reset_common_data(); sec->flags |= 1; TEST_EQ(vb2_secdata_fwmp_get_flag(ctx, 1), 1, "Successfully returns flag value"); /* NO_SECDATA_FWMP */ reset_common_data(); sec->flags |= 1; ctx->flags |= VB2_CONTEXT_NO_SECDATA_FWMP; TEST_EQ(vb2_secdata_fwmp_get_flag(ctx, 1), 0, "NO_SECDATA_FWMP forces default flag value"); /* FWMP hasn't been initialized (recovery mode) */ reset_common_data(); sd->status &= ~VB2_SD_STATUS_SECDATA_FWMP_INIT; ctx->flags |= VB2_CONTEXT_RECOVERY_MODE; TEST_EQ(vb2_secdata_fwmp_get_flag(ctx, 0), 0, "non-init in recovery mode forces default flag value"); /* FWMP hasn't been initialized (normal mode) */ reset_common_data(); sd->status &= ~VB2_SD_STATUS_SECDATA_FWMP_INIT; TEST_ABORT(vb2_secdata_fwmp_get_flag(ctx, 0), "non-init in normal mode triggers abort"); } static void get_dev_key_hash_test(void) { /* CONTEXT_NO_SECDATA_FWMP */ reset_common_data(); ctx->flags |= VB2_CONTEXT_NO_SECDATA_FWMP; TEST_TRUE(vb2_secdata_fwmp_get_dev_key_hash(ctx) == NULL, "NO_SECDATA_FWMP forces NULL pointer"); /* FWMP hasn't been initialized (recovery mode) */ reset_common_data(); sd->status &= ~VB2_SD_STATUS_SECDATA_FWMP_INIT; ctx->flags |= VB2_CONTEXT_RECOVERY_MODE; TEST_TRUE(vb2_secdata_fwmp_get_dev_key_hash(ctx) == NULL, "non-init in recovery mode forces NULL pointer"); /* FWMP hasn't been initialized (normal mode) */ reset_common_data(); sd->status &= ~VB2_SD_STATUS_SECDATA_FWMP_INIT; TEST_ABORT(vb2_secdata_fwmp_get_dev_key_hash(ctx), "non-init in normal mode triggers abort"); /* Success case */ reset_common_data(); TEST_TRUE(vb2_secdata_fwmp_get_dev_key_hash(ctx) == sec->dev_key_hash, "proper dev_key_hash pointer returned"); } int main(int argc, char* argv[]) { check_init_test(); get_flag_test(); get_dev_key_hash_test(); return gTestSuccess ? 0 : 255; }