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 * 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 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 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