xref: /openbsd/sys/stand/boot/boot.c (revision a4f11372)
1 /*	$OpenBSD: boot.c,v 1.57 2023/02/23 19:48:22 miod 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
boot(dev_t bootdev)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.timeout = boottimeout;
79 
80 	if (upgrade()) {
81 		strlcpy(cmd.image, "/bsd.upgrade", sizeof(cmd.image));
82 		printf("upgrade detected: switching to %s\n", cmd.image);
83 		isupgrade = 1;
84 	}
85 
86 	st = read_conf();
87 
88 #ifdef HIBERNATE
89 	int bootdev_has_hibernate(void);
90 
91 	if (bootdev_has_hibernate()) {
92 		strlcpy(cmd.image, "/bsd.booted", sizeof(cmd.image));
93 		printf("unhibernate detected: switching to %s\n", cmd.image);
94 		cmd.boothowto |= RB_UNHIBERNATE;
95 	}
96 #endif
97 
98 	if (!bootprompt)
99 		snprintf(cmd.path, sizeof cmd.path, "%s:%s",
100 		    cmd.bootdev, cmd.image);
101 
102 	while (1) {
103 		/* no boot.conf, or no boot cmd in there */
104 		if (bootprompt && st <= 0) {
105 			do {
106 				printf("boot> ");
107 			} while(!getcmd());
108 		}
109 
110 		if (loadrandom(BOOTRANDOM, rnddata, sizeof(rnddata)) == 0)
111 			cmd.boothowto |= RB_GOODRANDOM;
112 #ifdef MDRANDOM
113 		if (mdrandom(rnddata, sizeof(rnddata)) == 0)
114 			cmd.boothowto |= RB_GOODRANDOM;
115 #endif
116 #ifdef FWRANDOM
117 		if (fwrandom(rnddata, sizeof(rnddata)) == 0)
118 			cmd.boothowto |= RB_GOODRANDOM;
119 #endif
120 		rc4_keysetup(&randomctx, rnddata, sizeof rnddata);
121 		rc4_skip(&randomctx, 1536);
122 
123 		st = 0;
124 		bootprompt = 1;	/* allow reselect should we fail */
125 
126 		printf("booting %s: ", cmd.path);
127 		marks[MARK_START] = 0;
128 		if ((fd = loadfile(cmd.path, marks, LOAD_ALL)) != -1) {
129 
130 		        /* Prevent re-upgrade: chmod a-x bsd.upgrade */
131 			if (isupgrade) {
132 				struct stat st;
133 
134 				if (fstat(fd, &st) == 0) {
135 					st.st_mode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
136 					if (fchmod(fd, st.st_mode) == -1)
137 						printf("fchmod a-x %s: failed\n",
138 						    cmd.path);
139 				}
140 			}
141 			close(fd);
142 			break;
143 		}
144 
145 		kernelfile = KERNEL;
146 		try++;
147 		strlcpy(cmd.image, kernelfile, sizeof(cmd.image));
148 		printf(" failed(%d). will try %s\n", errno, kernelfile);
149 
150 		if (try < 2) {
151 			if (cmd.timeout > 0)
152 				cmd.timeout++;
153 		} else {
154 			if (cmd.timeout)
155 				printf("Turning timeout off.\n");
156 			cmd.timeout = 0;
157 		}
158 	}
159 
160 	/* exec */
161 	run_loadfile(marks, cmd.boothowto);
162 }
163 
164 int
loadrandom(char * name,char * buf,size_t buflen)165 loadrandom(char *name, char *buf, size_t buflen)
166 {
167 	char path[MAXPATHLEN];
168 	struct stat sb;
169 	int fd, i, error = 0;
170 
171 	/* Extract the device name from the kernel we are loading. */
172 	for (i = 0; i < sizeof(cmd.path); i++) {
173 		if (cmd.path[i] == ':') {
174 			strlcpy(path, cmd.path, i + 1);
175 			snprintf(path + i, sizeof(path) - i, ":%s", name);
176 			break;
177 		} else if (cmd.path[i] == '\0') {
178 			snprintf(path, sizeof path, "%s:%s",
179 			    cmd.bootdev, name);
180 			break;
181 		}
182 	}
183 
184 	fd = open(path, O_RDONLY);
185 	if (fd == -1) {
186 		if (errno != EPERM)
187 			printf("cannot open %s: %s\n", path, strerror(errno));
188 		return -1;
189 	}
190 	if (fstat(fd, &sb) == -1) {
191 		error = -1;
192 		goto done;
193 	}
194 	if (read(fd, buf, buflen) != buflen) {
195 		error = -1;
196 		goto done;
197 	}
198 	if (sb.st_mode & S_ISTXT) {
199 		printf("NOTE: random seed is being reused.\n");
200 		error = -1;
201 		goto done;
202 	}
203 	fchmod(fd, sb.st_mode | S_ISTXT);
204 done:
205 	close(fd);
206 	return (error);
207 }
208