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