Blame tests/addsections.c

Packit 032894
/* Test program for adding (more than SHN_LORESERVE) sections.
Packit 032894
   Copyright (C) 2018 Red Hat, Inc.
Packit 032894
   This file is part of elfutils.
Packit 032894
Packit 032894
   This file is free software; you can redistribute it and/or modify
Packit 032894
   it under the terms of the GNU General Public License as published by
Packit 032894
   the Free Software Foundation; either version 3 of the License, or
Packit 032894
   (at your option) any later version.
Packit 032894
Packit 032894
   elfutils is distributed in the hope that it will be useful, but
Packit 032894
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 032894
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 032894
   GNU General Public License for more details.
Packit 032894
Packit 032894
   You should have received a copy of the GNU General Public License
Packit 032894
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit 032894
Packit 032894
Packit 032894
#ifdef HAVE_CONFIG_H
Packit 032894
# include <config.h>
Packit 032894
#endif
Packit 032894
Packit 032894
#include <errno.h>
Packit 032894
#include <fcntl.h>
Packit 032894
#include <inttypes.h>
Packit 032894
#include <stdbool.h>
Packit 032894
#include <stdio.h>
Packit 032894
#include <stdlib.h>
Packit 032894
#include <string.h>
Packit 032894
#include <unistd.h>
Packit 032894
#include <sys/types.h>
Packit 032894
#include <sys/stat.h>
Packit 032894
Packit 032894
#include ELFUTILS_HEADER(elf)
Packit 032894
#include <gelf.h>
Packit 032894
Packit 032894
Packit 032894
/* shstrndx is special, might overflow into section zero header sh_link.  */
Packit 032894
static int
Packit 032894
setshstrndx (Elf *elf, size_t ndx)
Packit 032894
{
Packit 032894
  printf ("setshstrndx: %zd\n", ndx);
Packit 032894
Packit 032894
  GElf_Ehdr ehdr_mem;
Packit 032894
  GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
Packit 032894
  if (ehdr == NULL)
Packit 032894
    return -1;
Packit 032894
Packit 032894
  if (ndx < SHN_LORESERVE)
Packit 032894
    ehdr->e_shstrndx = ndx;
Packit 032894
  else
Packit 032894
    {
Packit 032894
      ehdr->e_shstrndx = SHN_XINDEX;
Packit 032894
      Elf_Scn *zscn = elf_getscn (elf, 0);
Packit 032894
      GElf_Shdr zshdr_mem;
Packit 032894
      GElf_Shdr *zshdr = gelf_getshdr (zscn, &zshdr_mem);
Packit 032894
      if (zshdr == NULL)
Packit 032894
	return -1;
Packit 032894
      zshdr->sh_link = ndx;
Packit 032894
      if (gelf_update_shdr (zscn, zshdr) == 0)
Packit 032894
	return -1;
Packit 032894
    }
Packit 032894
Packit 032894
  if (gelf_update_ehdr (elf, ehdr) == 0)
Packit 032894
    return -1;
Packit 032894
Packit 032894
  return 0;
Packit 032894
}
Packit 032894
Packit 032894
/* Will add nr new '.extra' sections and a new '.new_shstrtab' section
Packit 032894
   at the end.  */
