1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (C) 2023, STMicroelectronics 4 */ 5 6 #include <assert.h> 7 #include <elf_parser.h> 8 #include <string.h> 9 #include <trace.h> 10 #include <types_ext.h> 11 #include <util.h> 12 13 static bool va_in_fwm_image_range(void *va, uint8_t *fw, size_t fw_size) 14 { 15 uint8_t *vaddr = va; 16 17 return vaddr >= fw && vaddr < fw + fw_size; 18 } 19 20 TEE_Result e32_parse_ehdr(uint8_t *fw, size_t size) 21 { 22 Elf32_Ehdr *ehdr = (Elf32_Ehdr *)(void *)fw; 23 24 if (!fw || !IS_ALIGNED_WITH_TYPE(fw, uint32_t)) { 25 EMSG("Invalid firmware address"); 26 return TEE_ERROR_BAD_PARAMETERS; 27 } 28 29 if (size < sizeof(Elf32_Ehdr) || 30 size < (ehdr->e_shoff + sizeof(Elf32_Shdr))) 31 return TEE_ERROR_BAD_FORMAT; 32 33 if (!IS_ELF(*ehdr) || 34 ehdr->e_ident[EI_VERSION] != EV_CURRENT || 35 ehdr->e_ident[EI_CLASS] != ELFCLASS32 || 36 ehdr->e_phentsize != sizeof(Elf32_Phdr) || 37 ehdr->e_shentsize != sizeof(Elf32_Shdr)) { 38 EMSG("Invalid header"); 39 return TEE_ERROR_BAD_FORMAT; 40 } 41 42 if (ehdr->e_phnum == 0) { 43 EMSG("No loadable segment found"); 44 return TEE_ERROR_BAD_FORMAT; 45 } 46 47 return TEE_SUCCESS; 48 } 49 50 TEE_Result e32_parser_load_elf_image(uint8_t *fw, size_t fw_size, 51 TEE_Result (*load_seg)(uint8_t *src, 52 uint32_t size, 53 uint32_t da, 54 uint32_t mem_size, 55 void *priv), 56 void *priv_data) 57 { 58 Elf32_Ehdr *ehdr = (Elf32_Ehdr *)(void *)fw; 59 Elf32_Phdr *phdr = (void *)((int8_t *)ehdr + ehdr->e_phoff); 60 TEE_Result res = TEE_SUCCESS; 61 unsigned int i = 0; 62 63 if (!load_seg || fw + fw_size <= fw) 64 return TEE_ERROR_BAD_PARAMETERS; 65 66 if (!IS_ALIGNED_WITH_TYPE(phdr, uint32_t) || 67 !va_in_fwm_image_range(phdr, fw, fw_size)) 68 return TEE_ERROR_BAD_FORMAT; 69 70 for (i = 0; i < ehdr->e_phnum; i++, phdr++) { 71 uint32_t dst = phdr->p_paddr; 72 uint8_t *src = NULL; 73 74 if (phdr->p_type != PT_LOAD) 75 continue; 76 77 if (!va_in_fwm_image_range((void *)((vaddr_t)(phdr + 1) - 1), 78 fw, fw_size)) 79 return TEE_ERROR_BAD_FORMAT; 80 81 src = (uint8_t *)fw + phdr->p_offset; 82 83 if (!va_in_fwm_image_range(src, fw, fw_size) || 84 !va_in_fwm_image_range(src + phdr->p_filesz, fw, fw_size)) 85 return TEE_ERROR_BAD_FORMAT; 86 87 res = load_seg(src, phdr->p_filesz, dst, phdr->p_memsz, 88 priv_data); 89 if (res) 90 return res; 91 } 92 93 return TEE_SUCCESS; 94 } 95 96 TEE_Result e32_parser_find_rsc_table(uint8_t *fw, size_t fw_size, 97 Elf32_Addr *rsc_addr, 98 Elf32_Word *rsc_size) 99 { 100 Elf32_Shdr *shdr = NULL; 101 unsigned int i = 0; 102 char *name_table = NULL; 103 struct resource_table *table = NULL; 104 Elf32_Ehdr *ehdr = (Elf32_Ehdr *)(void *)fw; 105 uint8_t *elf_data = fw; 106 107 if (fw + fw_size <= fw || fw + ehdr->e_shoff < fw) 108 return TEE_ERROR_BAD_PARAMETERS; 109 110 shdr = (void *)(fw + ehdr->e_shoff); 111 if (!IS_ALIGNED_WITH_TYPE(shdr, uint32_t) || 112 !va_in_fwm_image_range(shdr, fw, fw_size)) 113 return TEE_ERROR_BAD_FORMAT; 114 115 name_table = (char *)elf_data + shdr[ehdr->e_shstrndx].sh_offset; 116 if (!va_in_fwm_image_range(name_table, fw, fw_size)) 117 return TEE_ERROR_BAD_FORMAT; 118 119 for (i = 0; i < ehdr->e_shnum; i++, shdr++) { 120 size_t size = shdr->sh_size; 121 size_t offset = shdr->sh_offset; 122 size_t s = 0; 123 124 if (!va_in_fwm_image_range(shdr, fw, fw_size)) 125 return TEE_ERROR_BAD_FORMAT; 126 127 if (strcmp(name_table + shdr->sh_name, ".resource_table")) 128 continue; 129 130 if (!shdr->sh_size) 131 return TEE_ERROR_NO_DATA; 132 133 if (offset + size > fw_size || offset + size < size) { 134 EMSG("Resource table truncated"); 135 return TEE_ERROR_BAD_FORMAT; 136 } 137 138 if (sizeof(struct resource_table) > size) { 139 EMSG("No header found in resource table"); 140 return TEE_ERROR_BAD_FORMAT; 141 } 142 143 table = (struct resource_table *)(void *)(elf_data + offset); 144 if (!IS_ALIGNED_WITH_TYPE(table, uint32_t)) 145 return TEE_ERROR_CORRUPT_OBJECT; 146 147 if (table->ver != 1) { 148 EMSG("Unsupported firmware version %"PRId32, 149 table->ver); 150 return TEE_ERROR_BAD_FORMAT; 151 } 152 153 if (table->reserved[0] || table->reserved[1]) { 154 EMSG("Non zero reserved bytes"); 155 return TEE_ERROR_BAD_FORMAT; 156 } 157 158 if (MUL_OVERFLOW(table->num, sizeof(*table->offset), &s) || 159 ADD_OVERFLOW(s, sizeof(struct resource_table), &s) || 160 s > size) { 161 EMSG("Resource table incomplete"); 162 return TEE_ERROR_BAD_FORMAT; 163 } 164 165 DMSG("Resource table address %#"PRIx32", size %"PRIu32, 166 shdr->sh_addr, shdr->sh_size); 167 168 *rsc_addr = shdr->sh_addr; 169 *rsc_size = shdr->sh_size; 170 171 return TEE_SUCCESS; 172 } 173 174 return TEE_ERROR_NO_DATA; 175 } 176