xref: /openbsd-src/usr.sbin/rdsetroot/rdsetroot.c (revision 7829d1e3305aa982fa0b0655ab71db9d25e9ed74)
1 /*	$OpenBSD: rdsetroot.c,v 1.1 2019/04/05 21:07:11 deraadt Exp $	*/
2 
3 /*
4  * Copyright (c) 1994 Gordon W. Ross
5  * Copyright (c) 1997 Per Fogelstrom. (ELF modifications)
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  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 /*
32  * Copy a ramdisk image into the space reserved for it.
33  * Kernel variables: rd_root_size, rd_root_image
34  */
35 
36 #include <sys/types.h>
37 #include <sys/mman.h>
38 #include <sys/stat.h>
39 
40 #include <elf.h>
41 #include <fcntl.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <unistd.h>
45 #include <err.h>
46 
47 #include "rdsetroot.h"
48 
49 struct elfhdr head;
50 
51 /* Offsets relative to start of data segment. */
52 long	rd_root_image_off, rd_root_size_off;
53 
54 /* value in the location at rd_root_size_off */
55 off_t	rd_root_size_val;
56 
57 /* pointers to pieces of mapped file */
58 char	*dataseg;
59 
60 /* parameters to mmap digged out from program header */
61 off_t	mmap_off;
62 size_t	mmap_size;
63 
64 __dead void usage(void);
65 
66 int	debug;
67 
68 struct elf_fn *elf_fn;
69 
70 int
71 main(int argc, char *argv[])
72 {
73 	int ch, kfd, n, xflag = 0, fsfd;
74 	char *fs = NULL;
75 	char *kernel;
76 	u_int32_t *ip;
77 
78 	while ((ch = getopt(argc, argv, "dx")) != -1) {
79 		switch (ch) {
80 		case 'd':
81 			debug = 1;
82 			break;
83 		case 'x':
84 			xflag = 1;
85 			break;
86 		default:
87 			usage();
88 		}
89 	}
90 	argc -= optind;
91 	argv += optind;
92 
93 	if (argc == 1)
94 		kernel = argv[0];
95 	else if (argc == 2) {
96 		kernel = argv[0];
97 		fs = argv[1];
98 	} else
99 		usage();
100 
101 	kfd = open(kernel, xflag ? O_RDONLY : O_RDWR, 0644);
102 	if (kfd < 0)
103 		err(1, "%s", kernel);
104 
105 	if (fs) {
106 		if (xflag)
107 			fsfd = open(fs, O_RDWR | O_CREAT | O_TRUNC, 0644);
108 		else
109 			fsfd = open(fs, O_RDONLY, 0644);
110 	} else {
111 		if (xflag)
112 			fsfd = dup(STDOUT_FILENO);
113 		else
114 			fsfd = dup(STDIN_FILENO);
115 	}
116 	if (fsfd < 0)
117 		err(1, "%s", fs);
118 
119 	if (pledge("stdio", NULL) == -1)
120 		err(1, "pledge");
121 
122 	n = read(kfd, &head, sizeof(head));
123 	if (n < sizeof(head))
124 		err(1, "%s: reading header", kernel);
125 
126 	if (!IS_ELF(head))
127 		err(1, "%s: bad magic number", kernel);
128 
129 	if (head.e_ident[EI_CLASS] == ELFCLASS32) {
130 		elf_fn = &ELF32_fn;
131 	} else if (head.e_ident[EI_CLASS] == ELFCLASS64) {
132 		elf_fn = &ELF64_fn;
133 	} else {
134 		fprintf(stderr, "%s: invalid elf, not 32 or 64 bit", kernel);
135 		exit(1);
136 	}
137 
138 	elf_fn->locate_image(kfd, &head, kernel, &rd_root_size_off,
139 	    &rd_root_image_off, &mmap_off, &mmap_size);
140 
141 	/*
142 	 * Map in the whole data segment.
143 	 * The file offset needs to be page aligned.
144 	 */
145 	dataseg = mmap(NULL, mmap_size,
146 	    xflag ? PROT_READ : PROT_READ | PROT_WRITE,
147 	    MAP_SHARED, kfd, mmap_off);
148 	if (dataseg == MAP_FAILED)
149 		err(1, "%s: can not map data seg", kernel);
150 
151 	/*
152 	 * Find value in the location: rd_root_size
153 	 */
154 	ip = (u_int32_t *) (dataseg + rd_root_size_off);
155 	rd_root_size_val = *ip;
156 	if (debug)
157 		fprintf(stderr, "rd_root_size  val: 0x%llx (%lld blocks)\n",
158 		    (unsigned long long)rd_root_size_val,
159 		    (unsigned long long)rd_root_size_val >> 9);
160 
161 	/*
162 	 * Copy the symbol table and string table.
163 	 */
164 	if (debug)
165 		fprintf(stderr, "copying root image...\n");
166 
167 	if (xflag) {
168 		n = write(fsfd, dataseg + rd_root_image_off,
169 		    (size_t)rd_root_size_val);
170 		if (n != rd_root_size_val)
171 			err(1, "write");
172 	} else {
173 		struct stat sstat;
174 
175 		if (fstat(fsfd, &sstat) == -1)
176 			err(1, "fstat");
177 		if (S_ISREG(sstat.st_mode) &&
178 		    sstat.st_size > rd_root_size_val) {
179 			fprintf(stderr, "ramdisk too small 0x%llx 0x%llx\n",
180 			    (unsigned long long)sstat.st_size,
181 			    (unsigned long long)rd_root_size_val);
182 			exit(1);
183 		}
184 		n = read(fsfd, dataseg + rd_root_image_off,
185 		    (size_t)rd_root_size_val);
186 		if (n < 0)
187 			err(1, "read");
188 
189 		msync(dataseg, mmap_size, 0);
190 	}
191 
192 	if (debug)
193 		fprintf(stderr, "...copied %d bytes\n", n);
194 	exit(0);
195 }
196 
197 __dead void
198 usage(void)
199 {
200 	extern char *__progname;
201 
202 	fprintf(stderr, "usage: %s [-dx] bsd [fs]\n", __progname);
203 	exit(1);
204 }
205