blob: 67aceb9aa400f4fefd4a5f57cd996ee14c2e4a25 [file] [log] [blame]
/*
* Copyright (C) 2016 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 "bvb_boot_image_header.h"
#include "bvb_util.h"
const char* bvb_lookup_property(const uint8_t* image_data, size_t image_size,
const char* key, size_t key_size,
size_t* out_value_size) {
const BvbBootImageHeader *header = NULL;
const char* ret = NULL;
const uint8_t* image_end;
const uint8_t* prop_start;
const uint8_t* prop_end;
const uint8_t* p;
if (out_value_size != NULL)
*out_value_size = 0;
if (image_data == NULL) {
bvb_debug("image_data is NULL\n.");
goto out;
}
if (key == NULL) {
bvb_debug("key is NULL\n.");
goto out;
}
if (image_size < sizeof(BvbBootImageHeader)) {
bvb_debug("Length is smaller than header.\n");
goto out;
}
// Ensure magic is correct.
if (bvb_memcmp(image_data, BVB_MAGIC, BVB_MAGIC_LEN) != 0) {
bvb_debug("Magic is incorrect.\n");
goto out;
}
if (key_size == 0)
key_size = bvb_strlen(key);
// Careful, not byteswapped - also ensure it's aligned properly.
bvb_assert_word_aligned(image_data);
header = (const BvbBootImageHeader *) image_data;
image_end = image_data + image_size;
prop_start = image_data + sizeof(BvbBootImageHeader) +
bvb_be64toh(header->authentication_data_block_size) +
bvb_be64toh(header->properties_offset);
prop_end = prop_start + bvb_be64toh(header->properties_size);
if (prop_start < image_data || prop_start > image_end ||
prop_end < image_data || prop_end > image_end ||
prop_end < prop_start) {
bvb_debug("Properties not inside passed-in data.\n");
goto out;
}
for (p = prop_start; p < prop_end; ) {
const BvbPropertyHeader *ph = (const BvbPropertyHeader *) p;
bvb_assert_word_aligned(ph);
uint64_t key_nb = bvb_be64toh(ph->key_num_bytes);
uint64_t value_nb = bvb_be64toh(ph->value_num_bytes);
uint64_t total = sizeof(BvbPropertyHeader) + 2 /* NUL bytes */
+ key_nb + value_nb;
uint64_t remainder = total % 8;
if (remainder != 0)
total += 8 - remainder;
if (total + p < prop_start || total + p > prop_end) {
bvb_debug("Invalid data in properties array.\n");
goto out;
}
if (p[sizeof(BvbPropertyHeader) + key_nb] != 0) {
bvb_debug("No terminating NUL byte in key.\n");
goto out;
}
if (p[sizeof(BvbPropertyHeader) + key_nb + 1 + value_nb] != 0) {
bvb_debug("No terminating NUL byte in value.\n");
goto out;
}
if (key_size == key_nb) {
if (bvb_memcmp(p + sizeof(BvbPropertyHeader), key, key_size) == 0) {
ret = (const char *) (p + sizeof(BvbPropertyHeader) + key_nb + 1);
if (out_value_size != NULL)
*out_value_size = value_nb;
goto out;
}
}
p += total;
}
out:
return ret;
}
int bvb_lookup_property_uint64(const uint8_t* image_data, size_t image_size,
const char* key, size_t key_size,
uint64_t* out_value) {
const char *value;
int ret = 0;
uint64_t parsed_val;
int base;
int n;
value = bvb_lookup_property(image_data, image_size, key, key_size, NULL);
if (value == NULL)
goto out;
base = 10;
if (bvb_memcmp(value, "0x", 2) == 0) {
base = 16;
value += 2;
}
parsed_val = 0;
for (n = 0; value[n] != '\0'; n++) {
int c = value[n];
int digit;
parsed_val *= base;
switch (base) {
case 10:
if (c >= '0' && c <= '9') {
digit = c - '0';
} else {
bvb_debug("Invalid digit.\n");
goto out;
}
break;
case 16:
if (c >= '0' && c <= '9') {
digit = c - '0';
} else if (c >= 'a' && c <= 'f') {
digit = c - 'a' + 10;
} else if (c >= 'A' && c <= 'F') {
digit = c - 'A' + 10;
} else {
bvb_debug("Invalid digit.\n");
goto out;
}
break;
default:
goto out;
}
parsed_val += digit;
}
ret = 1;
if (out_value != NULL)
*out_value = parsed_val;
out:
return ret;
}