xref: /openbsd-src/sys/arch/octeon/stand/rdboot/rdboot.c (revision 46035553bfdd96e63c94e32da0210227ec2e3cf1)
1 /*	$OpenBSD: rdboot.c,v 1.8 2020/12/09 18:10:19 krw Exp $	*/
2 
3 /*
4  * Copyright (c) 2019-2020 Visa Hankala
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/param.h>
21 #include <sys/ioctl.h>
22 #include <sys/mount.h>
23 #include <sys/reboot.h>
24 #include <sys/select.h>
25 #include <sys/stat.h>
26 
27 #include <err.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <paths.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <termios.h>
35 #include <unistd.h>
36 #include <util.h>
37 
38 #include <machine/octboot.h>
39 #include <machine/param.h>
40 
41 #include "cmd.h"
42 #include "disk.h"
43 
44 #define DEVRANDOM	"/dev/random"
45 #define BOOTRANDOM	"/etc/random.seed"
46 #define BOOTRANDOM_MAX	256	/* no point being greater than RC4STATE */
47 #define KERNEL		"/bsd"
48 
49 int	loadrandom(void);
50 void	kexec(void);
51 
52 struct cmd_state cmd;
53 int octbootfd = -1;
54 const char version[] = "1.3";
55 
56 int
57 main(void)
58 {
59 	char rootdev[PATH_MAX];
60 	int fd, hasboot;
61 
62 	fd = open(_PATH_CONSOLE, O_RDWR);
63 	login_tty(fd);
64 
65 	/* Keep stdout unbuffered to mimic ordinary bootblocks. */
66 	setvbuf(stdout, NULL, _IONBF, 0);
67 
68 	printf(">> OpenBSD/" MACHINE " BOOT %s\n", version);
69 
70 	octbootfd = open("/dev/octboot", O_WRONLY);
71 	if (octbootfd == -1)
72 		err(1, "cannot open boot control device");
73 
74 	memset(&cmd, 0, sizeof(cmd));
75 	cmd.boothowto = 0;
76 	cmd.conf = "/etc/boot.conf";
77 	strlcpy(cmd.image, KERNEL, sizeof(cmd.image));
78 	cmd.timeout = 5;
79 
80 	if (ioctl(octbootfd, OBIOC_GETROOTDEV, rootdev) == -1) {
81 		if (errno != ENOENT)
82 			fprintf(stderr, "cannot get rootdev from kernel: %s\n",
83 			    strerror(errno));
84 	} else {
85 		snprintf(cmd.bootdev, sizeof(cmd.bootdev), "%s%sa",
86 		    rootdev, isduid(rootdev, OPENDEV_PART) ? "." : "");
87 	}
88 
89 	disk_init();
90 
91 	if (upgrade()) {
92 		strlcpy(cmd.image, "/bsd.upgrade", sizeof(cmd.image));
93 		printf("upgrade detected: switching to %s\n", cmd.image);
94 	}
95 
96 	hasboot = read_conf();
97 
98 	for (;;) {
99 		if (hasboot <= 0) {
100 			do {
101 				printf("boot> ");
102 			} while (!getcmd());
103 		}
104 
105 		if (loadrandom() == 0)
106 			cmd.boothowto |= RB_GOODRANDOM;
107 
108 		kexec();
109 
110 		hasboot = 0;
111 		strlcpy(cmd.image, KERNEL, sizeof(cmd.image));
112 		printf("will try %s\n", cmd.image);
113 	}
114 
115 	return 0;
116 }
117 
118 int
119 loadrandom(void)
120 {
121 	char buf[BOOTRANDOM_MAX];
122 	struct stat sb;
123 	int fd, ret = 0;
124 
125 	/* Read the file from the device specified by the kernel path. */
126 	if (disk_open(cmd.path) == NULL)
127 		return -1;
128 	fd = open(BOOTRANDOM, O_RDONLY);
129 	if (fd == -1) {
130 		fprintf(stderr, "%s: cannot open %s: %s", __func__, BOOTRANDOM,
131 		    strerror(errno));
132 		disk_close();
133 		return -1;
134 	}
135 	if (fstat(fd, &sb) == 0) {
136 		if (sb.st_mode & S_ISTXT) {
137 			printf("NOTE: random seed is being reused.\n");
138 			ret = -1;
139 		}
140 		if (read(fd, buf, sizeof(buf)) != sizeof(buf))
141 			ret = -1;
142 		fchmod(fd, sb.st_mode | S_ISTXT);
143 	} else {
144 		ret = -1;
145 	}
146 	close(fd);
147 	disk_close();
148 
149 	/*
150 	 * Push the whole buffer to the entropy pool.
151 	 * The kernel will use the entropy on kexec().
152 	 * It does not matter if some of the buffer content is uninitialized.
153 	 */
154 	fd = open(DEVRANDOM, O_WRONLY);
155 	if (fd == -1) {
156 		fprintf(stderr, "%s: cannot open %s: %s", __func__,
157 		    DEVRANDOM, strerror(errno));
158 		return -1;
159 	}
160 	write(fd, buf, sizeof(buf));
161 	close(fd);
162 	return ret;
163 }
164 
165 void
166 kexec(void)
167 {
168 	struct octboot_kexec_args kargs;
169 	struct stat sb;
170 	char boothowtostr[32];
171 	char rootdev[32];
172 	char *kimg = NULL;
173 	const char *path;
174 	ssize_t n;
175 	off_t pos;
176 	int argc, fd = -1, ret;
177 
178 	path = disk_open(cmd.path);
179 	if (path == NULL)
180 		return;
181 
182 	fd = open(path, O_RDONLY);
183 	if (fd == -1)
184 		goto load_failed;
185 	if (fstat(fd, &sb) == -1)
186 		goto load_failed;
187 	if (!S_ISREG(sb.st_mode) || sb.st_size == 0) {
188 		errno = ENOEXEC;
189 		goto load_failed;
190 	}
191 
192 	kimg = malloc(sb.st_size);
193 	if (kimg == NULL)
194 		goto load_failed;
195 
196 	pos = 0;
197 	while (pos < sb.st_size) {
198 		n = read(fd, kimg + pos, sb.st_size - pos);
199 		if (n == -1)
200 			goto load_failed;
201 		pos += n;
202 	}
203 
204 	close(fd);
205 	disk_close();
206 
207 	memset(&kargs, 0, sizeof(kargs));
208 	kargs.kimg = kimg;
209 	kargs.klen = sb.st_size;
210 	argc = 0;
211 	if (cmd.boothowto != 0) {
212 		snprintf(boothowtostr, sizeof(boothowtostr), "boothowto=%d",
213 		    cmd.boothowto);
214 		kargs.argv[argc++] = boothowtostr;
215 	}
216 	if (cmd.hasduid) {
217 		snprintf(rootdev, sizeof(rootdev),
218 		    "rootdev=%02x%02x%02x%02x%02x%02x%02x%02x",
219 		    cmd.bootduid[0], cmd.bootduid[1],
220 		    cmd.bootduid[2], cmd.bootduid[3],
221 		    cmd.bootduid[4], cmd.bootduid[5],
222 		    cmd.bootduid[6], cmd.bootduid[7]);
223 		kargs.argv[argc++] = rootdev;
224 	}
225 
226 	printf("booting %s\n", cmd.path);
227 	ret = ioctl(octbootfd, OBIOC_KEXEC, &kargs);
228 	if (ret == -1)
229 		fprintf(stderr, "failed to execute kernel %s: %s\n",
230 		    cmd.path, strerror(errno));
231 	else
232 		fprintf(stderr, "kexec() returned unexpectedly\n");
233 	free(kimg);
234 	return;
235 
236 load_failed:
237 	fprintf(stderr, "failed to load kernel %s: %s\n",
238 	    cmd.path, strerror(errno));
239 	if (fd != -1)
240 		close(fd);
241 	disk_close();
242 	free(kimg);
243 }
244