[BACK]Return to verified_exec.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev

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>