[COMMITTED] gelf_getnote: Check padding overflow.
by Mark Wielaard
Since ELF notes need to be properly aligned they can include padding.
Make sure the padding itself and the padding calculation doesn't overflow.
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
libelf/ChangeLog | 4 ++++
libelf/gelf_getnote.c | 9 +++++++--
2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/libelf/ChangeLog b/libelf/ChangeLog
index 4886093..beb431f 100644
--- a/libelf/ChangeLog
+++ b/libelf/ChangeLog
@@ -1,5 +1,9 @@
2014-11-16 Mark Wielaard <mjw(a)redhat.com>
+ * gelf_getnote.c (gelf_getnote): Check padding overflow.
+
+2014-11-16 Mark Wielaard <mjw(a)redhat.com>
+
* elf_getdata.c (__libelf_set_rawdata_wrlock): Declare offset, size
and align as Elf64_Off and Elf64_Xword not size_t.
diff --git a/libelf/gelf_getnote.c b/libelf/gelf_getnote.c
index 8bb78c1..7dc8215 100644
--- a/libelf/gelf_getnote.c
+++ b/libelf/gelf_getnote.c
@@ -73,16 +73,21 @@ gelf_getnote (data, offset, result, name_offset, desc_offset)
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 (data->d_size - offset < namesz))
+ if (unlikely (offset > data->d_size
+ || data->d_size - offset < namesz
+ || (namesz == 0 && n->n_namesz != 0)))
offset = 0;
else
{
*name_offset = offset;
offset += namesz;
- if (unlikely (data->d_size - offset < descsz))
+ if (unlikely (offset > data->d_size
+ || data->d_size - offset < descsz
+ || (descsz == 0 && n->n_descsz != 0)))
offset = 0;
else
{
--
1.8.3.1
9 years, 5 months
[COMMITTED] libelf: getdata check 64bit values correctly on 32bit arch.
by Mark Wielaard
On 32bit arches size_t is too small to do size and overflow checks
of 64bit ELF files. Use the actual Elf64 types to make sure checks
on 64bit ELF files are done correctly on 32bit arches.
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
libelf/ChangeLog | 5 +++++
libelf/elf_getdata.c | 6 +++---
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/libelf/ChangeLog b/libelf/ChangeLog
index 4fbe94c..4886093 100644
--- a/libelf/ChangeLog
+++ b/libelf/ChangeLog
@@ -1,3 +1,8 @@
+2014-11-16 Mark Wielaard <mjw(a)redhat.com>
+
+ * elf_getdata.c (__libelf_set_rawdata_wrlock): Declare offset, size
+ and align as Elf64_Off and Elf64_Xword not size_t.
+
2014-11-14 Mark Wielaard <mjw(a)redhat.com>
* gelf_getnote.c (gelf_getnote): Check offset overflow.
diff --git a/libelf/elf_getdata.c b/libelf/elf_getdata.c
index 1ce1e23..0aeb997 100644
--- a/libelf/elf_getdata.c
+++ b/libelf/elf_getdata.c
@@ -170,9 +170,9 @@ int
internal_function
__libelf_set_rawdata_wrlock (Elf_Scn *scn)
{
- size_t offset;
- size_t size;
- size_t align;
+ Elf64_Off offset;
+ Elf64_Xword size;
+ Elf64_Xword align;
int type;
Elf *elf = scn->elf;
--
1.8.3.1
9 years, 5 months
[COMMITTED] readelf: Sanity check CIE unit_length and augmentationlen in debug_frame.
by Mark Wielaard
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
src/ChangeLog | 5 +++++
src/readelf.c | 17 ++++++++++++++++-
2 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/src/ChangeLog b/src/ChangeLog
index be1d55f..7561041 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,5 +1,10 @@
2014-11-14 Mark Wielaard <mjw(a)redhat.com>
+ * readelf.c (print_debug_frame_section): Sanity Check CIE
+ unit_length and augmentationlen.
+
+2014-11-14 Mark Wielaard <mjw(a)redhat.com>
+
* readelf.c (handle_versym): Check def == NULL before use.
2014-11-08 Mark Wielaard <mjw(a)redhat.com>
diff --git a/src/readelf.c b/src/readelf.c
index 243e16e..065ee1c 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -5332,6 +5332,10 @@ print_debug_frame_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
continue;
}
+ Dwarf_Word maxsize = dataend - readp;
+ if (unlikely (unit_length > maxsize))
+ goto invalid_data;
+
unsigned int ptr_size = ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
ptrdiff_t start = readp - (unsigned char *) data->d_buf;
@@ -5413,7 +5417,11 @@ print_debug_frame_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
get_uleb128 (augmentationlen, readp);
if (augmentationlen > (size_t) (dataend - readp))
- error (1, 0, gettext ("invalid augmentation length"));
+ {
+ error (0, 0, gettext ("invalid augmentation length"));
+ readp = cieend;
+ continue;
+ }
const char *hdr = "Augmentation data:";
const char *cp = augmentation + 1;
@@ -5561,6 +5569,13 @@ print_debug_frame_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
unsigned int augmentationlen;
get_uleb128 (augmentationlen, readp);
+ if (augmentationlen > (size_t) (dataend - readp))
+ {
+ error (0, 0, gettext ("invalid augmentation length"));
+ readp = cieend;
+ continue;
+ }
+
if (augmentationlen > 0)
{
const char *hdr = "Augmentation data:";
--
1.8.3.1
9 years, 5 months
[COMMITTED] libelf: gelf_getnote check for offset overflow.
by Mark Wielaard
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
libelf/ChangeLog | 4 ++++
libelf/gelf_getnote.c | 5 +++--
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/libelf/ChangeLog b/libelf/ChangeLog
index 45e220d..4fbe94c 100644
--- a/libelf/ChangeLog
+++ b/libelf/ChangeLog
@@ -1,3 +1,7 @@
+2014-11-14 Mark Wielaard <mjw(a)redhat.com>
+
+ * gelf_getnote.c (gelf_getnote): Check offset overflow.
+
2014-11-13 Mark Wielaard <mjw(a)redhat.com>
* elf_getdata.c (__libelf_set_rawdata_wrlock): Fix unsigned overflow
diff --git a/libelf/gelf_getnote.c b/libelf/gelf_getnote.c
index 1a36855..8bb78c1 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 Red Hat, Inc.
+ Copyright (C) 2007, 2014 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -62,7 +62,8 @@ gelf_getnote (data, offset, result, name_offset, desc_offset)
/* The data is already in the correct form. Just make sure the
offset is OK. */
- if (unlikely (offset + sizeof (GElf_Nhdr) > data->d_size))
+ if (unlikely (offset > data->d_size
+ || data->d_size - offset < sizeof (GElf_Nhdr)))
{
__libelf_seterrno (ELF_E_OFFSET_RANGE);
offset = 0;
--
1.8.3.1
9 years, 5 months
[COMMITTED] libdwelf: Check the d_buf actually exists in dwelf_elf_gnu_debuglink.
by Mark Wielaard
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
libdwelf/ChangeLog | 5 +++++
libdwelf/dwelf_elf_gnu_debuglink.c | 2 +-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/libdwelf/ChangeLog b/libdwelf/ChangeLog
index 9f95ea8..342cb9c 100644
--- a/libdwelf/ChangeLog
+++ b/libdwelf/ChangeLog
@@ -1,3 +1,8 @@
+2014-11-14 Mark Wielaard <mjw(a)redhat.com>
+
+ * dwelf_elf_gnu_debuglink.c (dwelf_elf_gnu_debuglink): Check d_buf
+ is not NULL.
+
2014-04-30 Mark Wielaard <mjw(a)redhat.com>
* Makefile.am (AM_CPPFLAGS): Add libdwfl and libebl include dirs.
diff --git a/libdwelf/dwelf_elf_gnu_debuglink.c b/libdwelf/dwelf_elf_gnu_debuglink.c
index 7b5fc93..6e22cf6 100644
--- a/libdwelf/dwelf_elf_gnu_debuglink.c
+++ b/libdwelf/dwelf_elf_gnu_debuglink.c
@@ -60,7 +60,7 @@ dwelf_elf_gnu_debuglink (Elf *elf, GElf_Word *crc)
/* Found the .gnu_debuglink section. Extract its contents. */
Elf_Data *rawdata = elf_rawdata (scn, NULL);
- if (rawdata == NULL)
+ if (rawdata == NULL || rawdata->d_buf == NULL)
return NULL;
/* The CRC comes after the zero-terminated file name,
--
1.8.3.1
9 years, 5 months
[COMMITTED] libdwfl: dwfl_module_getdwarf.c don't use symtab with bogus sh_entsize.
by Mark Wielaard
Those will cause a divide by zero. We have no way to know what size the
entries are.
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
libdwfl/ChangeLog | 5 +++++
libdwfl/dwfl_module_getdwarf.c | 4 ++++
2 files changed, 9 insertions(+)
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 78314c4..22bc783 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,8 @@
+2014-11-14 Mark Wielaard <mjw(a)redhat.com>
+
+ * dwfl_module_getdwarf.c (load_symtab): Don't use tables which have
+ a zero sh_entsize.
+
2014-11-10 Mark Wielaard <mjw(a)redhat.com>
* dwfl_module_getdwarf.c (find_dynsym): New inner function
diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c
index adb94b4..a20875b 100644
--- a/libdwfl/dwfl_module_getdwarf.c
+++ b/libdwfl/dwfl_module_getdwarf.c
@@ -575,6 +575,8 @@ load_symtab (struct dwfl_file *file, struct dwfl_file **symfile,
switch (shdr->sh_type)
{
case SHT_SYMTAB:
+ if (shdr->sh_entsize == 0)
+ break;
symtab = true;
*symscn = scn;
*symfile = file;
@@ -589,6 +591,8 @@ load_symtab (struct dwfl_file *file, struct dwfl_file **symfile,
if (symtab)
break;
/* Use this if need be, but keep looking for SHT_SYMTAB. */
+ if (shdr->sh_entsize == 0)
+ break;
*symscn = scn;
*symfile = file;
*strshndx = shdr->sh_link;
--
1.8.3.1
9 years, 5 months
[PATCH] libdwfl: find_dynsym don't assume dynamic linker has adjusted DYNAMIC entries.
by Mark Wielaard
We had a regression on i686 where we failed to find the vdso symbol table
and so couldn't resolve any addresses pointing into the vdso to function
names. This was because at least on i686 we have to rely on the phdrs and
the DYNAMIC segment to locate the symbol table.
The fix look large, but ignoring whitespace it is actually pretty small:
diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c
index e705f57..adb94b4 100644
--- a/libdwfl/dwfl_module_getdwarf.c
+++ b/libdwfl/dwfl_module_getdwarf.c
@@ -718,10 +718,12 @@ find_dynsym (Dwfl_Module *mod)
break;
}
- /* Translate pointers into file offsets. */
+ /* Translate pointers into file offsets. ADJUST is either zero
+ in case the dynamic segment wasn't adjusted or mod->main_bias. */
+ void translate_offs (GElf_Addr adjust)
+ {
GElf_Off offs[i_max] = { 0, };
- find_offsets (mod->main.elf, mod->main_bias, phnum, i_max, addrs,
- offs);
+ find_offsets (mod->main.elf, adjust, phnum, i_max, addrs, offs);
/* Figure out the size of the symbol table. */
if (offs[i_hash] != 0)
@@ -824,9 +826,18 @@ find_dynsym (Dwfl_Module *mod)
mod->symfile = &mod->main;
mod->symerr = DWFL_E_NOERROR;
}
- return;
}
}
+
+ /* First try unadjusted, like ELF files from disk, vdso.
+ Then try for already adjusted dynamic section, like ELF
+ from remote memory. */
+ translate_offs (0);
+ if (mod->symfile == NULL)
+ translate_offs (mod->main_bias);
+
+ return;
+ }
}
}
<--->
commit 037505 "Fix resolving ELF symbols for live PIDs with deleted files"
changed find_dynsym to assume the PT_DYNAMIC entries had been adjusted by
the dynamic linker. That is often a correct assumption when the ELF image
comes from remote memory. But we cannot rely on that. In the case of the
vdso image the DYNAMIC segment has not been adjusted for example.
There is no good way to determine whether the DYNAMIC segment has or
hasn't been adjusted already to the load address by the dynamic linker.
So we just try twice. Once without and if the fails again with assuming
adjustments being applied.
Includes a new vdsosyms testcase that fails on i686 before and succeeds
after the fix.
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
libdwfl/ChangeLog | 6 ++
libdwfl/dwfl_module_getdwarf.c | 219 ++++++++++++++++++++++-------------------
tests/ChangeLog | 7 ++
tests/Makefile.am | 5 +-
tests/vdsosyms.c | 101 +++++++++++++++++++
5 files changed, 232 insertions(+), 106 deletions(-)
create mode 100644 tests/vdsosyms.c
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index f788f33..78314c4 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,9 @@
+2014-11-10 Mark Wielaard <mjw(a)redhat.com>
+
+ * dwfl_module_getdwarf.c (find_dynsym): New inner function
+ translate_offs that takes an adjust argument. Try finding
+ the symbol table with and without adjusting to main_bias.
+
2014-09-26 Jan Kratochvil <jan.kratochvil(a)redhat.com>
Support NT_FILE for locating files.
diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c
index e705f57..adb94b4 100644
--- a/libdwfl/dwfl_module_getdwarf.c
+++ b/libdwfl/dwfl_module_getdwarf.c
@@ -718,114 +718,125 @@ find_dynsym (Dwfl_Module *mod)
break;
}
- /* Translate pointers into file offsets. */
- GElf_Off offs[i_max] = { 0, };
- find_offsets (mod->main.elf, mod->main_bias, phnum, i_max, addrs,
- offs);
-
- /* Figure out the size of the symbol table. */
- if (offs[i_hash] != 0)
- {
- /* In the original format, .hash says the size of .dynsym. */
-
- size_t entsz = SH_ENTSIZE_HASH (ehdr);
- data = elf_getdata_rawchunk (mod->main.elf,
- offs[i_hash] + entsz, entsz,
- entsz == 4 ? ELF_T_WORD
- : ELF_T_XWORD);
- if (data != NULL)
- mod->syments = (entsz == 4
- ? *(const GElf_Word *) data->d_buf
- : *(const GElf_Xword *) data->d_buf);
- }
- if (offs[i_gnu_hash] != 0 && mod->syments == 0)
- {
- /* In the new format, we can derive it with some work. */
+ /* Translate pointers into file offsets. ADJUST is either zero
+ in case the dynamic segment wasn't adjusted or mod->main_bias. */
+ void translate_offs (GElf_Addr adjust)
+ {
+ GElf_Off offs[i_max] = { 0, };
+ find_offsets (mod->main.elf, adjust, phnum, i_max, addrs, offs);
- const struct
+ /* Figure out the size of the symbol table. */
+ if (offs[i_hash] != 0)
{
- Elf32_Word nbuckets;
- Elf32_Word symndx;
- Elf32_Word maskwords;
- Elf32_Word shift2;
- } *header;
-
- data = elf_getdata_rawchunk (mod->main.elf, offs[i_gnu_hash],
- sizeof *header, ELF_T_WORD);
- if (data != NULL)
- {
- header = data->d_buf;
- Elf32_Word nbuckets = header->nbuckets;
- Elf32_Word symndx = header->symndx;
- GElf_Off buckets_at = (offs[i_gnu_hash] + sizeof *header
- + (gelf_getclass (mod->main.elf)
- * sizeof (Elf32_Word)
- * header->maskwords));
-
- data = elf_getdata_rawchunk (mod->main.elf, buckets_at,
- nbuckets * sizeof (Elf32_Word),
- ELF_T_WORD);
- if (data != NULL && symndx < nbuckets)
- {
- const Elf32_Word *const buckets = data->d_buf;
- Elf32_Word maxndx = symndx;
- for (Elf32_Word bucket = 0; bucket < nbuckets; ++bucket)
- if (buckets[bucket] > maxndx)
- maxndx = buckets[bucket];
-
- GElf_Off hasharr_at = (buckets_at
- + nbuckets * sizeof (Elf32_Word));
- hasharr_at += (maxndx - symndx) * sizeof (Elf32_Word);
- do
- {
- data = elf_getdata_rawchunk (mod->main.elf,
- hasharr_at,
- sizeof (Elf32_Word),
- ELF_T_WORD);
- if (data != NULL
- && (*(const Elf32_Word *) data->d_buf & 1u))
- {
- mod->syments = maxndx + 1;
- break;
- }
- ++maxndx;
- hasharr_at += sizeof (Elf32_Word);
- } while (data != NULL);
- }
- }
- }
- if (offs[i_strtab] > offs[i_symtab] && mod->syments == 0)
- mod->syments = ((offs[i_strtab] - offs[i_symtab])
- / gelf_fsize (mod->main.elf,
- ELF_T_SYM, 1, EV_CURRENT));
+ /* In the original format, .hash says the size of .dynsym. */
+
+ size_t entsz = SH_ENTSIZE_HASH (ehdr);
+ data = elf_getdata_rawchunk (mod->main.elf,
+ offs[i_hash] + entsz, entsz,
+ entsz == 4 ? ELF_T_WORD
+ : ELF_T_XWORD);
+ if (data != NULL)
+ mod->syments = (entsz == 4
+ ? *(const GElf_Word *) data->d_buf
+ : *(const GElf_Xword *) data->d_buf);
+ }
+ if (offs[i_gnu_hash] != 0 && mod->syments == 0)
+ {
+ /* In the new format, we can derive it with some work. */
- if (mod->syments > 0)
- {
- mod->symdata = elf_getdata_rawchunk (mod->main.elf,
- offs[i_symtab],
- gelf_fsize (mod->main.elf,
- ELF_T_SYM,
- mod->syments,
- EV_CURRENT),
- ELF_T_SYM);
- if (mod->symdata != NULL)
- {
- mod->symstrdata = elf_getdata_rawchunk (mod->main.elf,
- offs[i_strtab],
- strsz,
- ELF_T_BYTE);
- if (mod->symstrdata == NULL)
- mod->symdata = NULL;
- }
- if (mod->symdata == NULL)
- mod->symerr = DWFL_E (LIBELF, elf_errno ());
- else
+ const struct
{
- mod->symfile = &mod->main;
- mod->symerr = DWFL_E_NOERROR;
- }
- return;
- }
+ Elf32_Word nbuckets;
+ Elf32_Word symndx;
+ Elf32_Word maskwords;
+ Elf32_Word shift2;
+ } *header;
+
+ data = elf_getdata_rawchunk (mod->main.elf, offs[i_gnu_hash],
+ sizeof *header, ELF_T_WORD);
+ if (data != NULL)
+ {
+ header = data->d_buf;
+ Elf32_Word nbuckets = header->nbuckets;
+ Elf32_Word symndx = header->symndx;
+ GElf_Off buckets_at = (offs[i_gnu_hash] + sizeof *header
+ + (gelf_getclass (mod->main.elf)
+ * sizeof (Elf32_Word)
+ * header->maskwords));
+
+ data = elf_getdata_rawchunk (mod->main.elf, buckets_at,
+ nbuckets * sizeof (Elf32_Word),
+ ELF_T_WORD);
+ if (data != NULL && symndx < nbuckets)
+ {
+ const Elf32_Word *const buckets = data->d_buf;
+ Elf32_Word maxndx = symndx;
+ for (Elf32_Word bucket = 0; bucket < nbuckets; ++bucket)
+ if (buckets[bucket] > maxndx)
+ maxndx = buckets[bucket];
+
+ GElf_Off hasharr_at = (buckets_at
+ + nbuckets * sizeof (Elf32_Word));
+ hasharr_at += (maxndx - symndx) * sizeof (Elf32_Word);
+ do
+ {
+ data = elf_getdata_rawchunk (mod->main.elf,
+ hasharr_at,
+ sizeof (Elf32_Word),
+ ELF_T_WORD);
+ if (data != NULL
+ && (*(const Elf32_Word *) data->d_buf & 1u))
+ {
+ mod->syments = maxndx + 1;
+ break;
+ }
+ ++maxndx;
+ hasharr_at += sizeof (Elf32_Word);
+ } while (data != NULL);
+ }
+ }
+ }
+ if (offs[i_strtab] > offs[i_symtab] && mod->syments == 0)
+ mod->syments = ((offs[i_strtab] - offs[i_symtab])
+ / gelf_fsize (mod->main.elf,
+ ELF_T_SYM, 1, EV_CURRENT));
+
+ if (mod->syments > 0)
+ {
+ mod->symdata = elf_getdata_rawchunk (mod->main.elf,
+ offs[i_symtab],
+ gelf_fsize (mod->main.elf,
+ ELF_T_SYM,
+ mod->syments,
+ EV_CURRENT),
+ ELF_T_SYM);
+ if (mod->symdata != NULL)
+ {
+ mod->symstrdata = elf_getdata_rawchunk (mod->main.elf,
+ offs[i_strtab],
+ strsz,
+ ELF_T_BYTE);
+ if (mod->symstrdata == NULL)
+ mod->symdata = NULL;
+ }
+ if (mod->symdata == NULL)
+ mod->symerr = DWFL_E (LIBELF, elf_errno ());
+ else
+ {
+ mod->symfile = &mod->main;
+ mod->symerr = DWFL_E_NOERROR;
+ }
+ }
+ }
+
+ /* First try unadjusted, like ELF files from disk, vdso.
+ Then try for already adjusted dynamic section, like ELF
+ from remote memory. */
+ translate_offs (0);
+ if (mod->symfile == NULL)
+ translate_offs (mod->main_bias);
+
+ return;
}
}
}
diff --git a/tests/ChangeLog b/tests/ChangeLog
index 5c06d23..a048c71 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,10 @@
+2014-11-10 Mark Wielaard <mjw(a)redhat.com>
+
+ * vdsosyms.c: New test.
+ * Makefile.am (check_PROGRAMS): Add vdsosyms.
+ (TESTS): Likewise.
+ (vdsosyms_LDADD): New variable.
+
2014-10-06 Mark Wielaard <mjw(a)redhat.com>
* run-aggregate-size.sh: Add testfile-sizes3.o test case.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 09909d2..dcaf4f6 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -50,7 +50,7 @@ check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \
test-elf_cntl_gelf_getshdr dwflsyms dwfllines \
dwfl-report-elf-align varlocs backtrace backtrace-child \
backtrace-data backtrace-dwarf debuglink debugaltlink \
- buildid deleted deleted-lib.so aggregate_size
+ buildid deleted deleted-lib.so aggregate_size vdsosyms
asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \
asm-tst6 asm-tst7 asm-tst8 asm-tst9
@@ -110,7 +110,7 @@ TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \
run-backtrace-core-aarch64.sh \
run-backtrace-demangle.sh run-stack-d-test.sh run-stack-i-test.sh \
run-readelf-dwz-multi.sh run-allfcts-multi.sh run-deleted.sh \
- run-linkmap-cut.sh run-aggregate-size.sh
+ run-linkmap-cut.sh run-aggregate-size.sh vdsosyms
if !BIARCH
export ELFUTILS_DISABLE_BIARCH = 1
@@ -415,6 +415,7 @@ deleted_LDADD = ./deleted-lib.so
deleted_lib_so_LDFLAGS = -shared -rdynamic
deleted_lib_so_CFLAGS = -fPIC
aggregate_size_LDADD = $(libdw) $(libelf)
+vdsosyms_LDADD = $(libdw) $(libelf)
if GCOV
check: check-am coverage
diff --git a/tests/vdsosyms.c b/tests/vdsosyms.c
new file mode 100644
index 0000000..831caf4
--- /dev/null
+++ b/tests/vdsosyms.c
@@ -0,0 +1,101 @@
+/* Test program for getting symbol table from vdso module.
+ Copyright (C) 2014 Red Hat, Inc.
+ This file is part of elfutils.
+
+ This file is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+#include <assert.h>
+#include <errno.h>
+#include <error.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include ELFUTILS_HEADER(dwfl)
+
+#ifndef __linux__
+int
+main (int argc __attribute__ ((unused)), char **argv)
+{
+ printf ("Getting the vdso is unsupported.\n");
+ return 77;
+}
+#else /* __linux__ */
+static bool vdso_seen = false;
+
+static int
+module_callback (Dwfl_Module *mod, void **userdata __attribute__((unused)),
+ const char *name, Dwarf_Addr start __attribute__((unused)),
+ void *arg __attribute__((unused)))
+{
+ /* We can only recognize the vdso by inspecting the "magic name". */
+ if (strncmp ("[vdso: ", name, 7) == 0)
+ {
+ int syms = dwfl_module_getsymtab (mod);
+ printf ("vdso syms: %d\n", syms);
+ if (syms < 0)
+ error (2, 0, "dwfl_module_getsymtab: %s", dwfl_errmsg (-1));
+ vdso_seen = true;
+
+ for (int i = 0; i < syms; i++)
+ {
+ GElf_Sym sym;
+ GElf_Addr addr;
+ const char *sname = dwfl_module_getsym_info (mod, i, &sym, &addr,
+ NULL, NULL, NULL);
+ assert (sname != NULL);
+ printf ("%d: '%s' %" PRIx64 " (%" PRIx64 ")\n",
+ i, sname, sym.st_value, addr);
+ }
+ }
+
+ return DWARF_CB_OK;
+}
+
+int
+main (int argc __attribute__ ((unused)), char **argv __attribute__ ((unused)))
+{
+ static char *debuginfo_path;
+ static const Dwfl_Callbacks proc_callbacks =
+ {
+ .find_debuginfo = dwfl_standard_find_debuginfo,
+ .debuginfo_path = &debuginfo_path,
+
+ .find_elf = dwfl_linux_proc_find_elf,
+ };
+ Dwfl *dwfl = dwfl_begin (&proc_callbacks);
+ if (dwfl == NULL)
+ error (2, 0, "dwfl_begin: %s", dwfl_errmsg (-1));
+
+ /* Take our parent as "arbitrary" process to inspect. */
+ pid_t pid = getppid();
+
+ int result = dwfl_linux_proc_report (dwfl, pid);
+ if (result < 0)
+ error (2, 0, "dwfl_linux_proc_report: %s", dwfl_errmsg (-1));
+ else if (result > 0)
+ error (2, result, "dwfl_linux_proc_report");
+
+ if (dwfl_report_end (dwfl, NULL, NULL) != 0)
+ error (2, 0, "dwfl_report_end: %s", dwfl_errmsg (-1));
+
+ if (dwfl_getmodules (dwfl, module_callback, NULL, 0) != 0)
+ error (1, 0, "dwfl_getmodules: %s", dwfl_errmsg (-1));
+
+ return vdso_seen ? 0 : -1;
+}
+
+#endif /* ! __linux__ */
--
1.8.3.1
9 years, 5 months
[COMMITTED] readelf: Check def == NULL before use in handle_versym.
by Mark Wielaard
Don't use def if NULL. Move check earlier.
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
src/ChangeLog | 4 ++++
src/readelf.c | 5 ++++-
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/src/ChangeLog b/src/ChangeLog
index 6d3e951..be1d55f 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,7 @@
+2014-11-14 Mark Wielaard <mjw(a)redhat.com>
+
+ * readelf.c (handle_versym): Check def == NULL before use.
+
2014-11-08 Mark Wielaard <mjw(a)redhat.com>
* readelf.c (handle_versym): Initialize vername and filename array
diff --git a/src/readelf.c b/src/readelf.c
index 01c644f..243e16e 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -2744,11 +2744,14 @@ handle_versym (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
/* Get the data at the next offset. */
GElf_Verdef defmem;
GElf_Verdef *def = gelf_getverdef (defdata, offset, &defmem);
+ if (unlikely (def == NULL))
+ break;
+
GElf_Verdaux auxmem;
GElf_Verdaux *aux = gelf_getverdaux (defdata,
offset + def->vd_aux,
&auxmem);
- if (unlikely (def == NULL || aux == NULL))
+ if (unlikely (aux == NULL))
break;
vername[def->vd_ndx & 0x7fff]
--
1.8.3.1
9 years, 5 months
out-of-bounds read / crash in elfutils tools (readelf, nm, ...) with malformed file
by Hanno Böck
Hi,
Attached is a file that's a fuzzed elf executable which will crash
various tools shipped with elfutils, I tried it with nm and readelf -a,
maybe others affected.
What puzzles me a bit is that valgrin suggests nm and readelf crash at
different code paths. Both times its a one byte out of bounds read.
(actually this bug report is kind of a fallout of a bug search in
libbfd - various parser bugs in the binutils-tools have been found and
fixed in the past days and I thought I'd run other elf-related tools on
the collection of bug-exposing binaries)
I tested it both with 0.160 and latest git code.
Here's the valgrind output for nm:
==20828== Invalid read of size 1
==20828== at 0x4C2C4D2: strlen
(in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so) ==20828==
by 0x40346D: show_symbols (nm.c:1264) ==20828== by 0x4047AC:
handle_elf (nm.c:1485) ==20828== by 0x404E32: process_file (nm.c:391)
==20828== by 0x40247E: main (nm.c:252)
==20828== Address 0x4043dac is not stack'd, malloc'd or (recently)
free'd ==20828==
==20828==
==20828== Process terminating with default action of signal 11 (SIGSEGV)
==20828== Access not within mapped region at address 0x4043DAC
==20828== at 0x4C2C4D2: strlen
(in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so) ==20828==
by 0x40346D: show_symbols (nm.c:1264) ==20828== by 0x4047AC:
handle_elf (nm.c:1485) ==20828== by 0x404E32: process_file (nm.c:391)
==20828== by 0x40247E: main (nm.c:252)
Here for readelf -a:
==20829== Invalid read of size 1
==20829== at 0x54DA9A7: vfprintf (in /lib64/libc-2.19.so)
==20829== by 0x558737F: __printf_chk (in /lib64/libc-2.19.so)
==20829== by 0x4057E6: printf (stdio2.h:104)
==20829== by 0x4057E6: handle_symtab (readelf.c:2245)
==20829== by 0x4057E6: print_symtab (readelf.c:2139)
==20829== by 0x40F26E: process_elf_file (readelf.c:887)
==20829== by 0x411735: process_dwflmod (readelf.c:691)
==20829== by 0x4E52620: dwfl_getmodules
(in /usr/lib64/libdw-0.160.so) ==20829== by 0x408024: process_file
(readelf.c:790) ==20829== by 0x403D93: main (readelf.c:296)
==20829== Address 0x4043dac is not stack'd, malloc'd or (recently)
free'd ==20829==
==20829==
==20829== Process terminating with default action of signal 11 (SIGSEGV)
==20829== Access not within mapped region at address 0x4043DAC
==20829== at 0x54DA9A7: vfprintf (in /lib64/libc-2.19.so)
==20829== by 0x558737F: __printf_chk (in /lib64/libc-2.19.so)
==20829== by 0x4057E6: printf (stdio2.h:104)
==20829== by 0x4057E6: handle_symtab (readelf.c:2245)
==20829== by 0x4057E6: print_symtab (readelf.c:2139)
==20829== by 0x40F26E: process_elf_file (readelf.c:887)
==20829== by 0x411735: process_dwflmod (readelf.c:691)
==20829== by 0x4E52620: dwfl_getmodules
(in /usr/lib64/libdw-0.160.so) ==20829== by 0x408024: process_file
(readelf.c:790) ==20829== by 0x403D93: main (readelf.c:296)
cu,
--
Hanno Böck
http://hboeck.de/
mail/jabber: hanno(a)hboeck.de
GPG: BBB51E42
9 years, 5 months
[PATCH] libelf: Use mempcpy not __mempcpy.
by Mark Wielaard
We were using mempcpy everywhere else, only __libelf_next_arhdr_wrlock used
__mempcpy.
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
libelf/ChangeLog | 4 ++++
libelf/elf_begin.c | 4 ++--
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/libelf/ChangeLog b/libelf/ChangeLog
index dd0a755..a9d8c6f 100644
--- a/libelf/ChangeLog
+++ b/libelf/ChangeLog
@@ -1,3 +1,7 @@
+2014-11-08 Mark Wielaard <mjw(a)redhat.com>
+
+ * elf_begin.c (__libelf_next_arhdr_wrlock): Use mempcpy not __mempcpy.
+
2014-11-07 Mark Wielaard <mjw(a)redhat.com>
* elf_begin.c (file_read_elf): Correct sh_size check.
diff --git a/libelf/elf_begin.c b/libelf/elf_begin.c
index 5525a3b..d135dea 100644
--- a/libelf/elf_begin.c
+++ b/libelf/elf_begin.c
@@ -799,7 +799,7 @@ __libelf_next_arhdr_wrlock (elf)
}
/* Copy the raw name over to a NUL terminated buffer. */
- *((char *) __mempcpy (elf->state.ar.raw_name, ar_hdr->ar_name, 16)) = '\0';
+ *((char *) mempcpy (elf->state.ar.raw_name, ar_hdr->ar_name, 16)) = '\0';
elf_ar_hdr = &elf->state.ar.elf_ar_hdr;
@@ -895,7 +895,7 @@ __libelf_next_arhdr_wrlock (elf)
const char *string = ar_hdr->FIELD; \
if (ar_hdr->FIELD[sizeof (ar_hdr->FIELD) - 1] != ' ') \
{ \
- *((char *) __mempcpy (buf, ar_hdr->FIELD, sizeof (ar_hdr->FIELD))) \
+ *((char *) mempcpy (buf, ar_hdr->FIELD, sizeof (ar_hdr->FIELD))) \
= '\0'; \
string = buf; \
} \
--
1.9.3
9 years, 5 months