static void verify_preamble_tests(void) { struct vb2_fw_preamble *pre = &mock_vblock.p.pre; int wb_used_before; uint32_t v; /* Test successful call */ reset_common_data(FOR_PREAMBLE); wb_used_before = cc.workbuf_used; TEST_SUCC(vb2_load_fw_preamble(&cc), "preamble good"); TEST_EQ(sd->fw_version, 0x20002, "combined version"); TEST_EQ(sd->workbuf_preamble_offset, (wb_used_before + (VB2_WORKBUF_ALIGN - 1)) & ~(VB2_WORKBUF_ALIGN - 1), "preamble offset"); TEST_EQ(sd->workbuf_preamble_size, pre->preamble_size, "preamble size"); TEST_EQ(cc.workbuf_used, sd->workbuf_preamble_offset + sd->workbuf_preamble_size, "workbuf used"); /* Expected failures */ reset_common_data(FOR_PREAMBLE); sd->workbuf_data_key_size = 0; TEST_EQ(vb2_load_fw_preamble(&cc), VB2_ERROR_FW_PREAMBLE2_DATA_KEY, "preamble no data key"); reset_common_data(FOR_PREAMBLE); mock_unpack_key_retval = VB2_ERROR_UNPACK_KEY_HASH_ALGORITHM; TEST_EQ(vb2_load_fw_preamble(&cc), VB2_ERROR_UNPACK_KEY_HASH_ALGORITHM, "preamble unpack data key"); reset_common_data(FOR_PREAMBLE); cc.workbuf_used = cc.workbuf_size - sizeof(struct vb2_fw_preamble) + 8; TEST_EQ(vb2_load_fw_preamble(&cc), VB2_ERROR_FW_PREAMBLE2_WORKBUF_HEADER, "preamble not enough workbuf for header"); reset_common_data(FOR_PREAMBLE); sd->vblock_preamble_offset = sizeof(mock_vblock); TEST_EQ(vb2_load_fw_preamble(&cc), VB2_ERROR_EX_READ_RESOURCE_SIZE, "preamble read header"); reset_common_data(FOR_PREAMBLE); cc.workbuf_used = cc.workbuf_size - sizeof(mock_vblock.p) + 8; TEST_EQ(vb2_load_fw_preamble(&cc), VB2_ERROR_FW_PREAMBLE2_WORKBUF, "preamble not enough workbuf"); reset_common_data(FOR_PREAMBLE); pre->preamble_size = sizeof(mock_vblock); TEST_EQ(vb2_load_fw_preamble(&cc), VB2_ERROR_EX_READ_RESOURCE_SIZE, "preamble read full"); reset_common_data(FOR_PREAMBLE); mock_verify_preamble_retval = VB2_ERROR_PREAMBLE_SIG_INVALID; TEST_EQ(vb2_load_fw_preamble(&cc), VB2_ERROR_PREAMBLE_SIG_INVALID, "preamble verify"); reset_common_data(FOR_PREAMBLE); pre->firmware_version = 0x10000; TEST_EQ(vb2_load_fw_preamble(&cc), VB2_ERROR_FW_PREAMBLE_VERSION_RANGE, "preamble version range"); reset_common_data(FOR_PREAMBLE); pre->firmware_version = 1; TEST_EQ(vb2_load_fw_preamble(&cc), VB2_ERROR_FW_PREAMBLE_VERSION_ROLLBACK, "preamble version rollback"); reset_common_data(FOR_PREAMBLE); pre->firmware_version = 3; TEST_SUCC(vb2_load_fw_preamble(&cc), "preamble version roll forward"); vb2_secdata_get(&cc, VB2_SECDATA_VERSIONS, &v); TEST_EQ(v, 0x20003, "roll forward"); /* Newer version without result success doesn't roll forward */ reset_common_data(FOR_PREAMBLE); pre->firmware_version = 3; sd->last_fw_result = VB2_FW_RESULT_UNKNOWN; TEST_SUCC(vb2_load_fw_preamble(&cc), "preamble version no roll forward 1"); vb2_secdata_get(&cc, VB2_SECDATA_VERSIONS, &v); TEST_EQ(v, 0x20002, "no roll forward"); /* Newer version with success but for other slot doesn't roll forward */ reset_common_data(FOR_PREAMBLE); pre->firmware_version = 3; sd->last_fw_slot = 1; TEST_SUCC(vb2_load_fw_preamble(&cc), "preamble version no roll forward 2"); vb2_secdata_get(&cc, VB2_SECDATA_VERSIONS, &v); TEST_EQ(v, 0x20002, "no roll forward"); }
int vb2_check_dev_switch(struct vb2_context *ctx) { struct vb2_shared_data *sd = vb2_get_sd(ctx); uint32_t flags = 0; uint32_t old_flags; int is_dev = 0; int use_secdata = 1; int rv; /* Read secure flags */ rv = vb2_secdata_get(ctx, VB2_SECDATA_FLAGS, &flags); if (rv) { if (ctx->flags & VB2_CONTEXT_RECOVERY_MODE) { /* * Recovery mode needs to check other ways developer * mode can be enabled, so don't give up yet. But * since we can't read secdata, assume dev mode was * disabled. */ use_secdata = 0; flags = 0; } else { /* Normal mode simply fails */ return rv; } } old_flags = flags; /* Handle dev disable request */ if (use_secdata && vb2_nv_get(ctx, VB2_NV_DISABLE_DEV_REQUEST)) { flags &= ~VB2_SECDATA_FLAG_DEV_MODE; /* Clear the request */ vb2_nv_set(ctx, VB2_NV_DISABLE_DEV_REQUEST, 0); } /* * Check if we've been asked by the caller to disable dev mode. Note * that hardware switch and GBB flag will take precedence over this. */ if (ctx->flags & VB2_DISABLE_DEVELOPER_MODE) flags &= ~VB2_SECDATA_FLAG_DEV_MODE; /* Check virtual dev switch */ if (flags & VB2_SECDATA_FLAG_DEV_MODE) is_dev = 1; /* Handle forcing dev mode via physical switch */ if (ctx->flags & VB2_CONTEXT_FORCE_DEVELOPER_MODE) is_dev = 1; /* Check if GBB is forcing dev mode */ if (sd->gbb_flags & VB2_GBB_FLAG_FORCE_DEV_SWITCH_ON) is_dev = 1; /* Handle whichever mode we end up in */ if (is_dev) { /* Developer mode */ sd->flags |= VB2_SD_DEV_MODE_ENABLED; ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE; flags |= VB2_SECDATA_FLAG_LAST_BOOT_DEVELOPER; } else { /* Normal mode */ flags &= ~VB2_SECDATA_FLAG_LAST_BOOT_DEVELOPER; /* * Disable dev_boot_* flags. This ensures they will be * initially disabled if the user later transitions back into * developer mode. */ vb2_nv_set(ctx, VB2_NV_DEV_BOOT_USB, 0); vb2_nv_set(ctx, VB2_NV_DEV_BOOT_LEGACY, 0); vb2_nv_set(ctx, VB2_NV_DEV_BOOT_SIGNED_ONLY, 0); vb2_nv_set(ctx, VB2_NV_DEV_BOOT_FASTBOOT_FULL_CAP, 0); vb2_nv_set(ctx, VB2_NV_DEV_DEFAULT_BOOT, 0); vb2_nv_set(ctx, VB2_NV_FASTBOOT_UNLOCK_IN_FW, 0); } if (ctx->flags & VB2_CONTEXT_FORCE_WIPEOUT_MODE) vb2_nv_set(ctx, VB2_NV_REQ_WIPEOUT, 1); if (flags != old_flags) { /* * Just changed dev mode state. Clear TPM owner. This must be * done here instead of simply passing a flag to * vb2_check_tpm_clear(), because we don't want to update * last_boot_developer and then fail to clear the TPM owner. * * Note that we do this even if we couldn't read secdata, since * the TPM owner and secdata may be independent, and we want * the owner to be cleared if *this boot* is different than the * last one (perhaps due to GBB or hardware override). */ rv = vb2ex_tpm_clear_owner(ctx); if (use_secdata) { /* Check for failure to clear owner */ if (rv) { /* * Note that this truncates rv to 8 bit. Which * is not as useful as the full error code, but * we don't have NVRAM space to store the full * 32-bit code. */ vb2_fail(ctx, VB2_RECOVERY_TPM_CLEAR_OWNER, rv); return rv; } /* Save new flags */ rv = vb2_secdata_set(ctx, VB2_SECDATA_FLAGS, flags); if (rv) return rv; } } return VB2_SUCCESS; }
static void dev_switch_tests(void) { uint32_t v; /* Normal mode */ reset_common_data(); TEST_SUCC(vb2_check_dev_switch(&cc), "dev mode off"); TEST_EQ(sd->flags & VB2_SD_DEV_MODE_ENABLED, 0, "sd not in dev"); TEST_EQ(cc.flags & VB2_CONTEXT_DEVELOPER_MODE, 0, "ctx not in dev"); TEST_EQ(mock_tpm_clear_called, 0, "no tpm clear"); /* Dev mode */ reset_common_data(); vb2_secdata_set(&cc, VB2_SECDATA_FLAGS, (VB2_SECDATA_FLAG_DEV_MODE | VB2_SECDATA_FLAG_LAST_BOOT_DEVELOPER)); TEST_SUCC(vb2_check_dev_switch(&cc), "dev mode on"); TEST_NEQ(sd->flags & VB2_SD_DEV_MODE_ENABLED, 0, "sd in dev"); TEST_NEQ(cc.flags & VB2_CONTEXT_DEVELOPER_MODE, 0, "ctx in dev"); TEST_EQ(mock_tpm_clear_called, 0, "no tpm clear"); /* Any normal mode boot clears dev boot flags */ reset_common_data(); vb2_nv_set(&cc, VB2_NV_DEV_BOOT_USB, 1); vb2_nv_set(&cc, VB2_NV_DEV_BOOT_LEGACY, 1); vb2_nv_set(&cc, VB2_NV_DEV_BOOT_SIGNED_ONLY, 1); vb2_nv_set(&cc, VB2_NV_DEV_BOOT_FASTBOOT_FULL_CAP, 1); vb2_nv_set(&cc, VB2_NV_FASTBOOT_UNLOCK_IN_FW, 1); TEST_SUCC(vb2_check_dev_switch(&cc), "dev mode off"); TEST_EQ(vb2_nv_get(&cc, VB2_NV_DEV_BOOT_USB), 0, "cleared dev boot usb"); TEST_EQ(vb2_nv_get(&cc, VB2_NV_DEV_BOOT_LEGACY), 0, "cleared dev boot legacy"); TEST_EQ(vb2_nv_get(&cc, VB2_NV_DEV_BOOT_SIGNED_ONLY), 0, "cleared dev boot signed only"); TEST_EQ(vb2_nv_get(&cc, VB2_NV_DEV_BOOT_FASTBOOT_FULL_CAP), 0, "cleared dev boot fastboot full cap"); TEST_EQ(vb2_nv_get(&cc, VB2_NV_FASTBOOT_UNLOCK_IN_FW), 0, "cleared dev boot fastboot unlock in fw"); /* Normal-dev transition clears TPM */ reset_common_data(); vb2_secdata_set(&cc, VB2_SECDATA_FLAGS, VB2_SECDATA_FLAG_DEV_MODE); TEST_SUCC(vb2_check_dev_switch(&cc), "to dev mode"); TEST_EQ(mock_tpm_clear_called, 1, "tpm clear"); vb2_secdata_get(&cc, VB2_SECDATA_FLAGS, &v); TEST_EQ(v, (VB2_SECDATA_FLAG_DEV_MODE | VB2_SECDATA_FLAG_LAST_BOOT_DEVELOPER), "last boot developer now"); /* Dev-normal transition clears TPM too */ reset_common_data(); vb2_secdata_set(&cc, VB2_SECDATA_FLAGS, VB2_SECDATA_FLAG_LAST_BOOT_DEVELOPER); TEST_SUCC(vb2_check_dev_switch(&cc), "from dev mode"); TEST_EQ(mock_tpm_clear_called, 1, "tpm clear"); vb2_secdata_get(&cc, VB2_SECDATA_FLAGS, &v); TEST_EQ(v, 0, "last boot not developer now"); /* Disable dev mode */ reset_common_data(); vb2_secdata_set(&cc, VB2_SECDATA_FLAGS, (VB2_SECDATA_FLAG_DEV_MODE | VB2_SECDATA_FLAG_LAST_BOOT_DEVELOPER)); vb2_nv_set(&cc, VB2_NV_DISABLE_DEV_REQUEST, 1); TEST_SUCC(vb2_check_dev_switch(&cc), "disable dev request"); TEST_EQ(sd->flags & VB2_SD_DEV_MODE_ENABLED, 0, "sd not in dev"); TEST_EQ(vb2_nv_get(&cc, VB2_NV_DISABLE_DEV_REQUEST), 0, "request cleared"); /* Force enabled by gbb */ reset_common_data(); sd->gbb_flags |= VB2_GBB_FLAG_FORCE_DEV_SWITCH_ON; TEST_SUCC(vb2_check_dev_switch(&cc), "dev on via gbb"); TEST_NEQ(sd->flags & VB2_SD_DEV_MODE_ENABLED, 0, "sd in dev"); vb2_secdata_get(&cc, VB2_SECDATA_FLAGS, &v); TEST_EQ(v, VB2_SECDATA_FLAG_LAST_BOOT_DEVELOPER, "doesn't set dev on in secdata but does set last boot dev"); TEST_EQ(mock_tpm_clear_called, 1, "tpm clear"); /* Force enabled by ctx flag */ reset_common_data(); cc.flags |= VB2_CONTEXT_FORCE_DEVELOPER_MODE; TEST_SUCC(vb2_check_dev_switch(&cc), "dev on via ctx flag"); TEST_NEQ(sd->flags & VB2_SD_DEV_MODE_ENABLED, 0, "sd in dev"); vb2_secdata_get(&cc, VB2_SECDATA_FLAGS, &v); TEST_EQ(v, VB2_SECDATA_FLAG_LAST_BOOT_DEVELOPER, "doesn't set dev on in secdata but does set last boot dev"); TEST_EQ(mock_tpm_clear_called, 1, "tpm clear"); /* Simulate clear owner failure */ reset_common_data(); vb2_secdata_set(&cc, VB2_SECDATA_FLAGS, VB2_SECDATA_FLAG_LAST_BOOT_DEVELOPER); mock_tpm_clear_retval = VB2_ERROR_EX_TPM_CLEAR_OWNER; TEST_EQ(vb2_check_dev_switch(&cc), VB2_ERROR_EX_TPM_CLEAR_OWNER, "tpm clear fail"); TEST_EQ(mock_tpm_clear_called, 1, "tpm clear"); vb2_secdata_get(&cc, VB2_SECDATA_FLAGS, &v); TEST_EQ(v, VB2_SECDATA_FLAG_LAST_BOOT_DEVELOPER, "last boot still developer"); TEST_EQ(vb2_nv_get(&cc, VB2_NV_RECOVERY_REQUEST), VB2_RECOVERY_TPM_CLEAR_OWNER, "requests recovery"); TEST_EQ(vb2_nv_get(&cc, VB2_NV_RECOVERY_SUBCODE), (uint8_t)VB2_ERROR_EX_TPM_CLEAR_OWNER, "recovery subcode"); }