]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
Don't crash in fill code when sh_offset layout is out of order.
authorRoland McGrath <roland@redhat.com>
Fri, 12 Dec 2008 05:15:09 +0000 (21:15 -0800)
committerRoland McGrath <roland@redhat.com>
Fri, 12 Dec 2008 05:15:09 +0000 (21:15 -0800)
libelf/ChangeLog
libelf/elf32_updatefile.c

index 0567940bece67819beb451fed9970daced1de8d9..9578f8bde9093fd740d9b28d96177bac226a8b2b 100644 (file)
@@ -1,5 +1,11 @@
 2008-12-11  Roland McGrath  <roland@redhat.com>
 
+       * 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  <roland@redhat.com>
index e94de8318a560b01acd506c47c4d15a2ea991a8d..58ea755165835dc54650b8a717d10410b4573dfb 100644 (file)
@@ -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