Blame libelf/elf_strptr.c

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