linux/security/integrity/ima/ima_queue.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2005,2006,2007,2008 IBM Corporation
   3 *
   4 * Authors:
   5 * Serge Hallyn <serue@us.ibm.com>
   6 * Reiner Sailer <sailer@watson.ibm.com>
   7 * Mimi Zohar <zohar@us.ibm.com>
   8 *
   9 * This program is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU General Public License as
  11 * published by the Free Software Foundation, version 2 of the
  12 * License.
  13 *
  14 * File: ima_queue.c
  15 *       Implements queues that store template measurements and
  16 *       maintains aggregate over the stored measurements
  17 *       in the pre-configured TPM PCR (if available).
  18 *       The measurement list is append-only. No entry is
  19 *       ever removed or changed during the boot-cycle.
  20 */
  21#include <linux/module.h>
  22#include <linux/rculist.h>
  23#include <linux/slab.h>
  24#include "ima.h"
  25
  26#define AUDIT_CAUSE_LEN_MAX 32
  27
  28LIST_HEAD(ima_measurements);    /* list of all measurements */
  29
  30/* key: inode (before secure-hashing a file) */
  31struct ima_h_table ima_htable = {
  32        .len = ATOMIC_LONG_INIT(0),
  33        .violations = ATOMIC_LONG_INIT(0),
  34        .queue[0 ... IMA_MEASURE_HTABLE_SIZE - 1] = HLIST_HEAD_INIT
  35};
  36
  37/* mutex protects atomicity of extending measurement list
  38 * and extending the TPM PCR aggregate. Since tpm_extend can take
  39 * long (and the tpm driver uses a mutex), we can't use the spinlock.
  40 */
  41static DEFINE_MUTEX(ima_extend_list_mutex);
  42
  43/* lookup up the digest value in the hash table, and return the entry */
  44static struct ima_queue_entry *ima_lookup_digest_entry(u8 *digest_value)
  45{
  46        struct ima_queue_entry *qe, *ret = NULL;
  47        unsigned int key;
  48        struct hlist_node *pos;
  49        int rc;
  50
  51        key = ima_hash_key(digest_value);
  52        rcu_read_lock();
  53        hlist_for_each_entry_rcu(qe, pos, &ima_htable.queue[key], hnext) {
  54                rc = memcmp(qe->entry->digest, digest_value, IMA_DIGEST_SIZE);
  55                if (rc == 0) {
  56                        ret = qe;
  57                        break;
  58                }
  59        }
  60        rcu_read_unlock();
  61        return ret;
  62}
  63
  64/* ima_add_template_entry helper function:
  65 * - Add template entry to measurement list and hash table.
  66 *
  67 * (Called with ima_extend_list_mutex held.)
  68 */
  69static int ima_add_digest_entry(struct ima_template_entry *entry)
  70{
  71        struct ima_queue_entry *qe;
  72        unsigned int key;
  73
  74        qe = kmalloc(sizeof(*qe), GFP_KERNEL);
  75        if (qe == NULL) {
  76                pr_err("IMA: OUT OF MEMORY ERROR creating queue entry.\n");
  77                return -ENOMEM;
  78        }
  79        qe->entry = entry;
  80
  81        INIT_LIST_HEAD(&qe->later);
  82        list_add_tail_rcu(&qe->later, &ima_measurements);
  83
  84        atomic_long_inc(&ima_htable.len);
  85        key = ima_hash_key(entry->digest);
  86        hlist_add_head_rcu(&qe->hnext, &ima_htable.queue[key]);
  87        return 0;
  88}
  89
  90static int ima_pcr_extend(const u8 *hash)
  91{
  92        int result = 0;
  93
  94        if (!ima_used_chip)
  95                return result;
  96
  97        result = tpm_pcr_extend(TPM_ANY_NUM, CONFIG_IMA_MEASURE_PCR_IDX, hash);
  98        if (result != 0)
  99                pr_err("IMA: Error Communicating to TPM chip, result: %d\n",
 100                       result);
 101        return result;
 102}
 103
 104/* Add template entry to the measurement list and hash table,
 105 * and extend the pcr.
 106 */
 107int ima_add_template_entry(struct ima_template_entry *entry, int violation,
 108                           const char *op, struct inode *inode)
 109{
 110        u8 digest[IMA_DIGEST_SIZE];
 111        const char *audit_cause = "hash_added";
 112        char tpm_audit_cause[AUDIT_CAUSE_LEN_MAX];
 113        int audit_info = 1;
 114        int result = 0, tpmresult = 0;
 115
 116        mutex_lock(&ima_extend_list_mutex);
 117        if (!violation) {
 118                memcpy(digest, entry->digest, sizeof digest);
 119                if (ima_lookup_digest_entry(digest)) {
 120                        audit_cause = "hash_exists";
 121                        result = -EEXIST;
 122                        goto out;
 123                }
 124        }
 125
 126        result = ima_add_digest_entry(entry);
 127        if (result < 0) {
 128                audit_cause = "ENOMEM";
 129                audit_info = 0;
 130                goto out;
 131        }
 132
 133        if (violation)          /* invalidate pcr */
 134                memset(digest, 0xff, sizeof digest);
 135
 136        tpmresult = ima_pcr_extend(digest);
 137        if (tpmresult != 0) {
 138                snprintf(tpm_audit_cause, AUDIT_CAUSE_LEN_MAX, "TPM_error(%d)",
 139                         tpmresult);
 140                audit_cause = tpm_audit_cause;
 141                audit_info = 0;
 142        }
 143out:
 144        mutex_unlock(&ima_extend_list_mutex);
 145        integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
 146                            entry->template.file_name,
 147                            op, audit_cause, result, audit_info);
 148        return result;
 149}
 150
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.