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