You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
215 lines
7.0 KiB
215 lines
7.0 KiB
/*
|
|
* Copyright (C) 2017 The Android Open Source Project
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person
|
|
* obtaining a copy of this software and associated documentation
|
|
* files (the "Software"), to deal in the Software without
|
|
* restriction, including without limitation the rights to use, copy,
|
|
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
* of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be
|
|
* included in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*/
|
|
|
|
#include "avb_user_verification.h"
|
|
|
|
/* Maximum allow length (in bytes) of a partition name, including
|
|
* ab_suffix.
|
|
*/
|
|
#define AVB_PART_NAME_MAX_SIZE 32
|
|
|
|
/* Loads the toplevel AvbVBMetaImageHeader from the slot denoted by
|
|
* |ab_suffix| into |vbmeta_image|. No validation, verification, or
|
|
* byteswapping is performed.
|
|
*
|
|
* If successful, |true| is returned and the partition it was loaded
|
|
* from is returned in |out_partition_name| and the offset on said
|
|
* partition is returned in |out_vbmeta_offset|.
|
|
*/
|
|
static bool load_top_level_vbmeta_header(
|
|
AvbOps* ops,
|
|
const char* ab_suffix,
|
|
uint8_t vbmeta_image[AVB_VBMETA_IMAGE_HEADER_SIZE],
|
|
char out_partition_name[AVB_PART_NAME_MAX_SIZE],
|
|
uint64_t* out_vbmeta_offset) {
|
|
uint64_t vbmeta_offset = 0;
|
|
size_t num_read;
|
|
bool ret = false;
|
|
AvbIOResult io_res;
|
|
|
|
/* Construct full partition name. */
|
|
if (!avb_str_concat(out_partition_name,
|
|
AVB_PART_NAME_MAX_SIZE,
|
|
"vbmeta",
|
|
6,
|
|
ab_suffix,
|
|
avb_strlen(ab_suffix))) {
|
|
avb_error("Partition name and suffix does not fit.\n");
|
|
goto out;
|
|
}
|
|
|
|
/* Only read the header, not the entire struct. */
|
|
io_res = ops->read_from_partition(ops,
|
|
out_partition_name,
|
|
vbmeta_offset,
|
|
AVB_VBMETA_IMAGE_HEADER_SIZE,
|
|
vbmeta_image,
|
|
&num_read);
|
|
if (io_res == AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION) {
|
|
AvbFooter footer;
|
|
|
|
/* Try looking for the vbmeta struct in 'boot' via the footer. */
|
|
if (!avb_str_concat(out_partition_name,
|
|
AVB_PART_NAME_MAX_SIZE,
|
|
"boot",
|
|
4,
|
|
ab_suffix,
|
|
avb_strlen(ab_suffix))) {
|
|
avb_error("Partition name and suffix does not fit.\n");
|
|
goto out;
|
|
}
|
|
io_res = ops->read_from_partition(ops,
|
|
out_partition_name,
|
|
-AVB_FOOTER_SIZE,
|
|
AVB_FOOTER_SIZE,
|
|
&footer,
|
|
&num_read);
|
|
if (io_res != AVB_IO_RESULT_OK) {
|
|
avb_errorv("Error loading footer from partition '",
|
|
out_partition_name,
|
|
"'\n",
|
|
NULL);
|
|
goto out;
|
|
}
|
|
|
|
if (avb_memcmp(footer.magic, AVB_FOOTER_MAGIC, AVB_FOOTER_MAGIC_LEN) != 0) {
|
|
avb_errorv("Data from '",
|
|
out_partition_name,
|
|
"' does not look like a vbmeta footer.\n",
|
|
NULL);
|
|
goto out;
|
|
}
|
|
|
|
vbmeta_offset = avb_be64toh(footer.vbmeta_offset);
|
|
io_res = ops->read_from_partition(ops,
|
|
out_partition_name,
|
|
vbmeta_offset,
|
|
AVB_VBMETA_IMAGE_HEADER_SIZE,
|
|
vbmeta_image,
|
|
&num_read);
|
|
}
|
|
|
|
if (io_res != AVB_IO_RESULT_OK) {
|
|
avb_errorv(
|
|
"Error loading from partition '", out_partition_name, "'\n", NULL);
|
|
goto out;
|
|
}
|
|
|
|
if (out_vbmeta_offset != NULL) {
|
|
*out_vbmeta_offset = vbmeta_offset;
|
|
}
|
|
|
|
ret = true;
|
|
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
bool avb_user_verification_get(AvbOps* ops,
|
|
const char* ab_suffix,
|
|
bool* out_verification_enabled) {
|
|
uint8_t vbmeta_image[AVB_VBMETA_IMAGE_HEADER_SIZE]; /* 256 bytes. */
|
|
char partition_name[AVB_PART_NAME_MAX_SIZE]; /* 32 bytes. */
|
|
AvbVBMetaImageHeader* header;
|
|
uint32_t flags;
|
|
bool ret = false;
|
|
|
|
if (!load_top_level_vbmeta_header(
|
|
ops, ab_suffix, vbmeta_image, partition_name, NULL)) {
|
|
goto out;
|
|
}
|
|
|
|
if (avb_memcmp(vbmeta_image, AVB_MAGIC, AVB_MAGIC_LEN) != 0) {
|
|
avb_errorv("Data from '",
|
|
partition_name,
|
|
"' does not look like a vbmeta header.\n",
|
|
NULL);
|
|
goto out;
|
|
}
|
|
|
|
/* Set/clear the VERIFICATION_DISABLED bit, as requested. */
|
|
header = (AvbVBMetaImageHeader*)vbmeta_image;
|
|
flags = avb_be32toh(header->flags);
|
|
|
|
if (out_verification_enabled != NULL) {
|
|
*out_verification_enabled =
|
|
!(flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED);
|
|
}
|
|
|
|
ret = true;
|
|
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
bool avb_user_verification_set(AvbOps* ops,
|
|
const char* ab_suffix,
|
|
bool enable_verification) {
|
|
uint8_t vbmeta_image[AVB_VBMETA_IMAGE_HEADER_SIZE]; /* 256 bytes. */
|
|
char partition_name[AVB_PART_NAME_MAX_SIZE]; /* 32 bytes. */
|
|
uint64_t vbmeta_offset;
|
|
AvbIOResult io_res;
|
|
AvbVBMetaImageHeader* header;
|
|
uint32_t flags;
|
|
bool ret = false;
|
|
|
|
if (!load_top_level_vbmeta_header(
|
|
ops, ab_suffix, vbmeta_image, partition_name, &vbmeta_offset)) {
|
|
goto out;
|
|
}
|
|
|
|
if (avb_memcmp(vbmeta_image, AVB_MAGIC, AVB_MAGIC_LEN) != 0) {
|
|
avb_errorv("Data from '",
|
|
partition_name,
|
|
"' does not look like a vbmeta header.\n",
|
|
NULL);
|
|
goto out;
|
|
}
|
|
|
|
/* Set/clear the VERIFICATION_DISABLED bit, as requested. */
|
|
header = (AvbVBMetaImageHeader*)vbmeta_image;
|
|
flags = avb_be32toh(header->flags);
|
|
flags &= ~AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED;
|
|
if (!enable_verification) {
|
|
flags |= AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED;
|
|
}
|
|
header->flags = avb_htobe32(flags);
|
|
|
|
/* Write the header. */
|
|
io_res = ops->write_to_partition(ops,
|
|
partition_name,
|
|
vbmeta_offset,
|
|
AVB_VBMETA_IMAGE_HEADER_SIZE,
|
|
vbmeta_image);
|
|
if (io_res != AVB_IO_RESULT_OK) {
|
|
avb_errorv("Error writing to partition '", partition_name, "'\n", NULL);
|
|
goto out;
|
|
}
|
|
|
|
ret = true;
|
|
|
|
out:
|
|
return ret;
|
|
}
|