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