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