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