Coverage Report

Created: 2026-07-24 06:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/elfutils/libelf/elf_compress.c
Line
Count
Source
1
/* Compress or decompress a section.
2
   Copyright (C) 2015, 2016 Red Hat, Inc.
3
   Copyright (C) 2023, Mark J. Wielaard <mark@klomp.org>
4
   This file is part of elfutils.
5
6
   This file is free software; you can redistribute it and/or modify
7
   it under the terms of either
8
9
     * the GNU Lesser General Public License as published by the Free
10
       Software Foundation; either version 3 of the License, or (at
11
       your option) any later version
12
13
   or
14
15
     * the GNU General Public License as published by the Free
16
       Software Foundation; either version 2 of the License, or (at
17
       your option) any later version
18
19
   or both in parallel, as here.
20
21
   elfutils is distributed in the hope that it will be useful, but
22
   WITHOUT ANY WARRANTY; without even the implied warranty of
23
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24
   General Public License for more details.
25
26
   You should have received copies of the GNU General Public License and
27
   the GNU Lesser General Public License along with this program.  If
28
   not, see <http://www.gnu.org/licenses/>.  */
29
30
#ifdef HAVE_CONFIG_H
31
# include <config.h>
32
#endif
33
34
#include <libelf.h>
35
#include "libelfP.h"
36
#include "common.h"
37
38
#include <stddef.h>
39
#include <stdlib.h>
40
#include <string.h>
41
#include <zlib.h>
42
43
#ifdef USE_ZSTD
44
#include <zstd.h>
45
#endif
46
47
/* Cleanup and return result.  Don't leak memory.  */
48
static void *
49
do_deflate_cleanup (void *result, z_stream *z, void *out_buf,
50
                    Elf_Data *cdatap)
51
8.45k
{
52
8.45k
  deflateEnd (z);
53
8.45k
  free (out_buf);
54
8.45k
  if (cdatap != NULL)
55
6.03k
    free (cdatap->d_buf);
56
8.45k
  return result;
57
8.45k
}
58
59
#define deflate_cleanup(result, cdata) \
60
8.45k
    do_deflate_cleanup(result, &z, out_buf, cdata)
61
62
static
63
void *
64
__libelf_compress_zlib (Elf_Scn *scn, size_t hsize, int ei_data,
65
      size_t *orig_size, size_t *orig_addralign,
66
      size_t *new_size, bool force,
67
      Elf_Data *data, Elf_Data *next_data,
68
      void *out_buf, size_t out_size, size_t block)
