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