Skip to content
Snippets Groups Projects
Commit 9d563e4a authored by Linux Build Service Account's avatar Linux Build Service Account
Browse files

Merge 47604339 on remote branch

Change-Id: I5bc01c0d1569f6c367babae8939e39a50660be36
parents c5048855 47604339
No related branches found
No related tags found
No related merge requests found
......@@ -473,6 +473,8 @@ static EFI_STATUS load_image_and_authVB2(bootinfo *Info)
if((!Info->multi_slot_boot || target_dynamic_partition_supported())
&& Info->bootinto_recovery) {
if(!Info->multi_slot_boot)
VerifyFlags = VerifyFlags | AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION;
AddRequestedPartition(RequestedPartitionAll, IMG_RECOVERY);
NumRequestedPartition += 1;
/* Add dtbo validation if target supports dtbo image generation and
......
......@@ -402,6 +402,65 @@ AvbValidateVbmetaPublicKey(AvbOps *Ops, const uint8_t *PublicKeyData,
return AVB_IO_RESULT_OK;
}
AvbIOResult
AvbValidatePartitionPublicKey(AvbOps *Ops, const char* Partition,
const uint8_t *PublicKeyData, size_t PublicKeyLength,
const uint8_t *PublicKeyMetadata, size_t PublicKeyMetadataLength,
bool *OutIsTrusted, uint32_t* OutRollbackIndexLocation)
{
UINT8 *UserKeyBuffer = NULL;
UINT32 UserKeyLength = 0;
EFI_STATUS Status = EFI_SUCCESS;
AvbOpsUserData *UserData = NULL;
dprintf(DEBUG, "ValidatePartitionPublicKey PublicKeyLength %d, "
"PublicKeyMetadataLength %d\n",
PublicKeyLength, PublicKeyMetadataLength);
if (OutIsTrusted == NULL || PublicKeyData == NULL) {
dprintf(ERROR, "Invalid parameters\n");
return AVB_IO_RESULT_ERROR_IO;
}
Status = get_userkey(&UserKeyBuffer, &UserKeyLength);
if (Status != EFI_SUCCESS) {
dprintf(ERROR, "get_userkey failed!, %d\n", Status);
return AVB_IO_RESULT_ERROR_IO;
}
UserData = (AvbOpsUserData *)Ops->user_data;
UserData->IsUserKey = FALSE;
if (PublicKeyLength == UserKeyLength &&
memcmp (PublicKeyData, UserKeyBuffer, PublicKeyLength) == 0) {
*OutIsTrusted = true;
UserData->IsUserKey = TRUE;
} else if (PublicKeyLength == ARRAY_SIZE(OEMPublicKey) &&
memcmp(PublicKeyData, OEMPublicKey, PublicKeyLength) == 0) {
*OutIsTrusted = true;
} else {
*OutIsTrusted = false;
memset (UserData->PublicKey, ARRAY_SIZE (UserData->PublicKey), 0);
UserData->PublicKeyLen = 0;
}
if (*OutIsTrusted == true) {
if (PublicKeyLength > ARRAY_SIZE (UserData->PublicKey)) {
dprintf(ERROR, "ValidatePartitionPublicKey: "
"public key length too large %d\n",
PublicKeyLength);
return AVB_IO_RESULT_ERROR_OOM;
}
memcpy (UserData->PublicKey, PublicKeyData, PublicKeyLength);
UserData->PublicKeyLen = PublicKeyLength;
}
*OutRollbackIndexLocation = 1; // Recovery rollback index
dprintf(DEBUG,
"ValidatePartitionPublicKey OutIsTrusted %d, UserKey %d\n",
*OutIsTrusted, UserData->IsUserKey);
return AVB_IO_RESULT_OK;
}
AvbIOResult AvbReadRollbackIndex(AvbOps *Ops, size_t RollbackIndexLocation,
uint64_t *OutRollbackIndex)
......@@ -570,6 +629,7 @@ AvbOps *AvbOpsNew(VOID *UserData)
Ops->read_from_partition = AvbReadFromPartition;
Ops->write_to_partition = AvbWriteToPartition;
Ops->validate_vbmeta_public_key = AvbValidateVbmetaPublicKey;
Ops->validate_public_key_for_partition = AvbValidatePartitionPublicKey;
Ops->read_rollback_index = AvbReadRollbackIndex;
Ops->write_rollback_index = AvbWriteRollbackIndex;
Ops->read_is_device_unlocked = AvbReadIsDeviceUnlocked;
......
......@@ -161,6 +161,9 @@ struct AvbOps {
*
* If AVB_IO_RESULT_OK is returned then |out_is_trusted| is set -
* true if trusted or false if untrusted.
* NOTE: If AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION is passed to
* avb_slot_verify() then this operation is never used. Instead, the
* validate_public_key_for_partition() operation is used
*/
AvbIOResult (*validate_vbmeta_public_key)(AvbOps* ops,
const uint8_t* public_key_data,
......@@ -229,6 +232,26 @@ struct AvbOps {
AvbIOResult (*get_size_of_partition)(AvbOps* ops,
const char* partition,
uint64_t* out_size_num_bytes);
/* Like validate_vbmeta_public_key() but for when the flag
* AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION is being used. The name of the
* partition to get the public key for is passed in |partition_name|.
*
* Also returns the rollback index location to use for the partition, in
* |out_rollback_index_location|.
*
* Returns AVB_IO_RESULT_OK on success, otherwise an error code.
*/
AvbIOResult (*validate_public_key_for_partition)(
AvbOps* ops,
const char* partition,
const uint8_t* public_key_data,
size_t public_key_length,
const uint8_t* public_key_metadata,
size_t public_key_metadata_length,
bool* out_is_trusted,
uint32_t* out_rollback_index_location);
};
typedef struct {
......
......@@ -22,6 +22,34 @@
* SOFTWARE.
*/
/* Copyright (c) 2017,2020, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "avb_slot_verify.h"
#include "avb_chain_partition_descriptor.h"
#include "avb_footer.h"
......@@ -342,6 +370,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
AvbOps* ops,
const char* const* requested_partitions,
const char* ab_suffix,
AvbSlotVerifyFlags flags,
bool allow_verification_error,
AvbVBMetaImageFlags toplevel_vbmeta_flags,
int rollback_index_location,
......@@ -378,7 +407,12 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
* rollback_index_location to determine whether we're the main
* vbmeta struct.
*/
is_main_vbmeta = (rollback_index_location == 0);
is_main_vbmeta = false;
if (rollback_index_location == 0) {
if ((flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) == 0) {
is_main_vbmeta = true;
}
}
/* Don't use footers for vbmeta partitions ('vbmeta' or
* 'vbmeta_<partition_name>').
......@@ -490,6 +524,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
ret = load_and_verify_vbmeta(ops,
requested_partitions,
ab_suffix,
flags,
allow_verification_error,
0 /* toplevel_vbmeta_flags */,
0 /* rollback_index_location */,
......@@ -566,6 +601,8 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
}
}
uint32_t rollback_index_location_to_use = rollback_index_location;
/* Check if key used to make signature matches what is expected. */
if (pk_data != NULL) {
if (expected_public_key != NULL) {
......@@ -593,9 +630,27 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
pk_metadata_len = vbmeta_header.public_key_metadata_size;
}
avb_assert(is_main_vbmeta);
io_ret = ops->validate_vbmeta_public_key(
ops, pk_data, pk_len, pk_metadata, pk_metadata_len, &key_is_trusted);
// If we're not using a vbmeta partition, need to use another AvbOps...
if (flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) {
io_ret = ops->validate_public_key_for_partition(
ops,
full_partition_name,
pk_data,
pk_len,
pk_metadata,
pk_metadata_len,
&key_is_trusted,
&rollback_index_location_to_use);
} else {
avb_assert(is_main_vbmeta);
io_ret = ops->validate_vbmeta_public_key(ops,
pk_data,
pk_len,
pk_metadata,
pk_metadata_len,
&key_is_trusted);
}
if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto out;
......@@ -620,7 +675,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
/* Check rollback index. */
io_ret = ops->read_rollback_index(
ops, rollback_index_location, &stored_rollback_index);
ops, rollback_index_location_to_use, &stored_rollback_index);
if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto out;
......@@ -645,7 +700,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
if (!allow_verification_error) {
if (stored_rollback_index < vbmeta_header.rollback_index) {
io_ret = ops->write_rollback_index(
ops, rollback_index_location, vbmeta_header.rollback_index);
ops, rollback_index_location_to_use, vbmeta_header.rollback_index);
if (io_ret != AVB_IO_RESULT_OK) {
avb_errorv(full_partition_name,
": Error storing rollback index for location.\n",
......@@ -660,7 +715,9 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
if (is_main_vbmeta) {
avb_assert(slot_data->num_vbmeta_images == 0);
} else {
avb_assert(slot_data->num_vbmeta_images > 0);
if (!(flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION)) {
avb_assert(slot_data->num_vbmeta_images > 0);
}
}
if (slot_data->num_vbmeta_images == MAX_NUMBER_OF_VBMETA_IMAGES) {
avb_errorv(full_partition_name, ": Too many vbmeta images.\n", NULL);
......@@ -787,6 +844,7 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
sub_ret = load_and_verify_vbmeta(ops,
requested_partitions,
ab_suffix,
flags,
allow_verification_error,
toplevel_vbmeta_flags,
chain_desc.rollback_index_location,
......@@ -889,14 +947,15 @@ static AvbSlotVerifyResult load_and_verify_vbmeta(
}
}
if (rollback_index_location >= AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS) {
if (rollback_index_location_to_use >=
AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS) {
avb_errorv(
full_partition_name, ": Invalid rollback_index_location.\n", NULL);
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
goto out;
}
slot_data->rollback_indexes[rollback_index_location] =
slot_data->rollback_indexes[rollback_index_location_to_use] =
vbmeta_header.rollback_index;
if (out_algorithm_type != NULL) {
......@@ -984,6 +1043,16 @@ static char* sub_cmdline(AvbOps* ops,
}
}
/* It's possible there is no _PARTUUID for replacement above.
* Duplicate cmdline to ret for additional substitutions below.
*/
if (ret == NULL) {
ret = avb_strdup(cmdline);
if (ret == NULL) {
goto fail;
}
}
return ret;
fail:
......@@ -1108,6 +1177,7 @@ static int cmdline_append_hex(AvbSlotVerifyData* slot_data,
static AvbSlotVerifyResult append_options(
AvbOps* ops,
AvbSlotVerifyFlags flags,
AvbSlotVerifyData* slot_data,
AvbVBMetaImageHeader* toplevel_vbmeta,
AvbAlgorithmType algorithm_type,
......@@ -1117,12 +1187,17 @@ static AvbSlotVerifyResult append_options(
bool is_device_unlocked;
AvbIOResult io_ret;
/* Add androidboot.vbmeta.device option. */
if (!cmdline_append_option(slot_data,
"androidboot.vbmeta.device",
"PARTUUID=$(ANDROID_VBMETA_PARTUUID)")) {
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto out;
/* Add androidboot.vbmeta.device option... except if not using a vbmeta
* partition since it doesn't make sense in that case.
*/
if (!(flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION)) {
if (!cmdline_append_option(slot_data,
"androidboot.vbmeta.device",
"PARTUUID=$(ANDROID_VBMETA_PARTUUID)")) {
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
goto out;
}
}
/* Add androidboot.vbmeta.avb_version option. */
......@@ -1341,10 +1416,9 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
avb_assert(ops->read_is_device_unlocked != NULL);
avb_assert(ops->read_from_partition != NULL);
avb_assert(ops->get_size_of_partition != NULL);
avb_assert(ops->validate_vbmeta_public_key != NULL);
avb_assert(ops->read_rollback_index != NULL);
avb_assert(ops->get_unique_guid_for_partition != NULL);
/* avb_assert(ops->get_size_of_partition != NULL); */
avb_assert(ops->validate_public_key_for_partition != NULL);
if (out_data != NULL) {
*out_data = NULL;
......@@ -1360,6 +1434,21 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
goto fail;
}
/* Make sure passed-in AvbOps support verifying public keys and getting
* rollback index location if not using a vbmeta partition.
*/
if (flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) {
if (ops->validate_public_key_for_partition == NULL) {
avb_error(
"AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION was passed but the "
"validate_public_key_for_partition() operation isn't implemented.\n");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
goto fail;
}
} else {
avb_assert(ops->validate_vbmeta_public_key != NULL);
}
slot_data = avb_calloc(sizeof(AvbSlotVerifyData));
if (slot_data == NULL) {
ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
......@@ -1378,30 +1467,66 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
goto fail;
}
ret = load_and_verify_vbmeta(ops,
requested_partitions,
ab_suffix,
allow_verification_error,
0 /* toplevel_vbmeta_flags */,
0 /* rollback_index_location */,
"vbmeta",
avb_strlen("vbmeta"),
NULL /* expected_public_key */,
0 /* expected_public_key_length */,
slot_data,
&algorithm_type);
if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
goto fail;
if (flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) {
if (requested_partitions == NULL || requested_partitions[0] == NULL) {
avb_fatal(
"Requested partitions cannot be empty when using "
"AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION");
ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
goto fail;
}
/* No vbmeta partition, go through each of the requested partitions... */
for (size_t n = 0; requested_partitions[n] != NULL; n++) {
ret = load_and_verify_vbmeta(ops,
requested_partitions,
ab_suffix,
flags,
allow_verification_error,
0 /* toplevel_vbmeta_flags */,
0 /* rollback_index_location */,
requested_partitions[n],
avb_strlen(requested_partitions[n]),
NULL /* expected_public_key */,
0 /* expected_public_key_length */,
slot_data,
&algorithm_type);
if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
goto fail;
}
}
} else {
/* Usual path, load "vbmeta"... */
ret = load_and_verify_vbmeta(ops,
requested_partitions,
ab_suffix,
flags,
allow_verification_error,
0 /* toplevel_vbmeta_flags */,
0 /* rollback_index_location */,
"vbmeta",
avb_strlen("vbmeta"),
NULL /* expected_public_key */,
0 /* expected_public_key_length */,
slot_data,
&algorithm_type);
if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
goto fail;
}
}
if (!result_should_continue(ret)) {
goto fail;
}
/* If things check out, mangle the kernel command-line as needed. */
if (result_should_continue(ret)) {
if (!(flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION)) {
if (avb_strcmp(slot_data->vbmeta_images[0].partition_name, "vbmeta") != 0) {
avb_assert(
avb_strcmp(slot_data->vbmeta_images[0].partition_name, "boot") == 0);
using_boot_for_vbmeta = true;
}
}
/* Byteswap top-level vbmeta header since we'll need it below. */
avb_vbmeta_image_header_to_host_byte_order(
(const AvbVBMetaImageHeader*)slot_data->vbmeta_images[0].vbmeta_data,
......@@ -1443,6 +1568,7 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
* I/O or OOM error.
*/
AvbSlotVerifyResult sub_ret = append_options(ops,
flags,
slot_data,
&toplevel_vbmeta,
algorithm_type,
......@@ -1471,7 +1597,6 @@ AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
} else {
avb_slot_verify_data_free(slot_data);
}
}
if (!allow_verification_error) {
avb_assert(ret == AVB_SLOT_VERIFY_RESULT_OK);
......
......@@ -99,10 +99,21 @@ typedef enum {
* contents loaded from |requested_partition| will be the contents of
* the entire partition instead of just the size specified in the hash
* descriptor.
*
* If the AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION flag is set then
* data won't be loaded from the "vbmeta" partition and the
* |validate_vbmeta_public_key| operation is never called. Instead, the
* vbmeta structs in |requested_partitions| are loaded and processed and the
* |validate_public_key_for_partition| operation is called for each of these
* vbmeta structs. This flag is useful when booting into recovery on a device
* not using A/B - see section "Booting into recovery" in README.md for
* more information.
*/
typedef enum {
AVB_SLOT_VERIFY_FLAGS_NONE = 0,
AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR = (1 << 0)
AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR = (1 << 0),
AVB_SLOT_VERIFY_FLAGS_RESTART_CAUSED_BY_HASHTREE_CORRUPTION = (1 << 1),
AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION = (1 << 2),
} AvbSlotVerifyFlags;
/* Get a textual representation of |result|. */
......@@ -218,7 +229,9 @@ typedef struct {
* PARTUUID=$(ANDROID_VBMETA_PARTUUID) before substitution so it
* will end up pointing to the vbmeta partition for the verified
* slot. If there is no vbmeta partition it will point to the boot
* partition of the verified slot.
* partition of the verified slot. If the flag
* AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION is used, this is not
* set.
*
* androidboot.vbmeta.avb_version: This is set to the decimal value
* of AVB_VERSION_MAJOR followed by a dot followed by the decimal
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment