Coverage Report

Created: 2025-04-11 06:16

/src/elfutils/libelf/elf_compress.c
Line
Count
Source (jump to first uncovered line)
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
11.9k
{
52
11.9k
  deflateEnd (z);
53
11.9k
  free (out_buf);
54
11.9k
  if (cdatap != NULL)
55
8.95k
    free (cdatap->d_buf);
56
11.9k
  return result;
57
11.9k
}
58
59
#define deflate_cleanup(result, cdata) \
60
11.9k
    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
31.1k
{
70
  /* Caller gets to fill in the header at the start.  Just skip it here.  */
71
31.1k
  size_t used = hsize;
72
73
31.1k
  z_stream z;
74
31.1k
  z.zalloc = Z_NULL;
75
31.1k
  z.zfree = Z_NULL;
76
31.1k
  z.opaque = Z_NULL;
77
31.1k
  int zrc = deflateInit (&z, Z_BEST_COMPRESSION);
78
31.1k
  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
31.1k
  Elf_Data cdata;
85
31.1k
  cdata.d_buf = NULL;
86
87
  /* Loop over data buffers.  */
88
31.1k
  int flush = Z_NO_FLUSH;
89
31.1k
  do
90
31.1k
    {
91
      /* Convert to raw if different endianness.  */
92
31.1k
      cdata = *data;
93
31.1k
      bool convert = ei_data != MY_ELFDATA && data->d_size > 0;
94
31.1k
      if (convert)
95
15.9k
  {
96
    /* Don't do this conversion in place, we might want to keep
97
       the original data around, caller decides.  */
98
15.9k
    cdata.d_buf = malloc (data->d_size);
99
15.9k
    if (cdata.d_buf == NULL)
100
0
      {
101
0
        __libelf_seterrno (ELF_E_NOMEM);
102
0
        return deflate_cleanup (NULL, NULL);
103
0
      }
104
15.9k
    if (gelf_xlatetof (scn->elf, &cdata, data, ei_data) == NULL)
105
8.19k
      return deflate_cleanup (NULL, &cdata);
106
15.9k
  }
107
108
22.9k
      z.avail_in = cdata.d_size;
109
22.9k
      z.next_in = cdata.d_buf;
110
111
      /* Get next buffer to see if this is the last one.  */
112
22.9k
      data = next_data;
113
22.9k
      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
22.9k
      else
120
22.9k
  flush = Z_FINISH;
121
122
      /* Flush one data buffer.  */
123
22.9k
      do
124
65.9k
  {
125
65.9k
    z.avail_out = out_size - used;
126
65.9k
    z.next_out = out_buf + used;
127
65.9k
    zrc = deflate (&z, flush);
128
65.9k
    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
65.9k
    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
65.9k
    if (!force && flush == Z_FINISH && used >= *orig_size)
139
3.76k
      return deflate_cleanup ((void *) -1, convert ? &cdata : NULL);
140
141
62.1k
    if (z.avail_out == 0)
142
42.9k
      {
143
42.9k
        void *bigger = realloc (out_buf, out_size + block);
144
42.9k
        if (bigger == NULL)
145
0
    {
146
0
      __libelf_seterrno (ELF_E_NOMEM);
147
0
      return deflate_cleanup (NULL, convert ? &cdata : NULL);
148
0
    }
149
42.9k
        out_buf = bigger;
150
42.9k
        out_size += block;
151
42.9k
      }
152
62.1k
  }
153
62.1k
      while (z.avail_out == 0); /* Need more output buffer.  */
154
155
19.1k
      if (convert)
156
6.98k
  {
157
6.98k
    free (cdata.d_buf);
158
6.98k
    cdata.d_buf = NULL;
159
6.98k
  }
160
19.1k
    }
161
31.1k
  while (flush != Z_FINISH); /* More data blocks.  */
162
163
19.1k
  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
19.1k
  deflateEnd (&z);
170
19.1k
  *new_size = used;
171
19.1k
  return out_buf;
172
19.1k
}
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
265k
{
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
265k
  Elf_Data *data = elf_getdata (scn, NULL);
307
265k
  if (data == NULL)
308
204k
    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
60.3k
  Elf_Data *next_data = elf_getdata (scn, data);
316
60.3k
  if (next_data == NULL && !force
317
60.3k
      && data->d_size <= hsize + 5 + 6)
318
29.1k
    return (void *) -1;
319
320
31.1k
  *orig_addralign = data->d_align;
321
31.1k
  *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
31.1k
  size_t block = (data->d_size / 8) + hsize;
327
31.1k
  size_t out_size = 2 * block;
328
31.1k
  void *out_buf = malloc (out_size);
329
31.1k
  if (out_buf == NULL)
330
0
    {
331
0
      __libelf_seterrno (ELF_E_NOMEM);
332
0
      return NULL;
333
0
    }
334
335
31.1k
  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
31.1k
  else
348
31.1k
    return __libelf_compress_zlib (scn, hsize, ei_data, orig_size,
349
31.1k
           orig_addralign, new_size, force,
350
31.1k
           data, next_data, out_buf, out_size,
351
31.1k
           block);
352
31.1k
}
353
354
void *
355
internal_function
356
__libelf_decompress_zlib (void *buf_in, size_t size_in, size_t size_out)
357
469k
{
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
469k
  if (unlikely (size_out / 1032 > size_in))
362
2.35k
    {
363
2.35k
      __libelf_seterrno (ELF_E_INVALID_DATA);
364
2.35k
      return NULL;
365
2.35k
    }
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
467k
  void *buf_out = malloc (size_out ?: 1);
372
467k
  if (unlikely (buf_out == NULL))
373
0
    {
374
0
      __libelf_seterrno (ELF_E_NOMEM);
375
0
      return NULL;
376
0
    }
377
378
42.2k
  z_stream z =
379
42.2k
    {
380
42.2k
      .next_in = buf_in,
381
42.2k
      .avail_in = size_in,
382
42.2k
      .next_out = buf_out,
383
42.2k
      .avail_out = size_out
384
42.2k
    };
385
42.2k
  int zrc = inflateInit (&z);
386
463k
  while (z.avail_in > 0 && likely (zrc == Z_OK))
387
463k
    {
388
463k
      z.next_out = buf_out + (size_out - z.avail_out);
389
463k
      zrc = inflate (&z, Z_FINISH);
390
463k
      if (unlikely (zrc != Z_STREAM_END))
391
461k
  {
392
461k
    zrc = Z_DATA_ERROR;
393
461k
    break;
394
461k
  }
395
1.62k
      zrc = inflateReset (&z);
396
1.62k
    }
397
398
42.2k
  if (unlikely (zrc != Z_OK) || unlikely (z.avail_out != 0))
399
462k
    {
400
462k
      free (buf_out);
401
462k
      buf_out = NULL;
402
462k
      __libelf_seterrno (ELF_E_DECOMPRESS_ERROR);
403
462k
    }
404
405
42.2k
  inflateEnd(&z);
406
42.2k
  return buf_out;
407
42.2k
}
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
469k
{
440
469k
  if (chtype == ELFCOMPRESS_ZLIB)
441
469k
    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
469k
}
452
453
void *
454
internal_function
455
__libelf_decompress_elf (Elf_Scn *scn, size_t *size_out, size_t *addralign)
456
1.09M
{
457
1.09M
  GElf_Chdr chdr;
458
1.09M
  if (gelf_getchdr (scn, &chdr) == NULL)
459
412k
    return NULL;
460
461
681k
  bool unknown_compression = false;
462
681k
  if (chdr.ch_type != ELFCOMPRESS_ZLIB)
463
210k
    {
464
210k
      if (chdr.ch_type != ELFCOMPRESS_ZSTD)
465
209k
  unknown_compression = true;
466
467
210k
#ifndef USE_ZSTD
468
210k
      if (chdr.ch_type == ELFCOMPRESS_ZSTD)
469
614
  unknown_compression = true;
470
210k
#endif
471
210k
    }
472
473
681k
  if (unknown_compression)
474
210k
    {
475
210k
      __libelf_seterrno (ELF_E_UNKNOWN_COMPRESSION_TYPE);
476
210k
      return NULL;
477
210k
    }
478
479
471k
  if (! powerof2 (chdr.ch_addralign))
480
5.01k
    {
481
5.01k
      __libelf_seterrno (ELF_E_INVALID_ALIGN);
482
5.01k
      return NULL;
483
5.01k
    }
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
466k
  Elf_Data *data = elf_getdata (scn, NULL);
492
466k
  if (data == NULL)
493
0
    return NULL;
494
495
466k
  int elfclass = scn->elf->class;
496
466k
  size_t hsize = (elfclass == ELFCLASS32
497
466k
      ? sizeof (Elf32_Chdr) : sizeof (Elf64_Chdr));
498
466k
  size_t size_in = data->d_size - hsize;
499
466k
  void *buf_in = data->d_buf + hsize;
500
466k
  void *buf_out
501
466k
    = __libelf_decompress (chdr.ch_type, buf_in, size_in, chdr.ch_size);
502
503
466k
  *size_out = chdr.ch_size;
504
466k
  *addralign = chdr.ch_addralign;
505
466k
  return buf_out;
506
466k
}
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
23.3k
{
514
  /* This is the new raw data, replace and possibly free old data.  */
515
23.3k
  scn->rawdata.d.d_off = 0;
516
23.3k
  scn->rawdata.d.d_version = EV_CURRENT;
517
23.3k
  scn->rawdata.d.d_buf = buf;
518
23.3k
  scn->rawdata.d.d_size = size;
519
23.3k
  scn->rawdata.d.d_align = align;
520
23.3k
  scn->rawdata.d.d_type = type;
521
522
  /* Remove the old data.  */
523
23.3k
  Elf_Data_List *runp = scn->data_list.next;
524
23.3k
  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
23.3k
  scn->data_list.next = NULL;
533
23.3k
  scn->data_list_rear = NULL;
534
23.3k
  if (scn->data_base != scn->rawdata_base)
535
9.30k
    free (scn->data_base);
536
23.3k
  scn->data_base = NULL;
537
23.3k
  if (scn->zdata_base != buf
538
23.3k
      && 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
23.3k
  if (scn->elf->map_address == NULL
544
23.3k
      || scn->rawdata_base == scn->zdata_base
545
23.3k
      || (scn->flags & ELF_F_MALLOCED) != 0)
546
20.7k
    {
547
20.7k
      free (scn->rawdata_base);
548
20.7k
      scn->rawdata_base = NULL;
549
20.7k
      scn->zdata_base = NULL;
550
20.7k
    }
551
552
23.3k
  scn->rawdata_base = buf;
553
23.3k
  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
23.3k
  scn->data_read = 1;
558
23.3k
  scn->flags |= ELF_F_FILEDATA;
559
23.3k
  __libelf_set_data_list_rdlock (scn, 1);
560
23.3k
}
561
562
int
563
elf_compress (Elf_Scn *scn, int type, unsigned int flags)
564
1.07M
{
565
1.07M
  if (scn == NULL)
566
0
    return -1;
567
568
1.07M
  if ((flags & ~ELF_CHF_FORCE) != 0)
569
0
    {
570
0
      __libelf_seterrno (ELF_E_INVALID_OPERAND);
571
0
      return -1;
572
0
    }
573
574
1.07M
  bool force = (flags & ELF_CHF_FORCE) != 0;
575
576
1.07M
  Elf *elf = scn->elf;
577
1.07M
  GElf_Ehdr ehdr;
578
1.07M
  if (gelf_getehdr (elf, &ehdr) == NULL)
579
0
    return -1;
580
581
1.07M
  int elfclass = elf->class;
582
1.07M
  int elfdata = ehdr.e_ident[EI_DATA];
583
584
1.07M
  Elf64_Xword sh_flags;
585
1.07M
  Elf64_Word sh_type;
586
1.07M
  Elf64_Xword sh_addralign;
587
1.07M
  union shdr
588
1.07M
  {
589
1.07M
    Elf32_Shdr *s32;
590
1.07M
    Elf64_Shdr *s64;
591
1.07M
  } shdr;
592
1.07M
  if (elfclass == ELFCLASS32)
593
971k
    {
594
971k
      shdr.s32 = elf32_getshdr (scn);
595
971k
      if (shdr.s32 == NULL)
596
0
  return -1;
597
598
971k
      sh_flags = shdr.s32->sh_flags;
599
971k
      sh_type = shdr.s32->sh_type;
600
971k
      sh_addralign = shdr.s32->sh_addralign;
601
971k
    }
602
104k
  else
603
104k
    {
604
104k
      shdr.s64 = elf64_getshdr (scn);
605
104k
      if (shdr.s64 == NULL)
606
0
  return -1;
607
608
104k
      sh_flags = shdr.s64->sh_flags;
609
104k
      sh_type = shdr.s64->sh_type;
610
104k
      sh_addralign = shdr.s64->sh_addralign;
611
104k
    }
612
613
1.07M
  if ((sh_flags & SHF_ALLOC) != 0)
614
495k
    {
615
495k
      __libelf_seterrno (ELF_E_INVALID_SECTION_FLAGS);
616
495k
      return -1;
617
495k
    }
618
619
580k
  if (sh_type == SHT_NULL || sh_type == SHT_NOBITS)
620
45.7k
    {
621
45.7k
      __libelf_seterrno (ELF_E_INVALID_SECTION_TYPE);
622
45.7k
      return -1;
623
45.7k
    }
624
625
534k
  int compressed = (sh_flags & SHF_COMPRESSED);
626
534k
  if (type == ELFCOMPRESS_ZLIB || type == ELFCOMPRESS_ZSTD)
627
265k
    {
628
      /* Compress/Deflate.  */
629
265k
      if (compressed == 1)
630
0
  {
631
0
    __libelf_seterrno (ELF_E_ALREADY_COMPRESSED);
632
0
    return -1;
633
0
  }
634
635
265k
      size_t hsize = (elfclass == ELFCLASS32
636
265k
          ? sizeof (Elf32_Chdr) : sizeof (Elf64_Chdr));
637
265k
      size_t orig_size, orig_addralign, new_size;
638
265k
      void *out_buf = __libelf_compress (scn, hsize, elfdata,
639
265k
           &orig_size, &orig_addralign,
640
265k
           &new_size, force,
641
265k
           type == ELFCOMPRESS_ZSTD);
642
643
      /* Compression would make section larger, don't change anything.  */
644
265k
      if (out_buf == (void *) -1)
645
32.9k
  return 0;
646
647
      /* Compression failed, return error.  */
648
232k
      if (out_buf == NULL)
649
212k
  return -1;
650
651
      /* Put the header in front of the data.  */
652
19.1k
      if (elfclass == ELFCLASS32)
653
18.5k
  {
654
18.5k
    Elf32_Chdr chdr;
655
18.5k
    chdr.ch_type = type;
656
18.5k
    chdr.ch_size = orig_size;
657
18.5k
    chdr.ch_addralign = orig_addralign;
658
18.5k
    if (elfdata != MY_ELFDATA)
659
6.79k
      {
660
6.79k
        CONVERT (chdr.ch_type);
661
6.79k
        CONVERT (chdr.ch_size);
662
6.79k
        CONVERT (chdr.ch_addralign);
663
6.79k
      }
664
18.5k
    memcpy (out_buf, &chdr, sizeof (Elf32_Chdr));
665
18.5k
  }
666
684
      else
667
684
  {
668
684
    Elf64_Chdr chdr;
669
684
    chdr.ch_type = type;
670
684
    chdr.ch_reserved = 0;
671
684
    chdr.ch_size = orig_size;
672
684
    chdr.ch_addralign = sh_addralign;
673
684
    if (elfdata != MY_ELFDATA)
674
186
      {
675
186
        CONVERT (chdr.ch_type);
676
186
        CONVERT (chdr.ch_reserved);
677
186
        CONVERT (chdr.ch_size);
678
186
        CONVERT (chdr.ch_addralign);
679
186
      }
680
684
    memcpy (out_buf, &chdr, sizeof (Elf64_Chdr));
681
684
  }
682
683
      /* Note we keep the sh_entsize as is, we assume it is setup
684
   correctly and ignored when SHF_COMPRESSED is set.  */
685
19.1k
      if (elfclass == ELFCLASS32)
686
18.5k
  {
687
18.5k
    shdr.s32->sh_size = new_size;
688
18.5k
    shdr.s32->sh_addralign = __libelf_type_align (ELFCLASS32,
689
18.5k
              ELF_T_CHDR);
690
18.5k
    shdr.s32->sh_flags |= SHF_COMPRESSED;
691
0
  }
692
684
      else
693
684
  {
694
684
    shdr.s64->sh_size = new_size;
695
684
    shdr.s64->sh_addralign = __libelf_type_align (ELFCLASS64,
696
684
              ELF_T_CHDR);
697
684
    shdr.s64->sh_flags |= SHF_COMPRESSED;
698
0
  }
699
700
19.1k
      __libelf_reset_rawdata (scn, out_buf, new_size, 1, ELF_T_CHDR);
701
702
      /* The section is now compressed, we could keep the uncompressed
703
   data around, but since that might have been multiple Elf_Data
704
   buffers let the user uncompress it explicitly again if they
705
   want it to simplify bookkeeping.  */
706
0
      free (scn->zdata_base);
707
0
      scn->zdata_base = NULL;
708
709
0
      return 1;
710
19.1k
    }
711
269k
  else if (type == 0)
712
269k
    {
713
      /* Decompress/Inflate.  */
714
269k
      if (compressed == 0)
715
0
  {
716
0
    __libelf_seterrno (ELF_E_NOT_COMPRESSED);
717
0
    return -1;
718
0
  }
719
720
      /* If the data is already decompressed (by elf_strptr), then we
721
   only need to setup the rawdata and section header. XXX what
722
   about elf_newdata?  */
723
269k
      if (scn->zdata_base == NULL)
724
269k
  {
725
269k
    size_t size_out, addralign;
726
269k
    void *buf_out = __libelf_decompress_elf (scn, &size_out, &addralign);
727
269k
    if (buf_out == NULL)
728
267k
      return -1;
729
730
2.47k
    scn->zdata_base = buf_out;
731
2.47k
    scn->zdata_size = size_out;
732
2.47k
    scn->zdata_align = addralign;
733
2.47k
  }
734
735
      /* Note we keep the sh_entsize as is, we assume it is setup
736
   correctly and ignored when SHF_COMPRESSED is set.  */
737
2.49k
      if (elfclass == ELFCLASS32)
738
2.44k
  {
739
2.44k
    shdr.s32->sh_size = scn->zdata_size;
740
2.44k
    shdr.s32->sh_addralign = scn->zdata_align;
741
2.44k
    shdr.s32->sh_flags &= ~SHF_COMPRESSED;
742
2.44k
  }
743
54
      else
744
54
  {
745
54
    shdr.s64->sh_size = scn->zdata_size;
746
54
    shdr.s64->sh_addralign = scn->zdata_align;
747
54
    shdr.s64->sh_flags &= ~SHF_COMPRESSED;
748
54
  }
749
750
2.49k
      __libelf_reset_rawdata (scn, scn->zdata_base,
751
2.49k
            scn->zdata_size, scn->zdata_align,
752
2.49k
            __libelf_data_type (&ehdr, sh_type,
753
2.49k
              scn->zdata_align));
754
755
2.49k
      return 1;
756
269k
    }
757
0
  else
758
0
    {
759
0
      __libelf_seterrno (ELF_E_UNKNOWN_COMPRESSION_TYPE);
760
0
      return -1;
761
0
    }
762
534k
}