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