--- embedaddon/php/ext/fileinfo/libmagic/readelf.c 2012/02/21 23:47:56 1.1 +++ embedaddon/php/ext/fileinfo/libmagic/readelf.c 2013/07/22 01:31:50 1.1.1.3 @@ -27,7 +27,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: readelf.c,v 1.81 2008/11/04 16:38:28 christos Exp $") +FILE_RCSID("@(#)$File: readelf.c,v 1.97 2013/03/06 03:35:30 christos Exp $") #endif #ifdef BUILTIN_ELF @@ -47,8 +47,8 @@ private int dophn_core(struct magic_set *, int, int, i #endif private int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t, off_t, int *, int); -private int doshn(struct magic_set *, int, int, int, off_t, int, size_t, int *, - int); +private int doshn(struct magic_set *, int, int, int, off_t, int, size_t, + off_t, int *, int); private size_t donote(struct magic_set *, unsigned char *, size_t, size_t, int, int, size_t, int *); @@ -139,23 +139,26 @@ getu64(int swap, uint64_t value) ? (void *) &sh32 \ : (void *) &sh64) #define xsh_sizeof (clazz == ELFCLASS32 \ - ? sizeof sh32 \ - : sizeof sh64) -#define xsh_size (clazz == ELFCLASS32 \ + ? sizeof(sh32) \ + : sizeof(sh64)) +#define xsh_size (size_t)(clazz == ELFCLASS32 \ ? elf_getu32(swap, sh32.sh_size) \ : elf_getu64(swap, sh64.sh_size)) -#define xsh_offset (clazz == ELFCLASS32 \ +#define xsh_offset (off_t)(clazz == ELFCLASS32 \ ? elf_getu32(swap, sh32.sh_offset) \ : elf_getu64(swap, sh64.sh_offset)) #define xsh_type (clazz == ELFCLASS32 \ ? elf_getu32(swap, sh32.sh_type) \ : elf_getu32(swap, sh64.sh_type)) +#define xsh_name (clazz == ELFCLASS32 \ + ? elf_getu32(swap, sh32.sh_name) \ + : elf_getu32(swap, sh64.sh_name)) #define xph_addr (clazz == ELFCLASS32 \ ? (void *) &ph32 \ : (void *) &ph64) #define xph_sizeof (clazz == ELFCLASS32 \ - ? sizeof ph32 \ - : sizeof ph64) + ? sizeof(ph32) \ + : sizeof(ph64)) #define xph_type (clazz == ELFCLASS32 \ ? elf_getu32(swap, ph32.p_type) \ : elf_getu32(swap, ph64.p_type)) @@ -283,9 +286,11 @@ private const char os_style_names[][8] = { "NetBSD", }; -#define FLAGS_DID_CORE 1 -#define FLAGS_DID_NOTE 2 -#define FLAGS_DID_CORE_STYLE 4 +#define FLAGS_DID_CORE 0x01 +#define FLAGS_DID_NOTE 0x02 +#define FLAGS_DID_BUILD_ID 0x04 +#define FLAGS_DID_CORE_STYLE 0x08 +#define FLAGS_IS_CORE 0x10 private int dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off, @@ -296,14 +301,7 @@ dophn_core(struct magic_set *ms, int clazz, int swap, size_t offset; unsigned char nbuf[BUFSIZ]; ssize_t bufsize; - off_t savedoffset; - struct stat st; - if (fstat(fd, &st) < 0) { - file_badread(ms); - return -1; - } - if (size != xph_sizeof) { if (file_printf(ms, ", corrupted program header size") == -1) return -1; @@ -314,23 +312,21 @@ dophn_core(struct magic_set *ms, int clazz, int swap, * Loop through all the program headers. */ for ( ; num; num--) { - if ((savedoffset = lseek(fd, off, SEEK_SET)) == (off_t)-1) { + if (FINFO_LSEEK_FUNC(fd, off, SEEK_SET) == (off_t)-1) { file_badseek(ms); return -1; } - if (read(fd, xph_addr, xph_sizeof) == -1) { + if (FINFO_READ_FUNC(fd, xph_addr, xph_sizeof) == -1) { file_badread(ms); return -1; } + off += size; + if (xph_offset > fsize) { - if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) { - file_badseek(ms); - return -1; - } + /* Perhaps warn here */ continue; } - off += size; if (xph_type != PT_NOTE) continue; @@ -338,11 +334,11 @@ dophn_core(struct magic_set *ms, int clazz, int swap, * This is a PT_NOTE section; loop through all the notes * in the section. */ - if (lseek(fd, xph_offset, SEEK_SET) == (off_t)-1) { + if (FINFO_LSEEK_FUNC(fd, xph_offset, SEEK_SET) == (off_t)-1) { file_badseek(ms); return -1; } - bufsize = read(fd, nbuf, + bufsize = FINFO_READ_FUNC(fd, nbuf, ((xph_filesz < sizeof(nbuf)) ? xph_filesz : sizeof(nbuf))); if (bufsize == -1) { file_badread(ms); @@ -364,7 +360,7 @@ dophn_core(struct magic_set *ms, int clazz, int swap, #endif private size_t -donote(struct magic_set *ms, unsigned char *nbuf, size_t offset, size_t size, +donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, int clazz, int swap, size_t align, int *flags) { Elf32_Nhdr nh32; @@ -374,6 +370,7 @@ donote(struct magic_set *ms, unsigned char *nbuf, size int os_style = -1; #endif uint32_t namesz, descsz; + unsigned char *nbuf = CAST(unsigned char *, vbuf); (void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof); offset += xnh_sizeof; @@ -418,9 +415,14 @@ donote(struct magic_set *ms, unsigned char *nbuf, size return (offset >= size) ? offset : size; } - if (*flags & FLAGS_DID_NOTE) + if ((*flags & (FLAGS_DID_NOTE|FLAGS_DID_BUILD_ID)) == + (FLAGS_DID_NOTE|FLAGS_DID_BUILD_ID)) goto core; + if (namesz == 5 && strcmp((char *)&nbuf[noff], "SuSE") == 0 && + xnh_type == NT_GNU_VERSION && descsz == 2) { + file_printf(ms, ", for SuSE %d.%d", nbuf[doff], nbuf[doff + 1]); + } if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && xnh_type == NT_GNU_VERSION && descsz == 16) { uint32_t desc[4]; @@ -460,6 +462,20 @@ donote(struct magic_set *ms, unsigned char *nbuf, size return size; } + if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && + xnh_type == NT_GNU_BUILD_ID && (descsz == 16 || descsz == 20)) { + uint8_t desc[20]; + uint32_t i; + if (file_printf(ms, ", BuildID[%s]=", descsz == 16 ? "md5/uuid" : + "sha1") == -1) + return size; + (void)memcpy(desc, &nbuf[doff], descsz); + for (i = 0; i < descsz; i++) + if (file_printf(ms, "%02x", desc[i]) == -1) + return size; + *flags |= FLAGS_DID_BUILD_ID; + } + if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0 && xnh_type == NT_NETBSD_VERSION && descsz == 4) { uint32_t desc; @@ -675,7 +691,7 @@ core: break; default: - if (xnh_type == NT_PRPSINFO) { + if (xnh_type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) { size_t i, j; unsigned char c; /* @@ -692,6 +708,7 @@ core: unsigned char *cname, *cp; size_t reloffset = prpsoffsets(i); size_t noffset = doff + reloffset; + size_t k; for (j = 0; j < 16; j++, noffset++, reloffset++) { /* @@ -737,6 +754,24 @@ core: /* * Well, that worked. */ + + /* + * Try next offsets, in case this match is + * in the middle of a string. + */ + for (k = i + 1 ; k < NOFFSETS ; k++) { + size_t no; + int adjust = 1; + if (prpsoffsets(k) >= prpsoffsets(i)) + continue; + for (no = doff + prpsoffsets(k); + no < doff + prpsoffsets(i); no++) + adjust = adjust + && isprint(nbuf[no]); + if (adjust) + i = k; + } + cname = (unsigned char *) &nbuf[doff + prpsoffsets(i)]; for (cp = cname; *cp && isprint(*cp); cp++) @@ -815,15 +850,16 @@ static const cap_desc_t cap_desc_386[] = { private int doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, - size_t size, int *flags, int mach) + size_t size, off_t fsize, int *flags, int mach, int strtab) { Elf32_Shdr sh32; Elf64_Shdr sh64; int stripped = 1; void *nbuf; - off_t noff; + off_t noff, coff, name_off; uint64_t cap_hw1 = 0; /* SunOS 5.x hardware capabilites */ uint64_t cap_sf1 = 0; /* SunOS 5.x software capabilites */ + char name[50]; if (size != xsh_sizeof) { if (file_printf(ms, ", corrupted section header size") == -1) @@ -831,16 +867,18 @@ doshn(struct magic_set *ms, int clazz, int swap, int f return 0; } - if (lseek(fd, off, SEEK_SET) == (off_t)-1) { - file_badseek(ms); - return -1; - } - for ( ; num; num--) { - if (read(fd, xsh_addr, xsh_sizeof) == -1) { + if (FINFO_LSEEK_FUNC(fd, off, SEEK_SET) == (off_t)-1) { + file_badseek(ms); + return -1; + } + if (FINFO_READ_FUNC(fd, xsh_addr, xsh_sizeof) == -1) { file_badread(ms); return -1; } + off += size; + + /* Things we can determine before we seek */ switch (xsh_type) { case SHT_SYMTAB: #if 0 @@ -848,20 +886,25 @@ doshn(struct magic_set *ms, int clazz, int swap, int f #endif stripped = 0; break; - case SHT_NOTE: - if ((off = lseek(fd, (off_t)0, SEEK_CUR)) == - (off_t)-1) { - file_badread(ms); - return -1; + default: + if (xsh_offset > fsize) { + /* Perhaps warn here */ + continue; } + break; + } + + /* Things we can determine when we seek */ + switch (xsh_type) { + case SHT_NOTE: nbuf = emalloc((size_t)xsh_size); - if ((noff = lseek(fd, (off_t)xsh_offset, SEEK_SET)) == + if ((noff = FINFO_LSEEK_FUNC(fd, (off_t)xsh_offset, SEEK_SET)) == (off_t)-1) { file_badread(ms); efree(nbuf); return -1; } - if (read(fd, nbuf, (size_t)xsh_size) != + if (FINFO_READ_FUNC(fd, nbuf, (size_t)xsh_size) != (ssize_t)xsh_size) { efree(nbuf); file_badread(ms); @@ -878,35 +921,23 @@ doshn(struct magic_set *ms, int clazz, int swap, int f if (noff == 0) break; } - if ((lseek(fd, off, SEEK_SET)) == (off_t)-1) { - efree(nbuf); - file_badread(ms); - return -1; - } efree(nbuf); break; case SHT_SUNW_cap: - { - off_t coff; - if ((off = lseek(fd, (off_t)0, SEEK_CUR)) == + if (FINFO_LSEEK_FUNC(fd, (off_t)xsh_offset, SEEK_SET) == (off_t)-1) { - file_badread(ms); + file_badseek(ms); return -1; } - if (lseek(fd, (off_t)xsh_offset, SEEK_SET) == - (off_t)-1) { - file_badread(ms); - return -1; - } coff = 0; for (;;) { Elf32_Cap cap32; Elf64_Cap cap64; char cbuf[/*CONSTCOND*/ MAX(sizeof cap32, sizeof cap64)]; - if ((coff += xcap_sizeof) >= (off_t)xsh_size) + if ((coff += xcap_sizeof) > (off_t)xsh_size) break; - if (read(fd, cbuf, (size_t)xcap_sizeof) != + if (FINFO_READ_FUNC(fd, cbuf, (size_t)xcap_sizeof) != (ssize_t)xcap_sizeof) { file_badread(ms); return -1; @@ -924,19 +955,18 @@ doshn(struct magic_set *ms, int clazz, int swap, int f default: if (file_printf(ms, ", with unknown capability " - "0x%llx = 0x%llx", + "0x%" INT64_T_FORMAT "x = 0x%" + INT64_T_FORMAT "x", (unsigned long long)xcap_tag, (unsigned long long)xcap_val) == -1) return -1; break; } } - if (lseek(fd, off, SEEK_SET) == (off_t)-1) { - file_badread(ms); - return -1; - } break; - } + + default: + break; } } if (file_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1) @@ -972,12 +1002,13 @@ doshn(struct magic_set *ms, int clazz, int swap, int f } if (cap_hw1) if (file_printf(ms, - " unknown hardware capability 0x%llx", + " unknown hardware capability 0x%" + INT64_T_FORMAT "x", (unsigned long long)cap_hw1) == -1) return -1; } else { if (file_printf(ms, - " hardware capability 0x%llx", + " hardware capability 0x%" INT64_T_FORMAT "x", (unsigned long long)cap_hw1) == -1) return -1; } @@ -993,7 +1024,8 @@ doshn(struct magic_set *ms, int clazz, int swap, int f cap_sf1 &= ~SF1_SUNW_MASK; if (cap_sf1) if (file_printf(ms, - ", with unknown software capability 0x%llx", + ", with unknown software capability 0x%" + INT64_T_FORMAT "x", (unsigned long long)cap_sf1) == -1) return -1; } @@ -1014,15 +1046,8 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, const char *linking_style = "statically"; const char *shared_libraries = ""; unsigned char nbuf[BUFSIZ]; - int bufsize; + ssize_t bufsize; size_t offset, align; - off_t savedoffset = (off_t)-1; - struct stat st; - - if (fstat(fd, &st) < 0) { - file_badread(ms); - return -1; - } if (size != xph_sizeof) { if (file_printf(ms, ", corrupted program header size") == -1) @@ -1030,37 +1055,20 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, return 0; } - if (lseek(fd, off, SEEK_SET) == (off_t)-1) { - file_badseek(ms); - return -1; - } - for ( ; num; num--) { - if (read(fd, xph_addr, xph_sizeof) == -1) { - file_badread(ms); + if (FINFO_LSEEK_FUNC(fd, off, SEEK_SET) == (off_t)-1) { + file_badseek(ms); 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) { - file_badseek(ms); + if (FINFO_READ_FUNC(fd, xph_addr, xph_sizeof) == -1) { + file_badread(ms); return -1; } - if (xph_offset > fsize) { - if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) { - file_badseek(ms); - return -1; - } - continue; - } + off += size; + /* Things we can determine before we seek */ switch (xph_type) { case PT_DYNAMIC: linking_style = "dynamically"; @@ -1068,8 +1076,18 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, case PT_INTERP: shared_libraries = " (uses shared libs)"; break; + default: + if (xph_offset > fsize) { + /* Maybe warn here? */ + continue; + } + break; + } + + /* Things we can determine when we seek */ + switch (xph_type) { case PT_NOTE: - if ((align = xph_align) & 0x80000000) { + if ((align = xph_align) & 0x80000000UL) { if (file_printf(ms, ", invalid note alignment 0x%lx", (unsigned long)align) == -1) @@ -1082,12 +1100,11 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, * This is a PT_NOTE section; loop through all the notes * in the section. */ - if (lseek(fd, xph_offset, SEEK_SET) - == (off_t)-1) { + if (FINFO_LSEEK_FUNC(fd, xph_offset, SEEK_SET) == (off_t)-1) { file_badseek(ms); return -1; } - bufsize = read(fd, nbuf, ((xph_filesz < sizeof(nbuf)) ? + bufsize = FINFO_READ_FUNC(fd, nbuf, ((xph_filesz < sizeof(nbuf)) ? xph_filesz : sizeof(nbuf))); if (bufsize == -1) { file_badread(ms); @@ -1103,10 +1120,6 @@ dophn_exec(struct magic_set *ms, int clazz, int swap, if (offset == 0) break; } - if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) { - file_badseek(ms); - return -1; - } break; default: break; @@ -1153,7 +1166,7 @@ file_tryelf(struct magic_set *ms, int fd, const unsign /* * 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((FINFO_LSEEK_FUNC(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE)) fd = file_pipe2file(ms, fd, buf, nbytes); if (fstat(fd, &st) == -1) {