static void reset_common_data(enum reset_type t) { struct vb2_keyblock *kb = &mock_vblock.k.kb; struct vb2_fw_preamble *pre = &mock_vblock.p.pre; memset(workbuf, 0xaa, sizeof(workbuf)); memset(&cc, 0, sizeof(cc)); cc.workbuf = workbuf; cc.workbuf_size = sizeof(workbuf); vb2_init_context(&cc); sd = vb2_get_sd(&cc); vb2_nv_init(&cc); vb2_secdata_create(&cc); vb2_secdata_init(&cc); mock_read_res_fail_on_call = 0; mock_unpack_key_retval = VB2_SUCCESS; mock_verify_keyblock_retval = VB2_SUCCESS; mock_verify_preamble_retval = VB2_SUCCESS; /* Set up mock data for verifying keyblock */ sd->fw_version_secdata = 0x20002; vb2_secdata_set(&cc, VB2_SECDATA_VERSIONS, sd->fw_version_secdata); sd->gbb_rootkey_offset = vb2_offset_of(&mock_gbb, &mock_gbb.rootkey); sd->gbb_rootkey_size = sizeof(mock_gbb.rootkey_data); sd->last_fw_result = VB2_FW_RESULT_SUCCESS; mock_gbb.rootkey.algorithm = 11; mock_gbb.rootkey.key_offset = vb2_offset_of(&mock_gbb.rootkey, &mock_gbb.rootkey_data); mock_gbb.rootkey.key_size = sizeof(mock_gbb.rootkey_data); kb->keyblock_size = sizeof(mock_vblock.k); kb->data_key.algorithm = 7; kb->data_key.key_version = 2; kb->data_key.key_offset = vb2_offset_of(&mock_vblock.k, &mock_vblock.k.data_key_data) - vb2_offset_of(&mock_vblock.k, &kb->data_key); kb->data_key.key_size = sizeof(mock_vblock.k.data_key_data); strcpy(mock_vblock.k.data_key_data, "data key data!!"); pre->preamble_size = sizeof(mock_vblock.p); pre->firmware_version = 2; /* If verifying preamble, verify keyblock first to set up data key */ if (t == FOR_PREAMBLE) vb2_load_fw_keyblock(&cc); };
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"); }