diff options
author | Mark Wielaard <mjw@redhat.com> | 2015-12-30 01:39:29 +0100 |
---|---|---|
committer | Mark Wielaard <mjw@redhat.com> | 2016-01-06 14:27:10 +0100 |
commit | 519c13c9c7fc591609eed405a3e952707c60ec7e (patch) | |
tree | 00c3afe184607b9d62f6fd81553de14b90a09bc6 /libelf | |
parent | f5013e83d5c8fcd9309c8976c3f1167d28cd07aa (diff) | |
download | android_external_elfutils-519c13c9c7fc591609eed405a3e952707c60ec7e.tar.gz android_external_elfutils-519c13c9c7fc591609eed405a3e952707c60ec7e.tar.bz2 android_external_elfutils-519c13c9c7fc591609eed405a3e952707c60ec7e.zip |
libelf: Make elf_strptr index correctly into compressed section data.
elf_strptr indexes into the section data. This is defined as index into
the uncompressed data of the section. If the section is compressed make
sure the uncompressed data is available, but don't really decompress the
section header (elf_getdata will still return compressed data).
Signed-off-by: Mark Wielaard <mjw@redhat.com>
Diffstat (limited to 'libelf')
-rw-r--r-- | libelf/ChangeLog | 10 | ||||
-rw-r--r-- | libelf/elf_compress.c | 97 | ||||
-rw-r--r-- | libelf/elf_strptr.c | 50 | ||||
-rw-r--r-- | libelf/libelfP.h | 6 |
4 files changed, 120 insertions, 43 deletions
diff --git a/libelf/ChangeLog b/libelf/ChangeLog index 1e214006..3a1fe91d 100644 --- a/libelf/ChangeLog +++ b/libelf/ChangeLog @@ -1,3 +1,13 @@ +2015-11-26 Mark Wielaard <mjw@redhat.com> + + * elf_compress.c (__libelf_decompress_elf): New function, extracted + from... + (elf_compress): here. Check zdata_base use __libelf_decompress_elf. + * elf_strptr.c (elf_strptr): If SHF_COMPRESSED check, uncompress and + use zdata. + * libelfP.h (struct Elf_Scn): Add zdata_size and zdata_align. + (__libelf_decompress_elf): New internal function definition. + 2015-10-21 Mark Wielaard <mjw@redhat.com> * Makefile.am (libelf_a_SOURCES): Add elf_compress.c and diff --git a/libelf/elf_compress.c b/libelf/elf_compress.c index 17b80f2d..ec5b7174 100644 --- a/libelf/elf_compress.c +++ b/libelf/elf_compress.c @@ -248,6 +248,47 @@ __libelf_decompress (void *buf_in, size_t size_in, size_t size_out) return buf_out; } +void * +internal_function +__libelf_decompress_elf (Elf_Scn *scn, size_t *size_out, size_t *addralign) +{ + GElf_Chdr chdr; + if (gelf_getchdr (scn, &chdr) == NULL) + return NULL; + + if (chdr.ch_type != ELFCOMPRESS_ZLIB) + { + __libelf_seterrno (ELF_E_UNKNOWN_COMPRESSION_TYPE); + return NULL; + } + + if (! powerof2 (chdr.ch_addralign)) + { + __libelf_seterrno (ELF_E_INVALID_ALIGN); + return NULL; + } + + /* Take the in-memory representation, so we can even handle a + section that has just been constructed (maybe it was copied + over from some other ELF file first with elf_newdata). This + is slightly inefficient when the raw data needs to be + converted since then we'll be converting the whole buffer and + not just Chdr. */ + Elf_Data *data = elf_getdata (scn, NULL); + if (data == NULL) + return NULL; + + int elfclass = scn->elf->class; + size_t hsize = (elfclass == ELFCLASS32 + ? sizeof (Elf32_Chdr) : sizeof (Elf64_Chdr)); + size_t size_in = data->d_size - hsize; + void *buf_in = data->d_buf + hsize; + void *buf_out = __libelf_decompress (buf_in, size_in, chdr.ch_size); + *size_out = chdr.ch_size; + *addralign = chdr.ch_addralign; + return buf_out; +} + void internal_function __libelf_reset_rawdata (Elf_Scn *scn, void *buf, size_t size, size_t align, @@ -424,62 +465,42 @@ elf_compress (Elf_Scn *scn, int type, unsigned int flags) return -1; } - GElf_Chdr chdr; - if (gelf_getchdr (scn, &chdr) == NULL) - return -1; - - if (chdr.ch_type != ELFCOMPRESS_ZLIB) + /* If the data is already decompressed (by elf_strptr), then we + only need to setup the rawdata and section header. XXX what + about elf_newdata? */ + if (scn->zdata_base == NULL) { - __libelf_seterrno (ELF_E_UNKNOWN_COMPRESSION_TYPE); - return -1; + size_t size_out, addralign; + void *buf_out = __libelf_decompress_elf (scn, &size_out, &addralign); + if (buf_out == NULL) + return -1; + + scn->zdata_base = buf_out; + scn->zdata_size = size_out; + scn->zdata_align = addralign; } - if (! powerof2 (chdr.ch_addralign)) - { - __libelf_seterrno (ELF_E_INVALID_ALIGN); - return -1; - } - - /* Take the in-memory representation, so we can even handle a - section that has just been constructed (maybe it was copied - over from some other ELF file first with elf_newdata). This - is slightly inefficient when the raw data needs to be - converted since then we'll be converting the whole buffer and - not just Chdr. */ - Elf_Data *data = elf_getdata (scn, NULL); - if (data == NULL) - return -1; - - size_t hsize = (elfclass == ELFCLASS32 - ? sizeof (Elf32_Chdr) : sizeof (Elf64_Chdr)); - size_t size_in = data->d_size - hsize; - void *buf_in = data->d_buf + hsize; - void *buf_out = __libelf_decompress (buf_in, size_in, chdr.ch_size); - if (buf_out == NULL) - return -1; - /* Note we keep the sh_entsize as is, we assume it is setup correctly and ignored when SHF_COMPRESSED is set. */ if (elfclass == ELFCLASS32) { Elf32_Shdr *shdr = elf32_getshdr (scn); - shdr->sh_size = chdr.ch_size; - shdr->sh_addralign = chdr.ch_addralign; + shdr->sh_size = scn->zdata_size; + shdr->sh_addralign = scn->zdata_align; shdr->sh_flags &= ~SHF_COMPRESSED; } else { Elf64_Shdr *shdr = elf64_getshdr (scn); - shdr->sh_size = chdr.ch_size; - shdr->sh_addralign = chdr.ch_addralign; + shdr->sh_size = scn->zdata_size; + shdr->sh_addralign = scn->zdata_align; shdr->sh_flags &= ~SHF_COMPRESSED; } - __libelf_reset_rawdata (scn, buf_out, chdr.ch_size, chdr.ch_addralign, + __libelf_reset_rawdata (scn, scn->zdata_base, + scn->zdata_size, scn->zdata_align, __libelf_data_type (elf, sh_type)); - scn->zdata_base = buf_out; - return 1; } else diff --git a/libelf/elf_strptr.c b/libelf/elf_strptr.c index c5138dc6..e3b5876b 100644 --- a/libelf/elf_strptr.c +++ b/libelf/elf_strptr.c @@ -83,6 +83,20 @@ elf_strptr (Elf *elf, size_t idx, size_t offset) } } + void *get_zdata (void) + { + size_t zsize, zalign; + void *zdata = __libelf_decompress_elf (strscn, &zsize, &zalign); + if (zdata == NULL) + return NULL; + + strscn->zdata_base = zdata; + strscn->zdata_size = zsize; + strscn->zdata_align = zalign; + + return zdata; + } + size_t sh_size = 0; if (elf->class == ELFCLASS32) { @@ -94,8 +108,16 @@ elf_strptr (Elf *elf, size_t idx, size_t offset) goto out; } - sh_size = shdr->sh_size; - if (unlikely (offset >= shdr->sh_size)) + if ((shdr->sh_flags & SHF_COMPRESSED) == 0) + sh_size = shdr->sh_size; + else + { + if (strscn->zdata_base == NULL && get_zdata () == NULL) + goto out; + sh_size = strscn->zdata_size; + } + + if (unlikely (offset >= sh_size)) { /* The given offset is too big, it is beyond this section. */ __libelf_seterrno (ELF_E_OFFSET_RANGE); @@ -112,8 +134,16 @@ elf_strptr (Elf *elf, size_t idx, size_t offset) goto out; } - sh_size = shdr->sh_size; - if (unlikely (offset >= shdr->sh_size)) + if ((shdr->sh_flags & SHF_COMPRESSED) == 0) + sh_size = shdr->sh_size; + else + { + if (strscn->zdata_base == NULL && get_zdata () == NULL) + goto out; + sh_size = strscn->zdata_size; + } + + if (unlikely (offset >= sh_size)) { /* The given offset is too big, it is beyond this section. */ __libelf_seterrno (ELF_E_OFFSET_RANGE); @@ -131,7 +161,17 @@ elf_strptr (Elf *elf, size_t idx, size_t offset) goto out; } - if (likely (strscn->data_list_rear == NULL)) + if (unlikely (strscn->zdata_base != NULL)) + { + /* Make sure the string is NUL terminated. Start from the end, + which very likely is a NUL char. */ + if (likely (memrchr (&strscn->zdata_base[offset], + '\0', sh_size - offset) != NULL)) + result = &strscn->zdata_base[offset]; + else + __libelf_seterrno (ELF_E_INVALID_INDEX); + } + else if (likely (strscn->data_list_rear == NULL)) { // XXX The above is currently correct since elf_newdata will // make sure to convert the rawdata into the datalist if diff --git a/libelf/libelfP.h b/libelf/libelfP.h index 50f92174..57ccbce4 100644 --- a/libelf/libelfP.h +++ b/libelf/libelfP.h @@ -239,6 +239,8 @@ struct Elf_Scn char *data_base; /* The converted data of the section. */ char *zdata_base; /* The uncompressed data of the section. */ + size_t zdata_size; /* If zdata_base != NULL, the size of data. */ + size_t zdata_align; /* If zdata_base != NULL, the addralign. */ struct Elf_ScnList *list; /* Pointer to the section list element the data is in. */ @@ -600,6 +602,10 @@ extern void * __libelf_compress (Elf_Scn *scn, size_t hsize, int ei_data, extern void * __libelf_decompress (void *buf_in, size_t size_in, size_t size_out) internal_function; +extern void * __libelf_decompress_elf (Elf_Scn *scn, + size_t *size_out, size_t *addralign) + internal_function; + extern void __libelf_reset_rawdata (Elf_Scn *scn, void *buf, size_t size, size_t align, Elf_Type type) |