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