Home | History | Annotate | Download | only in libdwfl
      1 /* Decompression support for libdwfl: zlib (gzip), bzlib (bzip2) or lzma (xz).
      2    Copyright (C) 2009, 2016 Red Hat, Inc.
      3    This file is part of elfutils.
      4 
      5    This file is free software; you can redistribute it and/or modify
      6    it under the terms of either
      7 
      8      * the GNU Lesser General Public License as published by the Free
      9        Software Foundation; either version 3 of the License, or (at
     10        your option) any later version
     11 
     12    or
     13 
     14      * the GNU General Public License as published by the Free
     15        Software Foundation; either version 2 of the License, or (at
     16        your option) any later version
     17 
     18    or both in parallel, as here.
     19 
     20    elfutils is distributed in the hope that it will be useful, but
     21    WITHOUT ANY WARRANTY; without even the implied warranty of
     22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     23    General Public License for more details.
     24 
     25    You should have received copies of the GNU General Public License and
     26    the GNU Lesser General Public License along with this program.  If
     27    not, see <http://www.gnu.org/licenses/>.  */
     28 
     29 #include "../libelf/libelfP.h"
     30 #undef	_
     31 #include "libdwflP.h"
     32 
     33 #include <unistd.h>
     34 
     35 #if !USE_BZLIB
     36 # define __libdw_bunzip2(...)	DWFL_E_BADELF
     37 #endif
     38 
     39 #if !USE_LZMA
     40 # define __libdw_unlzma(...)	DWFL_E_BADELF
     41 #endif
     42 
     43 /* Consumes and replaces *ELF only on success.  */
     44 static Dwfl_Error
     45 decompress (int fd __attribute__ ((unused)), Elf **elf)
     46 {
     47   Dwfl_Error error = DWFL_E_BADELF;
     48   void *buffer = NULL;
     49   size_t size = 0;
     50 
     51   const off_t offset = (*elf)->start_offset;
     52   void *const mapped = ((*elf)->map_address == NULL ? NULL
     53 			: (*elf)->map_address + offset);
     54   const size_t mapped_size = (*elf)->maximum_size;
     55   if (mapped_size == 0)
     56     return error;
     57 
     58   error = __libdw_gunzip (fd, offset, mapped, mapped_size, &buffer, &size);
     59   if (error == DWFL_E_BADELF)
     60     error = __libdw_bunzip2 (fd, offset, mapped, mapped_size, &buffer, &size);
     61   if (error == DWFL_E_BADELF)
     62     error = __libdw_unlzma (fd, offset, mapped, mapped_size, &buffer, &size);
     63 
     64   if (error == DWFL_E_NOERROR)
     65     {
     66       if (unlikely (size == 0))
     67 	{
     68 	  error = DWFL_E_BADELF;
     69 	  free (buffer);
     70 	}
     71       else
     72 	{
     73 	  Elf *memelf = elf_memory (buffer, size);
     74 	  if (memelf == NULL)
     75 	    {
     76 	      error = DWFL_E_LIBELF;
     77 	      free (buffer);
     78 	    }
     79 	  else
     80 	    {
     81 	      memelf->flags |= ELF_F_MALLOCED;
     82 	      elf_end (*elf);
     83 	      *elf = memelf;
     84 	    }
     85 	}
     86     }
     87   else
     88     free (buffer);
     89 
     90   return error;
     91 }
     92 
     93 static Dwfl_Error
     94 what_kind (int fd, Elf **elfp, Elf_Kind *kind, bool *close_fd)
     95 {
     96   Dwfl_Error error = DWFL_E_NOERROR;
     97   *kind = elf_kind (*elfp);
     98   if (unlikely (*kind == ELF_K_NONE))
     99     {
    100       if (unlikely (*elfp == NULL))
    101 	error = DWFL_E_LIBELF;
    102       else
    103 	{
    104 	  error = decompress (fd, elfp);
    105 	  if (error == DWFL_E_NOERROR)
    106 	    {
    107 	      *close_fd = true;
    108 	      *kind = elf_kind (*elfp);
    109 	    }
    110 	}
    111     }
    112   return error;
    113 }
    114 
    115 Dwfl_Error internal_function
    116 __libdw_open_file (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok)
    117 {
    118   bool close_fd = false;
    119 
    120   Elf *elf = elf_begin (*fdp, ELF_C_READ_MMAP_PRIVATE, NULL);
    121 
    122   Elf_Kind kind;
    123   Dwfl_Error error = what_kind (*fdp, &elf, &kind, &close_fd);
    124   if (error == DWFL_E_BADELF)
    125     {
    126       /* It's not an ELF file or a compressed file.
    127 	 See if it's an image with a header preceding the real file.  */
    128 
    129       off_t offset = elf->start_offset;
    130       error = __libdw_image_header (*fdp, &offset,
    131 				    (elf->map_address == NULL ? NULL
    132 				     : elf->map_address + offset),
    133 				    elf->maximum_size);
    134       if (error == DWFL_E_NOERROR)
    135 	{
    136 	  /* Pure evil.  libelf needs some better interfaces.  */
    137 	  elf->kind = ELF_K_AR;
    138 	  elf->state.ar.elf_ar_hdr.ar_name = "libdwfl is faking you out";
    139 	  elf->state.ar.elf_ar_hdr.ar_size = elf->maximum_size - offset;
    140 	  elf->state.ar.offset = offset - sizeof (struct ar_hdr);
    141 	  Elf *subelf = elf_begin (-1, ELF_C_READ_MMAP_PRIVATE, elf);
    142 	  elf->kind = ELF_K_NONE;
    143 	  if (unlikely (subelf == NULL))
    144 	    error = DWFL_E_LIBELF;
    145 	  else
    146 	    {
    147 	      subelf->parent = NULL;
    148 	      subelf->flags |= elf->flags & (ELF_F_MMAPPED | ELF_F_MALLOCED);
    149 	      elf->flags &= ~(ELF_F_MMAPPED | ELF_F_MALLOCED);
    150 	      elf_end (elf);
    151 	      elf = subelf;
    152 	      error = what_kind (*fdp, &elf, &kind, &close_fd);
    153 	    }
    154 	}
    155     }
    156 
    157   if (error == DWFL_E_NOERROR
    158       && kind != ELF_K_ELF
    159       && !(archive_ok && kind == ELF_K_AR))
    160     error = DWFL_E_BADELF;
    161 
    162   if (error != DWFL_E_NOERROR)
    163     {
    164       elf_end (elf);
    165       elf = NULL;
    166     }
    167 
    168   if (error == DWFL_E_NOERROR ? close_fd : close_on_fail)
    169     {
    170       close (*fdp);
    171       *fdp = -1;
    172     }
    173 
    174   *elfp = elf;
    175   return error;
    176 }
    177