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 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25
26 /*
27 * dcom: Delete Comment
28 *
29 * This program demonstrates the use of libelf interface to
30 * copy the contents of one ELF file to create a new one.
31 * dcom creates a new ELF file using elf_begin(ELF_C_WRITE).
32 *
33 * In order to delete a section from an ELF file you must
34 * instead create a new ELF file and copy all but the 'selected'
35 * sections to the new ELF file. This is because libelf is
36 * unable to delete any sections from an ELF file, it can
37 * only add them.
38 *
39 * NOTE: While this program works fine for simple ELF objects,
40 * as they get more complex it may not properly update all of the
41 * fields required. This program is *only* an example of how
42 * to do this and not a complete program in itself.
43 */
44 #include <stdio.h>
45 #include <libelf.h>
46 #include <gelf.h>
47 #include <fcntl.h>
48 #include <string.h>
49 #include <stdlib.h>
50 #include <unistd.h>
51 #include <sys/types.h>
52 #include <sys/stat.h>
53 #include <sys/param.h>
54
55
56 static const char *CommentStr = ".comment";
57
58 /*
59 * Build a temporary file name that is in the
60 * same directory as the elf file being processed.
61 */
62 static char *
mkname(const char * bname)63 mkname(const char *bname)
64 {
65 char *ptr;
66 char buffer[MAXPATHLEN];
67
68 ptr = strcpy(buffer, bname);
69 ptr += strlen(buffer);
70 while (ptr >= buffer) {
71 if (*ptr == '/') {
72 *(ptr + 1) = '\0';
73 break;
74 }
75 ptr--;
76 }
77 if (ptr < buffer) {
78 buffer[0] = '.';
79 buffer[1] = '\0';
80 }
81 return (tempnam(buffer, 0));
82 }
83
84 static void
delete_comment(Elf * elf,int fd,const char * file)85 delete_comment(Elf *elf, int fd, const char *file)
86 {
87 Elf_Scn *scn = NULL;
88 char *tfile;
89 Elf *telf;
90 GElf_Ehdr ehdr, tehdr;
91 GElf_Phdr phdr, tphdr;
92 size_t shstrndx, shnum, phnum;
93 int tfd, *shndx, ndx = 1, off = 0;
94 struct stat sbuf;
95
96 if (gelf_getehdr(elf, &ehdr) == NULL) {
97 (void) fprintf(stderr, "%s: elf_getehdr() failed: %s\n",
98 file, elf_errmsg(0));
99 return;
100 }
101
102 if (elf_getshdrnum(elf, &shnum) == -1) {
103 (void) fprintf(stderr, "%s: elf_getshdrnum() failed: %s\n",
104 file, elf_errmsg(0));
105 return;
106 }
107
108 if (elf_getshdrstrndx(elf, &shstrndx) == -1) {
109 (void) fprintf(stderr, "%s: elf_getshdrstrndx() failed: %s\n",
110 file, elf_errmsg(0));
111 return;
112 }
113
114 if (elf_getphdrnum(elf, &phnum) == -1) {
115 (void) fprintf(stderr, "%s: elf_getphdrnum() failed: %s\n",
116 file, elf_errmsg(0));
117 return;
118 }
119
120 /*
121 * shndx is an array used to map the current section
122 * indexes to the new section indexes.
123 */
124 shndx = calloc(shnum, sizeof (int));
125
126 while ((scn = elf_nextscn(elf, scn)) != NULL) {
127 GElf_Shdr shdr;
128
129 /*
130 * Do a string compare to examine each section header
131 * to see if it is a ".comment" section. If it is then
132 * this is the section we want to process.
133 */
134 if (gelf_getshdr(scn, &shdr) == NULL) {
135 (void) fprintf(stderr, "%s: elf_getshdr() failed: %s\n",
136 file, elf_errmsg(0));
137 free(shndx);
138 return;
139 }
140 if (strcmp(CommentStr, elf_strptr(elf, shstrndx,
141 shdr.sh_name)) == 0) {
142 shndx[ndx] = -1;
143 off++;
144
145 /*
146 * If the .comment section is part of a loadable
147 * segment then it can not be delted from the
148 * ELF file.
149 */
150 if (shdr.sh_addr != 0) {
151 (void) printf("%s: .comment section is "
152 "part of a loadable segment, it "
153 "cannot be deleted.\n", file);
154 free(shndx);
155 return;
156 }
157 } else
158 shndx[ndx] = ndx - off;
159 ndx++;
160 }
161
162 /*
163 * obtain a unique file name and open a file descriptor
164 * pointing to that file.
165 */
166 tfile = mkname(file);
167 if ((tfd = open(tfile, O_RDWR | O_CREAT, 0600)) == -1) {
168 perror("temp open");
169 return;
170 }
171
172 /*
173 * Create a new ELF to duplicate the ELF file into.
174 */
175 if ((telf = elf_begin(tfd, ELF_C_WRITE, 0)) == NULL) {
176 (void) fprintf(stderr, "elf_begin(ELF_C_WRITE) failed: %s\n",
177 elf_errmsg(0));
178 return;
179 }
180
181 if (gelf_newehdr(telf, gelf_getclass(elf)) == NULL) {
182 (void) fprintf(stderr, "%s: elf_newehdr() failed: %s\n",
183 file, elf_errmsg(0));
184 free(shndx);
185 return;
186 }
187 if (gelf_getehdr(telf, &tehdr) == NULL) {
188 (void) fprintf(stderr, "%s: elf_getehdr() failed: %s\n",
189 file, elf_errmsg(0));
190 free(shndx);
191 return;
192 }
193
194 scn = NULL;
195 ndx = 1;
196 while ((scn = elf_nextscn(elf, scn)) != NULL) {
197 Elf_Scn *tscn;
198 Elf_Data *data, *tdata;
199 GElf_Shdr shdr, tshdr;
200
201 if (shndx[ndx] == -1) {
202 ndx++;
203 continue;
204 }
205
206 /*
207 * Duplicate all but the .comment section in the
208 * new file.
209 */
210 if (gelf_getshdr(scn, &shdr) == NULL) {
211 (void) fprintf(stderr, "%s: elf_getshdr() failed: %s\n",
212 file, elf_errmsg(0));
213 free(shndx);
214 return;
215 }
216 if ((tscn = elf_newscn(telf)) == NULL) {
217 (void) fprintf(stderr, "%s: elf_newscn() failed: %s\n",
218 file, elf_errmsg(0));
219 free(shndx);
220 return;
221 }
222 if (gelf_getshdr(tscn, &tshdr) == NULL) {
223 (void) fprintf(stderr, "%s: elf_getshdr() failed: %s\n",
224 file, elf_errmsg(0));
225 free(shndx);
226 return;
227 }
228 tshdr = shdr;
229 tshdr.sh_link = shndx[shdr.sh_link];
230
231 /*
232 * The relocation sections sh_info field also contains
233 * a section index that needs to be adjusted. This is
234 * the only section who's sh_info field contains
235 * a section index according to the ABI.
236 *
237 * If their are non-ABI sections who's sh_info field
238 * contains section indexes they will not properly
239 * be updated by this routine.
240 */
241 if (shdr.sh_type == SHT_REL)
242 tshdr.sh_info = shndx[ndx];
243
244 /*
245 * Flush the changes to the underlying elf32 or elf64
246 * section header.
247 */
248 (void) gelf_update_shdr(tscn, &tshdr);
249
250 if ((data = elf_getdata(scn, 0)) == NULL) {
251 (void) fprintf(stderr, "%s: elf_getdata() failed: %s\n",
252 file, elf_errmsg(0));
253 free(shndx);
254 return;
255 }
256 if ((tdata = elf_newdata(tscn)) == NULL) {
257 (void) fprintf(stderr, "%s: elf_newdata() failed: %s\n",
258 file, elf_errmsg(0));
259 free(shndx);
260 return;
261 }
262 *tdata = *data;
263 ndx++;
264 }
265
266 tehdr = ehdr;
267 if (shndx[shstrndx] < SHN_LORESERVE)
268 tehdr.e_shstrndx = shndx[shstrndx];
269 else {
270 Elf_Scn *_scn;
271 GElf_Shdr shdr0;
272
273 /*
274 * 'ELF Extended Sections' are enabled - we must
275 * store the shstrndx in Shdr[0].sh_link
276 */
277 if ((_scn = elf_getscn(telf, 0)) == NULL) {
278 (void) fprintf(stderr, "%s: elf_getscn() failed: %s\n",
279 file, elf_errmsg(0));
280 free(shndx);
281 return;
282 }
283 if (gelf_getshdr(_scn, &shdr0) == NULL) {
284 (void) fprintf(stderr, "%s: elf_getshdr() failed: %s\n",
285 file, elf_errmsg(0));
286 free(shndx);
287 return;
288 }
289 tehdr.e_shstrndx = SHN_XINDEX;
290 shdr0.sh_link = shndx[shstrndx];
291 (void) gelf_update_shdr(_scn, &shdr0);
292 }
293 (void) gelf_update_ehdr(telf, &tehdr);
294
295 free(shndx);
296
297 /*
298 * Duplicate all program headers contained in the ELF file.
299 */
300 if (phnum != 0) {
301 if (gelf_newphdr(telf, phnum) == NULL) {
302 (void) fprintf(stderr, "%s: elf_newphdr() failed: %s\n",
303 file, elf_errmsg(0));
304 return;
305 }
306 for (ndx = 0; ndx < (int)phnum; ndx++) {
307 if (gelf_getphdr(elf, ndx, &phdr) == NULL ||
308 gelf_getphdr(telf, ndx, &tphdr) == NULL) {
309 (void) fprintf(stderr,
310 "%s: elf_getphdr() failed: %s\n",
311 file, elf_errmsg(0));
312 return;
313 }
314 tphdr = phdr;
315 (void) gelf_update_phdr(telf, ndx, &tphdr);
316 }
317 }
318
319 /*
320 * The new Elf file has now been fully described to libelf.
321 * elf_update() will construct the new Elf file and write
322 * it out to disk.
323 */
324 if (elf_update(telf, ELF_C_WRITE) == -1) {
325 (void) fprintf(stderr, "elf_update() failed: %s\n",
326 elf_errmsg(0));
327 (void) elf_end(telf);
328 (void) close(tfd);
329 return;
330 }
331 (void) elf_end(telf);
332
333 /*
334 * set new files permissions to the original files
335 * permissions.
336 */
337 (void) fstat(fd, &sbuf);
338 (void) fchmod(tfd, sbuf.st_mode);
339
340 (void) close(tfd);
341
342 /*
343 * delete the original file and rename the new file
344 * to the orignal file.
345 */
346 (void) rename(tfile, file);
347 }
348
349 int
main(int argc,char ** argv)350 main(int argc, char ** argv)
351 {
352 int i;
353
354 if (argc < 2) {
355 (void) printf("usage: %s elf_file ...\n", argv[0]);
356 return (1);
357 }
358
359 /*
360 * Initialize the elf library, must be called before elf_begin()
361 * can be called.
362 */
363 if (elf_version(EV_CURRENT) == EV_NONE) {
364 (void) fprintf(stderr, "elf_version() failed: %s\n",
365 elf_errmsg(0));
366 return (1);
367 }
368
369 for (i = 1; i < argc; i++) {
370 int fd;
371 Elf *elf;
372 char *elf_fname;
373
374 elf_fname = argv[i];
375
376 if ((fd = open(elf_fname, O_RDONLY)) == -1) {
377 perror("open");
378 continue;
379 }
380
381 /*
382 * Attempt to open an Elf descriptor Read/Write
383 * for each file.
384 */
385 if ((elf = elf_begin(fd, ELF_C_READ, 0)) == NULL) {
386 (void) fprintf(stderr, "elf_begin() failed: %s\n",
387 elf_errmsg(0));
388 (void) close(fd);
389 continue;
390 }
391
392 /*
393 * Determine what kind of elf file this is:
394 */
395 if (elf_kind(elf) != ELF_K_ELF) {
396 /*
397 * can only delete comment sections from
398 * ELF files.
399 */
400 (void) printf("%s not of type ELF_K_ELF. "
401 "elf_kind == %d\n", elf_fname, elf_kind(elf));
402 } else
403 delete_comment(elf, fd, elf_fname);
404
405 (void) elf_end(elf);
406 (void) close(fd);
407 }
408
409 return (0);
410 }
411