1 |
vapier 15/02/28 22:59:34 |
2 |
|
3 |
Modified: scanelf.c |
4 |
Log: |
5 |
scanelf: add more range checks to deal with corrupt elfs |
6 |
|
7 |
Revision Changes Path |
8 |
1.277 pax-utils/scanelf.c |
9 |
|
10 |
file : http://sources.gentoo.org/viewvc.cgi/gentoo-projects/pax-utils/scanelf.c?rev=1.277&view=markup |
11 |
plain: http://sources.gentoo.org/viewvc.cgi/gentoo-projects/pax-utils/scanelf.c?rev=1.277&content-type=text/plain |
12 |
diff : http://sources.gentoo.org/viewvc.cgi/gentoo-projects/pax-utils/scanelf.c?r1=1.276&r2=1.277 |
13 |
|
14 |
Index: scanelf.c |
15 |
=================================================================== |
16 |
RCS file: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v |
17 |
retrieving revision 1.276 |
18 |
retrieving revision 1.277 |
19 |
diff -u -r1.276 -r1.277 |
20 |
--- scanelf.c 28 Feb 2015 22:57:40 -0000 1.276 |
21 |
+++ scanelf.c 28 Feb 2015 22:59:34 -0000 1.277 |
22 |
@@ -1,13 +1,13 @@ |
23 |
/* |
24 |
* Copyright 2003-2012 Gentoo Foundation |
25 |
* Distributed under the terms of the GNU General Public License v2 |
26 |
- * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.276 2015/02/28 22:57:40 vapier Exp $ |
27 |
+ * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.277 2015/02/28 22:59:34 vapier Exp $ |
28 |
* |
29 |
* Copyright 2003-2012 Ned Ludd - <solar@g.o> |
30 |
* Copyright 2004-2012 Mike Frysinger - <vapier@g.o> |
31 |
*/ |
32 |
|
33 |
-static const char rcsid[] = "$Id: scanelf.c,v 1.276 2015/02/28 22:57:40 vapier Exp $"; |
34 |
+static const char rcsid[] = "$Id: scanelf.c,v 1.277 2015/02/28 22:59:34 vapier Exp $"; |
35 |
const char argv0[] = "scanelf"; |
36 |
|
37 |
#include "paxinc.h" |
38 |
@@ -275,15 +275,23 @@ |
39 |
for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ |
40 |
Elf ## B ## _Addr vaddr = EGET(phdr[i].p_vaddr); \ |
41 |
Elf ## B ## _Addr filesz = EGET(phdr[i].p_filesz); \ |
42 |
- offset = EGET(phdr[i].p_offset); \ |
43 |
+ Elf ## B ## _Off hash_offset = offset + (vhash - vaddr); \ |
44 |
\ |
45 |
if (EGET(phdr[i].p_type) != PT_LOAD) \ |
46 |
continue; \ |
47 |
\ |
48 |
+ offset = EGET(phdr[i].p_offset); \ |
49 |
+ if (offset >= (uint64_t)elf->len) \ |
50 |
+ goto corrupt_hash; \ |
51 |
+ if (filesz >= (uint64_t)elf->len) \ |
52 |
+ goto corrupt_hash; \ |
53 |
+ if (hash_offset + (sizeof(Elf32_Word) * 4) > (uint64_t)elf->len) \ |
54 |
+ goto corrupt_hash; \ |
55 |
+ \ |
56 |
if (vhash >= vaddr && vhash < vaddr + filesz) { \ |
57 |
/* Scan the hash table to see how many entries we have */ \ |
58 |
Elf32_Word max_sym_idx = 0; \ |
59 |
- Elf32_Word *hashtbl = elf->vdata + offset + (vhash - vaddr); \ |
60 |
+ Elf32_Word *hashtbl = elf->vdata + hash_offset; \ |
61 |
Elf32_Word b, nbuckets = EGET(hashtbl[0]); \ |
62 |
Elf32_Word nchains = EGET(hashtbl[1]); \ |
63 |
Elf32_Word *buckets = &hashtbl[2]; \ |
64 |
@@ -291,6 +299,17 @@ |
65 |
Elf32_Word sym_idx; \ |
66 |
Elf32_Word chained; \ |
67 |
\ |
68 |
+ if (hash_offset >= (uint64_t)elf->len) \ |
69 |
+ goto corrupt_hash; \ |
70 |
+ if (nbuckets >= UINT32_MAX / 4) \ |
71 |
+ goto corrupt_hash; \ |
72 |
+ if (nchains >= UINT32_MAX / 4) \ |
73 |
+ goto corrupt_hash; \ |
74 |
+ if (nbuckets * 4 > elf->len - offset) \ |
75 |
+ goto corrupt_hash; \ |
76 |
+ if (nchains * 4 > elf->len - offset) \ |
77 |
+ goto corrupt_hash; \ |
78 |
+ \ |
79 |
for (b = 0; b < nbuckets; ++b) { \ |
80 |
if (!buckets[b]) \ |
81 |
continue; \ |
82 |
@@ -300,10 +319,8 @@ |
83 |
if (max_sym_idx < sym_idx) \ |
84 |
max_sym_idx = sym_idx; \ |
85 |
} \ |
86 |
- if (chained > nchains) { \ |
87 |
- warnf("corrupt ELF bucket"); \ |
88 |
- break; \ |
89 |
- } \ |
90 |
+ if (chained > nchains) \ |
91 |
+ goto corrupt_hash; \ |
92 |
} \ |
93 |
ESET(sym_shdr.sh_size, sym_shdr.sh_entsize * max_sym_idx); \ |
94 |
} \ |
95 |
@@ -321,6 +338,10 @@ |
96 |
} |
97 |
GET_SYMTABS_DT(32) |
98 |
GET_SYMTABS_DT(64) |
99 |
+ return; |
100 |
+ |
101 |
+ corrupt_hash: |
102 |
+ warn("%s: ELF hash table is corrupt", elf->filename); |
103 |
} |
104 |
|
105 |
static char *scanelf_file_pax(elfobj *elf, char *found_pax) |
106 |
@@ -440,8 +461,9 @@ |
107 |
} else if (elf->shdr != NULL) { \ |
108 |
/* no program headers which means this is prob an object file */ \ |
109 |
Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \ |
110 |
- Elf ## B ## _Shdr *strtbl = shdr + EGET(ehdr->e_shstrndx); \ |
111 |
- if ((void*)strtbl > elf->data_end) \ |
112 |
+ uint16_t shstrndx = EGET(ehdr->e_shstrndx); \ |
113 |
+ Elf ## B ## _Shdr *strtbl = shdr + shstrndx; \ |
114 |
+ if (shstrndx >= elf->len - sizeof(*strtbl) || !VALID_SHDR(elf, strtbl)) \ |
115 |
goto skip_this_shdr##B; \ |
116 |
/* let's flag -w/+x object files since the final ELF will most likely \ |
117 |
* need write access to the stack (who doesn't !?). so the combined \ |
118 |
@@ -1409,26 +1431,23 @@ |
119 |
if (cnt) \ |
120 |
cnt = EGET(symtab->sh_size) / cnt; \ |
121 |
for (i = 0; i < cnt; ++i) { \ |
122 |
- if ((void*)sym > elf->data_end) { \ |
123 |
- warnf("%s: corrupt ELF symbols - aborting", elf->filename); \ |
124 |
+ if ((void *)sym >= elf->data_end - sizeof(*sym)) \ |
125 |
goto break_out; \ |
126 |
- } \ |
127 |
if (sym->st_name) { \ |
128 |
/* make sure the symbol name is in acceptable memory range */ \ |
129 |
symname = elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name); \ |
130 |
- if ((void*)symname > elf->data_end) { \ |
131 |
- warnf("%s: corrupt ELF symbols", elf->filename); \ |
132 |
- ++sym; \ |
133 |
- continue; \ |
134 |
- } \ |
135 |
+ if (EGET(sym->st_name) >= (uint64_t)elf->len || \ |
136 |
+ EGET(strtab->sh_offset) + EGET(sym->st_name) >= (uint64_t)elf->len || \ |
137 |
+ !memchr(symname, 0, elf->len - EGET(strtab->sh_offset) + EGET(sym->st_name))) \ |
138 |
+ goto break_out; \ |
139 |
scanelf_match_symname(elf, found_sym, \ |
140 |
- &ret, &ret_len, symname, \ |
141 |
- ELF##B##_ST_TYPE(EGET(sym->st_info)), \ |
142 |
- ELF##B##_ST_BIND(EGET(sym->st_info)), \ |
143 |
- ELF##B##_ST_VISIBILITY(EGET(sym->st_other)), \ |
144 |
- EGET(sym->st_shndx), \ |
145 |
- /* st_size can be 64bit, but no one is really that big, so screw em */ \ |
146 |
- EGET(sym->st_size)); \ |
147 |
+ &ret, &ret_len, symname, \ |
148 |
+ ELF##B##_ST_TYPE(EGET(sym->st_info)), \ |
149 |
+ ELF##B##_ST_BIND(EGET(sym->st_info)), \ |
150 |
+ ELF##B##_ST_VISIBILITY(EGET(sym->st_other)), \ |
151 |
+ EGET(sym->st_shndx), \ |
152 |
+ /* st_size can be 64bit, but no one is really that big, so screw em */ \ |
153 |
+ EGET(sym->st_size)); \ |
154 |
} \ |
155 |
++sym; \ |
156 |
} \ |
157 |
@@ -1437,7 +1456,6 @@ |
158 |
FIND_SYM(64) |
159 |
} |
160 |
|
161 |
-break_out: |
162 |
if (be_wewy_wewy_quiet) return NULL; |
163 |
|
164 |
if (*find_sym != '*' && *found_sym) |
165 |
@@ -1446,6 +1464,10 @@ |
166 |
return NULL; |
167 |
else |
168 |
return " - "; |
169 |
+ |
170 |
+ break_out: |
171 |
+ warnf("%s: corrupt ELF symbols", elf->filename); |
172 |
+ return NULL; |
173 |
} |
174 |
|
175 |
static const char *scanelf_file_sections(elfobj *elf, char *found_section) |