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