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 5774 : what_kind (int fd, Elf **elfp, Elf_Kind *kind, bool *may_close_fd)
105 : {
106 5774 : Dwfl_Error error = DWFL_E_NOERROR;
107 5774 : *kind = elf_kind (*elfp);
108 5774 : 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 5774 : return error;
123 : }
124 :
125 : static Dwfl_Error
126 5774 : 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 5774 : bool may_close_fd = false;
130 :
131 5774 : Elf *elf = elf_begin (*fdp, ELF_C_READ_MMAP_PRIVATE, NULL);
132 :
133 5774 : Elf_Kind kind;
134 5774 : Dwfl_Error error = what_kind (*fdp, &elf, &kind, &may_close_fd);
135 5774 : 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 5774 : if (error == DWFL_E_NOERROR
169 5774 : && 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 5774 : if (bad_elf_ok && error == DWFL_E_BADELF)
175 : error = DWFL_E_NOERROR;
176 :
177 5774 : if (error != DWFL_E_NOERROR)
178 : {
179 0 : elf_end (elf);
180 0 : elf = NULL;
181 : }
182 :
183 5774 : if (! never_close_fd
184 5774 : && error == DWFL_E_NOERROR ? may_close_fd : close_on_fail)
185 : {
186 6 : close (*fdp);
187 6 : *fdp = -1;
188 : }
189 :
190 5774 : *elfp = elf;
191 5774 : return error;
192 : }
193 :
194 : Dwfl_Error internal_function
195 5702 : __libdw_open_file (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok)
196 : {
197 5702 : return libdw_open_elf (fdp, elfp, close_on_fail, archive_ok, false, false);
198 : }
199 :
200 : Dwfl_Error internal_function
201 72 : __libdw_open_elf (int fd, Elf **elfp)
202 : {
203 72 : return libdw_open_elf (&fd, elfp, false, true, true, true);
204 : }
|