lkml.org 
[lkml]   [2008]   [May]   [28]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    SubjectRe: [RFC][Patch 5/5]integrity: IMA as an integrity service provider
    From
    Date

    On Wed, 2008-05-28 at 01:22 -0700, Andrew Morton wrote:

    > +/**
    > + * ima_must_measure - measure decision based on policy.
    > + * @d - pointer to struct ima_data containing ima_args_data
    >
    > So if we know the type of d, did we _have_ to make it void*? It's
    > much better to use the C yype system if at all possible.

    This is one of the five integrity API calls. Each integrity template
    will define it differently, using a different data structure.

    > - ditto ima_collect_measurement()

    ima_collect_measurement is also one of the five integrity API calls.

    Here is a sample template kernel module that measures kernel memory.
    Of the five integrity API calls, it implements
    integrity_collect_measurement(), integrity_store_measurement(), and
    integrity_display_measurement(). It collects and stores measurements
    based on data read from security/kmem-template. The format is
    "name length address". The name can be any string identifier such as
    "proc_root"; the length is the number of bytes to measure; and address
    is a kernel memory address, which can be looked up in /proc/kallsyms.
    One caveat, the sample program currently does not validate the address.
    A userspace application triggers the measurement by writing to
    security/kmem-template.

    /*
    * Copyright (C) 2008 IBM Corporation
    * Author: Mimi Zohar <zohar@us.ibm.com>
    *
    * This program is free software; you can redistribute it and/or modify
    * it under the terms of the GNU General Public License as published by
    * the Free Software Foundation, version 2 of the License.
    *
    * kmem-template.c
    * - defines a kernel memory template
    * - reads from security/kmem-template "name length address"
    * - collects and stores measurement from address for length bytes
    */

    #include <asm/uaccess.h>
    #include <linux/module.h>
    #include <linux/moduleparam.h>
    #include <linux/kernel.h>
    #include <linux/fs.h>
    #include <linux/crypto.h>
    #include <linux/scatterlist.h>
    #include <linux/notifier.h>
    #include <linux/security.h>
    #include <linux/debugfs.h>
    #include <linux/seq_file.h>
    #include <linux/string.h>
    #include <linux/proc_fs.h>
    #include <linux/security.h>
    #include <linux/integrity.h>
    #include <linux/ima.h>

    #define MY_NAME THIS_MODULE->name
    #define IMA_DIGEST_SIZE 20

    static int __init init_kmem_template(void);
    static void __exit cleanup_kmem_template(void);

    struct kmem_data {
    char name[25];
    char *buf;
    int buflen;
    u8 digest[IMA_DIGEST_SIZE];
    };

    static void hexdump(unsigned char *buf, unsigned int len)
    {
    print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET,
    16, 1,
    buf, len, false);
    }

    int calc_hash(int buflen, char *buf, char *digest)
    {
    struct crypto_hash *tfm;
    struct hash_desc desc;
    struct scatterlist sg[1];
    int error, result = 0;

    tfm = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC);
    if (IS_ERR(tfm)) {
    printk(KERN_INFO "%s: failed to load %s transform: %ld\n",
    __func__, "sha1", PTR_ERR(tfm));
    return -ENOSYS;
    }
    desc.tfm = tfm;
    desc.flags = 0;
    error = crypto_hash_init(&desc);
    if (error) {
    result = -EINVAL;
    goto out;
    }

    sg_set_buf(sg, buf, buflen);
    result = crypto_hash_update(&desc, sg, buflen);
    if (!result) {
    error = crypto_hash_final(&desc, digest);
    if (error)
    result = -EINVAL;
    }

    out:
    crypto_free_hash(tfm);
    return result;
    }

    static int kmem_collect_measurement(void *d)
    {
    struct kmem_data *data = (struct kmem_data *)d;

    memset(data->digest, 0, sizeof data->digest);
    calc_hash(data->buflen, data->buf, data->digest);
    hexdump(data->buf, data->buflen);
    return 0;
    }

    /* Transform local kmem data to store data */
    void kmem_store_measurement(void *d)
    {
    struct kmem_data *data = (struct kmem_data *)d;
    struct ima_data idata;
    struct ima_store_data *template = &idata.data.template;

    idata.type = IMA_TEMPLATE;
    template->name = "kmem";
    template->len = sizeof *data;
    template->data = (char *)data;
    template->violation = 0;
    integrity_store_measurement("ima", (void *)&idata);
    return;
    }

    static void kmem_template_show(struct seq_file *m, void *e,
    enum integrity_show_type show)
    {
    struct kmem_data *data = (struct kmem_data *)e;
    int filename_len;
    char len[4];
    int i;

    for (i = 0; i < 20; i++) {
    switch (show) {
    case INTEGRITY_SHOW_ASCII:
    seq_printf(m, "%02x", data->digest[i]);
    break;
    case INTEGRITY_SHOW_BINARY:
    seq_putc(m, data->digest[i]);
    default:
    break;
    }
    }

    switch (show) {
    case INTEGRITY_SHOW_ASCII:
    seq_printf(m, " %s %d \n", data->name, data->buflen);
    break;
    case INTEGRITY_SHOW_BINARY:
    filename_len = strlen(data->name);
    memcpy(len, &filename_len, 4);
    for (i = 0; i < 4; i++)
    seq_putc(m, len[i]);
    for (i = 0; i < strlen(data->name); i++)
    seq_putc(m, data->name[i]);
    default:
    break;
    }
    }

    static struct template_operations kmem_ops = {
    .collect_measurement = kmem_collect_measurement,
    .store_measurement = kmem_store_measurement,
    .display_template = kmem_template_show
    };

    static int kmem_add_measure(char *name, unsigned int buflen,
    unsigned int addr)
    {
    struct kmem_data data;
    int rc;

    strncpy(data.name, name, sizeof data.name);
    data.buflen = buflen;
    data.buf = (char *)addr;
    rc = integrity_collect_measurement("kmem", &data);
    if (!rc)
    integrity_store_measurement("kmem", &data);
    return rc;
    }

    static ssize_t kmem_write_template(struct file *file, const char __user *buf,
    size_t buflen, loff_t *ppos)
    {
    char *data;
    char name[26];
    size_t result = 0, datalen;
    int rc;
    unsigned int addr, len;

    datalen = buflen > 256 ? 256 : buflen;
    data = kzalloc(datalen + 1, GFP_KERNEL);
    if (!data)
    result = -ENOMEM;

    if (copy_from_user(data, buf, datalen)) {
    result = -EFAULT;
    goto out;
    }

    result = datalen;

    rc = sscanf(data, "%25s %d %x ", name, &len, &addr);
    if (rc == 3)
    kmem_add_measure(name, len, addr);
    else {
    printk(KERN_INFO "%s: rc = %d\n", __func__, rc);
    result = -EINVAL;
    }
    out:
    if (!data)
    kfree(data);
    return result;
    }

    static struct file_operations kmem_template_ops = {
    .write = kmem_write_template
    };

    static struct dentry *kmem_template;

    static int __init init_kmem_template(void)
    {

    printk(KERN_INFO "%s: \n", __func__);
    register_template("kmem", &kmem_ops);

    kmem_template = securityfs_create_file("kmem-template",
    S_IRUSR | S_IRGRP | S_IWUSR,
    NULL, NULL, &kmem_template_ops);
    return 0;
    }

    static void __exit cleanup_kmem_template(void)
    {
    printk(KERN_INFO "%s\n", __FUNCTION__);
    unregister_template("kmem");

    securityfs_remove(kmem_template);
    }
    module_init(init_kmem_template);
    module_exit(cleanup_kmem_template);

    MODULE_LICENSE("GPL");



    \
     
     \ /
      Last update: 2008-05-29 05:35    [W:0.031 / U:1.580 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site