linux/security/integrity/ima/ima_template_lib.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2013 Politecnico di Torino, Italy
   3 *                    TORSEC group -- http://security.polito.it
   4 *
   5 * Author: Roberto Sassu <roberto.sassu@polito.it>
   6 *
   7 * This program is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU General Public License as
   9 * published by the Free Software Foundation, version 2 of the
  10 * License.
  11 *
  12 * File: ima_template_lib.c
  13 *      Library of supported template fields.
  14 */
  15#include <crypto/hash_info.h>
  16
  17#include "ima_template_lib.h"
  18
  19static bool ima_template_hash_algo_allowed(u8 algo)
  20{
  21        if (algo == HASH_ALGO_SHA1 || algo == HASH_ALGO_MD5)
  22                return true;
  23
  24        return false;
  25}
  26
  27enum data_formats {
  28        DATA_FMT_DIGEST = 0,
  29        DATA_FMT_DIGEST_WITH_ALGO,
  30        DATA_FMT_STRING,
  31        DATA_FMT_HEX
  32};
  33
  34static int ima_write_template_field_data(const void *data, const u32 datalen,
  35                                         enum data_formats datafmt,
  36                                         struct ima_field_data *field_data)
  37{
  38        u8 *buf, *buf_ptr;
  39        u32 buflen = datalen;
  40
  41        if (datafmt == DATA_FMT_STRING)
  42                buflen = datalen + 1;
  43
  44        buf = kzalloc(buflen, GFP_KERNEL);
  45        if (!buf)
  46                return -ENOMEM;
  47
  48        memcpy(buf, data, datalen);
  49
  50        /*
  51         * Replace all space characters with underscore for event names and
  52         * strings. This avoid that, during the parsing of a measurements list,
  53         * filenames with spaces or that end with the suffix ' (deleted)' are
  54         * split into multiple template fields (the space is the delimitator
  55         * character for measurements lists in ASCII format).
  56         */
  57        if (datafmt == DATA_FMT_STRING) {
  58                for (buf_ptr = buf; buf_ptr - buf < datalen; buf_ptr++)
  59                        if (*buf_ptr == ' ')
  60                                *buf_ptr = '_';
  61        }
  62
  63        field_data->data = buf;
  64        field_data->len = buflen;
  65        return 0;
  66}
  67
  68static void ima_show_template_data_ascii(struct seq_file *m,
  69                                         enum ima_show_type show,
  70                                         enum data_formats datafmt,
  71                                         struct ima_field_data *field_data)
  72{
  73        u8 *buf_ptr = field_data->data, buflen = field_data->len;
  74
  75        switch (datafmt) {
  76        case DATA_FMT_DIGEST_WITH_ALGO:
  77                buf_ptr = strnchr(field_data->data, buflen, ':');
  78                if (buf_ptr != field_data->data)
  79                        seq_printf(m, "%s", field_data->data);
  80
  81                /* skip ':' and '\0' */
  82                buf_ptr += 2;
  83                buflen -= buf_ptr - field_data->data;
  84        case DATA_FMT_DIGEST:
  85        case DATA_FMT_HEX:
  86                if (!buflen)
  87                        break;
  88                ima_print_digest(m, buf_ptr, buflen);
  89                break;
  90        case DATA_FMT_STRING:
  91                seq_printf(m, "%s", buf_ptr);
  92                break;
  93        default:
  94                break;
  95        }
  96}
  97
  98static void ima_show_template_data_binary(struct seq_file *m,
  99                                          enum ima_show_type show,
 100                                          enum data_formats datafmt,
 101                                          struct ima_field_data *field_data)
 102{
 103        u32 len = (show == IMA_SHOW_BINARY_OLD_STRING_FMT) ?
 104            strlen(field_data->data) : field_data->len;
 105
 106        if (show != IMA_SHOW_BINARY_NO_FIELD_LEN)
 107                ima_putc(m, &len, sizeof(len));
 108
 109        if (!len)
 110                return;
 111
 112        ima_putc(m, field_data->data, len);
 113}
 114
 115static void ima_show_template_field_data(struct seq_file *m,
 116                                         enum ima_show_type show,
 117                                         enum data_formats datafmt,
 118                                         struct ima_field_data *field_data)
 119{
 120        switch (show) {
 121        case IMA_SHOW_ASCII:
 122                ima_show_template_data_ascii(m, show, datafmt, field_data);
 123                break;
 124        case IMA_SHOW_BINARY:
 125        case IMA_SHOW_BINARY_NO_FIELD_LEN:
 126        case IMA_SHOW_BINARY_OLD_STRING_FMT:
 127                ima_show_template_data_binary(m, show, datafmt, field_data);
 128                break;
 129        default:
 130                break;
 131        }
 132}
 133
 134void ima_show_template_digest(struct seq_file *m, enum ima_show_type show,
 135                              struct ima_field_data *field_data)
 136{
 137        ima_show_template_field_data(m, show, DATA_FMT_DIGEST, field_data);
 138}
 139
 140void ima_show_template_digest_ng(struct seq_file *m, enum ima_show_type show,
 141                                 struct ima_field_data *field_data)
 142{
 143        ima_show_template_field_data(m, show, DATA_FMT_DIGEST_WITH_ALGO,
 144                                     field_data);
 145}
 146
 147void ima_show_template_string(struct seq_file *m, enum ima_show_type show,
 148                              struct ima_field_data *field_data)
 149{
 150        ima_show_template_field_data(m, show, DATA_FMT_STRING, field_data);
 151}
 152
 153void ima_show_template_sig(struct seq_file *m, enum ima_show_type show,
 154                           struct ima_field_data *field_data)
 155{
 156        ima_show_template_field_data(m, show, DATA_FMT_HEX, field_data);
 157}
 158
 159static int ima_eventdigest_init_common(u8 *digest, u32 digestsize, u8 hash_algo,
 160                                       struct ima_field_data *field_data)
 161{
 162        /*
 163         * digest formats:
 164         *  - DATA_FMT_DIGEST: digest
 165         *  - DATA_FMT_DIGEST_WITH_ALGO: [<hash algo>] + ':' + '\0' + digest,
 166         *    where <hash algo> is provided if the hash algoritm is not
 167         *    SHA1 or MD5
 168         */
 169        u8 buffer[CRYPTO_MAX_ALG_NAME + 2 + IMA_MAX_DIGEST_SIZE] = { 0 };
 170        enum data_formats fmt = DATA_FMT_DIGEST;
 171        u32 offset = 0;
 172
 173        if (hash_algo < HASH_ALGO__LAST) {
 174                fmt = DATA_FMT_DIGEST_WITH_ALGO;
 175                offset += snprintf(buffer, CRYPTO_MAX_ALG_NAME + 1, "%s",
 176                                   hash_algo_name[hash_algo]);
 177                buffer[offset] = ':';
 178                offset += 2;
 179        }
 180
 181        if (digest)
 182                memcpy(buffer + offset, digest, digestsize);
 183        else
 184                /*
 185                 * If digest is NULL, the event being recorded is a violation.
 186                 * Make room for the digest by increasing the offset of
 187                 * IMA_DIGEST_SIZE.
 188                 */
 189                offset += IMA_DIGEST_SIZE;
 190
 191        return ima_write_template_field_data(buffer, offset + digestsize,
 192                                             fmt, field_data);
 193}
 194
 195/*
 196 * This function writes the digest of an event (with size limit).
 197 */
 198int ima_eventdigest_init(struct integrity_iint_cache *iint, struct file *file,
 199                         const unsigned char *filename,
 200                         struct evm_ima_xattr_data *xattr_value, int xattr_len,
 201                         struct ima_field_data *field_data)
 202{
 203        struct {
 204                struct ima_digest_data hdr;
 205                char digest[IMA_MAX_DIGEST_SIZE];
 206        } hash;
 207        u8 *cur_digest = NULL;
 208        u32 cur_digestsize = 0;
 209        struct inode *inode;
 210        int result;
 211
 212        memset(&hash, 0, sizeof(hash));
 213
 214        if (!iint)              /* recording a violation. */
 215                goto out;
 216
 217        if (ima_template_hash_algo_allowed(iint->ima_hash->algo)) {
 218                cur_digest = iint->ima_hash->digest;
 219                cur_digestsize = iint->ima_hash->length;
 220                goto out;
 221        }
 222
 223        if (!file)              /* missing info to re-calculate the digest */
 224                return -EINVAL;
 225
 226        inode = file_inode(file);
 227        hash.hdr.algo = ima_template_hash_algo_allowed(ima_hash_algo) ?
 228            ima_hash_algo : HASH_ALGO_SHA1;
 229        result = ima_calc_file_hash(file, &hash.hdr);
 230        if (result) {
 231                integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
 232                                    filename, "collect_data",
 233                                    "failed", result, 0);
 234                return result;
 235        }
 236        cur_digest = hash.hdr.digest;
 237        cur_digestsize = hash.hdr.length;
 238out:
 239        return ima_eventdigest_init_common(cur_digest, cur_digestsize,
 240                                           HASH_ALGO__LAST, field_data);
 241}
 242
 243/*
 244 * This function writes the digest of an event (without size limit).
 245 */
 246int ima_eventdigest_ng_init(struct integrity_iint_cache *iint,
 247                            struct file *file, const unsigned char *filename,
 248                            struct evm_ima_xattr_data *xattr_value,
 249                            int xattr_len, struct ima_field_data *field_data)
 250{
 251        u8 *cur_digest = NULL, hash_algo = HASH_ALGO_SHA1;
 252        u32 cur_digestsize = 0;
 253
 254        /* If iint is NULL, we are recording a violation. */
 255        if (!iint)
 256                goto out;
 257
 258        cur_digest = iint->ima_hash->digest;
 259        cur_digestsize = iint->ima_hash->length;
 260
 261        hash_algo = iint->ima_hash->algo;
 262out:
 263        return ima_eventdigest_init_common(cur_digest, cur_digestsize,
 264                                           hash_algo, field_data);
 265}
 266
 267static int ima_eventname_init_common(struct integrity_iint_cache *iint,
 268                                     struct file *file,
 269                                     const unsigned char *filename,
 270                                     struct ima_field_data *field_data,
 271                                     bool size_limit)
 272{
 273        const char *cur_filename = NULL;
 274        u32 cur_filename_len = 0;
 275
 276        BUG_ON(filename == NULL && file == NULL);
 277
 278        if (filename) {
 279                cur_filename = filename;
 280                cur_filename_len = strlen(filename);
 281
 282                if (!size_limit || cur_filename_len <= IMA_EVENT_NAME_LEN_MAX)
 283                        goto out;
 284        }
 285
 286        if (file) {
 287                cur_filename = file->f_path.dentry->d_name.name;
 288                cur_filename_len = strlen(cur_filename);
 289        } else
 290                /*
 291                 * Truncate filename if the latter is too long and
 292                 * the file descriptor is not available.
 293                 */
 294                cur_filename_len = IMA_EVENT_NAME_LEN_MAX;
 295out:
 296        return ima_write_template_field_data(cur_filename, cur_filename_len,
 297                                             DATA_FMT_STRING, field_data);
 298}
 299
 300/*
 301 * This function writes the name of an event (with size limit).
 302 */
 303int ima_eventname_init(struct integrity_iint_cache *iint, struct file *file,
 304                       const unsigned char *filename,
 305                       struct evm_ima_xattr_data *xattr_value, int xattr_len,
 306                       struct ima_field_data *field_data)
 307{
 308        return ima_eventname_init_common(iint, file, filename,
 309                                         field_data, true);
 310}
 311
 312/*
 313 * This function writes the name of an event (without size limit).
 314 */
 315int ima_eventname_ng_init(struct integrity_iint_cache *iint, struct file *file,
 316                          const unsigned char *filename,
 317                          struct evm_ima_xattr_data *xattr_value, int xattr_len,
 318                          struct ima_field_data *field_data)
 319{
 320        return ima_eventname_init_common(iint, file, filename,
 321                                         field_data, false);
 322}
 323
 324/*
 325 *  ima_eventsig_init - include the file signature as part of the template data
 326 */
 327int ima_eventsig_init(struct integrity_iint_cache *iint, struct file *file,
 328                      const unsigned char *filename,
 329                      struct evm_ima_xattr_data *xattr_value, int xattr_len,
 330                      struct ima_field_data *field_data)
 331{
 332        enum data_formats fmt = DATA_FMT_HEX;
 333        int rc = 0;
 334
 335        if ((!xattr_value) || (xattr_value->type != EVM_IMA_XATTR_DIGSIG))
 336                goto out;
 337
 338        rc = ima_write_template_field_data(xattr_value, xattr_len, fmt,
 339                                           field_data);
 340out:
 341        return rc;
 342}
 343