xref: /openbsd/sys/stand/boot/boot.c (revision d89ec533)
1 /*	$OpenBSD: boot.c,v 1.56 2021/10/26 16:29:49 deraadt Exp $	*/
2 
3 /*
4  * Copyright (c) 2003 Dale Rahn
5  * Copyright (c) 1997,1998 Michael Shalayeff
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  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  */
30 
31 #include <sys/param.h>
32 #include <sys/reboot.h>
33 #include <sys/stat.h>
34 #include <libsa.h>
35 #include <lib/libsa/loadfile.h>
36 #include <lib/libkern/funcs.h>
37 #include <lib/libsa/arc4.h>
38 
39 #include <stand/boot/bootarg.h>
40 
41 #include "cmd.h"
42 
43 #ifndef KERNEL
44 #define KERNEL "/bsd"
45 #endif
46 
47 char prog_ident[40];
48 char *progname = "BOOT";
49 
50 extern	const char version[];
51 struct cmd_state cmd;
52 
53 /* bootprompt can be set by MD code to avoid prompt first time round */
54 int bootprompt = 1;
55 char *kernelfile = KERNEL;		/* can be changed by MD code */
56 int boottimeout = 5;			/* can be changed by MD code */
57 
58 char	rnddata[BOOTRANDOM_MAX] __aligned(sizeof(long));
59 struct rc4_ctx randomctx;
60 
61 void
62 boot(dev_t bootdev)
63 {
64 	int fd, isupgrade = 0;
65 	int try = 0, st;
66 	uint64_t marks[MARK_MAX];
67 
68 	machdep();
69 
70 	snprintf(prog_ident, sizeof(prog_ident),
71 	    ">> OpenBSD/" MACHINE " %s %s", progname, version);
72 	printf("%s\n", prog_ident);
73 
74 	devboot(bootdev, cmd.bootdev);
75 	strlcpy(cmd.image, kernelfile, sizeof(cmd.image));
76 	cmd.boothowto = 0;
77 	cmd.conf = "/etc/boot.conf";
78 	cmd.addr = (void *)DEFAULT_KERNEL_ADDRESS;
79 	cmd.timeout = boottimeout;
80 
81 	if (upgrade()) {
82 		strlcpy(cmd.image, "/bsd.upgrade", sizeof(cmd.image));
83 		printf("upgrade detected: switching to %s\n", cmd.image);
84 		isupgrade = 1;
85 	}
86 
87 	st = read_conf();
88 
89 #ifdef HIBERNATE
90 	int bootdev_has_hibernate(void);
91 
92 	if (bootdev_has_hibernate()) {
93 		strlcpy(cmd.image, "/bsd.booted", sizeof(cmd.image));
94 		printf("unhibernate detected: switching to %s\n", cmd.image);
95 		cmd.boothowto |= RB_UNHIBERNATE;
96 	}
97 #endif
98 
99 	if (!bootprompt)
100 		snprintf(cmd.path, sizeof cmd.path, "%s:%s",
101 		    cmd.bootdev, cmd.image);
102 
103 	while (1) {
104 		/* no boot.conf, or no boot cmd in there */
105 		if (bootprompt && st <= 0) {
106 			do {
107 				printf("boot> ");
108 			} while(!getcmd());
109 		}
110 
111 		if (loadrandom(BOOTRANDOM, rnddata, sizeof(rnddata)) == 0)
112 			cmd.boothowto |= RB_GOODRANDOM;
113 #ifdef MDRANDOM
114 		if (mdrandom(rnddata, sizeof(rnddata)) == 0)
115 			cmd.boothowto |= RB_GOODRANDOM;
116 #endif
117 #ifdef FWRANDOM
118 		if (fwrandom(rnddata, sizeof(rnddata)) == 0)
119 			cmd.boothowto |= RB_GOODRANDOM;
120 #endif
121 		rc4_keysetup(&randomctx, rnddata, sizeof rnddata);
122 		rc4_skip(&randomctx, 1536);
123 
124 		st = 0;
125 		bootprompt = 1;	/* allow reselect should we fail */
126 
127 		printf("booting %s: ", cmd.path);
128 		marks[MARK_START] = (u_long)cmd.addr;
129 		if ((fd = loadfile(cmd.path, marks, LOAD_ALL)) != -1) {
130 
131 		        /* Prevent re-upgrade: chmod a-x bsd.upgrade */
132 			if (isupgrade) {
133 				struct stat st;
134 
135 				if (fstat(fd, &st) == 0) {
136 					st.st_mode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
137 					if (fchmod(fd, st.st_mode) == -1)
138 						printf("fchmod a-x %s: failed\n",
139 						    cmd.path);
140 				}
141 			}
142 			close(fd);
143 			break;
144 		}
145 
146 		kernelfile = KERNEL;
147 		try++;
148 		strlcpy(cmd.image, kernelfile, sizeof(cmd.image));
149 		printf(" failed(%d). will try %s\n", errno, kernelfile);
150 
151 		if (try < 2) {
152 			if (cmd.timeout > 0)
153 				cmd.timeout++;
154 		} else {
155 			if (cmd.timeout)
156 				printf("Turning timeout off.\n");
157 			cmd.timeout = 0;
158 		}
159 	}
160 
161 	/* exec */
162 	run_loadfile(marks, cmd.boothowto);
163 }
164 
165 int
166 loadrandom(char *name, char *buf, size_t buflen)
167 {
168 	char path[MAXPATHLEN];
169 	struct stat sb;
170 	int fd, i, error = 0;
171 
172 	/* Extract the device name from the kernel we are loading. */
173 	for (i = 0; i < sizeof(cmd.path); i++) {
174 		if (cmd.path[i] == ':') {
175 			strlcpy(path, cmd.path, i + 1);
176 			snprintf(path + i, sizeof(path) - i, ":%s", name);
177 			break;
178 		} else if (cmd.path[i] == '\0') {
179 			snprintf(path, sizeof path, "%s:%s",
180 			    cmd.bootdev, name);
181 			break;
182 		}
183 	}
184 
185 	fd = open(path, O_RDONLY);
186 	if (fd == -1) {
187 		if (errno != EPERM)
188 			printf("cannot open %s: %s\n", path, strerror(errno));
189 		return -1;
190 	}
191 	if (fstat(fd, &sb) == -1) {
192 		error = -1;
193 		goto done;
194 	}
195 	if (read(fd, buf, buflen) != buflen) {
196 		error = -1;
197 		goto done;
198 	}
199 	if (sb.st_mode & S_ISTXT) {
200 		printf("NOTE: random seed is being reused.\n");
201 		error = -1;
202 		goto done;
203 	}
204 	fchmod(fd, sb.st_mode | S_ISTXT);
205 done:
206 	close(fd);
207 	return (error);
208 }
209