linux/security/integrity/ima/ima_api.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2008 IBM Corporation
   3 *
   4 * Author: Mimi Zohar <zohar@us.ibm.com>
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License as
   8 * published by the Free Software Foundation, version 2 of the
   9 * License.
  10 *
  11 * File: ima_api.c
  12 *      Implements must_measure, collect_measurement, store_measurement,
  13 *      and store_template.
  14 */
  15#include <linux/module.h>
  16
  17#include "ima.h"
  18static const char *IMA_TEMPLATE_NAME = "ima";
  19
  20/*
  21 * ima_store_template - store ima template measurements
  22 *
  23 * Calculate the hash of a template entry, add the template entry
  24 * to an ordered list of measurement entries maintained inside the kernel,
  25 * and also update the aggregate integrity value (maintained inside the
  26 * configured TPM PCR) over the hashes of the current list of measurement
  27 * entries.
  28 *
  29 * Applications retrieve the current kernel-held measurement list through
  30 * the securityfs entries in /sys/kernel/security/ima. The signed aggregate
  31 * TPM PCR (called quote) can be retrieved using a TPM user space library
  32 * and is used to validate the measurement list.
  33 *
  34 * Returns 0 on success, error code otherwise
  35 */
  36int ima_store_template(struct ima_template_entry *entry,
  37                       int violation, struct inode *inode)
  38{
  39        const char *op = "add_template_measure";
  40        const char *audit_cause = "hashing_error";
  41        int result;
  42
  43        memset(entry->digest, 0, sizeof(entry->digest));
  44        entry->template_name = IMA_TEMPLATE_NAME;
  45        entry->template_len = sizeof(entry->template);
  46
  47        if (!violation) {
  48                result = ima_calc_template_hash(entry->template_len,
  49                                                &entry->template,
  50                                                entry->digest);
  51                if (result < 0) {
  52                        integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
  53                                            entry->template_name, op,
  54                                            audit_cause, result, 0);
  55                        return result;
  56                }
  57        }
  58        result = ima_add_template_entry(entry, violation, op, inode);
  59        return result;
  60}
  61
  62/*
  63 * ima_add_violation - add violation to measurement list.
  64 *
  65 * Violations are flagged in the measurement list with zero hash values.
  66 * By extending the PCR with 0xFF's instead of with zeroes, the PCR
  67 * value is invalidated.
  68 */
  69void ima_add_violation(struct inode *inode, const unsigned char *filename,
  70                       const char *op, const char *cause)
  71{
  72        struct ima_template_entry *entry;
  73        int violation = 1;
  74        int result;
  75
  76        /* can overflow, only indicator */
  77        atomic_long_inc(&ima_htable.violations);
  78
  79        entry = kmalloc(sizeof(*entry), GFP_KERNEL);
  80        if (!entry) {
  81                result = -ENOMEM;
  82                goto err_out;
  83        }
  84        memset(&entry->template, 0, sizeof(entry->template));
  85        strncpy(entry->template.file_name, filename, IMA_EVENT_NAME_LEN_MAX);
  86        result = ima_store_template(entry, violation, inode);
  87        if (result < 0)
  88                kfree(entry);
  89err_out:
  90        integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
  91                            op, cause, result, 0);
  92}
  93
  94/**
  95 * ima_must_measure - measure decision based on policy.
  96 * @inode: pointer to inode to measure
  97 * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE)
  98 * @function: calling function (PATH_CHECK, BPRM_CHECK, FILE_MMAP)
  99 *
 100 * The policy is defined in terms of keypairs:
 101 *              subj=, obj=, type=, func=, mask=, fsmagic=
 102 *      subj,obj, and type: are LSM specific.
 103 *      func: PATH_CHECK | BPRM_CHECK | FILE_MMAP
 104 *      mask: contains the permission mask
 105 *      fsmagic: hex value
 106 *
 107 * Must be called with iint->mutex held.
 108 *
 109 * Return 0 to measure. Return 1 if already measured.
 110 * For matching a DONT_MEASURE policy, no policy, or other
 111 * error, return an error code.
 112*/
 113int ima_must_measure(struct ima_iint_cache *iint, struct inode *inode,
 114                     int mask, int function)
 115{
 116        int must_measure;
 117
 118        if (iint->flags & IMA_MEASURED)
 119                return 1;
 120
 121        must_measure = ima_match_policy(inode, function, mask);
 122        return must_measure ? 0 : -EACCES;
 123}
 124
 125/*
 126 * ima_collect_measurement - collect file measurement
 127 *
 128 * Calculate the file hash, if it doesn't already exist,
 129 * storing the measurement and i_version in the iint.
 130 *
 131 * Must be called with iint->mutex held.
 132 *
 133 * Return 0 on success, error code otherwise
 134 */
 135int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file)
 136{
 137        int result = -EEXIST;
 138
 139        if (!(iint->flags & IMA_MEASURED)) {
 140                u64 i_version = file->f_dentry->d_inode->i_version;
 141
 142                memset(iint->digest, 0, IMA_DIGEST_SIZE);
 143                result = ima_calc_hash(file, iint->digest);
 144                if (!result)
 145                        iint->version = i_version;
 146        }
 147        return result;
 148}
 149
 150/*
 151 * ima_store_measurement - store file measurement
 152 *
 153 * Create an "ima" template and then store the template by calling
 154 * ima_store_template.
 155 *
 156 * We only get here if the inode has not already been measured,
 157 * but the measurement could already exist:
 158 *      - multiple copies of the same file on either the same or
 159 *        different filesystems.
 160 *      - the inode was previously flushed as well as the iint info,
 161 *        containing the hashing info.
 162 *
 163 * Must be called with iint->mutex held.
 164 */
 165void ima_store_measurement(struct ima_iint_cache *iint, struct file *file,
 166                           const unsigned char *filename)
 167{
 168        const char *op = "add_template_measure";
 169        const char *audit_cause = "ENOMEM";
 170        int result = -ENOMEM;
 171        struct inode *inode = file->f_dentry->d_inode;
 172        struct ima_template_entry *entry;
 173        int violation = 0;
 174
 175        entry = kmalloc(sizeof(*entry), GFP_KERNEL);
 176        if (!entry) {
 177                integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
 178                                    op, audit_cause, result, 0);
 179                return;
 180        }
 181        memset(&entry->template, 0, sizeof(entry->template));
 182        memcpy(entry->template.digest, iint->digest, IMA_DIGEST_SIZE);
 183        strncpy(entry->template.file_name, filename, IMA_EVENT_NAME_LEN_MAX);
 184
 185        result = ima_store_template(entry, violation, inode);
 186        if (!result)
 187                iint->flags |= IMA_MEASURED;
 188        else
 189                kfree(entry);
 190}
 191