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