xref: /openbsd/sys/stand/boot/boot.c (revision 09467b48)
1 /*	$OpenBSD: boot.c,v 1.54 2020/06/15 14:43:57 naddy 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 	}
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] = (u_long)cmd.addr;
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
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 #define O_RDONLY	0
172 
173 	/* Extract the device name from the kernel we are loading. */
174 	for (i = 0; i < sizeof(cmd.path); i++) {
175 		if (cmd.path[i] == ':') {
176 			strlcpy(path, cmd.path, i + 1);
177 			snprintf(path + i, sizeof(path) - i, ":%s", name);
178 			break;
179 		} else if (cmd.path[i] == '\0') {
180 			snprintf(path, sizeof path, "%s:%s",
181 			    cmd.bootdev, name);
182 			break;
183 		}
184 	}
185 
186 	fd = open(path, O_RDONLY);
187 	if (fd == -1) {
188 		if (errno != EPERM)
189 			printf("cannot open %s: %s\n", path, strerror(errno));
190 		return -1;
191 	}
192 	if (fstat(fd, &sb) == -1) {
193 		error = -1;
194 		goto done;
195 	}
196 	if (read(fd, buf, buflen) != buflen) {
197 		error = -1;
198 		goto done;
199 	}
200 	if (sb.st_mode & S_ISTXT) {
201 		printf("NOTE: random seed is being reused.\n");
202 		error = -1;
203 		goto done;
204 	}
205 	fchmod(fd, sb.st_mode | S_ISTXT);
206 done:
207 	close(fd);
208 	return (error);
209 }
210