diff -ruBb glibc-2.19-orig/elf/dl-load.c glibc-2.19/elf/dl-load.c --- glibc-2.19-orig/elf/dl-load.c 2015-02-28 06:52:37.000000000 -0800 +++ glibc-2.19/elf/dl-load.c 2015-02-28 06:51:36.442857109 -0800 @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -131,6 +132,7 @@ # define FILEBUF_SIZE 832 #endif char buf[FILEBUF_SIZE] __attribute__ ((aligned (__alignof (ElfW(Ehdr))))); + ElfW(Off) base_offset; /* for FatELF binaries. */ }; /* This is the decomposed LD_LIBRARY_PATH search path. */ @@ -1078,7 +1080,7 @@ else { phdr = alloca (maplength); - __lseek (fd, header->e_phoff, SEEK_SET); + __lseek (fd, header->e_phoff + fbp->base_offset, SEEK_SET); if ((size_t) __libc_read (fd, (void *) phdr, maplength) != maplength) { errstring = N_("cannot read file data"); @@ -1293,7 +1295,7 @@ l->l_map_start = (ElfW(Addr)) __mmap ((void *) mappref, maplength, c->prot, MAP_COPY|MAP_FILE, - fd, c->mapoff); + fd, c->mapoff + fbp->base_offset); if (__builtin_expect ((void *) l->l_map_start == MAP_FAILED, 0)) { map_error: @@ -1344,7 +1346,7 @@ && (__mmap ((void *) (l->l_addr + c->mapstart), c->mapend - c->mapstart, c->prot, MAP_FIXED|MAP_COPY|MAP_FILE, - fd, c->mapoff) + fd, c->mapoff + fbp->base_offset) == MAP_FAILED)) goto map_error; @@ -1862,6 +1864,85 @@ } +#define ELF32_CLASS ELFCLASS32 +#define ELF64_CLASS ELFCLASS64 +#ifndef VALID_ELF_HEADER +# define VALID_ELF_HEADER(hdr,exp,size) (memcmp (hdr, exp, size) == 0) +# define VALID_ELF_OSABI(osabi) (osabi == ELFOSABI_SYSV) +# define VALID_ELF_ABIVERSION(osabi,ver) (ver == 0) +#endif +#if BYTE_ORDER == BIG_ENDIAN +#define le16_to_cpu(x) __bswap_16(x) +#define le32_to_cpu(x) __bswap_32(x) +#define le64_to_cpu(x) __bswap_64(x) +#else +#define le16_to_cpu(x) (x) +#define le32_to_cpu(x) (x) +#define le64_to_cpu(x) (x) +#endif +/* See if (fd) is a handle to a FatELF file. If so, seek to the start of + the ELF binary we want. Returns an error string, or NULL on success. + If this file isn't FatELF, we consider that a success condition. */ +static const char * +examine_fatelf(const int fd, struct filebuf *fbp) +{ + const fatelf_header *header = (fatelf_header *) fbp->buf; + size_t records = (fbp->len - sizeof (fatelf_header)) / sizeof (fatelf_record); + ElfW(Ehdr) ehdr; + size_t i; + + fbp->base_offset = 0; /* make sure this is sane. */ + + if (fbp->len < sizeof (fatelf_header)) + return NULL; /* Not FatELF (probably not ELF either, but oh well.) */ + else if (le32_to_cpu(header->magic) != FATELF_MAGIC) + return NULL; /* not FatELF; go on with normal ELF handling code. */ + else if (le16_to_cpu(header->version) != FATELF_FORMAT_VERSION) + return N_("unrecognized FatELF format version"); + + /* XXX There may be up to 255 records, but usually there will be 2 to 5. + If this proves to be a problem, we can make the effort to load more data + from fd here. But right now, we fit between 21 and 34 records here! */ + if (header->num_records < records) + records = (size_t) header->num_records; + + memset((void *) &ehdr, '\0', sizeof (ehdr)); + + for (i = 0; i < records; i++) + { + const fatelf_record *record = &header->records[i]; + const uint64_t offset = le64_to_cpu(record->offset); + const uint64_t size = le64_to_cpu(record->size); + const uint64_t end_offset = offset + size; + + /* the only fields any of the elf_machine_matches_host()s care about. */ + ehdr.e_machine = (ElfW(Half)) le16_to_cpu(record->machine); + ehdr.e_ident[EI_OSABI] = record->osabi; + ehdr.e_ident[EI_ABIVERSION] = record->osabi_version; + ehdr.e_ident[EI_CLASS] = record->word_size; + ehdr.e_ident[EI_DATA] = record->byte_order; + + /* if we fail a test here, we just jump to the next record. */ + if (!VALID_ELF_OSABI(record->osabi)) + continue; + else if (!VALID_ELF_ABIVERSION(record->osabi, record->osabi_version)) + continue; + else if (!elf_machine_matches_host(&ehdr)) + continue; + else if (((ElfW(Off)) end_offset) < offset) /* overflow? */ + continue; + else if (__lseek(fd, (off_t)le64_to_cpu(record->offset), SEEK_SET) == -1) + continue; + + /* reset fbp with the actual ELF data... */ + fbp->base_offset = (ElfW(Off)) offset; + fbp->len = __libc_read(fd, fbp->buf, sizeof (fbp->buf)); + return NULL; /* no error! */ + } + + return N_("No compatible ELF binaries in this FatELF file"); +} + /* Open a file and verify it is an ELF file for this architecture. We ignore only ELF files for other architectures. Non-ELF files and ELF files with different header information cause fatal errors since @@ -1952,6 +2033,10 @@ } while (__builtin_expect (fbp->len < sizeof (ElfW(Ehdr)), 0)); + errstring = examine_fatelf(fd, fbp); + if (errstring) + goto call_lose; + /* This is where the ELF header is loaded. */ ehdr = (ElfW(Ehdr) *) fbp->buf; @@ -2073,7 +2158,7 @@ else { phdr = alloca (maplength); - __lseek (fd, ehdr->e_phoff, SEEK_SET); + __lseek (fd, ehdr->e_phoff + fbp->base_offset, SEEK_SET); if ((size_t) __libc_read (fd, (void *) phdr, maplength) != maplength) { read_error: @@ -2095,7 +2180,7 @@ else { abi_note = alloca (size); - __lseek (fd, ph->p_offset, SEEK_SET); + __lseek (fd, ph->p_offset + fbp->base_offset, SEEK_SET); if (__libc_read (fd, (void *) abi_note, size) != size) goto read_error; } diff -ruBb glibc-2.19-orig/elf/elf.h glibc-2.19/elf/elf.h --- glibc-2.19-orig/elf/elf.h 2015-02-28 06:52:37.000000000 -0800 +++ glibc-2.19/elf/elf.h 2015-02-28 06:49:49.410853919 -0800 @@ -59,6 +59,34 @@ typedef Elf32_Half Elf32_Versym; typedef Elf64_Half Elf64_Versym; +/* This is little endian on disk, and looks like "FA700E1F" in a hex editor. */ +#define FATELF_MAGIC (0x1F0E70FA) +#define FATELF_FORMAT_VERSION (1) + +/* FatELF values on disk are always littleendian, and align like Elf64. */ +typedef struct +{ + uint16_t machine; /* maps to e_machine */ + uint8_t osabi; /* maps to e_ident[EI_OSABI] */ + uint8_t osabi_version; /* maps to e_ident[EI_ABIVERSION] */ + uint8_t word_size; /* maps to e_ident[EI_CLASS] */ + uint8_t byte_order; /* maps to e_ident[EI_DATA] */ + uint8_t reserved0; + uint8_t reserved1; + uint64_t offset; + uint64_t size; +} fatelf_record; + +/* FatELF values on disk are always littleendian, and align like Elf64. */ +typedef struct +{ + uint32_t magic; /* always FATELF_MAGIC */ + uint16_t version; /* latest is always FATELF_FORMAT_VERSION */ + uint8_t num_records; + uint8_t reserved0; + fatelf_record records[]; +} fatelf_header; + /* The ELF file header. This appears at the start of every ELF file. */