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
crunchide_main(int argc,char * argv[])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
add_to_keep_list(char * symbol)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
in_keep_list(char * symbol)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
add_file_to_keep_list(char * filename)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
hide_syms(char * filename)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