xref: /openbsd-src/sys/stand/boot/boot.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /*	$OpenBSD: boot.c,v 1.50 2019/10/29 02:55:50 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];
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 		loadrandom(BOOTRANDOM, rnddata, sizeof(rnddata));
111 #ifdef MDRANDOM
112 		mdrandom(rnddata, sizeof(rnddata));
113 #endif
114 #ifdef FWRANDOM
115 		fwrandom(rnddata, sizeof(rnddata));
116 #endif
117 		rc4_keysetup(&randomctx, rnddata, sizeof rnddata);
118 		rc4_skip(&randomctx, 1536);
119 
120 		st = 0;
121 		bootprompt = 1;	/* allow reselect should we fail */
122 
123 		printf("booting %s: ", cmd.path);
124 		marks[MARK_START] = (u_long)cmd.addr;
125 		if ((fd = loadfile(cmd.path, marks, LOAD_ALL)) != -1) {
126 
127 		        /* Prevent re-upgrade: chmod a-x bsd.upgrade */
128 			if (isupgrade) {
129 				struct stat st;
130 
131 				if (fstat(fd, &st) == 0) {
132 					st.st_mode &= ~(S_IXUSR|S_IXGRP|S_IXOTH);
133 					if (fchmod(fd, st.st_mode) == -1)
134 						printf("fchmod a-x %s: failed\n",
135 						    cmd.path);
136 				}
137 			}
138 			close(fd);
139 			break;
140 		}
141 
142 		kernelfile = KERNEL;
143 		try++;
144 		strlcpy(cmd.image, kernelfile, sizeof(cmd.image));
145 		printf(" failed(%d). will try %s\n", errno, kernelfile);
146 
147 		if (try < 2) {
148 			if (cmd.timeout > 0)
149 				cmd.timeout++;
150 		} else {
151 			if (cmd.timeout)
152 				printf("Turning timeout off.\n");
153 			cmd.timeout = 0;
154 		}
155 	}
156 
157 	/* exec */
158 	run_loadfile(marks, cmd.boothowto);
159 }
160 
161 void
162 loadrandom(char *name, char *buf, size_t buflen)
163 {
164 	char path[MAXPATHLEN];
165 	struct stat sb;
166 	int fd, i;
167 
168 #define O_RDONLY	0
169 
170 	/* Extract the device name from the kernel we are loading. */
171 	for (i = 0; i < sizeof(cmd.path); i++) {
172 		if (cmd.path[i] == ':') {
173 			strlcpy(path, cmd.path, i + 1);
174 			snprintf(path + i, sizeof(path) - i, ":%s", name);
175 			break;
176 		} else if (cmd.path[i] == '\0') {
177 			snprintf(path, sizeof path, "%s:%s",
178 			    cmd.bootdev, name);
179 			break;
180 		}
181 	}
182 
183 	fd = open(path, O_RDONLY);
184 	if (fd == -1) {
185 		if (errno != EPERM)
186 			printf("cannot open %s: %s\n", path, strerror(errno));
187 		return;
188 	}
189 	if (fstat(fd, &sb) == -1 ||
190 	    sb.st_uid != 0 ||
191 	    (sb.st_mode & (S_IWOTH|S_IROTH)))
192 		goto fail;
193 	(void) read(fd, buf, buflen);
194 fail:
195 	close(fd);
196 }
197