diff options
Diffstat (limited to 'libelf')
-rw-r--r-- | libelf/ChangeLog | 60 | ||||
-rw-r--r-- | libelf/elf-knowledge.h | 21 | ||||
-rw-r--r-- | libelf/elf32_xlatetom.c | 2 | ||||
-rw-r--r-- | libelf/elf_compress.c | 13 | ||||
-rw-r--r-- | libelf/elf_compress_gnu.c | 9 | ||||
-rw-r--r-- | libelf/elf_getdata.c | 32 | ||||
-rw-r--r-- | libelf/gelf_fsize.c | 2 | ||||
-rw-r--r-- | libelf/gelf_getnote.c | 47 | ||||
-rw-r--r-- | libelf/gelf_xlate.c | 3 | ||||
-rw-r--r-- | libelf/libelf.h | 2 | ||||
-rw-r--r-- | libelf/libelfP.h | 16 | ||||
-rw-r--r-- | libelf/note_xlate.h | 52 |
12 files changed, 206 insertions, 53 deletions
diff --git a/libelf/ChangeLog b/libelf/ChangeLog index 5c3c0b27..e026fbe6 100644 --- a/libelf/ChangeLog +++ b/libelf/ChangeLog @@ -21,6 +21,66 @@ * Makefile.am: Link libelf agaist libgnu.a if requested. +2018-11-16 Mark Wielaard <mark@klomp.org> + + * libebl.h (__elf32_msize): Mark with const attribute. + (__elf64_msize): Likewise. + +2018-11-13 Mark Wielaard <mark@klomp.org> + + * elf_getdata.c (__libelf_set_rawdata_wrlock): Explicitly set the + alignment of SHF_COMPRESSED data to the alignment of ELF_T_CHDR. + * elf_compress.c (elf_compress): After compression set sh_addralign + to the alignment of ELF_T_CHDR. + +2018-11-09 Mark Wielaard <mark@klomp.org> + + * elf_compress_gnu.c (elf_compress_gnu): Use elf_getdata. + +2018-11-12 Mark Wielaard <mark@klomp.org> + + * elf-knowledge.c (ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX): New define. + (NT_GNU_BUILD_ATTRIBUTE_{OPEN,FUNC}): Likewise. + (GNU_BUILD_ATTRIBUTE_TYPE_{NUMERIC,STRING,BOOL_TRUE,BOOL_FALSE}): + Likewise. + (GNU_BUILD_ATTRIBUTE_{VERSION,STACK_PROT,RELRO,STACK_SIZE,TOOL,ABI, + PIC,SHORT_ENUM}): Likewise. + +2018-11-09 Mark Wielaard <mark@klomp.org> + + * elf_compress.c (__libelf_reset_rawdata): Make rawdata change + explicit by calling __libelf_set_data_list. + * elf_getdata.c (convert_data): Don't convert if type is ELF_T_BYTE + even if endianness is different. + +2018-10-18 Mark Wielaard <mark@klomp.org> + + * libelf.h (Elf_Type): Add ELF_T_NHDR8. + * libelfP.h (__libelf_data_type): Add align argument. + (NOTE_ALIGN): Split into... + (NOTE_ALIGN4): ... and ... + (NOTE_ALIGN8): this. + * elf32_xlatetom.c (xlatetom): Recognize both ELF_T_NHDR and + ELF_T_NHDR8. + * elf_compress.c (elf_compress): Pass zdata_align to + __libelf_data_type. + * elf_compress_gnu.c (elf_compress_gnu): Pass sh_addralign to + __libelf_data_type. + * elf_getdata.c (shtype_map): Add ELF_T_NHDR8. + (__libelf_data_type): Take align as extra argument, use it to + determine Elf_Type. + (__libelf_set_rawdata_wrlock): Recognize ELF_T_NHDR8. Pass align to + __libelf_data_type. + * gelf_fsize.c (__libelf_type_sizes): Add ELF_T_NHDR8. + * gelf_getnote.c (gelf_getnote): Use Elf_Type of Elf_Data to calculate + padding. + * gelf_xlate.c (__elf_xfctstom): Set ELF_T_NHDR to elf_cvt_note4, + add ELF_T_NHDR8. + * note_xlate.h (elf_cvt_note): Take nhdr8 argument and use it to + determine padding. + (elf_cvt_note4): New function. + (elf_cvt_note8): Likewise. + 2018-09-13 Mark Wielaard <mark@klomp.org> * elf32_updatefile.c (updatemmap): Use shnum, not ehdr->e_shnum. diff --git a/libelf/elf-knowledge.h b/libelf/elf-knowledge.h index 64f58878..9d3be0ff 100644 --- a/libelf/elf-knowledge.h +++ b/libelf/elf-knowledge.h @@ -77,4 +77,25 @@ || ((Ehdr)->e_machine == EM_S390 \ && (Ehdr)->e_ident[EI_CLASS] == ELFCLASS64) ? 8 : 4) +/* GNU Annobin notes are not fully standardized and abuses the owner name. */ + +#define ELF_NOTE_GNU_BUILD_ATTRIBUTE_PREFIX "GA" + +#define NT_GNU_BUILD_ATTRIBUTE_OPEN 0x100 +#define NT_GNU_BUILD_ATTRIBUTE_FUNC 0x101 + +#define GNU_BUILD_ATTRIBUTE_TYPE_NUMERIC '*' +#define GNU_BUILD_ATTRIBUTE_TYPE_STRING '$' +#define GNU_BUILD_ATTRIBUTE_TYPE_BOOL_TRUE '+' +#define GNU_BUILD_ATTRIBUTE_TYPE_BOOL_FALSE '!' + +#define GNU_BUILD_ATTRIBUTE_VERSION 1 +#define GNU_BUILD_ATTRIBUTE_STACK_PROT 2 +#define GNU_BUILD_ATTRIBUTE_RELRO 3 +#define GNU_BUILD_ATTRIBUTE_STACK_SIZE 4 +#define GNU_BUILD_ATTRIBUTE_TOOL 5 +#define GNU_BUILD_ATTRIBUTE_ABI 6 +#define GNU_BUILD_ATTRIBUTE_PIC 7 +#define GNU_BUILD_ATTRIBUTE_SHORT_ENUM 8 + #endif /* elf-knowledge.h */ diff --git a/libelf/elf32_xlatetom.c b/libelf/elf32_xlatetom.c index 13cd485d..3b94cac7 100644 --- a/libelf/elf32_xlatetom.c +++ b/libelf/elf32_xlatetom.c @@ -60,7 +60,7 @@ elfw2(LIBELFBITS, xlatetom) (Elf_Data *dest, const Elf_Data *src, /* We shouldn't require integer number of records when processing notes. Payload bytes follow the header immediately, it's not an array of records as is the case otherwise. */ - if (src->d_type != ELF_T_NHDR + if (src->d_type != ELF_T_NHDR && src->d_type != ELF_T_NHDR8 && src->d_size % recsize != 0) { __libelf_seterrno (ELF_E_INVALID_DATA); diff --git a/libelf/elf_compress.c b/libelf/elf_compress.c index 711be591..be9eeaba 100644 --- a/libelf/elf_compress.c +++ b/libelf/elf_compress.c @@ -326,6 +326,12 @@ __libelf_reset_rawdata (Elf_Scn *scn, void *buf, size_t size, size_t align, scn->rawdata_base = buf; scn->flags |= ELF_F_MALLOCED; + + /* Pretend we (tried to) read the data from the file and setup the + data (might have to convert the Chdr to native format). */ + scn->data_read = 1; + scn->flags |= ELF_F_FILEDATA; + __libelf_set_data_list_rdlock (scn, 1); } int @@ -449,14 +455,14 @@ elf_compress (Elf_Scn *scn, int type, unsigned int flags) { Elf32_Shdr *shdr = elf32_getshdr (scn); shdr->sh_size = new_size; - shdr->sh_addralign = 1; + shdr->sh_addralign = __libelf_type_align (ELFCLASS32, ELF_T_CHDR); shdr->sh_flags |= SHF_COMPRESSED; } else { Elf64_Shdr *shdr = elf64_getshdr (scn); shdr->sh_size = new_size; - shdr->sh_addralign = 1; + shdr->sh_addralign = __libelf_type_align (ELFCLASS64, ELF_T_CHDR); shdr->sh_flags |= SHF_COMPRESSED; } @@ -513,7 +519,8 @@ elf_compress (Elf_Scn *scn, int type, unsigned int flags) __libelf_reset_rawdata (scn, scn->zdata_base, scn->zdata_size, scn->zdata_align, - __libelf_data_type (elf, sh_type)); + __libelf_data_type (elf, sh_type, + scn->zdata_align)); return 1; } diff --git a/libelf/elf_compress_gnu.c b/libelf/elf_compress_gnu.c index dfa7c571..1ecd6a08 100644 --- a/libelf/elf_compress_gnu.c +++ b/libelf/elf_compress_gnu.c @@ -144,9 +144,10 @@ elf_compress_gnu (Elf_Scn *scn, int inflate, unsigned int flags) else if (inflate == 0) { /* In theory the user could have constucted a compressed section - by hand. But we always just take the rawdata directly and - decompress that. */ - Elf_Data *data = elf_rawdata (scn, NULL); + by hand. And in practice they do. For example when copying + a section from one file to another using elf_newdata. So we + have to use elf_getdata (not elf_rawdata). */ + Elf_Data *data = elf_getdata (scn, NULL); if (data == NULL) return -1; @@ -196,7 +197,7 @@ elf_compress_gnu (Elf_Scn *scn, int inflate, unsigned int flags) } __libelf_reset_rawdata (scn, buf_out, size, sh_addralign, - __libelf_data_type (elf, sh_type)); + __libelf_data_type (elf, sh_type, sh_addralign)); scn->zdata_base = buf_out; diff --git a/libelf/elf_getdata.c b/libelf/elf_getdata.c index 278dfa8f..639a798e 100644 --- a/libelf/elf_getdata.c +++ b/libelf/elf_getdata.c @@ -65,7 +65,7 @@ static const Elf_Type shtype_map[EV_NUM - 1][TYPEIDX (SHT_HISUNW) + 1] = [SHT_PREINIT_ARRAY] = ELF_T_ADDR, [SHT_GROUP] = ELF_T_WORD, [SHT_SYMTAB_SHNDX] = ELF_T_WORD, - [SHT_NOTE] = ELF_T_NHDR, + [SHT_NOTE] = ELF_T_NHDR, /* Need alignment to guess ELF_T_NHDR8. */ [TYPEIDX (SHT_GNU_verdef)] = ELF_T_VDEF, [TYPEIDX (SHT_GNU_verneed)] = ELF_T_VNEED, [TYPEIDX (SHT_GNU_versym)] = ELF_T_HALF, @@ -106,6 +106,7 @@ const uint_fast8_t __libelf_type_aligns[EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM] [ELF_T_GNUHASH] = __alignof__ (Elf32_Word), \ [ELF_T_AUXV] = __alignof__ (ElfW2(Bits,auxv_t)), \ [ELF_T_CHDR] = __alignof__ (ElfW2(Bits,Chdr)), \ + [ELF_T_NHDR8] = 8 /* Special case for GNU Property note. */ \ } [EV_CURRENT - 1] = { @@ -118,7 +119,7 @@ const uint_fast8_t __libelf_type_aligns[EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM] Elf_Type internal_function -__libelf_data_type (Elf *elf, int sh_type) +__libelf_data_type (Elf *elf, int sh_type, GElf_Xword align) { /* Some broken ELF ABI for 64-bit machines use the wrong hash table entry size. See elf-knowledge.h for more information. */ @@ -129,7 +130,13 @@ __libelf_data_type (Elf *elf, int sh_type) return (SH_ENTSIZE_HASH (ehdr) == 4 ? ELF_T_WORD : ELF_T_XWORD); } else - return shtype_map[LIBELF_EV_IDX][TYPEIDX (sh_type)]; + { + Elf_Type t = shtype_map[LIBELF_EV_IDX][TYPEIDX (sh_type)]; + /* Special case for GNU Property notes. */ + if (t == ELF_T_NHDR && align == 8) + t = ELF_T_NHDR8; + return t; + } } /* Convert the data in the current section. */ @@ -139,7 +146,8 @@ convert_data (Elf_Scn *scn, int version __attribute__ ((unused)), int eclass, { const size_t align = __libelf_type_align (eclass, type); - if (data == MY_ELFDATA) + /* Do we need to convert the data and/or adjust for alignment? */ + if (data == MY_ELFDATA || type == ELF_T_BYTE) { if (((((size_t) (char *) scn->rawdata_base)) & (align - 1)) == 0) /* No need to copy, we can use the raw data. */ @@ -260,9 +268,15 @@ __libelf_set_rawdata_wrlock (Elf_Scn *scn) /* First a test whether the section is valid at all. */ size_t entsize; - /* Compressed data has a header, but then compressed data. */ + /* Compressed data has a header, but then compressed data. + Make sure to set the alignment of the header explicitly, + don't trust the file alignment for the section, it is + often wrong. */ if ((flags & SHF_COMPRESSED) != 0) - entsize = 1; + { + entsize = 1; + align = __libelf_type_align (elf->class, ELF_T_CHDR); + } else if (type == SHT_HASH) { GElf_Ehdr ehdr_mem; @@ -272,7 +286,9 @@ __libelf_set_rawdata_wrlock (Elf_Scn *scn) else { Elf_Type t = shtype_map[LIBELF_EV_IDX][TYPEIDX (type)]; - if (t == ELF_T_VDEF || t == ELF_T_NHDR + if (t == ELF_T_NHDR && align == 8) + t = ELF_T_NHDR8; + if (t == ELF_T_VDEF || t == ELF_T_NHDR || t == ELF_T_NHDR8 || (t == ELF_T_GNUHASH && elf->class == ELFCLASS64)) entsize = 1; else @@ -357,7 +373,7 @@ __libelf_set_rawdata_wrlock (Elf_Scn *scn) if ((flags & SHF_COMPRESSED) != 0) scn->rawdata.d.d_type = ELF_T_CHDR; else - scn->rawdata.d.d_type = __libelf_data_type (elf, type); + scn->rawdata.d.d_type = __libelf_data_type (elf, type, align); scn->rawdata.d.d_off = 0; /* Make sure the alignment makes sense. d_align should be aligned both diff --git a/libelf/gelf_fsize.c b/libelf/gelf_fsize.c index 0c509265..d04ec5d5 100644 --- a/libelf/gelf_fsize.c +++ b/libelf/gelf_fsize.c @@ -64,6 +64,8 @@ const size_t __libelf_type_sizes[EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM] = [ELF_T_VNEED] = sizeof (ElfW2(LIBELFBITS, Ext_Verneed)), \ [ELF_T_VNAUX] = sizeof (ElfW2(LIBELFBITS, Ext_Vernaux)), \ [ELF_T_NHDR] = sizeof (ElfW2(LIBELFBITS, Ext_Nhdr)), \ + /* Note the header size is the same, but padding is different. */ \ + [ELF_T_NHDR8] = sizeof (ElfW2(LIBELFBITS, Ext_Nhdr)), \ [ELF_T_SYMINFO] = sizeof (ElfW2(LIBELFBITS, Ext_Syminfo)), \ [ELF_T_MOVE] = sizeof (ElfW2(LIBELFBITS, Ext_Move)), \ [ELF_T_LIB] = sizeof (ElfW2(LIBELFBITS, Ext_Lib)), \ diff --git a/libelf/gelf_getnote.c b/libelf/gelf_getnote.c index c75eddab..6d33b355 100644 --- a/libelf/gelf_getnote.c +++ b/libelf/gelf_getnote.c @@ -1,5 +1,5 @@ /* Get note information at the supplied offset. - Copyright (C) 2007, 2014, 2015 Red Hat, Inc. + Copyright (C) 2007, 2014, 2015, 2018 Red Hat, Inc. This file is part of elfutils. This file is free software; you can redistribute it and/or modify @@ -43,7 +43,7 @@ gelf_getnote (Elf_Data *data, size_t offset, GElf_Nhdr *result, if (data == NULL) return 0; - if (unlikely (data->d_type != ELF_T_NHDR)) + if (unlikely (data->d_type != ELF_T_NHDR && data->d_type != ELF_T_NHDR8)) { __libelf_seterrno (ELF_E_INVALID_HANDLE); return 0; @@ -69,27 +69,42 @@ gelf_getnote (Elf_Data *data, size_t offset, GElf_Nhdr *result, const GElf_Nhdr *n = data->d_buf + offset; offset += sizeof *n; - /* Include padding. Check below for overflow. */ - GElf_Word namesz = NOTE_ALIGN (n->n_namesz); - GElf_Word descsz = NOTE_ALIGN (n->n_descsz); - - if (unlikely (offset > data->d_size - || data->d_size - offset < namesz - || (namesz == 0 && n->n_namesz != 0))) + if (offset > data->d_size) offset = 0; else { + /* This is slightly tricky, offset is guaranteed to be 4 + byte aligned, which is what we need for the name_offset. + And normally desc_offset is also 4 byte aligned, but not + for GNU Property notes, then it should be 8. So align + the offset, after adding the namesz, and include padding + in descsz to get to the end. */ *name_offset = offset; - offset += namesz; - if (unlikely (offset > data->d_size - || data->d_size - offset < descsz - || (descsz == 0 && n->n_descsz != 0))) + offset += n->n_namesz; + if (offset > data->d_size) offset = 0; else { - *desc_offset = offset; - offset += descsz; - *result = *n; + /* Include padding. Check below for overflow. */ + GElf_Word descsz = (data->d_type == ELF_T_NHDR8 + ? NOTE_ALIGN8 (n->n_descsz) + : NOTE_ALIGN4 (n->n_descsz)); + + if (data->d_type == ELF_T_NHDR8) + offset = NOTE_ALIGN8 (offset); + else + offset = NOTE_ALIGN4 (offset); + + if (unlikely (offset > data->d_size + || data->d_size - offset < descsz + || (descsz == 0 && n->n_descsz != 0))) + offset = 0; + else + { + *desc_offset = offset; + offset += descsz; + *result = *n; + } } } } diff --git a/libelf/gelf_xlate.c b/libelf/gelf_xlate.c index 479f1436..b5d6ef3d 100644 --- a/libelf/gelf_xlate.c +++ b/libelf/gelf_xlate.c @@ -195,7 +195,8 @@ const xfct_t __elf_xfctstom[EV_NUM - 1][EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM] [ELF_T_VDAUX] = elf_cvt_Verdef, \ [ELF_T_VNEED] = elf_cvt_Verneed, \ [ELF_T_VNAUX] = elf_cvt_Verneed, \ - [ELF_T_NHDR] = elf_cvt_note, \ + [ELF_T_NHDR] = elf_cvt_note4, \ + [ELF_T_NHDR8] = elf_cvt_note8, \ [ELF_T_SYMINFO] = ElfW2(Bits, cvt_Syminfo), \ [ELF_T_MOVE] = ElfW2(Bits, cvt_Move), \ [ELF_T_LIB] = ElfW2(Bits, cvt_Lib), \ diff --git a/libelf/libelf.h b/libelf/libelf.h index d11358cc..1ff11c95 100644 --- a/libelf/libelf.h +++ b/libelf/libelf.h @@ -117,6 +117,8 @@ typedef enum ELF_T_GNUHASH, /* GNU-style hash section. */ ELF_T_AUXV, /* Elf32_auxv_t, Elf64_auxv_t, ... */ ELF_T_CHDR, /* Compressed, Elf32_Chdr, Elf64_Chdr, ... */ + ELF_T_NHDR8, /* Special GNU Properties note. Same as Nhdr, + except padding. */ /* Keep this the last entry. */ ELF_T_NUM } Elf_Type; diff --git a/libelf/libelfP.h b/libelf/libelfP.h index ed216c8c..9f3e8e9d 100644 --- a/libelf/libelfP.h +++ b/libelf/libelfP.h @@ -452,7 +452,8 @@ extern const uint_fast8_t __libelf_type_aligns[EV_NUM - 1][ELFCLASSNUM - 1][ELF_ /* Given an Elf handle and a section type returns the Elf_Data d_type. Should not be called when SHF_COMPRESSED is set, the d_type should be ELF_T_BYTE. */ -extern Elf_Type __libelf_data_type (Elf *elf, int sh_type) internal_function; +extern Elf_Type __libelf_data_type (Elf *elf, int sh_type, GElf_Xword align) + internal_function; /* The libelf API does not have such a function but it is still useful. Get the memory size for the given type. @@ -460,9 +461,9 @@ extern Elf_Type __libelf_data_type (Elf *elf, int sh_type) internal_function; These functions cannot be marked internal since they are aliases of the export elfXX_fsize functions.*/ extern size_t __elf32_msize (Elf_Type __type, size_t __count, - unsigned int __version); + unsigned int __version) __const_attribute__; extern size_t __elf64_msize (Elf_Type __type, size_t __count, - unsigned int __version); + unsigned int __version) __const_attribute__; /* Create Elf descriptor from memory image. */ @@ -624,8 +625,13 @@ extern void __libelf_reset_rawdata (Elf_Scn *scn, void *buf, size_t size, } \ } while (0) -/* Align offset to 4 bytes as needed for note name and descriptor data. */ -#define NOTE_ALIGN(n) (((n) + 3) & -4U) +/* Align offset to 4 bytes as needed for note name and descriptor data. + This is almost always used, except for GNU Property notes, which use + 8 byte padding... */ +#define NOTE_ALIGN4(n) (((n) + 3) & -4U) + +/* Special note padding rule for GNU Property notes. */ +#define NOTE_ALIGN8(n) (((n) + 7) & -8U) /* Convenience macro. */ #define INVALID_NDX(ndx, type, data) \ diff --git a/libelf/note_xlate.h b/libelf/note_xlate.h index 62c6f63d..9bdc3e2c 100644 --- a/libelf/note_xlate.h +++ b/libelf/note_xlate.h @@ -1,5 +1,5 @@ /* Conversion functions for notes. - Copyright (C) 2007, 2009, 2014 Red Hat, Inc. + Copyright (C) 2007, 2009, 2014, 2018 Red Hat, Inc. This file is part of elfutils. This file is free software; you can redistribute it and/or modify @@ -27,38 +27,60 @@ not, see <http://www.gnu.org/licenses/>. */ static void -elf_cvt_note (void *dest, const void *src, size_t len, int encode) +elf_cvt_note (void *dest, const void *src, size_t len, int encode, + bool nhdr8) { + /* Note that the header is always the same size, but the padding + differs for GNU Property notes. */ assert (sizeof (Elf32_Nhdr) == sizeof (Elf64_Nhdr)); while (len >= sizeof (Elf32_Nhdr)) { + /* Convert the header. */ (1 ? Elf32_cvt_Nhdr : Elf64_cvt_Nhdr) (dest, src, sizeof (Elf32_Nhdr), encode); const Elf32_Nhdr *n = encode ? src : dest; - Elf32_Word namesz = NOTE_ALIGN (n->n_namesz); - Elf32_Word descsz = NOTE_ALIGN (n->n_descsz); - len -= sizeof *n; - src += sizeof *n; - dest += sizeof *n; + size_t note_len = sizeof *n; - if (namesz > len) + /* desc needs to be aligned. */ + note_len += n->n_namesz; + note_len = nhdr8 ? NOTE_ALIGN8 (note_len) : NOTE_ALIGN4 (note_len); + if (note_len > len || note_len < 8) break; - len -= namesz; - if (descsz > len) + + /* data as a whole needs to be aligned. */ + note_len += n->n_descsz; + note_len = nhdr8 ? NOTE_ALIGN8 (note_len) : NOTE_ALIGN4 (note_len); + if (note_len > len || note_len < 8) break; - len -= descsz; + /* Copy or skip the note data. */ + size_t note_data_len = note_len - sizeof *n; + src += sizeof *n; + dest += sizeof *n; if (src != dest) - memcpy (dest, src, namesz + descsz); + memcpy (dest, src, note_data_len); - src += namesz + descsz; - dest += namesz + descsz; + src += note_data_len; + dest += note_data_len; + len -= note_len; } - /* Copy opver any leftover data unconcerted. Probably part of + /* Copy over any leftover data unconverted. Probably part of truncated name/desc data. */ if (unlikely (len > 0) && src != dest) memcpy (dest, src, len); } + +static void +elf_cvt_note4 (void *dest, const void *src, size_t len, int encode) +{ + elf_cvt_note (dest, src, len, encode, false); +} + +static void +elf_cvt_note8 (void *dest, const void *src, size_t len, int encode) +{ + elf_cvt_note (dest, src, len, encode, true); +} |