From 75b07c00481fa85152fed79a5c5132b09da49d32 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Thu, 11 Dec 2008 21:15:09 -0800 Subject: [PATCH] Don't crash in fill code when sh_offset layout is out of order. --- libelf/ChangeLog | 6 ++++ libelf/elf32_updatefile.c | 64 +++++++++++++++++++++++---------------- 2 files changed, 44 insertions(+), 26 deletions(-) diff --git a/libelf/ChangeLog b/libelf/ChangeLog index 0567940be..9578f8bde 100644 --- a/libelf/ChangeLog +++ b/libelf/ChangeLog @@ -1,5 +1,11 @@ 2008-12-11 Roland McGrath + * elf32_updatefile.c (__elfw2(LIBELFBITS,updatemmap)): Handle + placement offset going backwards, for out-of-order or overlapping + (bogus) sh_offset layouts. It's a dumb use, but should not crash. + (__elfw2(LIBELFBITS,updatefile)): Likewise. + Fixes RHBZ#476136. + * libelf.h (Elf_Data): Whitespace fix. 2008-12-10 Roland McGrath diff --git a/libelf/elf32_updatefile.c b/libelf/elf32_updatefile.c index e94de8318..58ea75516 100644 --- a/libelf/elf32_updatefile.c +++ b/libelf/elf32_updatefile.c @@ -293,36 +293,43 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum) if (shdr->sh_type != SHT_NOBITS && scn->data_list_rear != NULL) do { + assert (dl->data.d.d_off >= 0); + assert ((GElf_Off) dl->data.d.d_off <= shdr->sh_size); + assert (dl->data.d.d_size <= (shdr->sh_size + - (GElf_Off) dl->data.d.d_off)); + if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY) { - if (scn_start + dl->data.d.d_off != last_position) + if (scn_start + dl->data.d.d_off > last_position) { - if (scn_start + dl->data.d.d_off > last_position) - { - /* This code assumes that the data blocks for - a section are ordered by offset. */ - size_t written = 0; + /* This code assumes that the data blocks for + a section are ordered by offset. */ + size_t written = 0; - if (last_position < shdr_start) - { - written = MIN (scn_start + dl->data.d.d_off - - last_position, - shdr_start - last_position); + if (last_position < shdr_start) + { + written = MIN (scn_start + dl->data.d.d_off + - last_position, + shdr_start - last_position); - memset (last_position, __libelf_fill_byte, - written); - } + memset (last_position, __libelf_fill_byte, + written); + } - if (last_position + written - != scn_start + dl->data.d.d_off - && shdr_end < scn_start + dl->data.d.d_off) - memset (shdr_end, __libelf_fill_byte, - scn_start + dl->data.d.d_off - shdr_end); + if (last_position + written + != scn_start + dl->data.d.d_off + && shdr_end < scn_start + dl->data.d.d_off) + memset (shdr_end, __libelf_fill_byte, + scn_start + dl->data.d.d_off - shdr_end); - last_position = scn_start + dl->data.d.d_off; - } } + /* Let it go backward if the sections are not + presented in layout order, or use a bogus + layout (overlaps, etc.). */ + + last_position = scn_start + dl->data.d.d_off; + if (unlikely (change_bo)) { #if EV_NUM != 2 @@ -347,6 +354,9 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum) else last_position += dl->data.d.d_size; + assert (scn_start + dl->data.d.d_off + dl->data.d.d_size + == last_position); + dl->flags &= ~ELF_F_DIRTY; dl = dl->next; @@ -621,19 +631,21 @@ __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum) char tmpbuf[MAX_TMPBUF]; void *buf = dl->data.d.d_buf; - if (scn_start + dl->data.d.d_off != last_offset) + if (scn_start + dl->data.d.d_off > last_offset) { - assert (last_offset < scn_start + dl->data.d.d_off); - if (unlikely (fill (elf->fildes, last_offset, (scn_start + dl->data.d.d_off) - last_offset, fillbuf, &filled) != 0)) return 1; - - last_offset = scn_start + dl->data.d.d_off; } + /* Let it go backward if the sections are not + presented in layout order, or use a bogus + layout (overlaps, etc.). */ + + last_offset = scn_start + dl->data.d.d_off; + if (unlikely (change_bo)) { #if EV_NUM != 2 -- 2.47.2