69
28.7k
{
70
  /* Caller gets to fill in the header at the start.  Just skip it here.  */
71
28.7k
  size_t used = hsize;
72
73
28.7k
  z_stream z;
74
28.7k
  z.zalloc = Z_NULL;
75
28.7k
  z.zfree = Z_NULL;
76
28.7k
  z.opaque = Z_NULL;
77
28.7k
  int zrc = deflateInit (&z, Z_BEST_COMPRESSION);
78
28.7k
  if (zrc != Z_OK)
79
0
    {
80
0
      __libelf_seterrno (ELF_E_COMPRESS_ERROR);
81
0
      return deflate_cleanup(NULL, NULL);
82
0
    }
83
84
28.7k
  Elf_Data cdata;
85
28.7k
  cdata.d_buf = NULL;
86
87
  /* Loop over data buffers.  */
88
28.7k
  int flush = Z_NO_FLUSH;
89
28.7k
  do
90
28.7k
    {
91
      /* Convert to raw if different endianness.  */
92
28.7k
      cdata = *data;
93
28.7k
      bool convert = ei_data != MY_ELFDATA && data->d_size > 0;
94
28.7k
      if (convert)
95
12.4k
  {
96
    /* Don't do this conversion in place, we might want to keep
97
       the original data around, caller decides.  */
98
12.4k
    cdata.d_buf = malloc (data->d_size);
99
12.4k
    if (cdata.d_buf == NULL)
100
0
      {
101
0
        __libelf_seterrno (ELF_E_NOMEM);
102
0
        return deflate_cleanup (NULL, NULL);
103
0
      }
104
12.4k
    if (gelf_xlatetof (scn->elf, &cdata, data, ei_data) == NULL)
105
5.11k
      return deflate_cleanup (NULL, &cdata);
106
12.4k
  }
107
108
23.6k
      z.avail_in = cdata.d_size;
109
23.6k
      z.next_in = cdata.d_buf;
110
111
      /* Get next buffer to see if this is the last one.  */
112
23.6k
      data = next_data;
113
23.6k
      if (data != NULL)
114
0
  {
115
0
    *orig_addralign = MAX (*orig_addralign, data->d_align);
116
0
    *orig_size += data->d_size;
117
0
    next_data = elf_getdata (scn, data);
118
0
  }
119
23.6k
      else
120
23.6k
  flush = Z_FINISH;
121
122
      /* Flush one data buffer.  */
123
23.6k
      do
124
67.1k
  {
125
67.1k
    z.avail_out = out_size - used;
126
67.1k
    z.next_out = out_buf + used;
127
67.1k
    zrc = deflate (&z, flush);
128
67.1k
    if (zrc == Z_STREAM_ERROR)
129
0
      {
130
0
        __libelf_seterrno (ELF_E_COMPRESS_ERROR);
131
0
        return deflate_cleanup (NULL, convert ? &cdata : NULL);
132
0
      }
133
67.1k
    used += (out_size - used) - z.avail_out;
134
135
    /* Bail out if we are sure the user doesn't want the
136
       compression forced and we are using more compressed data
137
       than original data.  */
138
67.1k
    if (!force && flush == Z_FINISH && used >= *orig_size)
139
3.34k
      return deflate_cleanup ((void *) -1, convert ? &cdata : NULL);
140
141
63.8k
    if (z.avail_out == 0)
142
43.5k
      {
143
43.5k
        void *bigger = realloc (out_buf, out_size + block);
144
43.5k
        if (bigger == NULL)
145
0
    {
146
0
      __libelf_seterrno (ELF_E_NOMEM);
147
0
      return deflate_cleanup (NULL, convert ? &cdata : NULL);
148
0
    }
149
43.5k
        out_buf = bigger;
150
43.5k
        out_size += block;
151
43.5k
      }
152
63.8k
  }
153
63.8k
      while (z.avail_out == 0); /* Need more output buffer.  */
154
155
20.3k
      if (convert)
156
6.40k
  {
157
6.40k
    free (cdata.d_buf);
158
6.40k
    cdata.d_buf = NULL;
159
6.40k
  }
160
20.3k
    }
161
28.7k
  while (flush != Z_FINISH); /* More data blocks.  */
162
163
20.3k
  if (zrc != Z_STREAM_END)
164
0
    {
165
0
      __libelf_seterrno (ELF_E_COMPRESS_ERROR);
166
0
      return deflate_cleanup (NULL, NULL);
167
0
    }
168
169
20.3k
  deflateEnd (&z);
170
20.3k
  *new_size = used;
171
20.3k
  return out_buf;
172
20.3k
}
173
174
#ifdef USE_ZSTD_COMPRESS
175
/* Cleanup and return result.  Don't leak memory.  */
176
static void *
177
do_zstd_cleanup (void *result, ZSTD_CCtx * const cctx, void *out_buf,
178
     Elf_Data *cdatap)
179
{
180
  ZSTD_freeCCtx (cctx);
181
  free (out_buf);
182
  if (cdatap != NULL)
183
    free (cdatap->d_buf);
184
  return result;
185
}
186
187
#define zstd_cleanup(result, cdata) \
188
    do_zstd_cleanup(result, cctx, out_buf, cdata)
189
190
static
191
void *
192
__libelf_compress_zstd (Elf_Scn *scn, size_t hsize, int ei_data,
193
      size_t *orig_size, size_t *orig_addralign,
194
      size_t *new_size, bool force,
195
      Elf_Data *data, Elf_Data *next_data,
196
      void *out_buf, size_t out_size, size_t block)
