diff options
author | Ian Darwin <ian@cvs.openbsd.org> | 2003-03-03 22:24:09 +0000 |
---|---|---|
committer | Ian Darwin <ian@cvs.openbsd.org> | 2003-03-03 22:24:09 +0000 |
commit | bbdce50ddead0cf5f94e0990d5128d956feac22a (patch) | |
tree | 4c08c2c568fe1465407e89f35564d10bf01cfc31 | |
parent | feaab2c3359e071a52d36c7a567303a853510885 (diff) |
Bring in readelf.c from Christos' version 3.41 to head off a local
stack attack noted by iDefense, and for more complete 64-bit ELF support.
Add hand-made config.h to avoid running configure but still be able
to use Christos' code. In print.c add error(...)-->err(1,...) wrapper.
Tested on i386, sparc64, macppc.
-rw-r--r-- | usr.bin/file/Makefile | 4 | ||||
-rw-r--r-- | usr.bin/file/compress.c | 140 | ||||
-rw-r--r-- | usr.bin/file/file.h | 16 | ||||
-rw-r--r-- | usr.bin/file/print.c | 15 | ||||
-rw-r--r-- | usr.bin/file/readelf.c | 729 | ||||
-rw-r--r-- | usr.bin/file/readelf.h | 73 |
6 files changed, 763 insertions, 214 deletions
diff --git a/usr.bin/file/Makefile b/usr.bin/file/Makefile index a56db6b73d2..5c19142ba1f 100644 --- a/usr.bin/file/Makefile +++ b/usr.bin/file/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.8 1997/09/02 15:25:52 kstailey Exp $ +# $OpenBSD: Makefile,v 1.9 2003/03/03 22:24:08 ian Exp $ MAGIC= /etc/magic MAGICOWN= root @@ -8,7 +8,7 @@ MAGICMODE= 444 PROG= file SRCS= file.c apprentice.c fsmagic.c softmagic.c ascmagic.c is_tar.c \ print.c compress.c readelf.c internat.c -CFLAGS+= -DMAGIC='"$(MAGIC)"' -DUSE_UTIMES +CFLAGS+= -DMAGIC='"$(MAGIC)"' -DUSE_UTIMES -DHAVE_CONFIG_H MAN= file.1 magic.5 CLEANFILES+= magic diff --git a/usr.bin/file/compress.c b/usr.bin/file/compress.c index 081cf713c51..3d7d1e13266 100644 --- a/usr.bin/file/compress.c +++ b/usr.bin/file/compress.c @@ -1,4 +1,4 @@ -/* $OpenBSD: compress.c,v 1.5 2002/02/16 21:27:46 millert Exp $ */ +/* $OpenBSD: compress.c,v 1.6 2003/03/03 22:24:08 ian Exp $ */ /* * compress routines: @@ -7,19 +7,26 @@ * uncompress(method, old, n, newch) - uncompress old into new, * using method, return sizeof new */ -#include <sys/wait.h> -#include <stdio.h> +#include "file.h" #include <stdlib.h> +#ifdef HAVE_UNISTD_H #include <unistd.h> +#endif #include <string.h> +#ifdef HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif +#include <stdio.h> +#include <stdlib.h> #include <err.h> - -#include "file.h" +#ifdef HAVE_LIBZ +#include <zlib.h> +#endif static struct { - char *magic; + const char *magic; int maglen; - char *argv[3]; + const char *const argv[3]; int silent; } compr[] = { { "\037\235", 2, { "uncompress", "-c", NULL }, 0 }, /* compressed */ @@ -33,6 +40,8 @@ static struct { static int ncompr = sizeof(compr) / sizeof(compr[0]); +static int swrite(int, const void *, size_t); +static int sread(int, void *, size_t); static int uncompress(int, const unsigned char *, unsigned char **, int); int @@ -64,6 +73,121 @@ int nbytes; return 1; } +/* + * `safe' write for sockets and pipes. + */ +static int +swrite(int fd, const void *buf, size_t n) +{ + int rv; + size_t rn = n; + + do + switch (rv = write(fd, buf, n)) { + case -1: + if (errno == EINTR) + continue; + return -1; + default: + n -= rv; + buf = ((const char *)buf) + rv; + break; + } + while (n > 0); + return rn; +} + +/* + * `safe' read for sockets and pipes. + */ +static int +sread(int fd, void *buf, size_t n) +{ + int rv; + size_t rn = n; + + do + switch (rv = read(fd, buf, n)) { + case -1: + if (errno == EINTR) + continue; + return -1; + case 0: + return rn - n; + default: + n -= rv; + buf = ((char *)buf) + rv; + break; + } + while (n > 0); + return rn; +} + +int +pipe2file(int fd, void *startbuf, size_t nbytes) +{ + char buf[4096]; + int r, tfd; + + (void)strcpy(buf, "/tmp/file.XXXXXX"); +#ifndef HAVE_MKSTEMP + { + char *ptr = mktemp(buf); + tfd = open(ptr, O_RDWR|O_TRUNC|O_EXCL|O_CREAT, 0600); + r = errno; + (void)unlink(ptr); + errno = r; + } +#else + tfd = mkstemp(buf); + r = errno; + (void)unlink(buf); + errno = r; +#endif + if (tfd == -1) { + error("Can't create temporary file for pipe copy (%s)\n", + strerror(errno)); + /*NOTREACHED*/ + } + + if (swrite(tfd, startbuf, nbytes) != nbytes) + r = 1; + else { + while ((r = sread(fd, buf, sizeof(buf))) > 0) + if (swrite(tfd, buf, r) != r) + break; + } + + switch (r) { + case -1: + error("Error copying from pipe to temp file (%s)\n", + strerror(errno)); + /*NOTREACHED*/ + case 0: + break; + default: + error("Error while writing to temp file (%s)\n", + strerror(errno)); + /*NOTREACHED*/ + } + + /* + * We duplicate the file descriptor, because fclose on a + * tmpfile will delete the file, but any open descriptors + * can still access the phantom inode. + */ + if ((fd = dup2(tfd, fd)) == -1) { + error("Couldn't dup destcriptor for temp file(%s)\n", + strerror(errno)); + /*NOTREACHED*/ + } + (void)close(tfd); + if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) { + error("Couldn't seek on temp file (%s)\n", strerror(errno)); + /*NOTREACHED*/ + } + return fd; +} static int uncompress(method, old, newch, n) @@ -92,7 +216,7 @@ int n; if (compr[method].silent) (void) close(2); - execvp(compr[method].argv[0], compr[method].argv); + execvp(compr[method].argv[0], (char *const *)compr[method].argv); err(1, "could not execute `%s'", compr[method].argv[0]); /*NOTREACHED*/ case -1: diff --git a/usr.bin/file/file.h b/usr.bin/file/file.h index 8f5c9071fed..ef4dbf22089 100644 --- a/usr.bin/file/file.h +++ b/usr.bin/file/file.h @@ -1,4 +1,4 @@ -/* $OpenBSD: file.h,v 1.10 2002/06/05 13:46:44 itojun Exp $ */ +/* $OpenBSD: file.h,v 1.11 2003/03/03 22:24:08 ian Exp $ */ /* * file.h - definitions for file(1) program @@ -30,6 +30,18 @@ #ifndef __file_h__ #define __file_h__ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include <stdio.h> +#ifdef HAVE_STDINT_H +#include <stdint.h> +#elif defined(HAVE_INTTYPES_H) +#include <inttypes.h> +#endif + #ifndef HOWMANY # define HOWMANY 8192 /* how much of the file to look at */ #endif @@ -91,7 +103,7 @@ extern int zmagic(unsigned char *, int); extern void ckfprintf(FILE *, const char *, ...); extern uint32_t signextend(struct magic *, uint32_t); extern int internatmagic(unsigned char *, int); -extern void tryelf(int, char *, int); +extern void tryelf(int, unsigned char *, int); extern int errno; /* Some unixes don't define this.. */ diff --git a/usr.bin/file/print.c b/usr.bin/file/print.c index 804eb79b0c2..93fa8498e50 100644 --- a/usr.bin/file/print.c +++ b/usr.bin/file/print.c @@ -1,4 +1,4 @@ -/* $OpenBSD: print.c,v 1.7 2002/02/19 19:39:38 millert Exp $ */ +/* $OpenBSD: print.c,v 1.8 2003/03/03 22:24:08 ian Exp $ */ /* * print.c - debugging printout routines @@ -38,7 +38,7 @@ #include "file.h" #ifndef lint -static char *moduleid = "$OpenBSD: print.c,v 1.7 2002/02/19 19:39:38 millert Exp $"; +static char *moduleid = "$OpenBSD: print.c,v 1.8 2003/03/03 22:24:08 ian Exp $"; #endif /* lint */ #define SZOF(a) (sizeof(a) / sizeof(a[0])) @@ -106,6 +106,17 @@ struct magic *m; } /* + * This "error" is here so we don't have to change all occurrences of + * error() to err(1,...) when importing new versions from Christos. + */ +void error(const char *fmt, ...) +{ + va_list va; + va_start(va, fmt); + verr(1, fmt, va); +} + +/* * ckfputs - futs, but with error checking * ckfprintf - fprintf, but with error checking */ diff --git a/usr.bin/file/readelf.c b/usr.bin/file/readelf.c index 6d7ea277202..5cd235ebdd0 100644 --- a/usr.bin/file/readelf.c +++ b/usr.bin/file/readelf.c @@ -1,42 +1,150 @@ -/* $OpenBSD: readelf.c,v 1.3 2002/06/05 13:46:44 itojun Exp $ */ +#include "file.h" #ifdef BUILTIN_ELF -#include <sys/types.h> #include <string.h> -#include <stdio.h> #include <ctype.h> #include <stdlib.h> +#ifdef HAVE_UNISTD_H #include <unistd.h> -#include <errno.h> +#endif #include "readelf.h" -#include "file.h" + +#ifndef lint +static char *RCSID = "@(#)$Id: readelf.c,v 1.4 2003/03/03 22:24:08 ian Exp $"; +#endif + +#ifdef ELFCORE +static void dophn_core(int, int, int, off_t, int, size_t); +#endif +static void dophn_exec(int, int, int, off_t, int, size_t); +static void doshn(int, int, int, off_t, int, size_t); + +static uint16_t getu16(int, uint16_t); +static uint32_t getu32(int, uint32_t); +static uint64_t getu64(int, uint64_t); + +static uint16_t +getu16(int swap, uint16_t value) +{ + union { + uint16_t ui; + char c[2]; + } retval, tmpval; + + if (swap) { + tmpval.ui = value; + + retval.c[0] = tmpval.c[1]; + retval.c[1] = tmpval.c[0]; + + return retval.ui; + } else + return value; +} + +static uint32_t +getu32(int swap, uint32_t value) +{ + union { + uint32_t ui; + char c[4]; + } retval, tmpval; + + if (swap) { + tmpval.ui = value; + + retval.c[0] = tmpval.c[3]; + retval.c[1] = tmpval.c[2]; + retval.c[2] = tmpval.c[1]; + retval.c[3] = tmpval.c[0]; + + return retval.ui; + } else + return value; +} + +static uint64_t +getu64(int swap, uint64_t value) +{ + union { + uint64_t ui; + char c[8]; + } retval, tmpval; + + if (swap) { + tmpval.ui = value; + + retval.c[0] = tmpval.c[7]; + retval.c[1] = tmpval.c[6]; + retval.c[2] = tmpval.c[5]; + retval.c[3] = tmpval.c[4]; + retval.c[4] = tmpval.c[3]; + retval.c[5] = tmpval.c[2]; + retval.c[6] = tmpval.c[1]; + retval.c[7] = tmpval.c[0]; + + return retval.ui; + } else + return value; +} + +#define sh_addr (class == ELFCLASS32 \ + ? (void *) &sh32 \ + : (void *) &sh64) +#define sh_size (class == ELFCLASS32 \ + ? sizeof sh32 \ + : sizeof sh64) +#define shs_type (class == ELFCLASS32 \ + ? getu32(swap, sh32.sh_type) \ + : getu32(swap, sh64.sh_type)) +#define ph_addr (class == ELFCLASS32 \ + ? (void *) &ph32 \ + : (void *) &ph64) +#define ph_size (class == ELFCLASS32 \ + ? sizeof ph32 \ + : sizeof ph64) +#define ph_type (class == ELFCLASS32 \ + ? getu32(swap, ph32.p_type) \ + : getu32(swap, ph64.p_type)) +#define ph_offset (class == ELFCLASS32 \ + ? getu32(swap, ph32.p_offset) \ + : getu64(swap, ph64.p_offset)) +#define ph_align (class == ELFCLASS32 \ + ? (ph32.p_align ? getu32(swap, ph32.p_align) : 4) \ + : (ph64.p_align ? getu64(swap, ph64.p_align) : 4)) +#define nh_size (class == ELFCLASS32 \ + ? sizeof *nh32 \ + : sizeof *nh64) +#define nh_type (class == ELFCLASS32 \ + ? getu32(swap, nh32->n_type) \ + : getu32(swap, nh64->n_type)) +#define nh_namesz (class == ELFCLASS32 \ + ? getu32(swap, nh32->n_namesz) \ + : getu32(swap, nh64->n_namesz)) +#define nh_descsz (class == ELFCLASS32 \ + ? getu32(swap, nh32->n_descsz) \ + : getu32(swap, nh64->n_descsz)) +#define prpsoffsets(i) (class == ELFCLASS32 \ + ? prpsoffsets32[i] \ + : prpsoffsets64[i]) static void -doshn(fd, off, num, size, buf) - int fd; - off_t off; - int num; - size_t size; - char *buf; +doshn(int class, int swap, int fd, off_t off, int num, size_t size) { - /* - * This works for both 32-bit and 64-bit ELF formats, - * because it looks only at the "sh_type" field, which is - * always 32 bits, and is preceded only by the "sh_name" - * field which is also always 32 bits, and because it uses - * the shdr size from the ELF header rather than using - * the size of an "Elf32_Shdr". - */ - Elf32_Shdr *sh = (Elf32_Shdr *) buf; + Elf32_Shdr sh32; + Elf64_Shdr sh64; + + if (size != sh_size) + error("corrupted section header size.\n"); if (lseek(fd, off, SEEK_SET) == -1) - err(1, "lseek failed"); + error("lseek failed (%s).\n", strerror(errno)); for ( ; num; num--) { - if (read(fd, buf, size) == -1) - err(1, "read failed"); - if (sh->sh_type == SHT_SYMTAB) { + if (read(fd, sh_addr, sh_size) == -1) + error("read failed (%s).\n", strerror(errno)); + if (shs_type == SHT_SYMTAB /* || shs_type == SHT_DYNSYM */) { (void) printf (", not stripped"); return; } @@ -50,186 +158,417 @@ doshn(fd, off, num, size, buf) * otherwise it's statically linked. */ static void -dophn_exec(fd, off, num, size, buf) - int fd; - off_t off; - int num; - size_t size; - char *buf; +dophn_exec(int class, int swap, int fd, off_t off, int num, size_t size) { - /* I am not sure if this works for 64 bit elf formats */ - Elf32_Phdr *ph = (Elf32_Phdr *) buf; + Elf32_Phdr ph32; + Elf32_Nhdr *nh32 = NULL; + Elf64_Phdr ph64; + Elf64_Nhdr *nh64 = NULL; + char *linking_style = "statically"; + char *shared_libraries = ""; + char nbuf[BUFSIZ]; + int bufsize; + size_t offset, nameoffset; + off_t savedoffset; + if (size != ph_size) + error("corrupted program header size.\n"); if (lseek(fd, off, SEEK_SET) == -1) - err(1, "lseek failed"); + error("lseek failed (%s).\n", strerror(errno)); for ( ; num; num--) { - if (read(fd, buf, size) == -1) - err(1, "read failed"); - if (ph->p_type == PT_INTERP) { + if (read(fd, ph_addr, ph_size) == -1) + error("read failed (%s).\n", strerror(errno)); + if ((savedoffset = lseek(fd, 0, SEEK_CUR)) == -1) + error("lseek failed (%s).\n", strerror(errno)); + + switch (ph_type) { + case PT_DYNAMIC: + linking_style = "dynamically"; + break; + case PT_INTERP: + shared_libraries = " (uses shared libs)"; + break; + case PT_NOTE: /* - * Has an interpreter - must be a dynamically-linked - * executable. + * This is a PT_NOTE section; loop through all the notes + * in the section. */ - printf(", dynamically linked"); - return; + if (lseek(fd, (off_t) ph_offset, SEEK_SET) == -1) + error("lseek failed (%s).\n", strerror(errno)); + bufsize = read(fd, nbuf, sizeof(nbuf)); + if (bufsize == -1) + error(": " "read failed (%s).\n", + strerror(errno)); + offset = 0; + for (;;) { + if (offset >= bufsize) + break; + if (class == ELFCLASS32) + nh32 = (Elf32_Nhdr *)&nbuf[offset]; + else + nh64 = (Elf64_Nhdr *)&nbuf[offset]; + offset += nh_size; + + if (offset + nh_namesz >= bufsize) { + /* + * We're past the end of the buffer. + */ + break; + } + + nameoffset = offset; + offset += nh_namesz; + offset = ((offset+ph_align-1)/ph_align)*ph_align; + + if ((nh_namesz == 0) && (nh_descsz == 0)) { + /* + * We're out of note headers. + */ + break; + } + + if (offset + nh_descsz >= bufsize) + break; + + if (nh_namesz == 4 && + strcmp(&nbuf[nameoffset], "GNU") == 0 && + nh_type == NT_GNU_VERSION && + nh_descsz == 16) { + uint32_t *desc = + (uint32_t *)&nbuf[offset]; + + printf(", for GNU/"); + switch (getu32(swap, desc[0])) { + case GNU_OS_LINUX: + printf("Linux"); + break; + case GNU_OS_HURD: + printf("Hurd"); + break; + case GNU_OS_SOLARIS: + printf("Solaris"); + break; + default: + printf("<unknown>"); + } + printf(" %d.%d.%d", + getu32(swap, desc[1]), + getu32(swap, desc[2]), + getu32(swap, desc[3])); + } + + if (nh_namesz == 7 && + strcmp(&nbuf[nameoffset], "NetBSD") == 0 && + nh_type == NT_NETBSD_VERSION && + nh_descsz == 4) { + printf(", for NetBSD"); + /* + * Version number is stuck at 199905, + * and hence is basically content-free. + */ + } + + if (nh_namesz == 8 && + strcmp(&nbuf[nameoffset], "FreeBSD") == 0 && + nh_type == NT_FREEBSD_VERSION && + nh_descsz == 4) { + uint32_t desc = getu32(swap, + *(uint32_t *)&nbuf[offset]); + printf(", for FreeBSD"); + /* + * Contents is __FreeBSD_version, + * whose relation to OS versions is + * defined by a huge table in the + * Porters' Handbook. Happily, the + * first three digits are the version + * number, at least in versions of + * FreeBSD that use this note. + */ + + printf(" %d.%d", desc / 100000, + desc / 10000 % 10); + if (desc / 1000 % 10 > 0) + printf(".%d", + desc / 1000 % 10); + } + + if (nh_namesz == 8 && + strcmp(&nbuf[nameoffset], "OpenBSD") == 0 && + nh_type == NT_OPENBSD_VERSION && + nh_descsz == 4) { + printf(", for OpenBSD"); + /* Content of note is always 0 */ + } + } + if ((lseek(fd, savedoffset + offset, SEEK_SET)) == -1) + error("lseek failed (%s).\n", strerror(errno)); + break; } } - printf(", statically linked"); + printf(", %s linked%s", linking_style, shared_libraries); } -size_t prpsoffsets[] = { - 100, /* SunOS 5.x */ - 32, /* Linux */ +#ifdef ELFCORE +size_t prpsoffsets32[] = { + 8, /* FreeBSD */ + 28, /* Linux 2.0.36 */ + 32, /* Linux (I forget which kernel version) */ + 84, /* SunOS 5.x */ +}; + +size_t prpsoffsets64[] = { + 120, /* SunOS 5.x, 64-bit */ }; -#define NOFFSETS (sizeof prpsoffsets / sizeof prpsoffsets[0]) +#define NOFFSETS32 (sizeof prpsoffsets32 / sizeof prpsoffsets32[0]) +#define NOFFSETS64 (sizeof prpsoffsets64 / sizeof prpsoffsets64[0]) + +#define NOFFSETS (class == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64) /* * Look through the program headers of an executable image, searching - * for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE"; if one - * is found, try looking in various places in its contents for a 16-character - * string containing only printable characters - if found, that string - * should be the name of the program that dropped core. - * Note: right after that 16-character string is, at least in SunOS 5.x - * (and possibly other SVR4-flavored systems) and Linux, a longer string - * (80 characters, in 5.x, probably other SVR4-flavored systems, and Linux) - * containing the start of the command line for that program. + * for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE" or + * "FreeBSD"; if one is found, try looking in various places in its + * contents for a 16-character string containing only printable + * characters - if found, that string should be the name of the program + * that dropped core. Note: right after that 16-character string is, + * at least in SunOS 5.x (and possibly other SVR4-flavored systems) and + * Linux, a longer string (80 characters, in 5.x, probably other + * SVR4-flavored systems, and Linux) containing the start of the + * command line for that program. + * + * The signal number probably appears in a section of type NT_PRSTATUS, + * but that's also rather OS-dependent, in ways that are harder to + * dissect with heuristics, so I'm not bothering with the signal number. + * (I suppose the signal number could be of interest in situations where + * you don't have the binary of the program that dropped core; if you + * *do* have that binary, the debugger will probably tell you what + * signal it was.) */ + +#define OS_STYLE_SVR4 0 +#define OS_STYLE_FREEBSD 1 +#define OS_STYLE_NETBSD 2 + +static const char *os_style_names[] = { + "SVR4", + "FreeBSD", + "NetBSD", +}; + static void -dophn_core(fd, off, num, size, buf) - int fd; - off_t off; - int num; - size_t size; - char *buf; +dophn_core(int class, int swap, int fd, off_t off, int num, size_t size) { - /* - * This doesn't work for 64-bit ELF, as the "p_offset" field is - * 64 bits in 64-bit ELF. - */ - /* - * This doesn't work for 64-bit ELF, as the "p_offset" field is - * 64 bits in 64-bit ELF. - */ - Elf32_Phdr *ph = (Elf32_Phdr *) buf; - Elf32_Nhdr *nh; - size_t offset, noffset, reloffset; + Elf32_Phdr ph32; + Elf32_Nhdr *nh32 = NULL; + Elf64_Phdr ph64; + Elf64_Nhdr *nh64 = NULL; + size_t offset, nameoffset, noffset, reloffset; unsigned char c; int i, j; char nbuf[BUFSIZ]; int bufsize; + int os_style = -1; + if (size != ph_size) + error("corrupted program header size.\n"); + /* + * Loop through all the program headers. + */ for ( ; num; num--) { if (lseek(fd, off, SEEK_SET) == -1) - err(1, "lseek failed"); - if (read(fd, buf, size) == -1) - err(1, "read failed"); + error("lseek failed (%s).\n", strerror(errno)); + if (read(fd, ph_addr, ph_size) == -1) + error("read failed (%s).\n", strerror(errno)); off += size; - if (ph->p_type != PT_NOTE) + if (ph_type != PT_NOTE) continue; - if (lseek(fd, ph->p_offset, SEEK_SET) == -1) - err(1, "lseek failed"); + + /* + * This is a PT_NOTE section; loop through all the notes + * in the section. + */ + if (lseek(fd, (off_t) ph_offset, SEEK_SET) == -1) + error("lseek failed (%s).\n", strerror(errno)); bufsize = read(fd, nbuf, BUFSIZ); if (bufsize == -1) - err(1, "read failed"); + error(": " "read failed (%s).\n", strerror(errno)); offset = 0; for (;;) { if (offset >= bufsize) break; - nh = (Elf32_Nhdr *)&nbuf[offset]; - offset += sizeof *nh; - - /* - * If this note isn't an NT_PRPSINFO note, it's - * not what we're looking for. - */ - if (nh->n_type != NT_PRPSINFO) { - offset += nh->n_namesz; - offset = ((offset + 3)/4)*4; - offset += nh->n_descsz; - offset = ((offset + 3)/4)*4; - continue; - } + if (class == ELFCLASS32) + nh32 = (Elf32_Nhdr *)&nbuf[offset]; + else + nh64 = (Elf64_Nhdr *)&nbuf[offset]; + offset += nh_size; /* - * Make sure this note has the name "CORE". + * Check whether this note has the name "CORE" or + * "FreeBSD", or "NetBSD-CORE". */ - if (offset + nh->n_namesz >= bufsize) { + if (offset + nh_namesz >= bufsize) { /* * We're past the end of the buffer. */ break; } - if (nh->n_namesz != 5 - || strcmp(&nbuf[offset], "CORE") != 0) - continue; - offset += nh->n_namesz; + + nameoffset = offset; + offset += nh_namesz; offset = ((offset + 3)/4)*4; /* - * Extract the program name. We assume it to be - * 16 characters (that's what it is in SunOS 5.x - * and Linux). - * - * Unfortunately, it's at a different offset in - * SunOS 5.x and Linux, so try multiple offsets. - * If the characters aren't all printable, reject - * it. + * Sigh. The 2.0.36 kernel in Debian 2.1, at + * least, doesn't correctly implement name + * sections, in core dumps, as specified by + * the "Program Linking" section of "UNIX(R) System + * V Release 4 Programmer's Guide: ANSI C and + * Programming Support Tools", because my copy + * clearly says "The first 'namesz' bytes in 'name' + * contain a *null-terminated* [emphasis mine] + * character representation of the entry's owner + * or originator", but the 2.0.36 kernel code + * doesn't include the terminating null in the + * name.... */ - for (i = 0; i < NOFFSETS; i++) { - reloffset = prpsoffsets[i]; - noffset = offset + reloffset; - for (j = 0; j < 16; - j++, noffset++, reloffset++) { - /* - * Make sure we're not past the end - * of the buffer; if we are, just - * give up. - */ - if (noffset >= bufsize) - return; + if (os_style == -1) { + if ((nh_namesz == 4 && + strncmp(&nbuf[nameoffset], + "CORE", 4) == 0) || + (nh_namesz == 5 && + strcmp(&nbuf[nameoffset], + "CORE") == 0)) { + os_style = OS_STYLE_SVR4; + } else + if ((nh_namesz == 8 && + strcmp(&nbuf[nameoffset], + "FreeBSD") == 0)) { + os_style = OS_STYLE_FREEBSD; + } else + if ((nh_namesz >= 11 && + strncmp(&nbuf[nameoffset], + "NetBSD-CORE", 11) == 0)) { + os_style = OS_STYLE_NETBSD; + } else + continue; + printf(", %s-style", os_style_names[os_style]); + } - /* - * Make sure we're not past the - * end of the contents; if we - * are, this obviously isn't - * the right offset. - */ - if (reloffset >= nh->n_descsz) - goto tryanother; - - c = nbuf[noffset]; - if (c != '\0' && !isprint(c)) - goto tryanother; - } + if (os_style == OS_STYLE_NETBSD && + nh_type == NT_NETBSD_CORE_PROCINFO) { + uint32_t signo; /* - * Well, that worked. + * Extract the program name. It is at + * offset 0x7c, and is up to 32-bytes, + * including the terminating NUL. + */ + printf(", from '%.31s'", &nbuf[offset + 0x7c]); + + /* + * Extract the signal number. It is at + * offset 0x08. */ - printf(", from '%.16s'", - &nbuf[offset + prpsoffsets[i]]); - return; + memcpy(&signo, &nbuf[offset + 0x08], + sizeof(signo)); + printf(" (signal %u)", getu32(swap, signo)); + } else + if (os_style != OS_STYLE_NETBSD && + nh_type == NT_PRPSINFO) { + /* + * Extract the program name. We assume + * it to be 16 characters (that's what it + * is in SunOS 5.x and Linux). + * + * Unfortunately, it's at a different offset + * in varous OSes, so try multiple offsets. + * If the characters aren't all printable, + * reject it. + */ + for (i = 0; i < NOFFSETS; i++) { + reloffset = prpsoffsets(i); + noffset = offset + reloffset; + for (j = 0; j < 16; + j++, noffset++, reloffset++) { + /* + * Make sure we're not past + * the end of the buffer; if + * we are, just give up. + */ + if (noffset >= bufsize) + goto tryanother; + + /* + * Make sure we're not past + * the end of the contents; + * if we are, this obviously + * isn't the right offset. + */ + if (reloffset >= nh_descsz) + goto tryanother; + + c = nbuf[noffset]; + if (c == '\0') { + /* + * A '\0' at the + * beginning is + * obviously wrong. + * Any other '\0' + * means we're done. + */ + if (j == 0) + goto tryanother; + else + break; + } else { + /* + * A nonprintable + * character is also + * wrong. + */ +#define isquote(c) (strchr("'\"`", (c)) != NULL) + if (!isprint(c) || + isquote(c)) + goto tryanother; + } + } - tryanother: - ; + /* + * Well, that worked. + */ + printf(", from '%.16s'", + &nbuf[offset + prpsoffsets(i)]); + break; + + tryanother: + ; + } + break; } - offset += nh->n_descsz; + offset += nh_descsz; offset = ((offset + 3)/4)*4; } } } +#endif void -tryelf(fd, buf, nbytes) - int fd; - char *buf; - int nbytes; +tryelf(int fd, unsigned char *buf, int nbytes) { union { int32_t l; char c[sizeof (int32_t)]; } u; + int class; + int swap; + + /* + * If we can't seek, it must be a pipe, socket or fifo. + */ + if((lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE)) + fd = pipe2file(fd, buf, nbytes); /* * ELF executables have multiple section headers in arbitrary @@ -237,12 +576,15 @@ tryelf(fd, buf, nbytes) * Instead we traverse thru all section headers until a symbol table * one is found or else the binary is stripped. */ - if (buf[EI_MAG0] != ELFMAG0 || buf[EI_MAG1] != ELFMAG1 + if (buf[EI_MAG0] != ELFMAG0 + || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1) || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3) return; - if (buf[4] == ELFCLASS32) { + class = buf[4]; + + if (class == ELFCLASS32) { Elf32_Ehdr elfhdr; if (nbytes <= sizeof (Elf32_Ehdr)) return; @@ -250,31 +592,36 @@ tryelf(fd, buf, nbytes) u.l = 1; (void) memcpy(&elfhdr, buf, sizeof elfhdr); - /* - * If the system byteorder does not equal the - * object byteorder then don't test. - * XXX - we could conceivably fix up the "dophn_XXX()" and - * "doshn()" routines to extract stuff in the right - * byte order.... - */ - if ((u.c[sizeof(long) - 1] + 1) == elfhdr.e_ident[5]) { - if (elfhdr.e_type == ET_CORE) - dophn_core(fd, elfhdr.e_phoff, elfhdr.e_phnum, - elfhdr.e_phentsize, buf); - else { - if (elfhdr.e_type == ET_EXEC) { - dophn_exec(fd, elfhdr.e_phoff, - elfhdr.e_phnum, - elfhdr.e_phentsize, buf); - } - doshn(fd, elfhdr.e_shoff, elfhdr.e_shnum, - elfhdr.e_shentsize, buf); + swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[5]; + + if (getu16(swap, elfhdr.e_type) == ET_CORE) +#ifdef ELFCORE + dophn_core(class, swap, + fd, + getu32(swap, elfhdr.e_phoff), + getu16(swap, elfhdr.e_phnum), + getu16(swap, elfhdr.e_phentsize)); +#else + ; +#endif + else { + if (getu16(swap, elfhdr.e_type) == ET_EXEC) { + dophn_exec(class, swap, + fd, + getu32(swap, elfhdr.e_phoff), + getu16(swap, elfhdr.e_phnum), + getu16(swap, elfhdr.e_phentsize)); } + doshn(class, swap, + fd, + getu32(swap, elfhdr.e_shoff), + getu16(swap, elfhdr.e_shnum), + getu16(swap, elfhdr.e_shentsize)); } return; } - if (buf[4] == ELFCLASS64) { + if (class == ELFCLASS64) { Elf64_Ehdr elfhdr; if (nbytes <= sizeof (Elf64_Ehdr)) return; @@ -282,32 +629,44 @@ tryelf(fd, buf, nbytes) u.l = 1; (void) memcpy(&elfhdr, buf, sizeof elfhdr); + swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[5]; - /* - * If the system byteorder does not equal the - * object byteorder then don't test. - * XXX - we could conceivably fix up the "dophn_XXX()" and - * "doshn()" routines to extract stuff in the right - * byte order.... - */ - if ((u.c[sizeof(long) - 1] + 1) == elfhdr.e_ident[5]) { -#ifdef notyet - if (elfhdr.e_type == ET_CORE) - dophn_core(fd, elfhdr.e_phoff, elfhdr.e_phnum, - elfhdr.e_phentsize, buf); - else + if (getu16(swap, elfhdr.e_type) == ET_CORE) +#ifdef ELFCORE + dophn_core(class, swap, + fd, +#ifdef USE_ARRAY_FOR_64BIT_TYPES + getu32(swap, elfhdr.e_phoff[1]), +#else + getu64(swap, elfhdr.e_phoff), #endif - { -#ifdef notyet - if (elfhdr.e_type == ET_EXEC) { - dophn_exec(fd, elfhdr.e_phoff, - elfhdr.e_phnum, - elfhdr.e_phentsize, buf); - } + getu16(swap, elfhdr.e_phnum), + getu16(swap, elfhdr.e_phentsize)); +#else + ; +#endif + else + { + if (getu16(swap, elfhdr.e_type) == ET_EXEC) { + dophn_exec(class, swap, + fd, +#ifdef USE_ARRAY_FOR_64BIT_TYPES + getu32(swap, elfhdr.e_phoff[1]), +#else + getu64(swap, elfhdr.e_phoff), #endif - doshn(fd, elfhdr.e_shoff, elfhdr.e_shnum, - elfhdr.e_shentsize, buf); + getu16(swap, elfhdr.e_phnum), + getu16(swap, elfhdr.e_phentsize)); } + doshn(class, swap, + fd, +#ifdef USE_ARRAY_FOR_64BIT_TYPES + getu32(swap, elfhdr.e_shoff[1]), +#else + getu64(swap, elfhdr.e_shoff), +#endif + getu16(swap, elfhdr.e_shnum), + getu16(swap, elfhdr.e_shentsize)); } return; } diff --git a/usr.bin/file/readelf.h b/usr.bin/file/readelf.h index bf661012747..f7494de6b61 100644 --- a/usr.bin/file/readelf.h +++ b/usr.bin/file/readelf.h @@ -1,7 +1,8 @@ -/* $OpenBSD: readelf.h,v 1.1 1997/02/09 23:58:34 millert Exp $ */ +/* $NetBSD: readelf.h,v 1.9 2002/05/18 07:00:47 pooka Exp $ */ /* * readelf.h + * @(#)Id: readelf.h,v 1.9 2002/05/16 18:45:56 christos Exp * * Provide elf data structures for non-elf machines, allowing file * non-elf hosts to determine if an elf binary is stripped. @@ -10,18 +11,29 @@ #ifndef __fake_elf_h__ #define __fake_elf_h__ -typedef unsigned int Elf32_Addr; -typedef unsigned short Elf32_Half; -typedef unsigned int Elf32_Off; -typedef unsigned int Elf32_Word; -typedef unsigned char Elf32_Char; +#if HAVE_STDINT_H +#include <stdint.h> +#endif -/* XXX: We need 64 bit numbers here */ -typedef unsigned int Elf64_Addr[2]; -typedef unsigned short Elf64_Half; -typedef unsigned int Elf64_Off[2]; -typedef unsigned int Elf64_Word; -typedef unsigned char Elf64_Char; +typedef uint32_t Elf32_Addr; +typedef uint32_t Elf32_Off; +typedef uint16_t Elf32_Half; +typedef uint32_t Elf32_Word; +typedef uint8_t Elf32_Char; + +#if SIZEOF_UINT64_T != 8 +#define USE_ARRAY_FOR_64BIT_TYPES +typedef uint32_t Elf64_Addr[2]; +typedef uint32_t Elf64_Off[2]; +typedef uint32_t Elf64_Xword[2]; +#else +typedef uint64_t Elf64_Addr; +typedef uint64_t Elf64_Off; +typedef uint64_t Elf64_Xword; +#endif +typedef uint16_t Elf64_Half; +typedef uint32_t Elf64_Word; +typedef uint8_t Elf64_Char; #define EI_NIDENT 16 @@ -66,6 +78,7 @@ typedef struct { /* sh_type */ #define SHT_SYMTAB 2 #define SHT_NOTE 7 +#define SHT_DYNSYM 11 /* elf type */ #define ELFDATANONE 0 /* e_ident[EI_DATA] */ @@ -93,6 +106,9 @@ typedef struct { #define ELFMAG3 'F' #define ELFMAG "\177ELF" +#define OLFMAG1 'O' +#define OLFMAG "\177OLF" + typedef struct { Elf32_Word p_type; Elf32_Off p_offset; @@ -104,6 +120,17 @@ typedef struct { Elf32_Word p_align; } Elf32_Phdr; +typedef struct { + Elf64_Word p_type; + Elf64_Word p_flags; + Elf64_Off p_offset; + Elf64_Addr p_vaddr; + Elf64_Addr p_paddr; + Elf64_Xword p_filesz; + Elf64_Xword p_memsz; + Elf64_Xword p_align; +} Elf64_Phdr; + #define PT_NULL 0 /* p_type */ #define PT_LOAD 1 #define PT_DYNAMIC 2 @@ -145,11 +172,13 @@ typedef struct { #define NT_PRPSINFO 3 #define NT_TASKSTRUCT 4 +#define NT_NETBSD_CORE_PROCINFO 1 + /* Note header in a PT_NOTE section */ typedef struct elf_note { - Elf32_Word n_namesz; /* Name size */ - Elf32_Word n_descsz; /* Content size */ - Elf32_Word n_type; /* Content type */ + Elf32_Word n_namesz; /* Name size */ + Elf32_Word n_descsz; /* Content size */ + Elf32_Word n_type; /* Content type */ } Elf32_Nhdr; typedef struct { @@ -165,4 +194,18 @@ typedef struct { #define NT_PLATFORM 5 #define NT_AUXV 6 +/* Note types used in executables */ +/* NetBSD executables (name = "NetBSD") */ +#define NT_NETBSD_VERSION 1 +#define NT_NETBSD_EMULATION 2 +#define NT_FREEBSD_VERSION 1 +#define NT_OPENBSD_VERSION 1 +/* GNU executables (name = "GNU") */ +#define NT_GNU_VERSION 1 + +/* GNU OS tags */ +#define GNU_OS_LINUX 0 +#define GNU_OS_HURD 1 +#define GNU_OS_SOLARIS 2 + #endif |