version 1.8, 2004/05/19 02:32:35 |
version 1.9, 2008/05/08 01:40:56 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* documentation and/or other materials provided with the distribution. |
* 3. The name of the author may not be used to endorse or promote products |
|
* derived from this software without specific prior written permission. |
|
* |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
|
#endif |
#endif |
|
|
#ifdef ELFCORE |
#ifdef ELFCORE |
private int dophn_core(struct magic_set *, int, int, int, off_t, int, size_t); |
private int dophn_core(struct magic_set *, int, int, int, off_t, int, size_t, |
|
off_t, int *); |
#endif |
#endif |
private int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t); |
private int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t, |
private int doshn(struct magic_set *, int, int, int, off_t, int, size_t); |
off_t, int *); |
|
private int doshn(struct magic_set *, int, int, int, off_t, int, size_t, int *); |
private size_t donote(struct magic_set *, unsigned char *, size_t, size_t, int, |
private size_t donote(struct magic_set *, unsigned char *, size_t, size_t, int, |
int, size_t); |
int, size_t, int *); |
|
|
#define ELF_ALIGN(a) ((((a) + align - 1) / align) * align) |
#define ELF_ALIGN(a) ((((a) + align - 1) / align) * align) |
|
|
|
#define isquote(c) (strchr("'\"`", (c)) != NULL) |
|
|
private uint16_t getu16(int, uint16_t); |
private uint16_t getu16(int, uint16_t); |
private uint32_t getu32(int, uint32_t); |
private uint32_t getu32(int, uint32_t); |
private uint64_t getu64(int, uint64_t); |
private uint64_t getu64(int, uint64_t); |
|
|
return value; |
return value; |
} |
} |
|
|
#define sh_addr (class == ELFCLASS32 \ |
#ifdef USE_ARRAY_FOR_64BIT_TYPES |
|
# define elf_getu64(swap, array) \ |
|
((swap ? ((uint64_t)getu32(swap, array[0])) << 32 : getu32(swap, array[0])) + \ |
|
(swap ? getu32(swap, array[1]) : ((uint64_t)getu32(swap, array[1]) << 32))) |
|
#else |
|
# define elf_getu64(swap, value) getu64(swap, value) |
|
#endif |
|
|
|
#define xsh_addr (class == ELFCLASS32 \ |
? (void *) &sh32 \ |
? (void *) &sh32 \ |
: (void *) &sh64) |
: (void *) &sh64) |
#define sh_size (class == ELFCLASS32 \ |
#define xsh_sizeof (class == ELFCLASS32 \ |
? sizeof sh32 \ |
? sizeof sh32 \ |
: sizeof sh64) |
: sizeof sh64) |
#define shs_type (class == ELFCLASS32 \ |
#define xsh_size (class == ELFCLASS32 \ |
|
? getu32(swap, sh32.sh_size) \ |
|
: getu64(swap, sh64.sh_size)) |
|
#define xsh_offset (class == ELFCLASS32 \ |
|
? getu32(swap, sh32.sh_offset) \ |
|
: getu64(swap, sh64.sh_offset)) |
|
#define xsh_type (class == ELFCLASS32 \ |
? getu32(swap, sh32.sh_type) \ |
? getu32(swap, sh32.sh_type) \ |
: getu32(swap, sh64.sh_type)) |
: getu32(swap, sh64.sh_type)) |
#define ph_addr (class == ELFCLASS32 \ |
#define xph_addr (class == ELFCLASS32 \ |
? (void *) &ph32 \ |
? (void *) &ph32 \ |
: (void *) &ph64) |
: (void *) &ph64) |
#define ph_size (class == ELFCLASS32 \ |
#define xph_sizeof (class == ELFCLASS32 \ |
? sizeof ph32 \ |
? sizeof ph32 \ |
: sizeof ph64) |
: sizeof ph64) |
#define ph_type (class == ELFCLASS32 \ |
#define xph_type (class == ELFCLASS32 \ |
? getu32(swap, ph32.p_type) \ |
? getu32(swap, ph32.p_type) \ |
: getu32(swap, ph64.p_type)) |
: getu32(swap, ph64.p_type)) |
#define ph_offset (class == ELFCLASS32 \ |
#define xph_offset (off_t)(class == ELFCLASS32 \ |
? getu32(swap, ph32.p_offset) \ |
? getu32(swap, ph32.p_offset) \ |
: getu64(swap, ph64.p_offset)) |
: getu64(swap, ph64.p_offset)) |
#define ph_align (size_t)((class == ELFCLASS32 \ |
#define xph_align (size_t)((class == ELFCLASS32 \ |
? (off_t) (ph32.p_align ? \ |
? (off_t) (ph32.p_align ? \ |
getu32(swap, ph32.p_align) : 4) \ |
getu32(swap, ph32.p_align) : 4) \ |
: (off_t) (ph64.p_align ? \ |
: (off_t) (ph64.p_align ? \ |
getu64(swap, ph64.p_align) : 4))) |
getu64(swap, ph64.p_align) : 4))) |
#define nh_size (class == ELFCLASS32 \ |
#define xph_filesz (size_t)((class == ELFCLASS32 \ |
|
? getu32(swap, ph32.p_filesz) \ |
|
: getu64(swap, ph64.p_filesz))) |
|
#define xnh_addr (class == ELFCLASS32 \ |
|
? (void *) &nh32 \ |
|
: (void *) &nh64) |
|
#define xph_memsz (size_t)((class == ELFCLASS32 \ |
|
? getu32(swap, ph32.p_memsz) \ |
|
: getu64(swap, ph64.p_memsz))) |
|
#define xnh_sizeof (class == ELFCLASS32 \ |
? sizeof nh32 \ |
? sizeof nh32 \ |
: sizeof nh64) |
: sizeof nh64) |
#define nh_type (class == ELFCLASS32 \ |
#define xnh_type (class == ELFCLASS32 \ |
? getu32(swap, nh32.n_type) \ |
? getu32(swap, nh32.n_type) \ |
: getu32(swap, nh64.n_type)) |
: getu32(swap, nh64.n_type)) |
#define nh_namesz (class == ELFCLASS32 \ |
#define xnh_namesz (class == ELFCLASS32 \ |
? getu32(swap, nh32.n_namesz) \ |
? getu32(swap, nh32.n_namesz) \ |
: getu32(swap, nh64.n_namesz)) |
: getu32(swap, nh64.n_namesz)) |
#define nh_descsz (class == ELFCLASS32 \ |
#define xnh_descsz (class == ELFCLASS32 \ |
? getu32(swap, nh32.n_descsz) \ |
? getu32(swap, nh32.n_descsz) \ |
: getu32(swap, nh64.n_descsz)) |
: getu32(swap, nh64.n_descsz)) |
#define prpsoffsets(i) (class == ELFCLASS32 \ |
#define prpsoffsets(i) (class == ELFCLASS32 \ |
|
|
#ifdef ELFCORE |
#ifdef ELFCORE |
size_t prpsoffsets32[] = { |
size_t prpsoffsets32[] = { |
8, /* FreeBSD */ |
8, /* FreeBSD */ |
28, /* Linux 2.0.36 */ |
28, /* Linux 2.0.36 (short name) */ |
32, /* Linux (I forget which kernel version) */ |
44, /* Linux (path name) */ |
84, /* SunOS 5.x */ |
84, /* SunOS 5.x */ |
}; |
}; |
|
|
size_t prpsoffsets64[] = { |
size_t prpsoffsets64[] = { |
120, /* SunOS 5.x, 64-bit */ |
16, /* FreeBSD, 64-bit */ |
|
40, /* Linux (tested on core from 2.4.x, short name) */ |
|
56, /* Linux (path name) */ |
|
120, /* SunOS 5.x, 64-bit */ |
}; |
}; |
|
|
#define NOFFSETS32 (sizeof prpsoffsets32 / sizeof prpsoffsets32[0]) |
#define NOFFSETS32 (sizeof prpsoffsets32 / sizeof prpsoffsets32[0]) |
|
|
"NetBSD", |
"NetBSD", |
}; |
}; |
|
|
|
#define FLAGS_DID_CORE 1 |
|
#define FLAGS_DID_NOTE 2 |
|
|
private int |
private int |
dophn_core(struct magic_set *ms, int class, int swap, int fd, off_t off, |
dophn_core(struct magic_set *ms, int class, int swap, int fd, off_t off, |
int num, size_t size) |
int num, size_t size, off_t fsize, int *flags) |
{ |
{ |
Elf32_Phdr ph32; |
Elf32_Phdr ph32; |
Elf64_Phdr ph64; |
Elf64_Phdr ph64; |
size_t offset; |
size_t offset; |
unsigned char nbuf[BUFSIZ]; |
unsigned char nbuf[BUFSIZ]; |
ssize_t bufsize; |
ssize_t bufsize; |
|
off_t savedoffset; |
|
struct stat st; |
|
|
if (size != ph_size) { |
if (fstat(fd, &st) < 0) { |
|
file_badread(ms); |
|
return -1; |
|
} |
|
|
|
if (size != xph_sizeof) { |
if (file_printf(ms, ", corrupted program header size") == -1) |
if (file_printf(ms, ", corrupted program header size") == -1) |
return -1; |
return -1; |
return 0; |
return 0; |
} |
} |
|
|
/* |
/* |
* Loop through all the program headers. |
* Loop through all the program headers. |
*/ |
*/ |
for ( ; num; num--) { |
for ( ; num; num--) { |
if (lseek(fd, off, SEEK_SET) == (off_t)-1) { |
if ((savedoffset = lseek(fd, off, SEEK_SET)) == (off_t)-1) { |
file_badseek(ms); |
file_badseek(ms); |
return -1; |
return -1; |
} |
} |
if (read(fd, ph_addr, ph_size) == -1) { |
if (read(fd, xph_addr, xph_sizeof) == -1) { |
file_badread(ms); |
file_badread(ms); |
return -1; |
return -1; |
} |
} |
|
if (xph_offset > fsize) { |
|
if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) { |
|
file_badseek(ms); |
|
return -1; |
|
} |
|
continue; |
|
} |
|
|
off += size; |
off += size; |
if (ph_type != PT_NOTE) |
if (xph_type != PT_NOTE) |
continue; |
continue; |
|
|
/* |
/* |
* This is a PT_NOTE section; loop through all the notes |
* This is a PT_NOTE section; loop through all the notes |
* in the section. |
* in the section. |
*/ |
*/ |
if (lseek(fd, (off_t) ph_offset, SEEK_SET) == (off_t)-1) { |
if (lseek(fd, xph_offset, SEEK_SET) == (off_t)-1) { |
file_badseek(ms); |
file_badseek(ms); |
return -1; |
return -1; |
} |
} |
bufsize = read(fd, nbuf, BUFSIZ); |
bufsize = read(fd, nbuf, |
|
((xph_filesz < sizeof(nbuf)) ? xph_filesz : sizeof(nbuf))); |
if (bufsize == -1) { |
if (bufsize == -1) { |
file_badread(ms); |
file_badread(ms); |
return -1; |
return -1; |
|
|
if (offset >= (size_t)bufsize) |
if (offset >= (size_t)bufsize) |
break; |
break; |
offset = donote(ms, nbuf, offset, (size_t)bufsize, |
offset = donote(ms, nbuf, offset, (size_t)bufsize, |
class, swap, 4); |
class, swap, 4, flags); |
if (offset == 0) |
if (offset == 0) |
break; |
break; |
|
|
|
|
|
|
private size_t |
private size_t |
donote(struct magic_set *ms, unsigned char *nbuf, size_t offset, size_t size, |
donote(struct magic_set *ms, unsigned char *nbuf, size_t offset, size_t size, |
int class, int swap, size_t align) |
int class, int swap, size_t align, int *flags) |
{ |
{ |
Elf32_Nhdr nh32; |
Elf32_Nhdr nh32; |
Elf64_Nhdr nh64; |
Elf64_Nhdr nh64; |
|
|
#endif |
#endif |
uint32_t namesz, descsz; |
uint32_t namesz, descsz; |
|
|
if (class == ELFCLASS32) |
(void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof); |
memcpy(&nh32, &nbuf[offset], sizeof(nh32)); |
offset += xnh_sizeof; |
else |
|
memcpy(&nh64, &nbuf[offset], sizeof(nh64)); |
|
offset += nh_size; |
|
|
|
namesz = nh_namesz; |
namesz = xnh_namesz; |
descsz = nh_descsz; |
descsz = xnh_descsz; |
if ((namesz == 0) && (descsz == 0)) { |
if ((namesz == 0) && (descsz == 0)) { |
/* |
/* |
* We're out of note headers. |
* We're out of note headers. |
*/ |
*/ |
return offset; |
return (offset >= size) ? offset : size; |
} |
} |
|
|
if (namesz & 0x80000000) { |
if (namesz & 0x80000000) { |
|
|
noff = offset; |
noff = offset; |
doff = ELF_ALIGN(offset + namesz); |
doff = ELF_ALIGN(offset + namesz); |
|
|
if (offset + namesz >= size) { |
if (offset + namesz > size) { |
/* |
/* |
* We're past the end of the buffer. |
* We're past the end of the buffer. |
*/ |
*/ |
|
|
} |
} |
|
|
offset = ELF_ALIGN(doff + descsz); |
offset = ELF_ALIGN(doff + descsz); |
if (offset + descsz >= size) { |
if (doff + descsz > size) { |
return offset; |
/* |
|
* We're past the end of the buffer. |
|
*/ |
|
return (offset >= size) ? offset : size; |
} |
} |
|
|
|
if (*flags & FLAGS_DID_NOTE) |
|
goto core; |
|
|
if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && |
if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && |
nh_type == NT_GNU_VERSION && descsz == 16) { |
xnh_type == NT_GNU_VERSION && descsz == 16) { |
uint32_t desc[4]; |
uint32_t desc[4]; |
(void)memcpy(desc, &nbuf[doff], sizeof(desc)); |
(void)memcpy(desc, &nbuf[doff], sizeof(desc)); |
|
|
|
|
if (file_printf(ms, " %d.%d.%d", getu32(swap, desc[1]), |
if (file_printf(ms, " %d.%d.%d", getu32(swap, desc[1]), |
getu32(swap, desc[2]), getu32(swap, desc[3])) == -1) |
getu32(swap, desc[2]), getu32(swap, desc[3])) == -1) |
return size; |
return size; |
|
*flags |= FLAGS_DID_NOTE; |
return size; |
return size; |
} |
} |
|
|
if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0 && |
if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0 && |
nh_type == NT_NETBSD_VERSION && descsz == 4) { |
xnh_type == NT_NETBSD_VERSION && descsz == 4) { |
uint32_t desc; |
uint32_t desc; |
(void)memcpy(&desc, &nbuf[doff], sizeof(desc)); |
(void)memcpy(&desc, &nbuf[doff], sizeof(desc)); |
desc = getu32(swap, desc); |
desc = getu32(swap, desc); |
|
|
* p = patchlevel |
* p = patchlevel |
*/ |
*/ |
if (desc > 100000000U) { |
if (desc > 100000000U) { |
u_int ver_patch = (desc / 100) % 100; |
uint32_t ver_patch = (desc / 100) % 100; |
u_int ver_rel = (desc / 10000) % 100; |
uint32_t ver_rel = (desc / 10000) % 100; |
u_int ver_min = (desc / 1000000) % 100; |
uint32_t ver_min = (desc / 1000000) % 100; |
u_int ver_maj = desc / 100000000; |
uint32_t ver_maj = desc / 100000000; |
|
|
if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1) |
if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1) |
return size; |
return size; |
|
|
return size; |
return size; |
} else if (ver_rel != 0) { |
} else if (ver_rel != 0) { |
while (ver_rel > 26) { |
while (ver_rel > 26) { |
file_printf(ms, "Z"); |
if (file_printf(ms, "Z") == -1) |
|
return size; |
ver_rel -= 26; |
ver_rel -= 26; |
} |
} |
file_printf(ms, "%c", 'A' + ver_rel - 1); |
if (file_printf(ms, "%c", 'A' + ver_rel - 1) |
|
== -1) |
|
return size; |
} |
} |
} |
} |
|
*flags |= FLAGS_DID_NOTE; |
return size; |
return size; |
} |
} |
|
|
if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0 && |
if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0 && |
nh_type == NT_FREEBSD_VERSION && descsz == 4) { |
xnh_type == NT_FREEBSD_VERSION && descsz == 4) { |
uint32_t desc; |
uint32_t desc; |
(void)memcpy(&desc, &nbuf[doff], sizeof(desc)); |
(void)memcpy(&desc, &nbuf[doff], sizeof(desc)); |
desc = getu32(swap, desc); |
desc = getu32(swap, desc); |
|
|
|
|
/* |
/* |
* Contents is __FreeBSD_version, whose relation to OS |
* Contents is __FreeBSD_version, whose relation to OS |
* versions is defined by a huge table in the Porters' |
* versions is defined by a huge table in the Porter's |
* Handbook. For up to 5.x, the first three digits are |
* Handbook. This is the general scheme: |
* the version number. For 5.x and higher, the scheme |
* |
* is: <major><two digit minor> <0 if release branch, |
* Releases: |
* otherwise 1>xx |
* Mmp000 (before 4.10) |
|
* Mmi0p0 (before 5.0) |
|
* Mmm0p0 |
|
* |
|
* Development branches: |
|
* Mmpxxx (before 4.6) |
|
* Mmp1xx (before 4.10) |
|
* Mmi1xx (before 5.0) |
|
* M000xx (pre-M.0) |
|
* Mmm1xx |
|
* |
|
* M = major version |
|
* m = minor version |
|
* i = minor version increment (491000 -> 4.10) |
|
* p = patchlevel |
|
* x = revision |
|
* |
|
* The first release of FreeBSD to use ELF by default |
|
* was version 3.0. |
*/ |
*/ |
if (desc / 100000 < 5) { |
if (desc == 460002) { |
|
if (file_printf(ms, " 4.6.2") == -1) |
|
return size; |
|
} else if (desc < 460100) { |
if (file_printf(ms, " %d.%d", desc / 100000, |
if (file_printf(ms, " %d.%d", desc / 100000, |
desc / 10000 % 10) == -1) |
desc / 10000 % 10) == -1) |
return size; |
return size; |
|
|
if (file_printf(ms, ".%d", desc / 1000 % 10) |
if (file_printf(ms, ".%d", desc / 1000 % 10) |
== -1) |
== -1) |
return size; |
return size; |
|
if ((desc % 1000 > 0) || (desc % 100000 == 0)) |
|
if (file_printf(ms, " (%d)", desc) == -1) |
|
return size; |
|
} else if (desc < 500000) { |
|
if (file_printf(ms, " %d.%d", desc / 100000, |
|
desc / 10000 % 10 + desc / 1000 % 10) == -1) |
|
return size; |
|
if (desc / 100 % 10 > 0) { |
|
if (file_printf(ms, " (%d)", desc) == -1) |
|
return size; |
|
} else if (desc / 10 % 10 > 0) { |
|
if (file_printf(ms, ".%d", desc / 10 % 10) |
|
== -1) |
|
return size; |
|
} |
} else { |
} else { |
if (file_printf(ms, " %d.%d", desc / 100000, |
if (file_printf(ms, " %d.%d", desc / 100000, |
desc / 1000 % 100) == -1) |
desc / 1000 % 100) == -1) |
return size; |
return size; |
desc %= 1000; |
if ((desc / 100 % 10 > 0) || |
if (desc > 100) { |
(desc % 100000 / 100 == 0)) { |
if (file_printf(ms, "-CURRENT (rev %d)", |
if (file_printf(ms, " (%d)", desc) == -1) |
desc % 100) == -1) |
|
return size; |
return size; |
} else if (desc != 0) { |
} else if (desc / 10 % 10 > 0) { |
if (file_printf(ms, ".%d", desc / 10) == -1) |
if (file_printf(ms, ".%d", desc / 10 % 10) |
|
== -1) |
return size; |
return size; |
} |
} |
} |
} |
|
*flags |= FLAGS_DID_NOTE; |
return size; |
return size; |
} |
} |
|
|
if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 && |
if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 && |
nh_type == NT_OPENBSD_VERSION && descsz == 4) { |
xnh_type == NT_OPENBSD_VERSION && descsz == 4) { |
if (file_printf(ms, ", for OpenBSD") == -1) |
if (file_printf(ms, ", for OpenBSD") == -1) |
return size; |
return size; |
/* Content of note is always 0 */ |
/* Content of note is always 0 */ |
|
*flags |= FLAGS_DID_NOTE; |
return size; |
return size; |
} |
} |
|
|
|
if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 && |
|
xnh_type == NT_DRAGONFLY_VERSION && descsz == 4) { |
|
uint32_t desc; |
|
if (file_printf(ms, ", for DragonFly") == -1) |
|
return size; |
|
(void)memcpy(&desc, &nbuf[doff], sizeof(desc)); |
|
desc = getu32(swap, desc); |
|
if (file_printf(ms, " %d.%d.%d", desc / 100000, |
|
desc / 10000 % 10, desc % 10000) == -1) |
|
return size; |
|
*flags |= FLAGS_DID_NOTE; |
|
return size; |
|
} |
|
|
|
core: |
/* |
/* |
* Sigh. The 2.0.36 kernel in Debian 2.1, at |
* Sigh. The 2.0.36 kernel in Debian 2.1, at |
* least, doesn't correctly implement name |
* least, doesn't correctly implement name |
|
|
} |
} |
|
|
#ifdef ELFCORE |
#ifdef ELFCORE |
if (os_style != -1) |
if ((*flags & FLAGS_DID_CORE) != 0) |
if (file_printf(ms, ", %s-style", os_style_names[os_style]) == -1) |
return size; |
|
|
|
if (os_style != -1) { |
|
if (file_printf(ms, ", %s-style", os_style_names[os_style]) |
|
== -1) |
return size; |
return size; |
|
} |
|
|
if (os_style == OS_STYLE_NETBSD && nh_type == NT_NETBSD_CORE_PROCINFO) { |
switch (os_style) { |
uint32_t signo; |
case OS_STYLE_NETBSD: |
/* |
if (xnh_type == NT_NETBSD_CORE_PROCINFO) { |
* Extract the program name. It is at |
uint32_t signo; |
* offset 0x7c, and is up to 32-bytes, |
/* |
* including the terminating NUL. |
* Extract the program name. It is at |
*/ |
* offset 0x7c, and is up to 32-bytes, |
if (file_printf(ms, ", from '%.31s'", &nbuf[doff + 0x7c]) == -1) |
* including the terminating NUL. |
|
*/ |
|
if (file_printf(ms, ", from '%.31s'", |
|
&nbuf[doff + 0x7c]) == -1) |
|
return size; |
|
|
|
/* |
|
* Extract the signal number. It is at |
|
* offset 0x08. |
|
*/ |
|
(void)memcpy(&signo, &nbuf[doff + 0x08], |
|
sizeof(signo)); |
|
if (file_printf(ms, " (signal %u)", |
|
getu32(swap, signo)) == -1) |
|
return size; |
return size; |
return size; |
|
} |
/* |
break; |
* Extract the signal number. It is at |
|
* offset 0x08. |
|
*/ |
|
memcpy(&signo, &nbuf[doff + 0x08], |
|
sizeof(signo)); |
|
if (file_printf(ms, " (signal %u)", getu32(swap, signo)) == -1) |
|
return size; |
|
return size; |
|
} else if (os_style != OS_STYLE_NETBSD && nh_type == NT_PRPSINFO) { |
|
size_t i, j; |
|
unsigned char c; |
|
/* |
|
* 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++) { |
|
size_t reloffset = prpsoffsets(i); |
|
size_t noffset = doff + 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 >= size) |
|
goto tryanother; |
|
|
|
/* |
default: |
* Make sure we're not past |
if (xnh_type == NT_PRPSINFO) { |
* the end of the contents; |
size_t i, j; |
* if we are, this obviously |
unsigned char c; |
* isn't the right offset. |
/* |
*/ |
* Extract the program name. We assume |
if (reloffset >= descsz) |
* it to be 16 characters (that's what it |
goto tryanother; |
* is in SunOS 5.x and Linux). |
|
* |
c = nbuf[noffset]; |
* Unfortunately, it's at a different offset |
if (c == '\0') { |
* in various OSes, so try multiple offsets. |
|
* If the characters aren't all printable, |
|
* reject it. |
|
*/ |
|
for (i = 0; i < NOFFSETS; i++) { |
|
size_t reloffset = prpsoffsets(i); |
|
size_t noffset = doff + reloffset; |
|
for (j = 0; j < 16; j++, noffset++, |
|
reloffset++) { |
/* |
/* |
* A '\0' at the |
* Make sure we're not past |
* beginning is |
* the end of the buffer; if |
* obviously wrong. |
* we are, just give up. |
* Any other '\0' |
|
* means we're done. |
|
*/ |
*/ |
if (j == 0) |
if (noffset >= size) |
goto tryanother; |
goto tryanother; |
else |
|
break; |
|
} else { |
|
/* |
/* |
* A nonprintable |
* Make sure we're not past |
* character is also |
* the end of the contents; |
* wrong. |
* if we are, this obviously |
|
* isn't the right offset. |
*/ |
*/ |
#define isquote(c) (strchr("'\"`", (c)) != NULL) |
if (reloffset >= descsz) |
if (!isprint(c) || isquote(c)) |
|
goto tryanother; |
goto tryanother; |
} |
|
} |
|
|
|
/* |
c = nbuf[noffset]; |
* Well, that worked. |
if (c == '\0') { |
*/ |
/* |
if (file_printf(ms, ", from '%.16s'", |
* A '\0' at the |
&nbuf[doff + prpsoffsets(i)]) == -1) |
* 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. |
|
*/ |
|
if (!isprint(c) || isquote(c)) |
|
goto tryanother; |
|
} |
|
} |
|
/* |
|
* Well, that worked. |
|
*/ |
|
if (file_printf(ms, ", from '%.16s'", |
|
&nbuf[doff + prpsoffsets(i)]) == -1) |
|
return size; |
return size; |
return size; |
return size; |
|
|
|
tryanother: |
tryanother: |
; |
; |
|
} |
} |
} |
return offset; |
break; |
} |
} |
#endif |
#endif |
|
*flags |= FLAGS_DID_CORE; |
return offset; |
return offset; |
} |
} |
|
|
private int |
private int |
doshn(struct magic_set *ms, int class, int swap, int fd, off_t off, int num, |
doshn(struct magic_set *ms, int class, int swap, int fd, off_t off, int num, |
size_t size) |
size_t size, int *flags) |
{ |
{ |
Elf32_Shdr sh32; |
Elf32_Shdr sh32; |
Elf64_Shdr sh64; |
Elf64_Shdr sh64; |
|
int stripped = 1; |
|
void *nbuf; |
|
off_t noff; |
|
|
if (size != sh_size) { |
if (size != xsh_sizeof) { |
if (file_printf(ms, ", corrupted section header size") == -1) |
if (file_printf(ms, ", corrupted section header size") == -1) |
return -1; |
return -1; |
return 0; |
return 0; |
|
|
} |
} |
|
|
for ( ; num; num--) { |
for ( ; num; num--) { |
if (read(fd, sh_addr, sh_size) == -1) { |
if (read(fd, xsh_addr, xsh_sizeof) == -1) { |
file_badread(ms); |
file_badread(ms); |
return -1; |
return -1; |
} |
} |
if (shs_type == SHT_SYMTAB /* || shs_type == SHT_DYNSYM */) { |
switch (xsh_type) { |
if (file_printf(ms, ", not stripped") == -1) |
case SHT_SYMTAB: |
|
#if 0 |
|
case SHT_DYNSYM: |
|
#endif |
|
stripped = 0; |
|
break; |
|
case SHT_NOTE: |
|
if ((off = lseek(fd, (off_t)0, SEEK_CUR)) == |
|
(off_t)-1) { |
|
file_badread(ms); |
return -1; |
return -1; |
return 0; |
} |
|
if ((nbuf = malloc((size_t)xsh_size)) == NULL) { |
|
file_error(ms, errno, "Cannot allocate memory" |
|
" for note"); |
|
return -1; |
|
} |
|
if ((noff = lseek(fd, (off_t)xsh_offset, SEEK_SET)) == |
|
(off_t)-1) { |
|
file_badread(ms); |
|
free(nbuf); |
|
return -1; |
|
} |
|
if (read(fd, nbuf, (size_t)xsh_size) != |
|
(ssize_t)xsh_size) { |
|
free(nbuf); |
|
file_badread(ms); |
|
return -1; |
|
} |
|
|
|
noff = 0; |
|
for (;;) { |
|
if (noff >= (size_t)xsh_size) |
|
break; |
|
noff = donote(ms, nbuf, (size_t)noff, |
|
(size_t)xsh_size, class, swap, 4, |
|
flags); |
|
if (noff == 0) |
|
break; |
|
} |
|
if ((lseek(fd, off, SEEK_SET)) == (off_t)-1) { |
|
free(nbuf); |
|
file_badread(ms); |
|
return -1; |
|
} |
|
free(nbuf); |
|
break; |
} |
} |
} |
} |
if (file_printf(ms, ", stripped") == -1) |
if (file_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1) |
return -1; |
return -1; |
return 0; |
return 0; |
} |
} |
|
|
*/ |
*/ |
private int |
private int |
dophn_exec(struct magic_set *ms, int class, int swap, int fd, off_t off, |
dophn_exec(struct magic_set *ms, int class, int swap, int fd, off_t off, |
int num, size_t size) |
int num, size_t size, off_t fsize, int *flags) |
{ |
{ |
Elf32_Phdr ph32; |
Elf32_Phdr ph32; |
Elf64_Phdr ph64; |
Elf64_Phdr ph64; |
|
|
unsigned char nbuf[BUFSIZ]; |
unsigned char nbuf[BUFSIZ]; |
int bufsize; |
int bufsize; |
size_t offset, align; |
size_t offset, align; |
off_t savedoffset; |
off_t savedoffset = (off_t)-1; |
|
struct stat st; |
|
|
if (size != ph_size) { |
if (fstat(fd, &st) < 0) { |
|
file_badread(ms); |
|
return -1; |
|
} |
|
|
|
if (size != xph_sizeof) { |
if (file_printf(ms, ", corrupted program header size") == -1) |
if (file_printf(ms, ", corrupted program header size") == -1) |
return -1; |
return -1; |
return 0; |
return 0; |
} |
} |
|
|
if (lseek(fd, off, SEEK_SET) == (off_t)-1) { |
if (lseek(fd, off, SEEK_SET) == (off_t)-1) { |
file_badseek(ms); |
file_badseek(ms); |
return -1; |
return -1; |
} |
} |
|
|
for ( ; num; num--) { |
for ( ; num; num--) { |
if (read(fd, ph_addr, ph_size) == -1) { |
if (read(fd, xph_addr, xph_sizeof) == -1) { |
file_badread(ms); |
file_badread(ms); |
return -1; |
return -1; |
} |
} |
|
if (xph_offset > st.st_size && savedoffset != (off_t)-1) { |
|
if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) { |
|
file_badseek(ms); |
|
return -1; |
|
} |
|
continue; |
|
} |
|
|
if ((savedoffset = lseek(fd, (off_t)0, SEEK_CUR)) == (off_t)-1) { |
if ((savedoffset = lseek(fd, (off_t)0, SEEK_CUR)) == (off_t)-1) { |
file_badseek(ms); |
file_badseek(ms); |
return -1; |
return -1; |
} |
} |
|
|
switch (ph_type) { |
if (xph_offset > fsize) { |
|
if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) { |
|
file_badseek(ms); |
|
return -1; |
|
} |
|
continue; |
|
} |
|
|
|
switch (xph_type) { |
case PT_DYNAMIC: |
case PT_DYNAMIC: |
linking_style = "dynamically"; |
linking_style = "dynamically"; |
break; |
break; |
|
|
shared_libraries = " (uses shared libs)"; |
shared_libraries = " (uses shared libs)"; |
break; |
break; |
case PT_NOTE: |
case PT_NOTE: |
if ((align = ph_align) & 0x80000000) { |
if ((align = xph_align) & 0x80000000) { |
if (file_printf(ms, |
if (file_printf(ms, |
", invalid note alignment 0x%lx", |
", invalid note alignment 0x%lx", |
(unsigned long)align) == -1) |
(unsigned long)align) == -1) |
|
|
* This is a PT_NOTE section; loop through all the notes |
* This is a PT_NOTE section; loop through all the notes |
* in the section. |
* in the section. |
*/ |
*/ |
if (lseek(fd, (off_t) ph_offset, SEEK_SET) |
if (lseek(fd, xph_offset, SEEK_SET) |
== (off_t)-1) { |
== (off_t)-1) { |
file_badseek(ms); |
file_badseek(ms); |
return -1; |
return -1; |
} |
} |
bufsize = read(fd, nbuf, sizeof(nbuf)); |
bufsize = read(fd, nbuf, ((xph_filesz < sizeof(nbuf)) ? |
|
xph_filesz : sizeof(nbuf))); |
if (bufsize == -1) { |
if (bufsize == -1) { |
file_badread(ms); |
file_badread(ms); |
return -1; |
return -1; |
|
|
if (offset >= (size_t)bufsize) |
if (offset >= (size_t)bufsize) |
break; |
break; |
offset = donote(ms, nbuf, offset, |
offset = donote(ms, nbuf, offset, |
(size_t)bufsize, class, swap, align); |
(size_t)bufsize, class, swap, align, |
|
flags); |
if (offset == 0) |
if (offset == 0) |
break; |
break; |
} |
} |
if (lseek(fd, savedoffset + offset, SEEK_SET) |
if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) { |
== (off_t)-1) { |
|
file_badseek(ms); |
file_badseek(ms); |
return -1; |
return -1; |
} |
} |
|
|
} u; |
} u; |
int class; |
int class; |
int swap; |
int swap; |
|
struct stat st; |
|
off_t fsize; |
|
int flags = 0; |
|
|
/* |
/* |
* If we cannot seek, it must be a pipe, socket or fifo. |
* If we cannot seek, it must be a pipe, socket or fifo. |
|
|
if((lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE)) |
if((lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE)) |
fd = file_pipe2file(ms, fd, buf, nbytes); |
fd = file_pipe2file(ms, fd, buf, nbytes); |
|
|
|
if (fstat(fd, &st) == -1) { |
|
file_badread(ms); |
|
return -1; |
|
} |
|
fsize = st.st_size; |
|
|
/* |
/* |
* ELF executables have multiple section headers in arbitrary |
* ELF executables have multiple section headers in arbitrary |
* file locations and thus file(1) cannot determine it from easily. |
* file locations and thus file(1) cannot determine it from easily. |
|
|
return 0; |
return 0; |
|
|
|
|
class = buf[4]; |
class = buf[EI_CLASS]; |
|
|
if (class == ELFCLASS32) { |
if (class == ELFCLASS32) { |
Elf32_Ehdr elfhdr; |
Elf32_Ehdr elfhdr; |
|
|
|
|
u.l = 1; |
u.l = 1; |
(void) memcpy(&elfhdr, buf, sizeof elfhdr); |
(void) memcpy(&elfhdr, buf, sizeof elfhdr); |
swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[5]; |
swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[EI_DATA]; |
|
|
if (getu16(swap, elfhdr.e_type) == ET_CORE) { |
if (getu16(swap, elfhdr.e_type) == ET_CORE) { |
#ifdef ELFCORE |
#ifdef ELFCORE |
if (dophn_core(ms, class, swap, fd, |
if (dophn_core(ms, class, swap, fd, |
(off_t)getu32(swap, elfhdr.e_phoff), |
(off_t)getu32(swap, elfhdr.e_phoff), |
getu16(swap, elfhdr.e_phnum), |
getu16(swap, elfhdr.e_phnum), |
(size_t)getu16(swap, elfhdr.e_phentsize)) == -1) |
(size_t)getu16(swap, elfhdr.e_phentsize), |
|
fsize, &flags) == -1) |
return -1; |
return -1; |
#else |
#else |
; |
; |
|
|
if (dophn_exec(ms, class, swap, |
if (dophn_exec(ms, class, swap, |
fd, (off_t)getu32(swap, elfhdr.e_phoff), |
fd, (off_t)getu32(swap, elfhdr.e_phoff), |
getu16(swap, elfhdr.e_phnum), |
getu16(swap, elfhdr.e_phnum), |
(size_t)getu16(swap, elfhdr.e_phentsize)) |
(size_t)getu16(swap, elfhdr.e_phentsize), |
|
fsize, &flags) |
== -1) |
== -1) |
return -1; |
return -1; |
} |
} |
if (doshn(ms, class, swap, fd, |
if (doshn(ms, class, swap, fd, |
(off_t)getu32(swap, elfhdr.e_shoff), |
(off_t)getu32(swap, elfhdr.e_shoff), |
getu16(swap, elfhdr.e_shnum), |
getu16(swap, elfhdr.e_shnum), |
(size_t)getu16(swap, elfhdr.e_shentsize)) == -1) |
(size_t)getu16(swap, elfhdr.e_shentsize), |
|
&flags) == -1) |
return -1; |
return -1; |
} |
} |
return 1; |
return 1; |
|
|
|
|
u.l = 1; |
u.l = 1; |
(void) memcpy(&elfhdr, buf, sizeof elfhdr); |
(void) memcpy(&elfhdr, buf, sizeof elfhdr); |
swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[5]; |
swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[EI_DATA]; |
|
|
if (getu16(swap, elfhdr.e_type) == ET_CORE) { |
if (getu16(swap, elfhdr.e_type) == ET_CORE) { |
#ifdef ELFCORE |
#ifdef ELFCORE |
if (dophn_core(ms, class, swap, fd, |
if (dophn_core(ms, class, swap, fd, |
#ifdef USE_ARRAY_FOR_64BIT_TYPES |
(off_t)elf_getu64(swap, elfhdr.e_phoff), |
(off_t)getu32(swap, elfhdr.e_phoff[1]), |
|
#else |
|
(off_t)getu64(swap, elfhdr.e_phoff), |
|
#endif |
|
getu16(swap, elfhdr.e_phnum), |
getu16(swap, elfhdr.e_phnum), |
(size_t)getu16(swap, elfhdr.e_phentsize)) == -1) |
(size_t)getu16(swap, elfhdr.e_phentsize), |
|
fsize, &flags) == -1) |
return -1; |
return -1; |
#else |
#else |
; |
; |
|
|
} else { |
} else { |
if (getu16(swap, elfhdr.e_type) == ET_EXEC) { |
if (getu16(swap, elfhdr.e_type) == ET_EXEC) { |
if (dophn_exec(ms, class, swap, fd, |
if (dophn_exec(ms, class, swap, fd, |
#ifdef USE_ARRAY_FOR_64BIT_TYPES |
(off_t)elf_getu64(swap, elfhdr.e_phoff), |
(off_t)getu32(swap, elfhdr.e_phoff[1]), |
|
#else |
|
(off_t)getu64(swap, elfhdr.e_phoff), |
|
#endif |
|
getu16(swap, elfhdr.e_phnum), |
getu16(swap, elfhdr.e_phnum), |
(size_t)getu16(swap, elfhdr.e_phentsize)) |
(size_t)getu16(swap, elfhdr.e_phentsize), |
== -1) |
fsize, &flags) == -1) |
return -1; |
return -1; |
} |
} |
if (doshn(ms, class, swap, fd, |
if (doshn(ms, class, swap, fd, |
#ifdef USE_ARRAY_FOR_64BIT_TYPES |
(off_t)elf_getu64(swap, elfhdr.e_shoff), |
(off_t)getu32(swap, elfhdr.e_shoff[1]), |
|
#else |
|
(off_t)getu64(swap, elfhdr.e_shoff), |
|
#endif |
|
getu16(swap, elfhdr.e_shnum), |
getu16(swap, elfhdr.e_shnum), |
(size_t)getu16(swap, elfhdr.e_shentsize)) == -1) |
(size_t)getu16(swap, elfhdr.e_shentsize), &flags) |
|
== -1) |
return -1; |
return -1; |
} |
} |
return 1; |
return 1; |