diff options
-rw-r--r-- | ChangeLog | 14 | ||||
-rw-r--r-- | elf/dl-hwcaps.c | 24 | ||||
-rw-r--r-- | elf/dl-load.c | 19 | ||||
-rw-r--r-- | elf/readelflib.c | 19 | ||||
-rw-r--r-- | include/elf.h | 16 |
5 files changed, 76 insertions, 16 deletions
diff --git a/ChangeLog b/ChangeLog index 77092bbfa5..593811dcb4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2017-11-28 H.J. Lu <hongjiu.lu@intel.com> + + [BZ #22370] + * elf/dl-hwcaps.c (ROUND): Removed. + (_dl_important_hwcaps): Replace ROUND with ELF_NOTE_DESC_OFFSET + and ELF_NOTE_NEXT_OFFSET. + * elf/dl-load.c (ROUND): Removed. + (open_verify): Replace ROUND with ELF_NOTE_NEXT_OFFSET. + * elf/readelflib.c (ROUND): Removed. + (process_elf_file): Replace ROUND with ELF_NOTE_NEXT_OFFSET. + * include/elf.h [!_ISOMAC]: Include <libc-pointer-arith.h>. + [!_ISOMAC] (ELF_NOTE_DESC_OFFSET): New. + [!_ISOMAC] (ELF_NOTE_NEXT_OFFSET): Likewise. + 2017-11-28 Joseph Myers <joseph@codesourcery.com> * sysdeps/s390/fpu/s_fmaf.c: Include <libm-alias-float.h>. diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c index 92f2eb45ce..27ba6122ff 100644 --- a/elf/dl-hwcaps.c +++ b/elf/dl-hwcaps.c @@ -67,6 +67,18 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz, { const ElfW(Addr) start = (phdr[i].p_vaddr + GLRO(dl_sysinfo_map)->l_addr); + /* NB: Some PT_NOTE segment may have alignment value of 0 + or 1. gABI specifies that PT_NOTE segments should be + aligned to 4 bytes in 32-bit objects and to 8 bytes in + 64-bit objects. As a Linux extension, we also support + 4 byte alignment in 64-bit objects. If p_align is less + than 4, we treate alignment as 4 bytes since some note + segments have 0 or 1 byte alignment. */ + ElfW(Addr) align = phdr[i].p_align; + if (align < 4) + align = 4; + else if (align != 4 && align != 8) + continue; /* The standard ELF note layout is exactly as the anonymous struct. The next element is a variable length vendor name of length VENDORLEN (with a real length rounded to ElfW(Word)), followed @@ -80,7 +92,6 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz, } *note = (const void *) start; while ((ElfW(Addr)) (note + 1) - start < phdr[i].p_memsz) { -#define ROUND(len) (((len) + sizeof (ElfW(Word)) - 1) & -sizeof (ElfW(Word))) /* The layout of the type 2, vendor "GNU" note is as follows: .long <Number of capabilities enabled by this note> .long <Capabilities mask> (as mask >> _DL_FIRST_EXTRA). @@ -91,17 +102,18 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz, && !memcmp ((note + 1), "GNU", sizeof "GNU") && note->datalen > 2 * sizeof (ElfW(Word)) + 2) { - const ElfW(Word) *p = ((const void *) (note + 1) - + ROUND (sizeof "GNU")); + const ElfW(Word) *p + = ((const void *) note + + ELF_NOTE_DESC_OFFSET (sizeof "GNU", align)); cnt += *p++; ++p; /* Skip mask word. */ dsocaps = (const char *) p; /* Pseudo-string "<b>name" */ dsocapslen = note->datalen - sizeof *p * 2; break; } - note = ((const void *) (note + 1) - + ROUND (note->vendorlen) + ROUND (note->datalen)); -#undef ROUND + note = ((const void *) note + + ELF_NOTE_NEXT_OFFSET (note->vendorlen, + note->datalen, align)); } if (dsocaps != NULL) break; diff --git a/elf/dl-load.c b/elf/dl-load.c index 1220183ce2..10d859bd35 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -1683,6 +1683,18 @@ open_verify (const char *name, int fd, if (ph->p_type == PT_NOTE && ph->p_filesz >= 32 && ph->p_align >= 4) { ElfW(Addr) size = ph->p_filesz; + /* NB: Some PT_NOTE segment may have alignment value of 0 + or 1. gABI specifies that PT_NOTE segments should be + aligned to 4 bytes in 32-bit objects and to 8 bytes in + 64-bit objects. As a Linux extension, we also support + 4 byte alignment in 64-bit objects. If p_align is less + than 4, we treate alignment as 4 bytes since some note + segments have 0 or 1 byte alignment. */ + ElfW(Addr) align = ph->p_align; + if (align < 4) + align = 4; + else if (align != 4 && align != 8) + continue; if (ph->p_offset + size <= (size_t) fbp->len) abi_note = (void *) (fbp->buf + ph->p_offset); @@ -1696,10 +1708,9 @@ open_verify (const char *name, int fd, while (memcmp (abi_note, &expected_note, sizeof (expected_note))) { -#define ROUND(len) (((len) + sizeof (ElfW(Word)) - 1) & -sizeof (ElfW(Word))) - ElfW(Addr) note_size = 3 * sizeof (ElfW(Word)) - + ROUND (abi_note[0]) - + ROUND (abi_note[1]); + ElfW(Addr) note_size + = ELF_NOTE_NEXT_OFFSET (abi_note[0], abi_note[1], + align); if (size - 32 < note_size) { diff --git a/elf/readelflib.c b/elf/readelflib.c index 9ad56dcc34..3a303fff5f 100644 --- a/elf/readelflib.c +++ b/elf/readelflib.c @@ -131,15 +131,26 @@ process_elf_file (const char *file_name, const char *lib, int *flag, ElfW(Word) *abi_note = (ElfW(Word) *) (file_contents + segment->p_offset); ElfW(Addr) size = segment->p_filesz; + /* NB: Some PT_NOTE segment may have alignment value of 0 + or 1. gABI specifies that PT_NOTE segments should be + aligned to 4 bytes in 32-bit objects and to 8 bytes in + 64-bit objects. As a Linux extension, we also support + 4 byte alignment in 64-bit objects. If p_align is less + than 4, we treate alignment as 4 bytes since some note + segments have 0 or 1 byte alignment. */ + ElfW(Addr) align = segment->p_align; + if (align < 4) + align = 4; + else if (align != 4 && align != 8) + continue; while (abi_note [0] != 4 || abi_note [1] != 16 || abi_note [2] != 1 || memcmp (abi_note + 3, "GNU", 4) != 0) { -#define ROUND(len) (((len) + sizeof (ElfW(Word)) - 1) & -sizeof (ElfW(Word))) - ElfW(Addr) note_size = 3 * sizeof (ElfW(Word)) - + ROUND (abi_note[0]) - + ROUND (abi_note[1]); + ElfW(Addr) note_size + = ELF_NOTE_NEXT_OFFSET (abi_note[0], abi_note[1], + align); if (size - 32 < note_size || note_size == 0) { diff --git a/include/elf.h b/include/elf.h index f06a33f256..ab76aafb1e 100644 --- a/include/elf.h +++ b/include/elf.h @@ -1,7 +1,19 @@ #ifndef _ELF_H #include <elf/elf.h> -# ifndef _ISOMAC +#ifndef _ISOMAC + +# include <libc-pointer-arith.h> + +/* Compute the offset of the note descriptor from size of note entry's + owner string and note alignment. */ +# define ELF_NOTE_DESC_OFFSET(namesz, align) \ + ALIGN_UP (sizeof (ElfW(Nhdr)) + (namesz), (align)) + +/* Compute the offset of the next note entry from size of note entry's + owner string, size of the note descriptor and note alignment. */ +# define ELF_NOTE_NEXT_OFFSET(namesz, descsz, align) \ + ALIGN_UP (ELF_NOTE_DESC_OFFSET ((namesz), (align)) + (descsz), (align)) /* Some information which is not meant for the public and therefore not in <elf.h>. */ @@ -13,5 +25,5 @@ (DF_1_NOW | DF_1_NODELETE | DF_1_INITFIRST | DF_1_NOOPEN \ | DF_1_ORIGIN | DF_1_NODEFLIB) -# endif /* !_ISOMAC */ +#endif /* !_ISOMAC */ #endif /* elf.h */ |