Line data Source code
1 : /* Compress or decompress a section.
2 : Copyright (C) 2015, 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.h>
34 : #include <system.h>
35 : #include "libelfP.h"
36 : #include "common.h"
37 :
38 : #include <stddef.h>
39 : #include <stdlib.h>
40 : #include <string.h>
41 : #include <unistd.h>
42 : #include <zlib.h>
43 :
44 : /* Cleanup and return result. Don't leak memory. */
45 : static void *
46 : do_deflate_cleanup (void *result, z_stream *z, void *out_buf,
47 : int ei_data, Elf_Data *cdatap)
48 : {
49 44 : deflateEnd (z);
50 44 : free (out_buf);
51 44 : if (ei_data != MY_ELFDATA)
52 19 : free (cdatap->d_buf);
53 : return result;
54 : }
55 :
56 : #define deflate_cleanup(result) \
57 : do_deflate_cleanup(result, &z, out_buf, ei_data, &cdata)
58 :
59 : /* Given a section, uses the (in-memory) Elf_Data to extract the
60 : original data size (including the given header size) and data
61 : alignment. Returns a buffer that has at least hsize bytes (for the
62 : caller to fill in with a header) plus zlib compressed date. Also
63 : returns the new buffer size in new_size (hsize + compressed data
64 : size). Returns (void *) -1 when FORCE is false and the compressed
65 : data would be bigger than the original data. */
66 : void *
67 : internal_function
68 489 : __libelf_compress (Elf_Scn *scn, size_t hsize, int ei_data,
69 : size_t *orig_size, size_t *orig_addralign,
70 : size_t *new_size, bool force)
71 : {
72 : /* The compressed data is the on-disk data. We simplify the
73 : implementation a bit by asking for the (converted) in-memory
74 : data (which might be all there is if the user created it with
75 : elf_newdata) and then convert back to raw if needed before
76 : compressing. Should be made a bit more clever to directly
77 : use raw if that is directly available. */
78 489 : Elf_Data *data = elf_getdata (scn, NULL);
79 489 : if (data == NULL)
80 : return NULL;
81 :
82 : /* When not forced and we immediately know we would use more data by
83 : compressing, because of the header plus zlib overhead (five bytes
84 : per 16 KB block, plus a one-time overhead of six bytes for the
85 : entire stream), don't do anything. */
86 489 : Elf_Data *next_data = elf_getdata (scn, data);
87 489 : if (next_data == NULL && !force
88 348 : && data->d_size <= hsize + 5 + 6)
89 : return (void *) -1;
90 :
91 475 : *orig_addralign = data->d_align;
92 475 : *orig_size = data->d_size;
93 :
94 : /* Guess an output block size. 1/8th of the original Elf_Data plus
95 : hsize. Make the first chunk twice that size (25%), then increase
96 : by a block (12.5%) when necessary. */
97 475 : size_t block = (data->d_size / 8) + hsize;
98 475 : size_t out_size = 2 * block;
99 475 : void *out_buf = malloc (out_size);
100 475 : if (out_buf == NULL)
101 : {
102 0 : __libelf_seterrno (ELF_E_NOMEM);
103 0 : return NULL;
104 : }
105 :
106 : /* Caller gets to fill in the header at the start. Just skip it here. */
107 475 : size_t used = hsize;
108 :
109 : z_stream z;
110 475 : z.zalloc = Z_NULL;
111 475 : z.zfree = Z_NULL;
112 475 : z.opaque = Z_NULL;
113 475 : int zrc = deflateInit (&z, Z_BEST_COMPRESSION);
114 475 : if (zrc != Z_OK)
115 : {
116 0 : free (out_buf);
117 0 : __libelf_seterrno (ELF_E_COMPRESS_ERROR);
118 0 : return NULL;
119 : }
120 :
121 : Elf_Data cdata;
122 475 : cdata.d_buf = NULL;
123 :
124 : /* Loop over data buffers. */
125 475 : int flush = Z_NO_FLUSH;
126 : do
127 : {
128 : /* Convert to raw if different endianess. */
129 475 : cdata = *data;
130 475 : if (ei_data != MY_ELFDATA)
131 : {
132 : /* Don't do this conversion in place, we might want to keep
133 : the original data around, caller decides. */
134 184 : cdata.d_buf = malloc (data->d_size);
135 184 : if (cdata.d_buf == NULL)
136 : {
137 0 : __libelf_seterrno (ELF_E_NOMEM);
138 0 : return deflate_cleanup (NULL);
139 : }
140 184 : if (gelf_xlatetof (scn->elf, &cdata, data, ei_data) == NULL)
141 0 : return deflate_cleanup (NULL);
142 : }
143 :
144 475 : z.avail_in = cdata.d_size;
145 475 : z.next_in = cdata.d_buf;
146 :
147 : /* Get next buffer to see if this is the last one. */
148 475 : data = next_data;
149 475 : if (data != NULL)
150 : {
151 0 : *orig_addralign = MAX (*orig_addralign, data->d_align);
152 0 : *orig_size += data->d_size;
153 0 : next_data = elf_getdata (scn, data);
154 : }
155 : else
156 : flush = Z_FINISH;
157 :
158 : /* Flush one data buffer. */
159 : do
160 : {
161 1079 : z.avail_out = out_size - used;
162 1079 : z.next_out = out_buf + used;
163 1079 : zrc = deflate (&z, flush);
164 1079 : if (zrc == Z_STREAM_ERROR)
165 : {
166 0 : __libelf_seterrno (ELF_E_COMPRESS_ERROR);
167 0 : return deflate_cleanup (NULL);
168 : }
169 1079 : used += (out_size - used) - z.avail_out;
170 :
171 : /* Bail out if we are sure the user doesn't want the
172 : compression forced and we are using more compressed data
173 : than original data. */
174 1079 : if (!force && flush == Z_FINISH && used >= *orig_size)
175 44 : return deflate_cleanup ((void *) -1);
176 :
177 1035 : if (z.avail_out == 0)
178 : {
179 604 : void *bigger = realloc (out_buf, out_size + block);
180 604 : if (bigger == NULL)
181 : {
182 0 : __libelf_seterrno (ELF_E_NOMEM);
183 0 : return deflate_cleanup (NULL);
184 : }
185 : out_buf = bigger;
186 : out_size += block;
187 : }
188 : }
189 1035 : while (z.avail_out == 0); /* Need more output buffer. */
190 :
191 431 : if (ei_data != MY_ELFDATA)
192 : {
193 165 : free (cdata.d_buf);
194 165 : cdata.d_buf = NULL;
195 : }
196 : }
197 431 : while (flush != Z_FINISH); /* More data blocks. */
198 :
199 431 : zrc = deflateEnd (&z);
200 431 : if (zrc != Z_OK)
201 : {
202 0 : __libelf_seterrno (ELF_E_COMPRESS_ERROR);
203 0 : return deflate_cleanup (NULL);
204 : }
205 :
206 431 : *new_size = used;
207 431 : return out_buf;
208 : }
209 :
210 : void *
211 : internal_function
212 707 : __libelf_decompress (void *buf_in, size_t size_in, size_t size_out)
213 : {
214 : /* Catch highly unlikely compression ratios so we don't allocate
215 : some giant amount of memory for nothing. The max compression
216 : factor 1032:1 comes from http://www.zlib.net/zlib_tech.html */
217 707 : if (unlikely (size_out / 1032 > size_in))
218 : {
219 0 : __libelf_seterrno (ELF_E_INVALID_DATA);
220 0 : return NULL;
221 : }
222 :
223 707 : void *buf_out = malloc (size_out);
224 707 : if (unlikely (buf_out == NULL))
225 : {
226 0 : __libelf_seterrno (ELF_E_NOMEM);
227 0 : return NULL;
228 : }
229 :
230 707 : z_stream z =
231 : {
232 : .next_in = buf_in,
233 : .avail_in = size_in,
234 : .next_out = buf_out,
235 : .avail_out = size_out
236 : };
237 707 : int zrc = inflateInit (&z);
238 2121 : while (z.avail_in > 0 && likely (zrc == Z_OK))
239 : {
240 707 : z.next_out = buf_out + (size_out - z.avail_out);
241 707 : zrc = inflate (&z, Z_FINISH);
242 707 : if (unlikely (zrc != Z_STREAM_END))
243 : {
244 : zrc = Z_DATA_ERROR;
245 : break;
246 : }
247 707 : zrc = inflateReset (&z);
248 : }
249 707 : if (likely (zrc == Z_OK))
250 707 : zrc = inflateEnd (&z);
251 :
252 707 : if (unlikely (zrc != Z_OK) || unlikely (z.avail_out != 0))
253 : {
254 0 : free (buf_out);
255 0 : __libelf_seterrno (ELF_E_DECOMPRESS_ERROR);
256 0 : return NULL;
257 : }
258 :
259 : return buf_out;
260 : }
261 :
262 : void *
263 : internal_function
264 447 : __libelf_decompress_elf (Elf_Scn *scn, size_t *size_out, size_t *addralign)
265 : {
266 : GElf_Chdr chdr;
267 447 : if (gelf_getchdr (scn, &chdr) == NULL)
268 : return NULL;
269 :
270 447 : if (chdr.ch_type != ELFCOMPRESS_ZLIB)
271 : {
272 0 : __libelf_seterrno (ELF_E_UNKNOWN_COMPRESSION_TYPE);
273 0 : return NULL;
274 : }
275 :
276 447 : if (! powerof2 (chdr.ch_addralign))
277 : {
278 0 : __libelf_seterrno (ELF_E_INVALID_ALIGN);
279 0 : return NULL;
280 : }
281 :
282 : /* Take the in-memory representation, so we can even handle a
283 : section that has just been constructed (maybe it was copied
284 : over from some other ELF file first with elf_newdata). This
285 : is slightly inefficient when the raw data needs to be
286 : converted since then we'll be converting the whole buffer and
287 : not just Chdr. */
288 447 : Elf_Data *data = elf_getdata (scn, NULL);
289 447 : if (data == NULL)
290 : return NULL;
291 :
292 447 : int elfclass = scn->elf->class;
293 447 : size_t hsize = (elfclass == ELFCLASS32
294 447 : ? sizeof (Elf32_Chdr) : sizeof (Elf64_Chdr));
295 447 : size_t size_in = data->d_size - hsize;
296 447 : void *buf_in = data->d_buf + hsize;
297 447 : void *buf_out = __libelf_decompress (buf_in, size_in, chdr.ch_size);
298 447 : *size_out = chdr.ch_size;
299 447 : *addralign = chdr.ch_addralign;
300 447 : return buf_out;
301 : }
302 :
303 : /* Assumes buf is a malloced buffer. */
304 : void
305 : internal_function
306 1134 : __libelf_reset_rawdata (Elf_Scn *scn, void *buf, size_t size, size_t align,
307 : Elf_Type type)
308 : {
309 : /* This is the new raw data, replace and possibly free old data. */
310 1134 : scn->rawdata.d.d_off = 0;
311 1134 : scn->rawdata.d.d_version = __libelf_version;
312 1134 : scn->rawdata.d.d_buf = buf;
313 1134 : scn->rawdata.d.d_size = size;
314 1134 : scn->rawdata.d.d_align = align;
315 1134 : scn->rawdata.d.d_type = type;
316 :
317 : /* Existing existing data is no longer valid. */
318 1134 : scn->data_list_rear = NULL;
319 1134 : if (scn->data_base != scn->rawdata_base)
320 498 : free (scn->data_base);
321 1134 : scn->data_base = NULL;
322 1134 : if (scn->elf->map_address == NULL
323 330 : || scn->rawdata_base == scn->zdata_base
324 330 : || (scn->flags & ELF_F_MALLOCED) != 0)
325 804 : free (scn->rawdata_base);
326 :
327 1134 : scn->rawdata_base = buf;
328 1134 : scn->flags |= ELF_F_MALLOCED;
329 1134 : }
330 :
331 : int
332 201847 : elf_compress (Elf_Scn *scn, int type, unsigned int flags)
333 : {
334 201847 : if (scn == NULL)
335 : return -1;
336 :
337 201847 : if ((flags & ~ELF_CHF_FORCE) != 0)
338 : {
339 0 : __libelf_seterrno (ELF_E_INVALID_OPERAND);
340 0 : return -1;
341 : }
342 :
343 201847 : bool force = (flags & ELF_CHF_FORCE) != 0;
344 :
345 201847 : Elf *elf = scn->elf;
346 : GElf_Ehdr ehdr;
347 201847 : if (gelf_getehdr (elf, &ehdr) == NULL)
348 : return -1;
349 :
350 201847 : int elfclass = elf->class;
351 201847 : int elfdata = ehdr.e_ident[EI_DATA];
352 :
353 : Elf64_Xword sh_flags;
354 : Elf64_Word sh_type;
355 : Elf64_Xword sh_addralign;
356 201847 : if (elfclass == ELFCLASS32)
357 : {
358 199247 : Elf32_Shdr *shdr = elf32_getshdr (scn);
359 199247 : if (shdr == NULL)
360 : return -1;
361 :
362 199247 : sh_flags = shdr->sh_flags;
363 199247 : sh_type = shdr->sh_type;
364 199247 : sh_addralign = shdr->sh_addralign;
365 : }
366 : else
367 : {
368 2600 : Elf64_Shdr *shdr = elf64_getshdr (scn);
369 2600 : if (shdr == NULL)
370 : return -1;
371 :
372 2600 : sh_flags = shdr->sh_flags;
373 2600 : sh_type = shdr->sh_type;
374 2600 : sh_addralign = shdr->sh_addralign;
375 : }
376 :
377 201847 : if ((sh_flags & SHF_ALLOC) != 0)
378 : {
379 155986 : __libelf_seterrno (ELF_E_INVALID_SECTION_FLAGS);
380 155986 : return -1;
381 : }
382 :
383 45861 : if (sh_type == SHT_NULL || sh_type == SHT_NOBITS)
384 : {
385 20 : __libelf_seterrno (ELF_E_INVALID_SECTION_TYPE);
386 20 : return -1;
387 : }
388 :
389 45841 : int compressed = (sh_flags & SHF_COMPRESSED);
390 45841 : if (type == ELFCOMPRESS_ZLIB)
391 : {
392 : /* Compress/Deflate. */
393 : if (compressed == 1)
394 : {
395 : __libelf_seterrno (ELF_E_ALREADY_COMPRESSED);
396 : return -1;
397 : }
398 :
399 313 : size_t hsize = (elfclass == ELFCLASS32
400 313 : ? sizeof (Elf32_Chdr) : sizeof (Elf64_Chdr));
401 : size_t orig_size, orig_addralign, new_size;
402 313 : void *out_buf = __libelf_compress (scn, hsize, elfdata,
403 : &orig_size, &orig_addralign,
404 : &new_size, force);
405 :
406 : /* Compression would make section larger, don't change anything. */
407 313 : if (out_buf == (void *) -1)
408 : return 0;
409 :
410 : /* Compression failed, return error. */
411 284 : if (out_buf == NULL)
412 : return -1;
413 :
414 : /* Put the header in front of the data. */
415 284 : if (elfclass == ELFCLASS32)
416 : {
417 : Elf32_Chdr chdr;
418 85 : chdr.ch_type = ELFCOMPRESS_ZLIB;
419 85 : chdr.ch_size = orig_size;
420 85 : chdr.ch_addralign = orig_addralign;
421 85 : if (elfdata != MY_ELFDATA)
422 : {
423 48 : CONVERT (chdr.ch_type);
424 96 : CONVERT (chdr.ch_size);
425 96 : CONVERT (chdr.ch_addralign);
426 : }
427 85 : memcpy (out_buf, &chdr, sizeof (Elf32_Chdr));
428 : }
429 : else
430 : {
431 : Elf64_Chdr chdr;
432 199 : chdr.ch_type = ELFCOMPRESS_ZLIB;
433 199 : chdr.ch_reserved = 0;
434 199 : chdr.ch_size = orig_size;
435 199 : chdr.ch_addralign = sh_addralign;
436 199 : if (elfdata != MY_ELFDATA)
437 : {
438 41 : CONVERT (chdr.ch_type);
439 41 : CONVERT (chdr.ch_reserved);
440 82 : CONVERT (chdr.ch_size);
441 82 : CONVERT (chdr.ch_addralign);
442 : }
443 199 : memcpy (out_buf, &chdr, sizeof (Elf64_Chdr));
444 : }
445 :
446 : /* Note we keep the sh_entsize as is, we assume it is setup
447 : correctly and ignored when SHF_COMPRESSED is set. */
448 284 : if (elfclass == ELFCLASS32)
449 : {
450 85 : Elf32_Shdr *shdr = elf32_getshdr (scn);
451 85 : shdr->sh_size = new_size;
452 85 : shdr->sh_addralign = 1;
453 85 : shdr->sh_flags |= SHF_COMPRESSED;
454 : }
455 : else
456 : {
457 199 : Elf64_Shdr *shdr = elf64_getshdr (scn);
458 199 : shdr->sh_size = new_size;
459 199 : shdr->sh_addralign = 1;
460 199 : shdr->sh_flags |= SHF_COMPRESSED;
461 : }
462 :
463 284 : __libelf_reset_rawdata (scn, out_buf, new_size, 1, ELF_T_CHDR);
464 :
465 : /* The section is now compressed, we could keep the uncompressed
466 : data around, but since that might have been multiple Elf_Data
467 : buffers let the user uncompress it explicitly again if they
468 : want it to simplify bookkeeping. */
469 284 : scn->zdata_base = NULL;
470 :
471 284 : return 1;
472 : }
473 45528 : else if (type == 0)
474 : {
475 : /* Decompress/Inflate. */
476 45528 : if (compressed == 0)
477 : {
478 45085 : __libelf_seterrno (ELF_E_NOT_COMPRESSED);
479 45085 : return -1;
480 : }
481 :
482 : /* If the data is already decompressed (by elf_strptr), then we
483 : only need to setup the rawdata and section header. XXX what
484 : about elf_newdata? */
485 443 : if (scn->zdata_base == NULL)
486 : {
487 : size_t size_out, addralign;
488 441 : void *buf_out = __libelf_decompress_elf (scn, &size_out, &addralign);
489 441 : if (buf_out == NULL)
490 0 : return -1;
491 :
492 441 : scn->zdata_base = buf_out;
493 441 : scn->zdata_size = size_out;
494 441 : scn->zdata_align = addralign;
495 : }
496 :
497 : /* Note we keep the sh_entsize as is, we assume it is setup
498 : correctly and ignored when SHF_COMPRESSED is set. */
499 443 : if (elfclass == ELFCLASS32)
500 : {
501 156 : Elf32_Shdr *shdr = elf32_getshdr (scn);
502 156 : shdr->sh_size = scn->zdata_size;
503 156 : shdr->sh_addralign = scn->zdata_align;
504 156 : shdr->sh_flags &= ~SHF_COMPRESSED;
505 : }
506 : else
507 : {
508 287 : Elf64_Shdr *shdr = elf64_getshdr (scn);
509 287 : shdr->sh_size = scn->zdata_size;
510 287 : shdr->sh_addralign = scn->zdata_align;
511 287 : shdr->sh_flags &= ~SHF_COMPRESSED;
512 : }
513 :
514 443 : __libelf_reset_rawdata (scn, scn->zdata_base,
515 : scn->zdata_size, scn->zdata_align,
516 : __libelf_data_type (elf, sh_type));
517 :
518 443 : return 1;
519 : }
520 : else
521 : {
522 0 : __libelf_seterrno (ELF_E_UNKNOWN_COMPRESSION_TYPE);
523 0 : return -1;
524 : }
525 : }
|