197
{
198
  /* Caller gets to fill in the header at the start.  Just skip it here.  */
199
  size_t used = hsize;
200
201
  ZSTD_CCtx* const cctx = ZSTD_createCCtx();
202
  Elf_Data cdata;
203
  cdata.d_buf = NULL;
204
205
  /* Loop over data buffers.  */
206
  ZSTD_EndDirective mode = ZSTD_e_continue;
207
208
  do
209
    {
210
      /* Convert to raw if different endianness.  */
211
      cdata = *data;
212
      bool convert = ei_data != MY_ELFDATA && data->d_size > 0;
213
      if (convert)
214
  {
215
    /* Don't do this conversion in place, we might want to keep
216
       the original data around, caller decides.  */
217
    cdata.d_buf = malloc (data->d_size);
218
    if (cdata.d_buf == NULL)
219
      {
220
        __libelf_seterrno (ELF_E_NOMEM);
221
        return zstd_cleanup (NULL, NULL);
222
      }
223
    if (gelf_xlatetof (scn->elf, &cdata, data, ei_data) == NULL)
224
      return zstd_cleanup (NULL, &cdata);
225
  }
226
227
      ZSTD_inBuffer ib = { cdata.d_buf, cdata.d_size, 0 };
228
229
      /* Get next buffer to see if this is the last one.  */
230
      data = next_data;
231
      if (data != NULL)
232
  {
233
    *orig_addralign = MAX (*orig_addralign, data->d_align);
234
    *orig_size += data->d_size;
235
    next_data = elf_getdata (scn, data);
236
  }
237
      else
238
  mode = ZSTD_e_end;
239
240
      /* Flush one data buffer.  */
241
      for (;;)
242
  {
243
    ZSTD_outBuffer ob = { out_buf + used, out_size - used, 0 };
244
    size_t ret = ZSTD_compressStream2 (cctx, &ob, &ib, mode);
245
    if (ZSTD_isError (ret))
246
      {
247
        __libelf_seterrno (ELF_E_COMPRESS_ERROR);
248
        return zstd_cleanup (NULL, convert ? &cdata : NULL);
249
      }
250
    used += ob.pos;
251
252
    /* Bail out if we are sure the user doesn't want the
253
       compression forced and we are using more compressed data
254
       than original data.  */
255
    if (!force && mode == ZSTD_e_end && used >= *orig_size)
256
      return zstd_cleanup ((void *) -1, convert ? &cdata : NULL);
257
258
    if (ret > 0)
259
      {
260
        void *bigger = realloc (out_buf, out_size + block);
261
        if (bigger == NULL)
262
    {
263
      __libelf_seterrno (ELF_E_NOMEM);
264
      return zstd_cleanup (NULL, convert ? &cdata : NULL);
265
    }
266
        out_buf = bigger;
267
        out_size += block;
268
      }
269
    else
270
      break;
271
  }
272
273
      if (convert)
274
  {
275
    free (cdata.d_buf);
276
    cdata.d_buf = NULL;
277
  }
278
    }
279
  while (mode != ZSTD_e_end); /* More data blocks.  */
280
281
  ZSTD_freeCCtx (cctx);
282
  *new_size = used;
283
  return out_buf;
284
}
285
#endif
286
287
/* Given a section, uses the (in-memory) Elf_Data to extract the
288
   original data size (including the given header size) and data
289
   alignment.  Returns a buffer that has at least hsize bytes (for the
290
   caller to fill in with a header) plus zlib compressed date.  Also
291
   returns the new buffer size in new_size (hsize + compressed data
292
   size).  Returns (void *) -1 when FORCE is false and the compressed
293
   data would be bigger than the original data.  */
294
void *
295
internal_function
296
__libelf_compress (Elf_Scn *scn, size_t hsize, int ei_data,
297
       size_t *orig_size, size_t *orig_addralign,
298
       size_t *new_size, bool force, bool use_zstd)
