1 /*- 2 * Copyright (c) 2007-2009 Kai Wang 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/param.h> 28 #include <sys/stat.h> 29 #include <err.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <unistd.h> 33 34 #ifndef LIBELF_AR 35 #include <archive.h> 36 #include <archive_entry.h> 37 #endif /* ! LIBELF_AR */ 38 39 #include "elfcopy.h" 40 41 ELFTC_VCSID("$Id: archive.c 3490 2016-08-31 00:12:22Z emaste $"); 42 43 #define _ARMAG_LEN 8 /* length of ar magic string */ 44 #define _ARHDR_LEN 60 /* length of ar header */ 45 #define _INIT_AS_CAP 128 /* initial archive string table size */ 46 #define _INIT_SYMOFF_CAP (256*(sizeof(uint32_t))) /* initial so table size */ 47 #define _INIT_SYMNAME_CAP 1024 /* initial sn table size */ 48 #define _MAXNAMELEN_SVR4 15 /* max member name length in svr4 variant */ 49 50 #ifndef LIBELF_AR 51 static void ac_read_objs(struct elfcopy *ecp, int ifd); 52 static void ac_write_cleanup(struct elfcopy *ecp); 53 static void ac_write_data(struct archive *a, const void *buf, size_t s); 54 static void ac_write_objs(struct elfcopy *ecp, int ofd); 55 #endif /* ! LIBELF_AR */ 56 static void add_to_ar_str_table(struct elfcopy *elfcopy, const char *name); 57 static void add_to_ar_sym_table(struct elfcopy *ecp, const char *name); 58 static void extract_arsym(struct elfcopy *ecp); 59 static void process_ar_obj(struct elfcopy *ecp, struct ar_obj *obj); 60 static void sync_ar(struct elfcopy *ecp); 61 62 63 static void 64 process_ar_obj(struct elfcopy *ecp, struct ar_obj *obj) 65 { 66 struct stat sb; 67 char *tempfile; 68 int fd; 69 70 /* Output to a temporary file. */ 71 create_tempfile(NULL, &tempfile, &fd); 72 if ((ecp->eout = elf_begin(fd, ELF_C_WRITE, NULL)) == NULL) { 73 cleanup_tempfile(tempfile); 74 errx(EXIT_FAILURE, "elf_begin() failed: %s", 75 elf_errmsg(-1)); 76 } 77 elf_flagelf(ecp->eout, ELF_C_SET, ELF_F_LAYOUT); 78 create_elf(ecp); 79 elf_end(ecp->ein); 80 elf_end(ecp->eout); 81 free(obj->buf); 82 obj->buf = NULL; 83 84 /* Extract archive symbols. */ 85 if (lseek(fd, 0, SEEK_SET) < 0) { 86 cleanup_tempfile(tempfile); 87 err(EXIT_FAILURE, "lseek failed for '%s'", tempfile); 88 } 89 if ((ecp->eout = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 90 cleanup_tempfile(tempfile); 91 errx(EXIT_FAILURE, "elf_begin() failed: %s", 92 elf_errmsg(-1)); 93 } 94 extract_arsym(ecp); 95 elf_end(ecp->eout); 96 97 if (fstat(fd, &sb) == -1) { 98 cleanup_tempfile(tempfile); 99 err(EXIT_FAILURE, "fstat %s failed", tempfile); 100 } 101 if (lseek(fd, 0, SEEK_SET) < 0) { 102 cleanup_tempfile(tempfile); 103 err(EXIT_FAILURE, "lseek %s failed", tempfile); 104 } 105 obj->size = sb.st_size; 106 if ((obj->maddr = malloc(obj->size)) == NULL) { 107 cleanup_tempfile(tempfile); 108 err(EXIT_FAILURE, "memory allocation failed for '%s'", 109 tempfile); 110 } 111 if ((size_t) read(fd, obj->maddr, obj->size) != obj->size) { 112 cleanup_tempfile(tempfile); 113 err(EXIT_FAILURE, "read failed for '%s'", tempfile); 114 } 115 if (cleanup_tempfile(tempfile) < 0) 116 err(EXIT_FAILURE, "unlink %s failed", tempfile); 117 free(tempfile); 118 tempfile = NULL; 119 close(fd); 120 if (strlen(obj->name) > _MAXNAMELEN_SVR4) 121 add_to_ar_str_table(ecp, obj->name); 122 ecp->rela_off += _ARHDR_LEN + obj->size + obj->size % 2; 123 STAILQ_INSERT_TAIL(&ecp->v_arobj, obj, objs); 124 } 125 126 /* 127 * Append to the archive string table buffer. 128 */ 129 static void 130 add_to_ar_str_table(struct elfcopy *ecp, const char *name) 131 { 132 133 if (ecp->as == NULL) { 134 ecp->as_cap = _INIT_AS_CAP; 135 ecp->as_sz = 0; 136 if ((ecp->as = malloc(ecp->as_cap)) == NULL) 137 err(EXIT_FAILURE, "malloc failed"); 138 } 139 140 /* 141 * The space required for holding one member name in as table includes: 142 * strlen(name) + (1 for '/') + (1 for '\n') + (possibly 1 for padding). 143 */ 144 while (ecp->as_sz + strlen(name) + 3 > ecp->as_cap) { 145 ecp->as_cap *= 2; 146 ecp->as = realloc(ecp->as, ecp->as_cap); 147 if (ecp->as == NULL) 148 err(EXIT_FAILURE, "realloc failed"); 149 } 150 strncpy(&ecp->as[ecp->as_sz], name, strlen(name)); 151 ecp->as_sz += strlen(name); 152 ecp->as[ecp->as_sz++] = '/'; 153 ecp->as[ecp->as_sz++] = '\n'; 154 } 155 156 /* 157 * Append to the archive symbol table buffer. 158 */ 159 static void 160 add_to_ar_sym_table(struct elfcopy *ecp, const char *name) 161 { 162 163 if (ecp->s_so == NULL) { 164 if ((ecp->s_so = malloc(_INIT_SYMOFF_CAP)) == NULL) 165 err(EXIT_FAILURE, "malloc failed"); 166 ecp->s_so_cap = _INIT_SYMOFF_CAP; 167 ecp->s_cnt = 0; 168 } 169 170 if (ecp->s_sn == NULL) { 171 if ((ecp->s_sn = malloc(_INIT_SYMNAME_CAP)) == NULL) 172 err(EXIT_FAILURE, "malloc failed"); 173 ecp->s_sn_cap = _INIT_SYMNAME_CAP; 174 ecp->s_sn_sz = 0; 175 } 176 177 if (ecp->s_cnt * sizeof(uint32_t) >= ecp->s_so_cap) { 178 ecp->s_so_cap *= 2; 179 ecp->s_so = realloc(ecp->s_so, ecp->s_so_cap); 180 if (ecp->s_so == NULL) 181 err(EXIT_FAILURE, "realloc failed"); 182 } 183 ecp->s_so[ecp->s_cnt] = ecp->rela_off; 184 ecp->s_cnt++; 185 186 /* 187 * The space required for holding one symbol name in sn table includes: 188 * strlen(name) + (1 for '\n') + (possibly 1 for padding). 189 */ 190 while (ecp->s_sn_sz + strlen(name) + 2 > ecp->s_sn_cap) { 191 ecp->s_sn_cap *= 2; 192 ecp->s_sn = realloc(ecp->s_sn, ecp->s_sn_cap); 193 if (ecp->s_sn == NULL) 194 err(EXIT_FAILURE, "realloc failed"); 195 } 196 strncpy(&ecp->s_sn[ecp->s_sn_sz], name, strlen(name)); 197 ecp->s_sn_sz += strlen(name); 198 ecp->s_sn[ecp->s_sn_sz++] = '\0'; 199 } 200 201 static void 202 sync_ar(struct elfcopy *ecp) 203 { 204 size_t s_sz; /* size of archive symbol table. */ 205 size_t pm_sz; /* size of pseudo members */ 206 int i; 207 208 /* 209 * Pad the symbol name string table. It is treated specially because 210 * symbol name table should be padded by a '\0', not the common '\n' 211 * for other members. The size of sn table includes the pad bit. 212 */ 213 if (ecp->s_cnt != 0 && ecp->s_sn_sz % 2 != 0) 214 ecp->s_sn[ecp->s_sn_sz++] = '\0'; 215 216 /* 217 * Archive string table is padded by a "\n" as the normal members. 218 * The difference is that the size of archive string table counts 219 * in the pad bit, while normal members' size fileds do not. 220 */ 221 if (ecp->as != NULL && ecp->as_sz % 2 != 0) 222 ecp->as[ecp->as_sz++] = '\n'; 223 224 /* 225 * If there is a symbol table, calculate the size of pseudo members, 226 * convert previously stored relative offsets to absolute ones, and 227 * then make them Big Endian. 228 * 229 * absolute_offset = htobe32(relative_offset + size_of_pseudo_members) 230 */ 231 232 if (ecp->s_cnt != 0) { 233 s_sz = (ecp->s_cnt + 1) * sizeof(uint32_t) + ecp->s_sn_sz; 234 pm_sz = _ARMAG_LEN + (_ARHDR_LEN + s_sz); 235 if (ecp->as != NULL) 236 pm_sz += _ARHDR_LEN + ecp->as_sz; 237 for (i = 0; (size_t)i < ecp->s_cnt; i++) 238 *(ecp->s_so + i) = htobe32(*(ecp->s_so + i) + 239 pm_sz); 240 } 241 } 242 243 /* 244 * Extract global symbols from archive members. 245 */ 246 static void 247 extract_arsym(struct elfcopy *ecp) 248 { 249 Elf_Scn *scn; 250 GElf_Shdr shdr; 251 GElf_Sym sym; 252 Elf_Data *data; 253 char *name; 254 size_t n, shstrndx; 255 int elferr, tabndx, len, i; 256 257 if (elf_kind(ecp->eout) != ELF_K_ELF) { 258 warnx("internal: cannot extract symbols from non-elf object"); 259 return; 260 } 261 if (elf_getshstrndx(ecp->eout, &shstrndx) == 0) { 262 warnx("elf_getshstrndx failed: %s", elf_errmsg(-1)); 263 return; 264 } 265 266 tabndx = -1; 267 scn = NULL; 268 while ((scn = elf_nextscn(ecp->eout, scn)) != NULL) { 269 if (gelf_getshdr(scn, &shdr) != &shdr) { 270 warnx("elf_getshdr failed: %s", elf_errmsg(-1)); 271 continue; 272 } 273 if ((name = elf_strptr(ecp->eout, shstrndx, shdr.sh_name)) == 274 NULL) { 275 warnx("elf_strptr failed: %s", elf_errmsg(-1)); 276 continue; 277 } 278 if (strcmp(name, ".strtab") == 0) { 279 tabndx = elf_ndxscn(scn); 280 break; 281 } 282 } 283 elferr = elf_errno(); 284 if (elferr != 0) 285 warnx("elf_nextscn failed: %s", elf_errmsg(elferr)); 286 287 /* Ignore members without symbol table. */ 288 if (tabndx == -1) 289 return; 290 291 scn = NULL; 292 while ((scn = elf_nextscn(ecp->eout, scn)) != NULL) { 293 if (gelf_getshdr(scn, &shdr) != &shdr) { 294 warnx("elf_getshdr failed: %s", elf_errmsg(-1)); 295 continue; 296 } 297 if (shdr.sh_type != SHT_SYMTAB) 298 continue; 299 300 data = NULL; 301 n = 0; 302 while (n < shdr.sh_size && 303 (data = elf_getdata(scn, data)) != NULL) { 304 len = data->d_size / shdr.sh_entsize; 305 for (i = 0; i < len; i++) { 306 if (gelf_getsym(data, i, &sym) != &sym) { 307 warnx("gelf_getsym failed: %s", 308 elf_errmsg(-1)); 309 continue; 310 } 311 312 /* keep only global or weak symbols */ 313 if (GELF_ST_BIND(sym.st_info) != STB_GLOBAL && 314 GELF_ST_BIND(sym.st_info) != STB_WEAK) 315 continue; 316 317 /* keep only defined symbols */ 318 if (sym.st_shndx == SHN_UNDEF) 319 continue; 320 321 if ((name = elf_strptr(ecp->eout, tabndx, 322 sym.st_name)) == NULL) { 323 warnx("elf_strptr failed: %s", 324 elf_errmsg(-1)); 325 continue; 326 } 327 328 add_to_ar_sym_table(ecp, name); 329 } 330 } 331 } 332 elferr = elf_errno(); 333 if (elferr != 0) 334 warnx("elf_nextscn failed: %s", elf_errmsg(elferr)); 335 } 336 337 #ifndef LIBELF_AR 338 339 /* 340 * Convenient wrapper for general libarchive error handling. 341 */ 342 #define AC(CALL) do { \ 343 if ((CALL)) \ 344 errx(EXIT_FAILURE, "%s", archive_error_string(a)); \ 345 } while (0) 346 347 /* Earlier versions of libarchive had some functions that returned 'void'. */ 348 #if ARCHIVE_VERSION_NUMBER >= 2000000 349 #define ACV(CALL) AC(CALL) 350 #else 351 #define ACV(CALL) do { \ 352 (CALL); \ 353 } while (0) 354 #endif 355 356 int 357 ac_detect_ar(int ifd) 358 { 359 struct archive *a; 360 struct archive_entry *entry; 361 int r; 362 363 r = -1; 364 if ((a = archive_read_new()) == NULL) 365 return (0); 366 archive_read_support_format_ar(a); 367 if (archive_read_open_fd(a, ifd, 10240) == ARCHIVE_OK) 368 r = archive_read_next_header(a, &entry); 369 archive_read_close(a); 370 archive_read_free(a); 371 372 return (r == ARCHIVE_OK); 373 } 374 375 void 376 ac_create_ar(struct elfcopy *ecp, int ifd, int ofd) 377 { 378 379 ac_read_objs(ecp, ifd); 380 sync_ar(ecp); 381 ac_write_objs(ecp, ofd); 382 ac_write_cleanup(ecp); 383 } 384 385 static void 386 ac_read_objs(struct elfcopy *ecp, int ifd) 387 { 388 struct archive *a; 389 struct archive_entry *entry; 390 struct ar_obj *obj; 391 const char *name; 392 char *buff; 393 size_t size; 394 int r; 395 396 ecp->rela_off = 0; 397 if (lseek(ifd, 0, SEEK_SET) == -1) 398 err(EXIT_FAILURE, "lseek failed"); 399 if ((a = archive_read_new()) == NULL) 400 errx(EXIT_FAILURE, "archive_read_new failed"); 401 archive_read_support_format_ar(a); 402 AC(archive_read_open_fd(a, ifd, 10240)); 403 for(;;) { 404 r = archive_read_next_header(a, &entry); 405 if (r == ARCHIVE_FATAL) 406 errx(EXIT_FAILURE, "%s", archive_error_string(a)); 407 if (r == ARCHIVE_EOF) 408 break; 409 if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY) 410 warnx("%s", archive_error_string(a)); 411 if (r == ARCHIVE_RETRY) 412 continue; 413 414 name = archive_entry_pathname(entry); 415 416 /* skip pseudo members. */ 417 if (strcmp(name, "/") == 0 || strcmp(name, "//") == 0) 418 continue; 419 420 size = archive_entry_size(entry); 421 422 if (size > 0) { 423 if ((buff = malloc(size)) == NULL) 424 err(EXIT_FAILURE, "malloc failed"); 425 if (archive_read_data(a, buff, size) != (ssize_t)size) { 426 warnx("%s", archive_error_string(a)); 427 free(buff); 428 continue; 429 } 430 if ((obj = malloc(sizeof(*obj))) == NULL) 431 err(EXIT_FAILURE, "malloc failed"); 432 if ((obj->name = strdup(name)) == NULL) 433 err(EXIT_FAILURE, "strdup failed"); 434 obj->buf = buff; 435 obj->uid = archive_entry_uid(entry); 436 obj->gid = archive_entry_gid(entry); 437 obj->md = archive_entry_mode(entry); 438 obj->mtime = archive_entry_mtime(entry); 439 if ((ecp->ein = elf_memory(buff, size)) == NULL) 440 errx(EXIT_FAILURE, "elf_memory() failed: %s", 441 elf_errmsg(-1)); 442 if (elf_kind(ecp->ein) != ELF_K_ELF) 443 errx(EXIT_FAILURE, 444 "file format not recognized"); 445 process_ar_obj(ecp, obj); 446 } 447 } 448 AC(archive_read_close(a)); 449 ACV(archive_read_free(a)); 450 } 451 452 static void 453 ac_write_objs(struct elfcopy *ecp, int ofd) 454 { 455 struct archive *a; 456 struct archive_entry *entry; 457 struct ar_obj *obj; 458 time_t timestamp; 459 int nr; 460 461 if ((a = archive_write_new()) == NULL) 462 errx(EXIT_FAILURE, "archive_write_new failed"); 463 archive_write_set_format_ar_svr4(a); 464 AC(archive_write_open_fd(a, ofd)); 465 466 /* Write the archive symbol table, even if it's empty. */ 467 entry = archive_entry_new(); 468 archive_entry_copy_pathname(entry, "/"); 469 if (elftc_timestamp(×tamp) != 0) 470 err(EXIT_FAILURE, "elftc_timestamp"); 471 archive_entry_set_mtime(entry, timestamp, 0); 472 archive_entry_set_size(entry, (ecp->s_cnt + 1) * sizeof(uint32_t) + 473 ecp->s_sn_sz); 474 AC(archive_write_header(a, entry)); 475 nr = htobe32(ecp->s_cnt); 476 ac_write_data(a, &nr, sizeof(uint32_t)); 477 ac_write_data(a, ecp->s_so, sizeof(uint32_t) * ecp->s_cnt); 478 ac_write_data(a, ecp->s_sn, ecp->s_sn_sz); 479 archive_entry_free(entry); 480 481 /* Write the archive string table, if exist. */ 482 if (ecp->as != NULL) { 483 entry = archive_entry_new(); 484 archive_entry_copy_pathname(entry, "//"); 485 archive_entry_set_size(entry, ecp->as_sz); 486 AC(archive_write_header(a, entry)); 487 ac_write_data(a, ecp->as, ecp->as_sz); 488 archive_entry_free(entry); 489 } 490 491 /* Write normal members. */ 492 STAILQ_FOREACH(obj, &ecp->v_arobj, objs) { 493 entry = archive_entry_new(); 494 archive_entry_copy_pathname(entry, obj->name); 495 archive_entry_set_uid(entry, obj->uid); 496 archive_entry_set_gid(entry, obj->gid); 497 archive_entry_set_mode(entry, obj->md); 498 archive_entry_set_size(entry, obj->size); 499 archive_entry_set_mtime(entry, obj->mtime, 0); 500 archive_entry_set_filetype(entry, AE_IFREG); 501 AC(archive_write_header(a, entry)); 502 ac_write_data(a, obj->maddr, obj->size); 503 archive_entry_free(entry); 504 } 505 506 AC(archive_write_close(a)); 507 ACV(archive_write_free(a)); 508 } 509 510 static void 511 ac_write_cleanup(struct elfcopy *ecp) 512 { 513 struct ar_obj *obj, *obj_temp; 514 515 STAILQ_FOREACH_SAFE(obj, &ecp->v_arobj, objs, obj_temp) { 516 STAILQ_REMOVE(&ecp->v_arobj, obj, ar_obj, objs); 517 if (obj->maddr != NULL) 518 free(obj->maddr); 519 free(obj->name); 520 free(obj); 521 } 522 523 free(ecp->as); 524 free(ecp->s_so); 525 free(ecp->s_sn); 526 ecp->as = NULL; 527 ecp->s_so = NULL; 528 ecp->s_sn = NULL; 529 } 530 531 /* 532 * Wrapper for archive_write_data(). 533 */ 534 static void 535 ac_write_data(struct archive *a, const void *buf, size_t s) 536 { 537 if (archive_write_data(a, buf, s) != (ssize_t)s) 538 errx(EXIT_FAILURE, "%s", archive_error_string(a)); 539 } 540 541 #endif /* ! LIBELF_AR */ 542