1 /* $OpenBSD: rdboot.c,v 1.3 2019/11/01 20:54:52 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 2019 Visa Hankala 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/param.h> 21 #include <sys/ioctl.h> 22 #include <sys/mount.h> 23 #include <sys/reboot.h> 24 #include <sys/select.h> 25 26 #include <err.h> 27 #include <errno.h> 28 #include <fcntl.h> 29 #include <paths.h> 30 #include <stdio.h> 31 #include <string.h> 32 #include <termios.h> 33 #include <unistd.h> 34 #include <util.h> 35 36 #include <machine/octboot.h> 37 #include <machine/param.h> 38 39 #include "cmd.h" 40 #include "disk.h" 41 42 #define DEVRANDOM "/dev/random" 43 #define BOOTRANDOM "/etc/random.seed" 44 #define BOOTRANDOM_MAX 256 /* no point being greater than RC4STATE */ 45 #define KERNEL "/bsd" 46 47 void loadrandom(void); 48 void kexec(void); 49 50 struct cmd_state cmd; 51 int octbootfd = -1; 52 const char version[] = "1.1"; 53 54 int 55 main(void) 56 { 57 char rootdev[PATH_MAX]; 58 int fd, hasboot; 59 60 fd = open(_PATH_CONSOLE, O_RDWR); 61 login_tty(fd); 62 63 /* Keep stdout unbuffered to mimic ordinary bootblocks. */ 64 setvbuf(stdout, NULL, _IONBF, 0); 65 66 printf(">> OpenBSD/" MACHINE " BOOT %s\n", version); 67 68 octbootfd = open("/dev/octboot", O_WRONLY); 69 if (octbootfd == -1) 70 err(1, "cannot open boot control device"); 71 72 memset(&cmd, 0, sizeof(cmd)); 73 cmd.boothowto = 0; 74 cmd.conf = "/etc/boot.conf"; 75 strlcpy(cmd.image, KERNEL, sizeof(cmd.image)); 76 cmd.timeout = 5; 77 78 if (ioctl(octbootfd, OBIOC_GETROOTDEV, rootdev) == -1) { 79 if (errno != ENOENT) 80 fprintf(stderr, "cannot get rootdev from kernel: %s\n", 81 strerror(errno)); 82 } else { 83 snprintf(cmd.bootdev, sizeof(cmd.bootdev), "%s%sa", 84 rootdev, isduid(rootdev, OPENDEV_PART) ? "." : ""); 85 } 86 87 disk_init(); 88 89 if (upgrade()) { 90 strlcpy(cmd.image, "/bsd.upgrade", sizeof(cmd.image)); 91 printf("upgrade detected: switching to %s\n", cmd.image); 92 } 93 94 hasboot = read_conf(); 95 96 for (;;) { 97 if (hasboot <= 0) { 98 do { 99 printf("boot> "); 100 } while (!getcmd()); 101 } 102 103 loadrandom(); 104 kexec(); 105 106 hasboot = 0; 107 strlcpy(cmd.image, KERNEL, sizeof(cmd.image)); 108 printf("will try %s\n", cmd.image); 109 } 110 111 return 0; 112 } 113 114 void 115 loadrandom(void) 116 { 117 char buf[BOOTRANDOM_MAX]; 118 int fd; 119 120 /* Read the file from the device specified by the kernel path. */ 121 if (disk_open(cmd.path) == NULL) 122 return; 123 fd = open(BOOTRANDOM, O_RDONLY); 124 if (fd == -1) { 125 fprintf(stderr, "%s: cannot open %s: %s", __func__, BOOTRANDOM, 126 strerror(errno)); 127 disk_close(); 128 return; 129 } 130 read(fd, buf, sizeof(buf)); 131 close(fd); 132 disk_close(); 133 134 /* 135 * Push the whole buffer to the entropy pool. 136 * The kernel will use the entropy on kexec(). 137 * It does not matter if some of the buffer content is uninitialized. 138 */ 139 fd = open(DEVRANDOM, O_WRONLY); 140 if (fd == -1) { 141 fprintf(stderr, "%s: cannot open %s: %s", __func__, 142 DEVRANDOM, strerror(errno)); 143 return; 144 } 145 write(fd, buf, sizeof(buf)); 146 close(fd); 147 } 148 149 void 150 kexec(void) 151 { 152 struct octboot_kexec_args kargs; 153 char kernelflags[8]; 154 char rootdev[32]; 155 const char *path; 156 int argc, ret; 157 158 path = disk_open(cmd.path); 159 if (path == NULL) 160 return; 161 162 memset(&kargs, 0, sizeof(kargs)); 163 kargs.path = path; 164 argc = 0; 165 if (cmd.boothowto != 0) { 166 snprintf(kernelflags, sizeof(kernelflags), "-%s%s%s%s", 167 (cmd.boothowto & RB_ASKNAME) ? "a" : "", 168 (cmd.boothowto & RB_CONFIG) ? "c" : "", 169 (cmd.boothowto & RB_KDB) ? "d" : "", 170 (cmd.boothowto & RB_SINGLE) ? "s" : ""); 171 kargs.argv[argc++] = kernelflags; 172 } 173 if (cmd.hasduid) { 174 snprintf(rootdev, sizeof(rootdev), 175 "rootdev=%02x%02x%02x%02x%02x%02x%02x%02x", 176 cmd.bootduid[0], cmd.bootduid[1], 177 cmd.bootduid[2], cmd.bootduid[3], 178 cmd.bootduid[4], cmd.bootduid[5], 179 cmd.bootduid[6], cmd.bootduid[7]); 180 kargs.argv[argc++] = rootdev; 181 } 182 183 printf("booting %s\n", cmd.path); 184 ret = ioctl(octbootfd, OBIOC_KEXEC, &kargs); 185 if (ret == -1) 186 fprintf(stderr, "failed to execute kernel %s: %s\n", 187 cmd.path, strerror(errno)); 188 else 189 fprintf(stderr, "kexec() returned unexpectedly\n"); 190 191 disk_close(); 192 } 193