1 /* 2 * various helper functions to access elf structures 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; 7 * version 2.1 of the License. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #include "libelf-private.h" 19 20 /* ------------------------------------------------------------------------ */ 21 elf_mark_broken(struct elf_binary * elf,const char * msg)22 void elf_mark_broken(struct elf_binary *elf, const char *msg) 23 { 24 if ( elf->broken == NULL ) 25 elf->broken = msg; 26 } 27 elf_check_broken(const struct elf_binary * elf)28 const char *elf_check_broken(const struct elf_binary *elf) 29 { 30 return elf->broken; 31 } 32 elf_ptrval_in_range(elf_ptrval ptrval,uint64_t size,const void * region,uint64_t regionsize)33 static bool elf_ptrval_in_range(elf_ptrval ptrval, uint64_t size, 34 const void *region, uint64_t regionsize) 35 /* 36 * Returns true if the putative memory area [ptrval,ptrval+size> 37 * is completely inside the region [region,region+regionsize>. 38 * 39 * ptrval and size are the untrusted inputs to be checked. 40 * region and regionsize are trusted and must be correct and valid, 41 * although it is OK for region to perhaps be maliciously NULL 42 * (but not some other malicious value). 43 */ 44 { 45 elf_ptrval regionp = (elf_ptrval)region; 46 47 if ( (region == NULL) || 48 (ptrval < regionp) || /* start is before region */ 49 (ptrval > regionp + regionsize) || /* start is after region */ 50 (size > regionsize - (ptrval - regionp)) ) /* too big */ 51 return 0; 52 return 1; 53 } 54 elf_access_ok(struct elf_binary * elf,uint64_t ptrval,size_t size)55 bool elf_access_ok(struct elf_binary * elf, 56 uint64_t ptrval, size_t size) 57 { 58 if ( elf_ptrval_in_range(ptrval, size, elf->image_base, elf->size) ) 59 return 1; 60 if ( elf_ptrval_in_range(ptrval, size, elf->dest_base, elf->dest_size) ) 61 return 1; 62 if ( elf_ptrval_in_range(ptrval, size, elf->xdest_base, elf->xdest_size) ) 63 return 1; 64 elf_mark_broken(elf, "out of range access"); 65 return 0; 66 } 67 elf_memcpy_safe(struct elf_binary * elf,elf_ptrval dst,elf_ptrval src,size_t size)68 void elf_memcpy_safe(struct elf_binary *elf, elf_ptrval dst, 69 elf_ptrval src, size_t size) 70 { 71 if ( elf_access_ok(elf, dst, size) && 72 elf_access_ok(elf, src, size) ) 73 { 74 /* use memmove because these checks do not prove that the 75 * regions don't overlap and overlapping regions grant 76 * permission for compiler malice */ 77 elf_memmove_unchecked(ELF_UNSAFE_PTR(dst), ELF_UNSAFE_PTR(src), size); 78 } 79 } 80 elf_memset_safe(struct elf_binary * elf,elf_ptrval dst,int c,size_t size)81 void elf_memset_safe(struct elf_binary *elf, elf_ptrval dst, int c, size_t size) 82 { 83 if ( elf_access_ok(elf, dst, size) ) 84 { 85 elf_memset_unchecked(ELF_UNSAFE_PTR(dst), c, size); 86 } 87 } 88 elf_access_unsigned(struct elf_binary * elf,elf_ptrval base,uint64_t moreoffset,size_t size)89 uint64_t elf_access_unsigned(struct elf_binary * elf, elf_ptrval base, 90 uint64_t moreoffset, size_t size) 91 { 92 elf_ptrval ptrval = base + moreoffset; 93 bool need_swap = elf_swap(elf); 94 const uint8_t *u8; 95 const uint16_t *u16; 96 const uint32_t *u32; 97 const uint64_t *u64; 98 99 if ( !elf_access_ok(elf, ptrval, size) ) 100 return 0; 101 102 switch ( size ) 103 { 104 case 1: 105 u8 = (const void*)ptrval; 106 return *u8; 107 case 2: 108 u16 = (const void*)ptrval; 109 return need_swap ? bswap_16(*u16) : *u16; 110 case 4: 111 u32 = (const void*)ptrval; 112 return need_swap ? bswap_32(*u32) : *u32; 113 case 8: 114 u64 = (const void*)ptrval; 115 return need_swap ? bswap_64(*u64) : *u64; 116 default: 117 return 0; 118 } 119 } 120 elf_round_up(struct elf_binary * elf,uint64_t addr)121 uint64_t elf_round_up(struct elf_binary *elf, uint64_t addr) 122 { 123 uint64_t elf_round = (elf_64bit(elf) ? 8 : 4) - 1; 124 125 return (addr + elf_round) & ~elf_round; 126 } 127 128 /* ------------------------------------------------------------------------ */ 129 elf_shdr_count(struct elf_binary * elf)130 unsigned elf_shdr_count(struct elf_binary *elf) 131 { 132 unsigned count = elf_uval(elf, elf->ehdr, e_shnum); 133 uint64_t max = elf->size / sizeof(Elf32_Shdr); 134 135 if ( max > UINT_MAX ) 136 max = UINT_MAX; 137 if ( count > max ) 138 { 139 elf_mark_broken(elf, "far too many section headers"); 140 count = max; 141 } 142 return count; 143 } 144 elf_phdr_count(struct elf_binary * elf)145 unsigned elf_phdr_count(struct elf_binary *elf) 146 { 147 return elf_uval(elf, elf->ehdr, e_phnum); 148 } 149 elf_shdr_by_name(struct elf_binary * elf,const char * name)150 ELF_HANDLE_DECL(elf_shdr) elf_shdr_by_name(struct elf_binary *elf, const char *name) 151 { 152 unsigned i, count = elf_shdr_count(elf); 153 ELF_HANDLE_DECL(elf_shdr) shdr; 154 const char *sname; 155 156 for ( i = 1; i < count; i++ ) 157 { 158 shdr = elf_shdr_by_index(elf, i); 159 if ( !elf_access_ok(elf, ELF_HANDLE_PTRVAL(shdr), 1) ) 160 /* input has an insane section header count field */ 161 break; 162 sname = elf_section_name(elf, shdr); 163 if ( sname && !strcmp(sname, name) ) 164 return shdr; 165 } 166 return ELF_INVALID_HANDLE(elf_shdr); 167 } 168 elf_shdr_by_index(struct elf_binary * elf,unsigned index)169 ELF_HANDLE_DECL(elf_shdr) elf_shdr_by_index(struct elf_binary *elf, unsigned index) 170 { 171 unsigned count = elf_shdr_count(elf); 172 elf_ptrval ptr; 173 174 if ( index >= count ) 175 return ELF_INVALID_HANDLE(elf_shdr); 176 177 ptr = (ELF_IMAGE_BASE(elf) 178 + elf_uval(elf, elf->ehdr, e_shoff) 179 + elf_uval(elf, elf->ehdr, e_shentsize) * index); 180 return ELF_MAKE_HANDLE(elf_shdr, ptr); 181 } 182 elf_phdr_by_index(struct elf_binary * elf,unsigned index)183 ELF_HANDLE_DECL(elf_phdr) elf_phdr_by_index(struct elf_binary *elf, unsigned index) 184 { 185 unsigned count = elf_phdr_count(elf); 186 elf_ptrval ptr; 187 188 if ( index >= count ) 189 return ELF_INVALID_HANDLE(elf_phdr); 190 191 ptr = (ELF_IMAGE_BASE(elf) 192 + elf_uval(elf, elf->ehdr, e_phoff) 193 + elf_uval(elf, elf->ehdr, e_phentsize) * index); 194 return ELF_MAKE_HANDLE(elf_phdr, ptr); 195 } 196 197 elf_section_name(struct elf_binary * elf,ELF_HANDLE_DECL (elf_shdr)shdr)198 const char *elf_section_name(struct elf_binary *elf, 199 ELF_HANDLE_DECL(elf_shdr) shdr) 200 { 201 if ( ELF_PTRVAL_INVALID(elf->sec_strtab) ) 202 return "unknown"; 203 204 return elf_strval(elf, elf->sec_strtab + elf_uval(elf, shdr, sh_name)); 205 } 206 elf_strval(struct elf_binary * elf,elf_ptrval start)207 const char *elf_strval(struct elf_binary *elf, elf_ptrval start) 208 { 209 uint64_t length; 210 211 for ( length = 0; ; length++ ) { 212 if ( !elf_access_ok(elf, start + length, 1) ) 213 return NULL; 214 if ( !elf_access_unsigned(elf, start, length, 1) ) 215 /* ok */ 216 return ELF_UNSAFE_PTR(start); 217 if ( length >= ELF_MAX_STRING_LENGTH ) 218 { 219 elf_mark_broken(elf, "excessively long string"); 220 return NULL; 221 } 222 } 223 } 224 elf_strfmt(struct elf_binary * elf,elf_ptrval start)225 const char *elf_strfmt(struct elf_binary *elf, elf_ptrval start) 226 { 227 const char *str = elf_strval(elf, start); 228 229 if ( str == NULL ) 230 return "(invalid)"; 231 return str; 232 } 233 elf_section_start(struct elf_binary * elf,ELF_HANDLE_DECL (elf_shdr)shdr)234 elf_ptrval elf_section_start(struct elf_binary *elf, ELF_HANDLE_DECL(elf_shdr) shdr) 235 { 236 return ELF_IMAGE_BASE(elf) + elf_uval(elf, shdr, sh_offset); 237 } 238 elf_section_end(struct elf_binary * elf,ELF_HANDLE_DECL (elf_shdr)shdr)239 elf_ptrval elf_section_end(struct elf_binary *elf, ELF_HANDLE_DECL(elf_shdr) shdr) 240 { 241 return ELF_IMAGE_BASE(elf) 242 + elf_uval(elf, shdr, sh_offset) + elf_uval(elf, shdr, sh_size); 243 } 244 elf_segment_start(struct elf_binary * elf,ELF_HANDLE_DECL (elf_phdr)phdr)245 elf_ptrval elf_segment_start(struct elf_binary *elf, ELF_HANDLE_DECL(elf_phdr) phdr) 246 { 247 return ELF_IMAGE_BASE(elf) 248 + elf_uval(elf, phdr, p_offset); 249 } 250 elf_segment_end(struct elf_binary * elf,ELF_HANDLE_DECL (elf_phdr)phdr)251 elf_ptrval elf_segment_end(struct elf_binary *elf, ELF_HANDLE_DECL(elf_phdr) phdr) 252 { 253 return ELF_IMAGE_BASE(elf) 254 + elf_uval(elf, phdr, p_offset) + elf_uval(elf, phdr, p_filesz); 255 } 256 elf_sym_by_name(struct elf_binary * elf,const char * symbol)257 ELF_HANDLE_DECL(elf_sym) elf_sym_by_name(struct elf_binary *elf, const char *symbol) 258 { 259 elf_ptrval ptr = elf_section_start(elf, elf->sym_tab); 260 elf_ptrval end = elf_section_end(elf, elf->sym_tab); 261 ELF_HANDLE_DECL(elf_sym) sym; 262 uint64_t info, name; 263 const char *sym_name; 264 265 for ( ; ptr < end; ptr += elf_size(elf, sym) ) 266 { 267 sym = ELF_MAKE_HANDLE(elf_sym, ptr); 268 info = elf_uval(elf, sym, st_info); 269 name = elf_uval(elf, sym, st_name); 270 if ( ELF32_ST_BIND(info) != STB_GLOBAL ) 271 continue; 272 sym_name = elf_strval(elf, elf->sym_strtab + name); 273 if ( sym_name == NULL ) /* out of range, oops */ 274 return ELF_INVALID_HANDLE(elf_sym); 275 if ( strcmp(sym_name, symbol) ) 276 continue; 277 return sym; 278 } 279 return ELF_INVALID_HANDLE(elf_sym); 280 } 281 elf_sym_by_index(struct elf_binary * elf,unsigned index)282 ELF_HANDLE_DECL(elf_sym) elf_sym_by_index(struct elf_binary *elf, unsigned index) 283 { 284 elf_ptrval ptr = elf_section_start(elf, elf->sym_tab); 285 ELF_HANDLE_DECL(elf_sym) sym; 286 287 sym = ELF_MAKE_HANDLE(elf_sym, ptr + index * elf_size(elf, sym)); 288 return sym; 289 } 290 elf_note_name(struct elf_binary * elf,ELF_HANDLE_DECL (elf_note)note)291 const char *elf_note_name(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note) 292 { 293 return elf_strval(elf, ELF_HANDLE_PTRVAL(note) + elf_size(elf, note)); 294 } 295 elf_note_desc(struct elf_binary * elf,ELF_HANDLE_DECL (elf_note)note)296 elf_ptrval elf_note_desc(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note) 297 { 298 unsigned namesz = (elf_uval(elf, note, namesz) + 3) & ~3; 299 300 return ELF_HANDLE_PTRVAL(note) + elf_size(elf, note) + namesz; 301 } 302 elf_note_numeric(struct elf_binary * elf,ELF_HANDLE_DECL (elf_note)note)303 uint64_t elf_note_numeric(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note) 304 { 305 elf_ptrval desc = elf_note_desc(elf, note); 306 unsigned descsz = elf_uval(elf, note, descsz); 307 308 switch (descsz) 309 { 310 case 1: 311 case 2: 312 case 4: 313 case 8: 314 return elf_access_unsigned(elf, desc, 0, descsz); 315 default: 316 return 0; 317 } 318 } 319 elf_note_numeric_array(struct elf_binary * elf,ELF_HANDLE_DECL (elf_note)note,unsigned int unitsz,unsigned int idx)320 uint64_t elf_note_numeric_array(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note, 321 unsigned int unitsz, unsigned int idx) 322 { 323 elf_ptrval desc = elf_note_desc(elf, note); 324 unsigned descsz = elf_uval(elf, note, descsz); 325 326 if ( descsz % unitsz || idx >= descsz / unitsz ) 327 return 0; 328 switch (unitsz) 329 { 330 case 1: 331 case 2: 332 case 4: 333 case 8: 334 return elf_access_unsigned(elf, desc, idx * unitsz, unitsz); 335 default: 336 return 0; 337 } 338 } 339 elf_note_next(struct elf_binary * elf,ELF_HANDLE_DECL (elf_note)note)340 ELF_HANDLE_DECL(elf_note) elf_note_next(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note) 341 { 342 unsigned namesz = (elf_uval(elf, note, namesz) + 3) & ~3; 343 unsigned descsz = (elf_uval(elf, note, descsz) + 3) & ~3; 344 345 elf_ptrval ptrval = ELF_HANDLE_PTRVAL(note) 346 + elf_size(elf, note) + namesz + descsz; 347 348 if ( ( ptrval <= ELF_HANDLE_PTRVAL(note) || /* wrapped or stuck */ 349 !elf_access_ok(elf, ELF_HANDLE_PTRVAL(note), 1) ) ) 350 ptrval = ELF_MAX_PTRVAL; /* terminate caller's loop */ 351 352 return ELF_MAKE_HANDLE(elf_note, ptrval); 353 } 354 355 /* ------------------------------------------------------------------------ */ 356 elf_is_elfbinary(const void * image_start,size_t image_size)357 bool elf_is_elfbinary(const void *image_start, size_t image_size) 358 { 359 const Elf32_Ehdr *ehdr = image_start; 360 361 if ( image_size < sizeof(*ehdr) ) 362 return 0; 363 364 return IS_ELF(*ehdr); 365 } 366 elf_phdr_is_loadable(struct elf_binary * elf,ELF_HANDLE_DECL (elf_phdr)phdr)367 bool elf_phdr_is_loadable(struct elf_binary *elf, ELF_HANDLE_DECL(elf_phdr) phdr) 368 { 369 uint64_t p_type = elf_uval(elf, phdr, p_type); 370 uint64_t p_flags = elf_uval(elf, phdr, p_flags); 371 372 return ((p_type == PT_LOAD) && (p_flags & (PF_R | PF_W | PF_X)) != 0); 373 } 374 elf_set_xdest(struct elf_binary * elf,void * addr,uint64_t size)375 void elf_set_xdest(struct elf_binary *elf, void *addr, uint64_t size) 376 { 377 elf->xdest_base = addr; 378 elf->xdest_size = size; 379 if ( addr != NULL ) 380 elf_memset_safe(elf, ELF_REALPTR2PTRVAL(addr), 0, size); 381 } 382 383 /* 384 * Local variables: 385 * mode: C 386 * c-file-style: "BSD" 387 * c-basic-offset: 4 388 * tab-width: 4 389 * indent-tabs-mode: nil 390 * End: 391 */ 392