Annotation of src/sys/dev/verified_exec.c, Revision 1.31.6.1
1.31.6.1! kardel 1: /* $NetBSD: verified_exec.c,v 1.31 2005/12/12 21:47:58 elad Exp $ */
1.1 blymn 2:
3: /*-
1.7 blymn 4: * Copyright 2005 Elad Efrat <elad@bsd.org.il>
5: * Copyright 2005 Brett Lymn <blymn@netbsd.org>
1.1 blymn 6: *
1.7 blymn 7: * This code is derived from software contributed to The NetBSD Foundation
8: * by Brett Lymn and Elad Efrat
1.1 blymn 9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
1.7 blymn 15: * 2. Neither the name of The NetBSD Foundation nor the names of its
16: * contributors may be used to endorse or promote products derived
17: * from this software without specific prior written permission.
1.1 blymn 18: *
1.7 blymn 19: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29: * POSSIBILITY OF SUCH DAMAGE.
1.1 blymn 30: */
1.4 lukem 31:
32: #include <sys/cdefs.h>
1.7 blymn 33: #if defined(__NetBSD__)
1.31.6.1! kardel 34: __KERNEL_RCSID(0, "$NetBSD: verified_exec.c,v 1.31 2005/12/12 21:47:58 elad Exp $");
1.7 blymn 35: #else
1.31.6.1! kardel 36: __RCSID("$Id: verified_exec.c,v 1.31 2005/12/12 21:47:58 elad Exp $\n$NetBSD: verified_exec.c,v 1.31 2005/12/12 21:47:58 elad Exp $");
1.7 blymn 37: #endif
1.1 blymn 38:
39: #include <sys/param.h>
40: #include <sys/systm.h>
41: #include <sys/proc.h>
42: #include <sys/errno.h>
43: #include <sys/buf.h>
44: #include <sys/malloc.h>
1.7 blymn 45:
46: #ifdef __FreeBSD__
47: #include <sys/kernel.h>
48: #include <sys/device_port.h>
49: #include <sys/ioccom.h>
50: #else
1.1 blymn 51: #include <sys/ioctl.h>
52: #include <sys/device.h>
1.7 blymn 53: #define DEVPORT_DEVICE struct device
54: #endif
55:
1.1 blymn 56: #include <sys/conf.h>
57: #include <sys/lock.h>
58: #include <sys/queue.h>
59: #include <sys/vnode.h>
60: #include <sys/fcntl.h>
61: #include <sys/namei.h>
1.10 elad 62: #include <sys/sysctl.h>
63: #define VERIEXEC_NEED_NODE
1.7 blymn 64: #include <sys/verified_exec.h>
1.31.6.1! kardel 65: #include <sys/kauth.h>
1.1 blymn 66:
1.7 blymn 67: /* count of number of times device is open (we really only allow one open) */
1.13 elad 68: static unsigned int veriexec_dev_usage;
1.7 blymn 69:
70: struct veriexec_softc {
71: DEVPORT_DEVICE veriexec_dev;
1.1 blymn 72: };
73:
1.7 blymn 74: #if defined(__FreeBSD__)
75: # define CDEV_MAJOR 216
76: # define BDEV_MAJOR -1
77: #endif
78:
79: const struct cdevsw veriexec_cdevsw = {
80: veriexecopen,
81: veriexecclose,
82: noread,
83: nowrite,
84: veriexecioctl,
85: #ifdef __NetBSD__
86: nostop,
87: notty,
88: #endif
89: nopoll,
90: nommap,
91: #if defined(__NetBSD__)
92: nokqfilter,
93: #elif defined(__FreeBSD__)
94: nostrategy,
95: "veriexec",
96: CDEV_MAJOR,
97: nodump,
98: nopsize,
99: 0, /* flags */
100: BDEV_MAJOR
101: #endif
1.1 blymn 102: };
103:
104: /* Autoconfiguration glue */
1.7 blymn 105: void veriexecattach(DEVPORT_DEVICE *parent, DEVPORT_DEVICE *self,
106: void *aux);
1.29 christos 107: int veriexecopen(dev_t dev, int flags, int fmt, struct lwp *l);
108: int veriexecclose(dev_t dev, int flags, int fmt, struct lwp *l);
1.7 blymn 109: int veriexecioctl(dev_t dev, u_long cmd, caddr_t data, int flags,
1.29 christos 110: struct lwp *l);
1.1 blymn 111:
112: void
1.7 blymn 113: veriexecattach(DEVPORT_DEVICE *parent, DEVPORT_DEVICE *self,
114: void *aux)
115: {
116: veriexec_dev_usage = 0;
1.18 elad 117:
118: if (veriexec_verbose >= 2)
119: printf("Veriexec: veriexecattach: Veriexec pseudo-device"
120: "attached.\n");
1.7 blymn 121: }
122:
123: int
124: veriexecopen(dev_t dev __unused, int flags __unused,
1.29 christos 125: int fmt __unused, struct lwp *l __unused)
1.1 blymn 126: {
1.17 elad 127: if (veriexec_verbose >= 2) {
128: printf("Veriexec: veriexecopen: Veriexec load device "
1.20 elad 129: "open attempt by uid=%u, pid=%u. (dev=%u)\n",
1.31.6.1! kardel 130: kauth_cred_geteuid(l->l_proc->p_cred),
! 131: l->l_proc->p_pid, dev);
1.17 elad 132: }
1.7 blymn 133:
1.31.6.1! kardel 134: if (kauth_authorize_generic(l->l_proc->p_cred, KAUTH_GENERIC_ISSUSER,
! 135: &l->l_proc->p_acflag) != 0)
1.13 elad 136: return (EPERM);
137:
1.7 blymn 138: if (veriexec_dev_usage > 0) {
1.18 elad 139: if (veriexec_verbose >= 2)
140: printf("Veriexec: load device already in use.\n");
141:
1.7 blymn 142: return(EBUSY);
143: }
144:
145: veriexec_dev_usage++;
146: return (0);
1.1 blymn 147: }
148:
149: int
1.7 blymn 150: veriexecclose(dev_t dev __unused, int flags __unused,
1.30 elad 151: int fmt __unused, struct lwp *l __unused)
1.1 blymn 152: {
1.7 blymn 153: if (veriexec_dev_usage > 0)
154: veriexec_dev_usage--;
155: return (0);
1.1 blymn 156: }
157:
158: int
1.7 blymn 159: veriexecioctl(dev_t dev __unused, u_long cmd, caddr_t data,
1.29 christos 160: int flags __unused, struct lwp *l)
1.1 blymn 161: {
1.7 blymn 162: int error = 0;
163:
1.15 elad 164: if (veriexec_strict > 0) {
165: printf("Veriexec: veriexecioctl: Strict mode, modifying "
1.31.6.1! kardel 166: "veriexec tables is not permitted.\n");
1.1 blymn 167:
1.7 blymn 168: return (EPERM);
1.1 blymn 169: }
1.31.6.1! kardel 170:
1.7 blymn 171: switch (cmd) {
1.27 elad 172: case VERIEXEC_TABLESIZE:
173: error = veriexec_newtable((struct veriexec_sizing_params *)
174: data);
1.7 blymn 175: break;
1.1 blymn 176:
1.27 elad 177: case VERIEXEC_LOAD:
1.30 elad 178: error = veriexec_load((struct veriexec_params *)data, l);
1.7 blymn 179: break;
1.5 perry 180:
1.28 elad 181: case VERIEXEC_DELETE:
182: error = veriexec_delete((struct veriexec_delete_params *)data);
183: break;
184:
1.31 elad 185: case VERIEXEC_QUERY:
186: error = veriexec_query((struct veriexec_query_params *)data);
187: break;
188:
1.1 blymn 189: default:
1.7 blymn 190: /* Invalid operation. */
1.1 blymn 191: error = ENODEV;
1.7 blymn 192: break;
1.1 blymn 193: }
194:
195: return (error);
196: }
197:
1.7 blymn 198: #if defined(__FreeBSD__)
199: static void
200: veriexec_drvinit(void *unused __unused)
201: {
202: make_dev(&verifiedexec_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
203: "veriexec");
204: verifiedexecattach(0, 0, 0);
205: }
206:
207: SYSINIT(veriexec, SI_SUB_PSEUDO, SI_ORDER_ANY, veriexec_drvinit, NULL);
208: #endif
1.27 elad 209:
210: int
211: veriexec_newtable(struct veriexec_sizing_params *params)
212: {
213: struct veriexec_hashtbl *tbl;
214: u_char node_name[16];
215: u_long hashmask;
216:
217: /* Check for existing table for device. */
218: if (veriexec_tblfind(params->dev) != NULL)
219: return (EEXIST);
220:
221: /* Allocate and initialize a Veriexec hash table. */
222: tbl = malloc(sizeof(*tbl), M_TEMP, M_WAITOK);
223: tbl->hash_size = params->hash_size;
224: tbl->hash_dev = params->dev;
225: tbl->hash_tbl = hashinit(params->hash_size, HASH_LIST, M_TEMP,
226: M_WAITOK, &hashmask);
227: tbl->hash_count = 0;
228:
229: LIST_INSERT_HEAD(&veriexec_tables, tbl, hash_list);
230:
231: snprintf(node_name, sizeof(node_name), "dev_%u",
232: tbl->hash_dev);
233:
234: sysctl_createv(NULL, 0, &veriexec_count_node, NULL,
235: CTLFLAG_READONLY, CTLTYPE_QUAD, node_name,
236: NULL, NULL, 0, &tbl->hash_count, 0,
237: tbl->hash_dev, CTL_EOL);
238:
239: return (0);
240: }
241:
242: int
1.30 elad 243: veriexec_load(struct veriexec_params *params, struct lwp *l)
1.27 elad 244: {
245: struct veriexec_hashtbl *tbl;
246: struct veriexec_hash_entry *hh;
247: struct veriexec_hash_entry *e;
248: struct nameidata nid;
249: struct vattr va;
250: int error;
251:
1.30 elad 252: NDINIT(&nid, LOOKUP, FOLLOW, UIO_SYSSPACE, params->file, l);
1.27 elad 253: error = namei(&nid);
254: if (error)
255: return (error);
256:
257: /* Add only regular files. */
258: if (nid.ni_vp->v_type != VREG) {
259: printf("Veriexec: veriexecioctl: Not adding \"%s\": "
260: "Not a regular file.\n", params->file);
261: vrele(nid.ni_vp);
262: return (EINVAL);
263: }
264:
265: /* Get attributes for device and inode. */
1.31.6.1! kardel 266: error = VOP_GETATTR(nid.ni_vp, &va, l->l_proc->p_cred, l);
! 267: if (error) {
! 268: vrele(nid.ni_vp);
1.27 elad 269: return (error);
1.31.6.1! kardel 270: }
1.27 elad 271:
272: /* Release our reference to the vnode. (namei) */
273: vrele(nid.ni_vp);
274:
275: /* Get table for the device. */
276: tbl = veriexec_tblfind(va.va_fsid);
277: if (tbl == NULL) {
278: return (EINVAL);
279: }
280:
281: hh = veriexec_lookup(va.va_fsid, va.va_fileid);
282: if (hh != NULL) {
283: /*
284: * Duplicate entry means something is wrong in
285: * the signature file. Just give collision info
286: * and return.
287: */
288: printf("veriexec: Duplicate entry. [%s, %ld:%llu] "
289: "old[type=0x%02x, algorithm=%s], "
290: "new[type=0x%02x, algorithm=%s] "
291: "(%s fingerprint)\n",
292: params->file, va.va_fsid,
293: (unsigned long long)va.va_fileid,
294: hh->type, hh->ops->type,
295: params->type, params->fp_type,
296: (((hh->ops->hash_len != params->size) ||
297: (memcmp(hh->fp, params->fingerprint,
298: min(hh->ops->hash_len, params->size))
299: != 0)) ? "different" : "same"));
300:
301: return (0);
302: }
303:
304: e = malloc(sizeof(*e), M_TEMP, M_WAITOK);
305: e->inode = va.va_fileid;
306: e->type = params->type;
307: e->status = FINGERPRINT_NOTEVAL;
308: e->page_fp = NULL;
309: e->page_fp_status = PAGE_FP_NONE;
310: e->npages = 0;
311: e->last_page_size = 0;
312: if ((e->ops = veriexec_find_ops(params->fp_type)) == NULL) {
313: free(e, M_TEMP);
314: printf("Veriexec: veriexecioctl: Invalid or unknown "
315: "fingerprint type \"%s\" for file \"%s\" "
316: "(dev=%ld, inode=%llu)\n", params->fp_type,
1.31.6.1! kardel 317: params->file, va.va_fsid,
1.27 elad 318: (unsigned long long)va.va_fileid);
319: return(EINVAL);
320: }
321:
322: /*
323: * Just a bit of a sanity check - require the size of
324: * the fp to be passed in, check this against the expected
325: * size. Of course userland could lie deliberately, this
326: * really only protects against the obvious fumble of
327: * changing the fp type but not updating the fingerprint
328: * string.
329: */
330: if (e->ops->hash_len != params->size) {
331: printf("Veriexec: veriexecioctl: Inconsistent "
332: "fingerprint size for type \"%s\" for file "
333: "\"%s\" (dev=%ld, inode=%llu), size was %u "
334: "was expecting %zu\n", params->fp_type,
335: params->file, va.va_fsid,
336: (unsigned long long)va.va_fileid,
337: params->size, e->ops->hash_len);
338:
339: free(e, M_TEMP);
340: return(EINVAL);
341: }
1.31.6.1! kardel 342:
1.27 elad 343: e->fp = malloc(e->ops->hash_len, M_TEMP, M_WAITOK);
344: memcpy(e->fp, params->fingerprint, e->ops->hash_len);
345:
346: veriexec_report("New entry.", params->file, &va, NULL,
347: REPORT_VERBOSE_HIGH, REPORT_NOALARM,
348: REPORT_NOPANIC);
349:
350: error = veriexec_hashadd(tbl, e);
351:
352: return (error);
353: }
1.28 elad 354:
355: int
356: veriexec_delete(struct veriexec_delete_params *params)
357: {
358: struct veriexec_hashtbl *tbl;
359: struct veriexec_hash_entry *vhe;
360:
361: /* Delete an entire table */
362: if (params->ino == 0) {
363: struct veriexec_hashhead *tbl_list;
364: u_long i;
365:
366: tbl = veriexec_tblfind(params->dev);
367: if (tbl == NULL)
368: return (ENOENT);
369:
370: /* Remove all entries from the table and lists */
371: tbl_list = tbl->hash_tbl;
372: for (i = 0; i < tbl->hash_size; i++) {
373: while (LIST_FIRST(&tbl_list[i]) != NULL) {
374: vhe = LIST_FIRST(&tbl_list[i]);
375: if (vhe->fp != NULL)
376: free(vhe->fp, M_TEMP);
377: if (vhe->page_fp != NULL)
378: free(vhe->page_fp, M_TEMP);
379: LIST_REMOVE(vhe, entries);
380: free(vhe, M_TEMP);
381: }
382: }
383:
384: /* Remove hash table and sysctl node */
385: hashdone(tbl->hash_tbl, M_TEMP);
386: LIST_REMOVE(tbl, hash_list);
387: sysctl_destroyv(__UNCONST(veriexec_count_node), params->dev,
388: CTL_EOL);
389: } else {
390: tbl = veriexec_tblfind(params->dev);
391: if (tbl == NULL)
392: return (ENOENT);
393:
394: vhe = veriexec_lookup(params->dev, params->ino);
395: if (vhe != NULL) {
396: if (vhe->fp != NULL)
397: free(vhe->fp, M_TEMP);
398: if (vhe->page_fp != NULL)
399: free(vhe->page_fp, M_TEMP);
400: LIST_REMOVE(vhe, entries);
401: free(vhe, M_TEMP);
402:
403: tbl->hash_count--;
404: }
405: }
406:
407: return (0);
408: }
1.31 elad 409:
410: int
411: veriexec_query(struct veriexec_query_params *params)
412: {
413: struct veriexec_hash_entry *vhe;
414: int error;
415:
416: vhe = veriexec_lookup(params->dev, params->ino);
417: if (vhe == NULL)
418: return (ENOENT);
419:
420: params->type = vhe->type;
421: params->status = vhe->status;
422: params->hash_len = vhe->ops->hash_len;
423: strlcpy(params->fp_type, vhe->ops->type, sizeof(params->fp_type));
424: memcpy(params->fp_type, vhe->ops->type, sizeof(params->fp_type));
425: error = copyout(params, params->uaddr, sizeof(*params));
426: if (error)
427: return (error);
428: if (params->fp_bufsize >= vhe->ops->hash_len) {
429: error = copyout(vhe->fp, params->fp, vhe->ops->hash_len);
430: if (error)
431: return (error);
432: } else
433: error = ENOMEM;
434:
435: return (error);
436: }
CVSweb <webmaster@jp.NetBSD.org>