diff options
author | Roland McGrath <roland@redhat.com> | 2008-12-11 21:15:09 -0800 |
---|---|---|
committer | Roland McGrath <roland@redhat.com> | 2008-12-11 21:15:09 -0800 |
commit | 75b07c00481fa85152fed79a5c5132b09da49d32 (patch) | |
tree | e18e1c716fba824541e9c3fd3b853ded8744c7ec /libelf/elf32_updatefile.c | |
parent | 970a16636800557b21b85874c03994d5b20ebd6e (diff) | |
download | android_external_elfutils-75b07c00481fa85152fed79a5c5132b09da49d32.tar.gz android_external_elfutils-75b07c00481fa85152fed79a5c5132b09da49d32.tar.bz2 android_external_elfutils-75b07c00481fa85152fed79a5c5132b09da49d32.zip |
Don't crash in fill code when sh_offset layout is out of order.
Diffstat (limited to 'libelf/elf32_updatefile.c')
-rw-r--r-- | libelf/elf32_updatefile.c | 64 |
1 files changed, 38 insertions, 26 deletions
diff --git a/libelf/elf32_updatefile.c b/libelf/elf32_updatefile.c index e94de831..58ea7551 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 |