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_appraise_or_measure, collect_measurement,
  13 *      appraise_measurement, store_measurement and store_template.
  14 */
  15#include <linux/module.h>
  16#include <linux/slab.h>
  17#include <linux/file.h>
  18#include <linux/fs.h>
  19#include <linux/xattr.h>
  20#include <linux/evm.h>
  21
  22#include "ima.h"
  23
  24/*
  25 * ima_free_template_entry - free an existing template entry
  26 */
  27void ima_free_template_entry(struct ima_template_entry *entry)
  28{
  29        int i;
  30
  31        for (i = 0; i < entry->template_desc->num_fields; i++)
  32                kfree(entry->template_data[i].data);
  33
  34        kfree(entry);
  35}
  36
  37/*
  38 * ima_alloc_init_template - create and initialize a new template entry
  39 */
  40int ima_alloc_init_template(struct ima_event_data *event_data,
  41                            struct ima_template_entry **entry)
  42{
  43        struct ima_template_desc *template_desc = ima_template_desc_current();
  44        int i, result = 0;
  45
  46        *entry = kzalloc(sizeof(**entry) + template_desc->num_fields *
  47                         sizeof(struct ima_field_data), GFP_NOFS);
  48        if (!*entry)
  49                return -ENOMEM;
  50
  51        (*entry)->template_desc = template_desc;
  52        for (i = 0; i < template_desc->num_fields; i++) {
  53                struct ima_template_field *field = template_desc->fields[i];
  54                u32 len;
  55
  56                result = field->field_init(event_data,
  57                                           &((*entry)->template_data[i]));
  58                if (result != 0)
  59                        goto out;
  60
  61                len = (*entry)->template_data[i].len;
  62                (*entry)->template_data_len += sizeof(len);
  63                (*entry)->template_data_len += len;
  64        }
  65        return 0;
  66out:
  67        ima_free_template_entry(*entry);
  68        *entry = NULL;
  69        return result;
  70}
  71
  72/*
  73 * ima_store_template - store ima template measurements
  74 *
  75 * Calculate the hash of a template entry, add the template entry
  76 * to an ordered list of measurement entries maintained inside the kernel,
  77 * and also update the aggregate integrity value (maintained inside the
  78 * configured TPM PCR) over the hashes of the current list of measurement
  79 * entries.
  80 *
  81 * Applications retrieve the current kernel-held measurement list through
  82 * the securityfs entries in /sys/kernel/security/ima. The signed aggregate
  83 * TPM PCR (called quote) can be retrieved using a TPM user space library
  84 * and is used to validate the measurement list.
  85 *
  86 * Returns 0 on success, error code otherwise
  87 */
  88int ima_store_template(struct ima_template_entry *entry,
  89                       int violation, struct inode *inode,
  90                       const unsigned char *filename, int pcr)
  91{
  92        static const char op[] = "add_template_measure";
  93        static const char audit_cause[] = "hashing_error";
  94        char *template_name = entry->template_desc->name;
  95        int result;
  96        struct {
  97                struct ima_digest_data hdr;
  98                char digest[TPM_DIGEST_SIZE];
  99        } hash;
 100
 101        if (!violation) {
 102                int num_fields = entry->template_desc->num_fields;
 103
 104                /* this function uses default algo */
 105                hash.hdr.algo = HASH_ALGO_SHA1;
 106                result = ima_calc_field_array_hash(&entry->template_data[0],
 107                                                   entry->template_desc,
 108                                                   num_fields, &hash.hdr);
 109                if (result < 0) {
 110                        integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode,
 111                                            template_name, op,
 112                                            audit_cause, result, 0);
 113                        return result;
 114                }
 115                memcpy(entry->digest, hash.hdr.digest, hash.hdr.length);
 116        }
 117        entry->pcr = pcr;
 118        result = ima_add_template_entry(entry, violation, op, inode, filename);
 119        return result;
 120}
 121
 122/*
 123 * ima_add_violation - add violation to measurement list.
 124 *
 125 * Violations are flagged in the measurement list with zero hash values.
 126 * By extending the PCR with 0xFF's instead of with zeroes, the PCR
 127 * value is invalidated.
 128 */
 129void ima_add_violation(struct file *file, const unsigned char *filename,
 130                       struct integrity_iint_cache *iint,
 131                       const char *op, const char *cause)
 132{
 133        struct ima_template_entry *entry;
 134        struct inode *inode = file_inode(file);
 135        struct ima_event_data event_data = {iint, file, filename, NULL, 0,
 136                                            cause};
 137        int violation = 1;
 138        int result;
 139
 140        /* can overflow, only indicator */
 141        atomic_long_inc(&ima_htable.violations);
 142
 143        result = ima_alloc_init_template(&event_data, &entry);
 144        if (result < 0) {
 145                result = -ENOMEM;
 146                goto err_out;
 147        }
 148        result = ima_store_template(entry, violation, inode,
 149                                    filename, CONFIG_IMA_MEASURE_PCR_IDX);
 150        if (result < 0)
 151                ima_free_template_entry(entry);
 152err_out:
 153        integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
 154                            op, cause, result, 0);
 155}
 156
 157/**
 158 * ima_get_action - appraise & measure decision based on policy.
 159 * @inode: pointer to inode to measure
 160 * @mask: contains the permission mask (MAY_READ, MAY_WRITE, MAY_EXECUTE)
 161 * @func: caller identifier
 162 * @pcr: pointer filled in if matched measure policy sets pcr=
 163 *
 164 * The policy is defined in terms of keypairs:
 165 *              subj=, obj=, type=, func=, mask=, fsmagic=
 166 *      subj,obj, and type: are LSM specific.
 167 *      func: FILE_CHECK | BPRM_CHECK | MMAP_CHECK | MODULE_CHECK
 168 *      mask: contains the permission mask
 169 *      fsmagic: hex value
 170 *
 171 * Returns IMA_MEASURE, IMA_APPRAISE mask.
 172 *
 173 */
 174int ima_get_action(struct inode *inode, int mask, enum ima_hooks func, int *pcr)
 175{
 176        int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE;
 177
 178        flags &= ima_policy_flag;
 179
 180        return ima_match_policy(inode, func, mask, flags, pcr);
 181}
 182
 183/*
 184 * ima_collect_measurement - collect file measurement
 185 *
 186 * Calculate the file hash, if it doesn't already exist,
 187 * storing the measurement and i_version in the iint.
 188 *
 189 * Must be called with iint->mutex held.
 190 *
 191 * Return 0 on success, error code otherwise
 192 */
 193int ima_collect_measurement(struct integrity_iint_cache *iint,
 194                            struct file *file, void *buf, loff_t size,
 195                            enum hash_algo algo)
 196{
 197        const char *audit_cause = "failed";
 198        struct inode *inode = file_inode(file);
 199        const char *filename = file->f_path.dentry->d_name.name;
 200        int result = 0;
 201        struct {
 202                struct ima_digest_data hdr;
 203                char digest[IMA_MAX_DIGEST_SIZE];
 204        } hash;
 205
 206        if (!(iint->flags & IMA_COLLECTED)) {
 207                u64 i_version = file_inode(file)->i_version;
 208
 209                if (file->f_flags & O_DIRECT) {
 210                        audit_cause = "failed(directio)";
 211                        result = -EACCES;
 212                        goto out;
 213                }
 214
 215                hash.hdr.algo = algo;
 216
 217                result = (!buf) ?  ima_calc_file_hash(file, &hash.hdr) :
 218                        ima_calc_buffer_hash(buf, size, &hash.hdr);
 219                if (!result) {
 220                        int length = sizeof(hash.hdr) + hash.hdr.length;
 221                        void *tmpbuf = krealloc(iint->ima_hash, length,
 222                                                GFP_NOFS);
 223                        if (tmpbuf) {
 224                                iint->ima_hash = tmpbuf;
 225                                memcpy(iint->ima_hash, &hash, length);
 226                                iint->version = i_version;
 227                                iint->flags |= IMA_COLLECTED;
 228                        } else
 229                                result = -ENOMEM;
 230                }
 231        }
 232out:
 233        if (result)
 234                integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
 235                                    filename, "collect_data", audit_cause,
 236                                    result, 0);
 237        return result;
 238}
 239
 240/*
 241 * ima_store_measurement - store file measurement
 242 *
 243 * Create an "ima" template and then store the template by calling
 244 * ima_store_template.
 245 *
 246 * We only get here if the inode has not already been measured,
 247 * but the measurement could already exist:
 248 *      - multiple copies of the same file on either the same or
 249 *        different filesystems.
 250 *      - the inode was previously flushed as well as the iint info,
 251 *        containing the hashing info.
 252 *
 253 * Must be called with iint->mutex held.
 254 */
 255void ima_store_measurement(struct integrity_iint_cache *iint,
 256                           struct file *file, const unsigned char *filename,
 257                           struct evm_ima_xattr_data *xattr_value,
 258                           int xattr_len, int pcr)
 259{
 260        static const char op[] = "add_template_measure";
 261        static const char audit_cause[] = "ENOMEM";
 262        int result = -ENOMEM;
 263        struct inode *inode = file_inode(file);
 264        struct ima_template_entry *entry;
 265        struct ima_event_data event_data = {iint, file, filename, xattr_value,
 266                                            xattr_len, NULL};
 267        int violation = 0;
 268
 269        if (iint->measured_pcrs & (0x1 << pcr))
 270                return;
 271
 272        result = ima_alloc_init_template(&event_data, &entry);
 273        if (result < 0) {
 274                integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
 275                                    op, audit_cause, result, 0);
 276                return;
 277        }
 278
 279        result = ima_store_template(entry, violation, inode, filename, pcr);
 280        if (!result || result == -EEXIST) {
 281                iint->flags |= IMA_MEASURED;
 282                iint->measured_pcrs |= (0x1 << pcr);
 283        }
 284        if (result < 0)
 285                ima_free_template_entry(entry);
 286}
 287
 288void ima_audit_measurement(struct integrity_iint_cache *iint,
 289                           const unsigned char *filename)
 290{
 291        struct audit_buffer *ab;
 292        char hash[(iint->ima_hash->length * 2) + 1];
 293        const char *algo_name = hash_algo_name[iint->ima_hash->algo];
 294        char algo_hash[sizeof(hash) + strlen(algo_name) + 2];
 295        int i;
 296
 297        if (iint->flags & IMA_AUDITED)
 298                return;
 299
 300        for (i = 0; i < iint->ima_hash->length; i++)
 301                hex_byte_pack(hash + (i * 2), iint->ima_hash->digest[i]);
 302        hash[i * 2] = '\0';
 303
 304        ab = audit_log_start(current->audit_context, GFP_KERNEL,
 305                             AUDIT_INTEGRITY_RULE);
 306        if (!ab)
 307                return;
 308
 309        audit_log_format(ab, "file=");
 310        audit_log_untrustedstring(ab, filename);
 311        audit_log_format(ab, " hash=");
 312        snprintf(algo_hash, sizeof(algo_hash), "%s:%s", algo_name, hash);
 313        audit_log_untrustedstring(ab, algo_hash);
 314
 315        audit_log_task_info(ab, current);
 316        audit_log_end(ab);
 317
 318        iint->flags |= IMA_AUDITED;
 319}
 320
 321const char *ima_d_path(const struct path *path, char **pathbuf)
 322{
 323        char *pathname = NULL;
 324
 325        *pathbuf = __getname();
 326        if (*pathbuf) {
 327                pathname = d_absolute_path(path, *pathbuf, PATH_MAX);
 328                if (IS_ERR(pathname)) {
 329                        __putname(*pathbuf);
 330                        *pathbuf = NULL;
 331                        pathname = NULL;
 332                }
 333        }
 334        return pathname ?: (const char *)path->dentry->d_name.name;
 335}
 336