Packit 032894
static void
Packit 032894
add_sections (const char *name, size_t nr, int use_mmap, size_t sec_size)
Packit 032894
{
Packit 032894
  printf ("add_sections '%s': %zd (sec_size: %zd)\n", name, nr, sec_size);
Packit 032894
Packit 032894
  int fd = open (name, O_RDWR);
Packit 032894
  if (fd < 0)
Packit 032894
    {
Packit 032894
      fprintf (stderr, "Couldn't open file '%s': %s\n",
Packit 032894
	       name, strerror (errno));
Packit 032894
      exit (1);
Packit 032894
    }
Packit 032894
Packit 032894
  Elf *elf = elf_begin (fd, use_mmap ? ELF_C_RDWR_MMAP : ELF_C_RDWR, NULL);
Packit 032894
  if (elf == NULL)
Packit 032894
    {
Packit 032894
      fprintf (stderr, "Couldn't open ELF file '%s': %s\n",
Packit 032894
	       name, elf_errmsg (-1));
Packit 032894
      exit (1);
Packit 032894
    }
Packit 032894
Packit 032894
  /* We will add a new shstrtab section with two new names at the end.
Packit 032894
     Just get the current shstrtab table and add two entries '.extra'
Packit 032894
     and '.old_shstrtab' at the end of the table, so all existing indexes
Packit 032894
     are still valid.  */
Packit 032894
  size_t shstrndx;
Packit 032894
  if (elf_getshdrstrndx (elf, &shstrndx) < 0)
Packit 032894
    {
Packit 032894
      printf ("cannot get shstrndx: %s\n", elf_errmsg (-1));
Packit 032894
      exit (1);
Packit 032894
    }
Packit 032894
Packit 032894
  Elf_Scn *shstrtab_scn = elf_getscn (elf, shstrndx);
Packit 032894
  if (shstrtab_scn == NULL)
Packit 032894
    {
Packit 032894
      printf ("couldn't get shstrtab scn: %s\n", elf_errmsg (-1));
Packit 032894
      exit (1);
Packit 032894
    }
Packit 032894
  Elf_Data *shstrtab_data = elf_getdata (shstrtab_scn, NULL);
Packit 032894
  if (shstrtab_data == NULL)
Packit 032894
    {
Packit 032894
      printf ("couldn't get shstrtab data: %s\n", elf_errmsg (-1));
Packit 032894
      exit (1);
Packit 032894
    }
Packit 032894
  size_t new_shstrtab_size = (shstrtab_data->d_size
Packit 032894
			      + strlen (".extra") + 1
Packit 032894
			      + strlen (".old_shstrtab") + 1);
Packit 032894
  void *new_shstrtab_buf = malloc (new_shstrtab_size);
Packit 032894
  if (new_shstrtab_buf == NULL)
Packit 032894
    {
Packit 032894
      printf ("couldn't allocate new shstrtab data d_buf\n");
Packit 032894
      exit (1);
Packit 032894
    }
Packit 032894
  memcpy (new_shstrtab_buf, shstrtab_data->d_buf, shstrtab_data->d_size);
Packit 032894
  size_t extra_idx = shstrtab_data->d_size;
Packit 032894
  size_t old_shstrtab_idx = extra_idx + strlen (".extra") + 1;
Packit 032894
  strcpy (new_shstrtab_buf + extra_idx, ".extra");
Packit 032894
  strcpy (new_shstrtab_buf + old_shstrtab_idx, ".old_shstrtab");
Packit 032894
Packit 032894
  /* Change the name of the old shstrtab section, because elflint
Packit 032894
     has a strict check on the name/type for .shstrtab.  */
Packit 032894
  GElf_Shdr shdr_mem;
Packit 032894
  GElf_Shdr *shdr = gelf_getshdr (shstrtab_scn, &shdr_mem);
Packit 032894
  if (shdr == NULL)
Packit 032894
    {
Packit 032894
      printf ("cannot get header for old shstrtab section: %s\n",
Packit 032894
              elf_errmsg (-1));
Packit 032894
      exit (1);
Packit 032894
    }
Packit 032894
Packit 032894
  size_t shstrtab_idx = shdr->sh_name;
Packit 032894
  shdr->sh_name = old_shstrtab_idx;
Packit 032894
Packit 032894
  if (gelf_update_shdr (shstrtab_scn, shdr) == 0)
Packit 032894
    {
Packit 032894
      printf ("cannot update old shstrtab section header: %s\n",
Packit 032894
	      elf_errmsg (-1));
Packit 032894
      exit (1);
Packit 032894
    }
Packit 032894
Packit 032894
  void *buf;
Packit 032894
  size_t bufsz;
Packit 032894
  if (sec_size == 0)
Packit 032894
    {
Packit 032894
      buf = strdup ("extra");
Packit 032894
      bufsz = strlen ("extra") + 1;
Packit 032894
    }
Packit 032894
  else
Packit 032894
    {
Packit 032894
      buf = malloc (sec_size);
Packit 032894
      if (buf == NULL)
Packit 032894
	{
Packit 032894
	  printf ("cannot allocate buffer data of %zd bytes\n", sec_size);
Packit 032894
	  exit (1);
Packit 032894
	}
Packit 032894
      memset (buf, 0xAA, sec_size);
Packit 032894
      bufsz = sec_size;
Packit 032894
    }
Packit 032894
Packit 032894
  // Add lots of .extra sections...
Packit 032894
  size_t cnt = 0;
Packit 032894
  while (cnt++ < nr)
Packit 032894
    {
Packit 032894
      Elf_Scn *scn = elf_newscn (elf);
Packit 032894
      if (scn == NULL)
Packit 032894
	{
Packit 032894
	  printf ("cannot create .extra section (%zd): %s\n", cnt,
Packit 032894
		  elf_errmsg (-1));
Packit 032894
	  exit (1);
Packit 032894
	}
Packit 032894
Packit 032894
      Elf_Data *data = elf_newdata (scn);
Packit 032894
      if (data == NULL)
Packit 032894
	{
Packit 032894
	  printf ("couldn't create new section data (%zd): %s\n", cnt,
Packit 032894
		  elf_errmsg (-1));
Packit 032894
	  exit (1);
Packit 032894
	}
Packit 032894
Packit 032894
      data->d_size = bufsz;
Packit 032894
      data->d_buf = buf;
Packit 032894
      data->d_type = ELF_T_BYTE;
Packit 032894
      data->d_align = 1;
Packit 032894
Packit 032894
      shdr = gelf_getshdr (scn, &shdr_mem);
Packit 032894
      if (shdr == NULL)
Packit 032894
	{
Packit 032894
	  printf ("cannot get header for new section (%zd): %s\n", cnt,
Packit 032894
		  elf_errmsg (-1));
Packit 032894
	  exit (1);
Packit 032894
	}
Packit 032894
Packit 032894
      shdr->sh_type = SHT_PROGBITS;
Packit 032894
      shdr->sh_flags = 0;
Packit 032894
      shdr->sh_addr = 0;
Packit 032894
      shdr->sh_link = SHN_UNDEF;
Packit 032894
      shdr->sh_info = SHN_UNDEF;
Packit 032894
      shdr->sh_addralign = 1;
Packit 032894
      shdr->sh_entsize = 0;
Packit 032894
      shdr->sh_size = data->d_size;
Packit 032894
      shdr->sh_name = extra_idx;
Packit 032894
Packit 032894
      if (gelf_update_shdr (scn, shdr) == 0)
Packit 032894
	{
Packit 032894
	  printf ("cannot update new section header (%zd): %s\n", cnt,
Packit 032894
		  elf_errmsg (-1));
Packit 032894
	  exit (1);
Packit 032894
	}
Packit 032894
    }
Packit 032894
Packit 032894
  // Create new shstrtab section.
Packit 032894
  Elf_Scn *new_shstrtab_scn = elf_newscn (elf);
Packit 032894
  if (new_shstrtab_scn == NULL)
Packit 032894
    {
Packit 032894
      printf ("cannot create new shstrtab section: %s\n", elf_errmsg (-1));
Packit 032894
      exit (1);
Packit 032894
    }
Packit 032894
Packit 032894
  Elf_Data *new_shstrtab_data = elf_newdata (new_shstrtab_scn);
Packit 032894
  if (new_shstrtab_data == NULL)
Packit 032894
    {
Packit 032894
      printf ("couldn't create new shstrtab section data: %s\n",
Packit 032894
	      elf_errmsg (-1));
Packit 032894
      exit (1);
Packit 032894
    }
Packit 032894
Packit 032894
  new_shstrtab_data->d_size = new_shstrtab_size;
Packit 032894
  new_shstrtab_data->d_buf = new_shstrtab_buf;
Packit 032894
  new_shstrtab_data->d_type = ELF_T_BYTE;
Packit 032894
  new_shstrtab_data->d_align = 1;
Packit 032894
Packit 032894
  shdr = gelf_getshdr (new_shstrtab_scn, &shdr_mem);
Packit 032894
  if (shdr == NULL)
Packit 032894
    {
Packit 032894
      printf ("cannot get header for new shstrtab section: %s\n",
Packit 032894
	      elf_errmsg (-1));
Packit 032894
      exit (1);
Packit 032894
    }
Packit 032894
Packit 032894
  shdr->sh_type = SHT_STRTAB;
Packit 032894
  shdr->sh_flags = 0;
Packit 032894
  shdr->sh_addr = 0;
Packit 032894
  shdr->sh_link = SHN_UNDEF;
Packit 032894
  shdr->sh_info = SHN_UNDEF;
Packit 032894
  shdr->sh_addralign = 1;
Packit 032894
  shdr->sh_entsize = 0;
Packit 032894
  shdr->sh_size = new_shstrtab_size;
Packit 032894
  shdr->sh_name = shstrtab_idx;
Packit 032894
Packit 032894
  // Finished new shstrtab section, update the header.
Packit 032894
  if (gelf_update_shdr (new_shstrtab_scn, shdr) == 0)
Packit 032894
    {
Packit 032894
      printf ("cannot update new shstrtab section header: %s\n",
Packit 032894
	      elf_errmsg (-1));
Packit 032894
      exit (1);
Packit 032894
    }
Packit 032894
Packit 032894
  // Set it as the new shstrtab section to get the names correct.
Packit 032894
  size_t new_shstrndx = elf_ndxscn (new_shstrtab_scn);
Packit 032894
  if (setshstrndx (elf, new_shstrndx) < 0)
Packit 032894
    {
Packit 032894
      printf ("cannot set shstrndx: %s\n", elf_errmsg (-1));
Packit 032894
      exit (1);
Packit 032894
    }
Packit 032894
Packit 032894
  // Write everything to disk.
Packit 032894
  if (elf_update (elf, ELF_C_WRITE) < 0)
Packit 032894
    {
Packit 032894
      printf ("failure in elf_update: %s\n", elf_errmsg (-1));
Packit 032894
      exit (1);
Packit 032894
    }
Packit 032894
Packit 032894
  if (elf_end (elf) != 0)
Packit 032894
    {
Packit 032894
      printf ("couldn't cleanup elf '%s': %s\n", name, elf_errmsg (-1));
Packit 032894
      exit (1);
Packit 032894
    }
Packit 032894
Packit 032894
  if (close (fd) != 0)
Packit 032894
    {
Packit 032894
      printf ("couldn't close '%s': %s\n", name, strerror (errno));
Packit 032894
      exit (1);
Packit 032894
    }
Packit 032894
Packit 032894
  free (buf);
Packit 032894
  free (new_shstrtab_buf);
Packit 032894
}
Packit 032894
Packit 032894
int
Packit 032894
main (int argc, char *argv[])
Packit 032894
{
Packit 032894
  elf_version (EV_CURRENT);
Packit 032894
Packit 032894
  /* Takes the given file, and adds the given number of sections.
Packit 032894
     Optionally using mmap and optionally using a given section size.  */
Packit 032894
  if (argc < 3 || argc > 5)
Packit 032894
    {
Packit 032894
      fprintf (stderr, "addsections [--mmap] nr elf.file [sec_size]\n");
Packit 032894
      exit (1);
Packit 032894
    }
Packit 032894
Packit 032894
  int argn = 1;
Packit 032894
  bool use_mmap = false;
Packit 032894
  if (strcmp (argv[argn], "--mmap") == 0)
Packit 032894
    {
Packit 032894
      use_mmap = true;
Packit 032894
      argn++;
Packit 032894
    }
Packit 032894
Packit 032894
  size_t nr = atoi (argv[argn++]);
Packit 032894
  const char *file = argv[argn++];
Packit 032894
Packit 032894
  size_t sec_size = 0;
Packit 032894
  if (argn < argc)
Packit 032894
    sec_size = atol (argv[argn++]);
Packit 032894
Packit 032894
  add_sections (file, nr, use_mmap, sec_size);
Packit 032894
Packit 032894
  return 0;
Packit 032894
}