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