]>
Commit | Line | Data |
---|---|---|
0749e45a AM |
1 | diff -ur rpm.org/file/src/readelf.c rpm/file/src/readelf.c |
2 | --- rpm.org/file/src/readelf.c 2004-06-14 16:30:54.607870936 +0200 | |
3 | +++ rpm/file/src/readelf.c 2004-03-22 21:28:40.000000000 +0100 | |
4 | @@ -1,25 +1,70 @@ | |
5 | -#include "system.h" | |
b6942f9f JB |
6 | +/* |
7 | + * Copyright (c) Christos Zoulas 2003. | |
8 | + * All Rights Reserved. | |
9 | + * | |
10 | + * Redistribution and use in source and binary forms, with or without | |
11 | + * modification, are permitted provided that the following conditions | |
12 | + * are met: | |
13 | + * 1. Redistributions of source code must retain the above copyright | |
14 | + * notice immediately at the beginning of the file, without modification, | |
15 | + * this list of conditions, and the following disclaimer. | |
16 | + * 2. Redistributions in binary form must reproduce the above copyright | |
17 | + * notice, this list of conditions and the following disclaimer in the | |
18 | + * documentation and/or other materials provided with the distribution. | |
19 | + * 3. The name of the author may not be used to endorse or promote products | |
20 | + * derived from this software without specific prior written permission. | |
21 | + * | |
22 | + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
23 | + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR | |
26 | + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
27 | + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
28 | + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
29 | + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
30 | + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
31 | + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
32 | + * SUCH DAMAGE. | |
33 | + */ | |
0749e45a | 34 | +#include "file.h" |
b6942f9f JB |
35 | |
36 | #ifdef BUILTIN_ELF | |
0749e45a AM |
37 | -#include "file.h" |
38 | +#include <string.h> | |
39 | +#include <ctype.h> | |
40 | +#include <stdlib.h> | |
41 | +#ifdef HAVE_UNISTD_H | |
42 | +#include <unistd.h> | |
43 | +#endif | |
44 | + | |
45 | #include "readelf.h" | |
46 | -#include "debug.h" | |
47 | ||
48 | -FILE_RCSID("@(#)Id: readelf.c,v 1.22 2002/07/03 18:26:38 christos Exp ") | |
49 | +#ifndef lint | |
50 | +FILE_RCSID("@(#)$Id$") | |
51 | +#endif | |
b6942f9f | 52 | |
0749e45a AM |
53 | -/*@access fmagic @*/ |
54 | +#ifdef ELFCORE | |
55 | +private int dophn_core(struct magic_set *, int, int, int, off_t, int, size_t); | |
56 | +#endif | |
57 | +private int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t); | |
58 | +private int doshn(struct magic_set *, int, int, int, off_t, int, size_t); | |
59 | +private size_t donote(struct magic_set *, unsigned char *, size_t, size_t, int, | |
60 | + int, size_t); | |
b6942f9f JB |
61 | + |
62 | +#define ELF_ALIGN(a) ((((a) + align - 1) / align) * align) | |
0749e45a AM |
63 | + |
64 | +private uint16_t getu16(int, uint16_t); | |
65 | +private uint32_t getu32(int, uint32_t); | |
66 | +private uint64_t getu64(int, uint64_t); | |
67 | ||
68 | -/*@-bounds@*/ | |
69 | -static uint16_t | |
70 | -getu16(const fmagic fm, uint16_t value) | |
71 | - /*@*/ | |
72 | +private uint16_t | |
73 | +getu16(int swap, uint16_t value) | |
74 | { | |
75 | union { | |
76 | uint16_t ui; | |
77 | char c[2]; | |
78 | } retval, tmpval; | |
79 | ||
80 | - if (fm->swap) { | |
81 | + if (swap) { | |
82 | tmpval.ui = value; | |
83 | ||
84 | retval.c[0] = tmpval.c[1]; | |
85 | @@ -30,16 +75,15 @@ | |
86 | return value; | |
87 | } | |
88 | ||
89 | -static uint32_t | |
90 | -getu32(const fmagic fm, uint32_t value) | |
91 | - /*@*/ | |
92 | +private uint32_t | |
93 | +getu32(int swap, uint32_t value) | |
94 | { | |
95 | union { | |
96 | uint32_t ui; | |
97 | char c[4]; | |
98 | } retval, tmpval; | |
99 | ||
100 | - if (fm->swap) { | |
101 | + if (swap) { | |
102 | tmpval.ui = value; | |
b6942f9f | 103 | |
0749e45a AM |
104 | retval.c[0] = tmpval.c[3]; |
105 | @@ -52,16 +96,15 @@ | |
106 | return value; | |
107 | } | |
108 | ||
109 | -static uint64_t | |
110 | -getu64(const fmagic fm, uint64_t value) | |
111 | - /*@*/ | |
112 | +private uint64_t | |
113 | +getu64(int swap, uint64_t value) | |
114 | { | |
115 | union { | |
116 | uint64_t ui; | |
117 | char c[8]; | |
118 | } retval, tmpval; | |
119 | ||
120 | - if (fm->swap) { | |
121 | + if (swap) { | |
122 | tmpval.ui = value; | |
123 | ||
124 | retval.c[0] = tmpval.c[7]; | |
125 | @@ -77,294 +120,65 @@ | |
126 | } else | |
127 | return value; | |
128 | } | |
129 | -/*@=bounds@*/ | |
130 | ||
131 | -#define sh_addr (fm->cls == ELFCLASS32 \ | |
132 | +#define sh_addr (class == ELFCLASS32 \ | |
133 | ? (void *) &sh32 \ | |
134 | : (void *) &sh64) | |
135 | -#define sh_size (fm->cls == ELFCLASS32 \ | |
136 | +#define sh_size (class == ELFCLASS32 \ | |
137 | ? sizeof sh32 \ | |
138 | : sizeof sh64) | |
139 | -#define shs_type (fm->cls == ELFCLASS32 \ | |
140 | - ? getu32(fm, sh32.sh_type) \ | |
141 | - : getu32(fm, sh64.sh_type)) | |
142 | - | |
143 | -#define ph_addr (fm->cls == ELFCLASS32 \ | |
144 | +#define shs_type (class == ELFCLASS32 \ | |
145 | + ? getu32(swap, sh32.sh_type) \ | |
146 | + : getu32(swap, sh64.sh_type)) | |
147 | +#define ph_addr (class == ELFCLASS32 \ | |
148 | ? (void *) &ph32 \ | |
149 | : (void *) &ph64) | |
150 | -#define ph_size (fm->cls == ELFCLASS32 \ | |
151 | +#define ph_size (class == ELFCLASS32 \ | |
152 | ? sizeof ph32 \ | |
153 | : sizeof ph64) | |
154 | -#define ph_type (fm->cls == ELFCLASS32 \ | |
155 | - ? getu32(fm, ph32.p_type) \ | |
156 | - : getu32(fm, ph64.p_type)) | |
157 | -#define ph_offset (fm->cls == ELFCLASS32 \ | |
158 | - ? getu32(fm, ph32.p_offset) \ | |
159 | - : getu64(fm, ph64.p_offset)) | |
b6942f9f JB |
160 | -#define ph_align (fm->cls == ELFCLASS32 \ |
161 | - ? (ph32.p_align ? getu32(fm, ph32.p_align) : 4) \ | |
162 | - : (ph64.p_align ? getu64(fm, ph64.p_align) : 4)) | |
0749e45a AM |
163 | -#define ph_filesz (fm->cls == ELFCLASS32 \ |
164 | - ? getu32(fm, ph32.p_filesz) \ | |
165 | - : getu64(fm, ph64.p_filesz)) | |
166 | - | |
167 | -#define nh_type (fm->cls == ELFCLASS32 \ | |
b6942f9f JB |
168 | - ? getu32(fm, nh32->n_type) \ |
169 | - : getu32(fm, nh64->n_type)) | |
0749e45a | 170 | -#define nh_namesz (fm->cls == ELFCLASS32 \ |
b6942f9f JB |
171 | - ? getu32(fm, nh32->n_namesz) \ |
172 | - : getu32(fm, nh64->n_namesz)) | |
0749e45a | 173 | -#define nh_descsz (fm->cls == ELFCLASS32 \ |
b6942f9f JB |
174 | - ? getu32(fm, nh32->n_descsz) \ |
175 | - : getu32(fm, nh64->n_descsz)) | |
0749e45a AM |
176 | -#define prpsoffsets(i) (fm->cls == ELFCLASS32 \ |
177 | +#define ph_type (class == ELFCLASS32 \ | |
178 | + ? getu32(swap, ph32.p_type) \ | |
179 | + : getu32(swap, ph64.p_type)) | |
180 | +#define ph_offset (class == ELFCLASS32 \ | |
181 | + ? getu32(swap, ph32.p_offset) \ | |
182 | + : getu64(swap, ph64.p_offset)) | |
183 | +#define ph_align (size_t)((class == ELFCLASS32 \ | |
184 | + ? (off_t) (ph32.p_align ? \ | |
185 | + getu32(swap, ph32.p_align) : 4) \ | |
186 | + : (off_t) (ph64.p_align ? \ | |
187 | + getu64(swap, ph64.p_align) : 4))) | |
188 | +#define nh_size (class == ELFCLASS32 \ | |
189 | + ? sizeof nh32 \ | |
190 | + : sizeof nh64) | |
191 | +#define nh_type (class == ELFCLASS32 \ | |
192 | + ? getu32(swap, nh32.n_type) \ | |
193 | + : getu32(swap, nh64.n_type)) | |
194 | +#define nh_namesz (class == ELFCLASS32 \ | |
195 | + ? getu32(swap, nh32.n_namesz) \ | |
196 | + : getu32(swap, nh64.n_namesz)) | |
197 | +#define nh_descsz (class == ELFCLASS32 \ | |
198 | + ? getu32(swap, nh32.n_descsz) \ | |
199 | + : getu32(swap, nh64.n_descsz)) | |
200 | +#define prpsoffsets(i) (class == ELFCLASS32 \ | |
b6942f9f JB |
201 | ? prpsoffsets32[i] \ |
202 | : prpsoffsets64[i]) | |
203 | ||
204 | -/*@-bounds@*/ | |
205 | -static void | |
206 | -doshn(fmagic fm, off_t off, int num, size_t size) | |
207 | - /*@globals fileSystem @*/ | |
208 | - /*@modifies fm, fileSystem @*/ | |
209 | -{ | |
210 | - Elf32_Shdr sh32; | |
211 | - Elf64_Shdr sh64; | |
212 | - | |
213 | - if (size != sh_size) { | |
214 | - error(EXIT_FAILURE, 0, "corrupted program header size.\n"); | |
215 | - /*@notreached@*/ | |
216 | - } | |
217 | - | |
218 | - if (lseek(fm->fd, off, SEEK_SET) == -1) { | |
219 | - error(EXIT_FAILURE, 0, "lseek failed (%s).\n", strerror(errno)); | |
220 | - /*@notreached@*/ | |
221 | - } | |
222 | - | |
223 | - for ( ; num; num--) { | |
224 | - if (read(fm->fd, sh_addr, size) == -1) { | |
225 | - error(EXIT_FAILURE, 0, "read failed (%s).\n", strerror(errno)); | |
226 | - /*@notreached@*/ | |
227 | - } | |
228 | - if (shs_type == SHT_SYMTAB /* || shs_type == SHT_DYNSYM */) { | |
229 | - file_printf(fm, ", not stripped"); | |
230 | - return; | |
231 | - } | |
232 | - } | |
233 | - file_printf(fm, ", stripped"); | |
234 | -} | |
235 | -/*@=bounds@*/ | |
236 | - | |
237 | -/* | |
238 | - * Look through the program headers of an executable image, searching | |
239 | - * for a PT_INTERP section; if one is found, it's dynamically linked, | |
240 | - * otherwise it's statically linked. | |
241 | - */ | |
242 | -/*@-bounds@*/ | |
243 | -static void | |
244 | -dophn_exec(fmagic fm, off_t off, int num, size_t size) | |
245 | - /*@globals fileSystem @*/ | |
246 | - /*@modifies fm, fileSystem @*/ | |
247 | -{ | |
248 | - Elf32_Phdr ph32; | |
249 | - Elf32_Nhdr *nh32 = NULL; | |
250 | - Elf64_Phdr ph64; | |
251 | - Elf64_Nhdr *nh64 = NULL; | |
252 | - char *linking_style = "statically"; | |
253 | - char *shared_libraries = ""; | |
254 | - char nbuf[BUFSIZ]; | |
0749e45a AM |
255 | - int nb; |
256 | - size_t nbufsize, offset, end, noff, doff; | |
257 | - size_t align = (fm->cls == ELFCLASS32 ? 4 : 8); | |
258 | -#define ALIGNED_LEN(len) (((len) + align - 1) & ~(align - 1)) | |
259 | - int printed; | |
b6942f9f JB |
260 | - |
261 | - if (size != ph_size) { | |
262 | - error(EXIT_FAILURE, 0, "corrupted program header size.\n"); | |
263 | - /*@notreached@*/ | |
264 | - } | |
265 | - | |
266 | - if (lseek(fm->fd, off, SEEK_SET) == -1) { | |
267 | - error(EXIT_FAILURE, 0, "lseek failed (%s).\n", strerror(errno)); | |
268 | - /*@notreached@*/ | |
269 | - } | |
270 | - | |
271 | - for ( ; num; num--) { | |
0749e45a AM |
272 | - /* Read the program header data. */ |
273 | - nb = read(fm->fd, ph_addr, size); | |
274 | - if (nb == -1) { | |
b6942f9f JB |
275 | - error(EXIT_FAILURE, 0, "read failed (%s).\n", strerror(errno)); |
276 | - /*@notreached@*/ | |
277 | - } | |
278 | - | |
0749e45a AM |
279 | - /* XXX Elf64 notes cannot be read, so don't attempt for now. */ |
280 | -#if !defined(__i386__) | |
281 | - if (ph_type == PT_NOTE) | |
282 | - break; | |
283 | -#endif | |
284 | - | |
b6942f9f JB |
285 | - switch (ph_type) { |
286 | - case PT_DYNAMIC: | |
287 | - linking_style = "dynamically"; | |
288 | - /*@switchbreak@*/ break; | |
289 | - case PT_INTERP: | |
290 | - shared_libraries = " (uses shared libs)"; | |
291 | - /*@switchbreak@*/ break; | |
292 | - case PT_NOTE: | |
293 | - /* | |
294 | - * This is a PT_NOTE section; loop through all the notes | |
295 | - * in the section. | |
296 | - */ | |
297 | - if (lseek(fm->fd, (off_t) ph_offset, SEEK_SET) == -1) { | |
298 | - error(EXIT_FAILURE, 0, "lseek failed (%s).\n", strerror(errno)); | |
299 | - /*@notreached@*/ | |
300 | - } | |
0749e45a AM |
301 | - |
302 | - /* XXX Read only the notes section. */ | |
303 | - nbufsize = (ph_filesz < sizeof(nbuf) | |
304 | - ? ph_filesz : sizeof(nbuf)); | |
305 | - nb = read(fm->fd, nbuf, nbufsize); | |
306 | - if (nb == -1) { | |
b6942f9f JB |
307 | - error(EXIT_FAILURE, 0, ": " "read failed (%s).\n", |
308 | - strerror(errno)); | |
309 | - /*@notreached@*/ | |
310 | - } | |
311 | - offset = 0; | |
0749e45a | 312 | - printed = 0; |
b6942f9f | 313 | - for (;;) { |
0749e45a AM |
314 | - end = offset + 12; |
315 | - if (end >= nb) | |
b6942f9f | 316 | - /*@innerbreak@*/ break; |
0749e45a | 317 | - |
b6942f9f JB |
318 | - if (fm->cls == ELFCLASS32) |
319 | - nh32 = (Elf32_Nhdr *)&nbuf[offset]; | |
320 | - else | |
321 | - nh64 = (Elf64_Nhdr *)&nbuf[offset]; | |
b6942f9f | 322 | - |
0749e45a | 323 | - offset = end; /* skip note header. */ |
b6942f9f | 324 | - |
0749e45a AM |
325 | - /* XXX Avoid notes that are not 1-16 bytes */ |
326 | - if (nh_namesz <= 0 || nh_descsz <= 0) | |
327 | - break; | |
328 | - if (nh_namesz > 16 || nh_descsz > 16) | |
329 | - break; | |
b6942f9f | 330 | - |
0749e45a AM |
331 | - end = offset + ALIGNED_LEN (nh_namesz) |
332 | - + ALIGNED_LEN (nh_descsz); | |
333 | - if (end > nb) | |
b6942f9f JB |
334 | - /*@innerbreak@*/ break; |
335 | - | |
0749e45a AM |
336 | - noff = offset; |
337 | - doff = ALIGNED_LEN(offset + nh_namesz); | |
338 | - offset = end; | |
339 | - | |
340 | - if (printed) | |
341 | - continue; | |
342 | - | |
b6942f9f | 343 | - if (nh_namesz == 4 && |
0749e45a | 344 | - strcmp(&nbuf[noff], "GNU") == 0 && |
b6942f9f JB |
345 | - nh_type == NT_GNU_VERSION && |
346 | - nh_descsz == 16) { | |
347 | - uint32_t *desc = | |
0749e45a | 348 | - (uint32_t *)&nbuf[doff]; |
b6942f9f | 349 | - |
0749e45a | 350 | - if (!printed) |
b6942f9f JB |
351 | - file_printf(fm, ", for GNU/"); |
352 | - switch (getu32(fm, desc[0])) { | |
353 | - case GNU_OS_LINUX: | |
354 | - file_printf(fm, "Linux"); | |
355 | - /*@switchbreak@*/ break; | |
356 | - case GNU_OS_HURD: | |
357 | - file_printf(fm, "Hurd"); | |
358 | - /*@switchbreak@*/ break; | |
359 | - case GNU_OS_SOLARIS: | |
360 | - file_printf(fm, "Solaris"); | |
361 | - /*@switchbreak@*/ break; | |
362 | - default: | |
363 | - file_printf(fm, "<unknown>"); | |
364 | - /*@switchbreak@*/ break; | |
365 | - } | |
366 | - file_printf(fm, " %d.%d.%d", | |
367 | - getu32(fm, desc[1]), | |
368 | - getu32(fm, desc[2]), | |
369 | - getu32(fm, desc[3])); | |
0749e45a | 370 | - printed = 1; |
b6942f9f JB |
371 | - } |
372 | - | |
373 | - if (nh_namesz == 7 && | |
0749e45a | 374 | - strcmp(&nbuf[noff], "NetBSD") == 0 && |
b6942f9f JB |
375 | - nh_type == NT_NETBSD_VERSION && |
376 | - nh_descsz == 4) { | |
377 | - file_printf(fm, ", for NetBSD"); | |
378 | - /* | |
379 | - * Version number is stuck at 199905, | |
380 | - * and hence is basically content-free. | |
381 | - */ | |
0749e45a | 382 | - printed = 1; |
b6942f9f JB |
383 | - } |
384 | - | |
385 | - if (nh_namesz == 8 && | |
0749e45a | 386 | - strcmp(&nbuf[noff], "FreeBSD") == 0 && |
b6942f9f JB |
387 | - nh_type == NT_FREEBSD_VERSION && |
388 | - nh_descsz == 4) { | |
389 | - uint32_t desc = getu32(fm, | |
0749e45a | 390 | - *(uint32_t *)&nbuf[doff]); |
b6942f9f JB |
391 | - file_printf(fm, ", for FreeBSD"); |
392 | - /* | |
393 | - * Contents is __FreeBSD_version, | |
394 | - * whose relation to OS versions is | |
395 | - * defined by a huge table in the | |
396 | - * Porters' Handbook. Happily, the | |
397 | - * first three digits are the version | |
398 | - * number, at least in versions of | |
399 | - * FreeBSD that use this note. | |
400 | - */ | |
401 | - | |
402 | - file_printf(fm, " %d.%d", desc / 100000, | |
403 | - desc / 10000 % 10); | |
404 | - if (desc / 1000 % 10 > 0) | |
405 | - file_printf(fm, ".%d", | |
406 | - desc / 1000 % 10); | |
0749e45a | 407 | - printed = 1; |
b6942f9f JB |
408 | - } |
409 | - | |
410 | - if (nh_namesz == 8 && | |
0749e45a | 411 | - strcmp(&nbuf[noff], "OpenBSD") == 0 && |
b6942f9f JB |
412 | - nh_type == NT_OPENBSD_VERSION && |
413 | - nh_descsz == 4) { | |
414 | - file_printf(fm, ", for OpenBSD"); | |
415 | - /* Content of note is always 0 */ | |
0749e45a | 416 | - printed = 1; |
b6942f9f JB |
417 | - } |
418 | - } | |
419 | - if ((lseek(fm->fd, ph_offset + offset, SEEK_SET)) == -1) { | |
420 | - error(EXIT_FAILURE, 0, "lseek failed (%s).\n", strerror(errno)); | |
421 | - /*@notreached@*/ | |
422 | - } | |
423 | - /*@switchbreak@*/ break; | |
424 | - } | |
425 | - } | |
426 | - file_printf(fm, ", %s linked%s", linking_style, shared_libraries); | |
427 | -} | |
428 | -/*@=bounds@*/ | |
429 | - | |
430 | #ifdef ELFCORE | |
0749e45a AM |
431 | -/*@unchecked@*/ /*@observer@*/ |
432 | -static size_t prpsoffsets32[] = { | |
433 | +size_t prpsoffsets32[] = { | |
434 | 8, /* FreeBSD */ | |
435 | 28, /* Linux 2.0.36 */ | |
436 | 32, /* Linux (I forget which kernel version) */ | |
437 | - 84 /* SunOS 5.x */ | |
438 | + 84, /* SunOS 5.x */ | |
439 | }; | |
440 | ||
441 | -/*@unchecked@*/ /*@observer@*/ | |
442 | -static size_t prpsoffsets64[] = { | |
443 | - 120 /* SunOS 5.x, 64-bit */ | |
444 | +size_t prpsoffsets64[] = { | |
445 | + 120, /* SunOS 5.x, 64-bit */ | |
446 | }; | |
447 | ||
448 | #define NOFFSETS32 (sizeof prpsoffsets32 / sizeof prpsoffsets32[0]) | |
449 | #define NOFFSETS64 (sizeof prpsoffsets64 / sizeof prpsoffsets64[0]) | |
450 | ||
451 | -#define NOFFSETS (fm->cls == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64) | |
452 | +#define NOFFSETS (class == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64) | |
453 | ||
454 | /* | |
455 | * Look through the program headers of an executable image, searching | |
456 | @@ -391,46 +205,38 @@ | |
457 | #define OS_STYLE_FREEBSD 1 | |
458 | #define OS_STYLE_NETBSD 2 | |
459 | ||
460 | -/*@unchecked@*/ /*@observer@*/ | |
461 | -static const char *os_style_names[] = { | |
462 | +private const char *os_style_names[] = { | |
463 | "SVR4", | |
464 | "FreeBSD", | |
465 | "NetBSD", | |
466 | }; | |
467 | ||
468 | -/*@-bounds@*/ | |
469 | -static void | |
470 | -dophn_core(fmagic fm, off_t off, int num, size_t size) | |
471 | - /*@globals fileSystem @*/ | |
472 | - /*@modifies fm, fileSystem @*/ | |
473 | +private int | |
474 | +dophn_core(struct magic_set *ms, int class, int swap, int fd, off_t off, | |
475 | + int num, size_t size) | |
b6942f9f JB |
476 | { |
477 | Elf32_Phdr ph32; | |
478 | - Elf32_Nhdr *nh32 = NULL; | |
479 | Elf64_Phdr ph64; | |
480 | - Elf64_Nhdr *nh64 = NULL; | |
481 | - size_t offset, nameoffset, noffset, reloffset; | |
482 | - unsigned char c; | |
483 | - int i, j; | |
484 | - char nbuf[BUFSIZ]; | |
0749e45a | 485 | - int nb; |
b6942f9f JB |
486 | - int os_style = -1; |
487 | + size_t offset; | |
488 | + unsigned char nbuf[BUFSIZ]; | |
489 | + ssize_t bufsize; | |
490 | ||
491 | if (size != ph_size) { | |
0749e45a AM |
492 | - error(EXIT_FAILURE, 0, "corrupted program header size.\n"); |
493 | - /*@notreached@*/ | |
494 | + if (file_printf(ms, ", corrupted program header size") == -1) | |
495 | + return -1; | |
496 | + return 0; | |
497 | } | |
498 | - | |
499 | /* | |
b6942f9f JB |
500 | * Loop through all the program headers. |
501 | */ | |
502 | for ( ; num; num--) { | |
503 | - if (lseek(fm->fd, off, SEEK_SET) == -1) { | |
0749e45a AM |
504 | - error(EXIT_FAILURE, 0, "lseek failed (%s).\n", strerror(errno)); |
505 | - /*@notreached@*/ | |
506 | - } | |
b6942f9f | 507 | - if (read(fm->fd, ph_addr, size) == -1) { |
0749e45a AM |
508 | - error(EXIT_FAILURE, 0, "read failed (%s).\n", strerror(errno)); |
509 | - /*@notreached@*/ | |
510 | + if (lseek(fd, off, SEEK_SET) == (off_t)-1) { | |
511 | + file_badseek(ms); | |
512 | + return -1; | |
513 | + } | |
514 | + if (read(fd, ph_addr, ph_size) == -1) { | |
515 | + file_badread(ms); | |
516 | + return -1; | |
b6942f9f | 517 | } |
0749e45a AM |
518 | off += size; |
519 | if (ph_type != PT_NOTE) | |
520 | @@ -440,192 +246,475 @@ | |
b6942f9f JB |
521 | * This is a PT_NOTE section; loop through all the notes |
522 | * in the section. | |
523 | */ | |
524 | - if (lseek(fm->fd, (off_t) ph_offset, SEEK_SET) == -1) { | |
0749e45a AM |
525 | - error(EXIT_FAILURE, 0, "lseek failed (%s).\n", strerror(errno)); |
526 | - /*@notreached@*/ | |
527 | - } | |
528 | - nb = read(fm->fd, nbuf, BUFSIZ); | |
529 | - if (nb == -1) { | |
530 | - error(EXIT_FAILURE, 0, ": " "read failed (%s).\n", strerror(errno)); | |
531 | - /*@notreached@*/ | |
532 | + if (lseek(fd, (off_t) ph_offset, SEEK_SET) == (off_t)-1) { | |
533 | + file_badseek(ms); | |
534 | + return -1; | |
535 | + } | |
536 | + bufsize = read(fd, nbuf, BUFSIZ); | |
537 | + if (bufsize == -1) { | |
538 | + file_badread(ms); | |
539 | + return -1; | |
b6942f9f JB |
540 | } |
541 | offset = 0; | |
542 | for (;;) { | |
0749e45a AM |
543 | - if (offset >= nb) |
544 | - /*@innerbreak@*/ break; | |
b6942f9f JB |
545 | - if (fm->cls == ELFCLASS32) |
546 | - nh32 = (Elf32_Nhdr *)&nbuf[offset]; | |
547 | - else | |
548 | - nh64 = (Elf64_Nhdr *)&nbuf[offset]; | |
0749e45a AM |
549 | - offset += 12; |
550 | + if (offset >= (size_t)bufsize) | |
551 | + break; | |
552 | + offset = donote(ms, nbuf, offset, (size_t)bufsize, | |
553 | + class, swap, 4); | |
554 | + if (offset == 0) | |
555 | + break; | |
b6942f9f JB |
556 | |
557 | - /* | |
558 | - * Check whether this note has the name "CORE" or | |
559 | - * "FreeBSD", or "NetBSD-CORE". | |
560 | - */ | |
0749e45a | 561 | - if (offset + nh_namesz >= nb) { |
b6942f9f JB |
562 | - /* |
563 | - * We're past the end of the buffer. | |
564 | - */ | |
565 | - /*@innerbreak@*/ break; | |
b6942f9f JB |
566 | + } |
567 | + } | |
0749e45a | 568 | + return 0; |
b6942f9f | 569 | +} |
b6942f9f JB |
570 | +#endif |
571 | + | |
0749e45a AM |
572 | +private size_t |
573 | +donote(struct magic_set *ms, unsigned char *nbuf, size_t offset, size_t size, | |
574 | + int class, int swap, size_t align) | |
b6942f9f JB |
575 | +{ |
576 | + Elf32_Nhdr nh32; | |
577 | + Elf64_Nhdr nh64; | |
578 | + size_t noff, doff; | |
579 | +#ifdef ELFCORE | |
580 | + int os_style = -1; | |
581 | +#endif | |
0749e45a AM |
582 | + uint32_t namesz, descsz; |
583 | + | |
584 | + if (class == ELFCLASS32) | |
b6942f9f JB |
585 | + memcpy(&nh32, &nbuf[offset], sizeof(nh32)); |
586 | + else | |
587 | + memcpy(&nh64, &nbuf[offset], sizeof(nh64)); | |
588 | + offset += nh_size; | |
0749e45a AM |
589 | + |
590 | + namesz = nh_namesz; | |
591 | + descsz = nh_descsz; | |
592 | + if ((namesz == 0) && (descsz == 0)) { | |
b6942f9f JB |
593 | + /* |
594 | + * We're out of note headers. | |
595 | + */ | |
596 | + return offset; | |
597 | + } | |
598 | + | |
0749e45a AM |
599 | + if (namesz & 0x80000000) { |
600 | + (void)file_printf(ms, ", bad note name size 0x%lx", | |
601 | + (unsigned long)namesz); | |
602 | + return offset; | |
603 | + } | |
604 | + | |
605 | + if (descsz & 0x80000000) { | |
606 | + (void)file_printf(ms, ", bad note description size 0x%lx", | |
607 | + (unsigned long)descsz); | |
608 | + return offset; | |
609 | + } | |
610 | + | |
611 | + | |
b6942f9f | 612 | + noff = offset; |
0749e45a | 613 | + doff = ELF_ALIGN(offset + namesz); |
b6942f9f | 614 | + |
0749e45a | 615 | + if (offset + namesz >= size) { |
b6942f9f JB |
616 | + /* |
617 | + * We're past the end of the buffer. | |
618 | + */ | |
619 | + return doff; | |
620 | + } | |
621 | + | |
0749e45a AM |
622 | + offset = ELF_ALIGN(doff + descsz); |
623 | + if (offset + descsz >= size) { | |
b6942f9f | 624 | + return offset; |
0749e45a | 625 | + } |
b6942f9f | 626 | + |
0749e45a AM |
627 | + if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && |
628 | + nh_type == NT_GNU_VERSION && descsz == 16) { | |
b6942f9f JB |
629 | + uint32_t desc[4]; |
630 | + (void)memcpy(desc, &nbuf[doff], sizeof(desc)); | |
631 | + | |
0749e45a AM |
632 | + if (file_printf(ms, ", for GNU/") == -1) |
633 | + return size; | |
634 | + switch (getu32(swap, desc[0])) { | |
b6942f9f | 635 | + case GNU_OS_LINUX: |
0749e45a AM |
636 | + if (file_printf(ms, "Linux") == -1) |
637 | + return size; | |
b6942f9f JB |
638 | + break; |
639 | + case GNU_OS_HURD: | |
0749e45a AM |
640 | + if (file_printf(ms, "Hurd") == -1) |
641 | + return size; | |
b6942f9f JB |
642 | + break; |
643 | + case GNU_OS_SOLARIS: | |
0749e45a AM |
644 | + if (file_printf(ms, "Solaris") == -1) |
645 | + return size; | |
b6942f9f JB |
646 | + break; |
647 | + default: | |
0749e45a AM |
648 | + if (file_printf(ms, "<unknown>") == -1) |
649 | + return size; | |
b6942f9f | 650 | + } |
0749e45a AM |
651 | + if (file_printf(ms, " %d.%d.%d", getu32(swap, desc[1]), |
652 | + getu32(swap, desc[2]), getu32(swap, desc[3])) == -1) | |
653 | + return size; | |
b6942f9f JB |
654 | + return size; |
655 | + } | |
656 | + | |
0749e45a AM |
657 | + if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0 && |
658 | + nh_type == NT_NETBSD_VERSION && descsz == 4) { | |
b6942f9f JB |
659 | + uint32_t desc; |
660 | + (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); | |
0749e45a | 661 | + desc = getu32(swap, desc); |
b6942f9f | 662 | + |
0749e45a AM |
663 | + if (file_printf(ms, ", for NetBSD") == -1) |
664 | + return size; | |
b6942f9f JB |
665 | + /* |
666 | + * The version number used to be stuck as 199905, and was thus | |
667 | + * basically content-free. Newer versions of NetBSD have fixed | |
668 | + * this and now use the encoding of __NetBSD_Version__: | |
669 | + * | |
670 | + * MMmmrrpp00 | |
671 | + * | |
672 | + * M = major version | |
673 | + * m = minor version | |
674 | + * r = release ["",A-Z,Z[A-Z] but numeric] | |
675 | + * p = patchlevel | |
676 | + */ | |
677 | + if (desc > 100000000U) { | |
678 | + u_int ver_patch = (desc / 100) % 100; | |
679 | + u_int ver_rel = (desc / 10000) % 100; | |
680 | + u_int ver_min = (desc / 1000000) % 100; | |
681 | + u_int ver_maj = desc / 100000000; | |
682 | + | |
0749e45a AM |
683 | + if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1) |
684 | + return size; | |
b6942f9f | 685 | + if (ver_rel == 0 && ver_patch != 0) { |
0749e45a AM |
686 | + if (file_printf(ms, ".%u", ver_patch) == -1) |
687 | + return size; | |
b6942f9f JB |
688 | + } else if (ver_rel != 0) { |
689 | + while (ver_rel > 26) { | |
0749e45a | 690 | + file_printf(ms, "Z"); |
b6942f9f JB |
691 | + ver_rel -= 26; |
692 | + } | |
0749e45a | 693 | + file_printf(ms, "%c", 'A' + ver_rel - 1); |
b6942f9f JB |
694 | } |
695 | + } | |
696 | + return size; | |
697 | + } | |
698 | ||
0749e45a AM |
699 | - nameoffset = offset; |
700 | - offset += nh_namesz; | |
701 | - offset = ((offset + 3)/4)*4; | |
702 | + if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0 && | |
703 | + nh_type == NT_FREEBSD_VERSION && descsz == 4) { | |
b6942f9f JB |
704 | + uint32_t desc; |
705 | + (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); | |
0749e45a AM |
706 | + desc = getu32(swap, desc); |
707 | + if (file_printf(ms, ", for FreeBSD") == -1) | |
708 | + return size; | |
709 | ||
710 | - /* | |
711 | - * Sigh. The 2.0.36 kernel in Debian 2.1, at | |
712 | - * least, doesn't correctly implement name | |
713 | - * sections, in core dumps, as specified by | |
714 | - * the "Program Linking" section of "UNIX(R) System | |
715 | - * V Release 4 Programmer's Guide: ANSI C and | |
716 | - * Programming Support Tools", because my copy | |
717 | - * clearly says "The first 'namesz' bytes in 'name' | |
718 | - * contain a *null-terminated* [emphasis mine] | |
719 | - * character representation of the entry's owner | |
720 | - * or originator", but the 2.0.36 kernel code | |
721 | - * doesn't include the terminating null in the | |
722 | - * name.... | |
723 | - */ | |
724 | - if (os_style == -1) { | |
725 | - if ((nh_namesz == 4 && | |
726 | - strncmp(&nbuf[nameoffset], | |
727 | - "CORE", 4) == 0) || | |
728 | - (nh_namesz == 5 && | |
729 | - strcmp(&nbuf[nameoffset], | |
730 | - "CORE") == 0)) { | |
731 | - os_style = OS_STYLE_SVR4; | |
732 | - } else | |
733 | - if ((nh_namesz == 8 && | |
734 | - strcmp(&nbuf[nameoffset], | |
735 | - "FreeBSD") == 0)) { | |
736 | - os_style = OS_STYLE_FREEBSD; | |
737 | - } else | |
738 | - if ((nh_namesz >= 11 && | |
739 | - strncmp(&nbuf[nameoffset], | |
740 | - "NetBSD-CORE", 11) == 0)) { | |
741 | - os_style = OS_STYLE_NETBSD; | |
742 | - } else | |
743 | - /*@innercontinue@*/ continue; | |
744 | - file_printf(fm, ", %s-style", os_style_names[os_style]); | |
b6942f9f | 745 | + /* |
0749e45a AM |
746 | + * Contents is __FreeBSD_version, whose relation to OS |
747 | + * versions is defined by a huge table in the Porters' | |
748 | + * Handbook. For up to 5.x, the first three digits are | |
749 | + * the version number. For 5.x and higher, the scheme | |
750 | + * is: <major><two digit minor> <0 if release branch, | |
751 | + * otherwise 1>xx | |
b6942f9f | 752 | + */ |
0749e45a AM |
753 | + if (desc / 100000 < 5) { |
754 | + if (file_printf(ms, " %d.%d", desc / 100000, | |
755 | + desc / 10000 % 10) == -1) | |
756 | + return size; | |
757 | + if (desc / 1000 % 10 > 0) | |
758 | + if (file_printf(ms, ".%d", desc / 1000 % 10) | |
759 | + == -1) | |
760 | + return size; | |
761 | + } else { | |
762 | + if (file_printf(ms, " %d.%d", desc / 100000, | |
763 | + desc / 1000 % 100) == -1) | |
764 | + return size; | |
765 | + desc %= 1000; | |
766 | + if (desc > 100) { | |
767 | + if (file_printf(ms, "-CURRENT (rev %d)", | |
768 | + desc % 100) == -1) | |
769 | + return size; | |
770 | + } else if (desc != 0) { | |
771 | + if (file_printf(ms, ".%d", desc / 10) == -1) | |
772 | + return size; | |
773 | } | |
774 | + } | |
b6942f9f JB |
775 | + return size; |
776 | + } | |
777 | ||
0749e45a AM |
778 | - if (os_style == OS_STYLE_NETBSD && |
779 | - nh_type == NT_NETBSD_CORE_PROCINFO) { | |
780 | - uint32_t signo; | |
781 | + if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 && | |
782 | + nh_type == NT_OPENBSD_VERSION && descsz == 4) { | |
783 | + if (file_printf(ms, ", for OpenBSD") == -1) | |
784 | + return size; | |
b6942f9f JB |
785 | + /* Content of note is always 0 */ |
786 | + return size; | |
787 | + } | |
0749e45a | 788 | |
b6942f9f JB |
789 | + /* |
790 | + * Sigh. The 2.0.36 kernel in Debian 2.1, at | |
791 | + * least, doesn't correctly implement name | |
792 | + * sections, in core dumps, as specified by | |
793 | + * the "Program Linking" section of "UNIX(R) System | |
794 | + * V Release 4 Programmer's Guide: ANSI C and | |
795 | + * Programming Support Tools", because my copy | |
796 | + * clearly says "The first 'namesz' bytes in 'name' | |
797 | + * contain a *null-terminated* [emphasis mine] | |
798 | + * character representation of the entry's owner | |
799 | + * or originator", but the 2.0.36 kernel code | |
800 | + * doesn't include the terminating null in the | |
801 | + * name.... | |
802 | + */ | |
0749e45a AM |
803 | + if ((namesz == 4 && strncmp((char *)&nbuf[noff], "CORE", 4) == 0) || |
804 | + (namesz == 5 && strcmp((char *)&nbuf[noff], "CORE") == 0)) { | |
b6942f9f JB |
805 | + os_style = OS_STYLE_SVR4; |
806 | + } | |
807 | + | |
0749e45a | 808 | + if ((namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0)) { |
b6942f9f JB |
809 | + os_style = OS_STYLE_FREEBSD; |
810 | + } | |
811 | + | |
0749e45a | 812 | + if ((namesz >= 11 && strncmp((char *)&nbuf[noff], "NetBSD-CORE", 11) |
b6942f9f JB |
813 | + == 0)) { |
814 | + os_style = OS_STYLE_NETBSD; | |
815 | + } | |
816 | + | |
817 | +#ifdef ELFCORE | |
818 | + if (os_style != -1) | |
0749e45a AM |
819 | + if (file_printf(ms, ", %s-style", os_style_names[os_style]) == -1) |
820 | + return size; | |
b6942f9f JB |
821 | + |
822 | + if (os_style == OS_STYLE_NETBSD && nh_type == NT_NETBSD_CORE_PROCINFO) { | |
823 | + uint32_t signo; | |
824 | + /* | |
825 | + * Extract the program name. It is at | |
826 | + * offset 0x7c, and is up to 32-bytes, | |
827 | + * including the terminating NUL. | |
828 | + */ | |
0749e45a AM |
829 | + if (file_printf(ms, ", from '%.31s'", &nbuf[doff + 0x7c]) == -1) |
830 | + return size; | |
b6942f9f JB |
831 | + |
832 | + /* | |
833 | + * Extract the signal number. It is at | |
834 | + * offset 0x08. | |
835 | + */ | |
836 | + memcpy(&signo, &nbuf[doff + 0x08], | |
837 | + sizeof(signo)); | |
0749e45a AM |
838 | + if (file_printf(ms, " (signal %u)", getu32(swap, signo)) == -1) |
839 | + return size; | |
b6942f9f JB |
840 | + return size; |
841 | + } else if (os_style != OS_STYLE_NETBSD && nh_type == NT_PRPSINFO) { | |
842 | + size_t i, j; | |
843 | + unsigned char c; | |
844 | + /* | |
845 | + * Extract the program name. We assume | |
846 | + * it to be 16 characters (that's what it | |
847 | + * is in SunOS 5.x and Linux). | |
848 | + * | |
849 | + * Unfortunately, it's at a different offset | |
850 | + * in varous OSes, so try multiple offsets. | |
851 | + * If the characters aren't all printable, | |
852 | + * reject it. | |
853 | + */ | |
854 | + for (i = 0; i < NOFFSETS; i++) { | |
855 | + size_t reloffset = prpsoffsets(i); | |
856 | + size_t noffset = doff + reloffset; | |
857 | + for (j = 0; j < 16; j++, noffset++, reloffset++) { | |
858 | /* | |
859 | - * Extract the program name. It is at | |
860 | - * offset 0x7c, and is up to 32-bytes, | |
861 | - * including the terminating NUL. | |
862 | - */ | |
863 | - file_printf(fm, ", from '%.31s'", &nbuf[offset + 0x7c]); | |
864 | - | |
865 | - /* | |
866 | - * Extract the signal number. It is at | |
867 | - * offset 0x08. | |
868 | + * Make sure we're not past | |
869 | + * the end of the buffer; if | |
870 | + * we are, just give up. | |
871 | */ | |
872 | - memcpy(&signo, &nbuf[offset + 0x08], | |
873 | - sizeof(signo)); | |
874 | - file_printf(fm, " (signal %u)", getu32(fm, signo)); | |
875 | - } else | |
876 | - if (os_style != OS_STYLE_NETBSD && | |
877 | - nh_type == NT_PRPSINFO) { | |
878 | + if (noffset >= size) | |
879 | + goto tryanother; | |
880 | + | |
881 | /* | |
882 | - * Extract the program name. We assume | |
883 | - * it to be 16 characters (that's what it | |
884 | - * is in SunOS 5.x and Linux). | |
885 | - * | |
886 | - * Unfortunately, it's at a different offset | |
887 | - * in varous OSes, so try multiple offsets. | |
888 | - * If the characters aren't all printable, | |
889 | - * reject it. | |
890 | + * Make sure we're not past | |
891 | + * the end of the contents; | |
892 | + * if we are, this obviously | |
893 | + * isn't the right offset. | |
894 | */ | |
895 | - for (i = 0; i < NOFFSETS; i++) { | |
896 | - reloffset = prpsoffsets(i); | |
897 | - noffset = offset + reloffset; | |
898 | - for (j = 0; j < 16; | |
899 | - j++, noffset++, reloffset++) { | |
900 | - /* | |
901 | - * Make sure we're not past | |
902 | - * the end of the buffer; if | |
903 | - * we are, just give up. | |
904 | - */ | |
0749e45a | 905 | - if (noffset >= nb) |
b6942f9f JB |
906 | - goto tryanother; |
907 | - | |
908 | - /* | |
909 | - * Make sure we're not past | |
910 | - * the end of the contents; | |
911 | - * if we are, this obviously | |
912 | - * isn't the right offset. | |
913 | - */ | |
914 | - if (reloffset >= nh_descsz) | |
915 | - goto tryanother; | |
916 | - | |
917 | - c = nbuf[noffset]; | |
918 | - if (c == '\0') { | |
919 | - /* | |
920 | - * A '\0' at the | |
921 | - * beginning is | |
922 | - * obviously wrong. | |
923 | - * Any other '\0' | |
924 | - * means we're done. | |
925 | - */ | |
926 | - if (j == 0) | |
927 | - goto tryanother; | |
928 | - else | |
929 | - /*@innerbreak@*/ break; | |
930 | - } else { | |
931 | - /* | |
932 | - * A nonprintable | |
933 | - * character is also | |
934 | - * wrong. | |
935 | - */ | |
936 | -#define isquote(c) (strchr("'\"`", (c)) != NULL) | |
937 | - if (!isprint(c) || | |
938 | - isquote(c)) | |
939 | - goto tryanother; | |
940 | - } | |
941 | - } | |
0749e45a | 942 | + if (reloffset >= descsz) |
b6942f9f JB |
943 | + goto tryanother; |
944 | ||
945 | + c = nbuf[noffset]; | |
946 | + if (c == '\0') { | |
947 | /* | |
948 | - * Well, that worked. | |
949 | + * A '\0' at the | |
950 | + * beginning is | |
951 | + * obviously wrong. | |
952 | + * Any other '\0' | |
953 | + * means we're done. | |
954 | */ | |
955 | - file_printf(fm, ", from '%.16s'", | |
956 | - &nbuf[offset + prpsoffsets(i)]); | |
957 | - /*@innerbreak@*/ break; | |
958 | - | |
959 | - tryanother: | |
960 | - ; | |
961 | + if (j == 0) | |
962 | + goto tryanother; | |
963 | + else | |
964 | + break; | |
965 | + } else { | |
966 | + /* | |
967 | + * A nonprintable | |
968 | + * character is also | |
969 | + * wrong. | |
970 | + */ | |
971 | +#define isquote(c) (strchr("'\"`", (c)) != NULL) | |
972 | + if (!isprint(c) || isquote(c)) | |
973 | + goto tryanother; | |
974 | } | |
975 | - /*@innerbreak@*/ break; | |
976 | } | |
977 | - offset += nh_descsz; | |
978 | - offset = ((offset + 3)/4)*4; | |
979 | + | |
980 | + /* | |
981 | + * Well, that worked. | |
982 | + */ | |
0749e45a AM |
983 | + if (file_printf(ms, ", from '%.16s'", |
984 | + &nbuf[doff + prpsoffsets(i)]) == -1) | |
985 | + return size; | |
b6942f9f JB |
986 | + return size; |
987 | + | |
988 | + tryanother: | |
989 | + ; | |
0749e45a | 990 | } |
b6942f9f | 991 | + return offset; |
0749e45a AM |
992 | } |
993 | -} | |
994 | -/*@=bounds@*/ | |
995 | #endif | |
b6942f9f JB |
996 | + return offset; |
997 | +} | |
0749e45a AM |
998 | |
999 | -/*@-bounds@*/ | |
1000 | -void | |
1001 | -fmagicE(fmagic fm) | |
1002 | +private int | |
1003 | +doshn(struct magic_set *ms, int class, int swap, int fd, off_t off, int num, | |
1004 | + size_t size) | |
b6942f9f JB |
1005 | +{ |
1006 | + Elf32_Shdr sh32; | |
1007 | + Elf64_Shdr sh64; | |
1008 | + | |
1009 | + if (size != sh_size) { | |
0749e45a AM |
1010 | + if (file_printf(ms, ", corrupted section header size") == -1) |
1011 | + return -1; | |
1012 | + return 0; | |
b6942f9f JB |
1013 | + } |
1014 | + | |
0749e45a AM |
1015 | + if (lseek(fd, off, SEEK_SET) == (off_t)-1) { |
1016 | + file_badseek(ms); | |
1017 | + return -1; | |
b6942f9f JB |
1018 | + } |
1019 | + | |
1020 | + for ( ; num; num--) { | |
0749e45a AM |
1021 | + if (read(fd, sh_addr, sh_size) == -1) { |
1022 | + file_badread(ms); | |
1023 | + return -1; | |
b6942f9f JB |
1024 | + } |
1025 | + if (shs_type == SHT_SYMTAB /* || shs_type == SHT_DYNSYM */) { | |
0749e45a AM |
1026 | + if (file_printf(ms, ", not stripped") == -1) |
1027 | + return -1; | |
1028 | + return 0; | |
b6942f9f JB |
1029 | + } |
1030 | + } | |
0749e45a AM |
1031 | + if (file_printf(ms, ", stripped") == -1) |
1032 | + return -1; | |
1033 | + return 0; | |
b6942f9f | 1034 | +} |
b6942f9f JB |
1035 | + |
1036 | +/* | |
1037 | + * Look through the program headers of an executable image, searching | |
1038 | + * for a PT_INTERP section; if one is found, it's dynamically linked, | |
1039 | + * otherwise it's statically linked. | |
1040 | + */ | |
0749e45a AM |
1041 | +private int |
1042 | +dophn_exec(struct magic_set *ms, int class, int swap, int fd, off_t off, | |
1043 | + int num, size_t size) | |
b6942f9f JB |
1044 | +{ |
1045 | + Elf32_Phdr ph32; | |
1046 | + Elf64_Phdr ph64; | |
1047 | + const char *linking_style = "statically"; | |
1048 | + const char *shared_libraries = ""; | |
1049 | + unsigned char nbuf[BUFSIZ]; | |
1050 | + int bufsize; | |
0749e45a | 1051 | + size_t offset, align; |
b6942f9f JB |
1052 | + off_t savedoffset; |
1053 | + | |
1054 | + if (size != ph_size) { | |
0749e45a AM |
1055 | + if (file_printf(ms, ", corrupted program header size") == -1) |
1056 | + return -1; | |
1057 | + return 0; | |
b6942f9f | 1058 | + } |
0749e45a AM |
1059 | + if (lseek(fd, off, SEEK_SET) == (off_t)-1) { |
1060 | + file_badseek(ms); | |
1061 | + return -1; | |
b6942f9f JB |
1062 | + } |
1063 | + | |
1064 | + for ( ; num; num--) { | |
0749e45a AM |
1065 | + if (read(fd, ph_addr, ph_size) == -1) { |
1066 | + file_badread(ms); | |
1067 | + return -1; | |
b6942f9f | 1068 | + } |
0749e45a AM |
1069 | + if ((savedoffset = lseek(fd, (off_t)0, SEEK_CUR)) == (off_t)-1) { |
1070 | + file_badseek(ms); | |
1071 | + return -1; | |
b6942f9f JB |
1072 | + } |
1073 | + | |
1074 | + switch (ph_type) { | |
1075 | + case PT_DYNAMIC: | |
1076 | + linking_style = "dynamically"; | |
0749e45a | 1077 | + break; |
b6942f9f JB |
1078 | + case PT_INTERP: |
1079 | + shared_libraries = " (uses shared libs)"; | |
0749e45a | 1080 | + break; |
b6942f9f | 1081 | + case PT_NOTE: |
0749e45a AM |
1082 | + if ((align = ph_align) & 0x80000000) { |
1083 | + if (file_printf(ms, | |
1084 | + ", invalid note alignment 0x%lx", | |
1085 | + (unsigned long)align) == -1) | |
1086 | + return -1; | |
1087 | + align = 4; | |
1088 | + } | |
b6942f9f JB |
1089 | + /* |
1090 | + * This is a PT_NOTE section; loop through all the notes | |
1091 | + * in the section. | |
1092 | + */ | |
0749e45a AM |
1093 | + if (lseek(fd, (off_t) ph_offset, SEEK_SET) |
1094 | + == (off_t)-1) { | |
1095 | + file_badseek(ms); | |
1096 | + return -1; | |
b6942f9f | 1097 | + } |
0749e45a | 1098 | + bufsize = read(fd, nbuf, sizeof(nbuf)); |
b6942f9f | 1099 | + if (bufsize == -1) { |
0749e45a AM |
1100 | + file_badread(ms); |
1101 | + return -1; | |
b6942f9f JB |
1102 | + } |
1103 | + offset = 0; | |
1104 | + for (;;) { | |
1105 | + if (offset >= (size_t)bufsize) | |
0749e45a AM |
1106 | + break; |
1107 | + offset = donote(ms, nbuf, offset, | |
1108 | + (size_t)bufsize, class, swap, align); | |
1109 | + if (offset == 0) | |
1110 | + break; | |
b6942f9f | 1111 | + } |
0749e45a AM |
1112 | + if (lseek(fd, savedoffset + offset, SEEK_SET) |
1113 | + == (off_t)-1) { | |
1114 | + file_badseek(ms); | |
1115 | + return -1; | |
b6942f9f | 1116 | + } |
0749e45a AM |
1117 | + break; |
1118 | + } | |
1119 | + } | |
1120 | + if (file_printf(ms, ", %s linked%s", linking_style, shared_libraries) | |
1121 | + == -1) | |
1122 | + return -1; | |
1123 | + return 0; | |
1124 | +} | |
1125 | + | |
1126 | + | |
1127 | +protected int | |
1128 | +file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf, | |
1129 | + size_t nbytes) | |
1130 | { | |
1131 | -/*@-sizeoftype@*/ | |
1132 | union { | |
1133 | int32_t l; | |
1134 | char c[sizeof (int32_t)]; | |
1135 | } u; | |
1136 | -/*@=sizeoftype@*/ | |
1137 | + int class; | |
1138 | + int swap; | |
1139 | ||
1140 | /* | |
1141 | - * If we can't seek, it must be a pipe, socket or fifo. | |
1142 | + * If we cannot seek, it must be a pipe, socket or fifo. | |
1143 | */ | |
1144 | - if((lseek(fm->fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE)) | |
1145 | - fm->fd = file_pipe2file(fm->fd, fm->buf, fm->nb); | |
1146 | + if((lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE)) | |
1147 | + fd = file_pipe2file(ms, fd, buf, nbytes); | |
1148 | ||
1149 | /* | |
1150 | * ELF executables have multiple section headers in arbitrary | |
1151 | @@ -633,96 +722,101 @@ | |
1152 | * Instead we traverse thru all section headers until a symbol table | |
1153 | * one is found or else the binary is stripped. | |
1154 | */ | |
1155 | - if (fm->buf[EI_MAG0] != ELFMAG0 | |
1156 | - || (fm->buf[EI_MAG1] != ELFMAG1 && fm->buf[EI_MAG1] != OLFMAG1) | |
1157 | - || fm->buf[EI_MAG2] != ELFMAG2 || fm->buf[EI_MAG3] != ELFMAG3) | |
1158 | - return; | |
1159 | + if (buf[EI_MAG0] != ELFMAG0 | |
1160 | + || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1) | |
1161 | + || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3) | |
1162 | + return 0; | |
1163 | ||
1164 | - fm->cls = fm->buf[EI_CLASS]; | |
1165 | ||
1166 | - if (fm->cls == ELFCLASS32) { | |
1167 | + class = buf[4]; | |
1168 | + | |
1169 | + if (class == ELFCLASS32) { | |
1170 | Elf32_Ehdr elfhdr; | |
1171 | - if (fm->nb <= sizeof (elfhdr)) | |
1172 | - return; | |
1173 | + if (nbytes <= sizeof (Elf32_Ehdr)) | |
1174 | + return 0; | |
1175 | ||
1176 | ||
1177 | u.l = 1; | |
1178 | - (void) memcpy(&elfhdr, fm->buf, sizeof elfhdr); | |
1179 | -/*@-sizeoftype@*/ | |
1180 | - fm->swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[EI_DATA]; | |
1181 | -/*@=sizeoftype@*/ | |
1182 | + (void) memcpy(&elfhdr, buf, sizeof elfhdr); | |
1183 | + swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[5]; | |
1184 | ||
1185 | - if (getu16(fm, elfhdr.e_type) == ET_CORE) | |
1186 | + if (getu16(swap, elfhdr.e_type) == ET_CORE) { | |
1187 | #ifdef ELFCORE | |
1188 | - dophn_core(fm, | |
1189 | - getu32(fm, elfhdr.e_phoff), | |
1190 | - getu16(fm, elfhdr.e_phnum), | |
1191 | - getu16(fm, elfhdr.e_phentsize)); | |
1192 | + if (dophn_core(ms, class, swap, fd, | |
1193 | + (off_t)getu32(swap, elfhdr.e_phoff), | |
1194 | + getu16(swap, elfhdr.e_phnum), | |
1195 | + (size_t)getu16(swap, elfhdr.e_phentsize)) == -1) | |
1196 | + return -1; | |
1197 | #else | |
1198 | ; | |
1199 | #endif | |
1200 | - else { | |
1201 | - if (getu16(fm, elfhdr.e_type) == ET_EXEC) { | |
1202 | - dophn_exec(fm, | |
1203 | - getu32(fm, elfhdr.e_phoff), | |
1204 | - getu16(fm, elfhdr.e_phnum), | |
1205 | - getu16(fm, elfhdr.e_phentsize)); | |
1206 | + } else { | |
1207 | + if (getu16(swap, elfhdr.e_type) == ET_EXEC) { | |
1208 | + if (dophn_exec(ms, class, swap, | |
1209 | + fd, (off_t)getu32(swap, elfhdr.e_phoff), | |
1210 | + getu16(swap, elfhdr.e_phnum), | |
1211 | + (size_t)getu16(swap, elfhdr.e_phentsize)) | |
1212 | + == -1) | |
1213 | + return -1; | |
1214 | } | |
1215 | - doshn(fm, | |
1216 | - getu32(fm, elfhdr.e_shoff), | |
1217 | - getu16(fm, elfhdr.e_shnum), | |
1218 | - getu16(fm, elfhdr.e_shentsize)); | |
1219 | + if (doshn(ms, class, swap, fd, | |
1220 | + (off_t)getu32(swap, elfhdr.e_shoff), | |
1221 | + getu16(swap, elfhdr.e_shnum), | |
1222 | + (size_t)getu16(swap, elfhdr.e_shentsize)) == -1) | |
1223 | + return -1; | |
b6942f9f | 1224 | } |
0749e45a AM |
1225 | - return; |
1226 | + return 1; | |
b6942f9f | 1227 | } |
b6942f9f | 1228 | |
0749e45a AM |
1229 | - if (fm->cls == ELFCLASS64) { |
1230 | + if (class == ELFCLASS64) { | |
1231 | Elf64_Ehdr elfhdr; | |
1232 | - if (fm->nb <= sizeof (elfhdr)) | |
1233 | - return; | |
1234 | + if (nbytes <= sizeof (Elf64_Ehdr)) | |
1235 | + return 0; | |
1236 | + | |
1237 | ||
1238 | u.l = 1; | |
1239 | - (void) memcpy(&elfhdr, fm->buf, sizeof elfhdr); | |
1240 | -/*@-sizeoftype@*/ | |
1241 | - fm->swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[EI_DATA]; | |
1242 | -/*@=sizeoftype@*/ | |
1243 | + (void) memcpy(&elfhdr, buf, sizeof elfhdr); | |
1244 | + swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[5]; | |
1245 | ||
1246 | - if (getu16(fm, elfhdr.e_type) == ET_CORE) | |
1247 | + if (getu16(swap, elfhdr.e_type) == ET_CORE) { | |
1248 | #ifdef ELFCORE | |
1249 | - dophn_core(fm, | |
1250 | + if (dophn_core(ms, class, swap, fd, | |
1251 | #ifdef USE_ARRAY_FOR_64BIT_TYPES | |
1252 | - getu32(fm, elfhdr.e_phoff[1]), | |
1253 | + (off_t)getu32(swap, elfhdr.e_phoff[1]), | |
1254 | #else | |
1255 | - getu64(fm, elfhdr.e_phoff), | |
1256 | + (off_t)getu64(swap, elfhdr.e_phoff), | |
1257 | #endif | |
1258 | - getu16(fm, elfhdr.e_phnum), | |
1259 | - getu16(fm, elfhdr.e_phentsize)); | |
1260 | + getu16(swap, elfhdr.e_phnum), | |
1261 | + (size_t)getu16(swap, elfhdr.e_phentsize)) == -1) | |
1262 | + return -1; | |
1263 | #else | |
1264 | ; | |
1265 | #endif | |
1266 | - else | |
1267 | - { | |
1268 | - if (getu16(fm, elfhdr.e_type) == ET_EXEC) { | |
1269 | - dophn_exec(fm, | |
1270 | + } else { | |
1271 | + if (getu16(swap, elfhdr.e_type) == ET_EXEC) { | |
1272 | + if (dophn_exec(ms, class, swap, fd, | |
1273 | #ifdef USE_ARRAY_FOR_64BIT_TYPES | |
1274 | - getu32(fm, elfhdr.e_phoff[1]), | |
1275 | + (off_t)getu32(swap, elfhdr.e_phoff[1]), | |
1276 | #else | |
1277 | - getu64(fm, elfhdr.e_phoff), | |
1278 | + (off_t)getu64(swap, elfhdr.e_phoff), | |
1279 | #endif | |
1280 | - getu16(fm, elfhdr.e_phnum), | |
1281 | - getu16(fm, elfhdr.e_phentsize)); | |
1282 | + getu16(swap, elfhdr.e_phnum), | |
1283 | + (size_t)getu16(swap, elfhdr.e_phentsize)) | |
1284 | + == -1) | |
1285 | + return -1; | |
1286 | } | |
1287 | - doshn(fm, | |
1288 | + if (doshn(ms, class, swap, fd, | |
1289 | #ifdef USE_ARRAY_FOR_64BIT_TYPES | |
1290 | - getu32(fm, elfhdr.e_shoff[1]), | |
1291 | + (off_t)getu32(swap, elfhdr.e_shoff[1]), | |
1292 | #else | |
1293 | - getu64(fm, elfhdr.e_shoff), | |
1294 | + (off_t)getu64(swap, elfhdr.e_shoff), | |
1295 | #endif | |
1296 | - getu16(fm, elfhdr.e_shnum), | |
1297 | - getu16(fm, elfhdr.e_shentsize)); | |
1298 | + getu16(swap, elfhdr.e_shnum), | |
1299 | + (size_t)getu16(swap, elfhdr.e_shentsize)) == -1) | |
1300 | + return -1; | |
1301 | } | |
1302 | - return; | |
1303 | + return 1; | |
1304 | } | |
1305 | + return 0; | |
1306 | } | |
1307 | -/*@=bounds@*/ | |
1308 | -#endif /* BUILTIN_ELF */ | |
1309 | +#endif |