xref: /freebsd/usr.bin/brandelf/brandelf.c (revision 22cf89c938886d14f5796fc49f9f020c23ea8eaf)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 2000, 2001 David O'Brien
5  * Copyright (c) 1996 Søren Schmidt
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer
13  *    in this position and unchanged.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 #include <sys/param.h>
34 #include <sys/capsicum.h>
35 #include <sys/elf_common.h>
36 #include <sys/errno.h>
37 
38 #include <capsicum_helpers.h>
39 #include <err.h>
40 #include <fcntl.h>
41 #include <stdbool.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46 
47 #include <libcasper.h>
48 #include <casper/cap_fileargs.h>
49 
50 static int elftype(const char *);
51 static const char *iselftype(int);
52 static void printelftypes(void);
53 static void usage(void) __dead2;
54 
55 struct ELFtypes {
56 	const char *str;
57 	int value;
58 };
59 /* XXX - any more types? */
60 static struct ELFtypes elftypes[] = {
61 	{ "FreeBSD",	ELFOSABI_FREEBSD },
62 	{ "Linux",	ELFOSABI_LINUX },
63 	{ "Solaris",	ELFOSABI_SOLARIS },
64 	{ "SVR4",	ELFOSABI_SYSV }
65 };
66 
67 int
68 main(int argc, char **argv)
69 {
70 
71 	const char *strtype = "FreeBSD";
72 	int ch, flags, retval, type;
73 	bool change, force, listed;
74 	fileargs_t *fa;
75 	cap_rights_t rights;
76 
77 	type = ELFOSABI_FREEBSD;
78 	retval = 0;
79 	change = false;
80 	force = false;
81 	listed = false;
82 
83 	while ((ch = getopt(argc, argv, "f:lt:v")) != -1)
84 		switch (ch) {
85 		case 'f':
86 			if (change)
87 				errx(1, "f option incompatible with t option");
88 			force = true;
89 			type = atoi(optarg);
90 			if (errno == ERANGE || type < 0 || type > 255) {
91 				warnx("invalid argument to option f: %s",
92 				    optarg);
93 				usage();
94 			}
95 			break;
96 		case 'l':
97 			printelftypes();
98 			listed = true;
99 			break;
100 		case 'v':
101 			/* does nothing */
102 			break;
103 		case 't':
104 			if (force)
105 				errx(1, "t option incompatible with f option");
106 			change = true;
107 			strtype = optarg;
108 			break;
109 		default:
110 			usage();
111 	}
112 	argc -= optind;
113 	argv += optind;
114 	if (argc == 0) {
115 		if (listed)
116 			exit(0);
117 		else {
118 			warnx("no file(s) specified");
119 			usage();
120 		}
121 	}
122 
123 	if (!force && (type = elftype(strtype)) == -1) {
124 		warnx("invalid ELF type '%s'", strtype);
125 		printelftypes();
126 		usage();
127 	}
128 
129 	flags = change || force ? O_RDWR : O_RDONLY;
130 	cap_rights_init(&rights, CAP_READ, CAP_SEEK);
131 	if (flags == O_RDWR)
132 		cap_rights_set(&rights, CAP_WRITE);
133 
134 	fa = fileargs_init(argc, argv, flags, 0, &rights, FA_OPEN);
135 	if (fa == NULL)
136 		err(1, "unable to init casper");
137 
138 	caph_cache_catpages();
139 	if (caph_limit_stdio() < 0 || caph_enter_casper() < 0)
140 		err(1, "unable to enter capability mode");
141 
142 	while (argc != 0) {
143 		int fd;
144 		char buffer[EI_NIDENT];
145 
146 		if ((fd = fileargs_open(fa, argv[0])) < 0) {
147 			warn("error opening file %s", argv[0]);
148 			retval = 1;
149 			goto fail;
150 		}
151 		if (read(fd, buffer, EI_NIDENT) < EI_NIDENT) {
152 			warnx("file '%s' too short", argv[0]);
153 			retval = 1;
154 			goto fail;
155 		}
156 		if (buffer[0] != ELFMAG0 || buffer[1] != ELFMAG1 ||
157 		    buffer[2] != ELFMAG2 || buffer[3] != ELFMAG3) {
158 			warnx("file '%s' is not ELF format", argv[0]);
159 			retval = 1;
160 			goto fail;
161 		}
162 		if (!change && !force) {
163 			fprintf(stdout,
164 				"File '%s' is of brand '%s' (%u).\n",
165 				argv[0], iselftype(buffer[EI_OSABI]),
166 				buffer[EI_OSABI]);
167 			if (!iselftype(type)) {
168 				warnx("ELF ABI Brand '%u' is unknown",
169 				      type);
170 				printelftypes();
171 			}
172 		}
173 		else {
174 			buffer[EI_OSABI] = type;
175 			lseek(fd, 0, SEEK_SET);
176 			if (write(fd, buffer, EI_NIDENT) != EI_NIDENT) {
177 				warn("error writing %s %d", argv[0], fd);
178 				retval = 1;
179 				goto fail;
180 			}
181 		}
182 fail:
183 		close(fd);
184 		argc--;
185 		argv++;
186 	}
187 
188 	fileargs_free(fa);
189 	return (retval);
190 }
191 
192 static void
193 usage(void)
194 {
195 	(void)fprintf(stderr,
196 	    "usage: brandelf [-lv] [-f ELF_ABI_number] [-t string] file ...\n");
197 	exit(1);
198 }
199 
200 static const char *
201 iselftype(int etype)
202 {
203 	size_t elfwalk;
204 
205 	for (elfwalk = 0; elfwalk < nitems(elftypes); elfwalk++)
206 		if (etype == elftypes[elfwalk].value)
207 			return (elftypes[elfwalk].str);
208 	return (0);
209 }
210 
211 static int
212 elftype(const char *elfstrtype)
213 {
214 	size_t elfwalk;
215 
216 	for (elfwalk = 0; elfwalk < nitems(elftypes); elfwalk++)
217 		if (strcasecmp(elfstrtype, elftypes[elfwalk].str) == 0)
218 			return (elftypes[elfwalk].value);
219 	return (-1);
220 }
221 
222 static void
223 printelftypes(void)
224 {
225 	size_t elfwalk;
226 
227 	fprintf(stderr, "known ELF types are: ");
228 	for (elfwalk = 0; elfwalk < nitems(elftypes); elfwalk++)
229 		fprintf(stderr, "%s(%u) ", elftypes[elfwalk].str,
230 		    elftypes[elfwalk].value);
231 	fprintf(stderr, "\n");
232 }
233