299
242k
{
300
  /* The compressed data is the on-disk data.  We simplify the
301
     implementation a bit by asking for the (converted) in-memory
302
     data (which might be all there is if the user created it with
303
     elf_newdata) and then convert back to raw if needed before
304
     compressing.  Should be made a bit more clever to directly
305
     use raw if that is directly available.  */
306
242k
  Elf_Data *data = elf_getdata (scn, NULL);
307
242k
  if (data == NULL)
308
194k
    return NULL;
309
310
  /* When not forced and we immediately know we would use more data by
311
     compressing, because of the header plus zlib overhead (five bytes
312
     per 16 KB block, plus a one-time overhead of six bytes for the
313
     entire stream), don't do anything.
314
     Size estimation for ZSTD compression would be similar.  */
315
48.9k
  Elf_Data *next_data = elf_getdata (scn, data);
316
48.9k
  if (next_data == NULL && !force
317
48.9k
      && data->d_size <= hsize + 5 + 6)
318
20.1k
    return (void *) -1;
319
320
28.7k
  *orig_addralign = data->d_align;
321
28.7k
  *orig_size = data->d_size;
322
323
  /* Guess an output block size. 1/8th of the original Elf_Data plus
324
     hsize.  Make the first chunk twice that size (25%), then increase
325
     by a block (12.5%) when necessary.  */
326
28.7k
  size_t block = (data->d_size / 8) + hsize;
327
28.7k
  size_t out_size = 2 * block;
328
28.7k
  void *out_buf = malloc (out_size);
329
28.7k
  if (out_buf == NULL)
330
0
    {
331
0
      __libelf_seterrno (ELF_E_NOMEM);
332
0
      return NULL;
333
0
    }
334
335
28.7k
  if (use_zstd)
336
0
    {
337
#ifdef USE_ZSTD_COMPRESS
338
      return __libelf_compress_zstd (scn, hsize, ei_data, orig_size,
339
           orig_addralign, new_size, force,
340
           data, next_data, out_buf, out_size,
341
           block);
342
#else
343
0
    __libelf_seterrno (ELF_E_UNKNOWN_COMPRESSION_TYPE);
344
0
    return NULL;
345
0
#endif
346
0
    }
347
28.7k
  else
348
28.7k
    return __libelf_compress_zlib (scn, hsize, ei_data, orig_size,
349
28.7k
           orig_addralign, new_size, force,
350
28.7k
           data, next_data, out_buf, out_size,
351
28.7k
           block);
352
28.7k
}
353
354
void *
355
internal_function
356
__libelf_decompress_zlib (void *buf_in, size_t size_in, size_t size_out)
357
75.3k
{
358
  /* Catch highly unlikely compression ratios so we don't allocate
359
     some giant amount of memory for nothing. The max compression
360
     factor 1032:1 comes from http://www.zlib.net/zlib_tech.html  */
361
75.3k
  if (unlikely (size_out / 1032 > size_in))
362
3.76k
    {
363
3.76k
      __libelf_seterrno (ELF_E_INVALID_DATA);
364
3.76k
      return NULL;
365
3.76k
    }
366
367
  /* Malloc might return NULL when requesting zero size.  This is highly
368
     unlikely, it would only happen when the compression was forced.
369
     But we do need a non-NULL buffer to return and set as result.
370
     Just make sure to always allocate at least 1 byte.  */
371
71.5k
  void *buf_out = malloc (size_out ?: 1);
372
71.5k
  if (unlikely (buf_out == NULL))
373
0
    {
374
0
      __libelf_seterrno (ELF_E_NOMEM);
375
0
      return NULL;
376
0
    }
377
378
71.5k
  z_stream z =
379
71.5k
    {
380
71.5k
      .next_in = buf_in,
381
71.5k
      .avail_in = size_in,
382
71.5k
      .next_out = buf_out,
383
71.5k
      .avail_out = size_out
384
71.5k
    };
385
71.5k
  int zrc = inflateInit (&z);
386
73.2k
  while (z.avail_in > 0 && likely (zrc == Z_OK))
387
70.6k
    {
388
70.6k
      z.next_out = buf_out + (size_out - z.avail_out);
389
70.6k
      zrc = inflate (&z, Z_FINISH);
390
70.6k
      if (unlikely (zrc != Z_STREAM_END))
391
68.9k
  {
392
68.9k
    zrc = Z_DATA_ERROR;
393
68.9k
    break;
394
68.9k
  }
395
1.65k
      zrc = inflateReset (&z);
396
1.65k
    }
397
398
71.5k
  if (unlikely (zrc != Z_OK) || unlikely (z.avail_out != 0))
399
69.3k
    {
400
69.3k
      free (buf_out);
401
69.3k
      buf_out = NULL;
402
69.3k
      __libelf_seterrno (ELF_E_DECOMPRESS_ERROR);
403
69.3k
    }
404
405
71.5k
  inflateEnd(&z);
406
71.5k
  return buf_out;
407
71.5k
}
408
409
#ifdef USE_ZSTD
410
static void *
411
__libelf_decompress_zstd (void *buf_in, size_t size_in, size_t size_out)
412
{
413
  /* Malloc might return NULL when requesting zero size.  This is highly
414
     unlikely, it would only happen when the compression was forced.
415
     But we do need a non-NULL buffer to return and set as result.
416
     Just make sure to always allocate at least 1 byte.  */
417
  void *buf_out = malloc (size_out ?: 1);
418
  if (unlikely (buf_out == NULL))
419
    {
420
      __libelf_seterrno (ELF_E_NOMEM);
421
      return NULL;
422
    }
423
424
  size_t ret = ZSTD_decompress (buf_out, size_out, buf_in, size_in);
425
  if (unlikely (ZSTD_isError (ret)) || unlikely (ret != size_out))
426
    {
427
      free (buf_out);
428
      __libelf_seterrno (ELF_E_DECOMPRESS_ERROR);
429
      return NULL;
430
    }
431
  else
432
    return buf_out;
433
}
434
#endif
435
436
void *
437
internal_function
438
__libelf_decompress (int chtype, void *buf_in, size_t size_in, size_t size_out)
439
75.3k
{
440
75.3k
  if (chtype == ELFCOMPRESS_ZLIB)
441
75.3k
    return __libelf_decompress_zlib (buf_in, size_in, size_out);
442
0
  else
443
0
    {
444
#ifdef USE_ZSTD
445
    return __libelf_decompress_zstd (buf_in, size_in, size_out);
446
#else
447
0
    __libelf_seterrno (ELF_E_UNKNOWN_COMPRESSION_TYPE);
448
0
    return NULL;
449
0
#endif
450
0
    }
451
75.3k
}
452
453
void *
454
internal_function
455
__libelf_decompress_elf (Elf_Scn *scn, size_t *size_out, size_t *addralign)
456
626k
{
457
626k
  GElf_Chdr chdr;
458
626k
  if (gelf_getchdr (scn, &chdr) == NULL)
459
361k
    return NULL;
460
461
626k
  bool unknown_compression = false;
462
265k
  if (chdr.ch_type != ELFCOMPRESS_ZLIB)
463
190k
    {
464
190k
      if (chdr.ch_type != ELFCOMPRESS_ZSTD)
465
190k
  unknown_compression = true;
466
467
190k
#ifndef USE_ZSTD
468
190k
      if (chdr.ch_type == ELFCOMPRESS_ZSTD)
469
222
  unknown_compression = true;
470
190k
#endif
471
190k
    }
472
473
265k
  if (unknown_compression)
474
190k
    {
475
190k
      __libelf_seterrno (ELF_E_UNKNOWN_COMPRESSION_TYPE);
476
190k
      return NULL;
477
190k
    }
478
479
74.6k
  if (! powerof2 (chdr.ch_addralign))
480
856
    {
481
856
      __libelf_seterrno (ELF_E_INVALID_ALIGN);
482
856
      return NULL;
483
856
    }
484
485
  /* Take the in-memory representation, so we can even handle a
486
     section that has just been constructed (maybe it was copied
487
     over from some other ELF file first with elf_newdata).  This
488
     is slightly inefficient when the raw data needs to be
489
     converted since then we'll be converting the whole buffer and
490
     not just Chdr.  */
491
73.7k
  Elf_Data *data = elf_getdata (scn, NULL);
492
73.7k
  if (data == NULL)
493
0
    return NULL;
494
495
73.7k
  int elfclass = scn->elf->class;
496
73.7k
  size_t hsize = (elfclass == ELFCLASS32
497
73.7k
      ? sizeof (Elf32_Chdr) : sizeof (Elf64_Chdr));
498
73.7k
  size_t size_in = data->d_size - hsize;
499
73.7k
  void *buf_in = data->d_buf + hsize;
500
73.7k
  void *buf_out
501
73.7k
    = __libelf_decompress (chdr.ch_type, buf_in, size_in, chdr.ch_size);
502
503
73.7k
  *size_out = chdr.ch_size;
504
73.7k
  *addralign = chdr.ch_addralign;
505
73.7k
  return buf_out;
506
73.7k
}
507
508
/* Assumes buf is a malloced buffer.  */
509
void
510
internal_function
511
__libelf_reset_rawdata (Elf_Scn *scn, void *buf, size_t size, size_t align,
512
      Elf_Type type)
