Created attachment 813722 [details] The file whose bss offset have a large number *Environment cat /etc/issue Ubuntu 13.04 \n \l uname -a Linux pek-hjia-d1 3.8.0-31-generic #46-Ubuntu SMP Tue Sep 10 20:03:44 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux *Problem 1) Here is the test source code $ cat >> test.c << EOF #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include "libelf.h" int main(int argc, char *argv[]) { int fd; Elf *e; if (elf_version(EV_CURRENT) == EV_NONE) { printf ("library out of date\n"); exit (1); } if ((fd = open("test/xB.linkhuge", O_RDWR)) < 0) { printf("%s %d failed\n", __FUNCTION__, __LINE__); exit (1); } if ((e = elf_begin(fd, ELF_C_RDWR_MMAP, (Elf *) 0)) == 0) { printf("failed %s", elf_errmsg (-1)); exit (1); } elf_flagelf (e, ELF_C_SET, ELF_F_LAYOUT); elf_update(e, ELF_C_WRITE); elf_end(e); close(fd); } EOF 2) Download http://kojipkgs.fedoraproject.org/packages/elfutils/0.157/2.fc21/x86_64/elfutils-libelf-devel-static-0.157-2.fc21.x86_64.rpm to get libelf.a for debug. Download http://kojipkgs.fedoraproject.org/packages/elfutils/0.157/2.fc21/x86_64/elfutils-libelf-devel-0.157-2.fc21.x86_64.rpm to get libelf.h for debug. 3) Compile test.c with libelf.a $ gcc test.c -o test_case -static -L. -lelf 4) Prepare file whose bss offset have a large number '00200000' $ ls test/xB.linkhuge -al -rwxr-xr-x 1 jiahongxu jiahongxu 1221403 Oct 18 18:55 test/xB.linkhuge $ readelf -a xB.linkhuge ...... [Nr] Name Type Address Offset Size EntSize Flags Link Info Align skip.. [25] .data PROGBITS 00000000005128a0 001128a0 0000000000010168 0000000000000000 WA 0 0 32 [26] .bss NOBITS 0000000001000000 00200000 0000000000010050 0000000000000000 WA 0 0 32 [27] .comment PROGBITS 0000000000000000 00122a08 0000000000000011 0000000000000001 MS 0 0 1 ...... 5) Run test_case with strace, there was mmap/munmap error. $ strace ./test_case execve("./test_case", ["./test_case"], [/* 59 vars */]) = 0 uname({sys="Linux", node="pek-hjia-d1", ...}) = 0 brk(0) = 0x16a6000 brk(0x16a71c0) = 0x16a71c0 arch_prctl(ARCH_SET_FS, 0x16a6880) = 0 brk(0x16c81c0) = 0x16c81c0 brk(0x16c9000) = 0x16c9000 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) open("test/xB.linkhuge", O_RDWR) = 3 fcntl(3, F_GETFL) = 0x8002 (flags O_RDWR|O_LARGEFILE) fstat(3, {st_mode=S_IFREG|0755, st_size=1221403, ...}) = 0 mmap(NULL, 1221403, PROT_READ|PROT_WRITE, MAP_SHARED, 3, 0) = 0x7ff720fe2000 fstat(3, {st_mode=S_IFREG|0755, st_size=1221403, ...}) = 0 ftruncate(3, 2097152) = 0 msync(0x7ff720fe2000, 1216568, MS_SYNC) = 0 munmap(0x7ff720fe2000, 2097152) = 0 close(3) = 0 exit_group(0) = ? 6) $ ls test/xB.linkhuge -al -rwxr-xr-x 1 jiahongxu jiahongxu 2097152 Oct 18 19:04 test/xB.linkhuge
*Analysis 1) While ELF_C_RDWR_MMAP was used, elf_begin invoked mmap() to map file into memory with the size of '1221403'. ...strace log... mmap(NULL, 1221403, PROT_READ|PROT_WRITE, MAP_SHARED, 3, 0) = 0x7ff720fe2000 ................ 2) While 'xB.linkhuge' bss Offset has a large number '00200000', elf_update caculated file size by __elf64_updatenull_wrlock and the size was enlarged from '1221403' to '2097152' 3) In this situation, elf_update invoked ftruncate to enlarge the file, and memory size (elf->maximum_size) also was incorrectly updated. ...strace log... ftruncate(3, 2097152) ................ 4) There was segment fault in elf_end which invoked munmap with the length is the enlarged file size '2097152', not the length of mmap '1216568'. ...strace log... munmap(0x7ff720fe2000, 2097152) = 0 ................
*Solution 1) I tried to modify elf_update.c, don't update memory size (elf->maximum_size) in this situation. It fixed this issue and everything looks ok, but I am not sure the modification is necessary. ...... 11 diff --git a/libelf/elf_update.c b/libelf/elf_update.c 12 --- a/libelf/elf_update.c 13 +++ b/libelf/elf_update.c 14 @@ -120,7 +120,9 @@ write_file (Elf *elf, off_t size, int change_bo, size_t shnum) 15 size = -1; 16 } 17 18 - if (size != -1 && elf->parent == NULL) 19 + /* If the file is enlarged by truncate, we should not update maximum_size to 20 + avoid segment fault while invoking munmap in elf_end */ 21 + if (size != -1 && elf->parent == NULL && (size_t) size <= elf->maximum_size) 22 elf->maximum_size = size; ...... 2) I also tried to add check before munmap in elf_end by msync with the length of elf->maximum_size, if msync return error, munmap should not be invoked, this could avoid segment fault. --- a/libelf/elf_end.c +++ b/libelf/elf_end.c @@ -217,7 +217,10 @@ elf_end (elf) if ((elf->flags & ELF_F_MALLOCED) != 0) free (elf->map_address); else if ((elf->flags & ELF_F_MMAPPED) != 0) - munmap (elf->map_address, elf->maximum_size); + { + if (msync (elf->map_address, elf->maximum_size, MS_SYNC) == 0) + munmap (elf->map_address, elf->maximum_size); + } } 3) Any suggestion is welcomed.
*** Bug 1019707 has been marked as a duplicate of this bug. ***
This bug appears to have been reported against 'rawhide' during the Fedora 22 development cycle. Changing version to '22'. More information and reason for this action is here: https://fedoraproject.org/wiki/Fedora_Program_Management/HouseKeeping/Fedora22
Still an issue with current upstream git elfutils.
So the problem is indeed the large sh_offset of the .bss section. Since it is NOBITS the size of the section is taken into account. gabi says that a NOBITS section occupies no space in the file, and its sh_offset member locates the conceptual placement in the file. So that is why updatenull_wrlock takes the sh_offset and assumes it is inside the file (enlarging the file size) when ELF_F_LAYOUT is set. We can probably just ignore the sh_offset of any NOBITS section in updatenull (). diff --git a/libelf/elf32_updatenull.c b/libelf/elf32_updatenull.c index 5e809b7..7629502 100644 --- a/libelf/elf32_updatenull.c +++ b/libelf/elf32_updatenull.c @@ -318,9 +318,8 @@ __elfw2(LIBELFBITS,updatenull_wrlock) (Elf *elf, int *change_bop, size_t shnum) if (elf->flags & ELF_F_LAYOUT) { size = MAX ((GElf_Word) size, - shdr->sh_offset - + (shdr->sh_type != SHT_NOBITS - ? shdr->sh_size : 0)); + (shdr->sh_type != SHT_NOBITS + ? shdr->sh_offset + shdr->sh_size : 0)); /* The alignment must be a power of two. This is a requirement from the ELF specification. Additionally It seems to fix the issue. Question. What program created the xB.linkhuge ELF file in the first place? It seems it is bug to generate a .bss NOBITS section with a sh_off that is not inside the file in the first place (even if we can work around it). So maybe that generator should also be fixed?
(In reply to Mark Wielaard from comment #6) > So the problem is indeed the large sh_offset of the .bss section. > Since it is NOBITS the size of the section is taken into account. Sorry, that should have read: "Since it is NOBITS the size of the section is ignored, but the offset is taken into account."
Such files are probably created by buggy binutils ld: https://sourceware.org/bugzilla/show_bug.cgi?id=12921
Patch posted upstream: https://lists.fedorahosted.org/pipermail/elfutils-devel/2015-March/004646.html
The patch is now in elfutils git master and the bug will be fixed when elfutils 0.162 is released later this week.
elfutils-0.162-1.fc22 has been submitted as an update for Fedora 22. https://admin.fedoraproject.org/updates/elfutils-0.162-1.fc22
Package elfutils-0.162-1.fc22: * should fix your issue, * was pushed to the Fedora 22 testing repository, * should be available at your local mirror within two days. Update it with: # su -c 'yum update --enablerepo=updates-testing elfutils-0.162-1.fc22' as soon as you are able to. Please go to the following url: https://admin.fedoraproject.org/updates/FEDORA-2015-9857/elfutils-0.162-1.fc22 then log in and leave karma (feedback).
elfutils-0.163-1.fc22 has been submitted as an update for Fedora 22. https://admin.fedoraproject.org/updates/elfutils-0.163-1.fc22
elfutils-0.163-1.fc22 has been pushed to the Fedora 22 stable repository. If problems still persist, please make note of it in this bug report.
elfutils-0.163-1.fc21 has been submitted as an update for Fedora 21. https://admin.fedoraproject.org/updates/elfutils-0.163-1.fc21
elfutils-0.163-1.fc21 has been pushed to the Fedora 21 stable repository. If problems still persist, please make note of it in this bug report.