Skip to content
This repository has been archived by the owner on Nov 15, 2022. It is now read-only.

Commit

Permalink
libelf: Make elf_strptr index correctly into compressed section data.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Mark Wielaard committed Jan 6, 2016
1 parent f5013e8 commit 519c13c
Show file tree
Hide file tree
Showing 10 changed files with 445 additions and 59 deletions.
10 changes: 10 additions & 0 deletions 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
Expand Down
97 changes: 59 additions & 38 deletions libelf/elf_compress.c
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down
50 changes: 45 additions & 5 deletions libelf/elf_strptr.c
Expand Up @@ -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)
{
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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
Expand Down
6 changes: 6 additions & 0 deletions libelf/libelfP.h
Expand Up @@ -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. */
Expand Down Expand Up @@ -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)
Expand Down
11 changes: 11 additions & 0 deletions tests/ChangeLog
@@ -1,3 +1,14 @@
2015-11-26 Mark Wielaard <mjw@redhat.com>

* zstrptr.c: New file.
* run-zstrptr.sh: New test.
* elfputzdata.c (main): (re)compress .shstrtab.
* run-elfputzdata.sh: Expect .shstrtab compression.
* Makefile.am (check_PROGRAMS): Add zstrptr.
(TESTS): Add run-zstrptr.sh.
(EXTRA_DIST): Likewise.
(zstrptr_LDADD): New variable.

2015-10-20 Mark Wielaard <mjw@redhat.com>

* run-readelf-zx.sh: New test.
Expand Down
8 changes: 5 additions & 3 deletions tests/Makefile.am
Expand Up @@ -53,7 +53,7 @@ check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \
buildid deleted deleted-lib.so aggregate_size vdsosyms \
getsrc_die strptr newdata elfstrtab dwfl-proc-attach \
elfshphehdr elfstrmerge dwelfgnucompressed elfgetchdr \
elfgetzdata elfputzdata
elfgetzdata elfputzdata zstrptr

asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \
asm-tst6 asm-tst7 asm-tst8 asm-tst9
Expand Down Expand Up @@ -123,7 +123,7 @@ TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \
run-getsrc-die.sh run-strptr.sh newdata elfstrtab dwfl-proc-attach \
elfshphehdr run-lfs-symbols.sh run-dwelfgnucompressed.sh \
run-elfgetchdr.sh \
run-elfgetzdata.sh run-elfputzdata.sh
run-elfgetzdata.sh run-elfputzdata.sh run-zstrptr.sh

if !BIARCH
export ELFUTILS_DISABLE_BIARCH = 1
Expand Down Expand Up @@ -319,7 +319,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
run-dwelfgnucompressed.sh \
testfile-zgabi32.bz2 testfile-zgabi64.bz2 \
testfile-zgabi32be.bz2 testfile-zgabi64be.bz2 \
run-elfgetchdr.sh run-elfgetzdata.sh run-elfputzdata.sh
run-elfgetchdr.sh run-elfgetzdata.sh run-elfputzdata.sh \
run-zstrptr.sh

if USE_VALGRIND
valgrind_cmd='valgrind -q --leak-check=full --error-exitcode=1'
Expand Down Expand Up @@ -472,6 +473,7 @@ dwelfgnucompressed_LDADD = $(libelf) $(libdw)
elfgetchdr_LDADD = $(libelf) $(libdw)
elfgetzdata_LDADD = $(libelf)
elfputzdata_LDADD = $(libelf)
zstrptr_LDADD = $(libelf)

if GCOV
check: check-am coverage
Expand Down
15 changes: 10 additions & 5 deletions tests/elfputzdata.c
Expand Up @@ -77,11 +77,7 @@ main (int argc, char *argv[])
GElf_Shdr mem;
GElf_Shdr *shdr = gelf_getshdr (scn, &mem);
const char *name = elf_strptr (elf, strndx, shdr->sh_name);
if (idx == strndx)
{
printf ("Not compressing section string table %zd\n", idx);
}
else if (shdr->sh_type == SHT_NOBITS
if (shdr->sh_type == SHT_NOBITS
|| (shdr->sh_flags & SHF_ALLOC) != 0)
{
printf ("Cannot compress %zd %s\n", idx, name);
Expand Down Expand Up @@ -221,6 +217,15 @@ main (int argc, char *argv[])
return -1;
}
free (orig_buf);
// Recompress the string table, just to make sure
// everything keeps working. See elf_strptr above.
if (! gnu && idx == strndx
&& elf_compress (scn, ELFCOMPRESS_ZLIB, 0) < 0)
{
printf ("couldn't recompress section header strings: %s\n",
elf_errmsg (-1));
return -1;
}
}
}

