Blame libdwfl/open.c

Packit Service 97d2fb
/* Decompression support for libdwfl: zlib (gzip), bzlib (bzip2) or lzma (xz).
Packit Service 97d2fb
   Copyright (C) 2009, 2016 Red Hat, Inc.
Packit Service 97d2fb
   This file is part of elfutils.
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/libelfP.h"
Packit Service 97d2fb
#undef	_
Packit Service 97d2fb
#include "libdwflP.h"
Packit Service 97d2fb
Packit Service 97d2fb
#include <unistd.h>
Packit Service 97d2fb
Packit Service 97d2fb
#if !USE_BZLIB
Packit Service 97d2fb
# define __libdw_bunzip2(...)	DWFL_E_BADELF
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
#if !USE_LZMA
Packit Service 97d2fb
# define __libdw_unlzma(...)	DWFL_E_BADELF
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
#if !USE_ZSTD
Packit Service 97d2fb
# define __libdw_unzstd(...)	DWFL_E_BADELF
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
/* Consumes and replaces *ELF only on success.  */
Packit Service 97d2fb
static Dwfl_Error
Packit Service 97d2fb
decompress (int fd __attribute__ ((unused)), Elf **elf)
Packit Service 97d2fb
{
Packit Service 97d2fb
  Dwfl_Error error = DWFL_E_BADELF;
Packit Service 97d2fb
  void *buffer = NULL;
Packit Service 97d2fb
  size_t size = 0;
Packit Service 97d2fb
Packit Service 97d2fb
  const off_t offset = (*elf)->start_offset;
Packit Service 97d2fb
  void *const mapped = ((*elf)->map_address == NULL ? NULL
Packit Service 97d2fb
			: (*elf)->map_address + offset);
Packit Service 97d2fb
  const size_t mapped_size = (*elf)->maximum_size;
Packit Service 97d2fb
  if (mapped_size == 0)
Packit Service 97d2fb
    return error;
Packit Service 97d2fb
Packit Service 97d2fb
  error = __libdw_gunzip (fd, offset, mapped, mapped_size, &buffer, &size);
Packit Service 97d2fb
  if (error == DWFL_E_BADELF)
Packit Service 97d2fb
    error = __libdw_bunzip2 (fd, offset, mapped, mapped_size, &buffer, &size);
Packit Service 97d2fb
  if (error == DWFL_E_BADELF)
Packit Service 97d2fb
    error = __libdw_unlzma (fd, offset, mapped, mapped_size, &buffer, &size);
Packit Service 97d2fb
  if (error == DWFL_E_BADELF)
Packit Service 97d2fb
    error = __libdw_unzstd (fd, offset, mapped, mapped_size, &buffer, &size);
Packit Service 97d2fb
Packit Service 97d2fb
  if (error == DWFL_E_NOERROR)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (unlikely (size == 0))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  error = DWFL_E_BADELF;
Packit Service 97d2fb
	  free (buffer);
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  Elf *memelf = elf_memory (buffer, size);
Packit Service 97d2fb
	  if (memelf == NULL)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      error = DWFL_E_LIBELF;
Packit Service 97d2fb
	      free (buffer);
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      memelf->flags |= ELF_F_MALLOCED;
Packit Service 97d2fb
	      elf_end (*elf);
Packit Service 97d2fb
	      *elf = memelf;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else
Packit Service 97d2fb
    free (buffer);
Packit Service 97d2fb
Packit Service 97d2fb
  return error;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static Dwfl_Error
Packit Service 97d2fb
what_kind (int fd, Elf **elfp, Elf_Kind *kind, bool *may_close_fd)
Packit Service 97d2fb
{
Packit Service 97d2fb
  Dwfl_Error error = DWFL_E_NOERROR;
Packit Service 97d2fb
  *kind = elf_kind (*elfp);
Packit Service 97d2fb
  if (unlikely (*kind == ELF_K_NONE))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (unlikely (*elfp == NULL))
Packit Service 97d2fb
	error = DWFL_E_LIBELF;
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  error = decompress (fd, elfp);
Packit Service 97d2fb
	  if (error == DWFL_E_NOERROR)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      *may_close_fd = true;
Packit Service 97d2fb
	      *kind = elf_kind (*elfp);
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
  return error;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static Dwfl_Error
Packit Service 97d2fb
libdw_open_elf (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok,
Packit Service 97d2fb
		bool never_close_fd, bool bad_elf_ok)
Packit Service 97d2fb
{
Packit Service 97d2fb
  bool may_close_fd = false;
Packit Service 97d2fb
Packit Service 97d2fb
  Elf *elf = elf_begin (*fdp, ELF_C_READ_MMAP_PRIVATE, NULL);
Packit Service 97d2fb
Packit Service 97d2fb
  Elf_Kind kind;
Packit Service 97d2fb
  Dwfl_Error error = what_kind (*fdp, &elf, &kind, &may_close_fd);
Packit Service 97d2fb
  if (error == DWFL_E_BADELF)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* It's not an ELF file or a compressed file.
Packit Service 97d2fb
	 See if it's an image with a header preceding the real file.  */
Packit Service 97d2fb
Packit Service 97d2fb
      off_t offset = elf->start_offset;
Packit Service 97d2fb
      error = __libdw_image_header (*fdp, &offset,
Packit Service 97d2fb
				    (elf->map_address == NULL ? NULL
Packit Service 97d2fb
				     : elf->map_address + offset),
Packit Service 97d2fb
				    elf->maximum_size);
Packit Service 97d2fb
      if (error == DWFL_E_NOERROR)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Pure evil.  libelf needs some better interfaces.  */
Packit Service 97d2fb
	  elf->kind = ELF_K_AR;
Packit Service 97d2fb
	  elf->state.ar.elf_ar_hdr.ar_name = "libdwfl is faking you out";
Packit Service 97d2fb
	  elf->state.ar.elf_ar_hdr.ar_size = elf->maximum_size - offset;
Packit Service 97d2fb
	  elf->state.ar.offset = offset - sizeof (struct ar_hdr);
Packit Service 97d2fb
	  Elf *subelf = elf_begin (-1, ELF_C_READ_MMAP_PRIVATE, elf);
Packit Service 97d2fb
	  elf->kind = ELF_K_NONE;
Packit Service 97d2fb
	  if (unlikely (subelf == NULL))
Packit Service 97d2fb
	    error = DWFL_E_LIBELF;
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      subelf->parent = NULL;
Packit Service 97d2fb
	      subelf->flags |= elf->flags & (ELF_F_MMAPPED | ELF_F_MALLOCED);
Packit Service 97d2fb
	      elf->flags &= ~(ELF_F_MMAPPED | ELF_F_MALLOCED);
Packit Service 97d2fb
	      elf_end (elf);
Packit Service 97d2fb
	      elf = subelf;
Packit Service 97d2fb
	      error = what_kind (*fdp, &elf, &kind, &may_close_fd);
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (error == DWFL_E_NOERROR
Packit Service 97d2fb
      && kind != ELF_K_ELF
Packit Service 97d2fb
      && !(archive_ok && kind == ELF_K_AR))
Packit Service 97d2fb
    error = DWFL_E_BADELF;
Packit Service 97d2fb
Packit Service 97d2fb
  /* This basically means, we keep a ELF_K_NONE Elf handle and return it.  */
Packit Service 97d2fb
  if (bad_elf_ok && error == DWFL_E_BADELF)
Packit Service 97d2fb
    error = DWFL_E_NOERROR;
Packit Service 97d2fb
Packit Service 97d2fb
  if (error != DWFL_E_NOERROR)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      elf_end (elf);
Packit Service 97d2fb
      elf = NULL;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (! never_close_fd
Packit Service 97d2fb
      && error == DWFL_E_NOERROR ? may_close_fd : close_on_fail)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      close (*fdp);
Packit Service 97d2fb
      *fdp = -1;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  *elfp = elf;
Packit Service 97d2fb
  return error;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Dwfl_Error internal_function
Packit Service 97d2fb
__libdw_open_file (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok)
Packit Service 97d2fb
{
Packit Service 97d2fb
  return libdw_open_elf (fdp, elfp, close_on_fail, archive_ok, false, false);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
Dwfl_Error internal_function
Packit Service 97d2fb
__libdw_open_elf (int fd, Elf **elfp)
Packit Service 97d2fb
{
Packit Service 97d2fb
  return libdw_open_elf (&fd, elfp, false, true, true, true);
Packit Service 97d2fb
}