[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.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>