• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Decompression support for libdwfl: zlib (gzip), bzlib (bzip2) or lzma (xz).
2    Copyright (C) 2009, 2016 Red Hat, Inc.
3    Copyright (C) 2022 Google LLC
4    This file is part of elfutils.
5 
6    This file is free software; you can redistribute it and/or modify
7    it under the terms of either
8 
9      * the GNU Lesser General Public License as published by the Free
10        Software Foundation; either version 3 of the License, or (at
11        your option) any later version
12 
13    or
14 
15      * the GNU General Public License as published by the Free
16        Software Foundation; either version 2 of the License, or (at
17        your option) any later version
18 
19    or both in parallel, as here.
20 
21    elfutils is distributed in the hope that it will be useful, but
22    WITHOUT ANY WARRANTY; without even the implied warranty of
23    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24    General Public License for more details.
25 
26    You should have received copies of the GNU General Public License and
27    the GNU Lesser General Public License along with this program.  If
28    not, see <http://www.gnu.org/licenses/>.  */
29 
30 #ifdef HAVE_CONFIG_H
31 # include <config.h>
32 #endif
33 
34 #include "../libelf/libelfP.h"
35 #undef	_
36 #include "libdwflP.h"
37 
38 #if !USE_BZLIB
39 # define __libdw_bunzip2(...)	DWFL_E_BADELF
40 #endif
41 
42 #if !USE_LZMA
43 # define __libdw_unlzma(...)	DWFL_E_BADELF
44 #endif
45 
46 #if !USE_ZSTD
47 # define __libdw_unzstd(...)	DWFL_E_BADELF
48 #endif
49 
50 /* Consumes and replaces *ELF only on success.  */
51 static Dwfl_Error
decompress(int fd,Elf ** elf)52 decompress (int fd __attribute__ ((unused)), Elf **elf)
53 {
54   Dwfl_Error error = DWFL_E_BADELF;
55   /* ELF cannot be decompressed, if there is no file descriptor.  */
56   if (fd == -1)
57     return error;
58   void *buffer = NULL;
59   size_t size = 0;
60 
61   const off_t offset = (*elf)->start_offset;
62   void *const mapped = ((*elf)->map_address == NULL ? NULL
63 			: (*elf)->map_address + offset);
64   const size_t mapped_size = (*elf)->maximum_size;
65   if (mapped_size == 0)
66     return error;
67 
68   error = __libdw_gunzip (fd, offset, mapped, mapped_size, &buffer, &size);
69   if (error == DWFL_E_BADELF)
70     error = __libdw_bunzip2 (fd, offset, mapped, mapped_size, &buffer, &size);
71   if (error == DWFL_E_BADELF)
72     error = __libdw_unlzma (fd, offset, mapped, mapped_size, &buffer, &size);
73   if (error == DWFL_E_BADELF)
74     error = __libdw_unzstd (fd, offset, mapped, mapped_size, &buffer, &size);
75 
76   if (error == DWFL_E_NOERROR)
77     {
78       if (unlikely (size == 0))
79 	{
80 	  error = DWFL_E_BADELF;
81 	  free (buffer);
82 	}
83       else
84 	{
85 	  Elf *memelf = elf_memory (buffer, size);
86 	  if (memelf == NULL)
87 	    {
88 	      error = DWFL_E_LIBELF;
89 	      free (buffer);
90 	    }
91 	  else
92 	    {
93 	      memelf->flags |= ELF_F_MALLOCED;
94 	      elf_end (*elf);
95 	      *elf = memelf;
96 	    }
97 	}
98     }
99   else
100     free (buffer);
101 
102   return error;
103 }
104 
105 static Dwfl_Error
what_kind(int fd,Elf ** elfp,Elf_Kind * kind,bool * may_close_fd)106 what_kind (int fd, Elf **elfp, Elf_Kind *kind, bool *may_close_fd)
107 {
108   Dwfl_Error error = DWFL_E_NOERROR;
109   *kind = elf_kind (*elfp);
110   if (unlikely (*kind == ELF_K_NONE))
111     {
112       if (unlikely (*elfp == NULL))
113 	error = DWFL_E_LIBELF;
114       else
115 	{
116 	  error = decompress (fd, elfp);
117 	  if (error == DWFL_E_NOERROR)
118 	    {
119 	      *may_close_fd = true;
120 	      *kind = elf_kind (*elfp);
121 	    }
122 	}
123     }
124   return error;
125 }
126 
127 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,bool use_elfp)128 libdw_open_elf (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok,
129 		bool never_close_fd, bool bad_elf_ok, bool use_elfp)
130 {
131   bool may_close_fd = false;
132 
133   Elf *elf =
134       use_elfp ? *elfp : elf_begin (*fdp, ELF_C_READ_MMAP_PRIVATE, NULL);
135 
136   Elf_Kind kind;
137   Dwfl_Error error = what_kind (*fdp, &elf, &kind, &may_close_fd);
138   if (error == DWFL_E_BADELF)
139     {
140       /* It's not an ELF file or a compressed file.
141 	 See if it's an image with a header preceding the real file.  */
142 
143       off_t offset = elf->start_offset;
144       error = __libdw_image_header (*fdp, &offset,
145 				    (elf->map_address == NULL ? NULL
146 				     : elf->map_address + offset),
147 				    elf->maximum_size);
148       if (error == DWFL_E_NOERROR)
149 	{
150 	  /* Pure evil.  libelf needs some better interfaces.  */
151 	  elf->kind = ELF_K_AR;
152 	  elf->state.ar.elf_ar_hdr.ar_name = "libdwfl is faking you out";
153 	  elf->state.ar.elf_ar_hdr.ar_size = elf->maximum_size - offset;
154 	  elf->state.ar.offset = offset - sizeof (struct ar_hdr);
155 	  Elf *subelf = elf_begin (-1, ELF_C_READ_MMAP_PRIVATE, elf);
156 	  elf->kind = ELF_K_NONE;
157 	  if (unlikely (subelf == NULL))
158 	    error = DWFL_E_LIBELF;
159 	  else
160 	    {
161 	      subelf->parent = NULL;
162 	      subelf->flags |= elf->flags & (ELF_F_MMAPPED | ELF_F_MALLOCED);
163 	      elf->flags &= ~(ELF_F_MMAPPED | ELF_F_MALLOCED);
164 	      elf_end (elf);
165 	      elf = subelf;
166 	      error = what_kind (*fdp, &elf, &kind, &may_close_fd);
167 	    }
168 	}
169     }
170 
171   if (error == DWFL_E_NOERROR
172       && kind != ELF_K_ELF
173       && !(archive_ok && kind == ELF_K_AR))
174     error = DWFL_E_BADELF;
175 
176   /* This basically means, we keep a ELF_K_NONE Elf handle and return it.  */
177   if (bad_elf_ok && error == DWFL_E_BADELF)
178     error = DWFL_E_NOERROR;
179 
180   if (error != DWFL_E_NOERROR)
181     {
182       elf_end (elf);
183       elf = NULL;
184     }
185 
186   if (! never_close_fd
187       && error == DWFL_E_NOERROR ? may_close_fd : close_on_fail)
188     {
189       close (*fdp);
190       *fdp = -1;
191     }
192 
193   *elfp = elf;
194   return error;
195 }
196 
197 Dwfl_Error internal_function
__libdw_open_file(int * fdp,Elf ** elfp,bool close_on_fail,bool archive_ok)198 __libdw_open_file (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok)
199 {
200   return libdw_open_elf (fdp, elfp, close_on_fail, archive_ok, false, false,
201 			 false);
202 }
203 
204 Dwfl_Error internal_function
__libdw_open_elf_memory(char * data,size_t size,Elf ** elfp,bool archive_ok)205 __libdw_open_elf_memory (char *data, size_t size, Elf **elfp, bool archive_ok)
206 {
207   /* It is ok to use `fd == -1` here, because libelf uses it as a value for
208      "no file opened" and code supports working with this value, and also
209      `never_close_fd == false` is passed to prevent closing non-existant file.
210      The only caveat is in `decompress` method, which doesn't support
211      decompressing from memory, so reading compressed zImage using this method
212      won't work.  */
213   int fd = -1;
214   *elfp = elf_memory (data, size);
215   /* Allow using this ELF as reference for subsequent elf_begin calls.  */
216   (*elfp)->cmd = ELF_C_READ_MMAP_PRIVATE;
217   return libdw_open_elf (&fd, elfp, false, archive_ok, true, false, true);
218 }
219 
220 Dwfl_Error internal_function
__libdw_open_elf(int fd,Elf ** elfp)221 __libdw_open_elf (int fd, Elf **elfp)
222 {
223   return libdw_open_elf (&fd, elfp, false, true, true, true, false);
224 }
225