This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / kernel / module-verify-elf.c
1 /* module-verify-elf.c: module ELF verifier
2  *
3  * Written by David Howells (dhowells@redhat.com)
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version
8  * 2 of the License, or (at your option) any later version.
9  */
10
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/slab.h>
14 #include <linux/elf.h>
15 #include "module-verify.h"
16
17 #if 0
18 #define _debug(FMT, ...) printk(FMT, ##__VA_ARGS__)
19 #else
20 #define _debug(FMT, ...) do {} while (0)
21 #endif
22
23 /*
24  * verify the ELF structure of a module
25  */
26 int module_verify_elf(struct module_verify_data *mvdata)
27 {
28         const Elf_Ehdr *hdr = mvdata->hdr;
29         const Elf_Shdr *section, *section2, *secstop;
30         const Elf_Rela *relas, *rela, *relastop;
31         const Elf_Rel *rels, *rel, *relstop;
32         const Elf_Sym *symbol, *symstop;
33         size_t size, sssize, *secsize, tmp, tmp2;
34         long last;
35         int line;
36
37         size = mvdata->size;
38         mvdata->nsects = hdr->e_shnum;
39
40 #define elfcheck(X)                                                     \
41 do { if (unlikely(!(X))) { line = __LINE__; goto elfcheck_error; } } while(0)
42
43 #define seccheck(X)                                                     \
44 do { if (unlikely(!(X))) { line = __LINE__; goto seccheck_error; } } while(0)
45
46 #define symcheck(X)                                                     \
47 do { if (unlikely(!(X))) { line = __LINE__; goto symcheck_error; } } while(0)
48
49 #define relcheck(X)                                                     \
50 do { if (unlikely(!(X))) { line = __LINE__; goto relcheck_error; } } while(0)
51
52 #define relacheck(X)                                                    \
53 do { if (unlikely(!(X))) { line = __LINE__; goto relacheck_error; } } while(0)
54
55         /* validate the ELF header */
56         elfcheck(hdr->e_ehsize < size);
57         elfcheck(hdr->e_entry == 0);
58         elfcheck(hdr->e_phoff == 0);
59         elfcheck(hdr->e_phnum == 0);
60
61         elfcheck(hdr->e_shnum < SHN_LORESERVE);
62         elfcheck(hdr->e_shoff < size);
63         elfcheck(hdr->e_shoff >= hdr->e_ehsize);
64         elfcheck((hdr->e_shoff & (sizeof(long) - 1)) == 0);
65         elfcheck(hdr->e_shstrndx > 0);
66         elfcheck(hdr->e_shstrndx < hdr->e_shnum);
67         elfcheck(hdr->e_shentsize == sizeof(Elf_Shdr));
68
69         tmp = (size_t) hdr->e_shentsize * (size_t) hdr->e_shnum;
70         elfcheck(tmp <= size - hdr->e_shoff);
71
72         /* allocate a table to hold in-file section sizes */
73         mvdata->secsizes = kcalloc(hdr->e_shnum, sizeof(size_t), GFP_KERNEL);
74         if (!mvdata->secsizes)
75                 return -ENOMEM;
76
77         /* validate the ELF section headers */
78         mvdata->sections = mvdata->buffer + hdr->e_shoff;
79         secstop = mvdata->sections + mvdata->nsects;
80
81         sssize = mvdata->sections[hdr->e_shstrndx].sh_size;
82         elfcheck(sssize > 0);
83
84         section = mvdata->sections;
85         seccheck(section->sh_type == SHT_NULL);
86         seccheck(section->sh_size == 0);
87         seccheck(section->sh_offset == 0);
88
89         secsize = mvdata->secsizes + 1;
90         for (section++; section < secstop; secsize++, section++) {
91                 seccheck(section->sh_name < sssize);
92                 seccheck(section->sh_link < hdr->e_shnum);
93
94                 if (section->sh_entsize > 0)
95                         seccheck(section->sh_size % section->sh_entsize == 0);
96
97                 seccheck(section->sh_offset >= hdr->e_ehsize);
98                 seccheck(section->sh_offset < size);
99
100                 /* determine the section's in-file size */
101                 tmp = size - section->sh_offset;
102                 if (section->sh_offset < hdr->e_shoff)
103                         tmp = hdr->e_shoff - section->sh_offset;
104
105                 for (section2 = mvdata->sections + 1;
106                      section2 < secstop;
107                      section2++) {
108                         if (section->sh_offset < section2->sh_offset) {
109                                 tmp2 = section2->sh_offset -
110                                         section->sh_offset;
111                                 if (tmp2 < tmp)
112                                         tmp = tmp2;
113                         }
114                 }
115                 *secsize = tmp;
116
117                 _debug("Section %ld: %zx bytes at %lx\n",
118                        section - mvdata->sections,
119                        *secsize,
120                        (unsigned long) section->sh_offset);
121
122                 /* perform section type specific checks */
123                 switch (section->sh_type) {
124                 case SHT_NOBITS:
125                         break;
126
127                 case SHT_REL:
128                         seccheck(section->sh_entsize == sizeof(Elf_Rel));
129                         goto more_rel_checks;
130
131                 case SHT_RELA:
132                         seccheck(section->sh_entsize == sizeof(Elf_Rela));
133                 more_rel_checks:
134                         seccheck(section->sh_info > 0);
135                         seccheck(section->sh_info < hdr->e_shnum);
136                         goto more_sec_checks;
137
138                 case SHT_SYMTAB:
139                         seccheck(section->sh_entsize == sizeof(Elf_Sym));
140                         goto more_sec_checks;
141
142                 default:
143                 more_sec_checks:
144                         /* most types of section must be contained entirely
145                          * within the file */
146                         seccheck(section->sh_size <= *secsize);
147                         break;
148                 }
149         }
150
151         /* validate the ELF section names */
152         section = &mvdata->sections[hdr->e_shstrndx];
153
154         seccheck(section->sh_offset != hdr->e_shoff);
155
156         mvdata->secstrings = mvdata->buffer + section->sh_offset;
157
158         last = -1;
159         for (section = mvdata->sections + 1; section < secstop; section++) {
160                 const char *secname;
161                 tmp = sssize - section->sh_name;
162                 secname = mvdata->secstrings + section->sh_name;
163                 seccheck(secname[0] != 0);
164                 if (section->sh_name > last)
165                         last = section->sh_name;
166         }
167
168         if (last > -1) {
169                 tmp = sssize - last;
170                 elfcheck(memchr(mvdata->secstrings + last, 0, tmp) != NULL);
171         }
172
173         /* look for various sections in the module */
174         for (section = mvdata->sections + 1; section < secstop; section++) {
175                 switch (section->sh_type) {
176                 case SHT_SYMTAB:
177                         if (strcmp(mvdata->secstrings + section->sh_name,
178                                    ".symtab") == 0
179                             ) {
180                                 seccheck(mvdata->symbols == NULL);
181                                 mvdata->symbols =
182                                         mvdata->buffer + section->sh_offset;
183                                 mvdata->nsyms =
184                                         section->sh_size / sizeof(Elf_Sym);
185                                 seccheck(section->sh_size > 0);
186                         }
187                         break;
188
189                 case SHT_STRTAB:
190                         if (strcmp(mvdata->secstrings + section->sh_name,
191                                    ".strtab") == 0
192                             ) {
193                                 seccheck(mvdata->strings == NULL);
194                                 mvdata->strings =
195                                         mvdata->buffer + section->sh_offset;
196                                 sssize = mvdata->nstrings = section->sh_size;
197                                 seccheck(section->sh_size > 0);
198                         }
199                         break;
200                 }
201         }
202
203         if (!mvdata->symbols) {
204                 printk("Couldn't locate module symbol table\n");
205                 goto format_error;
206         }
207
208         if (!mvdata->strings) {
209                 printk("Couldn't locate module strings table\n");
210                 goto format_error;
211         }
212
213         /* validate the symbol table */
214         symstop = mvdata->symbols + mvdata->nsyms;
215
216         symbol = mvdata->symbols;
217         symcheck(ELF_ST_TYPE(symbol[0].st_info) == STT_NOTYPE);
218         symcheck(symbol[0].st_shndx == SHN_UNDEF);
219         symcheck(symbol[0].st_value == 0);
220         symcheck(symbol[0].st_size == 0);
221
222         last = -1;
223         for (symbol++; symbol < symstop; symbol++) {
224                 symcheck(symbol->st_name < sssize);
225                 if (symbol->st_name > last)
226                         last = symbol->st_name;
227                 symcheck(symbol->st_shndx < mvdata->nsects ||
228                          symbol->st_shndx >= SHN_LORESERVE);
229         }
230
231         if (last > -1) {
232                 tmp = sssize - last;
233                 elfcheck(memchr(mvdata->strings + last, 0, tmp) != NULL);
234         }
235
236         /* validate each relocation table as best we can */
237         for (section = mvdata->sections + 1; section < secstop; section++) {
238                 section2 = mvdata->sections + section->sh_info;
239
240                 switch (section->sh_type) {
241                 case SHT_REL:
242                         rels = mvdata->buffer + section->sh_offset;
243                         relstop = mvdata->buffer +
244                                 section->sh_offset + section->sh_size;
245
246                         for (rel = rels; rel < relstop; rel++) {
247                                 relcheck(rel->r_offset < section2->sh_size);
248                                 relcheck(ELF_R_SYM(rel->r_info) <
249                                          mvdata->nsyms);
250                         }
251
252                         break;
253
254                 case SHT_RELA:
255                         relas = mvdata->buffer + section->sh_offset;
256                         relastop = mvdata->buffer +
257                                 section->sh_offset + section->sh_size;
258
259                         for (rela = relas; rela < relastop; rela++) {
260                                 relacheck(rela->r_offset < section2->sh_size);
261                                 relacheck(ELF_R_SYM(rela->r_info) <
262                                           mvdata->nsyms);
263                         }
264
265                         break;
266
267                 default:
268                         break;
269                 }
270         }
271
272
273         _debug("ELF okay\n");
274         return 0;
275
276 elfcheck_error:
277         printk("Verify ELF error (assertion %d)\n", line);
278         goto format_error;
279
280 seccheck_error:
281         printk("Verify ELF error [sec %ld] (assertion %d)\n",
282                (long)(section - mvdata->sections), line);
283         goto format_error;
284
285 symcheck_error:
286         printk("Verify ELF error [sym %ld] (assertion %d)\n",
287                (long)(symbol - mvdata->symbols), line);
288         goto format_error;
289
290 relcheck_error:
291         printk("Verify ELF error [sec %ld rel %ld] (assertion %d)\n",
292                (long)(section - mvdata->sections),
293                (long)(rel - rels), line);
294         goto format_error;
295
296 relacheck_error:
297         printk("Verify ELF error [sec %ld rela %ld] (assertion %d)\n",
298                (long)(section - mvdata->sections),
299                (long)(rela - relas), line);
300         goto format_error;
301
302 format_error:
303         return -ELIBBAD;
304 }