1 /*
2 * $FreeBSD: stable/12/sys/security/mac_veriexec/veriexec_metadata.c 371792 2022-03-30 16:42:04Z gbe $
3 *
4 * Copyright (c) 2011, 2012, 2013, 2015, 2016, Juniper Networks, Inc.
5 * All rights reserved.
6 *
7 * Originally derived from:
8 * $NetBSD: kern_verifiedexec.c,v 1.7 2003/11/18 13:13:03 martin Exp $
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33
34 #include "opt_mac.h"
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/exec.h>
39 #include <sys/lock.h>
40 #include <sys/malloc.h>
41 #include <sys/mutex.h>
42 #include <sys/proc.h>
43 #include <sys/sbuf.h>
44 #include <sys/vnode.h>
45
46 #include "mac_veriexec.h"
47 #include "mac_veriexec_internal.h"
48
49 /**
50 * @brief per-device meta-data storage
51 */
52 struct veriexec_dev_list {
53 dev_t fsid; /**< file system identifier of the mount point */
54 LIST_HEAD(filehead, mac_veriexec_file_info) file_head;
55 /**< list of per-file meta-data information */
56 LIST_ENTRY(veriexec_dev_list) entries;
57 /**< next entries in the device list */
58 };
59
60 typedef LIST_HEAD(veriexec_devhead, veriexec_dev_list) veriexec_devhead_t;
61
62 /**
63 * @brief Mutex to protect the meta-data store lists
64 */
65 struct mtx ve_mutex;
66
67 /**
68 * @brief Executables meta-data storage
69 *
70 * This is used to store the fingerprints for potentially-executable files.
71 */
72 veriexec_devhead_t veriexec_dev_head;
73
74 /**
75 * @brief Plain file meta-data storage
76 *
77 * This is used for files that are not allowed to be executed, but should
78 * have fingerprint validation available.
79 */
80 veriexec_devhead_t veriexec_file_dev_head;
81
82 /**
83 * @internal
84 * @brief Search the @p head meta-data list for the specified file identifier
85 * @p fileid in the file system identified by @p fsid
86 *
87 * If meta-data exists for file system identified by @p fsid, it has a
88 * fingerprint list, and @p found_dev is not @c NULL then store true in the
89 * location pointed to by @p found_dev
90 *
91 * @param head meta-data list to search
92 * @param fsid file system identifier to look for
93 * @param fileid file to look for
94 * @param gen generation of file
95 * @param found_dev indicator that an entry for the file system was found
96 *
97 * @return A pointer to the meta-data inforation if meta-data exists for
98 * the specified file identifier, otherwise @c NULL
99 */
100 static struct mac_veriexec_file_info *
get_veriexec_file(struct veriexec_devhead * head,dev_t fsid,long fileid,unsigned long gen,int * found_dev)101 get_veriexec_file(struct veriexec_devhead *head, dev_t fsid, long fileid,
102 unsigned long gen, int *found_dev)
103 {
104 struct veriexec_dev_list *lp;
105 struct mac_veriexec_file_info *ip, *tip;
106
107 ip = NULL;
108
109 /* Initialize the value found_dev, if non-NULL */
110 if (found_dev != NULL)
111 *found_dev = 0;
112
113 VERIEXEC_DEBUG(3, ("searching for file %ju.%lu on device %ju,"
114 " files=%d\n", (uintmax_t)fileid, gen, (uintmax_t)fsid,
115 (head == &veriexec_file_dev_head)));
116
117 /* Get a lock to access the list */
118 mtx_lock(&ve_mutex);
119
120 /* First, look for the file system */
121 for (lp = LIST_FIRST(head); lp != NULL; lp = LIST_NEXT(lp, entries))
122 if (lp->fsid == fsid)
123 break;
124
125 /* We found the file system in the list */
126 if (lp != NULL) {
127 VERIEXEC_DEBUG(3, ("found matching dev number %ju\n",
128 (uintmax_t)lp->fsid));
129
130 /* If found_dev is non-NULL, store true there */
131 if (found_dev != NULL)
132 *found_dev = 1;
133
134 /* Next, look for the meta-data information for the file */
135 LIST_FOREACH_SAFE(ip, &(lp->file_head), entries, tip) {
136 if (ip->fileid == fileid) {
137 if (ip->gen == gen)
138 break;
139 /* we need to garbage collect */
140 LIST_REMOVE(ip, entries);
141 free(ip, M_VERIEXEC);
142 }
143 }
144 }
145
146 /* Release the lock we obtained earlier */
147 mtx_unlock(&ve_mutex);
148
149 /* Return the meta-data information we found, if anything */
150 return (ip);
151 }
152
153 /**
154 * @internal
155 * @brief Search the meta-data store for information on the specified file.
156 *
157 * @param fsid file system identifier to look for
158 * @param fileid file to look for
159 * @param gen generation of file
160 * @param found_dev indicator that an entry for the file system was found
161 * @param check_files if 1, check the files list first, otherwise check the
162 * exectuables list first
163 *
164 * @return A pointer to the meta-data inforation if meta-data exists for
165 * the specified file identifier, otherwise @c NULL
166 */
167 static struct mac_veriexec_file_info *
find_veriexec_file(dev_t fsid,long fileid,unsigned long gen,int * found_dev,int check_files)168 find_veriexec_file(dev_t fsid, long fileid, unsigned long gen, int *found_dev,
169 int check_files)
170 {
171 struct veriexec_devhead *search[3];
172 struct mac_veriexec_file_info *ip;
173 int x;
174
175 /* Determine the order of the lists to search */
176 if (check_files) {
177 search[0] = &veriexec_file_dev_head;
178 search[1] = &veriexec_dev_head;
179 } else {
180 search[0] = &veriexec_dev_head;
181 search[1] = &veriexec_file_dev_head;
182 }
183 search[2] = NULL;
184
185 VERIEXEC_DEBUG(3, ("%s: searching for dev %ju, file %lu\n",
186 __func__, (uintmax_t)fsid, fileid));
187
188 /* Search for the specified file */
189 for (ip = NULL, x = 0; ip == NULL && search[x]; x++)
190 ip = get_veriexec_file(search[x], fsid, fileid, gen, found_dev);
191
192 return (ip);
193 }
194
195 /**
196 * @internal
197 * @brief Display the fingerprint for each entry in the device list
198 *
199 * @param sbp sbuf to write output to
200 * @param lp pointer to device list
201 */
202 static void
mac_veriexec_print_db_dev_list(struct sbuf * sbp,struct veriexec_dev_list * lp)203 mac_veriexec_print_db_dev_list(struct sbuf *sbp, struct veriexec_dev_list *lp)
204 {
205 struct mac_veriexec_file_info *ip;
206
207 #define FPB(i) (ip->fingerprint[i])
208 for (ip = LIST_FIRST(&(lp->file_head)); ip != NULL;
209 ip = LIST_NEXT(ip, entries))
210 sbuf_printf(sbp, " %ld: %u %ld [%02x %02x %02x %02x %02x "
211 "%02x %02x %02x...]\n", ip->fileid, ip->flags, ip->gen,
212 FPB(0), FPB(1), FPB(2), FPB(3), FPB(4), FPB(5), FPB(6),
213 FPB(7));
214 }
215
216 /**
217 * @internal
218 * @brief Display the device list
219 *
220 * @param sbp sbuf to write output to
221 * @param head pointer to head of the device list
222 */
223 static void
mac_veriexec_print_db_head(struct sbuf * sbp,struct veriexec_devhead * head)224 mac_veriexec_print_db_head(struct sbuf *sbp, struct veriexec_devhead *head)
225 {
226 struct veriexec_dev_list *lp;
227
228 for (lp = LIST_FIRST(head); lp != NULL; lp = LIST_NEXT(lp, entries)) {
229 sbuf_printf(sbp, " FS id: %ju\n", (uintmax_t)lp->fsid);
230 mac_veriexec_print_db_dev_list(sbp, lp);
231 }
232
233 }
234
235 /**
236 * @internal
237 * @brief Generate human-readable output for the current fingerprint database
238 *
239 * @param sbp sbuf to write output to
240 */
241 void
mac_veriexec_metadata_print_db(struct sbuf * sbp)242 mac_veriexec_metadata_print_db(struct sbuf *sbp)
243 {
244 struct {
245 struct veriexec_devhead *h;
246 const char *name;
247 } fpdbs[] = {
248 { &veriexec_file_dev_head, "regular files" },
249 { &veriexec_dev_head, "executable files" },
250 };
251 int i;
252
253 mtx_lock(&ve_mutex);
254 for (i = 0; i < sizeof(fpdbs)/sizeof(fpdbs[0]); i++) {
255 sbuf_printf(sbp, "%s fingerprint db:\n", fpdbs[i].name);
256 mac_veriexec_print_db_head(sbp, fpdbs[i].h);
257 }
258 mtx_unlock(&ve_mutex);
259 }
260 /**
261 * @brief Determine if the meta-data store has an entry for the specified file.
262 *
263 * @param fsid file system identifier to look for
264 * @param fileid file to look for
265 * @param gen generation of file
266 *
267 * @return 1 if there is an entry in the meta-data store, 0 otherwise.
268 */
269 int
mac_veriexec_metadata_has_file(dev_t fsid,long fileid,unsigned long gen)270 mac_veriexec_metadata_has_file(dev_t fsid, long fileid, unsigned long gen)
271 {
272
273 return (find_veriexec_file(fsid, fileid, gen, NULL,
274 VERIEXEC_FILES_FIRST) != NULL);
275 }
276
277 /**
278 * @brief Search the list of devices looking for the one given, in order to
279 * release the resources used by it.
280 *
281 * If found, free all file entries for it, and remove it from the list.
282 *
283 * @note Called with @a ve_mutex held
284 *
285 * @param fsid file system identifier to look for
286 * @param head meta-data list to search
287 *
288 * @return 0 if the device entry was freed, otherwise an error code
289 */
290 static int
free_veriexec_dev(dev_t fsid,struct veriexec_devhead * head)291 free_veriexec_dev(dev_t fsid, struct veriexec_devhead *head)
292 {
293 struct veriexec_dev_list *lp;
294 struct mac_veriexec_file_info *ip, *nip;
295
296 /* Look for the file system */
297 for (lp = LIST_FIRST(head); lp != NULL;
298 lp = LIST_NEXT(lp, entries))
299 if (lp->fsid == fsid) break;
300
301 /* If lp is NULL, we did not find it */
302 if (lp == NULL)
303 return ENOENT;
304
305 /* Unhook lp, before we free it and its content */
306 LIST_REMOVE(lp, entries);
307
308 /* Release the lock */
309 mtx_unlock(&ve_mutex);
310
311 /* Free the file entries in the list */
312 for (ip = LIST_FIRST(&(lp->file_head)); ip != NULL; ip = nip) {
313 nip = LIST_NEXT(ip, entries);
314 LIST_REMOVE(ip, entries);
315 free(ip, M_VERIEXEC);
316 }
317
318 /* Free the meta-data entry for the device */
319 free(lp, M_VERIEXEC);
320
321 /* Re-acquire the lock */
322 mtx_lock(&ve_mutex);
323 return 0;
324 }
325
326 /**
327 * @brief Search the list of devices looking for the one given.
328 *
329 * If it is not in the list then add it.
330 *
331 * @note Called with @a ve_mutex held
332 *
333 * @param fsid file system identifier to look for
334 * @param head meta-data list to search
335 *
336 * @return A pointer to the meta-data entry for the device, if found or added,
337 * otherwise @c NULL
338 */
339 static struct veriexec_dev_list *
find_veriexec_dev(dev_t fsid,struct veriexec_devhead * head)340 find_veriexec_dev(dev_t fsid, struct veriexec_devhead *head)
341 {
342 struct veriexec_dev_list *lp;
343 struct veriexec_dev_list *np = NULL;
344
345 search:
346 /* Look for the file system */
347 for (lp = LIST_FIRST(head); lp != NULL;
348 lp = LIST_NEXT(lp, entries))
349 if (lp->fsid == fsid) break;
350
351 if (lp == NULL) {
352 if (np == NULL) {
353 /*
354 * If pointer is null then entry not there,
355 * add a new one, first try to malloc while
356 * we hold mutex - should work most of the time.
357 */
358 np = malloc(sizeof(struct veriexec_dev_list),
359 M_VERIEXEC, M_NOWAIT);
360 if (np == NULL) {
361 /*
362 * So much for that plan, dop the mutex
363 * and repeat...
364 */
365 mtx_unlock(&ve_mutex);
366 np = malloc(sizeof(struct veriexec_dev_list),
367 M_VERIEXEC, M_WAITOK);
368 mtx_lock(&ve_mutex);
369 /*
370 * Repeat the search, in case someone
371 * added this while we slept.
372 */
373 goto search;
374 }
375 }
376 if (np) {
377 /* Add the entry to the list */
378 lp = np;
379 LIST_INIT(&(lp->file_head));
380 lp->fsid = fsid;
381 LIST_INSERT_HEAD(head, lp, entries);
382 }
383 } else if (np) {
384 /*
385 * Someone else did it while we slept.
386 */
387 mtx_unlock(&ve_mutex);
388 free(np, M_VERIEXEC);
389 mtx_lock(&ve_mutex);
390 }
391
392 return (lp);
393 }
394
395 /**
396 * @brief When a device is unmounted, we want to toss the signatures recorded
397 * against it.
398 *
399 * We are being called from unmount() with the root vnode just before it is
400 * freed.
401 *
402 * @param fsid file system identifier to look for
403 * @param td calling thread
404 *
405 * @return 0 on success, otherwise an error code.
406 */
407 int
mac_veriexec_metadata_unmounted(dev_t fsid,struct thread * td)408 mac_veriexec_metadata_unmounted(dev_t fsid, struct thread *td)
409 {
410 int error;
411
412 /*
413 * The device can have entries on both lists.
414 */
415 mtx_lock(&ve_mutex);
416 error = free_veriexec_dev(fsid, &veriexec_dev_head);
417 if (error && error != ENOENT) {
418 mtx_unlock(&ve_mutex);
419 return error;
420 }
421 error = free_veriexec_dev(fsid, &veriexec_file_dev_head);
422 mtx_unlock(&ve_mutex);
423 if (error && error != ENOENT) {
424 return error;
425 }
426 return 0;
427 }
428
429 /**
430 * @brief Return the flags assigned to the file identified by file system
431 * identifier @p fsid and file identifier @p fileid.
432 *
433 * @param fsid file system identifier
434 * @param fileid file identifier within the file system
435 * @param gen generation of file
436 * @param flags pointer to location to store the flags
437 * @param check_files if 1, check the files list first, otherwise check the
438 * exectuables list first
439 *
440 * @return 0 on success, otherwise an error code.
441 */
442 int
mac_veriexec_metadata_get_file_flags(dev_t fsid,long fileid,unsigned long gen,int * flags,int check_files)443 mac_veriexec_metadata_get_file_flags(dev_t fsid, long fileid, unsigned long gen,
444 int *flags, int check_files)
445 {
446 struct mac_veriexec_file_info *ip;
447 int found_dev;
448
449 ip = find_veriexec_file(fsid, fileid, gen, &found_dev, check_files);
450 if (ip == NULL)
451 return (ENOENT);
452
453 *flags = ip->flags;
454 return (0);
455 }
456
457 /**
458 * @brief get the files for the specified process
459 *
460 * @param cred credentials to use
461 * @param p process to get the flags for
462 * @param flags where to store the flags
463 * @param check_files if 1, check the files list first, otherwise check the
464 * exectuables list first
465 *
466 * @return 0 if the process has an entry in the meta-data store, otherwise an
467 * error code
468 */
469 int
mac_veriexec_metadata_get_executable_flags(struct ucred * cred,struct proc * p,int * flags,int check_files)470 mac_veriexec_metadata_get_executable_flags(struct ucred *cred, struct proc *p,
471 int *flags, int check_files)
472 {
473 struct vnode *proc_vn;
474 struct vattr vap;
475 int error;
476
477 /* Get the text vnode for the process */
478 proc_vn = p->p_textvp;
479 if (proc_vn == NULL)
480 return EINVAL;
481
482 /* Get vnode attributes */
483 error = VOP_GETATTR(proc_vn, &vap, cred);
484 if (error)
485 return error;
486
487 error = mac_veriexec_metadata_get_file_flags(vap.va_fsid,
488 vap.va_fileid, vap.va_gen, flags,
489 (check_files == VERIEXEC_FILES_FIRST));
490
491 return (error);
492 }
493
494 /**
495 * @brief Ensure the fingerprint status for the vnode @p vp is assigned to its
496 * MAC label.
497 *
498 * @param vp vnode to check
499 * @param vap vnode attributes to use
500 * @param td calling thread
501 * @param check_files if 1, check the files list first, otherwise check the
502 * exectuables list first
503 *
504 * @return 0 on success, otherwise an error code.
505 */
506 int
mac_veriexec_metadata_fetch_fingerprint_status(struct vnode * vp,struct vattr * vap,struct thread * td,int check_files)507 mac_veriexec_metadata_fetch_fingerprint_status(struct vnode *vp,
508 struct vattr *vap, struct thread *td, int check_files)
509 {
510 unsigned char digest[MAXFINGERPRINTLEN];
511 struct mac_veriexec_file_info *ip;
512 int error, found_dev;
513 fingerprint_status_t status;
514
515 error = 0;
516 ip = NULL;
517
518 status = mac_veriexec_get_fingerprint_status(vp);
519 if (status == FINGERPRINT_INVALID || status == FINGERPRINT_NODEV) {
520 found_dev = 0;
521 ip = find_veriexec_file(vap->va_fsid, vap->va_fileid,
522 vap->va_gen, &found_dev, check_files);
523 if (ip == NULL) {
524 status = (found_dev) ? FINGERPRINT_NOENTRY :
525 FINGERPRINT_NODEV;
526 VERIEXEC_DEBUG(3,
527 ("fingerprint status is %d for dev %ju, file "
528 "%ju.%lu\n", status, (uintmax_t)vap->va_fsid,
529 (uintmax_t)vap->va_fileid, vap->va_gen));
530 } else {
531 /*
532 * evaluate and compare fingerprint
533 */
534 error = mac_veriexec_fingerprint_check_vnode(vp, ip,
535 td, vap->va_size, digest);
536 switch (error) {
537 case 0:
538 /* Process flags */
539 if ((ip->flags & VERIEXEC_INDIRECT))
540 status = FINGERPRINT_INDIRECT;
541 else if ((ip->flags & VERIEXEC_FILE))
542 status = FINGERPRINT_FILE;
543 else
544 status = FINGERPRINT_VALID;
545 VERIEXEC_DEBUG(2,
546 ("%sfingerprint matches for dev %ju, file "
547 "%ju.%lu\n",
548 (status == FINGERPRINT_INDIRECT) ?
549 "indirect " :
550 (status == FINGERPRINT_FILE) ?
551 "file " : "", (uintmax_t)vap->va_fsid,
552 (uintmax_t)vap->va_fileid, vap->va_gen));
553 break;
554
555 case EAUTH:
556 #ifdef VERIFIED_EXEC_DEBUG_VERBOSE
557 {
558 char have[MAXFINGERPRINTLEN * 2 + 1];
559 char want[MAXFINGERPRINTLEN * 2 + 1];
560 int i, len;
561
562 len = ip->ops->digest_len;
563 for (i = 0; i < len; i++) {
564 sprintf(&want[i * 2], "%02x",
565 ip->fingerprint[i]);
566 sprintf(&have[i * 2], "%02x",
567 digest[i]);
568 }
569 log(LOG_ERR, MAC_VERIEXEC_FULLNAME
570 ": fingerprint for dev %ju, file "
571 "%ju.%lu %s != %s\n",
572 (uintmax_t)vap->va_fsid,
573 (uintmax_t)vap->va_fileid,
574 vap->va_gen,
575 have, want);
576 }
577 #endif
578 status = FINGERPRINT_NOMATCH;
579 break;
580 default:
581 VERIEXEC_DEBUG(2,
582 ("fingerprint status error %d\n", error));
583 break;
584 }
585 }
586 mac_veriexec_set_fingerprint_status(vp, status);
587 }
588 return (error);
589 }
590
591 /**
592 * Add a file and its fingerprint to the list of files attached
593 * to the device @p fsid.
594 *
595 * Only add the entry if it is not already on the list.
596 *
597 * @note Called with @a ve_mutex held
598 *
599 * @param file_dev if 1, the entry should be added on the file list,
600 * otherwise it should be added on the executable list
601 * @param fsid file system identifier of device
602 * @param fileid file to add
603 * @param gen generation of file
604 * @param fingerprint fingerprint to add to the store
605 * @param flags flags to set in the store
606 * @param fp_type digest type
607 * @param override if 1, override any values already stored
608 *
609 * @return 0 on success, otherwise an error code.
610 */
611 int
mac_veriexec_metadata_add_file(int file_dev,dev_t fsid,long fileid,unsigned long gen,unsigned char fingerprint[MAXFINGERPRINTLEN],int flags,const char * fp_type,int override)612 mac_veriexec_metadata_add_file(int file_dev, dev_t fsid, long fileid,
613 unsigned long gen, unsigned char fingerprint[MAXFINGERPRINTLEN],
614 int flags, const char *fp_type, int override)
615 {
616 struct mac_veriexec_fpops *fpops;
617 struct veriexec_dev_list *lp;
618 struct veriexec_devhead *head;
619 struct mac_veriexec_file_info *ip;
620 struct mac_veriexec_file_info *np = NULL;
621
622 /* Look up the device entry */
623 if (file_dev)
624 head = &veriexec_file_dev_head;
625 else
626 head = &veriexec_dev_head;
627 lp = find_veriexec_dev(fsid, head);
628
629 /* Look up the fingerprint operations for the digest type */
630 fpops = mac_veriexec_fingerprint_lookup_ops(fp_type);
631 if (fpops == NULL)
632 return (EOPNOTSUPP);
633
634 search:
635 for (ip = LIST_FIRST(&(lp->file_head)); ip != NULL;
636 ip = LIST_NEXT(ip, entries)) {
637 /* check for a dupe file in the list, skip if an entry
638 * exists for this file except for when the flags contains
639 * VERIEXEC_INDIRECT, always set the flags when it is so
640 * we don't get a hole caused by conflicting flags on
641 * hardlinked files. XXX maybe we should validate
642 * fingerprint is same and complain if it is not...
643 */
644 if (ip->fileid == fileid && ip->gen == gen) {
645 if (override) {
646 /*
647 * for a signed load we allow overrides,
648 * otherwise fingerpints needed for pkg loads
649 * can fail (the files are on temp device).
650 */
651 ip->flags = flags;
652 ip->ops = fpops;
653 memcpy(ip->fingerprint, fingerprint,
654 fpops->digest_len);
655 } else if ((flags & (VERIEXEC_INDIRECT|VERIEXEC_FILE)))
656 ip->flags |= flags;
657
658 if (np) {
659 /* unlikely but... we don't need it now. */
660 mtx_unlock(&ve_mutex);
661 free(np, M_VERIEXEC);
662 mtx_lock(&ve_mutex);
663 }
664 return (0);
665 }
666 }
667
668 /*
669 * We may have been past here before...
670 */
671 if (np == NULL) {
672 /*
673 * We first try with mutex held and nowait.
674 */
675 np = malloc(sizeof(struct mac_veriexec_file_info), M_VERIEXEC,
676 M_NOWAIT);
677 if (np == NULL) {
678 /*
679 * It was worth a try, now
680 * drop mutex while we malloc.
681 */
682 mtx_unlock(&ve_mutex);
683 np = malloc(sizeof(struct mac_veriexec_file_info),
684 M_VERIEXEC, M_WAITOK);
685 mtx_lock(&ve_mutex);
686 /*
687 * We now have to repeat our search!
688 */
689 goto search;
690 }
691 }
692
693 /* Set up the meta-data entry */
694 ip = np;
695 ip->flags = flags;
696 ip->ops = fpops;
697 ip->fileid = fileid;
698 ip->gen = gen;
699 memcpy(ip->fingerprint, fingerprint, fpops->digest_len);
700
701 VERIEXEC_DEBUG(3, ("add file %ju.%lu (files=%d)\n",
702 (uintmax_t)ip->fileid,
703 ip->gen, file_dev));
704
705 /* Add the entry to the list */
706 LIST_INSERT_HEAD(&(lp->file_head), ip, entries);
707 #ifdef DEBUG_VERIEXEC_FINGERPRINT
708 {
709 off_t offset;
710
711 printf("Stored %s fingerprint:\n", fp_type);
712 for (offset = 0; offset < fpops->digest_len; offset++)
713 printf("%02x", fingerprint[offset]);
714 printf("\n");
715 }
716 #endif
717 return (0);
718 }
719
720 /**
721 * @brief Intialize the meta-data store
722 */
723 void
mac_veriexec_metadata_init(void)724 mac_veriexec_metadata_init(void)
725 {
726
727 mtx_init(&ve_mutex, "veriexec lock", NULL, MTX_DEF);
728 LIST_INIT(&veriexec_dev_head);
729 LIST_INIT(&veriexec_file_dev_head);
730 }
731