mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-10-29 19:18:22 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			167 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			167 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: MIT
 | |
| /*
 | |
|  * Copyright (C) 2016 The Android Open Source Project
 | |
|  */
 | |
| 
 | |
| #include "avb_property_descriptor.h"
 | |
| #include "avb_util.h"
 | |
| 
 | |
| bool avb_property_descriptor_validate_and_byteswap(
 | |
|     const AvbPropertyDescriptor* src, AvbPropertyDescriptor* dest) {
 | |
|   uint64_t expected_size;
 | |
| 
 | |
|   avb_memcpy(dest, src, sizeof(AvbPropertyDescriptor));
 | |
| 
 | |
|   if (!avb_descriptor_validate_and_byteswap((const AvbDescriptor*)src,
 | |
|                                             (AvbDescriptor*)dest))
 | |
|     return false;
 | |
| 
 | |
|   if (dest->parent_descriptor.tag != AVB_DESCRIPTOR_TAG_PROPERTY) {
 | |
|     avb_error("Invalid tag for property descriptor.\n");
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   dest->key_num_bytes = avb_be64toh(dest->key_num_bytes);
 | |
|   dest->value_num_bytes = avb_be64toh(dest->value_num_bytes);
 | |
| 
 | |
|   /* Check that key and value are fully contained. */
 | |
|   expected_size = sizeof(AvbPropertyDescriptor) - sizeof(AvbDescriptor) + 2;
 | |
|   if (!avb_safe_add_to(&expected_size, dest->key_num_bytes) ||
 | |
|       !avb_safe_add_to(&expected_size, dest->value_num_bytes)) {
 | |
|     avb_error("Overflow while adding up sizes.\n");
 | |
|     return false;
 | |
|   }
 | |
|   if (expected_size > dest->parent_descriptor.num_bytes_following) {
 | |
|     avb_error("Descriptor payload size overflow.\n");
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| typedef struct {
 | |
|   const char* key;
 | |
|   size_t key_size;
 | |
|   const char* ret_value;
 | |
|   size_t ret_value_size;
 | |
| } PropertyIteratorData;
 | |
| 
 | |
| static bool property_lookup_desc_foreach(const AvbDescriptor* header,
 | |
|                                          void* user_data) {
 | |
|   PropertyIteratorData* data = (PropertyIteratorData*)user_data;
 | |
|   AvbPropertyDescriptor prop_desc;
 | |
|   const uint8_t* p;
 | |
|   bool ret = true;
 | |
| 
 | |
|   if (header->tag != AVB_DESCRIPTOR_TAG_PROPERTY) {
 | |
|     goto out;
 | |
|   }
 | |
| 
 | |
|   if (!avb_property_descriptor_validate_and_byteswap(
 | |
|           (const AvbPropertyDescriptor*)header, &prop_desc)) {
 | |
|     goto out;
 | |
|   }
 | |
| 
 | |
|   p = (const uint8_t*)header;
 | |
|   if (p[sizeof(AvbPropertyDescriptor) + prop_desc.key_num_bytes] != 0) {
 | |
|     avb_error("No terminating NUL byte in key.\n");
 | |
|     goto out;
 | |
|   }
 | |
| 
 | |
|   if (data->key_size == prop_desc.key_num_bytes) {
 | |
|     if (avb_memcmp(p + sizeof(AvbPropertyDescriptor),
 | |
|                    data->key,
 | |
|                    data->key_size) == 0) {
 | |
|       data->ret_value = (const char*)(p + sizeof(AvbPropertyDescriptor) +
 | |
|                                       prop_desc.key_num_bytes + 1);
 | |
|       data->ret_value_size = prop_desc.value_num_bytes;
 | |
|       /* Stop iterating. */
 | |
|       ret = false;
 | |
|       goto out;
 | |
|     }
 | |
|   }
 | |
| 
 | |
| out:
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| const char* avb_property_lookup(const uint8_t* image_data,
 | |
|                                 size_t image_size,
 | |
|                                 const char* key,
 | |
|                                 size_t key_size,
 | |
|                                 size_t* out_value_size) {
 | |
|   PropertyIteratorData data;
 | |
| 
 | |
|   if (key_size == 0) {
 | |
|     key_size = avb_strlen(key);
 | |
|   }
 | |
| 
 | |
|   data.key = key;
 | |
|   data.key_size = key_size;
 | |
| 
 | |
|   if (avb_descriptor_foreach(
 | |
|           image_data, image_size, property_lookup_desc_foreach, &data) == 0) {
 | |
|     if (out_value_size != NULL) {
 | |
|       *out_value_size = data.ret_value_size;
 | |
|     }
 | |
|     return data.ret_value;
 | |
|   }
 | |
| 
 | |
|   if (out_value_size != NULL) {
 | |
|     *out_value_size = 0;
 | |
|   }
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| bool avb_property_lookup_uint64(const uint8_t* image_data,
 | |
|                                 size_t image_size,
 | |
|                                 const char* key,
 | |
|                                 size_t key_size,
 | |
|                                 uint64_t* out_value) {
 | |
|   const char* value;
 | |
|   bool ret = false;
 | |
|   uint64_t parsed_val;
 | |
|   int base;
 | |
|   int n;
 | |
| 
 | |
|   value = avb_property_lookup(image_data, image_size, key, key_size, NULL);
 | |
|   if (value == NULL) {
 | |
|     goto out;
 | |
|   }
 | |
| 
 | |
|   base = 10;
 | |
|   if (avb_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;
 | |
| 
 | |
|     if (c >= '0' && c <= '9') {
 | |
|       digit = c - '0';
 | |
|     } else if (base == 16 && c >= 'a' && c <= 'f') {
 | |
|       digit = c - 'a' + 10;
 | |
|     } else if (base == 16 && c >= 'A' && c <= 'F') {
 | |
|       digit = c - 'A' + 10;
 | |
|     } else {
 | |
|       avb_error("Invalid digit.\n");
 | |
|       goto out;
 | |
|     }
 | |
| 
 | |
|     parsed_val += digit;
 | |
|   }
 | |
| 
 | |
|   ret = true;
 | |
|   if (out_value != NULL) {
 | |
|     *out_value = parsed_val;
 | |
|   }
 | |
| 
 | |
| out:
 | |
|   return ret;
 | |
| }
 |