1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 1988 AT&T
24 * All Rights Reserved
25 *
26 * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
27 */
28 /*
29 * Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
30 */
31
32 #include <errno.h>
33 #include "alist.h"
34 #include "mcs.h"
35 #include "extern.h"
36 #include "gelf.h"
37
38 /*
39 * Type used to pass state information for the current
40 * file between routines.
41 */
42 typedef struct {
43 int Sect_exists;
44 int notesegndx;
45 int notesctndx;
46 Seg_Table *b_e_seg_table;
47 section_info_table *sec_table;
48 int64_t *off_table; /* maintains section's offset; set to */
49 /* retain old offset, else 0 */
50 int64_t *nobits_table; /* maintains NOBITS sections */
51 char *new_sec_string;
52 } file_state_t;
53
54
55 /*
56 * Function prototypes.
57 */
58 static void copy_file(int, char *, Tmp_File *);
59 static void
60 copy_non_elf_to_temp_ar(int, Elf *, int, Elf_Arhdr *, char *, Cmd_Info *);
61 static void copy_elf_file_to_temp_ar_file(int, Elf_Arhdr *, char *);
62 static int process_file(Elf *, char *, Cmd_Info *);
63 static void initialize(int shnum, Cmd_Info *, file_state_t *);
64 static int build_segment_table(Elf*, GElf_Ehdr *, file_state_t *);
65 static int traverse_file(Elf *, GElf_Ehdr *, char *, Cmd_Info *,
66 file_state_t *);
67 static uint64_t location(int64_t, int, Elf *, file_state_t *);
68 static uint64_t scn_location(Elf_Scn *, Elf *, file_state_t *);
69 static int build_file(Elf *, GElf_Ehdr *, Cmd_Info *, file_state_t *);
70 static void post_process(Cmd_Info *, file_state_t *);
71
72
73
74 int
each_file(char * cur_file,Cmd_Info * cmd_info)75 each_file(char *cur_file, Cmd_Info *cmd_info)
76 {
77 Elf *elf = 0;
78 Elf_Cmd cmd;
79 Elf *arf = 0;
80 Elf_Arhdr *mem_header;
81 char *cur_filenm = NULL;
82 int code = 0;
83 int error = 0, err = 0;
84 int ar_file = 0;
85 int fdartmp;
86 int fd;
87 int oflag;
88
89 if (CHK_OPT(cmd_info, MIGHT_CHG))
90 oflag = O_RDWR;
91 else
92 oflag = O_RDONLY;
93
94 if ((fd = open(cur_file, oflag)) == -1) {
95 error_message(OPEN_ERROR, SYSTEM_ERROR, strerror(errno),
96 prog, cur_file);
97 return (FAILURE);
98 }
99
100 /*
101 * Note, elf_begin requires ELF_C_READ even if MIGHT_CHK is in effect.
102 * libelf does not allow elf_begin() with ELF_C_RDWR when processing
103 * archive file members. Because we are limited to ELF_C_READ use, any
104 * ELF data modification must be provided by updating a copy of
105 * the data, rather than updating the original file data.
106 */
107 cmd = ELF_C_READ;
108 if ((arf = elf_begin(fd, cmd, NULL)) == NULL) {
109 error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog);
110 (void) elf_end(arf);
111 (void) close(fd); /* done processing this file */
112 return (FAILURE);
113 }
114
115 if ((elf_kind(arf) == ELF_K_AR)) {
116 ar_file = 1;
117 if (CHK_OPT(cmd_info, MIGHT_CHG)) {
118 artmpfile.tmp_name = tempnam(TMPDIR, "mcs2");
119 if ((fdartmp = open(artmpfile.tmp_name,
120 O_WRONLY | O_APPEND | O_CREAT,
121 (mode_t)0666)) == 0) {
122 error_message(OPEN_TEMP_ERROR,
123 SYSTEM_ERROR, strerror(errno),
124 prog, artmpfile);
125 (void) elf_end(arf);
126 (void) close(fd);
127 mcs_exit(FAILURE);
128 }
129 artmpfile.tmp_unlink = 1;
130 /* write magic string to artmpfile */
131 if ((write(fdartmp, ARMAG, SARMAG)) != SARMAG) {
132 error_message(WRITE_ERROR,
133 SYSTEM_ERROR, strerror(errno),
134 prog, artmpfile.tmp_name, cur_file);
135 mcs_exit(FAILURE);
136 }
137 }
138 } else {
139 ar_file = 0;
140 cur_filenm = cur_file;
141 }
142
143 /*
144 * Holds temporary file;
145 * if archive, holds the current member file if it has an ehdr,
146 * and there were no errors in
147 * processing the object file.
148 */
149 elftmpfile.tmp_name = tempnam(TMPDIR, "mcs1");
150
151 while ((elf = elf_begin(fd, cmd, arf)) != 0) {
152 if (ar_file) /* get header info */ {
153 size_t len;
154
155 if ((mem_header = elf_getarhdr(elf)) == NULL) {
156 error_message(GETARHDR_ERROR, LIBelf_ERROR,
157 elf_errmsg(-1), prog, cur_file,
158 elf_getbase(elf));
159 (void) elf_end(elf);
160 (void) elf_end(arf);
161 (void) close(fd);
162 free_tempfile(&artmpfile);
163 return (FAILURE);
164 }
165
166 if (cur_filenm != NULL)
167 free(cur_filenm);
168
169 len = (strlen(cur_file) + 3 +
170 strlen(mem_header->ar_name));
171
172 if ((cur_filenm = malloc(len)) == NULL) {
173 error_message(MALLOC_ERROR,
174 PLAIN_ERROR, NULL, prog);
175 mcs_exit(FAILURE);
176 }
177
178 (void) snprintf(cur_filenm, len, "%s[%s]",
179 cur_file, mem_header->ar_name);
180 }
181
182 if (elf_kind(elf) == ELF_K_ELF) {
183 if ((code = process_file(elf, cur_filenm, cmd_info)) ==
184 FAILURE) {
185 if (!ar_file) {
186 (void) elf_end(arf);
187 (void) elf_end(elf);
188 (void) close(fd);
189 return (FAILURE);
190 } else {
191 copy_non_elf_to_temp_ar(fd, elf,
192 fdartmp, mem_header,
193 cur_file, cmd_info);
194 error++;
195 }
196 } else if (ar_file && CHK_OPT(cmd_info, MIGHT_CHG)) {
197 if (code == DONT_BUILD)
198 copy_non_elf_to_temp_ar(fd, elf,
199 fdartmp, mem_header,
200 cur_file, cmd_info);
201 else
202 copy_elf_file_to_temp_ar_file(
203 fdartmp, mem_header, cur_file);
204 }
205 } else {
206 /*
207 * decide what to do with non-ELF file
208 */
209 if (!ar_file) {
210 error_message(FILE_TYPE_ERROR, PLAIN_ERROR,
211 NULL, prog, cur_filenm);
212 (void) close(fd);
213 return (FAILURE);
214 } else {
215 if (CHK_OPT(cmd_info, MIGHT_CHG))
216 copy_non_elf_to_temp_ar(fd, elf,
217 fdartmp, mem_header,
218 cur_file, cmd_info);
219 }
220 }
221 cmd = elf_next(elf);
222 (void) elf_end(elf);
223 }
224
225 err = elf_errno();
226 if (err != 0) {
227 error_message(LIBELF_ERROR, LIBelf_ERROR,
228 elf_errmsg(err), prog);
229 error_message(NOT_MANIPULATED_ERROR, PLAIN_ERROR, NULL,
230 prog, cur_file);
231 return (FAILURE);
232 }
233
234 (void) elf_end(arf);
235
236 if (ar_file && CHK_OPT(cmd_info, MIGHT_CHG)) {
237 (void) close(fdartmp); /* done writing to ar_temp_file */
238 /* copy ar_temp_file to FILE */
239 copy_file(fd, cur_file, &artmpfile);
240 } else if (code != DONT_BUILD && CHK_OPT(cmd_info, MIGHT_CHG))
241 copy_file(fd, cur_file, &elftmpfile);
242 (void) close(fd); /* done processing this file */
243 return (error);
244 }
245
246 static int
process_file(Elf * elf,char * cur_file,Cmd_Info * cmd_info)247 process_file(Elf *elf, char *cur_file, Cmd_Info *cmd_info)
248 {
249 int error = SUCCESS;
250 int x;
251 GElf_Ehdr ehdr;
252 size_t shnum;
253 file_state_t state;
254
255 /*
256 * Initialize
257 */
258 if (gelf_getehdr(elf, &ehdr) == NULL) {
259 error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog);
260 return (FAILURE);
261 }
262
263 if (elf_getshdrnum(elf, &shnum) == -1) {
264 error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog);
265 return (FAILURE);
266 }
267
268 /* Initialize per-file state */
269 state.Sect_exists = 0;
270 state.notesegndx = -1;
271 state.notesctndx = -1;
272 state.b_e_seg_table = NULL;
273 state.sec_table = NULL;
274 state.off_table = 0;
275 state.nobits_table = NULL;
276 state.new_sec_string = NULL;
277
278 initialize(shnum, cmd_info, &state);
279
280 if ((ehdr.e_phnum != 0) &&
281 (build_segment_table(elf, &ehdr, &state) == FAILURE)) {
282 x = error = FAILURE;
283 } else if ((x = traverse_file(elf, &ehdr, cur_file,
284 cmd_info, &state)) == FAILURE) {
285 error_message(WRN_MANIPULATED_ERROR, PLAIN_ERROR, NULL,
286 prog, cur_file);
287 error = FAILURE;
288 } else if (x != DONT_BUILD && x != FAILURE) {
289 post_process(cmd_info, &state);
290 if (build_file(elf, &ehdr, cmd_info, &state) == FAILURE) {
291 error_message(WRN_MANIPULATED_ERROR, PLAIN_ERROR,
292 NULL, prog, cur_file);
293 error = FAILURE;
294 }
295 }
296
297 /* Release any dynamicaly allocated buffers */
298 if (state.b_e_seg_table != NULL)
299 free(state.b_e_seg_table);
300 if (state.sec_table != NULL)
301 free(state.sec_table);
302 if (state.off_table != NULL)
303 free(state.off_table);
304 if (state.nobits_table != NULL)
305 free(state.nobits_table);
306 if (state.new_sec_string != NULL)
307 free(state.new_sec_string);
308
309 if (x == DONT_BUILD)
310 return (DONT_BUILD);
311 else
312 return (error);
313 }
314
315 static int
traverse_file(Elf * elf,GElf_Ehdr * ehdr,char * cur_file,Cmd_Info * cmd_info,file_state_t * state)316 traverse_file(Elf *elf, GElf_Ehdr * ehdr, char *cur_file, Cmd_Info *cmd_info,
317 file_state_t *state)
318 {
319 Elf_Scn *scn;
320 Elf_Scn *temp_scn;
321 Elf_Data *data;
322 GElf_Shdr *shdr;
323 char *temp_name;
324 section_info_table *sinfo;
325 GElf_Xword x;
326 int ret = 0, SYM = 0; /* used by strip command */
327 int phnum = ehdr->e_phnum;
328 unsigned int i, scn_index;
329 size_t shstrndx, shnum;
330
331 state->Sect_exists = 0;
332
333 if (elf_getshdrnum(elf, &shnum) == -1) {
334 error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog);
335 return (FAILURE);
336 }
337 if (elf_getshdrstrndx(elf, &shstrndx) == -1) {
338 error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog);
339 return (FAILURE);
340 }
341
342 scn = 0;
343 scn_index = 1;
344 sinfo = &state->sec_table[scn_index];
345 while ((scn = elf_nextscn(elf, scn)) != 0) {
346 char *name;
347
348 shdr = &(sinfo->shdr);
349 if (gelf_getshdr(scn, shdr) == NULL) {
350 error_message(NO_SECT_TABLE_ERROR,
351 LIBelf_ERROR, elf_errmsg(-1), prog, cur_file);
352 return (FAILURE);
353 }
354
355 /*
356 * Note: If the object has problems, name
357 * may be set to NULL by the following.
358 */
359 name = elf_strptr(elf, shstrndx, (size_t)shdr->sh_name);
360
361 sinfo->scn = scn;
362 sinfo->secno = scn_index;
363 sinfo->osecno = scn_index;
364 SET_ACTION(sinfo->si_flags, ACT_NOP);
365 sinfo->name = name;
366 if (ehdr->e_phnum == 0)
367 SET_LOC(sinfo->si_flags, NOSEG);
368 else
369 SET_LOC(sinfo->si_flags, scn_location(scn, elf, state));
370
371 if (shdr->sh_type == SHT_GROUP) {
372 if (aplist_append(&cmd_info->sh_groups,
373 sinfo, 10) == NULL) {
374 error_message(MALLOC_ERROR, PLAIN_ERROR,
375 NULL, prog);
376 mcs_exit(FAILURE);
377 }
378 }
379
380 /*
381 * If the target section is pointed by a section
382 * holding relocation infomation, then the
383 * pointing section would be useless if the
384 * target section is removed.
385 */
386 if ((shdr->sh_type == SHT_REL ||
387 shdr->sh_type == SHT_RELA) &&
388 (shdr->sh_info != SHN_UNDEF &&
389 (temp_scn = elf_getscn(elf, shdr->sh_info)) != 0)) {
390 GElf_Shdr tmp_shdr;
391 if (gelf_getshdr(temp_scn, &tmp_shdr) != NULL) {
392 temp_name = elf_strptr(elf, shstrndx,
393 (size_t)tmp_shdr.sh_name);
394 sinfo->rel_name = temp_name;
395 sinfo->rel_scn_index =
396 shdr->sh_info;
397 if (phnum == 0)
398 sinfo->rel_loc = NOSEG;
399 else
400 sinfo->rel_loc =
401 scn_location(temp_scn, elf, state);
402 }
403 }
404 data = 0;
405 if ((data = elf_getdata(scn, data)) == NULL) {
406 error_message(LIBELF_ERROR,
407 LIBelf_ERROR, elf_errmsg(-1), prog);
408 return (FAILURE);
409 }
410 sinfo->data = data;
411
412 /*
413 * Check if this section is a candidate for
414 * action to be processes.
415 */
416 if ((name != NULL) && (sectcmp(name) == 0)) {
417 SET_CANDIDATE(sinfo->si_flags);
418
419 /*
420 * This flag just shows that there was a
421 * candidate.
422 */
423 state->Sect_exists++;
424 }
425
426 /*
427 * Any of the following section types should
428 * also be removed (if possible) if invoked via
429 * the 'strip' command.
430 */
431 if (CHK_OPT(cmd_info, I_AM_STRIP) &&
432 ((shdr->sh_type == SHT_SUNW_DEBUG) ||
433 (shdr->sh_type == SHT_SUNW_DEBUGSTR))) {
434 SET_CANDIDATE(sinfo->si_flags);
435 state->Sect_exists++;
436 }
437
438
439 /*
440 * Zap this file ?
441 */
442 if (CHK_OPT(cmd_info, zFLAG) &&
443 (shdr->sh_type == SHT_PROGBITS)) {
444 SET_CANDIDATE(sinfo->si_flags);
445 state->Sect_exists++;
446 }
447 x = GET_LOC(sinfo->si_flags);
448
449 /*
450 * Remember the note section index so that we can
451 * reset the NOTE segment offset to point to it. Depending
452 * on the operation being carried out, the note section may
453 * be assigned a new location in the resulting ELF
454 * image, and the program header needs to reflect that.
455 *
456 * There can be multiple contiguous note sections in
457 * an object, referenced by a single NOTE segment. We
458 * want to be sure and remember the one referenced by
459 * the program header, and not one of the others.
460 */
461 if ((shdr->sh_type == SHT_NOTE) && (state->notesctndx == -1) &&
462 (state->notesegndx != -1) &&
463 (state->b_e_seg_table[state->notesegndx].p_offset
464 == shdr->sh_offset))
465 state->notesctndx = scn_index;
466
467 if (x == IN || x == PRIOR)
468 state->off_table[scn_index] = shdr->sh_offset;
469 if (shdr->sh_type == SHT_NOBITS)
470 state->nobits_table[scn_index] = 1;
471
472 /*
473 * If this section satisfies the condition,
474 * apply the actions specified.
475 */
476 if (ISCANDIDATE(sinfo->si_flags)) {
477 ret += apply_action(sinfo, cur_file, cmd_info);
478 }
479
480 /*
481 * If I am strip command, determine if symtab can go or not.
482 */
483 if (CHK_OPT(cmd_info, I_AM_STRIP) &&
484 (CHK_OPT(cmd_info, xFLAG) == 0) &&
485 (CHK_OPT(cmd_info, lFLAG) == 0)) {
486 if (shdr->sh_type == SHT_SYMTAB &&
487 GET_LOC(sinfo->si_flags) == AFTER) {
488 SYM = scn_index;
489 }
490 }
491 scn_index++;
492 sinfo++;
493 }
494 sinfo->scn = (Elf_Scn *) -1;
495
496 /*
497 * If there were any errors traversing the file,
498 * just return error.
499 */
500 if (ret != 0)
501 return (FAILURE);
502
503 /*
504 * Remove symbol table if possible
505 */
506 if (CHK_OPT(cmd_info, I_AM_STRIP) && SYM != 0) {
507 GElf_Shdr tmp_shdr;
508
509 (void) gelf_getshdr(state->sec_table[SYM].scn, &tmp_shdr);
510 state->sec_table[SYM].secno = (GElf_Word)DELETED;
511 ++(cmd_info->no_of_nulled);
512 if (state->Sect_exists == 0)
513 ++state->Sect_exists;
514 SET_ACTION(state->sec_table[SYM].si_flags, ACT_DELETE);
515 state->off_table[SYM] = 0;
516 /*
517 * Can I remove section header
518 * string table ?
519 */
520 if ((tmp_shdr.sh_link < shnum) &&
521 (tmp_shdr.sh_link != SHN_UNDEF) &&
522 (tmp_shdr.sh_link != shstrndx) &&
523 (GET_LOC(state->sec_table[tmp_shdr.sh_link].si_flags) ==
524 AFTER)) {
525 state->sec_table[tmp_shdr.sh_link].secno =
526 (GElf_Word)DELETED;
527 ++(cmd_info->no_of_nulled);
528 if (state->Sect_exists == 0)
529 ++state->Sect_exists;
530 SET_ACTION(state->sec_table[tmp_shdr.sh_link].si_flags,
531 ACT_DELETE);
532 state->off_table[tmp_shdr.sh_link] = 0;
533 }
534 }
535
536 /*
537 * If I only printed the contents, then
538 * just report so.
539 */
540 if (CHK_OPT(cmd_info, pFLAG) && !CHK_OPT(cmd_info, MIGHT_CHG))
541 return (DONT_BUILD); /* don't bother creating a new file */
542 /* since the file has not changed */
543
544 /*
545 * I might need to add a new section. Check it.
546 */
547 if (state->Sect_exists == 0 && CHK_OPT(cmd_info, aFLAG)) {
548 int act = 0;
549 state->new_sec_string = calloc(1, cmd_info->str_size + 1);
550 if (state->new_sec_string == NULL)
551 return (FAILURE);
552 for (act = 0; act < actmax; act++) {
553 if (Action[act].a_action == ACT_APPEND) {
554 (void) strcat(state->new_sec_string,
555 Action[act].a_string);
556 (void) strcat(state->new_sec_string, "\n");
557 cmd_info->no_of_append = 1;
558 }
559 }
560 }
561
562 /*
563 * If I did not append any new sections, and I did not
564 * modify/delete any sections, then just report so.
565 */
566 if ((state->Sect_exists == 0 && cmd_info->no_of_append == 0) ||
567 !CHK_OPT(cmd_info, MIGHT_CHG))
568 return (DONT_BUILD);
569
570 /*
571 * Found at least one section which was processed.
572 * Deleted or Appended or Compressed.
573 */
574 if (state->Sect_exists) {
575 /*
576 * First, handle the deleted sections.
577 */
578 if (cmd_info->no_of_delete != 0 ||
579 cmd_info->no_of_nulled != 0) {
580 int acc = 0;
581 int rel_idx;
582
583 /*
584 * Handle relocation/target
585 * sections.
586 */
587 sinfo = &(state->sec_table[0]);
588 for (i = 1; i < shnum; i++) {
589 sinfo++;
590 rel_idx = sinfo->rel_scn_index;
591 if (rel_idx == 0)
592 continue;
593
594 /*
595 * If I am removed, then remove my
596 * target section.
597 */
598 if (((sinfo->secno ==
599 (GElf_Word)DELETED) ||
600 (sinfo->secno ==
601 (GElf_Word)NULLED)) &&
602 sinfo->rel_loc != IN) {
603 if (GET_LOC(state->
604 sec_table[rel_idx].si_flags) ==
605 PRIOR) {
606 state->sec_table[rel_idx].
607 secno = (GElf_Word)NULLED;
608 } else {
609 state->sec_table[rel_idx].
610 secno = (GElf_Word)DELETED;
611 }
612 SET_ACTION(
613 state->sec_table[rel_idx].si_flags,
614 ACT_DELETE);
615 }
616
617 /*
618 * I am not removed. Check if my target is
619 * removed or nulled. If so, let me try to
620 * remove my self.
621 */
622 if (((state->sec_table[rel_idx].secno ==
623 (GElf_Word)DELETED) ||
624 (state->sec_table[rel_idx].secno ==
625 (GElf_Word)NULLED)) &&
626 (GET_LOC(sinfo->si_flags) != IN)) {
627 if (GET_LOC(sinfo->si_flags) ==
628 PRIOR)
629 sinfo->secno =
630 (GElf_Word)NULLED;
631 else
632 sinfo->secno =
633 (GElf_Word)DELETED;
634 SET_ACTION(sinfo->si_flags, ACT_DELETE);
635 }
636 }
637
638 /*
639 * Now, take care of DELETED sections
640 */
641 sinfo = &(state->sec_table[1]);
642 for (i = 1; i < shnum; i++) {
643 shdr = &(sinfo->shdr);
644 if (sinfo->secno == (GElf_Word)DELETED) {
645 acc++;
646 /*
647 * The SHT_GROUP section which this
648 * section is a member may be able
649 * to be removed. See post_process().
650 */
651 if (shdr->sh_flags & SHF_GROUP) {
652 SET_OPT(cmd_info,
653 SHF_GROUP_DEL);
654 }
655 } else {
656 /*
657 * The data buffer of SHT_GROUP this
658 * section is a member needs to be
659 * updated. See post_process().
660 */
661 sinfo->secno -= acc;
662 if ((shdr->sh_flags & SHF_GROUP) &&
663 (acc != 0)) {
664 SET_OPT(cmd_info,
665 SHF_GROUP_MOVE);
666 }
667 }
668 sinfo++;
669 }
670 }
671 }
672
673 /*
674 * I know that the file has been modified.
675 * A new file need to be created.
676 */
677 return (SUCCESS);
678 }
679
680 static int
build_file(Elf * src_elf,GElf_Ehdr * src_ehdr,Cmd_Info * cmd_info,file_state_t * state)681 build_file(Elf *src_elf, GElf_Ehdr *src_ehdr, Cmd_Info *cmd_info,
682 file_state_t *state)
683 {
684 Elf_Scn *src_scn;
685 Elf_Scn *dst_scn;
686 int new_sh_name = 0; /* to hold the offset for the new */
687 /* section's name */
688 Elf *dst_elf = 0;
689 Elf_Data *elf_data;
690 Elf_Data *data;
691 int64_t scn_no, x;
692 size_t no_of_symbols = 0;
693 section_info_table *info;
694 unsigned int c = 0;
695 int fdtmp;
696 GElf_Shdr src_shdr;
697 GElf_Shdr dst_shdr;
698 GElf_Ehdr dst_ehdr;
699 GElf_Off new_offset = 0, r;
700 size_t shnum, shstrndx;
701
702
703 if (elf_getshdrnum(src_elf, &shnum) == -1) {
704 error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog);
705 return (FAILURE);
706 }
707 if (elf_getshdrstrndx(src_elf, &shstrndx) == -1) {
708 error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog);
709 return (FAILURE);
710 }
711
712 if ((fdtmp = open(elftmpfile.tmp_name, O_RDWR | O_TRUNC | O_CREAT,
713 (mode_t)0666)) == -1) {
714 error_message(OPEN_TEMP_ERROR, SYSTEM_ERROR, strerror(errno),
715 prog, elftmpfile.tmp_name);
716 return (FAILURE);
717 }
718 elftmpfile.tmp_unlink = 1;
719
720 if ((dst_elf = elf_begin(fdtmp, ELF_C_WRITE, (Elf *) 0)) == NULL) {
721 error_message(READ_ERROR, LIBelf_ERROR, elf_errmsg(-1),
722 prog, elftmpfile.tmp_name);
723 (void) close(fdtmp);
724 return (FAILURE);
725 }
726
727 if (gelf_newehdr(dst_elf, gelf_getclass(src_elf)) == 0) {
728 error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog);
729 return (FAILURE);
730 }
731
732 /* initialize dst_ehdr */
733 (void) gelf_getehdr(dst_elf, &dst_ehdr);
734 dst_ehdr = *src_ehdr;
735
736 /*
737 * If we are removing the header string table section,
738 * remove the reference to it from the ELF header.
739 */
740 if ((shstrndx != SHN_UNDEF) &&
741 (state->sec_table[shstrndx].secno == (GElf_Word)DELETED))
742 dst_ehdr.e_shstrndx = SHN_UNDEF;
743
744 /*
745 * flush the changes to the ehdr so the ident
746 * array and header string table index are filled in.
747 */
748 (void) gelf_update_ehdr(dst_elf, &dst_ehdr);
749
750
751 if (src_ehdr->e_phnum != 0) {
752 (void) elf_flagelf(dst_elf, ELF_C_SET, ELF_F_LAYOUT);
753
754 if (gelf_newphdr(dst_elf, src_ehdr->e_phnum) == 0) {
755 error_message(LIBELF_ERROR, LIBelf_ERROR,
756 elf_errmsg(-1), prog);
757 return (FAILURE);
758 }
759
760 for (x = 0; x < src_ehdr->e_phnum; ++x) {
761 GElf_Phdr dst;
762 GElf_Phdr src;
763
764 /* LINTED */
765 (void) gelf_getphdr(src_elf, (int)x, &src);
766 /* LINTED */
767 (void) gelf_getphdr(dst_elf, (int)x, &dst);
768 (void) memcpy(&dst, &src, sizeof (GElf_Phdr));
769 /* LINTED */
770 (void) gelf_update_phdr(dst_elf, (int)x, &dst);
771 }
772
773 x = location(dst_ehdr.e_phoff, 0, src_elf, state);
774 if (x == AFTER)
775 new_offset = (GElf_Off)src_ehdr->e_ehsize;
776 }
777
778 scn_no = 1;
779 while ((src_scn = state->sec_table[scn_no].scn) != (Elf_Scn *) -1) {
780 info = &state->sec_table[scn_no];
781 /* If section should be copied to new file NOW */
782 if ((info->secno != (GElf_Word)DELETED) &&
783 info->secno <= scn_no) {
784 if ((dst_scn = elf_newscn(dst_elf)) == NULL) {
785 error_message(LIBELF_ERROR,
786 LIBelf_ERROR, elf_errmsg(-1), prog);
787 return (FAILURE);
788 }
789 (void) gelf_getshdr(dst_scn, &dst_shdr);
790 (void) gelf_getshdr(info->scn, &src_shdr);
791 (void) memcpy(&dst_shdr, &src_shdr, sizeof (GElf_Shdr));
792
793 /*
794 * Update link and info fields
795 * The sh_link field may have special values so
796 * check them first.
797 */
798 if ((src_shdr.sh_link >= shnum) ||
799 (src_shdr.sh_link == 0))
800 dst_shdr.sh_link = src_shdr.sh_link;
801 else if ((int)state->sec_table[src_shdr.sh_link].secno <
802 0)
803 dst_shdr.sh_link = 0;
804 else
805 dst_shdr.sh_link =
806 state->sec_table[src_shdr.sh_link].secno;
807
808 if ((src_shdr.sh_type == SHT_REL) ||
809 (src_shdr.sh_type == SHT_RELA)) {
810 if ((src_shdr.sh_info >= shnum) ||
811 ((int)state->sec_table[src_shdr.
812 sh_info].secno < 0))
813 dst_shdr.sh_info = 0;
814 else
815 dst_shdr.sh_info = state->
816 sec_table[src_shdr.sh_info].secno;
817 }
818
819 data = state->sec_table[scn_no].data;
820 if ((elf_data = elf_newdata(dst_scn)) == NULL) {
821 error_message(LIBELF_ERROR,
822 LIBelf_ERROR, elf_errmsg(-1), prog);
823 return (FAILURE);
824 }
825 *elf_data = *data;
826
827 /*
828 * SHT_{DYNSYM, SYMTAB} might need some change, as
829 * they may contain section symbols that reference
830 * removed sections. SHT_SUNW_LDYNSYM does not
831 * contain section symbols, and therefore does not
832 * have this issue.
833 */
834 if (((src_shdr.sh_type == SHT_SYMTAB) ||
835 (src_shdr.sh_type == SHT_DYNSYM)) &&
836 src_shdr.sh_entsize != 0 &&
837 (cmd_info->no_of_delete != 0 ||
838 cmd_info->no_of_nulled != 0)) {
839 char *new_sym;
840
841 no_of_symbols = src_shdr.sh_size /
842 src_shdr.sh_entsize;
843 new_sym = malloc(no_of_symbols *
844 src_shdr.sh_entsize);
845 if (new_sym == NULL) {
846 error_message(MALLOC_ERROR,
847 PLAIN_ERROR, NULL, prog);
848 mcs_exit(FAILURE);
849 }
850
851 /* CSTYLED */
852 elf_data->d_buf = (void *) new_sym;
853 for (c = 0; c < no_of_symbols; c++) {
854 GElf_Sym csym;
855
856 (void) gelf_getsym(data, c, &csym);
857
858 if ((csym.st_shndx < SHN_LORESERVE) &&
859 (csym.st_shndx != SHN_UNDEF)) {
860 section_info_table *i;
861 i = &state->
862 sec_table[csym.st_shndx];
863 if (((int)i->secno !=
864 DELETED) &&
865 ((int)i->secno != NULLED)) {
866 csym.st_shndx =
867 i->secno;
868 } else {
869 /* BEGIN CSTYLED */
870 if (src_shdr.sh_type ==
871 SHT_SYMTAB) {
872 /*
873 * The section which
874 * this * symbol relates
875 * to is removed.
876 * There is no way to
877 * specify this fact,
878 * just change the shndx
879 * to 1.
880 */
881 csym.st_shndx = 1;
882 } else {
883 /*
884 * If this is in a
885 * .dynsym, NULL it out.
886 */
887 csym.st_shndx = 0;
888 csym.st_name = 0;
889 csym.st_value = 0;
890 csym.st_size = 0;
891 csym.st_info = 0;
892 csym.st_other = 0;
893 csym.st_shndx = 0;
894 }
895 /* END CSTYLED */
896 }
897 }
898
899 (void) gelf_update_sym(elf_data, c,
900 &csym);
901 }
902 }
903
904 /* update SHT_SYMTAB_SHNDX */
905 if ((src_shdr.sh_type == SHT_SYMTAB_SHNDX) &&
906 (src_shdr.sh_entsize != 0) &&
907 ((cmd_info->no_of_delete != 0) ||
908 (cmd_info->no_of_nulled != 0))) {
909 GElf_Word *oldshndx;
910 GElf_Word *newshndx;
911 uint_t entcnt;
912
913 entcnt = src_shdr.sh_size /
914 src_shdr.sh_entsize;
915 oldshndx = data->d_buf;
916 newshndx = malloc(entcnt * src_shdr.sh_entsize);
917 if (newshndx == NULL) {
918 error_message(MALLOC_ERROR,
919 PLAIN_ERROR, NULL, prog);
920 mcs_exit(FAILURE);
921 }
922 elf_data->d_buf = (void *)newshndx;
923 for (c = 0; c < entcnt; c++) {
924 if (oldshndx[c] != SHN_UNDEF) {
925 section_info_table *i;
926 i = &state->
927 sec_table[oldshndx[c]];
928 if (((int)i->secno !=
929 DELETED) &&
930 ((int)i->secno != NULLED))
931 newshndx[c] = i->secno;
932 else
933 newshndx[c] =
934 oldshndx[c];
935 } else
936 newshndx[c] =
937 oldshndx[c];
938 }
939 }
940
941 /*
942 * If the section is to be updated,
943 * do so.
944 */
945 if (ISCANDIDATE(info->si_flags)) {
946 if ((GET_LOC(info->si_flags) == PRIOR) &&
947 (((int)info->secno == NULLED) ||
948 ((int)info->secno == EXPANDED) ||
949 ((int)info->secno == SHRUNK))) {
950 /*
951 * The section is updated,
952 * but the position is not too
953 * good. Need to NULL this out.
954 */
955 dst_shdr.sh_name = 0;
956 dst_shdr.sh_type = SHT_PROGBITS;
957 if ((int)info->secno != NULLED) {
958 (cmd_info->no_of_moved)++;
959 SET_MOVING(info->si_flags);
960 }
961 } else {
962 /*
963 * The section is positioned AFTER,
964 * or there are no segments.
965 * It is safe to update this section.
966 */
967 data = state->sec_table[scn_no].mdata;
968 *elf_data = *data;
969 dst_shdr.sh_size = elf_data->d_size;
970 }
971 }
972 /* add new section name to shstrtab? */
973 else if (!state->Sect_exists &&
974 (state->new_sec_string != NULL) &&
975 (scn_no == shstrndx) &&
976 (dst_shdr.sh_type == SHT_STRTAB) &&
977 ((src_ehdr->e_phnum == 0) ||
978 ((x = scn_location(dst_scn, dst_elf, state))
979 != IN) ||
980 (x != PRIOR))) {
981 size_t sect_len;
982
983 sect_len = strlen(SECT_NAME);
984 if ((elf_data->d_buf =
985 malloc((dst_shdr.sh_size +
986 sect_len + 1))) == NULL) {
987 error_message(MALLOC_ERROR,
988 PLAIN_ERROR, NULL, prog);
989 mcs_exit(FAILURE);
990 }
991 /* put original data plus new data in section */
992 (void) memcpy(elf_data->d_buf,
993 data->d_buf, data->d_size);
994 (void) memcpy(&((char *)elf_data->d_buf)
995 [data->d_size], SECT_NAME, sect_len + 1);
996 /* LINTED */
997 new_sh_name = (int)dst_shdr.sh_size;
998 dst_shdr.sh_size += sect_len + 1;
999 elf_data->d_size += sect_len + 1;
1000 }
1001
1002 /*
1003 * Compute offsets.
1004 */
1005 if (src_ehdr->e_phnum != 0) {
1006 /*
1007 * Compute section offset.
1008 */
1009 if (state->off_table[scn_no] == 0) {
1010 if (dst_shdr.sh_addralign != 0) {
1011 r = new_offset %
1012 dst_shdr.sh_addralign;
1013 if (r)
1014 new_offset +=
1015 dst_shdr.
1016 sh_addralign - r;
1017 }
1018 dst_shdr.sh_offset = new_offset;
1019 elf_data->d_off = 0;
1020 } else {
1021 if (state->nobits_table[scn_no] == 0)
1022 new_offset =
1023 state->off_table[scn_no];
1024 }
1025 if (state->nobits_table[scn_no] == 0)
1026 new_offset += dst_shdr.sh_size;
1027 }
1028
1029 /* flush changes */
1030 (void) gelf_update_shdr(dst_scn, &dst_shdr);
1031 }
1032 scn_no++;
1033 }
1034
1035 /*
1036 * This is the real new section.
1037 */
1038 if (!state->Sect_exists && state->new_sec_string != NULL) {
1039 size_t string_size;
1040 string_size = strlen(state->new_sec_string) + 1;
1041 if ((dst_scn = elf_newscn(dst_elf)) == NULL) {
1042 error_message(LIBELF_ERROR,
1043 LIBelf_ERROR, elf_errmsg(-1), prog);
1044 return (FAILURE);
1045 }
1046 (void) gelf_getshdr(dst_scn, &dst_shdr);
1047
1048 dst_shdr.sh_name = new_sh_name;
1049 dst_shdr.sh_type = SHT_PROGBITS;
1050 dst_shdr.sh_flags = 0;
1051 dst_shdr.sh_addr = 0;
1052 if (src_ehdr->e_phnum != 0)
1053 dst_shdr.sh_offset = new_offset;
1054 else
1055 dst_shdr.sh_offset = 0;
1056 dst_shdr.sh_size = string_size + 1;
1057 dst_shdr.sh_link = 0;
1058 dst_shdr.sh_info = 0;
1059 dst_shdr.sh_addralign = 1;
1060 dst_shdr.sh_entsize = 0;
1061 (void) gelf_update_shdr(dst_scn, &dst_shdr); /* flush changes */
1062
1063 if ((elf_data = elf_newdata(dst_scn)) == NULL) {
1064 error_message(LIBELF_ERROR,
1065 LIBelf_ERROR, elf_errmsg(-1), prog);
1066 return (FAILURE);
1067 }
1068 elf_data->d_size = string_size + 1;
1069 if ((elf_data->d_buf = (char *)
1070 calloc(1, string_size + 1)) == NULL) {
1071 error_message(MALLOC_ERROR,
1072 PLAIN_ERROR, NULL, prog);
1073 mcs_exit(FAILURE);
1074 }
1075 (void) memcpy(&((char *)elf_data->d_buf)[1],
1076 state->new_sec_string, string_size);
1077 elf_data->d_align = 1;
1078 new_offset += string_size + 1;
1079 }
1080
1081 /*
1082 * If there are sections which needed to be moved,
1083 * then do it here.
1084 */
1085 if (cmd_info->no_of_moved != 0) {
1086 int cnt;
1087 info = &state->sec_table[0];
1088
1089 for (cnt = 0; cnt < shnum; cnt++, info++) {
1090 if ((GET_MOVING(info->si_flags)) == 0)
1091 continue;
1092
1093 if ((src_scn = elf_getscn(src_elf, info->osecno)) ==
1094 NULL) {
1095 error_message(LIBELF_ERROR,
1096 LIBelf_ERROR, elf_errmsg(-1), prog);
1097 return (FAILURE);
1098 }
1099 if (gelf_getshdr(src_scn, &src_shdr) == NULL) {
1100 error_message(LIBELF_ERROR,
1101 LIBelf_ERROR, elf_errmsg(-1), prog);
1102 return (FAILURE);
1103 }
1104 if ((dst_scn = elf_newscn(dst_elf)) == NULL) {
1105 error_message(LIBELF_ERROR,
1106 LIBelf_ERROR, elf_errmsg(-1), prog);
1107 return (FAILURE);
1108 }
1109 if (gelf_getshdr(dst_scn, &dst_shdr) == NULL) {
1110 error_message(LIBELF_ERROR,
1111 LIBelf_ERROR, elf_errmsg(-1), prog);
1112 return (FAILURE);
1113 }
1114 dst_shdr = src_shdr;
1115
1116 data = info->mdata;
1117
1118 dst_shdr.sh_offset = new_offset; /* UPDATE fields */
1119 dst_shdr.sh_size = data->d_size;
1120
1121 if ((shnum >= src_shdr.sh_link) ||
1122 (src_shdr.sh_link == 0))
1123 dst_shdr.sh_link = src_shdr.sh_link;
1124 else
1125 dst_shdr.sh_link =
1126 state->sec_table[src_shdr.sh_link].osecno;
1127
1128 if ((shnum >= src_shdr.sh_info) ||
1129 (src_shdr.sh_info == 0))
1130 dst_shdr.sh_info = src_shdr.sh_info;
1131 else
1132 dst_shdr.sh_info =
1133 state->sec_table[src_shdr.sh_info].osecno;
1134 (void) gelf_update_shdr(dst_scn, &dst_shdr);
1135 if ((elf_data = elf_newdata(dst_scn)) == NULL) {
1136 error_message(LIBELF_ERROR,
1137 LIBelf_ERROR, elf_errmsg(-1), prog);
1138 return (FAILURE);
1139 }
1140 (void) memcpy(elf_data, data, sizeof (Elf_Data));
1141
1142 new_offset += data->d_size;
1143 }
1144 }
1145
1146 /*
1147 * In the event that the position of the sting table has changed,
1148 * as a result of deleted sections, update the ehdr->e_shstrndx.
1149 */
1150 if ((shstrndx > 0) && (shnum > 0) &&
1151 (state->sec_table[shstrndx].secno < shnum)) {
1152 if (state->sec_table[shstrndx].secno < SHN_LORESERVE) {
1153 dst_ehdr.e_shstrndx =
1154 state->sec_table[dst_ehdr.e_shstrndx].secno;
1155 } else {
1156 Elf_Scn *_scn;
1157 GElf_Shdr shdr0;
1158
1159 /*
1160 * If shstrndx requires 'Extended ELF Sections'
1161 * then it is stored in shdr[0].sh_link
1162 */
1163 dst_ehdr.e_shstrndx = SHN_XINDEX;
1164 if ((_scn = elf_getscn(dst_elf, 0)) == NULL) {
1165 error_message(LIBELF_ERROR,
1166 LIBelf_ERROR, elf_errmsg(-1), prog);
1167 return (FAILURE);
1168 }
1169 (void) gelf_getshdr(_scn, &shdr0);
1170 shdr0.sh_link = state->sec_table[shstrndx].secno;
1171 (void) gelf_update_shdr(_scn, &shdr0);
1172 }
1173 }
1174
1175 if (src_ehdr->e_phnum != 0) {
1176 size_t align = gelf_fsize(dst_elf, ELF_T_ADDR, 1, EV_CURRENT);
1177
1178 /* UPDATE location of program header table */
1179 if (location(dst_ehdr.e_phoff, 0, dst_elf, state) == AFTER) {
1180 r = new_offset % align;
1181 if (r)
1182 new_offset += align - r;
1183
1184 dst_ehdr.e_phoff = new_offset;
1185 new_offset += dst_ehdr.e_phnum * dst_ehdr.e_phentsize;
1186 }
1187 /* UPDATE location of section header table */
1188 if ((location(dst_ehdr.e_shoff, 0, src_elf, state) == AFTER) ||
1189 ((location(dst_ehdr.e_shoff, 0, src_elf, state) == PRIOR) &&
1190 (!state->Sect_exists && state->new_sec_string != NULL))) {
1191 r = new_offset % align;
1192 if (r)
1193 new_offset += align - r;
1194
1195 dst_ehdr.e_shoff = new_offset;
1196 }
1197
1198 /*
1199 * The NOTE segment is the one segment whos
1200 * sections might get moved by mcs processing.
1201 * Make sure that the NOTE segments offset points
1202 * to the .note section.
1203 */
1204 if ((state->notesegndx != -1) && (state->notesctndx != -1) &&
1205 (state->sec_table[state->notesctndx].secno)) {
1206 Elf_Scn * notescn;
1207 GElf_Shdr nshdr;
1208
1209 notescn = elf_getscn(dst_elf,
1210 state->sec_table[state->notesctndx].secno);
1211 (void) gelf_getshdr(notescn, &nshdr);
1212
1213 if (gelf_getclass(dst_elf) == ELFCLASS32) {
1214 Elf32_Phdr * ph = elf32_getphdr(dst_elf) +
1215 state->notesegndx;
1216 /* LINTED */
1217 ph->p_offset = (Elf32_Off)nshdr.sh_offset;
1218 } else {
1219 Elf64_Phdr * ph = elf64_getphdr(dst_elf) +
1220 state->notesegndx;
1221 ph->p_offset = (Elf64_Off)nshdr.sh_offset;
1222 }
1223 }
1224 }
1225
1226 /* copy ehdr changes back into real ehdr */
1227 (void) gelf_update_ehdr(dst_elf, &dst_ehdr);
1228 if (elf_update(dst_elf, ELF_C_WRITE) < 0) {
1229 error_message(LIBELF_ERROR, LIBelf_ERROR, elf_errmsg(-1), prog);
1230 return (FAILURE);
1231 }
1232
1233 (void) elf_end(dst_elf);
1234 (void) close(fdtmp);
1235 return (SUCCESS);
1236 }
1237
1238 /*
1239 * Search through PHT saving the beginning and ending segment offsets
1240 */
1241 static int
build_segment_table(Elf * elf,GElf_Ehdr * ehdr,file_state_t * state)1242 build_segment_table(Elf * elf, GElf_Ehdr * ehdr, file_state_t *state)
1243 {
1244 unsigned int i;
1245
1246 state->b_e_seg_table = (Seg_Table *)
1247 calloc(ehdr->e_phnum, sizeof (Seg_Table));
1248 if (state->b_e_seg_table == NULL) {
1249 error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog);
1250 mcs_exit(FAILURE);
1251 }
1252
1253 for (i = 0; i < ehdr->e_phnum; i++) {
1254 GElf_Phdr ph;
1255
1256 (void) gelf_getphdr(elf, i, &ph);
1257
1258 /*
1259 * remember the note SEGMENTS index so that we can
1260 * re-set it's p_offset later if needed.
1261 */
1262 if (ph.p_type == PT_NOTE)
1263 state->notesegndx = i;
1264
1265 state->b_e_seg_table[i].p_offset = ph.p_offset;
1266 state->b_e_seg_table[i].p_memsz = ph.p_offset + ph.p_memsz;
1267 state->b_e_seg_table[i].p_filesz = ph.p_offset + ph.p_filesz;
1268 }
1269 return (SUCCESS);
1270 }
1271
1272
1273 static void
copy_elf_file_to_temp_ar_file(int fdartmp,Elf_Arhdr * mem_header,char * cur_file)1274 copy_elf_file_to_temp_ar_file(
1275 int fdartmp,
1276 Elf_Arhdr *mem_header,
1277 char *cur_file)
1278 {
1279 char *buf;
1280 char mem_header_buf[sizeof (struct ar_hdr) + 1];
1281 int fdtmp3;
1282 struct stat stbuf;
1283
1284 if ((fdtmp3 = open(elftmpfile.tmp_name, O_RDONLY)) == -1) {
1285 error_message(OPEN_TEMP_ERROR, SYSTEM_ERROR, strerror(errno),
1286 prog, elftmpfile.tmp_name);
1287 mcs_exit(FAILURE);
1288 }
1289
1290 (void) stat(elftmpfile.tmp_name, &stbuf); /* for size of file */
1291
1292 if ((buf =
1293 malloc(ROUNDUP(stbuf.st_size))) == NULL) {
1294 error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog);
1295 mcs_exit(FAILURE);
1296 }
1297
1298 if (read(fdtmp3, buf, stbuf.st_size) != stbuf.st_size) {
1299 error_message(READ_MANI_ERROR, SYSTEM_ERROR, strerror(errno),
1300 prog, elftmpfile.tmp_name, cur_file);
1301 mcs_exit(FAILURE);
1302 }
1303
1304 (void) sprintf(mem_header_buf, FORMAT, mem_header->ar_rawname,
1305 mem_header->ar_date, (unsigned)mem_header->ar_uid,
1306 (unsigned)mem_header->ar_gid, (unsigned)mem_header->ar_mode,
1307 stbuf.st_size, ARFMAG);
1308
1309 if (write(fdartmp, mem_header_buf,
1310 (unsigned)sizeof (struct ar_hdr)) !=
1311 (unsigned)sizeof (struct ar_hdr)) {
1312 error_message(WRITE_MANI_ERROR, SYSTEM_ERROR, strerror(errno),
1313 prog, elftmpfile.tmp_name, cur_file);
1314 mcs_exit(FAILURE);
1315 }
1316
1317 if (stbuf.st_size & 0x1) {
1318 buf[stbuf.st_size] = '\n';
1319 if (write(fdartmp, buf, (size_t)ROUNDUP(stbuf.st_size)) !=
1320 (size_t)ROUNDUP(stbuf.st_size)) {
1321 error_message(WRITE_MANI_ERROR, SYSTEM_ERROR,
1322 strerror(errno), prog, elftmpfile.tmp_name,
1323 cur_file);
1324 mcs_exit(FAILURE);
1325 }
1326 } else if (write(fdartmp, buf, stbuf.st_size) != stbuf.st_size) {
1327 error_message(WRITE_MANI_ERROR, SYSTEM_ERROR,
1328 strerror(errno), prog, elftmpfile.tmp_name,
1329 cur_file);
1330 mcs_exit(FAILURE);
1331 }
1332 free(buf);
1333 (void) close(fdtmp3);
1334 }
1335
1336 static void
copy_non_elf_to_temp_ar(int fd,Elf * elf,int fdartmp,Elf_Arhdr * mem_header,char * cur_file,Cmd_Info * cmd_info)1337 copy_non_elf_to_temp_ar(
1338 int fd,
1339 Elf *elf,
1340 int fdartmp,
1341 Elf_Arhdr *mem_header,
1342 char *cur_file,
1343 Cmd_Info *cmd_info)
1344 {
1345 char mem_header_buf[sizeof (struct ar_hdr) + 1];
1346 char *file_buf;
1347
1348 if ((strcmp(mem_header->ar_name, "/") != 0) &&
1349 (strcmp(mem_header->ar_name, "/SYM64/") != 0)) {
1350 (void) sprintf(mem_header_buf, FORMAT, mem_header->ar_rawname,
1351 mem_header->ar_date, (unsigned)mem_header->ar_uid,
1352 (unsigned)mem_header->ar_gid, (unsigned)mem_header->ar_mode,
1353 mem_header->ar_size, ARFMAG);
1354
1355 if (write(fdartmp, mem_header_buf, sizeof (struct ar_hdr)) !=
1356 sizeof (struct ar_hdr)) {
1357 error_message(WRITE_MANI_ERROR, SYSTEM_ERROR,
1358 strerror(errno), prog, cur_file);
1359 mcs_exit(FAILURE);
1360 }
1361 if ((file_buf =
1362 malloc(ROUNDUP(mem_header->ar_size))) == NULL) {
1363 error_message(MALLOC_ERROR, PLAIN_ERROR, NULL,
1364 prog);
1365 mcs_exit(FAILURE);
1366 }
1367
1368 if (lseek(fd, elf_getbase(elf), 0) != elf_getbase(elf)) {
1369 error_message(WRITE_MANI_ERROR, prog, cur_file);
1370 mcs_exit(FAILURE);
1371 }
1372
1373 if (read(fd, file_buf,
1374 (size_t)ROUNDUP(mem_header->ar_size)) !=
1375 (size_t)ROUNDUP(mem_header->ar_size)) {
1376 error_message(READ_MANI_ERROR, SYSTEM_ERROR,
1377 strerror(errno), prog, cur_file);
1378 mcs_exit(FAILURE);
1379 }
1380 if (write(fdartmp,
1381 file_buf,
1382 (size_t)ROUNDUP(mem_header->ar_size)) !=
1383 (size_t)ROUNDUP(mem_header->ar_size)) {
1384 error_message(WRITE_MANI_ERROR, SYSTEM_ERROR,
1385 strerror(errno), prog, cur_file);
1386 mcs_exit(FAILURE);
1387 }
1388 free(file_buf);
1389 } else if (CHK_OPT(cmd_info, MIGHT_CHG)) {
1390 error_message(SYM_TAB_AR_ERROR, PLAIN_ERROR, NULL,
1391 prog, cur_file);
1392 error_message(EXEC_AR_ERROR, PLAIN_ERROR, NULL, cur_file);
1393 }
1394 }
1395
1396 /*
1397 * Replace contents of file
1398 *
1399 * entry:
1400 * ofd - Open file descriptor for file fname
1401 * fname - Name of file being processed
1402 * temp_file_name - Address of pointer to temporary
1403 * file containing new contents for fname.
1404 *
1405 * exit:
1406 * The contents of the file given by temp_file->tmp_name are
1407 * copied to the file fname. The temporary file is
1408 * unlinked, and temp_file reset.
1409 */
1410 static void
copy_file(int ofd,char * fname,Tmp_File * temp_file)1411 copy_file(int ofd, char *fname, Tmp_File *temp_file)
1412 {
1413 enum { MMAP_USED, MMAP_UNUSED } mmap_status;
1414 int i;
1415 int fdtmp2;
1416 struct stat stbuf;
1417 char *buf;
1418
1419 for (i = 0; signum[i]; i++) /* started writing, cannot interrupt */
1420 (void) signal(signum[i], SIG_IGN);
1421
1422 if ((fdtmp2 = open(temp_file->tmp_name, O_RDONLY)) == -1) {
1423 error_message(OPEN_TEMP_ERROR, SYSTEM_ERROR, strerror(errno),
1424 prog, temp_file->tmp_name);
1425 mcs_exit(FAILURE);
1426 }
1427
1428 (void) stat(temp_file->tmp_name, &stbuf); /* for size of file */
1429
1430 /*
1431 * Get the contents of the updated file.
1432 * First try mmap()'ing. If mmap() fails,
1433 * then use the malloc() and read().
1434 */
1435 mmap_status = MMAP_USED;
1436 buf = (char *)mmap(0, stbuf.st_size, PROT_READ, MAP_SHARED, fdtmp2, 0);
1437 if (buf == (caddr_t)-1) {
1438 if ((buf =
1439 malloc(stbuf.st_size * sizeof (char))) == NULL) {
1440 error_message(MALLOC_ERROR, PLAIN_ERROR, NULL,
1441 prog);
1442 mcs_exit(FAILURE);
1443 }
1444
1445 if (read(fdtmp2, buf, stbuf.st_size) != stbuf.st_size) {
1446 error_message(READ_SYS_ERROR, SYSTEM_ERROR,
1447 strerror(errno), prog, temp_file->tmp_name);
1448 mcs_exit(FAILURE);
1449 }
1450 mmap_status = MMAP_UNUSED;
1451 }
1452
1453 if (ftruncate(ofd, 0) == -1) {
1454 error_message(WRITE_MANI_ERROR2, SYSTEM_ERROR, strerror(errno),
1455 prog, fname);
1456 mcs_exit(FAILURE);
1457 }
1458 if (lseek(ofd, 0, SEEK_SET) == -1) {
1459 error_message(WRITE_MANI_ERROR2, SYSTEM_ERROR, strerror(errno),
1460 prog, fname);
1461 mcs_exit(FAILURE);
1462 }
1463 if ((write(ofd, buf, stbuf.st_size)) != stbuf.st_size) {
1464 error_message(WRITE_MANI_ERROR2, SYSTEM_ERROR, strerror(errno),
1465 prog, fname);
1466 mcs_exit(FAILURE);
1467 }
1468
1469 /*
1470 * clean
1471 */
1472 if (mmap_status == MMAP_USED)
1473 (void) munmap(buf, stbuf.st_size);
1474 else
1475 free(buf);
1476 (void) close(fdtmp2);
1477 free_tempfile(temp_file);
1478 }
1479
1480 static uint64_t
location(int64_t offset,int mem_search,Elf * elf,file_state_t * state)1481 location(int64_t offset, int mem_search, Elf * elf, file_state_t *state)
1482 {
1483 int i;
1484 uint64_t upper;
1485 GElf_Ehdr ehdr;
1486
1487 (void) gelf_getehdr(elf, &ehdr);
1488
1489 for (i = 0; i < ehdr.e_phnum; i++) {
1490 if (mem_search)
1491 upper = state->b_e_seg_table[i].p_memsz;
1492 else
1493 upper = state->b_e_seg_table[i].p_filesz;
1494 if ((offset >= state->b_e_seg_table[i].p_offset) &&
1495 (offset <= upper))
1496 return (IN);
1497 else if (offset < state->b_e_seg_table[i].p_offset)
1498 return (PRIOR);
1499 }
1500 return (AFTER);
1501 }
1502
1503 static uint64_t
scn_location(Elf_Scn * scn,Elf * elf,file_state_t * state)1504 scn_location(Elf_Scn * scn, Elf * elf, file_state_t *state)
1505 {
1506 GElf_Shdr shdr;
1507
1508 (void) gelf_getshdr(scn, &shdr);
1509
1510 /*
1511 * If the section is not a NOTE section and it has no
1512 * virtual address then it is not part of a mapped segment.
1513 */
1514 if (shdr.sh_addr == 0)
1515 return (location(shdr.sh_offset + shdr.sh_size, 0, elf, state));
1516
1517 return (location(shdr.sh_offset + shdr.sh_size, 1, elf, state));
1518 }
1519
1520 static void
initialize(int shnum,Cmd_Info * cmd_info,file_state_t * state)1521 initialize(int shnum, Cmd_Info *cmd_info, file_state_t *state)
1522 {
1523 /*
1524 * Initialize command info
1525 */
1526 cmd_info->no_of_append = cmd_info->no_of_delete =
1527 cmd_info->no_of_nulled = cmd_info->no_of_compressed =
1528 cmd_info->no_of_moved = 0;
1529 cmd_info->sh_groups = NULL;
1530
1531 state->sec_table = (section_info_table *)
1532 calloc(shnum + 1, sizeof (section_info_table));
1533 if (state->sec_table == NULL) {
1534 error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog);
1535 mcs_exit(FAILURE);
1536 }
1537
1538 state->off_table = (int64_t *)calloc(shnum, sizeof (int64_t));
1539 if (state->off_table == NULL) {
1540 error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog);
1541 mcs_exit(FAILURE);
1542 }
1543
1544 state->nobits_table = (int64_t *)calloc(shnum, sizeof (int64_t));
1545 if (state->nobits_table == NULL) {
1546 error_message(MALLOC_ERROR, PLAIN_ERROR, NULL, prog);
1547 mcs_exit(FAILURE);
1548 }
1549 }
1550
1551 /*
1552 * Update the contents of SHT_GROUP if needed
1553 */
1554 static void
post_process(Cmd_Info * cmd_info,file_state_t * state)1555 post_process(Cmd_Info *cmd_info, file_state_t *state)
1556 {
1557 Aliste idx;
1558 section_info_table *sinfo;
1559 Word *grpdata, *ngrpdata;
1560 int64_t sno, sno2;
1561 Word i, j, num;
1562
1563 /*
1564 * If no change is required, then return.
1565 */
1566 if (!CHK_OPT(cmd_info, SHF_GROUP_MOVE|SHF_GROUP_DEL))
1567 return;
1568
1569 /*
1570 * If SHF_GROUP sections were removed, we might need to
1571 * remove SHT_GROUP sections.
1572 */
1573 if (CHK_OPT(cmd_info, SHF_GROUP_DEL)) {
1574 Word grpcnt;
1575 int deleted = 0;
1576
1577 for (APLIST_TRAVERSE(cmd_info->sh_groups, idx, sinfo)) {
1578 if (sinfo->secno == (GElf_Word)DELETED)
1579 continue;
1580 num = (sinfo->shdr).sh_size/sizeof (Word);
1581 grpcnt = 0;
1582 grpdata = (Word *)(sinfo->data->d_buf);
1583 for (i = 1; i < num; i++) {
1584 if (state->sec_table[grpdata[i]].secno !=
1585 (GElf_Word)DELETED)
1586 grpcnt++;
1587 }
1588
1589 /*
1590 * All members in this SHT_GROUP were removed.
1591 * We can remove this SHT_GROUP.
1592 */
1593 if (grpcnt == 0) {
1594 sinfo->secno = (GElf_Word)DELETED;
1595 (cmd_info->no_of_delete)++;
1596 deleted = 1;
1597 }
1598 }
1599
1600 /*
1601 * If we deleted a SHT_GROUP section,
1602 * we need to reasign section numbers.
1603 */
1604 if (deleted) {
1605 section_info_table *sinfo;
1606
1607 sno = 1;
1608 sno2 = 1;
1609 while (state->sec_table[sno].scn != (Elf_Scn *)-1) {
1610 sinfo = &state->sec_table[sno];
1611 if (sinfo->secno != (GElf_Word) DELETED)
1612 sinfo->secno = sno2++;
1613 sno++;
1614 }
1615 }
1616 }
1617
1618 /*
1619 * Now we can update data buffers of the SHT_GROUP sections.
1620 */
1621 for (APLIST_TRAVERSE(cmd_info->sh_groups, idx, sinfo)) {
1622 if (sinfo->secno == (GElf_Word)DELETED)
1623 continue;
1624 num = (sinfo->shdr).sh_size/sizeof (Word);
1625
1626 /*
1627 * Need to generate the updated data buffer
1628 */
1629 if ((sinfo->mdata = malloc(sizeof (Elf_Data))) == NULL) {
1630 error_message(MALLOC_ERROR, PLAIN_ERROR, NULL,
1631 prog);
1632 mcs_exit(FAILURE);
1633 }
1634 *(sinfo->mdata) = *(sinfo->data);
1635 if ((ngrpdata = sinfo->mdata->d_buf =
1636 malloc(sinfo->data->d_size)) == NULL) {
1637 error_message(MALLOC_ERROR, PLAIN_ERROR, NULL,
1638 prog);
1639 mcs_exit(FAILURE);
1640 }
1641
1642 grpdata = (Word *)(sinfo->data->d_buf);
1643 ngrpdata[0] = grpdata[0];
1644 j = 1;
1645 for (i = 1; i < num; i++) {
1646 if (state->sec_table[grpdata[i]].secno !=
1647 (GElf_Word)DELETED) {
1648 ngrpdata[j++] =
1649 state->sec_table[grpdata[i]].secno;
1650 }
1651 }
1652 sinfo->mdata->d_size = j * sizeof (Word);
1653 sinfo->data = sinfo->mdata;
1654 }
1655 free(cmd_info->sh_groups);
1656 cmd_info->sh_groups = NULL;
1657 }
1658