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_EXEC,
 161 *        MAY_APPEND)
 162 * @func: caller identifier
 163 * @pcr: pointer filled in if matched measure policy sets pcr=
 164 *
 165 * The policy is defined in terms of keypairs:
 166 *              subj=, obj=, type=, func=, mask=, fsmagic=
 167 *      subj,obj, and type: are LSM specific.
 168 *      func: FILE_CHECK | BPRM_CHECK | MMAP_CHECK | MODULE_CHECK
 169 *      mask: contains the permission mask
 170 *      fsmagic: hex value
 171 *
 172 * Returns IMA_MEASURE, IMA_APPRAISE mask.
 173 *
 174 */
 175int ima_get_action(struct inode *inode, int mask, enum ima_hooks func, int *pcr)
 176{
 177        int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE;
 178
 179        flags &= ima_policy_flag;
 180
 181        return ima_match_policy(inode, func, mask, flags, pcr);
 182}
 183
 184/*
 185 * ima_collect_measurement - collect file measurement
 186 *
 187 * Calculate the file hash, if it doesn't already exist,
 188 * storing the measurement and i_version in the iint.
 189 *
 190 * Must be called with iint->mutex held.
 191 *
 192 * Return 0 on success, error code otherwise
 193 */
 194int ima_collect_measurement(struct integrity_iint_cache *iint,
 195                            struct file *file, void *buf, loff_t size,
 196                            enum hash_algo algo)
 197{
 198        const char *audit_cause = "failed";
 199        struct inode *inode = file_inode(file);
 200        const char *filename = file->f_path.dentry->d_name.name;
 201        int result = 0;
 202        struct {
 203                struct ima_digest_data hdr;
 204                char digest[IMA_MAX_DIGEST_SIZE];
 205        } hash;
 206
 207        if (!(iint->flags & IMA_COLLECTED)) {
 208                u64 i_version = file_inode(file)->i_version;
 209
 210                if (file->f_flags & O_DIRECT) {
 211                        audit_cause = "failed(directio)";
 212                        result = -EACCES;
 213                        goto out;
 214                }
 215
 216                hash.hdr.algo = algo;
 217
 218                result = (!buf) ?  ima_calc_file_hash(file, &hash.hdr) :
 219                        ima_calc_buffer_hash(buf, size, &hash.hdr);
 220                if (!result) {
 221                        int length = sizeof(hash.hdr) + hash.hdr.length;
 222                        void *tmpbuf = krealloc(iint->ima_hash, length,
 223                                                GFP_NOFS);
 224                        if (tmpbuf) {
 225                                iint->ima_hash = tmpbuf;
 226                                memcpy(iint->ima_hash, &hash, length);
 227                                iint->version = i_version;
 228                                iint->flags |= IMA_COLLECTED;
 229                        } else
 230                                result = -ENOMEM;
 231                }
 232        }
 233out:
 234        if (result)
 235                integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
 236                                    filename, "collect_data", audit_cause,
 237                                    result, 0);
 238        return result;
 239}
 240
 241/*
 242 * ima_store_measurement - store file measurement
 243 *
 244 * Create an "ima" template and then store the template by calling
 245 * ima_store_template.
 246 *
 247 * We only get here if the inode has not already been measured,
 248 * but the measurement could already exist:
 249 *      - multiple copies of the same file on either the same or
 250 *        different filesystems.
 251 *      - the inode was previously flushed as well as the iint info,
 252 *        containing the hashing info.
 253 *
 254 * Must be called with iint->mutex held.
 255 */
 256void ima_store_measurement(struct integrity_iint_cache *iint,
 257                           struct file *file, const unsigned char *filename,
 258                           struct evm_ima_xattr_data *xattr_value,
 259                           int xattr_len, int pcr)
 260{
 261        static const char op[] = "add_template_measure";
 262        static const char audit_cause[] = "ENOMEM";
 263        int result = -ENOMEM;
 264        struct inode *inode = file_inode(file);
 265        struct ima_template_entry *entry;
 266        struct ima_event_data event_data = {iint, file, filename, xattr_value,
 267                                            xattr_len, NULL};
 268        int violation = 0;
 269
 270        if (iint->measured_pcrs & (0x1 << pcr))
 271                return;
 272
 273        result = ima_alloc_init_template(&event_data, &entry);
 274        if (result < 0) {
 275                integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
 276                                    op, audit_cause, result, 0);
 277                return;
 278        }
 279
 280        result = ima_store_template(entry, violation, inode, filename, pcr);
 281        if (!result || result == -EEXIST) {
 282                iint->flags |= IMA_MEASURED;
 283                iint->measured_pcrs |= (0x1 << pcr);
 284        }
 285        if (result < 0)
 286                ima_free_template_entry(entry);
 287}
 288
 289void ima_audit_measurement(struct integrity_iint_cache *iint,
 290                           const unsigned char *filename)
 291{
 292        struct audit_buffer *ab;
 293        char hash[(iint->ima_hash->length * 2) + 1];
 294        const char *algo_name = hash_algo_name[iint->ima_hash->algo];
 295        char algo_hash[sizeof(hash) + strlen(algo_name) + 2];
 296        int i;
 297
 298        if (iint->flags & IMA_AUDITED)
 299                return;
 300
 301        for (i = 0; i < iint->ima_hash->length; i++)
 302                hex_byte_pack(hash + (i * 2), iint->ima_hash->digest[i]);
 303        hash[i * 2] = '\0';
 304
 305        ab = audit_log_start(current->audit_context, GFP_KERNEL,
 306                             AUDIT_INTEGRITY_RULE);
 307        if (!ab)
 308                return;
 309
 310        audit_log_format(ab, "file=");
 311        audit_log_untrustedstring(ab, filename);
 312        audit_log_format(ab, " hash=");
 313        snprintf(algo_hash, sizeof(algo_hash), "%s:%s", algo_name, hash);
 314        audit_log_untrustedstring(ab, algo_hash);
 315
 316        audit_log_task_info(ab, current);
 317        audit_log_end(ab);
 318
 319        iint->flags |= IMA_AUDITED;
 320}
 321
 322/*
 323 * ima_d_path - return a pointer to the full pathname
 324 *
 325 * Attempt to return a pointer to the full pathname for use in the
 326 * IMA measurement list, IMA audit records, and auditing logs.
 327 *
 328 * On failure, return a pointer to a copy of the filename, not dname.
 329 * Returning a pointer to dname, could result in using the pointer
 330 * after the memory has been freed.
 331 */
 332const char *ima_d_path(const struct path *path, char **pathbuf, char *namebuf)
 333{
 334        char *pathname = NULL;
 335
 336        *pathbuf = __getname();
 337        if (*pathbuf) {
 338                pathname = d_absolute_path(path, *pathbuf, PATH_MAX);
 339                if (IS_ERR(pathname)) {
 340                        __putname(*pathbuf);
 341                        *pathbuf = NULL;
 342                        pathname = NULL;
 343                }
 344        }
 345
 346        if (!pathname) {
 347                strlcpy(namebuf, path->dentry->d_name.name, NAME_MAX);
 348                pathname = namebuf;
 349        }
 350
 351        return pathname;
 352}
 353