1 /* $OpenBSD: crunchide.c,v 1.12 2017/10/29 08:45:53 mpi Exp $ */ 2 3 /* 4 * Copyright (c) 1994 University of Maryland 5 * All Rights Reserved. 6 * 7 * Permission to use, copy, modify, distribute, and sell this software and its 8 * documentation for any purpose is hereby granted without fee, provided that 9 * the above copyright notice appear in all copies and that both that 10 * copyright notice and this permission notice appear in supporting 11 * documentation, and that the name of U.M. not be used in advertising or 12 * publicity pertaining to distribution of the software without specific, 13 * written prior permission. U.M. makes no representations about the 14 * suitability of this software for any purpose. It is provided "as is" 15 * without express or implied warranty. 16 * 17 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M. 19 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 21 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 22 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 23 * 24 * Author: James da Silva, Systems Design and Analysis Group 25 * Computer Science Department 26 * University of Maryland at College Park 27 */ 28 /* 29 * crunchide.c - tiptoes through an a.out symbol table, hiding all defined 30 * global symbols. Allows the user to supply a "keep list" of symbols 31 * that are not to be hidden. This program relies on the use of the 32 * linker's -dc flag to actually put global bss data into the file's 33 * bss segment (rather than leaving it as undefined "common" data). 34 * 35 * The point of all this is to allow multiple programs to be linked 36 * together without getting multiple-defined errors. 37 * 38 * For example, consider a program "foo.c". It can be linked with a 39 * small stub routine, called "foostub.c", eg: 40 * int foo_main(int argc, char **argv){ return main(argc, argv); } 41 * like so: 42 * cc -c foo.c foostub.c 43 * ld -dc -r foo.o foostub.o -o foo.combined.o 44 * crunchide -k _foo_main foo.combined.o 45 * at this point, foo.combined.o can be linked with another program 46 * and invoked with "foo_main(argc, argv)". foo's main() and any 47 * other globals are hidden and will not conflict with other symbols. 48 * 49 * TODO: 50 * - arrange that all the BSS segments start at the same address, so 51 * that the final crunched binary BSS size is the max of all the 52 * component programs' BSS sizes, rather than their sum. 53 */ 54 55 #include <sys/types.h> 56 #include <sys/mman.h> 57 #include <sys/stat.h> 58 59 #include <elf.h> 60 #include <fcntl.h> 61 #include <stdint.h> 62 #include <stdio.h> 63 #include <stdlib.h> 64 #include <string.h> 65 #include <unistd.h> 66 67 #include "mangle.h" 68 69 void usage(void); 70 71 void add_to_keep_list(char *); 72 void add_file_to_keep_list(char *); 73 74 void hide_syms(char *); 75 void elf_hide(int, char *); 76 int in_keep_list(char *symbol); 77 int crunchide_main(int argc, char *argv[]); 78 79 extern char *__progname; 80 extern int elf_mangle; 81 82 int 83 crunchide_main(int argc, char *argv[]) 84 { 85 int ch; 86 87 while ((ch = getopt(argc, argv, "Mhk:f:")) != -1) 88 switch (ch) { 89 case 'M': 90 elf_mangle = 1; 91 break; 92 case 'h': 93 break; 94 case 'k': 95 add_to_keep_list(optarg); 96 break; 97 case 'f': 98 add_file_to_keep_list(optarg); 99 break; 100 default: 101 usage(); 102 } 103 104 argc -= optind; 105 argv += optind; 106 107 if (argc == 0) 108 usage(); 109 110 if (elf_mangle) 111 init_mangle_state(); 112 113 while (argc) { 114 hide_syms(*argv); 115 argc--; 116 argv++; 117 } 118 if (elf_mangle) 119 fini_mangle_state(); 120 121 return 0; 122 } 123 124 struct keep { 125 struct keep *next; 126 char *sym; 127 } *keep_list; 128 129 void 130 add_to_keep_list(char *symbol) 131 { 132 struct keep *newp, *prevp, *curp; 133 int cmp = 0; 134 135 for (curp = keep_list, prevp = NULL; curp; prevp = curp, curp = curp->next) 136 if ((cmp = strcmp(symbol, curp->sym)) <= 0) 137 break; 138 139 if (curp && cmp == 0) 140 return; /* already in table */ 141 142 newp = calloc(1, sizeof(struct keep)); 143 if (newp) 144 newp->sym = strdup(symbol); 145 if (newp == NULL || newp->sym == NULL) { 146 fprintf(stderr, "%s: out of memory for keep list\n", __progname); 147 exit(1); 148 } 149 newp->next = curp; 150 if (prevp) 151 prevp->next = newp; 152 else 153 keep_list = newp; 154 } 155 156 int 157 in_keep_list(char *symbol) 158 { 159 struct keep *curp; 160 int cmp = 0; 161 162 for (curp = keep_list; curp; curp = curp->next) 163 if ((cmp = strcmp(symbol, curp->sym)) <= 0) 164 break; 165 166 return curp && cmp == 0; 167 } 168 169 void 170 add_file_to_keep_list(char *filename) 171 { 172 FILE *keepf; 173 char symbol[1024]; 174 int len; 175 176 if ((keepf = fopen(filename, "r")) == NULL) { 177 perror(filename); 178 usage(); 179 } 180 while (fgets(symbol, sizeof(symbol), keepf)) { 181 len = strlen(symbol); 182 if (len && symbol[len - 1] == '\n') 183 symbol[len - 1] = '\0'; 184 185 add_to_keep_list(symbol); 186 } 187 fclose(keepf); 188 } 189 190 void 191 hide_syms(char *filename) 192 { 193 int inf; 194 struct stat infstat; 195 char *buf; 196 197 /* 198 * Open the file and do some error checking. 199 */ 200 201 if ((inf = open(filename, O_RDWR)) == -1) { 202 perror(filename); 203 return; 204 } 205 if (fstat(inf, &infstat) == -1) { 206 perror(filename); 207 close(inf); 208 return; 209 } 210 if (infstat.st_size < sizeof(Elf_Ehdr) || infstat.st_size > SIZE_MAX) { 211 fprintf(stderr, "%s: invalid file size\n", filename); 212 close(inf); 213 return; 214 } 215 if ((buf = mmap(NULL, infstat.st_size, PROT_READ | PROT_WRITE, 216 MAP_FILE | MAP_SHARED, inf, 0)) == MAP_FAILED) { 217 fprintf(stderr, "%s: cannot map\n", filename); 218 close(inf); 219 return; 220 } 221 222 if (buf[0] == ELFMAG0 && buf[1] == ELFMAG1 && 223 buf[2] == ELFMAG2 && buf[3] == ELFMAG3) { 224 elf_hide(inf, buf); 225 return; 226 } 227 228 close(inf); 229 } 230