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 3102 2014-10-29 21:09:01Z 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_format_ar(a); 354 if (archive_read_open_fd(a, ifd, 10240) == ARCHIVE_OK) 355 r = archive_read_next_header(a, &entry); 356 archive_read_close(a); 357 archive_read_free(a); 358 359 return (r == ARCHIVE_OK); 360 } 361 362 void 363 ac_create_ar(struct elfcopy *ecp, int ifd, int ofd) 364 { 365 366 ac_read_objs(ecp, ifd); 367 sync_ar(ecp); 368 ac_write_objs(ecp, ofd); 369 ac_write_cleanup(ecp); 370 } 371 372 static void 373 ac_read_objs(struct elfcopy *ecp, int ifd) 374 { 375 struct archive *a; 376 struct archive_entry *entry; 377 struct ar_obj *obj; 378 const char *name; 379 char *buff; 380 size_t size; 381 int r; 382 383 ecp->rela_off = 0; 384 if (lseek(ifd, 0, SEEK_SET) == -1) 385 err(EXIT_FAILURE, "lseek failed"); 386 if ((a = archive_read_new()) == NULL) 387 errx(EXIT_FAILURE, "%s", archive_error_string(a)); 388 archive_read_support_format_ar(a); 389 AC(archive_read_open_fd(a, ifd, 10240)); 390 for(;;) { 391 r = archive_read_next_header(a, &entry); 392 if (r == ARCHIVE_FATAL) 393 errx(EXIT_FAILURE, "%s", archive_error_string(a)); 394 if (r == ARCHIVE_EOF) 395 break; 396 if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY) 397 warnx("%s", archive_error_string(a)); 398 if (r == ARCHIVE_RETRY) 399 continue; 400 401 name = archive_entry_pathname(entry); 402 403 /* skip pseudo members. */ 404 if (strcmp(name, "/") == 0 || strcmp(name, "//") == 0) 405 continue; 406 407 size = archive_entry_size(entry); 408 409 if (size > 0) { 410 if ((buff = malloc(size)) == NULL) 411 err(EXIT_FAILURE, "malloc failed"); 412 if (archive_read_data(a, buff, size) != (ssize_t)size) { 413 warnx("%s", archive_error_string(a)); 414 free(buff); 415 continue; 416 } 417 if ((obj = malloc(sizeof(*obj))) == NULL) 418 err(EXIT_FAILURE, "malloc failed"); 419 if ((obj->name = strdup(name)) == NULL) 420 err(EXIT_FAILURE, "strdup failed"); 421 obj->buf = buff; 422 obj->uid = archive_entry_uid(entry); 423 obj->gid = archive_entry_gid(entry); 424 obj->md = archive_entry_mode(entry); 425 obj->mtime = archive_entry_mtime(entry); 426 if ((ecp->ein = elf_memory(buff, size)) == NULL) 427 errx(EXIT_FAILURE, "elf_memory() failed: %s", 428 elf_errmsg(-1)); 429 if (elf_kind(ecp->ein) != ELF_K_ELF) 430 errx(EXIT_FAILURE, 431 "file format not recognized"); 432 process_ar_obj(ecp, obj); 433 } 434 } 435 AC(archive_read_close(a)); 436 ACV(archive_read_free(a)); 437 } 438 439 static void 440 ac_write_objs(struct elfcopy *ecp, int ofd) 441 { 442 struct archive *a; 443 struct archive_entry *entry; 444 struct ar_obj *obj; 445 int nr; 446 447 if ((a = archive_write_new()) == NULL) 448 errx(EXIT_FAILURE, "%s", archive_error_string(a)); 449 archive_write_set_format_ar_svr4(a); 450 AC(archive_write_open_fd(a, ofd)); 451 452 /* Write the archive symbol table, even if it's empty. */ 453 entry = archive_entry_new(); 454 archive_entry_copy_pathname(entry, "/"); 455 archive_entry_set_mtime(entry, time(NULL), 0); 456 archive_entry_set_size(entry, (ecp->s_cnt + 1) * sizeof(uint32_t) + 457 ecp->s_sn_sz); 458 AC(archive_write_header(a, entry)); 459 nr = htobe32(ecp->s_cnt); 460 ac_write_data(a, &nr, sizeof(uint32_t)); 461 ac_write_data(a, ecp->s_so, sizeof(uint32_t) * ecp->s_cnt); 462 ac_write_data(a, ecp->s_sn, ecp->s_sn_sz); 463 archive_entry_free(entry); 464 465 /* Write the archive string table, if exist. */ 466 if (ecp->as != NULL) { 467 entry = archive_entry_new(); 468 archive_entry_copy_pathname(entry, "//"); 469 archive_entry_set_size(entry, ecp->as_sz); 470 AC(archive_write_header(a, entry)); 471 ac_write_data(a, ecp->as, ecp->as_sz); 472 archive_entry_free(entry); 473 } 474 475 /* Write normal members. */ 476 STAILQ_FOREACH(obj, &ecp->v_arobj, objs) { 477 entry = archive_entry_new(); 478 archive_entry_copy_pathname(entry, obj->name); 479 archive_entry_set_uid(entry, obj->uid); 480 archive_entry_set_gid(entry, obj->gid); 481 archive_entry_set_mode(entry, obj->md); 482 archive_entry_set_size(entry, obj->size); 483 archive_entry_set_mtime(entry, obj->mtime, 0); 484 archive_entry_set_filetype(entry, AE_IFREG); 485 AC(archive_write_header(a, entry)); 486 ac_write_data(a, obj->maddr, obj->size); 487 archive_entry_free(entry); 488 } 489 490 AC(archive_write_close(a)); 491 ACV(archive_write_free(a)); 492 } 493 494 static void 495 ac_write_cleanup(struct elfcopy *ecp) 496 { 497 struct ar_obj *obj, *obj_temp; 498 499 STAILQ_FOREACH_SAFE(obj, &ecp->v_arobj, objs, obj_temp) { 500 STAILQ_REMOVE(&ecp->v_arobj, obj, ar_obj, objs); 501 if (obj->maddr != NULL) 502 free(obj->maddr); 503 free(obj->name); 504 free(obj); 505 } 506 507 free(ecp->as); 508 free(ecp->s_so); 509 free(ecp->s_sn); 510 ecp->as = NULL; 511 ecp->s_so = NULL; 512 ecp->s_sn = NULL; 513 } 514 515 /* 516 * Wrapper for archive_write_data(). 517 */ 518 static void 519 ac_write_data(struct archive *a, const void *buf, size_t s) 520 { 521 if (archive_write_data(a, buf, s) != (ssize_t)s) 522 errx(EXIT_FAILURE, "%s", archive_error_string(a)); 523 } 524 525 #endif /* ! LIBELF_AR */ 526