Expand Down
16 changes: 8 additions & 8 deletions tests/run-elfputzdata.sh
Expand Up @@ -53,7 +53,7 @@ Lets compress 29 .debug_info, size: 960
Lets compress 30 .debug_abbrev, size: 405
Lets compress 31 .debug_line, size: 189
Lets compress 32 .note, size: 240
Not compressing section string table 33
Lets compress 33 .shstrtab, size: 320
Lets compress 34 .symtab, size: 5488
Lets compress 35 .strtab, size: 5727
EOF
Expand Down Expand Up @@ -91,7 +91,7 @@ Lets compress 29 .debug_info, size: 960
Lets compress 30 .debug_abbrev, size: 405
Lets compress 31 .debug_line, size: 189
Lets compress 32 .note, size: 240
Not compressing section string table 33
Lets compress 33 .shstrtab, size: 320
Lets compress 34 .symtab, size: 5488
Lets compress 35 .strtab, size: 5727
EOF
Expand Down Expand Up @@ -130,7 +130,7 @@ Lets compress 27 .debug_line, size: 709
Lets compress 28 .debug_frame, size: 56
Lets compress 29 .debug_str, size: 2235
Lets compress 30 .debug_macinfo, size: 10518
Not compressing section string table 31
Lets compress 31 .shstrtab, size: 308
Lets compress 32 .symtab, size: 1944
Lets compress 33 .strtab, size: 757
EOF
Expand Down Expand Up @@ -166,7 +166,7 @@ Lets compress 27 .debug_line, size: 709
Lets compress 28 .debug_frame, size: 56
Lets compress 29 .debug_str, size: 2235
Lets compress 30 .debug_macinfo, size: 10518
Not compressing section string table 31
Lets compress 31 .shstrtab, size: 308
Lets compress 32 .symtab, size: 1944
Lets compress 33 .strtab, size: 757
EOF
Expand Down Expand Up @@ -208,7 +208,7 @@ Lets compress 30 .debug_frame, size: 96
Lets compress 31 .debug_str, size: 174
Lets compress 32 .debug_loc, size: 171
Lets compress 33 .debug_ranges, size: 32
Not compressing section string table 34
Lets compress 34 .shstrtab, size: 352
Lets compress 35 .symtab, size: 1800
Lets compress 36 .strtab, size: 602
EOF
Expand Down Expand Up @@ -247,7 +247,7 @@ Lets compress 30 .debug_frame, size: 96
Lets compress 31 .debug_str, size: 174
Lets compress 32 .debug_loc, size: 171
Lets compress 33 .debug_ranges, size: 32
Not compressing section string table 34
Lets compress 34 .shstrtab, size: 352
Lets compress 35 .symtab, size: 1800
Lets compress 36 .strtab, size: 602
EOF
Expand Down Expand Up @@ -291,7 +291,7 @@ Lets compress 32 .debug_frame, size: 64
Lets compress 33 .debug_str, size: 179
Lets compress 34 .debug_loc, size: 99
Lets compress 35 .debug_ranges, size: 16
Not compressing section string table 36
Lets compress 36 .shstrtab, size: 370
Lets compress 37 .symtab, size: 1232
Lets compress 38 .strtab, size: 569
EOF
Expand Down Expand Up @@ -332,7 +332,7 @@ Lets compress 32 .debug_frame, size: 64
Lets compress 33 .debug_str, size: 179
Lets compress 34 .debug_loc, size: 99
Lets compress 35 .debug_ranges, size: 16
Not compressing section string table 36
Lets compress 36 .shstrtab, size: 370
Lets compress 37 .symtab, size: 1232
Lets compress 38 .strtab, size: 569
EOF
Expand Down

0 comments on commit 519c13c

Please sign in to comment.