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