1 /*
2  * $FreeBSD$
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 *
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 *
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
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
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
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
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
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 *
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 seach, 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
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
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
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
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
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
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