Bug 1273250
Summary: | Adding a new section to an ELF file SIGSEGVs and core dumps on RHEL 7 but has no issues on RHEL 6.5. The elfutils or libelf behavior are different between RHEL7 and RHEL 6.5. | ||||||
---|---|---|---|---|---|---|---|
Product: | Red Hat Enterprise Linux 7 | Reporter: | Ron <monthero.ronald> | ||||
Component: | elfutils | Assignee: | Mark Wielaard <mjw> | ||||
Status: | CLOSED NOTABUG | QA Contact: | qe-baseos-tools-bugs | ||||
Severity: | high | Docs Contact: | |||||
Priority: | unspecified | ||||||
Version: | 7.0 | CC: | adnanbajwa88, mbenitez, mjw, monthero.ronald | ||||
Target Milestone: | rc | ||||||
Target Release: | --- | ||||||
Hardware: | x86_64 | ||||||
OS: | Linux | ||||||
Whiteboard: | |||||||
Fixed In Version: | Doc Type: | Bug Fix | |||||
Doc Text: | Story Points: | --- | |||||
Clone Of: | Environment: | ||||||
Last Closed: | 2015-10-20 12:03:33 UTC | Type: | Bug | ||||
Regression: | --- | Mount Type: | --- | ||||
Documentation: | --- | CRM: | |||||
Verified Versions: | Category: | --- | |||||
oVirt Team: | --- | RHEL 7.3 requirements from Atomic Host: | |||||
Cloudforms Team: | --- | Target Upstream Version: | |||||
Embargoed: | |||||||
Attachments: |
|
Description
Ron
2015-10-20 04:06:42 UTC
Created attachment 1084583 [details]
1)My sample program to create a new section in an elf binary. Attaching my sample program eadds.c with this email )
My sample program to create a new section in an elf binary.
( Attaching my sample program eadds.c with this email )
When adding content to an existing executable ELF file you should keep the phdrs that tell where the contents of the segments are read during runtime in tact. That means either updating the phdrs after adjusting the sections (which you probably want to do anyway since you are adding an allocated sections) or (if the section you add shouldn't be allocated) you need to keep the layout of the sections exactly as they were (so the phdr offsets match). This means you should at least use elf_flagelf (elf_ref, ELF_C_SET, ELF_F_LAYOUT); (this and the other flags should be set before you call elf_update for the fist time). In that case you are responsible for setting the section sh_offset, sh_size and sh_addr_align fields. And for updating the ehdr e_shoff field to tell libelf where the section headers should be written (normally at the end of the file). In particular for your example you probably want to do something like: /* Keep track of last section offset in the file. */ GElf_Off last_offset = 0; Elf_Scn *scn = NULL; while ((scn = elf_nextscn (elf_ref, scn)) != NULL) { GElf_Shdr shdr; if (gelf_getshdr (scn, &shdr) == NULL) { printf ("gelf_getshdr failed: %s\n", elf_errmsg (-1)); close (fd); return -1; } if (shdr.sh_type != SHT_NOBITS && last_offset < shdr.sh_offset + shdr.sh_size) last_offset = shdr.sh_offset + shdr.sh_size; } /* ... */ signature_scn_header->sh_offset = last_offset; signature_scn_header->sh_size = sizeof(sample_data); signature_scn_header->sh_addralign = 1; ehdr->e_shoff = last_offset + sizeof(sample_data); elf_flagelf (elf_ref, ELF_C_SET, ELF_F_LAYOUT); /* ... */ elf_update() Please reopen this bug if the above didn't help you and you still believe there is a bug in elfutils libelf. Mark Thanks for the piece of info. I tried it a few times but the program core dumps (even on RHEL 6.5) when I use ELF_F_LAYOUT flag in elf_flagelf() instead of ELF_F_DIRTY flag. Probably I might be missing something when I tried to stitch the code with your code snippets ( and I am not too familiar with ELF but just just aware of a few ELF library calls to add a section in an ELF file) And also the difference in behavior between RHEL 6.5 and RHEL 7.0 concerns me a little. Even with my original sample program - It works fine on a RHEL 6.5 but sigsegv on RHEL 7 ( On RHEL 7 creation of section in ELF is successful with my initial sample program, but core dumps segv when its executed) It would be of much help if you have steps to stitch your code with my sample program so that it will enable me to readily test and report to you. I can test it on both RHEL 6.5 and RHEL 7.0 and get back. Thanks and Regards -Ron (In reply to Ron from comment #4) > I tried it a few times but the program core dumps (even on RHEL 6.5) when I > use ELF_F_LAYOUT flag in elf_flagelf() instead of ELF_F_DIRTY flag. You have to at least call elf_flagelf before the first elf_update. And if you do you are responsible for setting the the section sh_offset, sh_size and sh_addr_align fields and for updating the ehdr e_shoff field. > And also the difference in behavior between RHEL 6.5 and RHEL 7.0 > concerns me a little. Even with my original sample program - It works fine > on a RHEL 6.5 but sigsegv on RHEL 7 ( On RHEL 7 creation of section in ELF > is successful with my initial sample program, but core dumps segv when its > executed) I expect that it working on rhel 6.5 is just by accident. Note that the program you attached doesn't compile: $ gcc -g -Wall -o eadds -lelf eadds.c eadds.c: In function ‘main’: eadds.c:94:1: error: expected declaration or statement at end of input } ^ eadds.c:28:21: warning: unused variable ‘secname’ [-Wunused-variable] char *fnm, *secname = ".HP.wli"; ^ eadds.c:25:18: warning: unused variable ‘elf_scn’ [-Wunused-variable] Elf_Scn *elf_scn, *sig_scn; ^ eadds.c:24:21: warning: unused variable ‘ehdr’ [-Wunused-variable] Elf64_Ehdr *ehdr; ^ eadds.c:94:1: warning: control reaches end of non-void function [-Wreturn-type] } ^ Thanks for the response. Oh well I guess when u copy from the bug report the program gets mangle because of the "//" style comments and also commenting unused variables Here is the same program with /* */ style comments (instead of //) and this should compile and execute successfully on RHEL 6.5 and fail on RHEL 7 /* PROGRAM BELOW */ /* Program to add a new section to an ELF binary compile this program as gcc eadds.c -o eadds -lelf Usage : ./eadds test-elf where test-elf is your sample ELF binary or a hello world elf binary */ #include <stdio.h> #include <fcntl.h> #include <time.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <elf.h> #include <libelf.h> #include <sys/resource.h> int main(int argc, char **argv) { int fd; Elf *elf_ref = NULL; /* Elf64_Ehdr *ehdr; */ /* Elf_Scn *elf_scn; */ Elf_Scn *sig_scn; Elf_Data *elf_data; Elf64_Shdr *signature_scn_header; char *fnm; /* char *secname = ".HP.wli"; */ unsigned char sample_data[] = {0xca, 0xfe, 0xba, 0xbe, 0xca, 0xfe, 0xba, 0xbe}; if(argc != 2){ printf("\n Usage: provide a command line input file \n"); exit(-1); } fnm = argv[1]; fd = open(fnm,O_RDWR, NULL); /* Protect from using a lower ELF version and initialize ELF library */ if (elf_version(EV_CURRENT) == EV_NONE) { printf("ELF library init failed: %s\n", elf_errmsg(-1)); close(fd); return -1; } elf_ref = elf_begin(fd, ELF_C_RDWR, NULL); if (elf_kind(elf_ref) != ELF_K_ELF) { printf("Program is not an ELF binary\n"); close(fd); return -2; } sig_scn = elf_newscn(elf_ref); elf_data = elf_newdata(sig_scn); elf_data->d_align = 1; elf_data->d_off = 0LL ; elf_data->d_buf = sample_data ; elf_data->d_type = ELF_T_BYTE ; elf_data->d_size = sizeof(sample_data); elf_data->d_version = EV_CURRENT ; signature_scn_header = elf64_getshdr(sig_scn); if (signature_scn_header == NULL) { printf("ELF elf32_getshdr failed"); return -2; } /* signature_scn_header->sh_name = 1; */ signature_scn_header->sh_name = 16; signature_scn_header->sh_type = SHT_NOTE; /* signature_scn_header->sh_type = SHT_PROGBITS; */ signature_scn_header->sh_flags = SHF_ALLOC; signature_scn_header->sh_entsize = 0; if (elf_update(elf_ref , ELF_C_NULL ) < 0) { printf("ELF update failed: %s", elf_errmsg (-1)); return -3; } (void) elf_flagshdr(sig_scn, ELF_C_SET, ELF_F_DIRTY); (void) elf_flagscn(sig_scn, ELF_C_SET, ELF_F_DIRTY); (void) elf_flagdata(elf_data, ELF_C_SET, ELF_F_DIRTY); (void) elf_flagehdr(elf_ref, ELF_C_SET, ELF_F_DIRTY); (void) elf_flagelf(elf_ref, ELF_C_SET, ELF_F_DIRTY); if (elf_update(elf_ref , ELF_C_WRITE ) < 0) { printf("ELF update failed: %s", elf_errmsg (-1)); return -4; } elf_end(elf_ref); close(fd); return 0; } readelf -S testx .. [28] .symtab SYMTAB 0000000000000000 000009e0 0000000000000600 0000000000000018 29 46 8 [29] .strtab STRTAB 0000000000000000 00000fe0 00000000000001f0 0000000000000000 0 0 1 [30] NULL 0000000000000000 1000300000000 0000000000400200 000000000040021c 0 0 562962838323200 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings) I (info), L (link order), G (group), x (unknown) O (extra OS processing required) o (OS specific), p (processor specific) [root@srp-linux-7-rhel6 wli-elf]# Section 30 is the new section added. Successful program Execution after adding a new section to the elf binary. [root]# ./testx Hello Linux Users [root@srp-linux-7-rhel6 wli-elf]# Thanks for the response. Oh well I guess when u copy from the bug report the program gets mangle because of the "//" style comments and also commenting unused variables Here is the same program with /* */ style comments (instead of //) and this should compile and execute successfully on RHEL 6.5 and fail on RHEL 7 /* PROGRAM BELOW */ /* Program to add a new section to an ELF binary compile this program as gcc eadds.c -o eadds -lelf Usage : ./eadds test-elf where test-elf is your sample ELF binary or a hello world elf binary */ #include <stdio.h> #include <fcntl.h> #include <time.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <elf.h> #include <libelf.h> #include <sys/resource.h> int main(int argc, char **argv) { int fd; Elf *elf_ref = NULL; /* Elf64_Ehdr *ehdr; */ /* Elf_Scn *elf_scn; */ Elf_Scn *sig_scn; Elf_Data *elf_data; Elf64_Shdr *signature_scn_header; char *fnm; /* char *secname = ".HP.wli"; */ unsigned char sample_data[] = {0xca, 0xfe, 0xba, 0xbe, 0xca, 0xfe, 0xba, 0xbe}; if(argc != 2){ printf("\n Usage: provide a command line input file \n"); exit(-1); } fnm = argv[1]; fd = open(fnm,O_RDWR, NULL); /* Protect from using a lower ELF version and initialize ELF library */ if (elf_version(EV_CURRENT) == EV_NONE) { printf("ELF library init failed: %s\n", elf_errmsg(-1)); close(fd); return -1; } elf_ref = elf_begin(fd, ELF_C_RDWR, NULL); if (elf_kind(elf_ref) != ELF_K_ELF) { printf("Program is not an ELF binary\n"); close(fd); return -2; } sig_scn = elf_newscn(elf_ref); elf_data = elf_newdata(sig_scn); elf_data->d_align = 1; elf_data->d_off = 0LL ; elf_data->d_buf = sample_data ; elf_data->d_type = ELF_T_BYTE ; elf_data->d_size = sizeof(sample_data); elf_data->d_version = EV_CURRENT ; signature_scn_header = elf64_getshdr(sig_scn); if (signature_scn_header == NULL) { printf("ELF elf32_getshdr failed"); return -2; } /* signature_scn_header->sh_name = 1; */ signature_scn_header->sh_name = 16; signature_scn_header->sh_type = SHT_NOTE; /* signature_scn_header->sh_type = SHT_PROGBITS; */ signature_scn_header->sh_flags = SHF_ALLOC; signature_scn_header->sh_entsize = 0; if (elf_update(elf_ref , ELF_C_NULL ) < 0) { printf("ELF update failed: %s", elf_errmsg (-1)); return -3; } (void) elf_flagshdr(sig_scn, ELF_C_SET, ELF_F_DIRTY); (void) elf_flagscn(sig_scn, ELF_C_SET, ELF_F_DIRTY); (void) elf_flagdata(elf_data, ELF_C_SET, ELF_F_DIRTY); (void) elf_flagehdr(elf_ref, ELF_C_SET, ELF_F_DIRTY); (void) elf_flagelf(elf_ref, ELF_C_SET, ELF_F_DIRTY); if (elf_update(elf_ref , ELF_C_WRITE ) < 0) { printf("ELF update failed: %s", elf_errmsg (-1)); return -4; } elf_end(elf_ref); close(fd); return 0; } readelf -S testx .. [28] .symtab SYMTAB 0000000000000000 000009e0 0000000000000600 0000000000000018 29 46 8 [29] .strtab STRTAB 0000000000000000 00000fe0 00000000000001f0 0000000000000000 0 0 1 [30] NULL 0000000000000000 1000300000000 0000000000400200 000000000040021c 0 0 562962838323200 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings) I (info), L (link order), G (group), x (unknown) O (extra OS processing required) o (OS specific), p (processor specific) [root@srp-linux-7-rhel6 wli-elf]# Section 30 is the new section added. Successful program Execution after adding a new section to the elf binary. [root]# ./testx Hello Linux Users [root@srp-linux-7-rhel6 wli-elf]# (In reply to Ron from comment #1) > Created attachment 1084583 [details] > 1)My sample program to create a new section in an elf binary. Attaching my > sample program eadds.c with this email ) > > My sample program to create a new section in an elf binary. > ( Attaching my sample program eadds.c with this email i compile your program according top your instruction but at the end i received "program is not in elf binary" |