Cont.: Adding a new section to an ELF file aborts with Assertion `shdr != NULL'

P.B. poundbang@gmail.com
Fri Dec 24 20:42:05 GMT 2021


Hi,

Sorry I for some reason could not reply to the original thread here to
follow up:
https://www.mail-archive.com/elfutils-devel@sourceware.org/msg04076.html

But I am facing the same issue, adding the section to a very simple ELF
file fails with  Assertion `shdr != NULL'. I am new to this so I am sure I
am doing something wrong, but not exactly certain what it is. I have also
tried to open ELF with ELF_C_WRITE as opposed to ELF_C_RDWR but then my
error is "elf_newdata() failed: executable header not created first" so I
am not sure what the proper sequence of events would be to add a section.

Below is my code and a run with the message.
Thank you!


Elfutils 0.186-1  - Debian testing

============= sample test.c I want to add a section to
=========================
#include <stdio.h>

int main(int argc, char **argv){
        printf("Hello world");
        return 0;
}

=========== test.c ELF Sections before adding section ===========
(Intel x86-64)
Program header table entries: 11 (40 - 2A8)
 0 P r--    40   268 00000040       6 D rw-  2DF8   1E0 00003DF8
 1 I "/lib64/ld-linux-x86-64.so.2"  7 N "GNU"
 2 B r--     0   568 00000000       8 U r--  2010    3C 00002010
 3 B r-s  1000   1DD 00001000       9 . rw-     0     0 00000000
 4 B r--  2000   158 00002000      10 R r--  2DE8   218 00003DE8
 5 B rw-  2DE8   248 00003DE8 +8
Section header table entries: 30 (3728 - 3EA8)
 0 (null)                               15 B r-x  11D4     9 .fini
 1 I "/lib64/ld-linux-x86-64.so.2"      16 B r--  2000    10 .rodata
 2 N "GNU"                              17 U r--  2010    3C .eh_frame_hdr
 3 N "GNU"                              18 U r--  2050   108 .eh_frame
 4 H r--   308    24 .gnu.hash [5]      19 ? rw-  2DE8     8 .init_array
 5 S r--   330    A8 .dynsym [6]        20 ? rw-  2DF0     8 .fini_array
 6 $ r--   3D8    84 .dynstr            21 D rw-  2DF8   1E0 .dynamic [6]
 7 V r--   45C     E .gnu.version [5]   22 O rw-  2FD8    28 .got
 8 V r--   470    20 .gnu.version_r [6] 23 P rw-  3000    20 .got.plt
 9 R r--   490    C0 .rela.dyn:0 [5]    24 B rw-  3020    10 .data
10 R r--   550    18 .rela.plt:23 [5]   25 0 rw-  3030     8 .bss
11 B r-x  1000    17 .init              26 C "GCC: (Debian 11.2.0-10)
11.2.0"
12 P r-x  1020    20 .plt               27 S ---  3050   3C0 .symtab [28]
13 B r-x  1040     8 .plt.got           28 $ ---  3410   210 .strtab
14 B r-x  1050   181 .text              29 $ ---  3620   107 .shstrtab [S]


============= add_section.c ===========================

