1/*-
2 * Copyright (c) 2017-2020, Juniper Networks, Inc.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
14 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
15 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
16 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
17 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
19 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25/*
26 * Routines to verify files loaded.
27 */
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD$");
30
31#include <sys/param.h>
32#include <string.h>
33#include <sys/queue.h>
34#include <sys/kenv.h>
35
36#include "libsecureboot.h"
37#include <verify_file.h>
38#include <manifests.h>
39
40#ifdef UNIT_TEST
41# include <err.h>
42# define panic warn
43/*
44 * define MANIFEST_SKIP to Skip - in tests/tvo.c so that
45 * tvo can control the value we use in find_manifest()
46 */
47extern char *Destdir;
48extern size_t DestdirLen;
49extern char *Skip;
50# undef MANIFEST_SKIP
51# define MANIFEST_SKIP Skip
52# undef VE_DEBUG_LEVEL
53#endif
54
55/*
56 * We sometimes need to know if input is verified or not.
57 * The extra slot is for tracking most recently opened.
58 */
59static int ve_status[SOPEN_MAX+1];
60static int ve_status_state;
61struct verify_status;
62struct verify_status *verified_files = NULL;
63static int loaded_manifests = 0;	/* have we loaded anything? */
64
65#define VE_STATUS_NONE	1
66#define VE_STATUS_VALID	2
67
68/**
69 * @brief set ve status for fd
70 */
71static void
72ve_status_set(int fd, int ves)
73{
74	if (fd >= 0 && fd < SOPEN_MAX) {
75		ve_status[fd] = ves;
76		ve_status_state = VE_STATUS_VALID;
77	}
78	ve_status[SOPEN_MAX] = ves;
79}
80
81/**
82 * @brief get ve status of fd
83 *
84 * What we return depends on ve_status_state.
85 *
86 * @return
87 *	@li ve_status[fd] if ve_status_state is valid
88 *	@li ve_status[SOPEN_MAX] if ve_status_state is none
89 *	@li VE_NOT_CHECKED if ve_status_state uninitialized
90 */
91int
92ve_status_get(int fd)
93{
94	if (!ve_status_state) {
95		return (VE_NOT_CHECKED);
96	}
97	if (ve_status_state == VE_STATUS_VALID &&
98		fd >= 0 && fd < SOPEN_MAX)
99		return (ve_status[fd]);
100	return (ve_status[SOPEN_MAX]);	/* most recent */
101}
102
103/**
104 * @brief track verify status
105 *
106 * occasionally loader will make multiple calls
107 * for the same file, we need only check it once.
108 */
109struct verify_status {
110	dev_t	vs_dev;
111	ino_t	vs_ino;
112	int	vs_status;
113	struct verify_status *vs_next;
114};
115
116int
117is_verified(struct stat *stp)
118{
119	struct verify_status *vsp;
120
121	if (stp->st_ino > 0) {
122		for (vsp = verified_files; vsp != NULL; vsp = vsp->vs_next) {
123			if (stp->st_dev == vsp->vs_dev &&
124			    stp->st_ino == vsp->vs_ino)
125				return (vsp->vs_status);
126		}
127	}
128	return (VE_NOT_CHECKED);
129}
130
131/* most recent first, since most likely to see repeated calls. */
132void
133add_verify_status(struct stat *stp, int status)
134{
135	struct verify_status *vsp;
136
137	vsp = malloc(sizeof(struct verify_status));
138	vsp->vs_next = verified_files;
139	vsp->vs_dev = stp->st_dev;
140	vsp->vs_ino = stp->st_ino;
141	vsp->vs_status = status;
142	verified_files = vsp;
143}
144
145
146/**
147 * @brief
148 * load specified manifest if verified
149 */
150int
151load_manifest(const char *name, const char *prefix,
152    const char *skip, struct stat *stp)
153{
154	struct stat st;
155	size_t n;
156	int rc;
157	char *content;
158
159	rc = VE_FINGERPRINT_NONE;
160	n = strlen(name);
161	if (n > 4) {
162		if (!stp) {
163			stp = &st;
164			if (stat(name, &st) < 0 || !S_ISREG(st.st_mode))
165				return (rc);
166		}
167		rc = is_verified(stp);
168		if (rc != VE_NOT_CHECKED) {
169			return (rc);
170		}
171		/* loader has no sense of time */
172		ve_utc_set(stp->st_mtime);
173		content = (char *)verify_signed(name, VEF_VERBOSE);
174		if (content) {
175#ifdef UNIT_TEST
176			if (DestdirLen > 0 &&
177			    strncmp(name, Destdir, DestdirLen) == 0) {
178				name += DestdirLen;
179				if (prefix &&
180				    strncmp(prefix, Destdir, DestdirLen) == 0)
181					prefix += DestdirLen;
182			}
183#endif
184			fingerprint_info_add(name, prefix, skip, content, stp);
185			add_verify_status(stp, VE_VERIFIED);
186			loaded_manifests = 1; /* we are verifying! */
187			DEBUG_PRINTF(3, ("loaded: %s %s %s\n",
188				name, prefix, skip));
189			rc = VE_VERIFIED;
190		} else {
191			rc = VE_FINGERPRINT_WRONG;
192			add_verify_status(stp, rc);	/* remember */
193		}
194	}
195	return (rc);
196}
197
198static int
199find_manifest(const char *name)
200{
201	struct stat st;
202	char buf[MAXPATHLEN];
203	char *prefix;
204	char *skip;
205	const char **tp;
206	int rc;
207
208	strncpy(buf, name, MAXPATHLEN - 1);
209	if (!(prefix = strrchr(buf, '/')))
210		return (-1);
211	*prefix = '\0';
212	prefix = strdup(buf);
213	rc = VE_FINGERPRINT_NONE;
214	for (tp = manifest_names; *tp; tp++) {
215		snprintf(buf, sizeof(buf), "%s/%s", prefix, *tp);
216		DEBUG_PRINTF(5, ("looking for %s\n", buf));
217		if (stat(buf, &st) == 0 && st.st_size > 0) {
218#ifdef MANIFEST_SKIP_ALWAYS		/* very unlikely */
219			skip = MANIFEST_SKIP_ALWAYS;
220#else
221#ifdef MANIFEST_SKIP			/* rare */
222			if (*tp[0] == '.') {
223				skip = MANIFEST_SKIP;
224			} else
225#endif
226				skip = NULL;
227#endif
228			rc = load_manifest(buf, skip ? prefix : NULL,
229			    skip, &st);
230			break;
231		}
232	}
233	free(prefix);
234	return (rc);
235}
236
237
238#ifdef LOADER_VERIEXEC_TESTING
239# define ACCEPT_NO_FP_DEFAULT	VE_MUST + 1
240#else
241# define ACCEPT_NO_FP_DEFAULT	VE_MUST
242#endif
243#ifndef VE_VERBOSE_DEFAULT
244# define VE_VERBOSE_DEFAULT	0
245#endif
246
247static int
248severity_guess(const char *filename)
249{
250	const char *cp;
251
252	/* Some files like *.conf and *.hints may be unsigned */
253	if ((cp = strrchr(filename, '.'))) {
254		if (strcmp(cp, ".conf") == 0 ||
255		    strcmp(cp, ".cookie") == 0 ||
256			strcmp(cp, ".hints") == 0)
257			return (VE_TRY);
258		if (strcmp(cp, ".4th") == 0 ||
259		    strcmp(cp, ".lua") == 0 ||
260		    strcmp(cp, ".rc") == 0)
261			return (VE_MUST);
262	}
263	return (VE_WANT);
264}
265
266static int Verifying = -1;		/* 0 if not verifying */
267
268static void
269verify_tweak(int fd, off_t off, struct stat *stp,
270    char *tweak, int *accept_no_fp,
271    int *verbose)
272{
273	if (strcmp(tweak, "off") == 0) {
274		Verifying = 0;
275	} else if (strcmp(tweak, "strict") == 0) {
276		/* anything caller wants verified must be */
277		*accept_no_fp = VE_WANT;
278		*verbose = 1; /* warn of anything unverified */
279		/* treat self test failure as fatal */
280		if (!ve_self_tests()) {
281			panic("verify self tests failed");
282		}
283	} else if (strcmp(tweak, "modules") == 0) {
284		/* modules/kernel must be verified */
285		*accept_no_fp = VE_MUST;
286	} else if (strcmp(tweak, "try") == 0) {
287		/* best effort: always accept no fp */
288		*accept_no_fp = VE_MUST + 1;
289	} else if (strcmp(tweak, "verbose") == 0) {
290		*verbose = 1;
291	} else if (strcmp(tweak, "quiet") == 0) {
292		*verbose = 0;
293	} else if (strncmp(tweak, "trust", 5) == 0) {
294		/* content is trust anchor to add or revoke */
295		unsigned char *ucp;
296		size_t num;
297
298		if (off > 0)
299			lseek(fd, 0, SEEK_SET);
300		ucp = read_fd(fd, stp->st_size);
301		if (ucp == NULL)
302			return;
303		if (strstr(tweak, "revoke")) {
304			num = ve_trust_anchors_revoke(ucp, stp->st_size);
305			DEBUG_PRINTF(3, ("revoked %d trust anchors\n",
306				(int) num));
307		} else {
308			num = ve_trust_anchors_add_buf(ucp, stp->st_size);
309			DEBUG_PRINTF(3, ("added %d trust anchors\n",
310				(int) num));
311		}
312	}
313}
314
315#ifndef VE_DEBUG_LEVEL
316# define VE_DEBUG_LEVEL 0
317#endif
318
319static int
320getenv_int(const char *var, int def)
321{
322	const char *cp;
323	char *ep;
324	long val;
325
326	val = def;
327	cp = getenv(var);
328	if (cp && *cp) {
329		val = strtol(cp, &ep, 0);
330		if ((ep && *ep) || val != (int)val) {
331			val = def;
332		}
333	}
334	return (int)val;
335}
336
337
338/**
339 * @brief prepare to verify an open file
340 *
341 * @param[in] fd
342 * 	open descriptor
343 *
344 * @param[in] filename
345 * 	path we opened and will use to lookup fingerprint
346 *
347 * @param[in] stp
348 *	stat pointer so we can check file type
349 */
350int
351verify_prep(int fd, const char *filename, off_t off, struct stat *stp,
352    const char *caller)
353{
354	int rc;
355
356	if (Verifying < 0) {
357		Verifying = ve_trust_init();
358#ifndef UNIT_TEST
359		ve_debug_set(getenv_int("VE_DEBUG_LEVEL", VE_DEBUG_LEVEL));
360#endif
361		/* initialize ve_status with default result */
362		rc = Verifying ? VE_NOT_CHECKED : VE_NOT_VERIFYING;
363		ve_status_set(0, rc);
364		ve_status_state = VE_STATUS_NONE;
365		if (Verifying) {
366			ve_self_tests();
367			ve_anchor_verbose_set(1);
368		}
369	}
370	if (!Verifying || fd < 0)
371		return (0);
372	if (stp) {
373		if (fstat(fd, stp) < 0 || !S_ISREG(stp->st_mode))
374			return (0);
375	}
376	DEBUG_PRINTF(2,
377	    ("verify_prep: caller=%s,fd=%d,name='%s',off=%lld,dev=%lld,ino=%lld\n",
378		caller, fd, filename, (long long)off, (long long)stp->st_dev,
379		(long long)stp->st_ino));
380	rc = is_verified(stp);
381	DEBUG_PRINTF(4,("verify_prep: is_verified()->%d\n", rc));
382	if (rc == VE_NOT_CHECKED) {
383		rc = find_manifest(filename);
384	} else {
385		ve_status_set(fd, rc);
386	}
387	return (rc);
388}
389
390/**
391 * @brief verify an open file
392 *
393 * @param[in] fd
394 * 	open descriptor
395 *
396 * @param[in] filename
397 * 	path we opened and will use to lookup fingerprint
398 *
399 * @param[in] off
400 * 	current offset in fd, must be restored on return
401 *
402 * @param[in] severity
403 * 	indicator of how to handle case of missing fingerprint
404 *
405 * We look for a signed manifest relative to the filename
406 * just opened and verify/load it if needed.
407 *
408 * We then use verify_fd() in libve to actually verify that hash for
409 * open file.  If it returns < 0 we look at the severity arg to decide
410 * what to do about it.
411 *
412 * If verify_fd() returns VE_FINGERPRINT_NONE we accept it if severity
413 * is < accept_no_fp.
414 *
415 * @return >= 0 on success < 0 on failure
416 */
417int
418verify_file(int fd, const char *filename, off_t off, int severity,
419    const char *caller)
420{
421	static int once;
422	static int accept_no_fp = ACCEPT_NO_FP_DEFAULT;
423	static int verbose = VE_VERBOSE_DEFAULT;
424	struct stat st;
425	char *cp;
426	int rc;
427
428	rc = verify_prep(fd, filename, off, &st, caller);
429
430	if (!rc)
431		return (0);
432
433	if (!once) {
434		once++;
435		verbose = getenv_int("VE_VERBOSE", VE_VERBOSE_DEFAULT);
436	}
437
438	if (rc != VE_FINGERPRINT_WRONG && loaded_manifests) {
439		if (severity <= VE_GUESS)
440			severity = severity_guess(filename);
441#ifdef VE_PCR_SUPPORT
442		/*
443		 * Only update pcr with things that must verify
444		 * these tend to be processed in a more deterministic
445		 * order, which makes our pseudo pcr more useful.
446		 */
447		ve_pcr_updating_set((severity == VE_MUST));
448#endif
449#ifdef UNIT_TEST
450		if (DestdirLen > 0 &&
451		    strncmp(filename, Destdir, DestdirLen) == 0) {
452			filename += DestdirLen;
453		}
454#endif
455		if ((rc = verify_fd(fd, filename, off, &st)) >= 0) {
456			if (verbose || severity > VE_WANT) {
457#if defined(VE_DEBUG_LEVEL) && VE_DEBUG_LEVEL > 0
458				printf("%serified %s %llu,%llu\n",
459				    (rc == VE_FINGERPRINT_IGNORE) ? "Unv" : "V",
460				    filename,
461				    (long long)st.st_dev, (long long)st.st_ino);
462#else
463				printf("%serified %s\n",
464				    (rc == VE_FINGERPRINT_IGNORE) ? "Unv" : "V",
465				    filename);
466#endif
467			}
468			if (severity < VE_MUST) { /* not a kernel or module */
469				if ((cp = strrchr(filename, '/'))) {
470					cp++;
471					if (strncmp(cp, "loader.ve.", 10) == 0) {
472						cp += 10;
473						verify_tweak(fd, off, &st, cp,
474						    &accept_no_fp, &verbose);
475					}
476				}
477			}
478			add_verify_status(&st, rc);
479			ve_status_set(fd, rc);
480			return (rc);
481		}
482
483		if (severity || verbose || rc == VE_FINGERPRINT_WRONG)
484			printf("Unverified: %s\n", ve_error_get());
485		if (rc == VE_FINGERPRINT_UNKNOWN && severity < VE_MUST)
486			rc = VE_UNVERIFIED_OK;
487		else if (rc == VE_FINGERPRINT_NONE && severity < accept_no_fp)
488			rc = VE_UNVERIFIED_OK;
489
490		add_verify_status(&st, rc);
491	}
492#ifdef LOADER_VERIEXEC_TESTING
493	else if (rc != VE_FINGERPRINT_WRONG) {
494		/*
495		 * We have not loaded any manifest and
496		 * not because of verication failure.
497		 * Most likely reason is we have none.
498		 * Allow boot to proceed if we are just testing.
499		 */
500		return (VE_UNVERIFIED_OK);
501	}
502#endif
503	if (rc == VE_FINGERPRINT_WRONG && severity > accept_no_fp)
504		panic("cannot continue");
505	ve_status_set(fd, rc);
506	return (rc);
507}
508
509/**
510 * @brief get hex string for pcr value and export
511 *
512 * In case we are doing measured boot, provide
513 * value of the "pcr" data we have accumulated.
514 */
515void
516verify_pcr_export(void)
517{
518#ifdef VE_PCR_SUPPORT
519	char hexbuf[br_sha256_SIZE * 2 + 2];
520	unsigned char hbuf[br_sha256_SIZE];
521	char *hinfo;
522	char *hex;
523	ssize_t hlen;
524
525	hlen = ve_pcr_get(hbuf, sizeof(hbuf));
526	if (hlen > 0) {
527		hex = hexdigest(hexbuf, sizeof(hexbuf), hbuf, hlen);
528		if (hex) {
529			hex[hlen*2] = '\0'; /* clobber newline */
530			setenv("loader.ve.pcr", hex, 1);
531			DEBUG_PRINTF(1,
532			    ("%s: setenv(loader.ve.pcr, %s\n", __func__,
533				hex));
534			hinfo = ve_pcr_hashed_get(1);
535			if (hinfo) {
536				setenv("loader.ve.hashed", hinfo, 1);
537				DEBUG_PRINTF(1,
538				    ("%s: setenv(loader.ve.hashed, %s\n",
539					__func__, hinfo));
540				if ((hlen = strlen(hinfo)) > KENV_MVALLEN) {
541					/*
542					 * bump kenv_mvallen
543					 * roundup to multiple of KENV_MVALLEN
544					 */
545					char mvallen[16];
546
547					hlen += KENV_MVALLEN -
548					    (hlen % KENV_MVALLEN);
549					if (snprintf(mvallen, sizeof(mvallen),
550						"%d", (int) hlen) < sizeof(mvallen))
551						setenv("kenv_mvallen", mvallen, 1);
552				}
553				free(hinfo);
554			}
555		}
556	}
557#endif
558}
559