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