Annotation of src/sys/dev/verified_exec.c, Revision 1.4.8.1
1.4.8.1 ! kent 1: /* $NetBSD: verified_exec.c,v 1.7 2005/04/20 13:44:45 blymn Exp $ */
1.1 blymn 2:
3: /*-
1.4.8.1 ! kent 4: * Copyright 2005 Elad Efrat <elad@bsd.org.il>
! 5: * Copyright 2005 Brett Lymn <blymn@netbsd.org>
1.1 blymn 6: *
1.4.8.1 ! kent 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.4.8.1 ! kent 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.4.8.1 ! kent 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.4.8.1 ! kent 33: #if defined(__NetBSD__)
! 34: __KERNEL_RCSID(0, "$NetBSD: verified_exec.c,v 1.7 2005/04/20 13:44:45 blymn Exp $");
! 35: #else
! 36: __RCSID("$Id: verified_exec.c,v 1.7 2005/04/20 13:44:45 blymn Exp $\n$NetBSD: verified_exec.c,v 1.7 2005/04/20 13:44:45 blymn Exp $");
! 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.4.8.1 ! kent 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.4.8.1 ! kent 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.4.8.1 ! kent 62: #include <sys/verified_exec.h>
1.1 blymn 63:
1.4.8.1 ! kent 64: /* count of number of times device is open (we really only allow one open) */
! 65: static unsigned veriexec_dev_usage;
1.1 blymn 66:
1.4.8.1 ! kent 67: struct veriexec_softc {
! 68: DEVPORT_DEVICE veriexec_dev;
1.1 blymn 69: };
70:
1.4.8.1 ! kent 71: #if defined(__FreeBSD__)
! 72: # define CDEV_MAJOR 216
! 73: # define BDEV_MAJOR -1
! 74: #endif
! 75:
! 76: const struct cdevsw veriexec_cdevsw = {
! 77: veriexecopen,
! 78: veriexecclose,
! 79: noread,
! 80: nowrite,
! 81: veriexecioctl,
! 82: #ifdef __NetBSD__
! 83: nostop,
! 84: notty,
! 85: #endif
! 86: nopoll,
! 87: nommap,
! 88: #if defined(__NetBSD__)
! 89: nokqfilter,
! 90: #elif defined(__FreeBSD__)
! 91: nostrategy,
! 92: "veriexec",
! 93: CDEV_MAJOR,
! 94: nodump,
! 95: nopsize,
! 96: 0, /* flags */
! 97: BDEV_MAJOR
! 98: #endif
! 99: };
1.1 blymn 100:
101: /* Autoconfiguration glue */
1.4.8.1 ! kent 102: void veriexecattach(DEVPORT_DEVICE *parent, DEVPORT_DEVICE *self,
! 103: void *aux);
! 104: int veriexecopen(dev_t dev, int flags, int fmt, struct proc *p);
! 105: int veriexecclose(dev_t dev, int flags, int fmt, struct proc *p);
! 106: int veriexecioctl(dev_t dev, u_long cmd, caddr_t data, int flags,
! 107: struct proc *p);
1.1 blymn 108:
109: void
1.4.8.1 ! kent 110: veriexecattach(DEVPORT_DEVICE *parent, DEVPORT_DEVICE *self,
! 111: void *aux)
1.1 blymn 112: {
1.4.8.1 ! kent 113: veriexec_dev_usage = 0;
! 114: veriexec_dprintf(("Veriexec: veriexecattach: Veriexec pseudo-device "
! 115: "attached.\n"));
1.1 blymn 116: }
117:
118: int
1.4.8.1 ! kent 119: veriexecopen(dev_t dev __unused, int flags __unused,
! 120: int fmt __unused, struct proc *p __unused)
1.1 blymn 121: {
122: #ifdef VERIFIED_EXEC_DEBUG_VERBOSE
1.4.8.1 ! kent 123: printf("Veriexec: veriexecopen: Veriexec load device open attempt by "
! 124: "uid=%u, pid=%u. (dev=%d)\n", p->p_ucred->cr_uid,
! 125: p->p_pid, dev);
1.1 blymn 126: #endif
127:
1.4.8.1 ! kent 128: if (veriexec_dev_usage > 0) {
! 129: veriexec_dprintf(("Veriexec: load device already in use\n"));
! 130: return(EBUSY);
1.1 blymn 131: }
132:
1.4.8.1 ! kent 133: veriexec_dev_usage++;
! 134: return (0);
1.1 blymn 135: }
136:
1.4.8.1 ! kent 137: int
! 138: veriexecclose(dev_t dev __unused, int flags __unused,
! 139: int fmt __unused, struct proc *p __unused)
1.1 blymn 140: {
1.4.8.1 ! kent 141: if (veriexec_dev_usage > 0)
! 142: veriexec_dev_usage--;
! 143: return (0);
1.1 blymn 144: }
145:
146: int
1.4.8.1 ! kent 147: veriexecioctl(dev_t dev __unused, u_long cmd, caddr_t data,
! 148: int flags __unused, struct proc *p)
1.1 blymn 149: {
1.4.8.1 ! kent 150: struct veriexec_hashtbl *tbl;
1.1 blymn 151: struct nameidata nid;
1.4.8.1 ! kent 152: struct vattr va;
! 153: int error = 0;
! 154: u_long hashmask;
1.1 blymn 155:
1.4.8.1 ! kent 156: /*
! 157: * Don't allow updates in multi-user mode, but we will allow
! 158: * queries of supported fingerprints.
! 159: *
! 160: */
! 161: if ((securelevel >= 1) && (cmd != VERIEXEC_FINGERPRINTS)) {
! 162: printf("Veriexec: veriexecioctl: Securelevel raised, loading"
! 163: "fingerprints is not permitted\n");
! 164:
! 165: return (EPERM);
! 166: }
1.1 blymn 167:
168: switch (cmd) {
1.4.8.1 ! kent 169: case VERIEXEC_TABLESIZE: {
! 170: struct veriexec_sizing_params *params =
! 171: (struct veriexec_sizing_params *) data;
! 172:
! 173: /* Allocate and initialize a Veriexec hash table. */
! 174: tbl = malloc(sizeof(struct veriexec_hashtbl), M_TEMP,
! 175: M_WAITOK);
! 176: tbl->hash_size = params->hash_size;
! 177: tbl->hash_dev = params->dev;
! 178: tbl->hash_tbl = hashinit(params->hash_size, HASH_LIST, M_TEMP,
! 179: M_WAITOK, &hashmask);
! 180:
! 181: LIST_INSERT_HEAD(&veriexec_tables, tbl, hash_list);
! 182:
! 183: break;
! 184: }
! 185:
! 186: case VERIEXEC_LOAD: {
! 187: struct veriexec_params *params =
! 188: (struct veriexec_params *) data;
! 189: struct veriexec_hash_entry *hh;
! 190: struct veriexec_hash_entry *e;
! 191:
! 192: NDINIT(&nid, LOOKUP, FOLLOW, UIO_SYSSPACE, params->file, p);
! 193: error = namei(&nid);
! 194: if (error)
! 195: return (error);
! 196: /* Add only regular files. */
! 197: if (nid.ni_vp->v_type != VREG) {
! 198: printf("Veriexec: veriexecioctl: Not adding \"%s\": "
! 199: "Not a regular file.\n", params->file);
! 200: vrele(nid.ni_vp);
! 201: return (EINVAL);
! 202: }
! 203:
! 204: nid.ni_vp->fp_status = FINGERPRINT_NOTEVAL;
! 205:
! 206: /* Get attributes for device and inode. */
! 207: error = VOP_GETATTR(nid.ni_vp, &va, p->p_ucred, p);
! 208: if (error)
! 209: return (error);
! 210:
! 211: /* Release our reference to the vnode. (namei) */
! 212: vrele(nid.ni_vp);
! 213:
! 214: /* Get table for the device. */
! 215: tbl = veriexec_tblfind(va.va_fsid);
! 216: if (tbl == NULL) {
! 217: return (EINVAL);
! 218: }
! 219:
! 220: hh = veriexec_lookup(va.va_fsid, va.va_fileid);
! 221: if (hh != NULL) {
! 222: /*
! 223: * Duplicate entry. Still check the type to
! 224: * ensure enforcement of a stricter policy.
! 225: * i.e. if orignal entry was direct exec but
! 226: * the new params flag the file as indirect or
! 227: * file then update the hash entry to the new
! 228: * type to ensure duplicate entries do not
! 229: * degrade the security policy...
1.1 blymn 230: */
1.4.8.1 ! kent 231:
! 232: if ((hh->type != params->type) &&
! 233: ((params->type == VERIEXEC_INDIRECT) ||
! 234: (params->type == VERIEXEC_FILE))) {
! 235: hh->type = params->type;
! 236: printf("Veriexec: veriexecioctl: Duplicate "
! 237: "entry for %s, (dev=%ld, inode=%ld) "
! 238: "but type mismatched. "
! 239: "Updating type to stricter one\n",
! 240: params->file, va.va_fsid, va.va_fileid);
1.1 blymn 241: }
242:
1.4.8.1 ! kent 243: #ifdef VERIFIED_EXEC_DEBUG_VERBOSE
! 244: printf("Veriexec: veriexecioctl: Duplicate "
! 245: "entry for %s. (dev=%ld, inode=%ld) "
! 246: "Ignoring.\n", params->file,
! 247: va.va_fsid, va.va_fileid);
! 248: #endif
! 249:
! 250: return (0);
! 251: }
! 252:
! 253: e = malloc(sizeof(*e), M_TEMP, M_WAITOK);
! 254: e->inode = va.va_fileid;
! 255: e->type = params->type;
! 256: if ((e->ops = veriexec_find_ops(params->fp_type)) == NULL) {
! 257: free(e, M_TEMP);
! 258: printf("Veriexec: veriexecioctl: Invalid or unknown "
! 259: "fingerprint type \"%s\" for file \"%s\" "
! 260: "(dev=%ld, inode=%ld)\n", params->fp_type,
! 261: params->file, va.va_fsid, va.va_fileid);
! 262: return(EINVAL);
1.1 blymn 263: }
1.4.8.1 ! kent 264:
! 265: /*
! 266: * Just a bit of a sanity check - require the size of
! 267: * the fp to be passed in, check this against the expected
! 268: * size. Of course userland could lie deliberately, this
! 269: * really only protects against the obvious fumble of
! 270: * changing the fp type but not updating the fingerprint
! 271: * string.
! 272: */
! 273: if (e->ops->hash_len != params->size) {
! 274: printf("Veriexec: veriexecioctl: Inconsistent "
! 275: "fingerprint size for type \"%s\" for file "
! 276: "\"%s\" (dev=%ld, inode=%ld), size was %u "
! 277: "was expecting %d\n", params->fp_type,
! 278: params->file, va.va_fsid, va.va_fileid,
! 279: params->size, e->ops->hash_len);
! 280: free(e, M_TEMP);
! 281: return(EINVAL);
! 282: }
! 283:
! 284: e->fp = malloc(e->ops->hash_len, M_TEMP, M_WAITOK);
! 285: memcpy(e->fp, params->fingerprint, e->ops->hash_len);
! 286:
! 287: veriexec_dprintf(("Veriexec: veriexecioctl: New entry. (file=%s,"
! 288: " dev=%d, inode=%u)\n", params->vxp_file, va.va_fsid,
! 289: va.va_fileid));
! 290:
! 291: error = veriexec_hashadd(tbl, e);
! 292:
1.1 blymn 293: break;
1.4.8.1 ! kent 294: }
1.1 blymn 295:
1.4.8.1 ! kent 296: case VERIEXEC_FINGERPRINTS: {
! 297: struct veriexec_fp_report *params =
! 298: (struct veriexec_fp_report *) data;
! 299:
! 300: if (strlen(veriexec_fp_names) >= params->size) {
! 301: params->size = strlen(veriexec_fp_names) + 1;
! 302: } else {
! 303: strlcpy(params->fingerprints, veriexec_fp_names,
! 304: params->size);
! 305: }
! 306:
! 307: break;
! 308: }
! 309:
1.1 blymn 310: default:
1.4.8.1 ! kent 311: /* Invalid operation. */
1.1 blymn 312: error = ENODEV;
1.4.8.1 ! kent 313:
! 314: break;
1.1 blymn 315: }
316:
317: return (error);
318: }
319:
1.4.8.1 ! kent 320: #if defined(__FreeBSD__)
! 321: static void
! 322: veriexec_drvinit(void *unused __unused)
! 323: {
! 324: make_dev(&verifiedexec_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
! 325: "veriexec");
! 326: verifiedexecattach(0, 0, 0);
! 327: }
! 328:
! 329: SYSINIT(veriexec, SI_SUB_PSEUDO, SI_ORDER_ANY, veriexec_drvinit, NULL);
! 330: #endif
CVSweb <webmaster@jp.NetBSD.org>