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