readelf.c revision 186690
120253Sjoerg/*
220302Sjoerg * Copyright (c) Christos Zoulas 2003.
320302Sjoerg * All Rights Reserved.
420253Sjoerg *
520253Sjoerg * Redistribution and use in source and binary forms, with or without
620253Sjoerg * modification, are permitted provided that the following conditions
720253Sjoerg * are met:
820253Sjoerg * 1. Redistributions of source code must retain the above copyright
920302Sjoerg *    notice immediately at the beginning of the file, without modification,
1020253Sjoerg *    this list of conditions, and the following disclaimer.
1120253Sjoerg * 2. Redistributions in binary form must reproduce the above copyright
1220253Sjoerg *    notice, this list of conditions and the following disclaimer in the
1320253Sjoerg *    documentation and/or other materials provided with the distribution.
1420302Sjoerg *
1520253Sjoerg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1620253Sjoerg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1720302Sjoerg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1820253Sjoerg * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
1920253Sjoerg * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2020253Sjoerg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2120253Sjoerg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2220253Sjoerg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2320253Sjoerg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2420253Sjoerg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2520253Sjoerg * SUCH DAMAGE.
2621330Sdavidn */
2720253Sjoerg#include "file.h"
2820253Sjoerg
2920253Sjoerg#ifdef BUILTIN_ELF
3020253Sjoerg#include <string.h>
3120253Sjoerg#include <ctype.h>
3220253Sjoerg#include <stdlib.h>
3320253Sjoerg#ifdef HAVE_UNISTD_H
3420253Sjoerg#include <unistd.h>
3520253Sjoerg#endif
3620253Sjoerg
3720253Sjoerg#include "readelf.h"
3820253Sjoerg#include "magic.h"
3920253Sjoerg
4020267Sjoerg#ifndef lint
4120253SjoergFILE_RCSID("@(#)$File: readelf.c,v 1.76 2008/07/16 18:00:57 christos Exp $")
4220253Sjoerg#endif
4320253Sjoerg
4420253Sjoerg#ifdef	ELFCORE
4520253Sjoergprivate int dophn_core(struct magic_set *, int, int, int, off_t, int, size_t,
4620253Sjoerg    off_t, int *);
4720253Sjoerg#endif
4820253Sjoergprivate int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t,
4920253Sjoerg    off_t, int *, int);
5020267Sjoergprivate int doshn(struct magic_set *, int, int, int, off_t, int, size_t, int *,
5120253Sjoerg    int);
5220253Sjoergprivate size_t donote(struct magic_set *, void *, size_t, size_t, int,
5320253Sjoerg    int, size_t, int *);
5420253Sjoerg
5520253Sjoerg#define	ELF_ALIGN(a)	((((a) + align - 1) / align) * align)
5620253Sjoerg
5720253Sjoerg#define isquote(c) (strchr("'\"`", (c)) != NULL)
5820253Sjoerg
5920253Sjoergprivate uint16_t getu16(int, uint16_t);
6020253Sjoergprivate uint32_t getu32(int, uint32_t);
6120253Sjoergprivate uint64_t getu64(int, uint64_t);
6220253Sjoerg
6320253Sjoergprivate uint16_t
6420253Sjoerggetu16(int swap, uint16_t value)
6520253Sjoerg{
6620253Sjoerg	union {
6720253Sjoerg		uint16_t ui;
6820253Sjoerg		char c[2];
6920253Sjoerg	} retval, tmpval;
7020253Sjoerg
7120253Sjoerg	if (swap) {
7220253Sjoerg		tmpval.ui = value;
7320253Sjoerg
7420253Sjoerg		retval.c[0] = tmpval.c[1];
7521330Sdavidn		retval.c[1] = tmpval.c[0];
7620253Sjoerg
7720253Sjoerg		return retval.ui;
7820253Sjoerg	} else
7920253Sjoerg		return value;
8020253Sjoerg}
8120253Sjoerg
8220253Sjoergprivate uint32_t
8320253Sjoerggetu32(int swap, uint32_t value)
8420253Sjoerg{
8520253Sjoerg	union {
8620253Sjoerg		uint32_t ui;
8720253Sjoerg		char c[4];
8820253Sjoerg	} retval, tmpval;
8920253Sjoerg
9020747Sdavidn	if (swap) {
9120253Sjoerg		tmpval.ui = value;
9220253Sjoerg
9320253Sjoerg		retval.c[0] = tmpval.c[3];
9420253Sjoerg		retval.c[1] = tmpval.c[2];
9520253Sjoerg		retval.c[2] = tmpval.c[1];
9620253Sjoerg		retval.c[3] = tmpval.c[0];
9720253Sjoerg
9820253Sjoerg		return retval.ui;
9920253Sjoerg	} else
10020253Sjoerg		return value;
10120253Sjoerg}
10220253Sjoerg
10320253Sjoergprivate uint64_t
10420253Sjoerggetu64(int swap, uint64_t value)
10520679Sdavidn{
10620253Sjoerg	union {
10720253Sjoerg		uint64_t ui;
10820253Sjoerg		char c[8];
10920253Sjoerg	} retval, tmpval;
11020253Sjoerg
11120253Sjoerg	if (swap) {
11221330Sdavidn		tmpval.ui = value;
11321330Sdavidn
11421330Sdavidn		retval.c[0] = tmpval.c[7];
11521330Sdavidn		retval.c[1] = tmpval.c[6];
11620253Sjoerg		retval.c[2] = tmpval.c[5];
11720253Sjoerg		retval.c[3] = tmpval.c[4];
11820253Sjoerg		retval.c[4] = tmpval.c[3];
11920253Sjoerg		retval.c[5] = tmpval.c[2];
12020253Sjoerg		retval.c[6] = tmpval.c[1];
12120253Sjoerg		retval.c[7] = tmpval.c[0];
12220253Sjoerg
12320253Sjoerg		return retval.ui;
12420253Sjoerg	} else
12520253Sjoerg		return value;
12620253Sjoerg}
12720253Sjoerg
12820253Sjoerg#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 >= (size_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[MAX(sizeof cap32, sizeof cap64)];
911				if ((coff += xcap_sizeof) >= (size_t)xsh_size)
912					break;
913				if (read(fd, cbuf, (size_t)xcap_sizeof) !=
914				    (ssize_t)xcap_sizeof) {
915					file_badread(ms);
916					return -1;
917				}
918				(void)memcpy(xcap_addr, cbuf, xcap_sizeof);
919				switch (xcap_tag) {
920				case CA_SUNW_NULL:
921					break;
922				case CA_SUNW_HW_1:
923					cap_hw1 |= xcap_val;
924					break;
925				case CA_SUNW_SF_1:
926					cap_sf1 |= xcap_val;
927					break;
928				default:
929					if (file_printf(ms,
930					    ", with unknown capability "
931					    "0x%llx = 0x%llx",
932					    xcap_tag, xcap_val) == -1)
933						return -1;
934					break;
935				}
936			}
937			if (lseek(fd, off, SEEK_SET) == (off_t)-1) {
938				file_badread(ms);
939				return -1;
940			}
941			break;
942		    }
943		}
944	}
945	if (file_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1)
946		return -1;
947	if (cap_hw1) {
948		const cap_desc_t *cdp;
949		switch (mach) {
950		case EM_SPARC:
951		case EM_SPARC32PLUS:
952		case EM_SPARCV9:
953			cdp = cap_desc_sparc;
954			break;
955		case EM_386:
956		case EM_IA_64:
957		case EM_AMD64:
958			cdp = cap_desc_386;
959			break;
960		default:
961			cdp = NULL;
962			break;
963		}
964		if (file_printf(ms, ", uses") == -1)
965			return -1;
966		if (cdp) {
967			while (cdp->cd_name) {
968				if (cap_hw1 & cdp->cd_mask) {
969					if (file_printf(ms,
970					    " %s", cdp->cd_name) == -1)
971						return -1;
972					cap_hw1 &= ~cdp->cd_mask;
973				}
974				++cdp;
975			}
976			if (cap_hw1)
977				if (file_printf(ms,
978				    " unknown hardware capability 0x%llx",
979				    cap_hw1) == -1)
980					return -1;
981		} else {
982			if (file_printf(ms,
983			    " hardware capability 0x%llx", cap_hw1) == -1)
984				return -1;
985		}
986	}
987	if (cap_sf1) {
988		if (cap_sf1 & SF1_SUNW_FPUSED) {
989			if (file_printf(ms,
990			    (cap_sf1 & SF1_SUNW_FPKNWN)
991			    ? ", uses frame pointer"
992			    : ", not known to use frame pointer") == -1)
993				return -1;
994		}
995		cap_sf1 &= ~SF1_SUNW_MASK;
996		if (cap_sf1)
997			if (file_printf(ms,
998			    ", with unknown software capability 0x%llx",
999			    cap_sf1) == -1)
1000				return -1;
1001	}
1002	return 0;
1003}
1004
1005/*
1006 * Look through the program headers of an executable image, searching
1007 * for a PT_INTERP section; if one is found, it's dynamically linked,
1008 * otherwise it's statically linked.
1009 */
1010private int
1011dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
1012    int num, size_t size, off_t fsize, int *flags, int sh_num)
1013{
1014	Elf32_Phdr ph32;
1015	Elf64_Phdr ph64;
1016	const char *linking_style = "statically";
1017	const char *shared_libraries = "";
1018	unsigned char nbuf[BUFSIZ];
1019	int bufsize;
1020	size_t offset, align;
1021	off_t savedoffset = (off_t)-1;
1022	struct stat st;
1023
1024	if (fstat(fd, &st) < 0) {
1025		file_badread(ms);
1026		return -1;
1027	}
1028
1029	if (size != xph_sizeof) {
1030		if (file_printf(ms, ", corrupted program header size") == -1)
1031			return -1;
1032		return 0;
1033	}
1034
1035	if (lseek(fd, off, SEEK_SET) == (off_t)-1) {
1036		file_badseek(ms);
1037		return -1;
1038	}
1039
1040  	for ( ; num; num--) {
1041  		if (read(fd, xph_addr, xph_sizeof) == -1) {
1042  			file_badread(ms);
1043			return -1;
1044		}
1045		if (xph_offset > st.st_size && savedoffset != (off_t)-1) {
1046			if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) {
1047				file_badseek(ms);
1048				return -1;
1049			}
1050			continue;
1051		}
1052
1053		if ((savedoffset = lseek(fd, (off_t)0, SEEK_CUR)) == (off_t)-1) {
1054  			file_badseek(ms);
1055			return -1;
1056		}
1057
1058		if (xph_offset > fsize) {
1059			if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) {
1060				file_badseek(ms);
1061				return -1;
1062			}
1063			continue;
1064		}
1065
1066		switch (xph_type) {
1067		case PT_DYNAMIC:
1068			linking_style = "dynamically";
1069			break;
1070		case PT_INTERP:
1071			shared_libraries = " (uses shared libs)";
1072			break;
1073		case PT_NOTE:
1074			if ((align = xph_align) & 0x80000000) {
1075				if (file_printf(ms,
1076				    ", invalid note alignment 0x%lx",
1077				    (unsigned long)align) == -1)
1078					return -1;
1079				align = 4;
1080			}
1081			if (sh_num)
1082				break;
1083			/*
1084			 * This is a PT_NOTE section; loop through all the notes
1085			 * in the section.
1086			 */
1087			if (lseek(fd, xph_offset, SEEK_SET)
1088			    == (off_t)-1) {
1089				file_badseek(ms);
1090				return -1;
1091			}
1092			bufsize = read(fd, nbuf, ((xph_filesz < sizeof(nbuf)) ?
1093			    xph_filesz : sizeof(nbuf)));
1094			if (bufsize == -1) {
1095				file_badread(ms);
1096				return -1;
1097			}
1098			offset = 0;
1099			for (;;) {
1100				if (offset >= (size_t)bufsize)
1101					break;
1102				offset = donote(ms, nbuf, offset,
1103				    (size_t)bufsize, clazz, swap, align,
1104				    flags);
1105				if (offset == 0)
1106					break;
1107			}
1108			if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) {
1109				file_badseek(ms);
1110				return -1;
1111			}
1112			break;
1113		default:
1114			break;
1115		}
1116	}
1117	if (file_printf(ms, ", %s linked%s", linking_style, shared_libraries)
1118	    == -1)
1119	    return -1;
1120	return 0;
1121}
1122
1123
1124protected int
1125file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf,
1126    size_t nbytes)
1127{
1128	union {
1129		int32_t l;
1130		char c[sizeof (int32_t)];
1131	} u;
1132	int clazz;
1133	int swap;
1134	struct stat st;
1135	off_t fsize;
1136	int flags = 0;
1137	Elf32_Ehdr elf32hdr;
1138	Elf64_Ehdr elf64hdr;
1139	uint16_t type;
1140
1141	if (ms->flags & MAGIC_MIME)
1142		return 0;
1143	/*
1144	 * ELF executables have multiple section headers in arbitrary
1145	 * file locations and thus file(1) cannot determine it from easily.
1146	 * Instead we traverse thru all section headers until a symbol table
1147	 * one is found or else the binary is stripped.
1148	 * Return immediately if it's not ELF (so we avoid pipe2file unless needed).
1149	 */
1150	if (buf[EI_MAG0] != ELFMAG0
1151	    || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1)
1152	    || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3)
1153		return 0;
1154
1155	/*
1156	 * If we cannot seek, it must be a pipe, socket or fifo.
1157	 */
1158	if((lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE))
1159		fd = file_pipe2file(ms, fd, buf, nbytes);
1160
1161	if (fstat(fd, &st) == -1) {
1162  		file_badread(ms);
1163		return -1;
1164	}
1165	fsize = st.st_size;
1166
1167	clazz = buf[EI_CLASS];
1168
1169	switch (clazz) {
1170	case ELFCLASS32:
1171#undef elf_getu
1172#define elf_getu(a, b)	elf_getu32(a, b)
1173#undef elfhdr
1174#define elfhdr elf32hdr
1175#include "elfclass.h"
1176	case ELFCLASS64:
1177#undef elf_getu
1178#define elf_getu(a, b)	elf_getu64(a, b)
1179#undef elfhdr
1180#define elfhdr elf64hdr
1181#include "elfclass.h"
1182	default:
1183	    if (file_printf(ms, ", unknown class %d", clazz) == -1)
1184		    return -1;
1185	    break;
1186	}
1187	return 0;
1188}
1189#endif
1190