]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libsecureboot/verify_file.c
Update to version 3.1.1
[FreeBSD/FreeBSD.git] / lib / libsecureboot / verify_file.c
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 #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  */
47 extern char *Destdir;
48 extern size_t DestdirLen;
49 extern 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  */
59 static int ve_status[SOPEN_MAX+1];
60 static int ve_status_state;
61 struct verify_status;
62 struct verify_status *verified_files = NULL;
63 static 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  */
71 static void
72 ve_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  */
91 int
92 ve_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  */
109 struct verify_status {
110         dev_t   vs_dev;
111         ino_t   vs_ino;
112         int     vs_status;
113         struct verify_status *vs_next;
114 };
115
116 int
117 is_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. */
132 void
133 add_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  */
150 int
151 load_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
198 static int
199 find_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
247 static int
248 severity_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         }
259         return (VE_WANT);
260 }
261
262 static int Verifying = -1;              /* 0 if not verifying */
263
264 static void
265 verify_tweak(int fd, off_t off, struct stat *stp,
266     char *tweak, int *accept_no_fp,
267     int *verbose)
268 {
269         if (strcmp(tweak, "off") == 0) {
270                 Verifying = 0;
271         } else if (strcmp(tweak, "strict") == 0) {
272                 /* anything caller wants verified must be */
273                 *accept_no_fp = VE_WANT;
274                 *verbose = 1; /* warn of anything unverified */
275                 /* treat self test failure as fatal */
276                 if (!ve_self_tests()) {
277                         panic("verify self tests failed");
278                 }
279         } else if (strcmp(tweak, "modules") == 0) {
280                 /* modules/kernel must be verified */
281                 *accept_no_fp = VE_MUST;
282         } else if (strcmp(tweak, "try") == 0) {
283                 /* best effort: always accept no fp */
284                 *accept_no_fp = VE_MUST + 1;
285         } else if (strcmp(tweak, "verbose") == 0) {
286                 *verbose = 1;
287         } else if (strcmp(tweak, "quiet") == 0) {
288                 *verbose = 0;
289         } else if (strncmp(tweak, "trust", 5) == 0) {
290                 /* content is trust anchor to add or revoke */
291                 unsigned char *ucp;
292                 size_t num;
293
294                 if (off > 0)
295                         lseek(fd, 0, SEEK_SET);
296                 ucp = read_fd(fd, stp->st_size);
297                 if (ucp == NULL)
298                         return;
299                 if (strstr(tweak, "revoke")) {
300                         num = ve_trust_anchors_revoke(ucp, stp->st_size);
301                         DEBUG_PRINTF(3, ("revoked %d trust anchors\n",
302                                 (int) num));
303                 } else {
304                         num = ve_trust_anchors_add_buf(ucp, stp->st_size);
305                         DEBUG_PRINTF(3, ("added %d trust anchors\n",
306                                 (int) num));
307                 }
308         }
309 }
310
311 #ifndef VE_DEBUG_LEVEL
312 # define VE_DEBUG_LEVEL 0
313 #endif
314
315 static int
316 getenv_int(const char *var, int def)
317 {
318         const char *cp;
319         char *ep;
320         long val;
321
322         val = def;
323         cp = getenv(var);
324         if (cp && *cp) {
325                 val = strtol(cp, &ep, 0);
326                 if ((ep && *ep) || val != (int)val) {
327                         val = def;
328                 }
329         }
330         return (int)val;
331 }
332
333
334 /**
335  * @brief prepare to verify an open file
336  *
337  * @param[in] fd
338  *      open descriptor
339  *
340  * @param[in] filename
341  *      path we opened and will use to lookup fingerprint
342  *
343  * @param[in] stp
344  *      stat pointer so we can check file type
345  */
346 int
347 verify_prep(int fd, const char *filename, off_t off, struct stat *stp,
348     const char *caller)
349 {
350         int rc;
351
352         if (Verifying < 0) {
353                 Verifying = ve_trust_init();
354 #ifndef UNIT_TEST
355                 ve_debug_set(getenv_int("VE_DEBUG_LEVEL", VE_DEBUG_LEVEL));
356 #endif
357                 /* initialize ve_status with default result */
358                 rc = Verifying ? VE_NOT_CHECKED : VE_NOT_VERIFYING;
359                 ve_status_set(0, rc);
360                 ve_status_state = VE_STATUS_NONE;
361                 if (Verifying) {
362                         ve_self_tests();
363                         ve_anchor_verbose_set(1);
364                 }
365         }
366         if (!Verifying || fd < 0)
367                 return (0);
368         if (stp) {
369                 if (fstat(fd, stp) < 0 || !S_ISREG(stp->st_mode))
370                         return (0);
371         }
372         DEBUG_PRINTF(2,
373             ("verify_prep: caller=%s,fd=%d,name='%s',off=%lld,dev=%lld,ino=%lld\n",
374                 caller, fd, filename, (long long)off, (long long)stp->st_dev,
375                 (long long)stp->st_ino));
376         rc = is_verified(stp);
377         DEBUG_PRINTF(4,("verify_prep: is_verified()->%d\n", rc));
378         if (rc == VE_NOT_CHECKED) {
379                 rc = find_manifest(filename);
380         } else {
381                 ve_status_set(fd, rc);
382         }
383         return (rc);
384 }
385
386 /**
387  * @brief verify an open file
388  *
389  * @param[in] fd
390  *      open descriptor
391  *
392  * @param[in] filename
393  *      path we opened and will use to lookup fingerprint
394  *
395  * @param[in] off
396  *      current offset in fd, must be restored on return
397  *
398  * @param[in] severity
399  *      indicator of how to handle case of missing fingerprint
400  *
401  * We look for a signed manifest relative to the filename
402  * just opened and verify/load it if needed.
403  *
404  * We then use verify_fd() in libve to actually verify that hash for
405  * open file.  If it returns < 0 we look at the severity arg to decide
406  * what to do about it.
407  *
408  * If verify_fd() returns VE_FINGERPRINT_NONE we accept it if severity
409  * is < accept_no_fp.
410  *
411  * @return >= 0 on success < 0 on failure
412  */
413 int
414 verify_file(int fd, const char *filename, off_t off, int severity,
415     const char *caller)
416 {
417         static int once;
418         static int accept_no_fp = ACCEPT_NO_FP_DEFAULT;
419         static int verbose = VE_VERBOSE_DEFAULT;
420         struct stat st;
421         char *cp;
422         int rc;
423
424         rc = verify_prep(fd, filename, off, &st, caller);
425
426         if (!rc)
427                 return (0);
428
429         if (!once) {
430                 once++;
431                 verbose = getenv_int("VE_VERBOSE", VE_VERBOSE_DEFAULT);
432         }
433
434         if (rc != VE_FINGERPRINT_WRONG && loaded_manifests) {
435                 if (severity <= VE_GUESS)
436                         severity = severity_guess(filename);
437 #ifdef VE_PCR_SUPPORT
438                 /*
439                  * Only update pcr with things that must verify
440                  * these tend to be processed in a more deterministic
441                  * order, which makes our pseudo pcr more useful.
442                  */
443                 ve_pcr_updating_set((severity == VE_MUST));
444 #endif
445 #ifdef UNIT_TEST
446                 if (DestdirLen > 0 &&
447                     strncmp(filename, Destdir, DestdirLen) == 0) {
448                         filename += DestdirLen;
449                 }
450 #endif
451                 if ((rc = verify_fd(fd, filename, off, &st)) >= 0) {
452                         if (verbose || severity > VE_WANT) {
453 #if defined(VE_DEBUG_LEVEL) && VE_DEBUG_LEVEL > 0
454                                 printf("%serified %s %llu,%llu\n",
455                                     (rc == VE_FINGERPRINT_IGNORE) ? "Unv" : "V",
456                                     filename,
457                                     (long long)st.st_dev, (long long)st.st_ino);
458 #else
459                                 printf("%serified %s\n",
460                                     (rc == VE_FINGERPRINT_IGNORE) ? "Unv" : "V",
461                                     filename);
462 #endif
463                         }
464                         if (severity < VE_MUST) { /* not a kernel or module */
465                                 if ((cp = strrchr(filename, '/'))) {
466                                         cp++;
467                                         if (strncmp(cp, "loader.ve.", 10) == 0) {
468                                                 cp += 10;
469                                                 verify_tweak(fd, off, &st, cp,
470                                                     &accept_no_fp, &verbose);
471                                         }
472                                 }
473                         }
474                         add_verify_status(&st, rc);
475                         ve_status_set(fd, rc);
476                         return (rc);
477                 }
478
479                 if (severity || verbose || rc == VE_FINGERPRINT_WRONG)
480                         printf("Unverified: %s\n", ve_error_get());
481                 if (rc == VE_FINGERPRINT_UNKNOWN && severity < VE_MUST)
482                         rc = VE_UNVERIFIED_OK;
483                 else if (rc == VE_FINGERPRINT_NONE && severity < accept_no_fp)
484                         rc = VE_UNVERIFIED_OK;
485
486                 add_verify_status(&st, rc);
487         }
488 #ifdef LOADER_VERIEXEC_TESTING
489         else if (rc != VE_FINGERPRINT_WRONG) {
490                 /*
491                  * We have not loaded any manifest and
492                  * not because of verication failure.
493                  * Most likely reason is we have none.
494                  * Allow boot to proceed if we are just testing.
495                  */
496                 return (VE_UNVERIFIED_OK);
497         }
498 #endif
499         if (rc == VE_FINGERPRINT_WRONG && severity > accept_no_fp)
500                 panic("cannot continue");
501         ve_status_set(fd, rc);
502         return (rc);
503 }
504
505 /**
506  * @brief get hex string for pcr value and export
507  *
508  * In case we are doing measured boot, provide
509  * value of the "pcr" data we have accumulated.
510  */
511 void
512 verify_pcr_export(void)
513 {
514 #ifdef VE_PCR_SUPPORT
515         char hexbuf[br_sha256_SIZE * 2 + 2];
516         unsigned char hbuf[br_sha256_SIZE];
517         char *hinfo;
518         char *hex;
519         ssize_t hlen;
520
521         hlen = ve_pcr_get(hbuf, sizeof(hbuf));
522         if (hlen > 0) {
523                 hex = hexdigest(hexbuf, sizeof(hexbuf), hbuf, hlen);
524                 if (hex) {
525                         hex[hlen*2] = '\0'; /* clobber newline */
526                         setenv("loader.ve.pcr", hex, 1);
527                         DEBUG_PRINTF(1,
528                             ("%s: setenv(loader.ve.pcr, %s\n", __func__,
529                                 hex));
530                         hinfo = ve_pcr_hashed_get(1);
531                         if (hinfo) {
532                                 setenv("loader.ve.hashed", hinfo, 1);
533                                 DEBUG_PRINTF(1,
534                                     ("%s: setenv(loader.ve.hashed, %s\n",
535                                         __func__, hinfo));
536                                 if ((hlen = strlen(hinfo)) > KENV_MVALLEN) {
537                                         /*
538                                          * bump kenv_mvallen
539                                          * roundup to multiple of KENV_MVALLEN
540                                          */
541                                         char mvallen[16];
542
543                                         hlen += KENV_MVALLEN -
544                                             (hlen % KENV_MVALLEN);
545                                         if (snprintf(mvallen, sizeof(mvallen),
546                                                 "%d", (int) hlen) < sizeof(mvallen))
547                                                 setenv("kenv_mvallen", mvallen, 1);
548                                 }
549                                 free(hinfo);
550                         }
551                 }
552         }
553 #endif
554 }