From: Ulrich Drepper Date: Tue, 4 Apr 2006 21:07:28 +0000 (+0000) Subject: Fix read/write of existing file using mmap and different layout of the ELF X-Git-Tag: elfutils-0.120~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=697d8d283e5fda32c1930135ff884dd276499e4a;p=thirdparty%2Felfutils.git Fix read/write of existing file using mmap and different layout of the ELF file. --- diff --git a/libelf/ChangeLog b/libelf/ChangeLog index 2714ff34e..c69b3d392 100644 --- a/libelf/ChangeLog +++ b/libelf/ChangeLog @@ -1,3 +1,16 @@ +2006-04-04 Ulrich Drepper + + * elf32_updatefile.c (updatemmap): Cleanups. Remove shdr_dest + variable. Before writing sections, make a copy of the section + header data if necessary. Don't write section header while + writing the section constent, it might overwrite some sections. + Restore the pointer afterwards. + * elf32_updatenull.c (updatenull): If the offset of a section in a + file changed make sure we read the section so that it'll be written + out. + + * elf_update.c: Remove debug message. + 2005-12-07 Roland McGrath * gelf_xlate.c [! ALLOW_UNALIGNED] (union unaligned): New type. diff --git a/libelf/elf32_updatefile.c b/libelf/elf32_updatefile.c index 260fb3468..906989746 100644 --- a/libelf/elf32_updatefile.c +++ b/libelf/elf32_updatefile.c @@ -1,5 +1,5 @@ /* Write changed data structures. - Copyright (C) 2000, 2001, 2002, 2004, 2005 Red Hat, Inc. + Copyright (C) 2000, 2001, 2002, 2004, 2005, 2006 Red Hat, Inc. Written by Ulrich Drepper , 2000. This program is free software; you can redistribute it and/or modify @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -82,7 +83,6 @@ internal_function_def __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum) { ElfW2(LIBELFBITS,Ehdr) *ehdr; - xfct_t fctp; char *last_position; /* We need the ELF header several times. */ @@ -100,6 +100,7 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum) { /* Today there is only one version of the ELF header. */ #if EV_NUM != 2 + xfct_t fctp; fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]; #else # undef fctp @@ -137,6 +138,7 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum) { /* Today there is only one version of the ELF header. */ #if EV_NUM != 2 + xfct_t fctp; fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]; #else # undef fctp @@ -166,12 +168,11 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum) /* Write all the sections. Well, only those which are modified. */ if (shnum > 0) { - ElfW2(LIBELFBITS,Shdr) *shdr_dest; Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns; Elf_Scn **scns = (Elf_Scn **) alloca (shnum * sizeof (Elf_Scn *)); - char *shdr_start = ((char *) elf->map_address + elf->start_offset - + ehdr->e_shoff); - char *shdr_end = shdr_start + ehdr->e_shnum * ehdr->e_shentsize; + char *const shdr_start = ((char *) elf->map_address + elf->start_offset + + ehdr->e_shoff); + char *const shdr_end = shdr_start + ehdr->e_shnum * ehdr->e_shentsize; #if EV_NUM != 2 xfct_t shdr_fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]; @@ -179,26 +180,43 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum) # undef shdr_fctp # define shdr_fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR] #endif - shdr_dest = (ElfW2(LIBELFBITS,Shdr) *) - ((char *) elf->map_address + elf->start_offset + ehdr->e_shoff); +#define shdr_dest ((ElfW2(LIBELFBITS,Shdr) *) shdr_start) /* Get all sections into the array and sort them. */ sort_sections (scns, list); + /* We possibly have to copy the section header data because moving + the sections might overwrite the data. */ + for (size_t cnt = 0; cnt < shnum; ++cnt) + { + Elf_Scn *scn = scns[cnt]; + + if ((scn->shdr_flags & ELF_F_MALLOCED) == 0 + && scn->shdr.ELFW(e,LIBELFBITS) != &shdr_dest[scn->index]) + { + assert ((char *) elf->map_address + elf->start_offset + < (char *) scn->shdr.ELFW(e,LIBELFBITS)); + assert ((char *) scn->shdr.ELFW(e,LIBELFBITS) + < (char *) elf->map_address + elf->maximum_size); + + void *p = alloca (sizeof (ElfW2(LIBELFBITS,Shdr))); + scn->shdr.ELFW(e,LIBELFBITS) + = memcpy (p, scn->shdr.ELFW(e,LIBELFBITS), + sizeof (ElfW2(LIBELFBITS,Shdr))); + } + } + /* Iterate over all the section in the order in which they appear in the output file. */ for (size_t cnt = 0; cnt < shnum; ++cnt) { Elf_Scn *scn = scns[cnt]; - ElfW2(LIBELFBITS,Shdr) *shdr; - char *scn_start; - Elf_Data_List *dl; - shdr = scn->shdr.ELFW(e,LIBELFBITS); + ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS); - scn_start = ((char *) elf->map_address - + elf->start_offset + shdr->sh_offset); - dl = &scn->data_list; + char *scn_start = ((char *) elf->map_address + + elf->start_offset + shdr->sh_offset); + Elf_Data_List *dl = &scn->data_list; if (shdr->sh_type != SHT_NOBITS && scn->data_list_rear != NULL) do @@ -236,10 +254,11 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum) if (unlikely (change_bo)) { #if EV_NUM != 2 + xfct_t fctp; fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]; #else # undef fctp - fctp = __elf_xfctstom[0][0][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]; +# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type] #endif /* Do the real work. */ @@ -265,7 +284,23 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum) /* We have to trust the existing section header information. */ last_position += shdr->sh_size; - /* Write the section header table entry if necessary. */ + scn->flags &= ~ELF_F_DIRTY; + } + + /* Fill the gap between last section and section header table if + necessary. */ + if ((elf->flags & ELF_F_DIRTY) + && last_position < ((char *) elf->map_address + elf->start_offset + + ehdr->e_shoff)) + memset (last_position, __libelf_fill_byte, + (char *) elf->map_address + elf->start_offset + ehdr->e_shoff + - last_position); + + /* Write the section header table entry if necessary. */ + for (size_t cnt = 0; cnt < shnum; ++cnt) + { + Elf_Scn *scn = scns[cnt]; + if ((scn->shdr_flags | elf->flags) & ELF_F_DIRTY) { if (unlikely (change_bo)) @@ -277,25 +312,28 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum) scn->shdr.ELFW(e,LIBELFBITS), sizeof (ElfW2(LIBELFBITS,Shdr))); + /* If we previously made a copy of the section header + entry we now have to adjust the pointer again so + point to new place in the mapping. */ + if ((scn->shdr_flags & ELF_F_MALLOCED) == 0) + scn->shdr.ELFW(e,LIBELFBITS) = &shdr_dest[scn->index]; + scn->shdr_flags &= ~ELF_F_DIRTY; } - - scn->flags &= ~ELF_F_DIRTY; } - - /* Fill the gap between last section and section header table if - necessary. */ - if ((elf->flags & ELF_F_DIRTY) - && last_position < ((char *) elf->map_address + elf->start_offset - + ehdr->e_shoff)) - memset (last_position, __libelf_fill_byte, - (char *) elf->map_address + elf->start_offset + ehdr->e_shoff - - last_position); } /* That was the last part. Clear the overall flag. */ elf->flags &= ~ELF_F_DIRTY; + /* Make sure the content hits the disk. */ + char *msync_start = ((char *) elf->map_address + + elf->start_offset / sysconf (_SC_PAGESIZE)); + char *msync_end = ((char *) elf->map_address + + elf->start_offset + ehdr->e_shoff + * ehdr->e_shentsize * shnum); + (void) msync (msync_start, msync_end - msync_start, MS_SYNC); + return 0; } @@ -349,7 +387,6 @@ __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum) { char fillbuf[FILLBUFSIZE]; size_t filled = 0; - xfct_t fctp; /* We need the ELF header several times. */ ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr; @@ -369,6 +406,7 @@ __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum) { /* Today there is only one version of the ELF header. */ #if EV_NUM != 2 + xfct_t fctp; fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]; #else # undef fctp @@ -419,6 +457,7 @@ __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum) { /* Today there is only one version of the ELF header. */ #if EV_NUM != 2 + xfct_t fctp; fctp = __elf_xfctstom[__libelf_version - 1][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]; #else # undef fctp @@ -525,10 +564,11 @@ __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum) if (unlikely (change_bo)) { #if EV_NUM != 2 + xfct_t fctp; fctp = __elf_xfctstom[__libelf_version - 1][dl->data.d.d_version - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]; #else # undef fctp - fctp = __elf_xfctstom[0][0][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]; +# define fctp __elf_xfctstom[0][EV_CURRENT - 1][ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type] #endif buf = tmpbuf; diff --git a/libelf/elf32_updatenull.c b/libelf/elf32_updatenull.c index ed7242b24..9c61cd777 100644 --- a/libelf/elf32_updatenull.c +++ b/libelf/elf32_updatenull.c @@ -1,5 +1,5 @@ /* Update data structures for changes. - Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006 Red Hat, Inc. Written by Ulrich Drepper , 2000. This program is free software; you can redistribute it and/or modify @@ -319,8 +319,18 @@ __elfw2(LIBELFBITS,updatenull) (Elf *elf, int *change_bop, size_t shnum) scn->shdr_flags); size = (size + sh_align - 1) & ~(sh_align - 1); + int offset_changed = 0; update_if_changed (shdr->sh_offset, (GElf_Word) size, - changed); + offset_changed); + changed |= offset_changed; + + if (offset_changed && scn->data_list_rear == NULL) + { + /* The position of the section in the file + changed. Create the section data list. */ + if (INTUSE(elf_getdata) (scn, NULL) == NULL) + return -1; + } /* See whether the section size is correct. */ update_if_changed (shdr->sh_size, (GElf_Word) offset, diff --git a/libelf/elf_update.c b/libelf/elf_update.c index f380e2b9d..ee1760d42 100644 --- a/libelf/elf_update.c +++ b/libelf/elf_update.c @@ -1,5 +1,5 @@ /* Update data structures for changes and write them out. - Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005 Red Hat, Inc. + Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2006 Red Hat, Inc. Contributed by Ulrich Drepper , 1999. This program is free software; you can redistribute it and/or modify @@ -181,15 +181,7 @@ elf_update (elf, cmd) size = -1; } else - { - if (elf->parent != NULL) - { - extern int puts (const char *); - puts ("this is an archive member"); - } - - size = write_file (elf, size, change_bo, shnum); - } + size = write_file (elf, size, change_bo, shnum); } out: