Branch data Line data Source code
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
52 : 8 : decompress (int fd __attribute__ ((unused)), Elf **elf)
53 : : {
54 : 8 : Dwfl_Error error = DWFL_E_BADELF;
55 : : /* ELF cannot be decompressed, if there is no file descriptor. */
56 [ - + ]: 8 : if (fd == -1)
57 : : return error;
58 : 8 : void *buffer = NULL;
59 : 8 : size_t size = 0;
60 : :
61 : 8 : const off_t offset = (*elf)->start_offset;
62 : 16 : void *const mapped = ((*elf)->map_address == NULL ? NULL
63 [ + - ]: 8 : : (*elf)->map_address + offset);
64 : 8 : const size_t mapped_size = (*elf)->maximum_size;
65 [ - + ]: 8 : if (mapped_size == 0)
66 : : return error;
67 : :
68 : 8 : error = __libdw_gunzip (fd, offset, mapped, mapped_size, &buffer, &size);
69 [ + - ]: 8 : if (error == DWFL_E_BADELF)
70 : 8 : error = __libdw_bunzip2 (fd, offset, mapped, mapped_size, &buffer, &size);
71 [ + + ]: 8 : if (error == DWFL_E_BADELF)
72 : 6 : error = __libdw_unlzma (fd, offset, mapped, mapped_size, &buffer, &size);
73 [ + + ]: 6 : if (error == DWFL_E_BADELF)
74 : 2 : error = __libdw_unzstd (fd, offset, mapped, mapped_size, &buffer, &size);
75 : :
76 [ + - ]: 8 : if (error == DWFL_E_NOERROR)
77 : : {
78 [ - + ]: 8 : if (unlikely (size == 0))
79 : : {
80 : 0 : error = DWFL_E_BADELF;
81 : 0 : free (buffer);
82 : : }
83 : : else
84 : : {
85 : 8 : Elf *memelf = elf_memory (buffer, size);
86 [ - + ]: 8 : if (memelf == NULL)
87 : : {
88 : 0 : error = DWFL_E_LIBELF;
89 : 0 : free (buffer);
90 : : }
91 : : else
92 : : {
93 : 8 : memelf->flags |= ELF_F_MALLOCED;
94 : 8 : elf_end (*elf);
95 : 8 : *elf = memelf;
96 : : }
97 : : }
98 : : }
99 : : else
100 : 0 : free (buffer);
101 : :
102 : : return error;
103 : : }
104 : :
105 : : static Dwfl_Error
106 : 5949 : what_kind (int fd, Elf **elfp, Elf_Kind *kind, bool *may_close_fd)
107 : : {
108 : 5949 : Dwfl_Error error = DWFL_E_NOERROR;
109 : 5949 : *kind = elf_kind (*elfp);
110 [ + + ]: 5949 : if (unlikely (*kind == ELF_K_NONE))
111 : : {
112 [ + - ]: 8 : if (unlikely (*elfp == NULL))
113 : : error = DWFL_E_LIBELF;
114 : : else
115 : : {
116 : 8 : error = decompress (fd, elfp);
117 [ + - ]: 8 : if (error == DWFL_E_NOERROR)
118 : : {
119 : 8 : *may_close_fd = true;
120 : 8 : *kind = elf_kind (*elfp);
121 : : }
122 : : }
123 : : }
124 : 5949 : return error;
125 : : }
126 : :
127 : : static Dwfl_Error
128 : 5949 : 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 : 5949 : bool may_close_fd = false;
132 : :
133 : 11898 : Elf *elf =
134 [ + + ]: 5949 : use_elfp ? *elfp : elf_begin (*fdp, ELF_C_READ_MMAP_PRIVATE, NULL);
135 : :
136 : 5949 : Elf_Kind kind;
137 : 5949 : Dwfl_Error error = what_kind (*fdp, &elf, &kind, &may_close_fd);
138 [ - + ]: 5949 : 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 : 0 : off_t offset = elf->start_offset;
144 : 0 : error = __libdw_image_header (*fdp, &offset,
145 [ # # ]: 0 : (elf->map_address == NULL ? NULL
146 : 0 : : elf->map_address + offset),
147 : : elf->maximum_size);
148 [ # # ]: 0 : if (error == DWFL_E_NOERROR)
149 : : {
150 : : /* Pure evil. libelf needs some better interfaces. */
151 : 0 : elf->kind = ELF_K_AR;
152 : 0 : elf->state.ar.elf_ar_hdr.ar_name = "libdwfl is faking you out";
153 : 0 : elf->state.ar.elf_ar_hdr.ar_size = elf->maximum_size - offset;
154 : 0 : elf->state.ar.offset = offset - sizeof (struct ar_hdr);
155 : 0 : Elf *subelf = elf_begin (-1, ELF_C_READ_MMAP_PRIVATE, elf);
156 : 0 : elf->kind = ELF_K_NONE;
157 [ # # ]: 0 : if (unlikely (subelf == NULL))
158 : : error = DWFL_E_LIBELF;
159 : : else
160 : : {
161 : 0 : subelf->parent = NULL;
162 : 0 : subelf->flags |= elf->flags & (ELF_F_MMAPPED | ELF_F_MALLOCED);
163 : 0 : elf->flags &= ~(ELF_F_MMAPPED | ELF_F_MALLOCED);
164 : 0 : elf_end (elf);
165 : 0 : elf = subelf;
166 : 0 : error = what_kind (*fdp, &elf, &kind, &may_close_fd);
167 : : }
168 : : }
169 : : }
170 : :
171 [ + - ]: 5949 : if (error == DWFL_E_NOERROR
172 [ + + ]: 5949 : && kind != ELF_K_ELF
173 [ + - + - ]: 1 : && !(archive_ok && kind == ELF_K_AR))
174 : 5949 : error = DWFL_E_BADELF;
175 : :
176 : : /* This basically means, we keep a ELF_K_NONE Elf handle and return it. */
177 [ + - ]: 5949 : if (bad_elf_ok && error == DWFL_E_BADELF)
178 : : error = DWFL_E_NOERROR;
179 : :
180 [ - + ]: 5949 : if (error != DWFL_E_NOERROR)
181 : : {
182 : 0 : elf_end (elf);
183 : 0 : elf = NULL;
184 : : }
185 : :
186 [ + + ]: 5949 : if (! never_close_fd
187 [ + + ]: 5949 : && error == DWFL_E_NOERROR ? may_close_fd : close_on_fail)
188 : : {
189 : 6 : close (*fdp);
190 : 6 : *fdp = -1;
191 : : }
192 : :
193 : 5949 : *elfp = elf;
194 : 5949 : return error;
195 : : }
196 : :
197 : : Dwfl_Error internal_function
198 : 5867 : __libdw_open_file (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok)
199 : : {
200 : 5867 : return libdw_open_elf (fdp, elfp, close_on_fail, archive_ok, false, false,
201 : : false);
202 : : }
203 : :
204 : : Dwfl_Error internal_function
205 : 2 : __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 : 2 : int fd = -1;
214 : 2 : *elfp = elf_memory (data, size);
215 : : /* Allow using this ELF as reference for subsequent elf_begin calls. */
216 : 2 : (*elfp)->cmd = ELF_C_READ_MMAP_PRIVATE;
217 : 2 : return libdw_open_elf (&fd, elfp, false, archive_ok, true, false, true);
218 : : }
219 : :
220 : : Dwfl_Error internal_function
221 : 80 : __libdw_open_elf (int fd, Elf **elfp)
222 : : {
223 : 80 : return libdw_open_elf (&fd, elfp, false, true, true, true, false);
224 : : }
|