xref: /freebsd/lib/libsecureboot/verify_file.c (revision 8df8b2d3e51d1b816201d8a1fe8bc29fe192e562)
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 #define VE_NOT_CHECKED -42
40 
41 #ifdef UNIT_TEST
42 # include <err.h>
43 # define panic warn
44 /*
45  * define MANIFEST_SKIP to Skip - in tests/tvo.c so that
46  * tvo can control the value we use in find_manifest()
47  */
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 static int
116 is_verified(struct stat *stp)
117 {
118 	struct verify_status *vsp;
119 
120 	for (vsp = verified_files; vsp != NULL; vsp = vsp->vs_next) {
121 		if (stp->st_dev == vsp->vs_dev &&
122 		    stp->st_ino == vsp->vs_ino)
123 			return (vsp->vs_status);
124 	}
125 	return (VE_NOT_CHECKED);
126 }
127 
128 /* most recent first, since most likely to see repeated calls. */
129 static void
130 add_verify_status(struct stat *stp, int status)
131 {
132 	struct verify_status *vsp;
133 
134 	vsp = malloc(sizeof(struct verify_status));
135 	vsp->vs_next = verified_files;
136 	vsp->vs_dev = stp->st_dev;
137 	vsp->vs_ino = stp->st_ino;
138 	vsp->vs_status = status;
139 	verified_files = vsp;
140 }
141 
142 
143 /**
144  * @brief
145  * load specified manifest if verified
146  */
147 int
148 load_manifest(const char *name, const char *prefix,
149     const char *skip, struct stat *stp)
150 {
151 	struct stat st;
152 	size_t n;
153 	int rc;
154 	char *content;
155 
156 	rc = VE_FINGERPRINT_NONE;
157 	n = strlen(name);
158 	if (n > 4) {
159 		if (!stp) {
160 			stp = &st;
161 			if (stat(name, &st) < 0 || !S_ISREG(st.st_mode))
162 				return (rc);
163 		}
164 		rc = is_verified(stp);
165 		if (rc != VE_NOT_CHECKED) {
166 			return (rc);
167 		}
168 		/* loader has no sense of time */
169 		ve_utc_set(stp->st_mtime);
170 		content = (char *)verify_signed(name, VEF_VERBOSE);
171 		if (content) {
172 			fingerprint_info_add(name, prefix, skip, content, stp);
173 			add_verify_status(stp, VE_VERIFIED);
174 			loaded_manifests = 1; /* we are verifying! */
175 			DEBUG_PRINTF(3, ("loaded: %s %s %s\n",
176 				name, prefix, skip));
177 			rc = 0;
178 		} else {
179 			rc = VE_FINGERPRINT_WRONG;
180 			add_verify_status(stp, rc);	/* remember */
181 		}
182 	}
183 	return (rc);
184 }
185 
186 static int
187 find_manifest(const char *name)
188 {
189 	struct stat st;
190 	char buf[MAXPATHLEN];
191 	char *prefix;
192 	char *skip;
193 	const char **tp;
194 	int rc;
195 
196 	strncpy(buf, name, MAXPATHLEN - 1);
197 	if (!(prefix = strrchr(buf, '/')))
198 		return (-1);
199 	*prefix = '\0';
200 	prefix = strdup(buf);
201 	rc = VE_FINGERPRINT_NONE;
202 	for (tp = manifest_names; *tp; tp++) {
203 		snprintf(buf, sizeof(buf), "%s/%s", prefix, *tp);
204 		DEBUG_PRINTF(5, ("looking for %s\n", buf));
205 		if (stat(buf, &st) == 0 && st.st_size > 0) {
206 #ifdef MANIFEST_SKIP_ALWAYS		/* very unlikely */
207 			skip = MANIFEST_SKIP_ALWAYS;
208 #else
209 #ifdef MANIFEST_SKIP			/* rare */
210 			if (*tp[0] == '.') {
211 				skip = MANIFEST_SKIP;
212 			} else
213 #endif
214 				skip = NULL;
215 #endif
216 			rc = load_manifest(buf, skip ? prefix : NULL,
217 			    skip, &st);
218 			break;
219 		}
220 	}
221 	free(prefix);
222 	return (rc);
223 }
224 
225 
226 #ifdef LOADER_VERIEXEC_TESTING
227 # define ACCEPT_NO_FP_DEFAULT	VE_MUST + 1
228 #else
229 # define ACCEPT_NO_FP_DEFAULT	VE_MUST
230 #endif
231 #ifndef VE_VERBOSE_DEFAULT
232 # define VE_VERBOSE_DEFAULT	0
233 #endif
234 
235 static int
236 severity_guess(const char *filename)
237 {
238 	const char *cp;
239 
240 	/* Some files like *.conf and *.hints may be unsigned */
241 	if ((cp = strrchr(filename, '.'))) {
242 		if (strcmp(cp, ".conf") == 0 ||
243 		    strcmp(cp, ".cookie") == 0 ||
244 			strcmp(cp, ".hints") == 0)
245 			return (VE_TRY);
246 	}
247 	return (VE_WANT);
248 }
249 
250 static void
251 verify_tweak(char *tweak, int *accept_no_fp, 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 	}
274 }
275 
276 /**
277  * @brief verify an open file
278  *
279  * @param[in] fd
280  * 	open descriptor
281  *
282  * @param[in] filename
283  * 	path we opened and will use to lookup fingerprint
284  *
285  * @param[in] off
286  * 	current offset in fd, must be restored on return
287  *
288  * @param[in] severity
289  * 	indicator of how to handle case of missing fingerprint
290  *
291  * We look for a signed manifest relative to the filename
292  * just opened and verify/load it if needed.
293  *
294  * We then use verify_fd() in libve to actually verify that hash for
295  * open file.  If it returns < 0 we look at the severity arg to decide
296  * what to do about it.
297  *
298  * If verify_fd() returns VE_FINGERPRINT_NONE we accept it if severity
299  * is < accept_no_fp.
300  *
301  * @return >= 0 on success < 0 on failure
302  */
303 int
304 verify_file(int fd, const char *filename, off_t off, int severity)
305 {
306 	static int verifying = -1;
307 	static int accept_no_fp = ACCEPT_NO_FP_DEFAULT;
308 	static int verbose = VE_VERBOSE_DEFAULT;
309 	struct stat st;
310 	char *cp;
311 	int rc;
312 
313 	if (verifying < 0) {
314 		verifying = ve_trust_init();
315 #ifdef VE_DEBUG_LEVEL
316 		ve_debug_set(VE_DEBUG_LEVEL);
317 #endif
318 		/* initialize ve_status with default result */
319 		rc = verifying ? VE_NOT_CHECKED : VE_NOT_VERIFYING;
320 		ve_status_set(0, rc);
321 		ve_status_state = VE_STATUS_NONE;
322 		if (verifying)
323 			ve_self_tests();
324 	}
325 	if (!verifying)
326 		return (0);
327 
328 	if (fd < 0 || fstat(fd, &st) < 0 || !S_ISREG(st.st_mode))
329 		return (0);
330 
331 	DEBUG_PRINTF(3, ("fd=%d,name='%s',off=%lld,dev=%lld,ino=%lld\n",
332 		fd, filename, (long long)off, (long long)st.st_dev,
333 		(long long)st.st_ino));
334 
335 
336 	rc = is_verified(&st);
337 	if (rc != VE_NOT_CHECKED) {
338 		ve_status_set(fd, rc);
339 		return (rc);
340 	}
341 	rc = find_manifest(filename);
342 	if (rc != VE_FINGERPRINT_WRONG && loaded_manifests) {
343 		if (severity <= VE_GUESS)
344 			severity = severity_guess(filename);
345 		if ((rc = verify_fd(fd, filename, off, &st)) >= 0) {
346 			if (verbose || severity > VE_WANT) {
347 #if defined(VE_DEBUG_LEVEL) && VE_DEBUG_LEVEL > 0
348 				printf("Verified %s %llu,%llu\n", filename,
349 				    st.st_dev, st.st_ino);
350 #else
351 				printf("Verified %s\n", filename);
352 #endif
353 			}
354 			if (severity < VE_MUST) { /* not a kernel or module */
355 
356 				if ((cp = strrchr(filename, '/'))) {
357 					cp++;
358 					if (strncmp(cp, "loader.ve.", 10) == 0) {
359 						cp += 10;
360 						verify_tweak(cp,
361 						    &accept_no_fp, &verbose,
362 						    &verifying);
363 					}
364 				}
365 			}
366 			add_verify_status(&st, rc);
367 			ve_status_set(fd, rc);
368 			return (rc);
369 		}
370 
371 		if (severity || verbose)
372 			printf("Unverified: %s\n", ve_error_get());
373 		if (rc == VE_FINGERPRINT_UNKNOWN && severity < VE_MUST)
374 			rc = VE_UNVERIFIED_OK;
375 		else if (rc == VE_FINGERPRINT_NONE && severity < accept_no_fp)
376 			rc = VE_UNVERIFIED_OK;
377 
378 		add_verify_status(&st, rc);
379 	}
380 #ifdef LOADER_VERIEXEC_TESTING
381 	else if (rc != VE_FINGERPRINT_WRONG) {
382 		/*
383 		 * We have not loaded any manifest and
384 		 * not because of verication failure.
385 		 * Most likely reason is we have none.
386 		 * Allow boot to proceed if we are just testing.
387 		 */
388 		return (VE_UNVERIFIED_OK);
389 	}
390 #endif
391 	if (rc == VE_FINGERPRINT_WRONG && severity > accept_no_fp)
392 		panic("cannot continue");
393 	ve_status_set(fd, rc);
394 	return (rc);
395 }
396 
397 /**
398  * @brief get hex string for pcr value and export
399  *
400  * In case we are doing measured boot, provide
401  * value of the "pcr" data we have accumulated.
402  */
403 void
404 verify_pcr_export(void)
405 {
406 #ifdef VE_PCR_SUPPORT
407 	char hexbuf[br_sha256_SIZE * 2 + 2];
408 	unsigned char hbuf[br_sha256_SIZE];
409 	char *hex;
410 	ssize_t hlen;
411 
412 	hlen = ve_pcr_get(hbuf, sizeof(hbuf));
413 	if (hlen > 0) {
414 		hex = hexdigest(hexbuf, sizeof(hexbuf), hbuf, hlen);
415 		if (hex) {
416 			hex[hlen*2] = '\0'; /* clobber newline */
417 			setenv("loader.ve.pcr", hex, 1);
418 		}
419 	}
420 #endif
421 }
422