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