Blame libelf/elf_strptr.c

Packit 032894
/* Return string pointer from string section.
Packit 032894
   Copyright (C) 1998-2002, 2004, 2008, 2009, 2015 Red Hat, Inc.
Packit 032894
   This file is part of elfutils.
Packit 032894
   Contributed by Ulrich Drepper <drepper@redhat.com>, 1998.
Packit 032894
Packit 032894
   This file is free software; you can redistribute it and/or modify
Packit 032894
   it under the terms of either
Packit 032894
Packit 032894
     * the GNU Lesser General Public License as published by the Free
Packit 032894
       Software Foundation; either version 3 of the License, or (at
Packit 032894
       your option) any later version
Packit 032894
Packit 032894
   or
Packit 032894
Packit 032894
     * the GNU General Public License as published by the Free
Packit 032894
       Software Foundation; either version 2 of the License, or (at
Packit 032894
       your option) any later version
Packit 032894
Packit 032894
   or both in parallel, as here.
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 GNU
Packit 032894
   General Public License for more details.
Packit 032894
Packit 032894
   You should have received copies of the GNU General Public License and
Packit 032894
   the GNU Lesser General Public License along with this program.  If
Packit 032894
   not, see <http://www.gnu.org/licenses/>.  */
Packit 032894
Packit 032894
#ifdef HAVE_CONFIG_H
Packit 032894
# include <config.h>
Packit 032894
#endif
Packit 032894
Packit 032894
#include <libelf.h>
Packit 032894
#include <stdbool.h>
Packit 032894
#include <stddef.h>
Packit 032894
Packit 032894
#include "libelfP.h"
Packit 032894
Packit 032894
Packit 032894
static void *
Packit 032894
get_zdata (Elf_Scn *strscn)
Packit 032894
{
Packit 032894
  size_t zsize, zalign;
Packit 032894
  void *zdata = __libelf_decompress_elf (strscn, &zsize, &zalign);
Packit 032894
  if (zdata == NULL)
Packit 032894
    return NULL;
Packit 032894
Packit 032894
  strscn->zdata_base = zdata;
Packit 032894
  strscn->zdata_size = zsize;
Packit 032894
  strscn->zdata_align = zalign;
Packit 032894
Packit 032894
  return zdata;
Packit 032894
}
Packit 032894
Packit 032894
static bool validate_str (const char *str, size_t from, size_t to)
Packit 032894
{
Packit 032894
#if HAVE_DECL_MEMRCHR
Packit 032894
  return memrchr (&str[from], '\0', to - from) != NULL;
Packit 032894
#else
Packit 032894
  do {
Packit 032894
    if (to <= from)
Packit 032894
      return false;
Packit 032894
Packit 032894
    to--;
Packit 032894
  } while (str[to]);
Packit 032894
Packit 032894
  return true;
Packit 032894
#endif
Packit 032894
}
Packit 032894
Packit 032894
char *
Packit 032894
elf_strptr (Elf *elf, size_t idx, size_t offset)
Packit 032894
{
Packit 032894
  if (elf == NULL)
Packit 032894
    return NULL;
Packit 032894
Packit 032894
  if (elf->kind != ELF_K_ELF)
Packit 032894
    {
Packit 032894
      __libelf_seterrno (ELF_E_INVALID_HANDLE);
Packit 032894
      return NULL;
Packit 032894
    }
Packit 032894
Packit 032894
  rwlock_rdlock (elf->lock);
Packit 032894
Packit 032894
  char *result = NULL;
Packit 032894
  Elf_Scn *strscn;
Packit 032894
Packit 032894
  /* Find the section in the list.  */
Packit 032894
  Elf_ScnList *runp = (elf->class == ELFCLASS32
Packit 032894
		       || (offsetof (struct Elf, state.elf32.scns)
Packit 032894
			   == offsetof (struct Elf, state.elf64.scns))
Packit 032894
		       ? &elf->state.elf32.scns : &elf->state.elf64.scns);
Packit 032894
  while (1)
Packit 032894
    {
Packit 032894
      if (idx < runp->max)
Packit 032894
	{
Packit 032894
	  if (idx < runp->cnt)
Packit 032894
	    strscn = &runp->data[idx];
Packit 032894
	  else
Packit 032894
	    {
Packit 032894
	      __libelf_seterrno (ELF_E_INVALID_INDEX);
Packit 032894
	      goto out;
Packit 032894
	    }
Packit 032894
	  break;
Packit 032894
	}
Packit 032894
Packit 032894
      idx -= runp->max;
Packit 032894
Packit 032894
      runp = runp->next;
Packit 032894
      if (runp == NULL)
Packit 032894
	{
Packit 032894
	  __libelf_seterrno (ELF_E_INVALID_INDEX);
Packit 032894
	  goto out;
Packit 032894
	}
Packit 032894
    }
Packit 032894
Packit 032894
  size_t sh_size = 0;
Packit 032894
  if (elf->class == ELFCLASS32)
Packit 032894
    {
Packit 032894
      Elf32_Shdr *shdr = strscn->shdr.e32 ?: __elf32_getshdr_rdlock (strscn);
Packit 032894
      if (unlikely (shdr->sh_type != SHT_STRTAB))
Packit 032894
	{
Packit 032894
	  /* This is no string section.  */
Packit 032894
	  __libelf_seterrno (ELF_E_INVALID_SECTION);
Packit 032894
	  goto out;
Packit 032894
	}
Packit 032894
Packit 032894
      if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
Packit 032894
	sh_size = shdr->sh_size;
Packit 032894
      else
Packit 032894
	{
Packit 032894
	  if (strscn->zdata_base == NULL && get_zdata (strscn) == NULL)
Packit 032894
	    goto out;
Packit 032894
	  sh_size = strscn->zdata_size;
Packit 032894
	}
Packit 032894
Packit 032894
      if (unlikely (offset >= sh_size))
Packit 032894
	{
Packit 032894
	  /* The given offset is too big, it is beyond this section.  */
Packit 032894
	  __libelf_seterrno (ELF_E_OFFSET_RANGE);
Packit 032894
	  goto out;
Packit 032894
	}
Packit 032894
    }
Packit 032894
  else
Packit 032894
    {
Packit 032894
      Elf64_Shdr *shdr = strscn->shdr.e64 ?: __elf64_getshdr_rdlock (strscn);
Packit Service 35cfd5
      if (unlikely (shdr == NULL || shdr->sh_type != SHT_STRTAB))
Packit 032894
	{
Packit 032894
	  /* This is no string section.  */
Packit 032894
	  __libelf_seterrno (ELF_E_INVALID_SECTION);
Packit 032894
	  goto out;
Packit 032894
	}
Packit 032894
Packit 032894
      if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
Packit 032894
	sh_size = shdr->sh_size;
Packit 032894
      else
Packit 032894
	{
Packit 032894
	  if (strscn->zdata_base == NULL && get_zdata (strscn) == NULL)
Packit 032894
	    goto out;
Packit 032894
	  sh_size = strscn->zdata_size;
Packit 032894
	}
Packit 032894
Packit 032894
      if (unlikely (offset >= sh_size))
Packit 032894
	{
Packit 032894
	  /* The given offset is too big, it is beyond this section.  */
Packit 032894
	  __libelf_seterrno (ELF_E_OFFSET_RANGE);
Packit 032894
	  goto out;
Packit 032894
	}
Packit 032894
    }
Packit 032894
Packit 032894
  if (strscn->rawdata_base == NULL && ! strscn->data_read)
Packit 032894
    {
Packit 032894
      rwlock_unlock (elf->lock);
Packit 032894
      rwlock_wrlock (elf->lock);
Packit 032894
      if (strscn->rawdata_base == NULL && ! strscn->data_read
Packit 032894
	/* Read the section data.  */
Packit 032894
	  && __libelf_set_rawdata_wrlock (strscn) != 0)
Packit 032894
	goto out;
Packit 032894
    }
Packit 032894
Packit 032894
  if (unlikely (strscn->zdata_base != NULL))
Packit 032894
    {
Packit 032894
      /* Make sure the string is NUL terminated.  Start from the end,
Packit 032894
         which very likely is a NUL char.  */
Packit 032894
      if (likely (validate_str (strscn->zdata_base, offset, sh_size)))
Packit 032894
        result = &strscn->zdata_base[offset];
Packit 032894
      else
Packit 032894
        __libelf_seterrno (ELF_E_INVALID_INDEX);
Packit 032894
    }
Packit 032894
  else if (likely (strscn->data_list_rear == NULL))
Packit 032894
    {
Packit 032894
      // XXX The above is currently correct since elf_newdata will
Packit 032894
      // make sure to convert the rawdata into the datalist if
Packit 032894
      // necessary. But it would be more efficient to keep the rawdata
Packit 032894
      // unconverted and only then iterate over the rest of the (newly
Packit 032894
      // added data) list.  Note that when the ELF file is mmapped
Packit 032894
      // rawdata_base can be set while rawdata.d hasn't been
Packit 032894
      // initialized yet (when data_read is zero). So we cannot just
Packit 032894
      // look at the rawdata.d.d_size.
Packit 032894
Packit 032894
      /* Make sure the string is NUL terminated.  Start from the end,
Packit 032894
	 which very likely is a NUL char.  */
Packit 032894
      if (likely (validate_str (strscn->rawdata_base, offset, sh_size)))
Packit 032894
	result = &strscn->rawdata_base[offset];
Packit 032894
      else
Packit 032894
	__libelf_seterrno (ELF_E_INVALID_INDEX);
Packit 032894
    }
Packit 032894
  else
Packit 032894
    {
Packit 032894
      /* This is a file which is currently created.  Use the list of
Packit 032894
	 data blocks.  */
Packit 032894
      struct Elf_Data_List *dl = &strscn->data_list;
Packit 032894
      while (dl != NULL)
Packit 032894
	{
Packit 032894
	  if (offset >= (size_t) dl->data.d.d_off
Packit 032894
	      && offset < dl->data.d.d_off + dl->data.d.d_size)
Packit 032894
	    {
Packit 032894
	      /* Make sure the string is NUL terminated.  Start from
Packit 032894
		 the end, which very likely is a NUL char.  */
Packit 032894
	      if (likely (validate_str ((char *) dl->data.d.d_buf,
Packit 032894
					offset - dl->data.d.d_off,
Packit 032894
					dl->data.d.d_size)))
Packit 032894
		result = ((char *) dl->data.d.d_buf
Packit 032894
			  + (offset - dl->data.d.d_off));
Packit 032894
	      else
Packit 032894
		__libelf_seterrno (ELF_E_INVALID_INDEX);
Packit 032894
	      break;
Packit 032894
	    }
Packit 032894
Packit 032894
	  dl = dl->next;
Packit 032894
	}
Packit 032894
    }
Packit 032894
Packit 032894
 out:
Packit 032894
  rwlock_unlock (elf->lock);
Packit 032894
Packit 032894
  return result;
Packit 032894
}
Packit 032894
INTDEF(elf_strptr)