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