513
21.7k
{
514
  /* This is the new raw data, replace and possibly free old data.  */
515
21.7k
  scn->rawdata.d.d_off = 0;
516
21.7k
  scn->rawdata.d.d_version = EV_CURRENT;
517
21.7k
  scn->rawdata.d.d_buf = buf;
518
21.7k
  scn->rawdata.d.d_size = size;
519
21.7k
  scn->rawdata.d.d_align = align;
520
21.7k
  scn->rawdata.d.d_type = type;
521
522
  /* Remove the old data.  */
523
21.7k
  Elf_Data_List *runp = scn->data_list.next;
524
21.7k
  while (runp != NULL)
525
0
    {
526
0
      Elf_Data_List *oldp = runp;
527
0
      runp = runp->next;
528
0
      if ((oldp->flags & ELF_F_MALLOCED) != 0)
529
0
  free (oldp);
530
0
    }
531
  /* Existing existing data is no longer valid.  */
532
21.7k
  scn->data_list.next = NULL;
533
21.7k
  scn->data_list_rear = NULL;
534
21.7k
  if (scn->data_base != scn->rawdata_base)
535
7.14k
    free (scn->data_base);
536
21.7k
  scn->data_base = NULL;
537
21.7k
  if (scn->zdata_base != buf
538
20.8k
      && scn->zdata_base != scn->rawdata_base)
539
20.8k
    {
540
20.8k
      free (scn->zdata_base);
541
20.8k
      scn->zdata_base = NULL;
542
20.8k
    }
543
21.7k
  if (scn->elf->map_address == NULL
544
0
      || scn->rawdata_base == scn->zdata_base
545
0
      || (scn->flags & ELF_F_MALLOCED) != 0)
546
21.7k
    {
547
21.7k
      free (scn->rawdata_base);
548
21.7k
      scn->rawdata_base = NULL;
549
21.7k
      scn->zdata_base = NULL;
550
21.7k
    }
551
552
21.7k
  scn->rawdata_base = buf;
553
21.7k
  scn->flags |= ELF_F_MALLOCED;
554
555
  /* Pretend we (tried to) read the data from the file and setup the
556
     data (might have to convert the Chdr to native format).  */
557
21.7k
  scn->data_read = 1;
558
21.7k
  scn->flags |= ELF_F_FILEDATA;
559
21.7k
  __libelf_set_data_list_rdlock (scn, 1);
560
21.7k
}
561
562
int
563
elf_compress (Elf_Scn *scn, int type, unsigned int flags)
564
961k
{
565
961k
  if (scn == NULL)
566
0
    return -1;
567
568
961k
  if ((flags & ~ELF_CHF_FORCE) != 0)
569
0
    {
570
0
      __libelf_seterrno (ELF_E_INVALID_OPERAND);
571
0
      return -1;
572
0
    }
573
574
961k
  bool force = (flags & ELF_CHF_FORCE) != 0;
575
576
961k
  Elf *elf = scn->elf;
577
961k
  GElf_Ehdr ehdr;
578
961k
  if (gelf_getehdr (elf, &ehdr) == NULL)
579
0
    return -1;
580
581
961k
  int elfclass = elf->class;
582
961k
  int elfdata = ehdr.e_ident[EI_DATA];
583
584
961k
  Elf64_Xword sh_flags;
585
961k
  Elf64_Word sh_type;
586
961k
  union shdr
587
961k
  {
588
961k
    Elf32_Shdr *s32;
589
961k
    Elf64_Shdr *s64;
590
961k
  } shdr;
591
961k
  if (elfclass == ELFCLASS32)
592
817k
    {
593
817k
      shdr.s32 = elf32_getshdr (scn);
594
817k
      if (shdr.s32 == NULL)
595
0
  return -1;
596
597
817k
      sh_flags = shdr.s32->sh_flags;
598
817k
      sh_type = shdr.s32->sh_type;
599
817k
    }
600
144k
  else
601
144k
    {
602
144k
      shdr.s64 = elf64_getshdr (scn);
603
144k
      if (shdr.s64 == NULL)
604
0
  return -1;
605
606
144k
      sh_flags = shdr.s64->sh_flags;
607
144k
      sh_type = shdr.s64->sh_type;
608
144k
    }
609
610
961k
  if ((sh_flags & SHF_ALLOC) != 0)
611
438k
    {
612
438k
      __libelf_seterrno (ELF_E_INVALID_SECTION_FLAGS);
613
438k
      return -1;
614
438k
    }
615
616
523k
  if (sh_type == SHT_NULL || sh_type == SHT_NOBITS)
617
37.4k
    {
618
37.4k
      __libelf_seterrno (ELF_E_INVALID_SECTION_TYPE);
619
37.4k
      return -1;
620
37.4k
    }
621
622
485k
  int compressed = (sh_flags & SHF_COMPRESSED);
623
485k
  if (type == ELFCOMPRESS_ZLIB || type == ELFCOMPRESS_ZSTD)
624
242k
    {
625
      /* Compress/Deflate.  */
626
242k
      if (compressed == 1)
627
0
  {
628
0
    __libelf_seterrno (ELF_E_ALREADY_COMPRESSED);
629
0
    return -1;
630
0
  }
631
632
242k
      size_t hsize = (elfclass == ELFCLASS32
633
242k
          ? sizeof (Elf32_Chdr) : sizeof (Elf64_Chdr));
634
242k
      size_t orig_size, orig_addralign, new_size;
635
242k
      void *out_buf = __libelf_compress (scn, hsize, elfdata,
636
242k
           &orig_size, &orig_addralign,
637
242k
           &new_size, force,
638
242k
           type == ELFCOMPRESS_ZSTD);
639
640
      /* Compression would make section larger, don't change anything.  */
641
242k
      if (out_buf == (void *) -1)
642
23.4k
  return 0;
643
644
      /* Compression failed, return error.  */
645
219k
      if (out_buf == NULL)
646
199k
  return -1;
647
648
      /* Put the header in front of the data.  */
649
20.3k
      if (elfclass == ELFCLASS32)
650
19.3k
  {
651
19.3k
    Elf32_Chdr chdr;
652
19.3k
    chdr.ch_type = type;
653
19.3k
    chdr.ch_size = orig_size;
654
19.3k
    chdr.ch_addralign = orig_addralign;
655
19.3k
    if (elfdata != MY_ELFDATA)
656
6.22k
      {
657
6.22k
        CONVERT (chdr.ch_type);
658
6.22k
        CONVERT (chdr.ch_size);
659
6.22k
        CONVERT (chdr.ch_addralign);
660
6.22k
      }
661
19.3k
    memcpy (out_buf, &chdr, sizeof (Elf32_Chdr));
662
19.3k
  }
663
949
      else
664
949
  {
665
949
    Elf64_Chdr chdr;
666
949
    chdr.ch_type = type;
667
949
    chdr.ch_reserved = 0;
668
949
    chdr.ch_size = orig_size;
669
949
    chdr.ch_addralign = orig_addralign;
670
949
    if (elfdata != MY_ELFDATA)
671
180
      {
672
180
        CONVERT (chdr.ch_type);
673
180
        CONVERT (chdr.ch_reserved);
674
180
        CONVERT (chdr.ch_size);
675
180
        CONVERT (chdr.ch_addralign);
676
180
      }
677
949
    memcpy (out_buf, &chdr, sizeof (Elf64_Chdr));
678
949
  }
679
680
      /* Note we keep the sh_entsize as is, we assume it is setup
681
   correctly and ignored when SHF_COMPRESSED is set.  */
682
20.3k
      if (elfclass == ELFCLASS32)
683
19.3k
  {
684
19.3k
    shdr.s32->sh_size = new_size;
685
19.3k
    shdr.s32->sh_addralign = __libelf_type_align (ELFCLASS32,
686
19.3k
              ELF_T_CHDR);
687
19.3k
    shdr.s32->sh_flags |= SHF_COMPRESSED;
688
19.3k
  }
689
949
      else
690
949
  {
691
949
    shdr.s64->sh_size = new_size;
692
949
    shdr.s64->sh_addralign = __libelf_type_align (ELFCLASS64,
693
949
              ELF_T_CHDR);
694
949
    shdr.s64->sh_flags |= SHF_COMPRESSED;
695
949
  }
696
697
20.3k
      __libelf_reset_rawdata (scn, out_buf, new_size, 1, ELF_T_CHDR);
698
699
      /* The section is now compressed, we could keep the uncompressed
700
   data around, but since that might have been multiple Elf_Data
701
   buffers let the user uncompress it explicitly again if they
702
   want it to simplify bookkeeping.  */
703
20.3k
      free (scn->zdata_base);
704
20.3k
      scn->zdata_base = NULL;
705
706
20.3k
      return 1;
707
219k
    }
708
242k
  else if (type == 0)
709
242k
    {
710
      /* Decompress/Inflate.  */
711
242k
      if (compressed == 0)
712
0
  {
713
0
    __libelf_seterrno (ELF_E_NOT_COMPRESSED);
714
0
    return -1;
715
0
  }
716
717
      /* If the data is already decompressed (by elf_strptr), then we
718
   only need to setup the rawdata and section header. XXX what
719
   about elf_newdata?  */
720
242k
      if (scn->zdata_base == NULL)
721
242k
  {
722
242k
    size_t size_out, addralign;
723
242k
    void *buf_out = __libelf_decompress_elf (scn, &size_out, &addralign);
724
242k
    if (buf_out == NULL)
725
242k
      return -1;
726
727
848
    scn->zdata_base = buf_out;
728
848
    scn->zdata_size = size_out;
729
848
    scn->zdata_align = addralign;
730
848
  }
731
732
      /* Note we keep the sh_entsize as is, we assume it is setup
733
   correctly and ignored when SHF_COMPRESSED is set.  */
734
866
      if (elfclass == ELFCLASS32)
735
814
  {
736
814
    shdr.s32->sh_size = scn->zdata_size;
737
814
    shdr.s32->sh_addralign = scn->zdata_align;
738
814
    shdr.s32->sh_flags &= ~SHF_COMPRESSED;
739
814
  }
740
52
      else
741
52
  {
742
52
    shdr.s64->sh_size = scn->zdata_size;
743
52
    shdr.s64->sh_addralign = scn->zdata_align;
744
52
    shdr.s64->sh_flags &= ~SHF_COMPRESSED;
745
52
  }
746
747
866
      __libelf_reset_rawdata (scn, scn->zdata_base,
748
866
            scn->zdata_size, scn->zdata_align,
749
866
            __libelf_data_type (&ehdr, sh_type,
750
866
              scn->zdata_align));
751
752
866
      return 1;
753
242k
    }
754
0
  else
755
0
    {
756
0
      __libelf_seterrno (ELF_E_UNKNOWN_COMPRESSION_TYPE);
757
0
      return -1;
758
0
    }
759
485k
}