int main(int argc, char **argv) {
    // Parameters
    char *bin_path = NULL;
    char *data_file = NULL;
    char *section_name = NULL;

    // Elf section and data
    unsigned char *section_data_raw = NULL; // Section Data buffer content
    int fd = -1;                   // File descriptor for the ELF file
    Elf *e = NULL;                 // ELF struct
    Elf64_Addr sec_start_addr = 0; // Section Start Address
    Elf64_Xword sec_sz = 0;        // Section size
    uint64_t sec_data_offset = 0;  // Data Offset from start of section
    size_t sec_data_sz = 0;        // Date size

    Elf_Scn *scn;
    Elf_Data *data;
    Elf64_Shdr *shdr;
    size_t scn_idx;
    off_t fsize = -1;

    if (argc < 4) {
        printf("secinject <file> <section> <data_file>\n");
        exit(EXIT_FAILURE);
    }

    if (check_bin_path(argv[1], &bin_path) == FALSE) {
        err(EXIT_FAILURE, "RW Access to \"%s\" failed", argv[1]);
    }

    section_name = argv[2];

    if (check_data_path(argv[3], &data_file) == FALSE) {
        err(EXIT_FAILURE, "Read Access to \"%s\" failed", argv[3]);
    }
    ssize_t nread = read_file_to_buffer(data_file, &section_data_raw);

    if (elf_version(EV_CURRENT) == EV_NONE)
        errx(EXIT_FAILURE, "ELF library initialization failed: %s",
elf_errmsg(-1));

    // Open file rw
    if ((fd = open(argv[1], O_RDWR, 0)) < 0)
        err(EXIT_FAILURE, "open \"%s\" RW failed", bin_path);

    // Open ELF readwrite
    if ((e = elf_begin(fd, ELF_C_RDWR, NULL)) == NULL)
        errx(EXIT_FAILURE, "elf_begin() failed: %s.", elf_errmsg(-1));


    // 2. Create new section
    if ((scn = elf_newscn(e)) == NULL)
        errx(EXIT_FAILURE, "elf_newscn() failed: %s.", elf_errmsg(-1));

    if ((data = elf_newdata(scn)) == NULL)
        errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
             elf_errmsg(-1));

    data->d_align = 4;
    data->d_buf = section_data_raw;
    data->d_off = 0LL;
    data->d_size = nread;
    data->d_type = ELF_T_DYN;
    data->d_version = EV_CURRENT;


    scn_idx = elf_ndxscn(scn);
    printf("New Section index: %zu\n", scn_idx);

    scn = elf_getscn(e, scn_idx);
    if ((shdr = elf64_getshdr(scn)) == NULL ){
        err(EXIT_FAILURE, "elf64_getshdr() failed: %s.",
             elf_errmsg(-1));
    }

    shdr->sh_name = scn_idx;
    shdr->sh_type = SHT_PROGBITS;
    shdr->sh_flags = SHF_ALLOC | SHF_WRITE;
    shdr->sh_entsize = 0;

    if (elf_update(e , ELF_C_NULL ) < 0) {
        err(EXIT_FAILURE, "elf_update() failed: %s.",
            elf_errmsg(-1));
    }

    (void) elf_flagshdr(scn, ELF_C_SET, ELF_F_DIRTY);
    (void) elf_flagscn(scn, ELF_C_SET, ELF_F_DIRTY);
    (void) elf_flagdata(data, ELF_C_SET, ELF_F_DIRTY);
    (void) elf_flagehdr(e, ELF_C_SET, ELF_F_DIRTY);
    (void) elf_flagelf(e, ELF_C_SET, ELF_F_DIRTY);

    if (elf_update(e, ELF_C_WRITE ) < 0) {
        err(EXIT_FAILURE, "elf_update() failed: %s.",
            elf_errmsg(-1));
    }

    if (e != NULL)
        elf_end(e);

    if (fd != -1)
        close(fd);

    exit(EXIT_SUCCESS);
}


=============  Run ======================


New Section index: 30
secinject: elf32_updatenull.c:214: __elf64_updatenull_wrlock: Assertion
`shdr != NULL' failed.
Aborted

=========== GDB shdr check =================

Breakpoint 1, main (argc=4, argv=0x7ffe136cb9e8) at secinject.c:86
86    if (elf_update(e , ELF_C_NULL ) < 0) {

(gdb) p scn
$1 = (Elf_Scn *) 0x55799dbd6510
(gdb) p shdr
$2 = (Elf64_Shdr *) 0x55799dbd7560
(gdb) p e
$3 = (Elf *) 0x55799dbd46b0
(gdb) p shdr->sh_name
$4 = 36



========== Error in: elfutils-0.183/libelf/elf32_updatenull.c: 214:
 ========
/* Load the section headers if necessary.  This loads the
         headers for all sections.  */
      if (scn1 != NULL && scn1->shdr.ELFW(e,LIBELFBITS) == NULL)
        (void) __elfw2(LIBELFBITS,getshdr_wrlock) (scn1);

      do
        {
          for (size_t cnt = first == true; cnt < list->cnt; ++cnt)
            {
              Elf_Scn *scn = &list->data[cnt];
              ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
              int64_t offset = 0;

 214:         assert (shdr != NULL);
              ElfW2(LIBELFBITS,SizeWord) sh_entsize = shdr->sh_entsize;
              ElfW2(LIBELFBITS,SizeWord) sh_align = shdr->sh_addralign ?: 1;


More information about the Elfutils-devel mailing list