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