1 /* $OpenBSD: crunchide.c,v 1.8 2014/03/16 20:45:47 guenther 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 #include <unistd.h> 55 #include <stdio.h> 56 #include <stdlib.h> 57 #include <string.h> 58 #include <errno.h> 59 #include <fcntl.h> 60 #include <a.out.h> 61 #include <sys/types.h> 62 #include <sys/mman.h> 63 #include <sys/stat.h> 64 #include "mangle.h" 65 66 void usage(void); 67 68 void add_to_keep_list(char *); 69 void add_file_to_keep_list(char *); 70 71 void hide_syms(char *); 72 #ifdef _NLIST_DO_ELF 73 void elf_hide(int, char *); 74 #endif 75 int in_keep_list(char *symbol); 76 int crunchide_main(int argc, char *argv[]); 77 78 extern char *__progname; 79 extern int elf_mangle; 80 81 int 82 crunchide_main(int argc, char *argv[]) 83 { 84 int ch; 85 86 while ((ch = getopt(argc, argv, "Mhk:f:")) != -1) 87 switch (ch) { 88 case 'M': 89 elf_mangle = 1; 90 break; 91 case 'h': 92 break; 93 case 'k': 94 add_to_keep_list(optarg); 95 break; 96 case 'f': 97 add_file_to_keep_list(optarg); 98 break; 99 default: 100 usage(); 101 } 102 103 argc -= optind; 104 argv += optind; 105 106 if (argc == 0) 107 usage(); 108 109 if (elf_mangle) 110 init_mangle_state(); 111 112 while (argc) { 113 hide_syms(*argv); 114 argc--; 115 argv++; 116 } 117 if (elf_mangle) 118 fini_mangle_state(); 119 120 return 0; 121 } 122 123 struct keep { 124 struct keep *next; 125 char *sym; 126 } *keep_list; 127 128 void 129 add_to_keep_list(char *symbol) 130 { 131 struct keep *newp, *prevp, *curp; 132 int cmp = 0; 133 134 for (curp = keep_list, prevp = NULL; curp; prevp = curp, curp = curp->next) 135 if ((cmp = strcmp(symbol, curp->sym)) <= 0) 136 break; 137 138 if (curp && cmp == 0) 139 return; /* already in table */ 140 141 newp = (struct keep *) calloc(1, sizeof(struct keep)); 142 if (newp) 143 newp->sym = strdup(symbol); 144 if (newp == NULL || newp->sym == NULL) { 145 fprintf(stderr, "%s: out of memory for keep list\n", __progname); 146 exit(1); 147 } 148 newp->next = curp; 149 if (prevp) 150 prevp->next = newp; 151 else 152 keep_list = newp; 153 } 154 155 int 156 in_keep_list(char *symbol) 157 { 158 struct keep *curp; 159 int cmp = 0; 160 161 for (curp = keep_list; curp; curp = curp->next) 162 if ((cmp = strcmp(symbol, curp->sym)) <= 0) 163 break; 164 165 return curp && cmp == 0; 166 } 167 168 void 169 add_file_to_keep_list(char *filename) 170 { 171 FILE *keepf; 172 char symbol[1024]; 173 int len; 174 175 if ((keepf = fopen(filename, "r")) == NULL) { 176 perror(filename); 177 usage(); 178 } 179 while (fgets(symbol, sizeof(symbol), keepf)) { 180 len = strlen(symbol); 181 if (len && symbol[len - 1] == '\n') 182 symbol[len - 1] = '\0'; 183 184 add_to_keep_list(symbol); 185 } 186 fclose(keepf); 187 } 188 189 void 190 hide_syms(char *filename) 191 { 192 int inf; 193 struct stat infstat; 194 char *buf; 195 196 /* 197 * Open the file and do some error checking. 198 */ 199 200 if ((inf = open(filename, O_RDWR)) == -1) { 201 perror(filename); 202 return; 203 } 204 if (fstat(inf, &infstat) == -1) { 205 perror(filename); 206 close(inf); 207 return; 208 } 209 if (infstat.st_size < sizeof(struct exec)) { 210 fprintf(stderr, "%s: short file\n", filename); 211 close(inf); 212 return; 213 } 214 if ((buf = mmap(NULL, infstat.st_size, PROT_READ | PROT_WRITE, 215 MAP_FILE | MAP_SHARED, inf, 0)) == MAP_FAILED) { 216 fprintf(stderr, "%s: cannot map\n", filename); 217 close(inf); 218 return; 219 } 220 221 #ifdef _NLIST_DO_ELF 222 if (buf[0] == 0x7f && (buf[1] == 'E' || buf[1] == 'O') && 223 buf[2] == 'L' && buf[3] == 'F') { 224 elf_hide(inf, buf); 225 return; 226 } 227 #endif /* _NLIST_DO_ELF */ 228 } 229