xref: /aosp_15_r20/external/elfutils/libdwfl/open.c (revision 7304104da70ce23c86437a01be71edd1a2d7f37e)
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 "libelfP.h"
35 #include "libdwflP.h"
36 
37 #if !USE_BZLIB
38 # define __libdw_bunzip2(...)	DWFL_E_BADELF
39 #endif
40 
41 #if !USE_LZMA
42 # define __libdw_unlzma(...)	DWFL_E_BADELF
43 #endif
44 
45 #if !USE_ZSTD
46 # define __libdw_unzstd(...)	DWFL_E_BADELF
47 #endif
48 
49 /* Consumes and replaces *ELF only on success.  */
50 static Dwfl_Error
decompress(int fd,Elf ** elf)51 decompress (int fd __attribute__ ((unused)), Elf **elf)
52 {
53   Dwfl_Error error = DWFL_E_BADELF;
54   /* ELF cannot be decompressed, if there is no file descriptor.  */
55   if (fd == -1)
56     return error;
57   void *buffer = NULL;
58   size_t size = 0;
59 
60   const off_t offset = (*elf)->start_offset;
61   void *const mapped = ((*elf)->map_address == NULL ? NULL
62 			: (*elf)->map_address + offset);
63   const size_t mapped_size = (*elf)->maximum_size;
64   if (mapped_size == 0)
65     return error;
66 
67   error = __libdw_gunzip (fd, offset, mapped, mapped_size, &buffer, &size);
68   if (error == DWFL_E_BADELF)
69     error = __libdw_bunzip2 (fd, offset, mapped, mapped_size, &buffer, &size);
70   if (error == DWFL_E_BADELF)
71     error = __libdw_unlzma (fd, offset, mapped, mapped_size, &buffer, &size);
72   if (error == DWFL_E_BADELF)
73     error = __libdw_unzstd (fd, offset, mapped, mapped_size, &buffer, &size);
74 
75   if (error == DWFL_E_NOERROR)
76     {
77       if (unlikely (size == 0))
78 	{
79 	  error = DWFL_E_BADELF;
80 	  free (buffer);
81 	}
82       else
83 	{
84 	  Elf *memelf = elf_memory (buffer, size);
85 	  if (memelf == NULL)
86 	    {
87 	      error = DWFL_E_LIBELF;
88 	      free (buffer);
89 	    }
90 	  else
91 	    {
92 	      memelf->flags |= ELF_F_MALLOCED;
93 	      elf_end (*elf);
94 	      *elf = memelf;
95 	    }
96 	}
97     }
98   else
99     free (buffer);
100 
101   return error;
102 }
103 
104 static Dwfl_Error
what_kind(int fd,Elf ** elfp,Elf_Kind * kind,bool * may_close_fd)105 what_kind (int fd, Elf **elfp, Elf_Kind *kind, bool *may_close_fd)
106 {
107   Dwfl_Error error = DWFL_E_NOERROR;
108   *kind = elf_kind (*elfp);
109   if (unlikely (*kind == ELF_K_NONE))
110     {
111       if (unlikely (*elfp == NULL))
112 	error = DWFL_E_LIBELF;
113       else
114 	{
115 	  error = decompress (fd, elfp);
116 	  if (error == DWFL_E_NOERROR)
117 	    {
118 	      *may_close_fd = true;
119 	      *kind = elf_kind (*elfp);
120 	    }
121 	}
122     }
123   return error;
124 }
125 
126 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)127 libdw_open_elf (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok,
128 		bool never_close_fd, bool bad_elf_ok, bool use_elfp)
129 {
130   bool may_close_fd = false;
131 
132   Elf *elf =
133       use_elfp ? *elfp : elf_begin (*fdp, ELF_C_READ_MMAP_PRIVATE, NULL);
134 
135   Elf_Kind kind;
136   Dwfl_Error error = what_kind (*fdp, &elf, &kind, &may_close_fd);
137   if (error == DWFL_E_BADELF)
138     {
139       /* It's not an ELF file or a compressed file.
140 	 See if it's an image with a header preceding the real file.  */
141 
142       off_t offset = elf->start_offset;
143       error = __libdw_image_header (*fdp, &offset,
144 				    (elf->map_address == NULL ? NULL
145 				     : elf->map_address + offset),
146 				    elf->maximum_size);
147       if (error == DWFL_E_NOERROR)
148 	{
149 	  /* Pure evil.  libelf needs some better interfaces.  */
150 	  elf->kind = ELF_K_AR;
151 	  elf->state.ar.elf_ar_hdr.ar_name = "libdwfl is faking you out";
152 	  elf->state.ar.elf_ar_hdr.ar_size = elf->maximum_size - offset;
153 	  elf->state.ar.offset = offset - sizeof (struct ar_hdr);
154 	  Elf *subelf = elf_begin (-1, elf->cmd, elf);
155 	  elf->kind = ELF_K_NONE;
156 	  if (unlikely (subelf == NULL))
157 	    error = DWFL_E_LIBELF;
158 	  else
159 	    {
160 	      subelf->parent = NULL;
161 	      subelf->flags |= elf->flags & (ELF_F_MMAPPED | ELF_F_MALLOCED);
162 	      elf->flags &= ~(ELF_F_MMAPPED | ELF_F_MALLOCED);
163 	      elf_end (elf);
164 	      elf = subelf;
165 	      error = what_kind (*fdp, &elf, &kind, &may_close_fd);
166 	    }
167 	}
168     }
169 
170   if (error == DWFL_E_NOERROR
171       && kind != ELF_K_ELF
172       && !(archive_ok && kind == ELF_K_AR))
173     error = DWFL_E_BADELF;
174 
175   /* This basically means, we keep a ELF_K_NONE Elf handle and return it.  */
176   if (bad_elf_ok && error == DWFL_E_BADELF)
177     error = DWFL_E_NOERROR;
178 
179   if (error != DWFL_E_NOERROR)
180     {
181       elf_end (elf);
182       elf = NULL;
183     }
184 
185   if (! never_close_fd
186       && error == DWFL_E_NOERROR ? may_close_fd : close_on_fail)
187     {
188       close (*fdp);
189       *fdp = -1;
190     }
191 
192   *elfp = elf;
193   return error;
194 }
195 
196 Dwfl_Error internal_function
__libdw_open_file(int * fdp,Elf ** elfp,bool close_on_fail,bool archive_ok)197 __libdw_open_file (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok)
198 {
199   return libdw_open_elf (fdp, elfp, close_on_fail, archive_ok, false, false,
200 			 false);
201 }
202 
203 Dwfl_Error internal_function
__libdw_open_elf_memory(char * data,size_t size,Elf ** elfp,bool archive_ok)204 __libdw_open_elf_memory (char *data, size_t size, Elf **elfp, bool archive_ok)
205 {
206   /* It is ok to use `fd == -1` here, because libelf uses it as a value for
207      "no file opened" and code supports working with this value, and also
208      `never_close_fd == false` is passed to prevent closing non-existent file.
209      The only caveat is in `decompress` method, which doesn't support
210      decompressing from memory, so reading compressed zImage using this method
211      won't work.  */
212   int fd = -1;
213   *elfp = elf_memory (data, size);
214   if (unlikely(*elfp == NULL))
215     {
216       return DWFL_E_LIBELF;
217     }
218   return libdw_open_elf (&fd, elfp, false, archive_ok, true, false, true);
219 }
220 
221 Dwfl_Error internal_function
__libdw_open_elf(int fd,Elf ** elfp)222 __libdw_open_elf (int fd, Elf **elfp)
223 {
224   return libdw_open_elf (&fd, elfp, false, true, true, true, false);
225 }
226