xref: /freebsd/sys/security/mac_veriexec/veriexec_metadata.c (revision 6eabf4ce35ec1c79ab9a9dbe70ac934d62d2cd5d)
188a3358eSStephen J. Kiernan /*-
288a3358eSStephen J. Kiernan  * SPDX-License-Identifier: BSD-2-Clause
3fb47a376SStephen J. Kiernan  *
494288674SStephen J. Kiernan  * Copyright (c) 2011, 2012, 2013, 2015, 2016, 2019, Juniper Networks, Inc.
5fb47a376SStephen J. Kiernan  * All rights reserved.
6fb47a376SStephen J. Kiernan  *
7fb47a376SStephen J. Kiernan  * Originally derived from:
8fb47a376SStephen J. Kiernan  *	$NetBSD: kern_verifiedexec.c,v 1.7 2003/11/18 13:13:03 martin Exp $
9fb47a376SStephen J. Kiernan  *
10fb47a376SStephen J. Kiernan  * Redistribution and use in source and binary forms, with or without
11fb47a376SStephen J. Kiernan  * modification, are permitted provided that the following conditions
12fb47a376SStephen J. Kiernan  * are met:
13fb47a376SStephen J. Kiernan  * 1. Redistributions of source code must retain the above copyright
14fb47a376SStephen J. Kiernan  *    notice, this list of conditions and the following disclaimer.
15fb47a376SStephen J. Kiernan  * 2. Redistributions in binary form must reproduce the above copyright
16fb47a376SStephen J. Kiernan  *    notice, this list of conditions and the following disclaimer in the
17fb47a376SStephen J. Kiernan  *    documentation and/or other materials provided with the distribution.
18fb47a376SStephen J. Kiernan  *
19fb47a376SStephen J. Kiernan  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20fb47a376SStephen J. Kiernan  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21fb47a376SStephen J. Kiernan  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22fb47a376SStephen J. Kiernan  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23fb47a376SStephen J. Kiernan  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24fb47a376SStephen J. Kiernan  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25fb47a376SStephen J. Kiernan  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26fb47a376SStephen J. Kiernan  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27fb47a376SStephen J. Kiernan  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28fb47a376SStephen J. Kiernan  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29fb47a376SStephen J. Kiernan  * SUCH DAMAGE.
30fb47a376SStephen J. Kiernan  */
31fb47a376SStephen J. Kiernan 
32fb47a376SStephen J. Kiernan #include <sys/cdefs.h>
33fb47a376SStephen J. Kiernan 
34fb47a376SStephen J. Kiernan #include "opt_mac.h"
35fb47a376SStephen J. Kiernan 
36fb47a376SStephen J. Kiernan #include <sys/param.h>
37fb47a376SStephen J. Kiernan #include <sys/systm.h>
38fb47a376SStephen J. Kiernan #include <sys/exec.h>
39fb47a376SStephen J. Kiernan #include <sys/lock.h>
40fb47a376SStephen J. Kiernan #include <sys/malloc.h>
41fb47a376SStephen J. Kiernan #include <sys/mutex.h>
42fb47a376SStephen J. Kiernan #include <sys/proc.h>
43fb47a376SStephen J. Kiernan #include <sys/sbuf.h>
44d195f39dSSteve Kiernan #ifdef MAC_VERIEXEC_DEBUG
45d195f39dSSteve Kiernan #include <sys/syslog.h>
46d195f39dSSteve Kiernan #endif
47fb47a376SStephen J. Kiernan #include <sys/vnode.h>
48fb47a376SStephen J. Kiernan 
49fb47a376SStephen J. Kiernan #include "mac_veriexec.h"
50fb47a376SStephen J. Kiernan #include "mac_veriexec_internal.h"
51fb47a376SStephen J. Kiernan 
52fb47a376SStephen J. Kiernan /**
53fb47a376SStephen J. Kiernan  * @brief per-device meta-data storage
54fb47a376SStephen J. Kiernan  */
55fb47a376SStephen J. Kiernan struct veriexec_dev_list {
56fb47a376SStephen J. Kiernan 	dev_t fsid;	/**< file system identifier of the mount point */
57fb47a376SStephen J. Kiernan 	LIST_HEAD(filehead, mac_veriexec_file_info) file_head;
58fb47a376SStephen J. Kiernan 	    /**< list of per-file meta-data information */
59fb47a376SStephen J. Kiernan 	LIST_ENTRY(veriexec_dev_list) entries;
60fb47a376SStephen J. Kiernan 	    /**< next entries in the device list */
61fb47a376SStephen J. Kiernan };
62fb47a376SStephen J. Kiernan 
63fb47a376SStephen J. Kiernan typedef LIST_HEAD(veriexec_devhead, veriexec_dev_list) veriexec_devhead_t;
64fb47a376SStephen J. Kiernan 
65fb47a376SStephen J. Kiernan /**
66fb47a376SStephen J. Kiernan  * @brief Mutex to protect the meta-data store lists
67fb47a376SStephen J. Kiernan  */
68fb47a376SStephen J. Kiernan struct mtx ve_mutex;
69fb47a376SStephen J. Kiernan 
70fb47a376SStephen J. Kiernan /**
71fb47a376SStephen J. Kiernan  * @brief Executables meta-data storage
72fb47a376SStephen J. Kiernan  *
73fb47a376SStephen J. Kiernan  * This is used to store the fingerprints for potentially-executable files.
74fb47a376SStephen J. Kiernan  */
75fb47a376SStephen J. Kiernan veriexec_devhead_t veriexec_dev_head;
76fb47a376SStephen J. Kiernan 
77fb47a376SStephen J. Kiernan /**
78fb47a376SStephen J. Kiernan  * @brief Plain file meta-data storage
79fb47a376SStephen J. Kiernan  *
80fb47a376SStephen J. Kiernan  * This is used for files that are not allowed to be executed, but should
81fb47a376SStephen J. Kiernan  * have fingerprint validation available.
82fb47a376SStephen J. Kiernan  */
83fb47a376SStephen J. Kiernan veriexec_devhead_t veriexec_file_dev_head;
84fb47a376SStephen J. Kiernan 
85fb47a376SStephen J. Kiernan /**
86fb47a376SStephen J. Kiernan  * @internal
87fb47a376SStephen J. Kiernan  * @brief Search the @p head meta-data list for the specified file identifier
88fb47a376SStephen J. Kiernan  *     @p fileid in the file system identified by @p fsid
89fb47a376SStephen J. Kiernan  *
90fb47a376SStephen J. Kiernan  * If meta-data exists for file system identified by @p fsid, it has a
91fb47a376SStephen J. Kiernan  * fingerprint list, and @p found_dev is not @c NULL then store true in the
92fb47a376SStephen J. Kiernan  * location pointed to by @p found_dev
93fb47a376SStephen J. Kiernan  *
94fb47a376SStephen J. Kiernan  * @param head		meta-data list to search
95fb47a376SStephen J. Kiernan  * @param fsid		file system identifier to look for
96fb47a376SStephen J. Kiernan  * @param fileid	file to look for
97fb47a376SStephen J. Kiernan  * @param gen		generation of file
98fb47a376SStephen J. Kiernan  * @param found_dev	indicator that an entry for the file system was found
99fb47a376SStephen J. Kiernan  *
100fb47a376SStephen J. Kiernan  * @return A pointer to the meta-data inforation if meta-data exists for
101fb47a376SStephen J. Kiernan  *     the specified file identifier, otherwise @c NULL
102fb47a376SStephen J. Kiernan  */
103fb47a376SStephen J. Kiernan static struct mac_veriexec_file_info *
get_veriexec_file(struct veriexec_devhead * head,dev_t fsid,long fileid,unsigned long gen,int * found_dev)104fb47a376SStephen J. Kiernan get_veriexec_file(struct veriexec_devhead *head, dev_t fsid, long fileid,
105fb47a376SStephen J. Kiernan     unsigned long gen, int *found_dev)
106fb47a376SStephen J. Kiernan {
107fb47a376SStephen J. Kiernan 	struct veriexec_dev_list *lp;
108fb47a376SStephen J. Kiernan 	struct mac_veriexec_file_info *ip, *tip;
109fb47a376SStephen J. Kiernan 
110fb47a376SStephen J. Kiernan 	ip = NULL;
111fb47a376SStephen J. Kiernan 
112fb47a376SStephen J. Kiernan 	/* Initialize the value found_dev, if non-NULL */
113fb47a376SStephen J. Kiernan 	if (found_dev != NULL)
114fb47a376SStephen J. Kiernan 		*found_dev = 0;
115fb47a376SStephen J. Kiernan 
116593d37bbSStephen J. Kiernan 	VERIEXEC_DEBUG(3, ("searching for file %ju.%lu on device %ju,"
117593d37bbSStephen J. Kiernan 	    " files=%d\n", (uintmax_t)fileid, gen, (uintmax_t)fsid,
118fb47a376SStephen J. Kiernan 	    (head == &veriexec_file_dev_head)));
119fb47a376SStephen J. Kiernan 
120fb47a376SStephen J. Kiernan 	/* Get a lock to access the list */
121fb47a376SStephen J. Kiernan 	mtx_lock(&ve_mutex);
122fb47a376SStephen J. Kiernan 
123fb47a376SStephen J. Kiernan 	/* First, look for the file system */
124fb47a376SStephen J. Kiernan 	for (lp = LIST_FIRST(head); lp != NULL; lp = LIST_NEXT(lp, entries))
125fb47a376SStephen J. Kiernan 		if (lp->fsid == fsid)
126fb47a376SStephen J. Kiernan 			break;
127fb47a376SStephen J. Kiernan 
128fb47a376SStephen J. Kiernan 	/* We found the file system in the list */
129fb47a376SStephen J. Kiernan 	if (lp != NULL) {
130593d37bbSStephen J. Kiernan 		VERIEXEC_DEBUG(3, ("found matching dev number %ju\n",
131593d37bbSStephen J. Kiernan 		    (uintmax_t)lp->fsid));
132fb47a376SStephen J. Kiernan 
133fb47a376SStephen J. Kiernan 		/* If found_dev is non-NULL, store true there */
134fb47a376SStephen J. Kiernan 		if (found_dev != NULL)
135fb47a376SStephen J. Kiernan 			*found_dev = 1;
136fb47a376SStephen J. Kiernan 
137fb47a376SStephen J. Kiernan 		/* Next, look for the meta-data information for the file */
138fb47a376SStephen J. Kiernan 		LIST_FOREACH_SAFE(ip, &(lp->file_head), entries, tip) {
139fb47a376SStephen J. Kiernan 			if (ip->fileid == fileid) {
140fb47a376SStephen J. Kiernan 				if (ip->gen == gen)
141fb47a376SStephen J. Kiernan 					break;
142fb47a376SStephen J. Kiernan 				/* we need to garbage collect */
143fb47a376SStephen J. Kiernan 				LIST_REMOVE(ip, entries);
14494288674SStephen J. Kiernan 				if (ip->label)
14594288674SStephen J. Kiernan 					free(ip->label, M_VERIEXEC);
146fb47a376SStephen J. Kiernan 				free(ip, M_VERIEXEC);
147fb47a376SStephen J. Kiernan 			}
148fb47a376SStephen J. Kiernan 		}
149fb47a376SStephen J. Kiernan 	}
150fb47a376SStephen J. Kiernan 
151fb47a376SStephen J. Kiernan 	/* Release the lock we obtained earlier */
152fb47a376SStephen J. Kiernan 	mtx_unlock(&ve_mutex);
153fb47a376SStephen J. Kiernan 
154fb47a376SStephen J. Kiernan 	/* Return the meta-data information we found, if anything */
155fb47a376SStephen J. Kiernan 	return (ip);
156fb47a376SStephen J. Kiernan }
157fb47a376SStephen J. Kiernan 
158fb47a376SStephen J. Kiernan /**
159fb47a376SStephen J. Kiernan  * @internal
160fb47a376SStephen J. Kiernan  * @brief Display the fingerprint for each entry in the device list
161fb47a376SStephen J. Kiernan  *
162fb47a376SStephen J. Kiernan  * @param sbp		sbuf to write output to
163fb47a376SStephen J. Kiernan  * @param lp		pointer to device list
164fb47a376SStephen J. Kiernan  */
165fb47a376SStephen J. Kiernan static void
mac_veriexec_print_db_dev_list(struct sbuf * sbp,struct veriexec_dev_list * lp)166fb47a376SStephen J. Kiernan mac_veriexec_print_db_dev_list(struct sbuf *sbp, struct veriexec_dev_list *lp)
167fb47a376SStephen J. Kiernan {
168fb47a376SStephen J. Kiernan 	struct mac_veriexec_file_info *ip;
169fb47a376SStephen J. Kiernan 
170fb47a376SStephen J. Kiernan #define FPB(i) (ip->fingerprint[i])
171fb47a376SStephen J. Kiernan 	for (ip = LIST_FIRST(&(lp->file_head)); ip != NULL;
172fb47a376SStephen J. Kiernan 	    ip = LIST_NEXT(ip, entries))
173fb47a376SStephen J. Kiernan 		sbuf_printf(sbp, "  %ld: %u %ld [%02x %02x %02x %02x %02x "
174fb47a376SStephen J. Kiernan 		    "%02x %02x %02x...]\n", ip->fileid, ip->flags, ip->gen,
175fb47a376SStephen J. Kiernan 		    FPB(0), FPB(1), FPB(2), FPB(3), FPB(4), FPB(5), FPB(6),
176fb47a376SStephen J. Kiernan 		    FPB(7));
177fb47a376SStephen J. Kiernan }
178fb47a376SStephen J. Kiernan 
179fb47a376SStephen J. Kiernan /**
180fb47a376SStephen J. Kiernan  * @internal
181fb47a376SStephen J. Kiernan  * @brief Display the device list
182fb47a376SStephen J. Kiernan  *
183fb47a376SStephen J. Kiernan  * @param sbp		sbuf to write output to
184fb47a376SStephen J. Kiernan  * @param head		pointer to head of the device list
185fb47a376SStephen J. Kiernan  */
186fb47a376SStephen J. Kiernan static void
mac_veriexec_print_db_head(struct sbuf * sbp,struct veriexec_devhead * head)187fb47a376SStephen J. Kiernan mac_veriexec_print_db_head(struct sbuf *sbp, struct veriexec_devhead *head)
188fb47a376SStephen J. Kiernan {
189fb47a376SStephen J. Kiernan 	struct veriexec_dev_list *lp;
190fb47a376SStephen J. Kiernan 
191fb47a376SStephen J. Kiernan 	for (lp = LIST_FIRST(head); lp != NULL; lp = LIST_NEXT(lp, entries)) {
192593d37bbSStephen J. Kiernan 		sbuf_printf(sbp, " FS id: %ju\n", (uintmax_t)lp->fsid);
193fb47a376SStephen J. Kiernan 		mac_veriexec_print_db_dev_list(sbp, lp);
194fb47a376SStephen J. Kiernan 	}
195fb47a376SStephen J. Kiernan 
196fb47a376SStephen J. Kiernan }
197fb47a376SStephen J. Kiernan 
198fb47a376SStephen J. Kiernan /**
199fb47a376SStephen J. Kiernan  * @internal
200fb47a376SStephen J. Kiernan  * @brief Generate human-readable output for the current fingerprint database
201fb47a376SStephen J. Kiernan  *
202fb47a376SStephen J. Kiernan  * @param sbp	sbuf to write output to
203fb47a376SStephen J. Kiernan  */
204fb47a376SStephen J. Kiernan void
mac_veriexec_metadata_print_db(struct sbuf * sbp)205fb47a376SStephen J. Kiernan mac_veriexec_metadata_print_db(struct sbuf *sbp)
206fb47a376SStephen J. Kiernan {
207fb47a376SStephen J. Kiernan 	struct {
208fb47a376SStephen J. Kiernan 		struct veriexec_devhead *h;
209fb47a376SStephen J. Kiernan 		const char *name;
210fb47a376SStephen J. Kiernan 	} fpdbs[] = {
211fb47a376SStephen J. Kiernan 		{ &veriexec_file_dev_head, "regular files" },
212fb47a376SStephen J. Kiernan 		{ &veriexec_dev_head, "executable files" },
213fb47a376SStephen J. Kiernan 	};
214fb47a376SStephen J. Kiernan 	int i;
215fb47a376SStephen J. Kiernan 
216fb47a376SStephen J. Kiernan 	mtx_lock(&ve_mutex);
217fb47a376SStephen J. Kiernan 	for (i = 0; i < sizeof(fpdbs)/sizeof(fpdbs[0]); i++) {
218fb47a376SStephen J. Kiernan 		sbuf_printf(sbp, "%s fingerprint db:\n", fpdbs[i].name);
219fb47a376SStephen J. Kiernan 		mac_veriexec_print_db_head(sbp, fpdbs[i].h);
220fb47a376SStephen J. Kiernan 	}
221fb47a376SStephen J. Kiernan 	mtx_unlock(&ve_mutex);
222fb47a376SStephen J. Kiernan }
223fb47a376SStephen J. Kiernan /**
224fb47a376SStephen J. Kiernan  * @brief Determine if the meta-data store has an entry for the specified file.
225fb47a376SStephen J. Kiernan  *
226fb47a376SStephen J. Kiernan  * @param fsid		file system identifier to look for
227fb47a376SStephen J. Kiernan  * @param fileid	file to look for
228fb47a376SStephen J. Kiernan  * @param gen		generation of file
229fb47a376SStephen J. Kiernan  *
230fb47a376SStephen J. Kiernan  * @return 1 if there is an entry in the meta-data store, 0 otherwise.
231fb47a376SStephen J. Kiernan  */
232fb47a376SStephen J. Kiernan int
mac_veriexec_metadata_has_file(dev_t fsid,long fileid,unsigned long gen)233fb47a376SStephen J. Kiernan mac_veriexec_metadata_has_file(dev_t fsid, long fileid, unsigned long gen)
234fb47a376SStephen J. Kiernan {
235fb47a376SStephen J. Kiernan 
23694288674SStephen J. Kiernan 	return (mac_veriexec_metadata_get_file_info(fsid, fileid, gen, NULL,
2378512d82eSSteve Kiernan 	    NULL, VERIEXEC_FILES_FIRST) == 0);
238fb47a376SStephen J. Kiernan }
239fb47a376SStephen J. Kiernan 
240fb47a376SStephen J. Kiernan /**
241fb47a376SStephen J. Kiernan  * @brief Search the list of devices looking for the one given, in order to
242fb47a376SStephen J. Kiernan  *     release the resources used by it.
243fb47a376SStephen J. Kiernan  *
244fb47a376SStephen J. Kiernan  * If found, free all file entries for it, and remove it from the list.
245fb47a376SStephen J. Kiernan  *
246fb47a376SStephen J. Kiernan  * @note Called with @a ve_mutex held
247fb47a376SStephen J. Kiernan  *
248fb47a376SStephen J. Kiernan  * @param fsid		file system identifier to look for
249fb47a376SStephen J. Kiernan  * @param head		meta-data list to search
250fb47a376SStephen J. Kiernan  *
251fb47a376SStephen J. Kiernan  * @return 0 if the device entry was freed, otherwise an error code
252fb47a376SStephen J. Kiernan  */
253fb47a376SStephen J. Kiernan static int
free_veriexec_dev(dev_t fsid,struct veriexec_devhead * head)254fb47a376SStephen J. Kiernan free_veriexec_dev(dev_t fsid, struct veriexec_devhead *head)
255fb47a376SStephen J. Kiernan {
256fb47a376SStephen J. Kiernan 	struct veriexec_dev_list *lp;
257fb47a376SStephen J. Kiernan 	struct mac_veriexec_file_info *ip, *nip;
258fb47a376SStephen J. Kiernan 
259fb47a376SStephen J. Kiernan 	/* Look for the file system */
260fb47a376SStephen J. Kiernan 	for (lp = LIST_FIRST(head); lp != NULL;
261fb47a376SStephen J. Kiernan 	     lp = LIST_NEXT(lp, entries))
262fb47a376SStephen J. Kiernan 		if (lp->fsid == fsid) break;
263fb47a376SStephen J. Kiernan 
264fb47a376SStephen J. Kiernan 	/* If lp is NULL, we did not find it */
265fb47a376SStephen J. Kiernan 	if (lp == NULL)
266fb47a376SStephen J. Kiernan 		return ENOENT;
267fb47a376SStephen J. Kiernan 
268fb47a376SStephen J. Kiernan 	/* Unhook lp, before we free it and its content */
269fb47a376SStephen J. Kiernan 	LIST_REMOVE(lp, entries);
270fb47a376SStephen J. Kiernan 
271fb47a376SStephen J. Kiernan 	/* Release the lock */
272fb47a376SStephen J. Kiernan 	mtx_unlock(&ve_mutex);
273fb47a376SStephen J. Kiernan 
274fb47a376SStephen J. Kiernan 	/* Free the file entries in the list */
275fb47a376SStephen J. Kiernan 	for (ip = LIST_FIRST(&(lp->file_head)); ip != NULL; ip = nip) {
276fb47a376SStephen J. Kiernan 		nip = LIST_NEXT(ip, entries);
277fb47a376SStephen J. Kiernan 		LIST_REMOVE(ip, entries);
27894288674SStephen J. Kiernan 		if (ip->label)
27994288674SStephen J. Kiernan 			free(ip->label, M_VERIEXEC);
280fb47a376SStephen J. Kiernan 		free(ip, M_VERIEXEC);
281fb47a376SStephen J. Kiernan 	}
282fb47a376SStephen J. Kiernan 
283fb47a376SStephen J. Kiernan 	/* Free the meta-data entry for the device */
284fb47a376SStephen J. Kiernan 	free(lp, M_VERIEXEC);
285fb47a376SStephen J. Kiernan 
286fb47a376SStephen J. Kiernan 	/* Re-acquire the lock */
287fb47a376SStephen J. Kiernan 	mtx_lock(&ve_mutex);
288fb47a376SStephen J. Kiernan 	return 0;
289fb47a376SStephen J. Kiernan }
290fb47a376SStephen J. Kiernan 
291fb47a376SStephen J. Kiernan /**
292fb47a376SStephen J. Kiernan  * @brief Search the list of devices looking for the one given.
293fb47a376SStephen J. Kiernan  *
294fb47a376SStephen J. Kiernan  * If it is not in the list then add it.
295fb47a376SStephen J. Kiernan  *
296fb47a376SStephen J. Kiernan  * @note Called with @a ve_mutex held
297fb47a376SStephen J. Kiernan  *
298fb47a376SStephen J. Kiernan  * @param fsid		file system identifier to look for
299fb47a376SStephen J. Kiernan  * @param head		meta-data list to search
300fb47a376SStephen J. Kiernan  *
301fb47a376SStephen J. Kiernan  * @return A pointer to the meta-data entry for the device, if found or added,
302fb47a376SStephen J. Kiernan  *     otherwise @c NULL
303fb47a376SStephen J. Kiernan  */
304fb47a376SStephen J. Kiernan static struct veriexec_dev_list *
find_veriexec_dev(dev_t fsid,struct veriexec_devhead * head)305fb47a376SStephen J. Kiernan find_veriexec_dev(dev_t fsid, struct veriexec_devhead *head)
306fb47a376SStephen J. Kiernan {
307fb47a376SStephen J. Kiernan 	struct veriexec_dev_list *lp;
308fb47a376SStephen J. Kiernan 	struct veriexec_dev_list *np = NULL;
309fb47a376SStephen J. Kiernan 
310fb47a376SStephen J. Kiernan search:
311fb47a376SStephen J. Kiernan 	/* Look for the file system */
312fb47a376SStephen J. Kiernan 	for (lp = LIST_FIRST(head); lp != NULL;
313fb47a376SStephen J. Kiernan 	     lp = LIST_NEXT(lp, entries))
314fb47a376SStephen J. Kiernan 		if (lp->fsid == fsid) break;
315fb47a376SStephen J. Kiernan 
316fb47a376SStephen J. Kiernan 	if (lp == NULL) {
317fb47a376SStephen J. Kiernan 		if (np == NULL) {
318fb47a376SStephen J. Kiernan 			/*
319fb47a376SStephen J. Kiernan 			 * If pointer is null then entry not there,
320fb47a376SStephen J. Kiernan 			 * add a new one, first try to malloc while
321fb47a376SStephen J. Kiernan 			 * we hold mutex - should work most of the time.
322fb47a376SStephen J. Kiernan 			 */
323fb47a376SStephen J. Kiernan 			np = malloc(sizeof(struct veriexec_dev_list),
324fb47a376SStephen J. Kiernan 			    M_VERIEXEC, M_NOWAIT);
325fb47a376SStephen J. Kiernan 			if (np == NULL) {
326fb47a376SStephen J. Kiernan 				/*
327fb47a376SStephen J. Kiernan 				 * So much for that plan, dop the mutex
328fb47a376SStephen J. Kiernan 				 * and repeat...
329fb47a376SStephen J. Kiernan 				 */
330fb47a376SStephen J. Kiernan 				mtx_unlock(&ve_mutex);
331fb47a376SStephen J. Kiernan 				np = malloc(sizeof(struct veriexec_dev_list),
332fb47a376SStephen J. Kiernan 				    M_VERIEXEC, M_WAITOK);
333fb47a376SStephen J. Kiernan 				mtx_lock(&ve_mutex);
334fb47a376SStephen J. Kiernan 				/*
3351920133dSGordon Bergling 				 * Repeat the search, in case someone
336fb47a376SStephen J. Kiernan 				 * added this while we slept.
337fb47a376SStephen J. Kiernan 				 */
338fb47a376SStephen J. Kiernan 				goto search;
339fb47a376SStephen J. Kiernan 			}
340fb47a376SStephen J. Kiernan 		}
341fb47a376SStephen J. Kiernan 		if (np) {
342fb47a376SStephen J. Kiernan 			/* Add the entry to the list */
343fb47a376SStephen J. Kiernan 			lp = np;
344fb47a376SStephen J. Kiernan 			LIST_INIT(&(lp->file_head));
345fb47a376SStephen J. Kiernan 			lp->fsid = fsid;
346fb47a376SStephen J. Kiernan 			LIST_INSERT_HEAD(head, lp, entries);
347fb47a376SStephen J. Kiernan 		}
348fb47a376SStephen J. Kiernan 	} else if (np) {
349fb47a376SStephen J. Kiernan 		/*
350fb47a376SStephen J. Kiernan 		 * Someone else did it while we slept.
351fb47a376SStephen J. Kiernan 		 */
352fb47a376SStephen J. Kiernan 		mtx_unlock(&ve_mutex);
353fb47a376SStephen J. Kiernan 		free(np, M_VERIEXEC);
354fb47a376SStephen J. Kiernan 		mtx_lock(&ve_mutex);
355fb47a376SStephen J. Kiernan 	}
356fb47a376SStephen J. Kiernan 
357fb47a376SStephen J. Kiernan 	return (lp);
358fb47a376SStephen J. Kiernan }
359fb47a376SStephen J. Kiernan 
360fb47a376SStephen J. Kiernan /**
36194288674SStephen J. Kiernan  * @internal
36294288674SStephen J. Kiernan  * @brief Allocate and initialize label record with the provided data.
36394288674SStephen J. Kiernan  *
36494288674SStephen J. Kiernan  * @param labelp	Location to store the initialized label
36594288674SStephen J. Kiernan  * @param src		Pointer to label string to copy
36694288674SStephen J. Kiernan  * @param srclen	Length of label string to copy
36794288674SStephen J. Kiernan  *
36894288674SStephen J. Kiernan  * @return Length of resulting label
36994288674SStephen J. Kiernan  *
37094288674SStephen J. Kiernan  * @note Called with ve_mutex locked.
37194288674SStephen J. Kiernan  */
37294288674SStephen J. Kiernan static size_t
mac_veriexec_init_label(char ** labelp,size_t labellen,char * src,size_t srclen)37394288674SStephen J. Kiernan mac_veriexec_init_label(char **labelp, size_t labellen, char *src,
37494288674SStephen J. Kiernan     size_t srclen)
37594288674SStephen J. Kiernan {
37694288674SStephen J. Kiernan 	char *label;
37794288674SStephen J. Kiernan 
37894288674SStephen J. Kiernan 	label = *labelp;
37994288674SStephen J. Kiernan 	if (labellen < srclen) {
38094288674SStephen J. Kiernan 		mtx_unlock(&ve_mutex);
38194288674SStephen J. Kiernan 		if (label != NULL)
38294288674SStephen J. Kiernan 			free(label, M_VERIEXEC);
38394288674SStephen J. Kiernan 		label = malloc(srclen, M_VERIEXEC, M_WAITOK);
38494288674SStephen J. Kiernan 		mtx_lock(&ve_mutex);
38594288674SStephen J. Kiernan 		labellen = srclen;
38694288674SStephen J. Kiernan 		*labelp = label;
38794288674SStephen J. Kiernan 	}
38894288674SStephen J. Kiernan 	memcpy(label, src, srclen);
38994288674SStephen J. Kiernan 	return labellen;
39094288674SStephen J. Kiernan }
39194288674SStephen J. Kiernan 
39294288674SStephen J. Kiernan /**
393fb47a376SStephen J. Kiernan  * @brief When a device is unmounted, we want to toss the signatures recorded
394fb47a376SStephen J. Kiernan  *     against it.
395fb47a376SStephen J. Kiernan  *
396fb47a376SStephen J. Kiernan  * We are being called from unmount() with the root vnode just before it is
397fb47a376SStephen J. Kiernan  * freed.
398fb47a376SStephen J. Kiernan  *
399fb47a376SStephen J. Kiernan  * @param fsid		file system identifier to look for
400fb47a376SStephen J. Kiernan  * @param td		calling thread
401fb47a376SStephen J. Kiernan  *
402fb47a376SStephen J. Kiernan  * @return 0 on success, otherwise an error code.
403fb47a376SStephen J. Kiernan  */
404fb47a376SStephen J. Kiernan int
mac_veriexec_metadata_unmounted(dev_t fsid,struct thread * td)405fb47a376SStephen J. Kiernan mac_veriexec_metadata_unmounted(dev_t fsid, struct thread *td)
406fb47a376SStephen J. Kiernan {
407fb47a376SStephen J. Kiernan     int error;
408fb47a376SStephen J. Kiernan 
409fb47a376SStephen J. Kiernan     /*
410fb47a376SStephen J. Kiernan      * The device can have entries on both lists.
411fb47a376SStephen J. Kiernan      */
412fb47a376SStephen J. Kiernan     mtx_lock(&ve_mutex);
413fb47a376SStephen J. Kiernan     error = free_veriexec_dev(fsid, &veriexec_dev_head);
414fb47a376SStephen J. Kiernan     if (error && error != ENOENT) {
415fb47a376SStephen J. Kiernan 	    mtx_unlock(&ve_mutex);
416fb47a376SStephen J. Kiernan 	    return error;
417fb47a376SStephen J. Kiernan     }
418fb47a376SStephen J. Kiernan     error = free_veriexec_dev(fsid, &veriexec_file_dev_head);
419fb47a376SStephen J. Kiernan     mtx_unlock(&ve_mutex);
420fb47a376SStephen J. Kiernan     if (error && error != ENOENT) {
421fb47a376SStephen J. Kiernan 	    return error;
422fb47a376SStephen J. Kiernan     }
423fb47a376SStephen J. Kiernan     return 0;
424fb47a376SStephen J. Kiernan }
425fb47a376SStephen J. Kiernan 
426fb47a376SStephen J. Kiernan /**
427fb47a376SStephen J. Kiernan  * @brief Return the flags assigned to the file identified by file system
428fb47a376SStephen J. Kiernan  * 	  identifier @p fsid and file identifier @p fileid.
429fb47a376SStephen J. Kiernan  *
430fb47a376SStephen J. Kiernan  * @param fsid		file system identifier
431fb47a376SStephen J. Kiernan  * @param fileid	file identifier within the file system
432fb47a376SStephen J. Kiernan  * @param gen		generation of file
433fb47a376SStephen J. Kiernan  * @param flags		pointer to location to store the flags
434fb47a376SStephen J. Kiernan  * @param check_files	if 1, check the files list first, otherwise check the
435fb47a376SStephen J. Kiernan  * 			exectuables list first
436fb47a376SStephen J. Kiernan  *
437fb47a376SStephen J. Kiernan  * @return 0 on success, otherwise an error code.
438fb47a376SStephen J. Kiernan  */
439fb47a376SStephen J. Kiernan int
mac_veriexec_metadata_get_file_flags(dev_t fsid,long fileid,unsigned long gen,int * flags,int check_files)440fb47a376SStephen J. Kiernan mac_veriexec_metadata_get_file_flags(dev_t fsid, long fileid, unsigned long gen,
441fb47a376SStephen J. Kiernan     int *flags, int check_files)
442fb47a376SStephen J. Kiernan {
443fb47a376SStephen J. Kiernan 	struct mac_veriexec_file_info *ip;
4448512d82eSSteve Kiernan 	int error;
445fb47a376SStephen J. Kiernan 
4468512d82eSSteve Kiernan 	error = mac_veriexec_metadata_get_file_info(fsid, fileid, gen, NULL,
4478512d82eSSteve Kiernan 	    &ip, check_files);
4488512d82eSSteve Kiernan 	if (error != 0)
4498512d82eSSteve Kiernan 		return (error);
450fb47a376SStephen J. Kiernan 
451fb47a376SStephen J. Kiernan 	*flags = ip->flags;
452fb47a376SStephen J. Kiernan 	return (0);
453fb47a376SStephen J. Kiernan }
454fb47a376SStephen J. Kiernan 
455fb47a376SStephen J. Kiernan /**
456fb47a376SStephen J. Kiernan  * @brief get the files for the specified process
457fb47a376SStephen J. Kiernan  *
458fb47a376SStephen J. Kiernan  * @param cred		credentials to use
459fb47a376SStephen J. Kiernan  * @param p		process to get the flags for
460fb47a376SStephen J. Kiernan  * @param flags		where to store the flags
461fb47a376SStephen J. Kiernan  * @param check_files	if 1, check the files list first, otherwise check the
462fb47a376SStephen J. Kiernan  * 			exectuables list first
463fb47a376SStephen J. Kiernan  *
464fb47a376SStephen J. Kiernan  * @return 0 if the process has an entry in the meta-data store, otherwise an
465fb47a376SStephen J. Kiernan  *     error code
466fb47a376SStephen J. Kiernan  */
467fb47a376SStephen J. Kiernan int
mac_veriexec_metadata_get_executable_flags(struct ucred * cred,struct proc * p,int * flags,int check_files)468fb47a376SStephen J. Kiernan mac_veriexec_metadata_get_executable_flags(struct ucred *cred, struct proc *p,
469fb47a376SStephen J. Kiernan     int *flags, int check_files)
470fb47a376SStephen J. Kiernan {
471fb47a376SStephen J. Kiernan 	struct vnode *proc_vn;
472fb47a376SStephen J. Kiernan 	struct vattr vap;
473fb47a376SStephen J. Kiernan 	int error;
474fb47a376SStephen J. Kiernan 
475fb47a376SStephen J. Kiernan 	/* Get the text vnode for the process */
476fb47a376SStephen J. Kiernan 	proc_vn = p->p_textvp;
477fb47a376SStephen J. Kiernan 	if (proc_vn == NULL)
478fb47a376SStephen J. Kiernan 		return EINVAL;
479fb47a376SStephen J. Kiernan 
480fb47a376SStephen J. Kiernan 	/* Get vnode attributes */
481fb47a376SStephen J. Kiernan 	error = VOP_GETATTR(proc_vn, &vap, cred);
482fb47a376SStephen J. Kiernan 	if (error)
483fb47a376SStephen J. Kiernan 		return error;
484fb47a376SStephen J. Kiernan 
485fb47a376SStephen J. Kiernan 	error = mac_veriexec_metadata_get_file_flags(vap.va_fsid,
486fb47a376SStephen J. Kiernan 	    vap.va_fileid, vap.va_gen, flags,
487fb47a376SStephen J. Kiernan 	    (check_files == VERIEXEC_FILES_FIRST));
488fb47a376SStephen J. Kiernan 
489fb47a376SStephen J. Kiernan 	return (error);
490fb47a376SStephen J. Kiernan }
491fb47a376SStephen J. Kiernan 
492fb47a376SStephen J. Kiernan /**
493fb47a376SStephen J. Kiernan  * @brief Ensure the fingerprint status for the vnode @p vp is assigned to its
494fb47a376SStephen J. Kiernan  *     MAC label.
495fb47a376SStephen J. Kiernan  *
496fb47a376SStephen J. Kiernan  * @param vp		vnode to check
497fb47a376SStephen J. Kiernan  * @param vap		vnode attributes to use
498fb47a376SStephen J. Kiernan  * @param td		calling thread
499fb47a376SStephen J. Kiernan  * @param check_files	if 1, check the files list first, otherwise check the
500fb47a376SStephen J. Kiernan  * 			exectuables list first
501fb47a376SStephen J. Kiernan  *
502fb47a376SStephen J. Kiernan  * @return 0 on success, otherwise an error code.
503fb47a376SStephen J. Kiernan  */
504fb47a376SStephen J. Kiernan int
mac_veriexec_metadata_fetch_fingerprint_status(struct vnode * vp,struct vattr * vap,struct thread * td,int check_files)505fb47a376SStephen J. Kiernan mac_veriexec_metadata_fetch_fingerprint_status(struct vnode *vp,
506fb47a376SStephen J. Kiernan     struct vattr *vap, struct thread *td, int check_files)
507fb47a376SStephen J. Kiernan {
508fb47a376SStephen J. Kiernan 	unsigned char digest[MAXFINGERPRINTLEN];
509fb47a376SStephen J. Kiernan 	struct mac_veriexec_file_info *ip;
510fb47a376SStephen J. Kiernan 	int error, found_dev;
511fb47a376SStephen J. Kiernan 	fingerprint_status_t status;
512fb47a376SStephen J. Kiernan 
513fb47a376SStephen J. Kiernan 	error = 0;
514fb47a376SStephen J. Kiernan 	ip = NULL;
515fb47a376SStephen J. Kiernan 
516fb47a376SStephen J. Kiernan 	status = mac_veriexec_get_fingerprint_status(vp);
517fb47a376SStephen J. Kiernan 	if (status == FINGERPRINT_INVALID || status == FINGERPRINT_NODEV) {
518fb47a376SStephen J. Kiernan 		found_dev = 0;
5197bb4d130SStephen J. Kiernan 		if (mac_veriexec_metadata_get_file_info(vap->va_fsid,
5207bb4d130SStephen J. Kiernan 		    vap->va_fileid, vap->va_gen, &found_dev, &ip,
5217bb4d130SStephen J. Kiernan 		    check_files) != 0) {
522fb47a376SStephen J. Kiernan 			status = (found_dev) ? FINGERPRINT_NOENTRY :
523fb47a376SStephen J. Kiernan 			    FINGERPRINT_NODEV;
524fb47a376SStephen J. Kiernan 			VERIEXEC_DEBUG(3,
525593d37bbSStephen J. Kiernan 			    ("fingerprint status is %d for dev %ju, file "
526593d37bbSStephen J. Kiernan 			    "%ju.%lu\n", status, (uintmax_t)vap->va_fsid,
527593d37bbSStephen J. Kiernan 			    (uintmax_t)vap->va_fileid, vap->va_gen));
528fb47a376SStephen J. Kiernan 		} else {
529fb47a376SStephen J. Kiernan 			/*
530fb47a376SStephen J. Kiernan 			 * evaluate and compare fingerprint
531fb47a376SStephen J. Kiernan 			 */
532fb47a376SStephen J. Kiernan 			error = mac_veriexec_fingerprint_check_vnode(vp, ip,
533fb47a376SStephen J. Kiernan 			    td, vap->va_size, digest);
534fb47a376SStephen J. Kiernan 			switch (error) {
535fb47a376SStephen J. Kiernan 			case 0:
536fb47a376SStephen J. Kiernan 				/* Process flags */
537fb47a376SStephen J. Kiernan 				if ((ip->flags & VERIEXEC_INDIRECT))
538fb47a376SStephen J. Kiernan 					status = FINGERPRINT_INDIRECT;
539fb47a376SStephen J. Kiernan 				else if ((ip->flags & VERIEXEC_FILE))
540fb47a376SStephen J. Kiernan 					status = FINGERPRINT_FILE;
541fb47a376SStephen J. Kiernan 				else
542fb47a376SStephen J. Kiernan 					status = FINGERPRINT_VALID;
543fb47a376SStephen J. Kiernan 				VERIEXEC_DEBUG(2,
544593d37bbSStephen J. Kiernan 				    ("%sfingerprint matches for dev %ju, file "
545593d37bbSStephen J. Kiernan 				    "%ju.%lu\n",
546fb47a376SStephen J. Kiernan 				     (status == FINGERPRINT_INDIRECT) ?
547fb47a376SStephen J. Kiernan 				     "indirect " :
548fb47a376SStephen J. Kiernan 				     (status == FINGERPRINT_FILE) ?
549593d37bbSStephen J. Kiernan 				     "file " : "", (uintmax_t)vap->va_fsid,
550593d37bbSStephen J. Kiernan 				     (uintmax_t)vap->va_fileid, vap->va_gen));
551fb47a376SStephen J. Kiernan 				break;
552fb47a376SStephen J. Kiernan 
553fb47a376SStephen J. Kiernan 			case EAUTH:
554d195f39dSSteve Kiernan #ifdef MAC_VERIEXEC_DEBUG
555fb47a376SStephen J. Kiernan 				{
556fb47a376SStephen J. Kiernan 					char have[MAXFINGERPRINTLEN * 2 + 1];
557fb47a376SStephen J. Kiernan 					char want[MAXFINGERPRINTLEN * 2 + 1];
558fb47a376SStephen J. Kiernan 					int i, len;
559fb47a376SStephen J. Kiernan 
560fb47a376SStephen J. Kiernan 					len = ip->ops->digest_len;
561fb47a376SStephen J. Kiernan 					for (i = 0; i < len; i++) {
562fb47a376SStephen J. Kiernan 						sprintf(&want[i * 2], "%02x",
563fb47a376SStephen J. Kiernan 						    ip->fingerprint[i]);
564fb47a376SStephen J. Kiernan 						sprintf(&have[i * 2], "%02x",
565fb47a376SStephen J. Kiernan 						    digest[i]);
566fb47a376SStephen J. Kiernan 					}
567fb47a376SStephen J. Kiernan 					log(LOG_ERR, MAC_VERIEXEC_FULLNAME
568593d37bbSStephen J. Kiernan 					    ": fingerprint for dev %ju, file "
569593d37bbSStephen J. Kiernan 					    "%ju.%lu %s != %s\n",
570593d37bbSStephen J. Kiernan 					    (uintmax_t)vap->va_fsid,
571593d37bbSStephen J. Kiernan 					    (uintmax_t)vap->va_fileid,
572593d37bbSStephen J. Kiernan 					    vap->va_gen,
573fb47a376SStephen J. Kiernan 					    have, want);
574fb47a376SStephen J. Kiernan 				}
575fb47a376SStephen J. Kiernan #endif
576fb47a376SStephen J. Kiernan 				status = FINGERPRINT_NOMATCH;
577fb47a376SStephen J. Kiernan 				break;
578fb47a376SStephen J. Kiernan 			default:
579fb47a376SStephen J. Kiernan 				VERIEXEC_DEBUG(2,
580fb47a376SStephen J. Kiernan 				    ("fingerprint status error %d\n", error));
581fb47a376SStephen J. Kiernan 				break;
582fb47a376SStephen J. Kiernan 			}
583fb47a376SStephen J. Kiernan 		}
584fb47a376SStephen J. Kiernan 		mac_veriexec_set_fingerprint_status(vp, status);
585fb47a376SStephen J. Kiernan 	}
586fb47a376SStephen J. Kiernan 	return (error);
587fb47a376SStephen J. Kiernan }
588fb47a376SStephen J. Kiernan 
589fb47a376SStephen J. Kiernan /**
59048ffacbcSSteve Kiernan  * Return label if we have one
59148ffacbcSSteve Kiernan  *
59248ffacbcSSteve Kiernan  * @param fsid         file system identifier to look for
59348ffacbcSSteve Kiernan  * @param fileid       file to look for
59448ffacbcSSteve Kiernan  * @param gen          generation of file
59548ffacbcSSteve Kiernan  * @param check_files  look at non-executable files?
59648ffacbcSSteve Kiernan  *
59748ffacbcSSteve Kiernan  * @return A pointer to the label or @c NULL
59848ffacbcSSteve Kiernan  */
59948ffacbcSSteve Kiernan const char *
mac_veriexec_metadata_get_file_label(dev_t fsid,long fileid,unsigned long gen,int check_files)60048ffacbcSSteve Kiernan mac_veriexec_metadata_get_file_label(dev_t fsid, long fileid,
60148ffacbcSSteve Kiernan     unsigned long gen, int check_files)
60248ffacbcSSteve Kiernan {
60348ffacbcSSteve Kiernan 	struct mac_veriexec_file_info *ip;
60448ffacbcSSteve Kiernan 	int error;
60548ffacbcSSteve Kiernan 
60648ffacbcSSteve Kiernan 	error = mac_veriexec_metadata_get_file_info(fsid, fileid, gen, NULL,
60748ffacbcSSteve Kiernan 	    &ip, check_files);
60848ffacbcSSteve Kiernan 	if (error)
60948ffacbcSSteve Kiernan 		return (NULL);
61048ffacbcSSteve Kiernan 
61148ffacbcSSteve Kiernan 	return ((ip->flags & VERIEXEC_LABEL) != 0 ? ip->label : NULL);
61248ffacbcSSteve Kiernan }
61348ffacbcSSteve Kiernan 
61448ffacbcSSteve Kiernan /**
615fb47a376SStephen J. Kiernan  * Add a file and its fingerprint to the list of files attached
616fb47a376SStephen J. Kiernan  * to the device @p fsid.
617fb47a376SStephen J. Kiernan  *
618fb47a376SStephen J. Kiernan  * Only add the entry if it is not already on the list.
619fb47a376SStephen J. Kiernan  *
620fb47a376SStephen J. Kiernan  * @note Called with @a ve_mutex held
621fb47a376SStephen J. Kiernan  *
622fb47a376SStephen J. Kiernan  * @param file_dev	if 1, the entry should be added on the file list,
623fb47a376SStephen J. Kiernan  * 			otherwise it should be added on the executable list
624fb47a376SStephen J. Kiernan  * @param fsid		file system identifier of device
625fb47a376SStephen J. Kiernan  * @param fileid	file to add
626fb47a376SStephen J. Kiernan  * @param gen		generation of file
627fb47a376SStephen J. Kiernan  * @param fingerprint	fingerprint to add to the store
628fb47a376SStephen J. Kiernan  * @param flags		flags to set in the store
629fb47a376SStephen J. Kiernan  * @param fp_type	digest type
630fb47a376SStephen J. Kiernan  * @param override	if 1, override any values already stored
631fb47a376SStephen J. Kiernan  *
632fb47a376SStephen J. Kiernan  * @return 0 on success, otherwise an error code.
633fb47a376SStephen J. Kiernan  */
634fb47a376SStephen J. Kiernan int
mac_veriexec_metadata_add_file(int file_dev,dev_t fsid,long fileid,unsigned long gen,unsigned char fingerprint[MAXFINGERPRINTLEN],char * label,size_t labellen,int flags,const char * fp_type,int override)635fb47a376SStephen J. Kiernan mac_veriexec_metadata_add_file(int file_dev, dev_t fsid, long fileid,
636fb47a376SStephen J. Kiernan     unsigned long gen, unsigned char fingerprint[MAXFINGERPRINTLEN],
63794288674SStephen J. Kiernan     char *label, size_t labellen, int flags, const char *fp_type, int override)
638fb47a376SStephen J. Kiernan {
639fb47a376SStephen J. Kiernan 	struct mac_veriexec_fpops *fpops;
640fb47a376SStephen J. Kiernan 	struct veriexec_dev_list *lp;
641fb47a376SStephen J. Kiernan 	struct veriexec_devhead *head;
642fb47a376SStephen J. Kiernan 	struct mac_veriexec_file_info *ip;
643fb47a376SStephen J. Kiernan 	struct mac_veriexec_file_info *np = NULL;
644fb47a376SStephen J. Kiernan 
64594288674SStephen J. Kiernan 	/* Label and labellen must be set if VERIEXEC_LABEL is set */
64694288674SStephen J. Kiernan 	if ((flags & VERIEXEC_LABEL) != 0 && (label == NULL || labellen == 0))
64794288674SStephen J. Kiernan 		return (EINVAL);
64894288674SStephen J. Kiernan 
649fb47a376SStephen J. Kiernan 	/* Look up the device entry */
650fb47a376SStephen J. Kiernan 	if (file_dev)
651fb47a376SStephen J. Kiernan 		head = &veriexec_file_dev_head;
652fb47a376SStephen J. Kiernan 	else
653fb47a376SStephen J. Kiernan 		head = &veriexec_dev_head;
654fb47a376SStephen J. Kiernan 	lp = find_veriexec_dev(fsid, head);
655fb47a376SStephen J. Kiernan 
656fb47a376SStephen J. Kiernan 	/* Look up the fingerprint operations for the digest type */
657fb47a376SStephen J. Kiernan 	fpops = mac_veriexec_fingerprint_lookup_ops(fp_type);
658fb47a376SStephen J. Kiernan 	if (fpops == NULL)
659fb47a376SStephen J. Kiernan 		return (EOPNOTSUPP);
660fb47a376SStephen J. Kiernan 
661fb47a376SStephen J. Kiernan search:
662fb47a376SStephen J. Kiernan 	for (ip = LIST_FIRST(&(lp->file_head)); ip != NULL;
663fb47a376SStephen J. Kiernan 	     ip = LIST_NEXT(ip, entries)) {
664fb47a376SStephen J. Kiernan 		  /* check for a dupe file in the list, skip if an entry
665fb47a376SStephen J. Kiernan 		   * exists for this file except for when the flags contains
666fb47a376SStephen J. Kiernan 		   * VERIEXEC_INDIRECT, always set the flags when it is so
667fb47a376SStephen J. Kiernan 		   * we don't get a hole caused by conflicting flags on
668fb47a376SStephen J. Kiernan 		   * hardlinked files.  XXX maybe we should validate
669fb47a376SStephen J. Kiernan 		   * fingerprint is same and complain if it is not...
670fb47a376SStephen J. Kiernan 		   */
671fb47a376SStephen J. Kiernan 		if (ip->fileid == fileid && ip->gen == gen) {
672fb47a376SStephen J. Kiernan 			if (override) {
673fb47a376SStephen J. Kiernan 				/*
674fb47a376SStephen J. Kiernan 				 * for a signed load we allow overrides,
675fb47a376SStephen J. Kiernan 				 * otherwise fingerpints needed for pkg loads
676fb47a376SStephen J. Kiernan 				 * can fail (the files are on temp device).
677fb47a376SStephen J. Kiernan 				 */
678fb47a376SStephen J. Kiernan 				ip->flags = flags;
679fb47a376SStephen J. Kiernan 				ip->ops = fpops;
680fb47a376SStephen J. Kiernan 				memcpy(ip->fingerprint, fingerprint,
681fb47a376SStephen J. Kiernan 				    fpops->digest_len);
68294288674SStephen J. Kiernan 				if (flags & VERIEXEC_LABEL) {
68394288674SStephen J. Kiernan 					ip->labellen = mac_veriexec_init_label(
68494288674SStephen J. Kiernan 					    &ip->label, ip->labellen, label,
68594288674SStephen J. Kiernan 					    labellen);
68694288674SStephen J. Kiernan 				} else if (ip->labellen > 0) {
68794288674SStephen J. Kiernan 					free(ip->label, M_VERIEXEC);
68894288674SStephen J. Kiernan 					ip->labellen = 0;
68994288674SStephen J. Kiernan 					ip->label = NULL;
69094288674SStephen J. Kiernan 				}
691fb47a376SStephen J. Kiernan 			} else if ((flags & (VERIEXEC_INDIRECT|VERIEXEC_FILE)))
692fb47a376SStephen J. Kiernan 				ip->flags |= flags;
693fb47a376SStephen J. Kiernan 
694fb47a376SStephen J. Kiernan 			if (np) {
695fb47a376SStephen J. Kiernan 				/* unlikely but... we don't need it now. */
696fb47a376SStephen J. Kiernan 				mtx_unlock(&ve_mutex);
697fb47a376SStephen J. Kiernan 				free(np, M_VERIEXEC);
698fb47a376SStephen J. Kiernan 				mtx_lock(&ve_mutex);
699fb47a376SStephen J. Kiernan 			}
700fb47a376SStephen J. Kiernan 			return (0);
701fb47a376SStephen J. Kiernan 		}
702fb47a376SStephen J. Kiernan 	}
703fb47a376SStephen J. Kiernan 
704fb47a376SStephen J. Kiernan 	/*
705fb47a376SStephen J. Kiernan 	 * We may have been past here before...
706fb47a376SStephen J. Kiernan 	 */
707fb47a376SStephen J. Kiernan 	if (np == NULL) {
708fb47a376SStephen J. Kiernan 		/*
709fb47a376SStephen J. Kiernan 		 * We first try with mutex held and nowait.
710fb47a376SStephen J. Kiernan 		 */
711fb47a376SStephen J. Kiernan 		np = malloc(sizeof(struct mac_veriexec_file_info), M_VERIEXEC,
712fb47a376SStephen J. Kiernan 		    M_NOWAIT);
713fb47a376SStephen J. Kiernan 		if (np == NULL) {
714fb47a376SStephen J. Kiernan 			/*
715fb47a376SStephen J. Kiernan 			 * It was worth a try, now
716fb47a376SStephen J. Kiernan 			 * drop mutex while we malloc.
717fb47a376SStephen J. Kiernan 			 */
718fb47a376SStephen J. Kiernan 			mtx_unlock(&ve_mutex);
719fb47a376SStephen J. Kiernan 			np = malloc(sizeof(struct mac_veriexec_file_info),
720fb47a376SStephen J. Kiernan 			    M_VERIEXEC, M_WAITOK);
721fb47a376SStephen J. Kiernan 			mtx_lock(&ve_mutex);
722fb47a376SStephen J. Kiernan 			/*
723fb47a376SStephen J. Kiernan 			 * We now have to repeat our search!
724fb47a376SStephen J. Kiernan 			 */
725fb47a376SStephen J. Kiernan 			goto search;
726fb47a376SStephen J. Kiernan 		}
727fb47a376SStephen J. Kiernan 	}
728fb47a376SStephen J. Kiernan 
729fb47a376SStephen J. Kiernan 	/* Set up the meta-data entry */
730fb47a376SStephen J. Kiernan 	ip = np;
731fb47a376SStephen J. Kiernan 	ip->flags = flags;
732fb47a376SStephen J. Kiernan 	ip->ops = fpops;
733fb47a376SStephen J. Kiernan 	ip->fileid = fileid;
734fb47a376SStephen J. Kiernan 	ip->gen = gen;
735*6eabf4ceSSimon J. Gerraty 	ip->label = NULL;
736*6eabf4ceSSimon J. Gerraty 	ip->labellen = 0;
737fb47a376SStephen J. Kiernan 	memcpy(ip->fingerprint, fingerprint, fpops->digest_len);
73894288674SStephen J. Kiernan 	if (flags & VERIEXEC_LABEL)
73994288674SStephen J. Kiernan 		ip->labellen = mac_veriexec_init_label(&ip->label,
74094288674SStephen J. Kiernan 		    ip->labellen, label, labellen);
741fb47a376SStephen J. Kiernan 
742593d37bbSStephen J. Kiernan 	VERIEXEC_DEBUG(3, ("add file %ju.%lu (files=%d)\n",
743593d37bbSStephen J. Kiernan 	    (uintmax_t)ip->fileid,
744fb47a376SStephen J. Kiernan 	    ip->gen, file_dev));
745fb47a376SStephen J. Kiernan 
746fb47a376SStephen J. Kiernan 	/* Add the entry to the list */
747fb47a376SStephen J. Kiernan 	LIST_INSERT_HEAD(&(lp->file_head), ip, entries);
748fb47a376SStephen J. Kiernan #ifdef DEBUG_VERIEXEC_FINGERPRINT
749fb47a376SStephen J. Kiernan 	{
750fb47a376SStephen J. Kiernan 		off_t offset;
751fb47a376SStephen J. Kiernan 
752fb47a376SStephen J. Kiernan 		printf("Stored %s fingerprint:\n", fp_type);
753fb47a376SStephen J. Kiernan 		for (offset = 0; offset < fpops->digest_len; offset++)
754fb47a376SStephen J. Kiernan 			printf("%02x", fingerprint[offset]);
755fb47a376SStephen J. Kiernan 		printf("\n");
756fb47a376SStephen J. Kiernan 	}
757fb47a376SStephen J. Kiernan #endif
758fb47a376SStephen J. Kiernan 	return (0);
759fb47a376SStephen J. Kiernan }
760fb47a376SStephen J. Kiernan 
761fb47a376SStephen J. Kiernan /**
76294288674SStephen J. Kiernan  * @brief Search the meta-data store for information on the specified file.
76394288674SStephen J. Kiernan  *
76494288674SStephen J. Kiernan  * @param fsid          file system identifier to look for
76594288674SStephen J. Kiernan  * @param fileid        file to look for
76694288674SStephen J. Kiernan  * @param gen           generation of file
76794288674SStephen J. Kiernan  * @param found_dev	indicator that an entry for the file system was found
7688512d82eSSteve Kiernan  * @param ipp           pointer to location to store the info pointer
76994288674SStephen J. Kiernan  * @param check_files   if 1, check the files list first, otherwise check the
77094288674SStephen J. Kiernan  *                      exectuables list first
77194288674SStephen J. Kiernan  *
77294288674SStephen J. Kiernan  * @return A pointer to the meta-data inforation if meta-data exists for
77394288674SStephen J. Kiernan  *     the specified file identifier, otherwise @c NULL
77494288674SStephen J. Kiernan  */
7758512d82eSSteve Kiernan int
mac_veriexec_metadata_get_file_info(dev_t fsid,long fileid,unsigned long gen,int * found_dev,struct mac_veriexec_file_info ** ipp,int check_files)77694288674SStephen J. Kiernan mac_veriexec_metadata_get_file_info(dev_t fsid, long fileid, unsigned long gen,
7778512d82eSSteve Kiernan     int *found_dev, struct mac_veriexec_file_info **ipp, int check_files)
77894288674SStephen J. Kiernan {
77994288674SStephen J. Kiernan 	struct veriexec_devhead *search[3];
78094288674SStephen J. Kiernan 	struct mac_veriexec_file_info *ip;
78194288674SStephen J. Kiernan 	int x;
78294288674SStephen J. Kiernan 
78394288674SStephen J. Kiernan 	/* Determine the order of the lists to search */
78494288674SStephen J. Kiernan 	if (check_files) {
78594288674SStephen J. Kiernan 		search[0] = &veriexec_file_dev_head;
78694288674SStephen J. Kiernan 		search[1] = &veriexec_dev_head;
78794288674SStephen J. Kiernan 	} else {
78894288674SStephen J. Kiernan 		search[0] = &veriexec_dev_head;
78994288674SStephen J. Kiernan 		search[1] = &veriexec_file_dev_head;
79094288674SStephen J. Kiernan 	}
79194288674SStephen J. Kiernan 	search[2] = NULL;
79294288674SStephen J. Kiernan 
7938512d82eSSteve Kiernan 	VERIEXEC_DEBUG(3, ("%s: searching for dev %#jx, file %lu.%lu\n",
7948512d82eSSteve Kiernan 	    __func__, (uintmax_t)fsid, fileid, gen));
79594288674SStephen J. Kiernan 
79694288674SStephen J. Kiernan 	/* Search for the specified file */
79794288674SStephen J. Kiernan 	for (ip = NULL, x = 0; ip == NULL && search[x]; x++)
79894288674SStephen J. Kiernan 		ip = get_veriexec_file(search[x], fsid, fileid, gen, found_dev);
79994288674SStephen J. Kiernan 
8008512d82eSSteve Kiernan 	if (ipp != NULL)
8018512d82eSSteve Kiernan 		*ipp = ip;
8028512d82eSSteve Kiernan 	if (ip == NULL)
8038512d82eSSteve Kiernan 		return (ENOENT);
8048512d82eSSteve Kiernan 	return (0);
80594288674SStephen J. Kiernan }
80694288674SStephen J. Kiernan 
80794288674SStephen J. Kiernan /**
808fb47a376SStephen J. Kiernan  * @brief Intialize the meta-data store
809fb47a376SStephen J. Kiernan  */
810fb47a376SStephen J. Kiernan void
mac_veriexec_metadata_init(void)811fb47a376SStephen J. Kiernan mac_veriexec_metadata_init(void)
812fb47a376SStephen J. Kiernan {
813fb47a376SStephen J. Kiernan 
814fb47a376SStephen J. Kiernan 	mtx_init(&ve_mutex, "veriexec lock", NULL, MTX_DEF);
815fb47a376SStephen J. Kiernan 	LIST_INIT(&veriexec_dev_head);
816fb47a376SStephen J. Kiernan 	LIST_INIT(&veriexec_file_dev_head);
817fb47a376SStephen J. Kiernan }
818