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;
  74        u32 buflen = field_data->len;
  75
  76        switch (datafmt) {
  77        case DATA_FMT_DIGEST_WITH_ALGO:
  78                buf_ptr = strnchr(field_data->data, buflen, ':');
  79                if (buf_ptr != field_data->data)
  80                        seq_printf(m, "%s", field_data->data);
  81
  82                /* skip ':' and '\0' */
  83                buf_ptr += 2;
  84                buflen -= buf_ptr - field_data->data;
  85        case DATA_FMT_DIGEST:
  86        case DATA_FMT_HEX:
  87                if (!buflen)
  88                        break;
  89                ima_print_digest(m, buf_ptr, buflen);
  90                break;
  91        case DATA_FMT_STRING:
  92                seq_printf(m, "%s", buf_ptr);
  93                break;
  94        default:
  95                break;
  96        }
  97}
  98
  99static void ima_show_template_data_binary(struct seq_file *m,
 100                                          enum ima_show_type show,
 101                                          enum data_formats datafmt,
 102                                          struct ima_field_data *field_data)
 103{
 104        u32 len = (show == IMA_SHOW_BINARY_OLD_STRING_FMT) ?
 105            strlen(field_data->data) : field_data->len;
 106
 107        if (show != IMA_SHOW_BINARY_NO_FIELD_LEN)
 108                ima_putc(m, &len, sizeof(len));
 109
 110        if (!len)
 111                return;
 112
 113        ima_putc(m, field_data->data, len);
 114}
 115
 116static void ima_show_template_field_data(struct seq_file *m,
 117                                         enum ima_show_type show,
 118                                         enum data_formats datafmt,
 119                                         struct ima_field_data *field_data)
 120{
 121        switch (show) {
 122        case IMA_SHOW_ASCII:
 123                ima_show_template_data_ascii(m, show, datafmt, field_data);
 124                break;
 125        case IMA_SHOW_BINARY:
 126        case IMA_SHOW_BINARY_NO_FIELD_LEN:
 127        case IMA_SHOW_BINARY_OLD_STRING_FMT:
 128                ima_show_template_data_binary(m, show, datafmt, field_data);
 129                break;
 130        default:
 131                break;
 132        }
 133}
 134
 135void ima_show_template_digest(struct seq_file *m, enum ima_show_type show,
 136                              struct ima_field_data *field_data)
 137{
 138        ima_show_template_field_data(m, show, DATA_FMT_DIGEST, field_data);
 139}
 140
 141void ima_show_template_digest_ng(struct seq_file *m, enum ima_show_type show,
 142                                 struct ima_field_data *field_data)
 143{
 144        ima_show_template_field_data(m, show, DATA_FMT_DIGEST_WITH_ALGO,
 145                                     field_data);
 146}
 147
 148void ima_show_template_string(struct seq_file *m, enum ima_show_type show,
 149                              struct ima_field_data *field_data)
 150{
 151        ima_show_template_field_data(m, show, DATA_FMT_STRING, field_data);
 152}
 153
 154void ima_show_template_sig(struct seq_file *m, enum ima_show_type show,
 155                           struct ima_field_data *field_data)
 156{
 157        ima_show_template_field_data(m, show, DATA_FMT_HEX, field_data);
 158}
 159
 160static int ima_eventdigest_init_common(u8 *digest, u32 digestsize, u8 hash_algo,
 161                                       struct ima_field_data *field_data)
 162{
 163        /*
 164         * digest formats:
 165         *  - DATA_FMT_DIGEST: digest
 166         *  - DATA_FMT_DIGEST_WITH_ALGO: [<hash algo>] + ':' + '\0' + digest,
 167         *    where <hash algo> is provided if the hash algoritm is not
 168         *    SHA1 or MD5
 169         */
 170        u8 buffer[CRYPTO_MAX_ALG_NAME + 2 + IMA_MAX_DIGEST_SIZE] = { 0 };
 171        enum data_formats fmt = DATA_FMT_DIGEST;
 172        u32 offset = 0;
 173
 174        if (hash_algo < HASH_ALGO__LAST) {
 175                fmt = DATA_FMT_DIGEST_WITH_ALGO;
 176                offset += snprintf(buffer, CRYPTO_MAX_ALG_NAME + 1, "%s",
 177                                   hash_algo_name[hash_algo]);
 178                buffer[offset] = ':';
 179                offset += 2;
 180        }
 181
 182        if (digest)
 183                memcpy(buffer + offset, digest, digestsize);
 184        else
 185                /*
 186                 * If digest is NULL, the event being recorded is a violation.
 187                 * Make room for the digest by increasing the offset of
 188                 * IMA_DIGEST_SIZE.
 189                 */
 190                offset += IMA_DIGEST_SIZE;
 191
 192        return ima_write_template_field_data(buffer, offset + digestsize,
 193                                             fmt, field_data);
 194}
 195
 196/*
 197 * This function writes the digest of an event (with size limit).
 198 */
 199int ima_eventdigest_init(struct ima_event_data *event_data,
 200                         struct ima_field_data *field_data)
 201{
 202        struct {
 203                struct ima_digest_data hdr;
 204                char digest[IMA_MAX_DIGEST_SIZE];
 205        } hash;
 206        u8 *cur_digest = NULL;
 207        u32 cur_digestsize = 0;
 208        struct inode *inode;
 209        int result;
 210
 211        memset(&hash, 0, sizeof(hash));
 212
 213        if (event_data->violation)      /* recording a violation. */
 214                goto out;
 215
 216        if (ima_template_hash_algo_allowed(event_data->iint->ima_hash->algo)) {
 217                cur_digest = event_data->iint->ima_hash->digest;
 218                cur_digestsize = event_data->iint->ima_hash->length;
 219                goto out;
 220        }
 221
 222        if (!event_data->file)  /* missing info to re-calculate the digest */
 223                return -EINVAL;
 224
 225        inode = file_inode(event_data->file);
 226        hash.hdr.algo = ima_template_hash_algo_allowed(ima_hash_algo) ?
 227            ima_hash_algo : HASH_ALGO_SHA1;
 228        result = ima_calc_file_hash(event_data->file, &hash.hdr);
 229        if (result) {
 230                integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
 231                                    event_data->filename, "collect_data",
 232                                    "failed", result, 0);
 233                return result;
 234        }
 235        cur_digest = hash.hdr.digest;
 236        cur_digestsize = hash.hdr.length;
 237out:
 238        return ima_eventdigest_init_common(cur_digest, cur_digestsize,
 239                                           HASH_ALGO__LAST, field_data);
 240}
 241
 242/*
 243 * This function writes the digest of an event (without size limit).
 244 */
 245int ima_eventdigest_ng_init(struct ima_event_data *event_data,
 246                            struct ima_field_data *field_data)
 247{
 248        u8 *cur_digest = NULL, hash_algo = HASH_ALGO_SHA1;
 249        u32 cur_digestsize = 0;
 250
 251        if (event_data->violation)      /* recording a violation. */
 252                goto out;
 253
 254        cur_digest = event_data->iint->ima_hash->digest;
 255        cur_digestsize = event_data->iint->ima_hash->length;
 256
 257        hash_algo = event_data->iint->ima_hash->algo;
 258out:
 259        return ima_eventdigest_init_common(cur_digest, cur_digestsize,
 260                                           hash_algo, field_data);
 261}
 262
 263static int ima_eventname_init_common(struct ima_event_data *event_data,
 264                                     struct ima_field_data *field_data,
 265                                     bool size_limit)
 266{
 267        const char *cur_filename = NULL;
 268        u32 cur_filename_len = 0;
 269
 270        BUG_ON(event_data->filename == NULL && event_data->file == NULL);
 271
 272        if (event_data->filename) {
 273                cur_filename = event_data->filename;
 274                cur_filename_len = strlen(event_data->filename);
 275
 276                if (!size_limit || cur_filename_len <= IMA_EVENT_NAME_LEN_MAX)
 277                        goto out;
 278        }
 279
 280        if (event_data->file) {
 281                cur_filename = event_data->file->f_path.dentry->d_name.name;
 282                cur_filename_len = strlen(cur_filename);
 283        } else
 284                /*
 285                 * Truncate filename if the latter is too long and
 286                 * the file descriptor is not available.
 287                 */
 288                cur_filename_len = IMA_EVENT_NAME_LEN_MAX;
 289out:
 290        return ima_write_template_field_data(cur_filename, cur_filename_len,
 291                                             DATA_FMT_STRING, field_data);
 292}
 293
 294/*
 295 * This function writes the name of an event (with size limit).
 296 */
 297int ima_eventname_init(struct ima_event_data *event_data,
 298                       struct ima_field_data *field_data)
 299{
 300        return ima_eventname_init_common(event_data, field_data, true);
 301}
 302
 303/*
 304 * This function writes the name of an event (without size limit).
 305 */
 306int ima_eventname_ng_init(struct ima_event_data *event_data,
 307                          struct ima_field_data *field_data)
 308{
 309        return ima_eventname_init_common(event_data, field_data, false);
 310}
 311
 312/*
 313 *  ima_eventsig_init - include the file signature as part of the template data
 314 */
 315int ima_eventsig_init(struct ima_event_data *event_data,
 316                      struct ima_field_data *field_data)
 317{
 318        enum data_formats fmt = DATA_FMT_HEX;
 319        struct evm_ima_xattr_data *xattr_value = event_data->xattr_value;
 320        int xattr_len = event_data->xattr_len;
 321        int rc = 0;
 322
 323        if ((!xattr_value) || (xattr_value->type != EVM_IMA_XATTR_DIGSIG))
 324                goto out;
 325
 326        rc = ima_write_template_field_data(xattr_value, xattr_len, fmt,
 327                                           field_data);
 328out:
 329        return rc;
 330}
 331