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