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