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);
};
Example #2
0
void vb2_fail(struct vb2_context *ctx, uint8_t reason, uint8_t subcode)
{
	struct vb2_shared_data *sd = vb2_get_sd(ctx);

	/* If NV data hasn't been initialized, initialize it now */
	if (!(sd->status & VB2_SD_STATUS_NV_INIT))
		vb2_nv_init(ctx);

	/* See if we were far enough in the boot process to choose a slot */
	if (sd->status & VB2_SD_STATUS_CHOSE_SLOT) {

		/* Boot failed */
		vb2_nv_set(ctx, VB2_NV_FW_RESULT, VB2_FW_RESULT_FAILURE);

		/* Use up remaining tries */
		vb2_nv_set(ctx, VB2_NV_TRY_COUNT, 0);

		/*
		 * Try the other slot next time.  We'll alternate
		 * between slots, which may help if one or both slots is
		 * flaky.
		 */
		vb2_nv_set(ctx, VB2_NV_TRY_NEXT, 1 - sd->fw_slot);

		/*
		 * If we didn't try the other slot last boot, or we tried it
		 * and it didn't fail, try it next boot.
		 */
		if (sd->last_fw_slot != 1 - sd->fw_slot ||
		    sd->last_fw_result != VB2_FW_RESULT_FAILURE)
			return;
	}

	/*
	 * If we're still here, we failed before choosing a slot, or both
	 * this slot and the other slot failed in successive boots.  So we
	 * need to go to recovery.
	 *
	 * Set a recovery reason and subcode only if they're not already set.
	 * If recovery is already requested, it's a more specific error code
	 * than later code is providing and we shouldn't overwrite it.
	 */
	VB2_DEBUG("Need recovery, reason: %#x / %#x\n", reason, subcode);
	if (!vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST)) {
		vb2_nv_set(ctx, VB2_NV_RECOVERY_REQUEST, reason);
		vb2_nv_set(ctx, VB2_NV_RECOVERY_SUBCODE, subcode);
	}
}
Example #3
0
static void reset_common_data(void)
{
	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_tpm_clear_called = 0;
	mock_tpm_clear_retval = VB2_SUCCESS;
};
Example #4
0
/* Reset mock data (for use before each test) */
static void ResetMocks(void)
{
	int gbb_used;

	memset(gbb_data, 0, sizeof(gbb_data));
	gbb->major_version = GBB_MAJOR_VER;
	gbb->minor_version = GBB_MINOR_VER;
	gbb->flags = 0;
	gbb_used = sizeof(GoogleBinaryBlockHeader);

	gbb->hwid_offset = gbb_used;
	strcpy(gbb_data + gbb->hwid_offset, "Test HWID");
	gbb->hwid_size = strlen(gbb_data + gbb->hwid_offset) + 1;
	gbb_used = (gbb_used + gbb->hwid_size + 7) & ~7;

	mock_localization_count = 3;
	mock_altfw_mask = 3 << 1;	/* This mask selects 1 and 2 */

	gbb->header_size = sizeof(*gbb);
	gbb->rootkey_offset = gbb_used;
	gbb->rootkey_size = 64;
	gbb_used += 64;
	gbb->recovery_key_offset = gbb_used;
	gbb->recovery_key_size = 64;
	gbb_used += 64;

	memset(&ctx, 0, sizeof(ctx));
	ctx.workbuf = workbuf;
	ctx.workbuf_size = sizeof(workbuf);
	vb2_init_context(&ctx);
	vb2_nv_init(&ctx);

	sd = vb2_get_sd(&ctx);
	sd->vbsd = shared;
	sd->gbb = (struct vb2_gbb_header *)gbb_data;
	sd->gbb_size = sizeof(gbb_data);

	memset(&shared_data, 0, sizeof(shared_data));
	VbSharedDataInit(shared, sizeof(shared_data));

	*debug_info = 0;
}
Example #5
0
int vb2api_fw_phase1(struct vb2_context *ctx)
{
    int rv;

    /* Initialize the vboot context if it hasn't been yet */
    vb2_init_context(ctx);

    /* Initialize NV context */
    vb2_nv_init(ctx);

    /* Initialize secure data */
    rv = vb2_secdata_init(ctx);
    if (rv)
        vb2_fail(ctx, VB2_RECOVERY_SECDATA_INIT, rv);

    /* Load and parse the GBB header */
    rv = vb2_fw_parse_gbb(ctx);
    if (rv)
        vb2_fail(ctx, VB2_RECOVERY_GBB_HEADER, rv);

    /* Check for dev switch */
    rv = vb2_check_dev_switch(ctx);
    if (rv)
        vb2_fail(ctx, VB2_RECOVERY_DEV_SWITCH, rv);

    /*
     * Check for recovery.  Note that this function returns void, since
     * any errors result in requesting recovery.
     */
    vb2_check_recovery(ctx);

    /* Return error if recovery is needed */
    if (ctx->flags & VB2_CONTEXT_RECOVERY_MODE) {
        /* Always clear RAM when entering recovery mode */
        ctx->flags |= VB2_CONTEXT_CLEAR_RAM;

        return VB2_ERROR_API_PHASE1_RECOVERY;
    }

    return VB2_SUCCESS;
}
Example #6
0
static void reset_common_data(enum reset_type t)
{
	struct vb2_packed_key *k;

	memset(workbuf, 0xaa, sizeof(workbuf));

	memset(&cc, 0, sizeof(cc));
	cc.workbuf = workbuf;
	cc.workbuf_size = sizeof(workbuf);
	vb2_workbuf_from_ctx(&cc, &wb);

	vb2_init_context(&cc);
	sd = vb2_get_sd(&cc);

	vb2_nv_init(&cc);

	vb2_secdatak_create(&cc);
	vb2_secdatak_init(&cc);
	vb2_secdatak_set(&cc, VB2_SECDATAK_VERSIONS, 0x20002);

	mock_read_res_fail_on_call = 0;
	mock_unpack_key_retval = VB2_SUCCESS;
	mock_read_gbb_header_retval = VB2_SUCCESS;
	mock_load_kernel_keyblock_retval = VB2_SUCCESS;
	mock_load_kernel_preamble_retval = VB2_SUCCESS;

	/* Recovery key in mock GBB */
	mock_gbb.recovery_key.algorithm = 11;
	mock_gbb.recovery_key.key_offset =
		vb2_offset_of(&mock_gbb.recovery_key,
			      &mock_gbb.recovery_key_data);
	mock_gbb.recovery_key.key_size = sizeof(mock_gbb.recovery_key_data);
	strcpy(mock_gbb.recovery_key_data, "The recovery key");
	mock_gbb.h.recovery_key_offset =
		vb2_offset_of(&mock_gbb, &mock_gbb.recovery_key);
	mock_gbb.h.recovery_key_size =
		mock_gbb.recovery_key.key_offset +
		mock_gbb.recovery_key.key_size;

	if (t == FOR_PHASE1) {
		uint8_t *kdata;

		/* Create mock firmware preamble in the context */
		sd->workbuf_preamble_offset = cc.workbuf_used;
		fwpre = (struct vb2_fw_preamble *)
			(cc.workbuf + sd->workbuf_preamble_offset);
		k = &fwpre->kernel_subkey;
		kdata = (uint8_t *)fwpre + sizeof(*fwpre);
		memcpy(kdata, fw_kernel_key_data, sizeof(fw_kernel_key_data));
		k->algorithm = 7;
		k->key_offset = vb2_offset_of(k, kdata);
		k->key_size = sizeof(fw_kernel_key_data);
		sd->workbuf_preamble_size = sizeof(*fwpre) + k->key_size;
		cc.workbuf_used += sd->workbuf_preamble_size;

	} else if (t == FOR_PHASE2) {
		struct vb2_signature *sig;
		struct vb2_digest_context dc;
		uint8_t *sdata;

		/* Create mock kernel data key */
		sd->workbuf_data_key_offset = cc.workbuf_used;
		kdkey = (struct vb2_packed_key *)
			(cc.workbuf + sd->workbuf_data_key_offset);
		kdkey->algorithm = VB2_ALG_RSA2048_SHA256;
		sd->workbuf_data_key_size = sizeof(*kdkey);
		cc.workbuf_used += sd->workbuf_data_key_size;

		/* Create mock kernel preamble in the context */
		sd->workbuf_preamble_offset = cc.workbuf_used;
		kpre = (struct vb2_kernel_preamble *)
			(cc.workbuf + sd->workbuf_preamble_offset);
		sdata = (uint8_t *)kpre + sizeof(*kpre);

		sig = &kpre->body_signature;
		sig->data_size = sizeof(kernel_data);
		sig->sig_offset = vb2_offset_of(sig, sdata);
		sig->sig_size = VB2_SHA512_DIGEST_SIZE;

		vb2_digest_init(&dc, VB2_HASH_SHA256);
		vb2_digest_extend(&dc, (const uint8_t *)kernel_data,
				  sizeof(kernel_data));
		vb2_digest_finalize(&dc, sdata, sig->sig_size);

		sd->workbuf_preamble_size = sizeof(*kpre) + sig->sig_size;
		sd->vblock_preamble_offset =
			0x10000 - sd->workbuf_preamble_size;
		cc.workbuf_used += sd->workbuf_preamble_size;

	} else {
		/* Set flags and versions for roll-forward */
		sd->kernel_version = 0x20004;
		sd->kernel_version_secdatak = 0x20002;
		sd->flags |= VB2_SD_FLAG_KERNEL_SIGNED;
		cc.flags |= VB2_CONTEXT_ALLOW_KERNEL_ROLL_FORWARD;
	}
};
Example #7
0
int vb2api_fw_phase1(struct vb2_context *ctx)
{
	int rv;
	struct vb2_shared_data *sd;

	/* Initialize the vboot context if it hasn't been yet */
	vb2_init_context(ctx);
	sd = vb2_get_sd(ctx);

	/* Initialize NV context */
	vb2_nv_init(ctx);

	/*
	 * Handle caller-requested reboot due to secdata.  Do this before we
	 * even look at secdata.  If we fail because of a reboot loop we'll be
	 * the first failure so will get to set the recovery reason.
	 */
	if (!(ctx->flags & VB2_CONTEXT_SECDATA_WANTS_REBOOT)) {
		/* No reboot requested */
		vb2_nv_set(ctx, VB2_NV_TPM_REQUESTED_REBOOT, 0);
	} else if (vb2_nv_get(ctx, VB2_NV_TPM_REQUESTED_REBOOT)) {
		/*
		 * Reboot requested... again.  Fool me once, shame on you.
		 * Fool me twice, shame on me.  Fail into recovery to avoid
		 * a reboot loop.
		 */
		vb2_fail(ctx, VB2_RECOVERY_RO_TPM_REBOOT, 0);
	} else {
		/* Reboot requested for the first time */
		vb2_nv_set(ctx, VB2_NV_TPM_REQUESTED_REBOOT, 1);
		return VB2_ERROR_API_PHASE1_SECDATA_REBOOT;
	}

	/* Initialize secure data */
	rv = vb2_secdata_init(ctx);
	if (rv)
		vb2_fail(ctx, VB2_RECOVERY_SECDATA_INIT, rv);

	/* Load and parse the GBB header */
	rv = vb2_fw_parse_gbb(ctx);
	if (rv)
		vb2_fail(ctx, VB2_RECOVERY_GBB_HEADER, rv);

	/*
	 * Check for recovery.  Note that this function returns void, since any
	 * errors result in requesting recovery.  That's also why we don't
	 * return error from failures in the preceding two steps; those
	 * failures simply cause us to detect recovery mode here.
	 */
	vb2_check_recovery(ctx);

	/* Check for dev switch */
	rv = vb2_check_dev_switch(ctx);
	if (rv && !(ctx->flags & VB2_CONTEXT_RECOVERY_MODE)) {
		/*
		 * Error in dev switch processing, and we weren't already
		 * headed for recovery mode.  Reboot into recovery mode, since
		 * it's too late to handle those errors this boot, and we need
		 * to take a different path through the dev switch checking
		 * code in that case.
		 */
		vb2_fail(ctx, VB2_RECOVERY_DEV_SWITCH, rv);
		return rv;
	}

	/*
	 * Check for possible reasons to ask the firmware to make display
	 * available.  sd->recovery_reason may have been set above by
	 * vb2_check_recovery.  VB2_SD_FLAG_DEV_MODE_ENABLED may have been set
	 * above by vb2_check_dev_switch.
	 */
	if (!(ctx->flags & VB2_CONTEXT_DISPLAY_INIT) &&
	    (vb2_nv_get(ctx, VB2_NV_OPROM_NEEDED) ||
	     sd->flags & VB2_SD_FLAG_DEV_MODE_ENABLED ||
	     sd->recovery_reason))
		ctx->flags |= VB2_CONTEXT_DISPLAY_INIT;
	/* Mark display as available for downstream vboot and vboot callers. */
	if (ctx->flags & VB2_CONTEXT_DISPLAY_INIT)
		sd->flags |= VB2_SD_FLAG_DISPLAY_AVAILABLE;

	/* Return error if recovery is needed */
	if (ctx->flags & VB2_CONTEXT_RECOVERY_MODE) {
		/* Always clear RAM when entering recovery mode */
		ctx->flags |= VB2_CONTEXT_CLEAR_RAM;
		return VB2_ERROR_API_PHASE1_RECOVERY;
	}

	return VB2_SUCCESS;
}
static void nv_storage_test(void)
{
    struct nv_field *vnf;
    uint8_t goodcrc;
    uint8_t workbuf[VB2_WORKBUF_RECOMMENDED_SIZE]
    __attribute__ ((aligned (VB2_WORKBUF_ALIGN)));
    struct vb2_context c = {
        .flags = 0,
        .workbuf = workbuf,
        .workbuf_size = sizeof(workbuf),
    };
    struct vb2_shared_data *sd = vb2_get_sd(&c);

    memset(c.nvdata, 0xA6, sizeof(c.nvdata));
    vb2_init_context(&c);

    /* Init with invalid data should set defaults and regenerate CRC */
    vb2_nv_init(&c);
    TEST_EQ(c.nvdata[0], 0x70, "vb2_nv_init() reset header byte");
    TEST_NEQ(c.nvdata[15], 0, "vb2_nv_init() CRC");
    TEST_EQ(sd->status, VB2_SD_STATUS_NV_INIT | VB2_SD_STATUS_NV_REINIT,
            "vb2_nv_init() status changed");
    test_changed(&c, 1, "vb2_nv_init() reset changed");
    goodcrc = c.nvdata[15];
    TEST_SUCC(vb2_nv_check_crc(&c), "vb2_nv_check_crc() good");

    /* Another init should not cause further changes */
    c.flags = 0;
    sd->status = 0;
    vb2_nv_init(&c);
    test_changed(&c, 0, "vb2_nv_init() didn't re-reset");
    TEST_EQ(c.nvdata[15], goodcrc, "vb2_nv_init() CRC same");
    TEST_EQ(sd->status, VB2_SD_STATUS_NV_INIT, "vb2_nv_init() status same");

    /* Perturbing the header should force defaults */
    c.nvdata[0] ^= 0x40;
    TEST_EQ(vb2_nv_check_crc(&c),
            VB2_ERROR_NV_HEADER, "vb2_nv_check_crc() bad header");
    vb2_nv_init(&c);
    TEST_EQ(c.nvdata[0], 0x70, "vb2_nv_init() reset header byte again");
    test_changed(&c, 1, "vb2_nv_init() corrupt changed");
    TEST_EQ(c.nvdata[15], goodcrc, "vb2_nv_init() CRC same again");

    /* So should perturbing some other byte */
    TEST_EQ(c.nvdata[11], 0, "Kernel byte starts at 0");
    c.nvdata[11] = 12;
    TEST_EQ(vb2_nv_check_crc(&c),
            VB2_ERROR_NV_CRC, "vb2_nv_check_crc() bad CRC");
    vb2_nv_init(&c);
    TEST_EQ(c.nvdata[11], 0, "vb2_nv_init() reset kernel byte");
    test_changed(&c, 1, "vb2_nv_init() corrupt elsewhere changed");
    TEST_EQ(c.nvdata[15], goodcrc, "vb2_nv_init() CRC same again");

    /* Clear the kernel and firmware flags */
    vb2_nv_init(&c);
    TEST_EQ(vb2_nv_get(&c, VB2_NV_FIRMWARE_SETTINGS_RESET),
            1, "Firmware settings are reset");
    vb2_nv_set(&c, VB2_NV_FIRMWARE_SETTINGS_RESET, 0);
    TEST_EQ(vb2_nv_get(&c, VB2_NV_FIRMWARE_SETTINGS_RESET),
            0, "Firmware settings are clear");

    TEST_EQ(vb2_nv_get(&c, VB2_NV_KERNEL_SETTINGS_RESET),
            1, "Kernel settings are reset");
    vb2_nv_set(&c, VB2_NV_KERNEL_SETTINGS_RESET, 0);
    TEST_EQ(vb2_nv_get(&c, VB2_NV_KERNEL_SETTINGS_RESET),
            0, "Kernel settings are clear");

    TEST_EQ(c.nvdata[0], 0x40, "Header byte now just has the header bit");
    /* That should have changed the CRC */
    TEST_NEQ(c.nvdata[15], goodcrc,
             "vb2_nv_init() CRC changed due to flags clear");

    /* Test explicitly setting the reset flags again */
    vb2_nv_init(&c);
    vb2_nv_set(&c, VB2_NV_FIRMWARE_SETTINGS_RESET, 1);
    TEST_EQ(vb2_nv_get(&c, VB2_NV_FIRMWARE_SETTINGS_RESET),
            1, "Firmware settings forced reset");
    vb2_nv_set(&c, VB2_NV_FIRMWARE_SETTINGS_RESET, 0);

    vb2_nv_set(&c, VB2_NV_KERNEL_SETTINGS_RESET, 1);
    TEST_EQ(vb2_nv_get(&c, VB2_NV_KERNEL_SETTINGS_RESET),
            1, "Kernel settings forced reset");
    vb2_nv_set(&c, VB2_NV_KERNEL_SETTINGS_RESET, 0);

    /* Get/set an invalid field */
    vb2_nv_init(&c);
    vb2_nv_set(&c, -1, 1);
    TEST_EQ(vb2_nv_get(&c, -1), 0, "Get invalid setting");

    /* Test other fields */
    vb2_nv_init(&c);
    for (vnf = nvfields; vnf->desc; vnf++) {
        TEST_EQ(vb2_nv_get(&c, vnf->param), vnf->default_value,
                vnf->desc);
        vb2_nv_set(&c, vnf->param, vnf->test_value);
        TEST_EQ(vb2_nv_get(&c, vnf->param), vnf->test_value, vnf->desc);
        vb2_nv_set(&c, vnf->param, vnf->test_value2);
        TEST_EQ(vb2_nv_get(&c, vnf->param), vnf->test_value2,
                vnf->desc);
    }

    /* None of those changes should have caused a reset to defaults */
    vb2_nv_init(&c);
    TEST_EQ(vb2_nv_get(&c, VB2_NV_FIRMWARE_SETTINGS_RESET),
            0, "Firmware settings are still clear");
    TEST_EQ(vb2_nv_get(&c, VB2_NV_KERNEL_SETTINGS_RESET),
            0, "Kernel settings are still clear");

    /* Writing identical settings doesn't cause the CRC to regenerate */
    c.flags = 0;
    vb2_nv_init(&c);
    test_changed(&c, 0, "No regen CRC on open");
    for (vnf = nvfields; vnf->desc; vnf++)
        vb2_nv_set(&c, vnf->param, vnf->test_value2);
    test_changed(&c, 0, "No regen CRC if data not changed");

    /* Test out-of-range fields mapping to defaults or failing */
    vb2_nv_init(&c);
    vb2_nv_set(&c, VB2_NV_TRY_COUNT, 16);
    TEST_EQ(vb2_nv_get(&c, VB2_NV_TRY_COUNT),
            15, "Try b count out of range");
    vb2_nv_set(&c, VB2_NV_RECOVERY_REQUEST, 0x101);
    TEST_EQ(vb2_nv_get(&c, VB2_NV_RECOVERY_REQUEST),
            VB2_RECOVERY_LEGACY, "Recovery request out of range");
    vb2_nv_set(&c, VB2_NV_LOCALIZATION_INDEX, 0x102);
    TEST_EQ(vb2_nv_get(&c, VB2_NV_LOCALIZATION_INDEX),
            0, "Localization index out of range");

    vb2_nv_set(&c, VB2_NV_FW_RESULT, VB2_FW_RESULT_UNKNOWN + 1);
    vb2_nv_set(&c, VB2_NV_FW_RESULT, VB2_FW_RESULT_UNKNOWN + 100);
    TEST_EQ(vb2_nv_get(&c, VB2_NV_FW_RESULT),
            VB2_FW_RESULT_UNKNOWN, "Firmware result out of range");
}

int main(int argc, char* argv[])
{
    nv_storage_test();

    return gTestSuccess ? 0 : 255;
}