summaryrefslogtreecommitdiffstats
path: root/libelf/elf32_updatefile.c
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2008-12-11 21:15:09 -0800
committerRoland McGrath <roland@redhat.com>2008-12-11 21:15:09 -0800
commit75b07c00481fa85152fed79a5c5132b09da49d32 (patch)
treee18e1c716fba824541e9c3fd3b853ded8744c7ec /libelf/elf32_updatefile.c
parent970a16636800557b21b85874c03994d5b20ebd6e (diff)
downloadandroid_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.c64
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