blob: 8b3ac3d8fe91fa5500afad0ec5182a221332e9cd [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#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;
}