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