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