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 #ifdef HAVE_CONFIG_H
30 # include <config.h>
31 #endif
32 
33 #include "../libelf/libelfP.h"
34 #undef	_
35 #include "libdwflP.h"
36 
37 #include <unistd.h>
38 
39 #if !USE_BZLIB
40 # define __libdw_bunzip2(...)	DWFL_E_BADELF
41 #endif
42 
43 #if !USE_LZMA
44 # define __libdw_unlzma(...)	DWFL_E_BADELF
45 #endif
46 
47 #if !USE_ZSTD
48 # define __libdw_unzstd(...)	DWFL_E_BADELF
49 #endif
50 
51 /* Consumes and replaces *ELF only on success.  */
52 static Dwfl_Error
decompress(int fd,Elf ** elf)53 decompress (int fd __attribute__ ((unused)), Elf **elf)
54 {
55   Dwfl_Error error = DWFL_E_BADELF;
56   void *buffer = NULL;
57   size_t size = 0;
58 
59   const off_t offset = (*elf)->start_offset;
60   void *const mapped = ((*elf)->map_address == NULL ? NULL
61 			: (*elf)->map_address + offset);
62   const size_t mapped_size = (*elf)->maximum_size;
63   if (mapped_size == 0)
64     return error;
65 
66   error = __libdw_gunzip (fd, offset, mapped, mapped_size, &buffer, &size);
67   if (error == DWFL_E_BADELF)
68     error = __libdw_bunzip2 (fd, offset, mapped, mapped_size, &buffer, &size);
69   if (error == DWFL_E_BADELF)
70     error = __libdw_unlzma (fd, offset, mapped, mapped_size, &buffer, &size);
71   if (error == DWFL_E_BADELF)
72     error = __libdw_unzstd (fd, offset, mapped, mapped_size, &buffer, &size);
73 
74   if (error == DWFL_E_NOERROR)
75     {
76       if (unlikely (size == 0))
77 	{
78 	  error = DWFL_E_BADELF;
79 	  free (buffer);
80 	}
81       else
82 	{
83 	  Elf *memelf = elf_memory (buffer, size);
84 	  if (memelf == NULL)
85 	    {
86 	      error = DWFL_E_LIBELF;
87 	      free (buffer);
88 	    }
89 	  else
90 	    {
91 	      memelf->flags |= ELF_F_MALLOCED;
92 	      elf_end (*elf);
93 	      *elf = memelf;
94 	    }
95 	}
96     }
97   else
98     free (buffer);
99 
100   return error;
101 }
102 
103 static Dwfl_Error
what_kind(int fd,Elf ** elfp,Elf_Kind * kind,bool * may_close_fd)104 what_kind (int fd, Elf **elfp, Elf_Kind *kind, bool *may_close_fd)
105 {
106   Dwfl_Error error = DWFL_E_NOERROR;
107   *kind = elf_kind (*elfp);
108   if (unlikely (*kind == ELF_K_NONE))
109     {
110       if (unlikely (*elfp == NULL))
111 	error = DWFL_E_LIBELF;
112       else
113 	{
114 	  error = decompress (fd, elfp);
115 	  if (error == DWFL_E_NOERROR)
116 	    {
117 	      *may_close_fd = true;
118 	      *kind = elf_kind (*elfp);
119 	    }
120 	}
121     }
122   return error;
123 }
124 
125 static Dwfl_Error
libdw_open_elf(int * fdp,Elf ** elfp,bool close_on_fail,bool archive_ok,bool never_close_fd,bool bad_elf_ok)126 libdw_open_elf (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok,
127 		bool never_close_fd, bool bad_elf_ok)
128 {
129   bool may_close_fd = false;
130 
131   Elf *elf = elf_begin (*fdp, ELF_C_READ_MMAP_PRIVATE, NULL);
132 
133   Elf_Kind kind;
134   Dwfl_Error error = what_kind (*fdp, &elf, &kind, &may_close_fd);
135   if (error == DWFL_E_BADELF)
136     {
137       /* It's not an ELF file or a compressed file.
138 	 See if it's an image with a header preceding the real file.  */
139 
140       off_t offset = elf->start_offset;
141       error = __libdw_image_header (*fdp, &offset,
142 				    (elf->map_address == NULL ? NULL
143 				     : elf->map_address + offset),
144 				    elf->maximum_size);
145       if (error == DWFL_E_NOERROR)
146 	{
147 	  /* Pure evil.  libelf needs some better interfaces.  */
148 	  elf->kind = ELF_K_AR;
149 	  elf->state.ar.elf_ar_hdr.ar_name = "libdwfl is faking you out";
150 	  elf->state.ar.elf_ar_hdr.ar_size = elf->maximum_size - offset;
151 	  elf->state.ar.offset = offset - sizeof (struct ar_hdr);
152 	  Elf *subelf = elf_begin (-1, ELF_C_READ_MMAP_PRIVATE, elf);
153 	  elf->kind = ELF_K_NONE;
154 	  if (unlikely (subelf == NULL))
155 	    error = DWFL_E_LIBELF;
156 	  else
157 	    {
158 	      subelf->parent = NULL;
159 	      subelf->flags |= elf->flags & (ELF_F_MMAPPED | ELF_F_MALLOCED);
160 	      elf->flags &= ~(ELF_F_MMAPPED | ELF_F_MALLOCED);
161 	      elf_end (elf);
162 	      elf = subelf;
163 	      error = what_kind (*fdp, &elf, &kind, &may_close_fd);
164 	    }
165 	}
166     }
167 
168   if (error == DWFL_E_NOERROR
169       && kind != ELF_K_ELF
170       && !(archive_ok && kind == ELF_K_AR))
171     error = DWFL_E_BADELF;
172 
173   /* This basically means, we keep a ELF_K_NONE Elf handle and return it.  */
174   if (bad_elf_ok && error == DWFL_E_BADELF)
175     error = DWFL_E_NOERROR;
176 
177   if (error != DWFL_E_NOERROR)
178     {
179       elf_end (elf);
180       elf = NULL;
181     }
182 
183   if (! never_close_fd
184       && error == DWFL_E_NOERROR ? may_close_fd : close_on_fail)
185     {
186       close (*fdp);
187       *fdp = -1;
188     }
189 
190   *elfp = elf;
191   return error;
192 }
193 
194 Dwfl_Error internal_function
__libdw_open_file(int * fdp,Elf ** elfp,bool close_on_fail,bool archive_ok)195 __libdw_open_file (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok)
196 {
197   return libdw_open_elf (fdp, elfp, close_on_fail, archive_ok, false, false);
198 }
199 
200 Dwfl_Error internal_function
__libdw_open_elf(int fd,Elf ** elfp)201 __libdw_open_elf (int fd, Elf **elfp)
202 {
203   return libdw_open_elf (&fd, elfp, false, true, true, true);
204 }
205