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
47char prog_ident[40];
48char *progname = "BOOT";
49
50extern	const char version[];
51struct cmd_state cmd;
52
53/* bootprompt can be set by MD code to avoid prompt first time round */
54int bootprompt = 1;
55char *kernelfile = KERNEL;		/* can be changed by MD code */
56int boottimeout = 5;			/* can be changed by MD code */
57
58char	rnddata[BOOTRANDOM_MAX] __aligned(sizeof(long));
59struct rc4_ctx randomctx;
60
61void
62boot(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
164int
165loadrandom(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);
204done:
205	close(fd);
206	return (error);
207}
208