readelf.c revision 275671
1/*
2 * Copyright (c) Christos Zoulas 2003.
3 * All Rights Reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice immediately at the beginning of the file, without modification,
10 *    this list of conditions, and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
19 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27#include "file.h"
28
29#ifndef lint
30FILE_RCSID("@(#)$File: readelf.c,v 1.90 2011/08/23 08:01:12 christos Exp $")
31#endif
32
33#ifdef BUILTIN_ELF
34#include <string.h>
35#include <ctype.h>
36#include <stdlib.h>
37#ifdef HAVE_UNISTD_H
38#include <unistd.h>
39#endif
40
41#include "readelf.h"
42#include "magic.h"
43
44#ifdef	ELFCORE
45private int dophn_core(struct magic_set *, int, int, int, off_t, int, size_t,
46    off_t, int *);
47#endif
48private int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t,
49    off_t, int *, int);
50private int doshn(struct magic_set *, int, int, int, off_t, int, size_t,
51    off_t, int *, int);
52private size_t donote(struct magic_set *, void *, size_t, size_t, int,
53    int, size_t, int *);
54
55#define	ELF_ALIGN(a)	((((a) + align - 1) / align) * align)
56
57#define isquote(c) (strchr("'\"`", (c)) != NULL)
58
59private uint16_t getu16(int, uint16_t);
60private uint32_t getu32(int, uint32_t);
61private uint64_t getu64(int, uint64_t);
62
63#define MAX_PHNUM	256
64#define	MAX_SHNUM	1024
65
66private int
67toomany(struct magic_set *ms, const char *name, uint16_t num)
68{
69	if (file_printf(ms, ", too many %s header sections (%u)", name, num
70	    ) == -1)
71		return -1;
72	return 0;
73}
74
75private uint16_t
76getu16(int swap, uint16_t value)
77{
78	union {
79		uint16_t ui;
80		char c[2];
81	} retval, tmpval;
82
83	if (swap) {
84		tmpval.ui = value;
85
86		retval.c[0] = tmpval.c[1];
87		retval.c[1] = tmpval.c[0];
88
89		return retval.ui;
90	} else
91		return value;
92}
93
94private uint32_t
95getu32(int swap, uint32_t value)
96{
97	union {
98		uint32_t ui;
99		char c[4];
100	} retval, tmpval;
101
102	if (swap) {
103		tmpval.ui = value;
104
105		retval.c[0] = tmpval.c[3];
106		retval.c[1] = tmpval.c[2];
107		retval.c[2] = tmpval.c[1];
108		retval.c[3] = tmpval.c[0];
109
110		return retval.ui;
111	} else
112		return value;
113}
114
115private uint64_t
116getu64(int swap, uint64_t value)
117{
118	union {
119		uint64_t ui;
120		char c[8];
121	} retval, tmpval;
122
123	if (swap) {
124		tmpval.ui = value;
125
126		retval.c[0] = tmpval.c[7];
127		retval.c[1] = tmpval.c[6];
128		retval.c[2] = tmpval.c[5];
129		retval.c[3] = tmpval.c[4];
130		retval.c[4] = tmpval.c[3];
131		retval.c[5] = tmpval.c[2];
132		retval.c[6] = tmpval.c[1];
133		retval.c[7] = tmpval.c[0];
134
135		return retval.ui;
136	} else
137		return value;
138}
139
140#define elf_getu16(swap, value) getu16(swap, value)
141#define elf_getu32(swap, value) getu32(swap, value)
142#ifdef USE_ARRAY_FOR_64BIT_TYPES
143# define elf_getu64(swap, array) \
144	((swap ? ((uint64_t)elf_getu32(swap, array[0])) << 32 : elf_getu32(swap, array[0])) + \
145	 (swap ? elf_getu32(swap, array[1]) : ((uint64_t)elf_getu32(swap, array[1]) << 32)))
146#else
147# define elf_getu64(swap, value) getu64(swap, value)
148#endif
149
150#define xsh_addr	(clazz == ELFCLASS32			\
151			 ? (void *) &sh32			\
152			 : (void *) &sh64)
153#define xsh_sizeof	(clazz == ELFCLASS32			\
154			 ? sizeof sh32				\
155			 : sizeof sh64)
156#define xsh_size	(clazz == ELFCLASS32			\
157			 ? elf_getu32(swap, sh32.sh_size)	\
158			 : elf_getu64(swap, sh64.sh_size))
159#define xsh_offset	(off_t)(clazz == ELFCLASS32		\
160			 ? elf_getu32(swap, sh32.sh_offset)	\
161			 : elf_getu64(swap, sh64.sh_offset))
162#define xsh_type	(clazz == ELFCLASS32			\
163			 ? elf_getu32(swap, sh32.sh_type)	\
164			 : elf_getu32(swap, sh64.sh_type))
165#define xph_addr	(clazz == ELFCLASS32			\
166			 ? (void *) &ph32			\
167			 : (void *) &ph64)
168#define xph_sizeof	(clazz == ELFCLASS32			\
169			 ? sizeof ph32				\
170			 : sizeof ph64)
171#define xph_type	(clazz == ELFCLASS32			\
172			 ? elf_getu32(swap, ph32.p_type)	\
173			 : elf_getu32(swap, ph64.p_type))
174#define xph_offset	(off_t)(clazz == ELFCLASS32		\
175			 ? elf_getu32(swap, ph32.p_offset)	\
176			 : elf_getu64(swap, ph64.p_offset))
177#define xph_align	(size_t)((clazz == ELFCLASS32		\
178			 ? (off_t) (ph32.p_align ? 		\
179			    elf_getu32(swap, ph32.p_align) : 4) \
180			 : (off_t) (ph64.p_align ?		\
181			    elf_getu64(swap, ph64.p_align) : 4)))
182#define xph_filesz	(size_t)((clazz == ELFCLASS32		\
183			 ? elf_getu32(swap, ph32.p_filesz)	\
184			 : elf_getu64(swap, ph64.p_filesz)))
185#define xnh_addr	(clazz == ELFCLASS32			\
186			 ? (void *) &nh32			\
187			 : (void *) &nh64)
188#define xph_memsz	(size_t)((clazz == ELFCLASS32		\
189			 ? elf_getu32(swap, ph32.p_memsz)	\
190			 : elf_getu64(swap, ph64.p_memsz)))
191#define xnh_sizeof	(clazz == ELFCLASS32			\
192			 ? sizeof nh32				\
193			 : sizeof nh64)
194#define xnh_type	(clazz == ELFCLASS32			\
195			 ? elf_getu32(swap, nh32.n_type)	\
196			 : elf_getu32(swap, nh64.n_type))
197#define xnh_namesz	(clazz == ELFCLASS32			\
198			 ? elf_getu32(swap, nh32.n_namesz)	\
199			 : elf_getu32(swap, nh64.n_namesz))
200#define xnh_descsz	(clazz == ELFCLASS32			\
201			 ? elf_getu32(swap, nh32.n_descsz)	\
202			 : elf_getu32(swap, nh64.n_descsz))
203#define prpsoffsets(i)	(clazz == ELFCLASS32			\
204			 ? prpsoffsets32[i]			\
205			 : prpsoffsets64[i])
206#define xcap_addr	(clazz == ELFCLASS32			\
207			 ? (void *) &cap32			\
208			 : (void *) &cap64)
209#define xcap_sizeof	(clazz == ELFCLASS32			\
210			 ? sizeof cap32				\
211			 : sizeof cap64)
212#define xcap_tag	(clazz == ELFCLASS32			\
213			 ? elf_getu32(swap, cap32.c_tag)	\
214			 : elf_getu64(swap, cap64.c_tag))
215#define xcap_val	(clazz == ELFCLASS32			\
216			 ? elf_getu32(swap, cap32.c_un.c_val)	\
217			 : elf_getu64(swap, cap64.c_un.c_val))
218
219#ifdef ELFCORE
220/*
221 * Try larger offsets first to avoid false matches
222 * from earlier data that happen to look like strings.
223 */
224static const size_t	prpsoffsets32[] = {
225#ifdef USE_NT_PSINFO
226	104,		/* SunOS 5.x (command line) */
227	88,		/* SunOS 5.x (short name) */
228#endif /* USE_NT_PSINFO */
229
230	100,		/* SunOS 5.x (command line) */
231	84,		/* SunOS 5.x (short name) */
232
233	44,		/* Linux (command line) */
234	28,		/* Linux 2.0.36 (short name) */
235
236	8,		/* FreeBSD */
237};
238
239static const size_t	prpsoffsets64[] = {
240#ifdef USE_NT_PSINFO
241	152,		/* SunOS 5.x (command line) */
242	136,		/* SunOS 5.x (short name) */
243#endif /* USE_NT_PSINFO */
244
245	136,		/* SunOS 5.x, 64-bit (command line) */
246	120,		/* SunOS 5.x, 64-bit (short name) */
247
248	56,		/* Linux (command line) */
249	40,             /* Linux (tested on core from 2.4.x, short name) */
250
251	16,		/* FreeBSD, 64-bit */
252};
253
254#define	NOFFSETS32	(sizeof prpsoffsets32 / sizeof prpsoffsets32[0])
255#define NOFFSETS64	(sizeof prpsoffsets64 / sizeof prpsoffsets64[0])
256
257#define NOFFSETS	(clazz == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64)
258
259/*
260 * Look through the program headers of an executable image, searching
261 * for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE" or
262 * "FreeBSD"; if one is found, try looking in various places in its
263 * contents for a 16-character string containing only printable
264 * characters - if found, that string should be the name of the program
265 * that dropped core.  Note: right after that 16-character string is,
266 * at least in SunOS 5.x (and possibly other SVR4-flavored systems) and
267 * Linux, a longer string (80 characters, in 5.x, probably other
268 * SVR4-flavored systems, and Linux) containing the start of the
269 * command line for that program.
270 *
271 * SunOS 5.x core files contain two PT_NOTE sections, with the types
272 * NT_PRPSINFO (old) and NT_PSINFO (new).  These structs contain the
273 * same info about the command name and command line, so it probably
274 * isn't worthwhile to look for NT_PSINFO, but the offsets are provided
275 * above (see USE_NT_PSINFO), in case we ever decide to do so.  The
276 * NT_PRPSINFO and NT_PSINFO sections are always in order and adjacent;
277 * the SunOS 5.x file command relies on this (and prefers the latter).
278 *
279 * The signal number probably appears in a section of type NT_PRSTATUS,
280 * but that's also rather OS-dependent, in ways that are harder to
281 * dissect with heuristics, so I'm not bothering with the signal number.
282 * (I suppose the signal number could be of interest in situations where
283 * you don't have the binary of the program that dropped core; if you
284 * *do* have that binary, the debugger will probably tell you what
285 * signal it was.)
286 */
287
288#define	OS_STYLE_SVR4		0
289#define	OS_STYLE_FREEBSD	1
290#define	OS_STYLE_NETBSD		2
291
292private const char os_style_names[][8] = {
293	"SVR4",
294	"FreeBSD",
295	"NetBSD",
296};
297
298#define FLAGS_DID_CORE		0x01
299#define FLAGS_DID_NOTE		0x02
300#define FLAGS_DID_BUILD_ID	0x04
301#define FLAGS_DID_CORE_STYLE	0x08
302#define FLAGS_IS_CORE		0x10
303
304private int
305dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
306    int num, size_t size, off_t fsize, int *flags)
307{
308	Elf32_Phdr ph32;
309	Elf64_Phdr ph64;
310	size_t offset;
311	unsigned char nbuf[BUFSIZ];
312	ssize_t bufsize;
313
314	if (size != xph_sizeof) {
315		if (file_printf(ms, ", corrupted program header size") == -1)
316			return -1;
317		return 0;
318	}
319
320	/*
321	 * Loop through all the program headers.
322	 */
323	for ( ; num; num--) {
324		if (lseek(fd, off, SEEK_SET) == (off_t)-1) {
325			file_badseek(ms);
326			return -1;
327		}
328		if (read(fd, xph_addr, xph_sizeof) == -1) {
329			file_badread(ms);
330			return -1;
331		}
332		off += size;
333
334		if (xph_offset > fsize) {
335			/* Perhaps warn here */
336			continue;
337		}
338
339		if (xph_type != PT_NOTE)
340			continue;
341
342		/*
343		 * This is a PT_NOTE section; loop through all the notes
344		 * in the section.
345		 */
346		if (lseek(fd, xph_offset, SEEK_SET) == (off_t)-1) {
347			file_badseek(ms);
348			return -1;
349		}
350		bufsize = read(fd, nbuf,
351		    ((xph_filesz < sizeof(nbuf)) ? xph_filesz : sizeof(nbuf)));
352		if (bufsize == -1) {
353			file_badread(ms);
354			return -1;
355		}
356		offset = 0;
357		for (;;) {
358			if (offset >= (size_t)bufsize)
359				break;
360			offset = donote(ms, nbuf, offset, (size_t)bufsize,
361			    clazz, swap, 4, flags);
362			if (offset == 0)
363				break;
364
365		}
366	}
367	return 0;
368}
369#endif
370
371private size_t
372donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
373    int clazz, int swap, size_t align, int *flags)
374{
375	Elf32_Nhdr nh32;
376	Elf64_Nhdr nh64;
377	size_t noff, doff;
378#ifdef ELFCORE
379	int os_style = -1;
380#endif
381	uint32_t namesz, descsz;
382	unsigned char *nbuf = CAST(unsigned char *, vbuf);
383
384	(void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof);
385	offset += xnh_sizeof;
386
387	namesz = xnh_namesz;
388	descsz = xnh_descsz;
389	if ((namesz == 0) && (descsz == 0)) {
390		/*
391		 * We're out of note headers.
392		 */
393		return (offset >= size) ? offset : size;
394	}
395
396	if (namesz & 0x80000000) {
397	    (void)file_printf(ms, ", bad note name size 0x%lx",
398		(unsigned long)namesz);
399	    return 0;
400	}
401
402	if (descsz & 0x80000000) {
403	    (void)file_printf(ms, ", bad note description size 0x%lx",
404		(unsigned long)descsz);
405	    return 0;
406	}
407
408
409	noff = offset;
410	doff = ELF_ALIGN(offset + namesz);
411
412	if (offset + namesz > size) {
413		/*
414		 * We're past the end of the buffer.
415		 */
416		return doff;
417	}
418
419	offset = ELF_ALIGN(doff + descsz);
420	if (doff + descsz > size) {
421		/*
422		 * We're past the end of the buffer.
423		 */
424		return (offset >= size) ? offset : size;
425	}
426
427	if ((*flags & (FLAGS_DID_NOTE|FLAGS_DID_BUILD_ID)) ==
428	    (FLAGS_DID_NOTE|FLAGS_DID_BUILD_ID))
429		goto core;
430
431	if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
432	    xnh_type == NT_GNU_VERSION && descsz == 16) {
433		uint32_t desc[4];
434		(void)memcpy(desc, &nbuf[doff], sizeof(desc));
435
436		if (file_printf(ms, ", for GNU/") == -1)
437			return size;
438		switch (elf_getu32(swap, desc[0])) {
439		case GNU_OS_LINUX:
440			if (file_printf(ms, "Linux") == -1)
441				return size;
442			break;
443		case GNU_OS_HURD:
444			if (file_printf(ms, "Hurd") == -1)
445				return size;
446			break;
447		case GNU_OS_SOLARIS:
448			if (file_printf(ms, "Solaris") == -1)
449				return size;
450			break;
451		case GNU_OS_KFREEBSD:
452			if (file_printf(ms, "kFreeBSD") == -1)
453				return size;
454			break;
455		case GNU_OS_KNETBSD:
456			if (file_printf(ms, "kNetBSD") == -1)
457				return size;
458			break;
459		default:
460			if (file_printf(ms, "<unknown>") == -1)
461				return size;
462		}
463		if (file_printf(ms, " %d.%d.%d", elf_getu32(swap, desc[1]),
464		    elf_getu32(swap, desc[2]), elf_getu32(swap, desc[3])) == -1)
465			return size;
466		*flags |= FLAGS_DID_NOTE;
467		return size;
468	}
469
470	if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
471	    xnh_type == NT_GNU_BUILD_ID && (descsz == 16 || descsz == 20)) {
472	    uint32_t desc[5], i;
473	    if (file_printf(ms, ", BuildID[%s]=0x", descsz == 16 ? "md5/uuid" :
474		"sha1") == -1)
475		    return size;
476	    (void)memcpy(desc, &nbuf[doff], descsz);
477	    for (i = 0; i < descsz >> 2; i++)
478		if (file_printf(ms, "%.8x", desc[i]) == -1)
479		    return size;
480	    *flags |= FLAGS_DID_BUILD_ID;
481	}
482
483	if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0 &&
484	    xnh_type == NT_NETBSD_VERSION && descsz == 4) {
485		uint32_t desc;
486		(void)memcpy(&desc, &nbuf[doff], sizeof(desc));
487		desc = elf_getu32(swap, desc);
488
489		if (file_printf(ms, ", for NetBSD") == -1)
490			return size;
491		/*
492		 * The version number used to be stuck as 199905, and was thus
493		 * basically content-free.  Newer versions of NetBSD have fixed
494		 * this and now use the encoding of __NetBSD_Version__:
495		 *
496		 *	MMmmrrpp00
497		 *
498		 * M = major version
499		 * m = minor version
500		 * r = release ["",A-Z,Z[A-Z] but numeric]
501		 * p = patchlevel
502		 */
503		if (desc > 100000000U) {
504			uint32_t ver_patch = (desc / 100) % 100;
505			uint32_t ver_rel = (desc / 10000) % 100;
506			uint32_t ver_min = (desc / 1000000) % 100;
507			uint32_t ver_maj = desc / 100000000;
508
509			if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1)
510				return size;
511			if (ver_rel == 0 && ver_patch != 0) {
512				if (file_printf(ms, ".%u", ver_patch) == -1)
513					return size;
514			} else if (ver_rel != 0) {
515				while (ver_rel > 26) {
516					if (file_printf(ms, "Z") == -1)
517						return size;
518					ver_rel -= 26;
519				}
520				if (file_printf(ms, "%c", 'A' + ver_rel - 1)
521				    == -1)
522					return size;
523			}
524		}
525		*flags |= FLAGS_DID_NOTE;
526		return size;
527	}
528
529	if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0 &&
530	    xnh_type == NT_FREEBSD_VERSION && descsz == 4) {
531		uint32_t desc;
532		(void)memcpy(&desc, &nbuf[doff], sizeof(desc));
533		desc = elf_getu32(swap, desc);
534		if (file_printf(ms, ", for FreeBSD") == -1)
535			return size;
536
537		/*
538		 * Contents is __FreeBSD_version, whose relation to OS
539		 * versions is defined by a huge table in the Porter's
540		 * Handbook.  This is the general scheme:
541		 *
542		 * Releases:
543		 * 	Mmp000 (before 4.10)
544		 * 	Mmi0p0 (before 5.0)
545		 * 	Mmm0p0
546		 *
547		 * Development branches:
548		 * 	Mmpxxx (before 4.6)
549		 * 	Mmp1xx (before 4.10)
550		 * 	Mmi1xx (before 5.0)
551		 * 	M000xx (pre-M.0)
552		 * 	Mmm1xx
553		 *
554		 * M = major version
555		 * m = minor version
556		 * i = minor version increment (491000 -> 4.10)
557		 * p = patchlevel
558		 * x = revision
559		 *
560		 * The first release of FreeBSD to use ELF by default
561		 * was version 3.0.
562		 */
563		if (desc == 460002) {
564			if (file_printf(ms, " 4.6.2") == -1)
565				return size;
566		} else if (desc < 460100) {
567			if (file_printf(ms, " %d.%d", desc / 100000,
568			    desc / 10000 % 10) == -1)
569				return size;
570			if (desc / 1000 % 10 > 0)
571				if (file_printf(ms, ".%d", desc / 1000 % 10)
572				    == -1)
573					return size;
574			if ((desc % 1000 > 0) || (desc % 100000 == 0))
575				if (file_printf(ms, " (%d)", desc) == -1)
576					return size;
577		} else if (desc < 500000) {
578			if (file_printf(ms, " %d.%d", desc / 100000,
579			    desc / 10000 % 10 + desc / 1000 % 10) == -1)
580				return size;
581			if (desc / 100 % 10 > 0) {
582				if (file_printf(ms, " (%d)", desc) == -1)
583					return size;
584			} else if (desc / 10 % 10 > 0) {
585				if (file_printf(ms, ".%d", desc / 10 % 10)
586				    == -1)
587					return size;
588			}
589		} else {
590			if (file_printf(ms, " %d.%d", desc / 100000,
591			    desc / 1000 % 100) == -1)
592				return size;
593			if ((desc / 100 % 10 > 0) ||
594			    (desc % 100000 / 100 == 0)) {
595				if (file_printf(ms, " (%d)", desc) == -1)
596					return size;
597			} else if (desc / 10 % 10 > 0) {
598				if (file_printf(ms, ".%d", desc / 10 % 10)
599				    == -1)
600					return size;
601			}
602		}
603		*flags |= FLAGS_DID_NOTE;
604		return size;
605	}
606
607	if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 &&
608	    xnh_type == NT_OPENBSD_VERSION && descsz == 4) {
609		if (file_printf(ms, ", for OpenBSD") == -1)
610			return size;
611		/* Content of note is always 0 */
612		*flags |= FLAGS_DID_NOTE;
613		return size;
614	}
615
616	if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 &&
617	    xnh_type == NT_DRAGONFLY_VERSION && descsz == 4) {
618		uint32_t desc;
619		if (file_printf(ms, ", for DragonFly") == -1)
620			return size;
621		(void)memcpy(&desc, &nbuf[doff], sizeof(desc));
622		desc = elf_getu32(swap, desc);
623		if (file_printf(ms, " %d.%d.%d", desc / 100000,
624		    desc / 10000 % 10, desc % 10000) == -1)
625			return size;
626		*flags |= FLAGS_DID_NOTE;
627		return size;
628	}
629
630core:
631	/*
632	 * Sigh.  The 2.0.36 kernel in Debian 2.1, at
633	 * least, doesn't correctly implement name
634	 * sections, in core dumps, as specified by
635	 * the "Program Linking" section of "UNIX(R) System
636	 * V Release 4 Programmer's Guide: ANSI C and
637	 * Programming Support Tools", because my copy
638	 * clearly says "The first 'namesz' bytes in 'name'
639	 * contain a *null-terminated* [emphasis mine]
640	 * character representation of the entry's owner
641	 * or originator", but the 2.0.36 kernel code
642	 * doesn't include the terminating null in the
643	 * name....
644	 */
645	if ((namesz == 4 && strncmp((char *)&nbuf[noff], "CORE", 4) == 0) ||
646	    (namesz == 5 && strcmp((char *)&nbuf[noff], "CORE") == 0)) {
647		os_style = OS_STYLE_SVR4;
648	}
649
650	if ((namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0)) {
651		os_style = OS_STYLE_FREEBSD;
652	}
653
654	if ((namesz >= 11 && strncmp((char *)&nbuf[noff], "NetBSD-CORE", 11)
655	    == 0)) {
656		os_style = OS_STYLE_NETBSD;
657	}
658
659#ifdef ELFCORE
660	if ((*flags & FLAGS_DID_CORE) != 0)
661		return size;
662
663	if (os_style != -1 && (*flags & FLAGS_DID_CORE_STYLE) == 0) {
664		if (file_printf(ms, ", %s-style", os_style_names[os_style])
665		    == -1)
666			return size;
667		*flags |= FLAGS_DID_CORE_STYLE;
668	}
669
670	switch (os_style) {
671	case OS_STYLE_NETBSD:
672		if (xnh_type == NT_NETBSD_CORE_PROCINFO) {
673			uint32_t signo;
674			/*
675			 * Extract the program name.  It is at
676			 * offset 0x7c, and is up to 32-bytes,
677			 * including the terminating NUL.
678			 */
679			if (file_printf(ms, ", from '%.31s'",
680			    &nbuf[doff + 0x7c]) == -1)
681				return size;
682
683			/*
684			 * Extract the signal number.  It is at
685			 * offset 0x08.
686			 */
687			(void)memcpy(&signo, &nbuf[doff + 0x08],
688			    sizeof(signo));
689			if (file_printf(ms, " (signal %u)",
690			    elf_getu32(swap, signo)) == -1)
691				return size;
692			*flags |= FLAGS_DID_CORE;
693			return size;
694		}
695		break;
696
697	default:
698		if (xnh_type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) {
699			size_t i, j;
700			unsigned char c;
701			/*
702			 * Extract the program name.  We assume
703			 * it to be 16 characters (that's what it
704			 * is in SunOS 5.x and Linux).
705			 *
706			 * Unfortunately, it's at a different offset
707			 * in various OSes, so try multiple offsets.
708			 * If the characters aren't all printable,
709			 * reject it.
710			 */
711			for (i = 0; i < NOFFSETS; i++) {
712				unsigned char *cname, *cp;
713				size_t reloffset = prpsoffsets(i);
714				size_t noffset = doff + reloffset;
715				size_t k;
716				for (j = 0; j < 16; j++, noffset++,
717				    reloffset++) {
718					/*
719					 * Make sure we're not past
720					 * the end of the buffer; if
721					 * we are, just give up.
722					 */
723					if (noffset >= size)
724						goto tryanother;
725
726					/*
727					 * Make sure we're not past
728					 * the end of the contents;
729					 * if we are, this obviously
730					 * isn't the right offset.
731					 */
732					if (reloffset >= descsz)
733						goto tryanother;
734
735					c = nbuf[noffset];
736					if (c == '\0') {
737						/*
738						 * A '\0' at the
739						 * beginning is
740						 * obviously wrong.
741						 * Any other '\0'
742						 * means we're done.
743						 */
744						if (j == 0)
745							goto tryanother;
746						else
747							break;
748					} else {
749						/*
750						 * A nonprintable
751						 * character is also
752						 * wrong.
753						 */
754						if (!isprint(c) || isquote(c))
755							goto tryanother;
756					}
757				}
758				/*
759				 * Well, that worked.
760				 */
761
762				/*
763				 * Try next offsets, in case this match is
764				 * in the middle of a string.
765				 */
766				for (k = i + 1 ; k < NOFFSETS ; k++) {
767					size_t no;
768					int adjust = 1;
769					if (prpsoffsets(k) >= prpsoffsets(i))
770						continue;
771					for (no = doff + prpsoffsets(k);
772					     no < doff + prpsoffsets(i); no++)
773						adjust = adjust
774						         && isprint(nbuf[no]);
775					if (adjust)
776						i = k;
777				}
778
779				cname = (unsigned char *)
780				    &nbuf[doff + prpsoffsets(i)];
781				for (cp = cname; *cp && isprint(*cp); cp++)
782					continue;
783				/*
784				 * Linux apparently appends a space at the end
785				 * of the command line: remove it.
786				 */
787				while (cp > cname && isspace(cp[-1]))
788					cp--;
789				if (file_printf(ms, ", from '%.*s'",
790				    (int)(cp - cname), cname) == -1)
791					return size;
792				*flags |= FLAGS_DID_CORE;
793				return size;
794
795			tryanother:
796				;
797			}
798		}
799		break;
800	}
801#endif
802	return offset;
803}
804
805/* SunOS 5.x hardware capability descriptions */
806typedef struct cap_desc {
807	uint64_t cd_mask;
808	const char *cd_name;
809} cap_desc_t;
810
811static const cap_desc_t cap_desc_sparc[] = {
812	{ AV_SPARC_MUL32,		"MUL32" },
813	{ AV_SPARC_DIV32,		"DIV32" },
814	{ AV_SPARC_FSMULD,		"FSMULD" },
815	{ AV_SPARC_V8PLUS,		"V8PLUS" },
816	{ AV_SPARC_POPC,		"POPC" },
817	{ AV_SPARC_VIS,			"VIS" },
818	{ AV_SPARC_VIS2,		"VIS2" },
819	{ AV_SPARC_ASI_BLK_INIT,	"ASI_BLK_INIT" },
820	{ AV_SPARC_FMAF,		"FMAF" },
821	{ AV_SPARC_FJFMAU,		"FJFMAU" },
822	{ AV_SPARC_IMA,			"IMA" },
823	{ 0, NULL }
824};
825
826static const cap_desc_t cap_desc_386[] = {
827	{ AV_386_FPU,			"FPU" },
828	{ AV_386_TSC,			"TSC" },
829	{ AV_386_CX8,			"CX8" },
830	{ AV_386_SEP,			"SEP" },
831	{ AV_386_AMD_SYSC,		"AMD_SYSC" },
832	{ AV_386_CMOV,			"CMOV" },
833	{ AV_386_MMX,			"MMX" },
834	{ AV_386_AMD_MMX,		"AMD_MMX" },
835	{ AV_386_AMD_3DNow,		"AMD_3DNow" },
836	{ AV_386_AMD_3DNowx,		"AMD_3DNowx" },
837	{ AV_386_FXSR,			"FXSR" },
838	{ AV_386_SSE,			"SSE" },
839	{ AV_386_SSE2,			"SSE2" },
840	{ AV_386_PAUSE,			"PAUSE" },
841	{ AV_386_SSE3,			"SSE3" },
842	{ AV_386_MON,			"MON" },
843	{ AV_386_CX16,			"CX16" },
844	{ AV_386_AHF,			"AHF" },
845	{ AV_386_TSCP,			"TSCP" },
846	{ AV_386_AMD_SSE4A,		"AMD_SSE4A" },
847	{ AV_386_POPCNT,		"POPCNT" },
848	{ AV_386_AMD_LZCNT,		"AMD_LZCNT" },
849	{ AV_386_SSSE3,			"SSSE3" },
850	{ AV_386_SSE4_1,		"SSE4.1" },
851	{ AV_386_SSE4_2,		"SSE4.2" },
852	{ 0, NULL }
853};
854
855private int
856doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
857    size_t size, off_t fsize, int *flags, int mach)
858{
859	Elf32_Shdr sh32;
860	Elf64_Shdr sh64;
861	int stripped = 1;
862	size_t nbadcap = 0;
863	void *nbuf;
864	off_t noff, coff;
865	uint64_t cap_hw1 = 0;	/* SunOS 5.x hardware capabilites */
866	uint64_t cap_sf1 = 0;	/* SunOS 5.x software capabilites */
867
868	if (size != xsh_sizeof) {
869		if (file_printf(ms, ", corrupted section header size") == -1)
870			return -1;
871		return 0;
872	}
873
874	for ( ; num; num--) {
875		if (lseek(fd, off, SEEK_SET) == (off_t)-1) {
876			file_badseek(ms);
877			return -1;
878		}
879		if (read(fd, xsh_addr, xsh_sizeof) == -1) {
880			file_badread(ms);
881			return -1;
882		}
883		off += size;
884
885		/* Things we can determine before we seek */
886		switch (xsh_type) {
887		case SHT_SYMTAB:
888#if 0
889		case SHT_DYNSYM:
890#endif
891			stripped = 0;
892			break;
893		default:
894			if (xsh_offset > fsize) {
895				/* Perhaps warn here */
896				continue;
897			}
898			break;
899		}
900
901		/* Things we can determine when we seek */
902		switch (xsh_type) {
903		case SHT_NOTE:
904			if ((nbuf = malloc((size_t)xsh_size)) == NULL) {
905				file_error(ms, errno, "Cannot allocate memory"
906				    " for note");
907				return -1;
908			}
909			if ((noff = lseek(fd, (off_t)xsh_offset, SEEK_SET)) ==
910			    (off_t)-1) {
911				file_badread(ms);
912				free(nbuf);
913				return -1;
914			}
915			if (read(fd, nbuf, (size_t)xsh_size) !=
916			    (ssize_t)xsh_size) {
917				free(nbuf);
918				file_badread(ms);
919				return -1;
920			}
921
922			noff = 0;
923			for (;;) {
924				if (noff >= (off_t)xsh_size)
925					break;
926				noff = donote(ms, nbuf, (size_t)noff,
927				    (size_t)xsh_size, clazz, swap, 4,
928				    flags);
929				if (noff == 0)
930					break;
931			}
932			free(nbuf);
933			break;
934		case SHT_SUNW_cap:
935			if (nbadcap > 5)
936				break;
937			if (lseek(fd, (off_t)xsh_offset, SEEK_SET) ==
938			    (off_t)-1) {
939				file_badseek(ms);
940				return -1;
941			}
942			coff = 0;
943			for (;;) {
944				Elf32_Cap cap32;
945				Elf64_Cap cap64;
946				char cbuf[/*CONSTCOND*/
947				    MAX(sizeof cap32, sizeof cap64)];
948				if ((coff += xcap_sizeof) > (off_t)xsh_size)
949					break;
950				if (read(fd, cbuf, (size_t)xcap_sizeof) !=
951				    (ssize_t)xcap_sizeof) {
952					file_badread(ms);
953					return -1;
954				}
955				(void)memcpy(xcap_addr, cbuf, xcap_sizeof);
956				switch (xcap_tag) {
957				case CA_SUNW_NULL:
958					break;
959				case CA_SUNW_HW_1:
960					cap_hw1 |= xcap_val;
961					break;
962				case CA_SUNW_SF_1:
963					cap_sf1 |= xcap_val;
964					break;
965				default:
966					if (file_printf(ms,
967					    ", with unknown capability "
968					    "0x%" INT64_T_FORMAT "x = 0x%"
969					    INT64_T_FORMAT "x",
970					    (unsigned long long)xcap_tag,
971					    (unsigned long long)xcap_val) == -1)
972						return -1;
973					if (nbadcap++ > 2)
974						coff = xsh_size;
975					break;
976				}
977			}
978			break;
979
980		default:
981			break;
982		}
983	}
984	if (file_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1)
985		return -1;
986	if (cap_hw1) {
987		const cap_desc_t *cdp;
988		switch (mach) {
989		case EM_SPARC:
990		case EM_SPARC32PLUS:
991		case EM_SPARCV9:
992			cdp = cap_desc_sparc;
993			break;
994		case EM_386:
995		case EM_IA_64:
996		case EM_AMD64:
997			cdp = cap_desc_386;
998			break;
999		default:
1000			cdp = NULL;
1001			break;
1002		}
1003		if (file_printf(ms, ", uses") == -1)
1004			return -1;
1005		if (cdp) {
1006			while (cdp->cd_name) {
1007				if (cap_hw1 & cdp->cd_mask) {
1008					if (file_printf(ms,
1009					    " %s", cdp->cd_name) == -1)
1010						return -1;
1011					cap_hw1 &= ~cdp->cd_mask;
1012				}
1013				++cdp;
1014			}
1015			if (cap_hw1)
1016				if (file_printf(ms,
1017				    " unknown hardware capability 0x%"
1018				    INT64_T_FORMAT "x",
1019				    (unsigned long long)cap_hw1) == -1)
1020					return -1;
1021		} else {
1022			if (file_printf(ms,
1023			    " hardware capability 0x%" INT64_T_FORMAT "x",
1024			    (unsigned long long)cap_hw1) == -1)
1025				return -1;
1026		}
1027	}
1028	if (cap_sf1) {
1029		if (cap_sf1 & SF1_SUNW_FPUSED) {
1030			if (file_printf(ms,
1031			    (cap_sf1 & SF1_SUNW_FPKNWN)
1032			    ? ", uses frame pointer"
1033			    : ", not known to use frame pointer") == -1)
1034				return -1;
1035		}
1036		cap_sf1 &= ~SF1_SUNW_MASK;
1037		if (cap_sf1)
1038			if (file_printf(ms,
1039			    ", with unknown software capability 0x%"
1040			    INT64_T_FORMAT "x",
1041			    (unsigned long long)cap_sf1) == -1)
1042				return -1;
1043	}
1044	return 0;
1045}
1046
1047/*
1048 * Look through the program headers of an executable image, searching
1049 * for a PT_INTERP section; if one is found, it's dynamically linked,
1050 * otherwise it's statically linked.
1051 */
1052private int
1053dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
1054    int num, size_t size, off_t fsize, int *flags, int sh_num)
1055{
1056	Elf32_Phdr ph32;
1057	Elf64_Phdr ph64;
1058	const char *linking_style = "statically";
1059	const char *shared_libraries = "";
1060	unsigned char nbuf[BUFSIZ];
1061	ssize_t bufsize;
1062	size_t offset, align;
1063
1064	if (size != xph_sizeof) {
1065		if (file_printf(ms, ", corrupted program header size") == -1)
1066			return -1;
1067		return 0;
1068	}
1069
1070  	for ( ; num; num--) {
1071		if (lseek(fd, off, SEEK_SET) == (off_t)-1) {
1072			file_badseek(ms);
1073			return -1;
1074		}
1075
1076  		if (read(fd, xph_addr, xph_sizeof) == -1) {
1077  			file_badread(ms);
1078			return -1;
1079		}
1080
1081		off += size;
1082
1083		/* Things we can determine before we seek */
1084		switch (xph_type) {
1085		case PT_DYNAMIC:
1086			linking_style = "dynamically";
1087			break;
1088		case PT_INTERP:
1089			shared_libraries = " (uses shared libs)";
1090			break;
1091		default:
1092			if (xph_offset > fsize) {
1093				/* Maybe warn here? */
1094				continue;
1095			}
1096			break;
1097		}
1098
1099		/* Things we can determine when we seek */
1100		switch (xph_type) {
1101		case PT_NOTE:
1102			if ((align = xph_align) & 0x80000000UL) {
1103				if (file_printf(ms,
1104				    ", invalid note alignment 0x%lx",
1105				    (unsigned long)align) == -1)
1106					return -1;
1107				align = 4;
1108			}
1109			if (sh_num)
1110				break;
1111			/*
1112			 * This is a PT_NOTE section; loop through all the notes
1113			 * in the section.
1114			 */
1115			if (lseek(fd, xph_offset, SEEK_SET) == (off_t)-1) {
1116				file_badseek(ms);
1117				return -1;
1118			}
1119			bufsize = read(fd, nbuf, ((xph_filesz < sizeof(nbuf)) ?
1120			    xph_filesz : sizeof(nbuf)));
1121			if (bufsize == -1) {
1122				file_badread(ms);
1123				return -1;
1124			}
1125			offset = 0;
1126			for (;;) {
1127				if (offset >= (size_t)bufsize)
1128					break;
1129				offset = donote(ms, nbuf, offset,
1130				    (size_t)bufsize, clazz, swap, align,
1131				    flags);
1132				if (offset == 0)
1133					break;
1134			}
1135			break;
1136		default:
1137			break;
1138		}
1139	}
1140	if (file_printf(ms, ", %s linked%s", linking_style, shared_libraries)
1141	    == -1)
1142	    return -1;
1143	return 0;
1144}
1145
1146
1147protected int
1148file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf,
1149    size_t nbytes)
1150{
1151	union {
1152		int32_t l;
1153		char c[sizeof (int32_t)];
1154	} u;
1155	int clazz;
1156	int swap;
1157	struct stat st;
1158	off_t fsize;
1159	int flags = 0;
1160	Elf32_Ehdr elf32hdr;
1161	Elf64_Ehdr elf64hdr;
1162	uint16_t type, phnum, shnum;
1163
1164	if (ms->flags & (MAGIC_MIME|MAGIC_APPLE))
1165		return 0;
1166	/*
1167	 * ELF executables have multiple section headers in arbitrary
1168	 * file locations and thus file(1) cannot determine it from easily.
1169	 * Instead we traverse thru all section headers until a symbol table
1170	 * one is found or else the binary is stripped.
1171	 * Return immediately if it's not ELF (so we avoid pipe2file unless needed).
1172	 */
1173	if (buf[EI_MAG0] != ELFMAG0
1174	    || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1)
1175	    || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3)
1176		return 0;
1177
1178	/*
1179	 * If we cannot seek, it must be a pipe, socket or fifo.
1180	 */
1181	if((lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE))
1182		fd = file_pipe2file(ms, fd, buf, nbytes);
1183
1184	if (fstat(fd, &st) == -1) {
1185  		file_badread(ms);
1186		return -1;
1187	}
1188	fsize = st.st_size;
1189
1190	clazz = buf[EI_CLASS];
1191
1192	switch (clazz) {
1193	case ELFCLASS32:
1194#undef elf_getu
1195#define elf_getu(a, b)	elf_getu32(a, b)
1196#undef elfhdr
1197#define elfhdr elf32hdr
1198#include "elfclass.h"
1199	case ELFCLASS64:
1200#undef elf_getu
1201#define elf_getu(a, b)	elf_getu64(a, b)
1202#undef elfhdr
1203#define elfhdr elf64hdr
1204#include "elfclass.h"
1205	default:
1206	    if (file_printf(ms, ", unknown class %d", clazz) == -1)
1207		    return -1;
1208	    break;
1209	}
1210	return 0;
1211}
1212#endif
1213