1/* @LICENSE(UNSW_OZPLB) */
2
3/*
4 * Australian Public Licence B (OZPLB)
5 *
6 * Version 1-0
7 *
8 * Copyright (c) 2004 University of New South Wales
9 *
10 * All rights reserved.
11 *
12 * Developed by: Operating Systems and Distributed Systems Group (DiSy)
13 *               University of New South Wales
14 *               http://www.disy.cse.unsw.edu.au
15 *
16 * Permission is granted by University of New South Wales, free of charge, to
17 * any person obtaining a copy of this software and any associated
18 * documentation files (the "Software") to deal with the Software without
19 * restriction, including (without limitation) the rights to use, copy,
20 * modify, adapt, merge, publish, distribute, communicate to the public,
21 * sublicense, and/or sell, lend or rent out copies of the Software, and
22 * to permit persons to whom the Software is furnished to do so, subject
23 * to the following conditions:
24 *
25 *     * Redistributions of source code must retain the above copyright
26 *       notice, this list of conditions and the following disclaimers.
27 *
28 *     * Redistributions in binary form must reproduce the above
29 *       copyright notice, this list of conditions and the following
30 *       disclaimers in the documentation and/or other materials provided
31 *       with the distribution.
32 *
33 *     * Neither the name of University of New South Wales, nor the names of its
34 *       contributors, may be used to endorse or promote products derived
35 *       from this Software without specific prior written permission.
36 *
37 * EXCEPT AS EXPRESSLY STATED IN THIS LICENCE AND TO THE FULL EXTENT
38 * PERMITTED BY APPLICABLE LAW, THE SOFTWARE IS PROVIDED "AS-IS", AND
39 * NATIONAL ICT AUSTRALIA AND ITS CONTRIBUTORS MAKE NO REPRESENTATIONS,
40 * WARRANTIES OR CONDITIONS OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
41 * BUT NOT LIMITED TO ANY REPRESENTATIONS, WARRANTIES OR CONDITIONS
42 * REGARDING THE CONTENTS OR ACCURACY OF THE SOFTWARE, OR OF TITLE,
43 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT,
44 * THE ABSENCE OF LATENT OR OTHER DEFECTS, OR THE PRESENCE OR ABSENCE OF
45 * ERRORS, WHETHER OR NOT DISCOVERABLE.
46 *
47 * TO THE FULL EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL
48 * NATIONAL ICT AUSTRALIA OR ITS CONTRIBUTORS BE LIABLE ON ANY LEGAL
49 * THEORY (INCLUDING, WITHOUT LIMITATION, IN AN ACTION OF CONTRACT,
50 * NEGLIGENCE OR OTHERWISE) FOR ANY CLAIM, LOSS, DAMAGES OR OTHER
51 * LIABILITY, INCLUDING (WITHOUT LIMITATION) LOSS OF PRODUCTION OR
52 * OPERATION TIME, LOSS, DAMAGE OR CORRUPTION OF DATA OR RECORDS; OR LOSS
53 * OF ANTICIPATED SAVINGS, OPPORTUNITY, REVENUE, PROFIT OR GOODWILL, OR
54 * OTHER ECONOMIC LOSS; OR ANY SPECIAL, INCIDENTAL, INDIRECT,
55 * CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES, ARISING OUT OF OR IN
56 * CONNECTION WITH THIS LICENCE, THE SOFTWARE OR THE USE OF OR OTHER
57 * DEALINGS WITH THE SOFTWARE, EVEN IF NATIONAL ICT AUSTRALIA OR ITS
58 * CONTRIBUTORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH CLAIM, LOSS,
59 * DAMAGES OR OTHER LIABILITY.
60 *
61 * If applicable legislation implies representations, warranties, or
62 * conditions, or imposes obligations or liability on University of New South
63 * Wales or one of its contributors in respect of the Software that
64 * cannot be wholly or partly excluded, restricted or modified, the
65 * liability of University of New South Wales or the contributor is limited, to
66 * the full extent permitted by the applicable legislation, at its
67 * option, to:
68 * a.  in the case of goods, any one or more of the following:
69 * i.  the replacement of the goods or the supply of equivalent goods;
70 * ii.  the repair of the goods;
71 * iii. the payment of the cost of replacing the goods or of acquiring
72 *  equivalent goods;
73 * iv.  the payment of the cost of having the goods repaired; or
74 * b.  in the case of services:
75 * i.  the supplying of the services again; or
76 * ii.  the payment of the cost of having the services supplied again.
77 *
78 * The construction, validity and performance of this licence is governed
79 * by the laws in force in New South Wales, Australia.
80 */
81#include <elf/elf.h>
82#include <elf/elf32.h>
83#include <elf/elf64.h>
84#include <string.h>
85#include <stdio.h>
86
87/* ELF header functions */
88int elf_newFile(void *file, size_t size, elf_t *res)
89{
90    return elf_newFile_maybe_unsafe(file, size, true, true, res);
91}
92
93int elf_newFile_maybe_unsafe(void *file, size_t size, bool check_pht, bool check_st, elf_t *res)
94{
95    elf_t new_file = {
96        .elfFile = file,
97        .elfSize = size
98    };
99
100    int status = elf_checkFile(&new_file);
101    if (status < 0) {
102        return status;
103    }
104
105    if (check_pht) {
106        status = elf_checkProgramHeaderTable(&new_file);
107        if (status < 0) {
108            return status;
109        }
110    }
111
112    if (check_st) {
113        status = elf_checkSectionTable(&new_file);
114        if (status < 0) {
115            return status;
116        }
117    }
118
119    if (res) {
120        *res = new_file;
121    }
122
123    return status;
124}
125
126int elf_check_magic(char *file)
127{
128    if (memcmp(file, ELFMAG, SELFMAG) != 0) {
129        return -1;
130    }
131
132    return 0;
133}
134
135/*
136 * Checks that elfFile points to a valid elf file. Returns 0 if the elf
137 * file is valid, < 0 if invalid.
138 */
139int elf_checkFile(elf_t *elfFile)
140{
141    int res = elf32_checkFile(elfFile);
142    if (res == 0) {
143        return 0;
144    }
145
146    res = elf64_checkFile(elfFile);
147    if (res == 0) {
148        return 0;
149    }
150
151    return -1;
152}
153
154int elf_checkProgramHeaderTable(elf_t *elfFile)
155{
156    if (elf_isElf32(elfFile)) {
157        return elf32_checkProgramHeaderTable(elfFile);
158    } else {
159        return elf64_checkProgramHeaderTable(elfFile);
160    }
161}
162
163int elf_checkSectionTable(elf_t *elfFile)
164{
165    if (elf_isElf32(elfFile)) {
166        return elf32_checkSectionTable(elfFile);
167    } else {
168        return elf64_checkSectionTable(elfFile);
169    }
170}
171
172uintptr_t elf_getEntryPoint(elf_t *elfFile)
173{
174    if (elf_isElf32(elfFile)) {
175        return elf32_getEntryPoint(elfFile);
176    } else {
177        return elf64_getEntryPoint(elfFile);
178    }
179}
180
181size_t elf_getNumProgramHeaders(elf_t *elfFile)
182{
183    if (elf_isElf32(elfFile)) {
184        return elf32_getNumProgramHeaders(elfFile);
185    } else {
186        return elf64_getNumProgramHeaders(elfFile);
187    }
188}
189
190size_t elf_getNumSections(elf_t *elfFile)
191{
192    if (elf_isElf32(elfFile)) {
193        return elf32_getNumSections(elfFile);
194    } else {
195        return elf64_getNumSections(elfFile);
196    }
197}
198
199size_t elf_getSectionStringTableIndex(elf_t *elf)
200{
201    if (elf_isElf32(elf)) {
202        return elf32_getSectionStringTableIndex(elf);
203    } else {
204        return elf64_getSectionStringTableIndex(elf);
205    }
206}
207
208const char *elf_getStringTable(elf_t *elf, size_t string_segment)
209{
210    const char *string_table = elf_getSection(elf, string_segment);
211    if (string_table == NULL) {
212        return NULL; /* no such section */
213    }
214
215    if (elf_getSectionType(elf, string_segment) != SHT_STRTAB) {
216        return NULL; /* not a string table */
217    }
218
219    size_t size = elf_getSectionSize(elf, string_segment);
220    if (string_table[size - 1] != 0) {
221        return NULL; /* string table is not null-terminated */
222    }
223
224    return string_table;
225}
226
227const char *elf_getSectionStringTable(elf_t *elf)
228{
229    size_t index = elf_getSectionStringTableIndex(elf);
230    return elf_getStringTable(elf, index);
231}
232
233
234/* Section header functions */
235void *elf_getSection(elf_t *elf, size_t i)
236{
237    if (i == 0 || i >= elf_getNumSections(elf)) {
238        return NULL; /* no such section */
239    }
240
241    size_t section_offset = elf_getSectionOffset(elf, i);
242    size_t section_size = elf_getSectionSize(elf, i);
243    if (section_size == 0) {
244        return NULL; /* section is empty */
245    }
246
247    size_t section_end = section_offset + section_size;
248    /* possible wraparound - check that section end is not before section start */
249    if (section_end > elf->elfSize || section_end < section_offset) {
250        return NULL;
251    }
252
253    return elf->elfFile + section_offset;
254}
255
256void *elf_getSectionNamed(elf_t *elfFile, const char *str, size_t *id)
257{
258    size_t numSections = elf_getNumSections(elfFile);
259    for (size_t i = 0; i < numSections; i++) {
260        if (strcmp(str, elf_getSectionName(elfFile, i)) == 0) {
261            if (id != NULL) {
262                *id = i;
263            }
264            return elf_getSection(elfFile, i);
265        }
266    }
267    return NULL;
268}
269
270const char *elf_getSectionName(elf_t *elf, size_t i)
271{
272    size_t str_table_idx = elf_getSectionStringTableIndex(elf);
273    const char *str_table = elf_getStringTable(elf, str_table_idx);
274    size_t offset = elf_getSectionNameOffset(elf, i);
275    size_t size = elf_getSectionSize(elf, str_table_idx);
276
277    if (str_table == NULL || offset > size) {
278        return "<corrupted>";
279    }
280
281    return str_table + offset;
282}
283
284size_t elf_getSectionNameOffset(elf_t *elfFile, size_t i)
285{
286    if (elf_isElf32(elfFile)) {
287        return elf32_getSectionNameOffset(elfFile, i);
288    } else {
289        return elf64_getSectionNameOffset(elfFile, i);
290    }
291}
292
293uint32_t elf_getSectionType(elf_t *elfFile, size_t i)
294{
295    if (elf_isElf32(elfFile)) {
296        return elf32_getSectionType(elfFile, i);
297    } else {
298        return elf64_getSectionType(elfFile, i);
299    }
300}
301
302size_t elf_getSectionFlags(elf_t *elfFile, size_t i)
303{
304    if (elf_isElf32(elfFile)) {
305        return elf32_getSectionFlags(elfFile, i);
306    } else {
307        return elf64_getSectionFlags(elfFile, i);
308    }
309}
310
311uintptr_t elf_getSectionAddr(elf_t *elfFile, size_t i)
312{
313    if (elf_isElf32(elfFile)) {
314        return elf32_getSectionAddr(elfFile, i);
315    } else {
316        return elf64_getSectionAddr(elfFile, i);
317    }
318}
319
320size_t elf_getSectionOffset(elf_t *elfFile, size_t i)
321{
322    if (elf_isElf32(elfFile)) {
323        return elf32_getSectionOffset(elfFile, i);
324    } else {
325        return elf64_getSectionOffset(elfFile, i);
326    }
327}
328
329size_t elf_getSectionSize(elf_t *elfFile, size_t i)
330{
331    if (elf_isElf32(elfFile)) {
332        return elf32_getSectionSize(elfFile, i);
333    } else {
334        return elf64_getSectionSize(elfFile, i);
335    }
336}
337
338uint32_t elf_getSectionLink(elf_t *elfFile, size_t i)
339{
340    if (elf_isElf32(elfFile)) {
341        return elf32_getSectionLink(elfFile, i);
342    } else {
343        return elf64_getSectionLink(elfFile, i);
344    }
345}
346
347uint32_t elf_getSectionInfo(elf_t *elfFile, size_t i)
348{
349    if (elf_isElf32(elfFile)) {
350        return elf32_getSectionInfo(elfFile, i);
351    } else {
352        return elf64_getSectionInfo(elfFile, i);
353    }
354}
355
356size_t elf_getSectionAddrAlign(elf_t *elfFile, size_t i)
357{
358    if (elf_isElf32(elfFile)) {
359        return elf32_getSectionAddrAlign(elfFile, i);
360    } else {
361        return elf64_getSectionAddrAlign(elfFile, i);
362    }
363}
364
365size_t elf_getSectionEntrySize(elf_t *elfFile, size_t i)
366{
367    if (elf_isElf32(elfFile)) {
368        return elf32_getSectionEntrySize(elfFile, i);
369    } else {
370        return elf64_getSectionEntrySize(elfFile, i);
371    }
372}
373
374
375/* Program headers function */
376void *elf_getProgramSegment(elf_t *elf, size_t ph)
377{
378    size_t offset = elf_getProgramHeaderOffset(elf, ph);
379    size_t file_size = elf_getProgramHeaderFileSize(elf, ph);
380    size_t segment_end = offset + file_size;
381    /* possible wraparound - check that segment end is not before segment start */
382    if (elf->elfSize < segment_end || segment_end < offset) {
383        return NULL;
384    }
385
386    return elf->elfFile + offset;
387}
388
389uint32_t elf_getProgramHeaderType(elf_t *elfFile, size_t ph)
390{
391    if (elf_isElf32(elfFile)) {
392        return elf32_getProgramHeaderType(elfFile, ph);
393    } else {
394        return elf64_getProgramHeaderType(elfFile, ph);
395    }
396}
397
398size_t elf_getProgramHeaderOffset(elf_t *elfFile, size_t ph)
399{
400    if (elf_isElf32(elfFile)) {
401        return elf32_getProgramHeaderOffset(elfFile, ph);
402    } else {
403        return elf64_getProgramHeaderOffset(elfFile, ph);
404    }
405}
406
407uintptr_t elf_getProgramHeaderVaddr(elf_t *elfFile, size_t ph)
408{
409    if (elf_isElf32(elfFile)) {
410        return elf32_getProgramHeaderVaddr(elfFile, ph);
411    } else {
412        return elf64_getProgramHeaderVaddr(elfFile, ph);
413    }
414}
415
416uintptr_t elf_getProgramHeaderPaddr(elf_t *elfFile, size_t ph)
417{
418    if (elf_isElf32(elfFile)) {
419        return elf32_getProgramHeaderPaddr(elfFile, ph);
420    } else {
421        return elf64_getProgramHeaderPaddr(elfFile, ph);
422    }
423}
424
425size_t elf_getProgramHeaderFileSize(elf_t *elfFile, size_t ph)
426{
427    if (elf_isElf32(elfFile)) {
428        return elf32_getProgramHeaderFileSize(elfFile, ph);
429    } else {
430        return elf64_getProgramHeaderFileSize(elfFile, ph);
431    }
432}
433
434size_t elf_getProgramHeaderMemorySize(elf_t *elfFile, size_t ph)
435{
436    if (elf_isElf32(elfFile)) {
437        return elf32_getProgramHeaderMemorySize(elfFile, ph);
438    } else {
439        return elf64_getProgramHeaderMemorySize(elfFile, ph);
440    }
441}
442
443uint32_t elf_getProgramHeaderFlags(elf_t *elfFile, size_t ph)
444{
445    if (elf_isElf32(elfFile)) {
446        return elf32_getProgramHeaderFlags(elfFile, ph);
447    } else {
448        return elf64_getProgramHeaderFlags(elfFile, ph);
449    }
450}
451
452size_t elf_getProgramHeaderAlign(elf_t *elfFile, size_t ph)
453{
454    if (elf_isElf32(elfFile)) {
455        return elf32_getProgramHeaderAlign(elfFile, ph);
456    } else {
457        return elf64_getProgramHeaderAlign(elfFile, ph);
458    }
459}
460
461
462/* Utility functions */
463int elf_getMemoryBounds(elf_t *elfFile, elf_addr_type_t addr_type, uintptr_t *min, uintptr_t *max)
464{
465    uintptr_t mem_min = UINTPTR_MAX;
466    uintptr_t mem_max = 0;
467    size_t i;
468
469    for (i = 0; i < elf_getNumProgramHeaders(elfFile); i++) {
470        uintptr_t sect_min, sect_max;
471
472        if (elf_getProgramHeaderMemorySize(elfFile, i) == 0) {
473            continue;
474        }
475
476        if (addr_type == PHYSICAL) {
477            sect_min = elf_getProgramHeaderPaddr(elfFile, i);
478        } else {
479            sect_min = elf_getProgramHeaderVaddr(elfFile, i);
480        }
481
482        sect_max = sect_min + elf_getProgramHeaderMemorySize(elfFile, i);
483
484        if (sect_max > mem_max) {
485            mem_max = sect_max;
486        }
487        if (sect_min < mem_min) {
488            mem_min = sect_min;
489        }
490    }
491    *min = mem_min;
492    *max = mem_max;
493
494    return 1;
495}
496
497int elf_vaddrInProgramHeader(elf_t *elfFile, size_t ph, uintptr_t vaddr)
498{
499    uintptr_t min = elf_getProgramHeaderVaddr(elfFile, ph);
500    uintptr_t max = min + elf_getProgramHeaderMemorySize(elfFile, ph);
501    if (vaddr >= min && vaddr < max) {
502        return 1;
503    } else {
504        return 0;
505    }
506}
507
508uintptr_t elf_vtopProgramHeader(elf_t *elfFile, size_t ph, uintptr_t vaddr)
509{
510    uintptr_t ph_phys = elf_getProgramHeaderPaddr(elfFile, ph);
511    uintptr_t ph_virt = elf_getProgramHeaderVaddr(elfFile, ph);
512    uintptr_t paddr;
513
514    paddr = vaddr - ph_virt + ph_phys;
515
516    return paddr;
517}
518
519int elf_loadFile(elf_t *elf, elf_addr_type_t addr_type)
520{
521    size_t i;
522
523    for (i = 0; i < elf_getNumProgramHeaders(elf); i++) {
524        /* Load that section */
525        uintptr_t dest, src;
526        size_t len;
527        if (addr_type == PHYSICAL) {
528            dest = elf_getProgramHeaderPaddr(elf, i);
529        } else {
530            dest = elf_getProgramHeaderVaddr(elf, i);
531        }
532        len = elf_getProgramHeaderFileSize(elf, i);
533        src = (uintptr_t) elf->elfFile + elf_getProgramHeaderOffset(elf, i);
534        memcpy((void *) dest, (void *) src, len);
535        dest += len;
536        memset((void *) dest, 0, elf_getProgramHeaderMemorySize(elf, i) - len);
537    }
538
539    return 1;
540}
541