]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libsecureboot/verify_file.c
MFC r345830: Create kernel module to parse Veriexec manifest based on envs
[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
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(char *tweak, int *accept_no_fp, int *verbose, int *verifying)
250 {
251         if (strcmp(tweak, "off") == 0) {
252                 *verifying = 0;
253         } else if (strcmp(tweak, "strict") == 0) {
254                 /* anything caller wants verified must be */
255                 *accept_no_fp = VE_WANT;
256                 *verbose = 1; /* warn of anything unverified */
257                 /* treat self test failure as fatal */
258                 if (!ve_self_tests()) {
259                         panic("verify self tests failed");
260                 }
261         } else if (strcmp(tweak, "modules") == 0) {
262                 /* modules/kernel must be verified */
263                 *accept_no_fp = VE_MUST;
264         } else if (strcmp(tweak, "try") == 0) {
265                 /* best effort: always accept no fp */
266                 *accept_no_fp = VE_MUST + 1;
267         } else if (strcmp(tweak, "verbose") == 0) {
268                 *verbose = 1;
269         } else if (strcmp(tweak, "quiet") == 0) {
270                 *verbose = 0;
271         }
272 }
273
274 /**
275  * @brief verify an open file
276  *
277  * @param[in] fd
278  *      open descriptor
279  *
280  * @param[in] filename
281  *      path we opened and will use to lookup fingerprint
282  *
283  * @param[in] off
284  *      current offset in fd, must be restored on return
285  *
286  * @param[in] severity
287  *      indicator of how to handle case of missing fingerprint
288  *
289  * We look for a signed manifest relative to the filename
290  * just opened and verify/load it if needed.
291  *
292  * We then use verify_fd() in libve to actually verify that hash for
293  * open file.  If it returns < 0 we look at the severity arg to decide
294  * what to do about it.
295  *
296  * If verify_fd() returns VE_FINGERPRINT_NONE we accept it if severity
297  * is < accept_no_fp.
298  *
299  * @return >= 0 on success < 0 on failure
300  */
301 int
302 verify_file(int fd, const char *filename, off_t off, int severity)
303 {
304         static int verifying = -1;
305         static int accept_no_fp = ACCEPT_NO_FP_DEFAULT;
306         static int verbose = VE_VERBOSE_DEFAULT;
307         struct stat st;
308         char *cp;
309         int rc;
310
311         if (verifying < 0) {
312                 verifying = ve_trust_init();
313 #ifdef VE_DEBUG_LEVEL
314                 ve_debug_set(VE_DEBUG_LEVEL);
315 #endif
316                 /* initialize ve_status with default result */
317                 rc = verifying ? VE_NOT_CHECKED : VE_NOT_VERIFYING;
318                 ve_status_set(0, rc);
319                 ve_status_state = VE_STATUS_NONE;
320                 if (verifying)
321                         ve_self_tests();
322         }
323         if (!verifying)
324                 return (0);
325
326         if (fd < 0 || fstat(fd, &st) < 0 || !S_ISREG(st.st_mode))
327                 return (0);
328
329         DEBUG_PRINTF(3, ("fd=%d,name='%s',off=%lld,dev=%lld,ino=%lld\n",
330                 fd, filename, (long long)off, (long long)st.st_dev,
331                 (long long)st.st_ino));
332     
333
334         rc = is_verified(&st);
335         if (rc != VE_NOT_CHECKED) {
336                 ve_status_set(fd, rc);
337                 return (rc);
338         }
339         rc = find_manifest(filename);
340         if (rc != VE_FINGERPRINT_WRONG && loaded_manifests) {
341                 if (severity <= VE_GUESS)
342                         severity = severity_guess(filename);
343                 if ((rc = verify_fd(fd, filename, off, &st)) >= 0) {
344                         if (verbose || severity > VE_WANT) {
345 #if defined(VE_DEBUG_LEVEL) && VE_DEBUG_LEVEL > 0
346                                 printf("Verified %s %llu,%llu\n", filename,
347                                     (long long)st.st_dev, (long long)st.st_ino);
348 #else
349                                 printf("Verified %s\n", filename);
350 #endif
351                         }
352                         if (severity < VE_MUST) { /* not a kernel or module */
353                                 
354                                 if ((cp = strrchr(filename, '/'))) {
355                                         cp++;
356                                         if (strncmp(cp, "loader.ve.", 10) == 0) {
357                                                 cp += 10;
358                                                 verify_tweak(cp,
359                                                     &accept_no_fp, &verbose,
360                                                     &verifying);
361                                         }
362                                 }
363                         }
364                         add_verify_status(&st, rc);
365                         ve_status_set(fd, rc);
366                         return (rc);
367                 }
368
369                 if (severity || verbose || rc == VE_FINGERPRINT_WRONG)
370                         printf("Unverified: %s\n", ve_error_get());
371                 if (rc == VE_FINGERPRINT_UNKNOWN && severity < VE_MUST)
372                         rc = VE_UNVERIFIED_OK;
373                 else if (rc == VE_FINGERPRINT_NONE && severity < accept_no_fp)
374                         rc = VE_UNVERIFIED_OK;
375
376                 add_verify_status(&st, rc);
377         }
378 #ifdef LOADER_VERIEXEC_TESTING
379         else if (rc != VE_FINGERPRINT_WRONG) {
380                 /*
381                  * We have not loaded any manifest and
382                  * not because of verication failure.
383                  * Most likely reason is we have none.
384                  * Allow boot to proceed if we are just testing.
385                  */
386                 return (VE_UNVERIFIED_OK);
387         }
388 #endif
389         if (rc == VE_FINGERPRINT_WRONG && severity > accept_no_fp)
390                 panic("cannot continue");
391         ve_status_set(fd, rc);
392         return (rc);
393 }
394
395 /**
396  * @brief get hex string for pcr value and export
397  *
398  * In case we are doing measured boot, provide
399  * value of the "pcr" data we have accumulated.
400  */
401 void
402 verify_pcr_export(void)
403 {
404 #ifdef VE_PCR_SUPPORT
405         char hexbuf[br_sha256_SIZE * 2 + 2];
406         unsigned char hbuf[br_sha256_SIZE];
407         char *hex;
408         ssize_t hlen;
409
410         hlen = ve_pcr_get(hbuf, sizeof(hbuf));
411         if (hlen > 0) {
412                 hex = hexdigest(hexbuf, sizeof(hexbuf), hbuf, hlen);
413                 if (hex) {
414                         hex[hlen*2] = '\0'; /* clobber newline */
415                         setenv("loader.ve.pcr", hex, 1);
416                 }
417         }
418 #endif
419 }