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
  16#include "ima_template_lib.h"
  17
  18static bool ima_template_hash_algo_allowed(u8 algo)
  19{
  20        if (algo == HASH_ALGO_SHA1 || algo == HASH_ALGO_MD5)
  21                return true;
  22
  23        return false;
  24}
  25
  26enum data_formats {
  27        DATA_FMT_DIGEST = 0,
  28        DATA_FMT_DIGEST_WITH_ALGO,
  29        DATA_FMT_STRING,
  30        DATA_FMT_HEX
  31};
  32
  33static int ima_write_template_field_data(const void *data, const u32 datalen,
  34                                         enum data_formats datafmt,
  35                                         struct ima_field_data *field_data)
  36{
  37        u8 *buf, *buf_ptr;
  38        u32 buflen = datalen;
  39
  40        if (datafmt == DATA_FMT_STRING)
  41                buflen = datalen + 1;
  42
  43        buf = kzalloc(buflen, GFP_KERNEL);
  44        if (!buf)
  45                return -ENOMEM;
  46
  47        memcpy(buf, data, datalen);
  48
  49        /*
  50         * Replace all space characters with underscore for event names and
  51         * strings. This avoid that, during the parsing of a measurements list,
  52         * filenames with spaces or that end with the suffix ' (deleted)' are
  53         * split into multiple template fields (the space is the delimitator
  54         * character for measurements lists in ASCII format).
  55         */
  56        if (datafmt == DATA_FMT_STRING) {
  57                for (buf_ptr = buf; buf_ptr - buf < datalen; buf_ptr++)
  58                        if (*buf_ptr == ' ')
  59                                *buf_ptr = '_';
  60        }
  61
  62        field_data->data = buf;
  63        field_data->len = buflen;
  64        return 0;
  65}
  66
  67static void ima_show_template_data_ascii(struct seq_file *m,
  68                                         enum ima_show_type show,
  69                                         enum data_formats datafmt,
  70                                         struct ima_field_data *field_data)
  71{
  72        u8 *buf_ptr = field_data->data;
  73        u32 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 ima_event_data *event_data,
 199                         struct ima_field_data *field_data)
 200{
 201        struct {
 202                struct ima_digest_data hdr;
 203                char digest[IMA_MAX_DIGEST_SIZE];
 204        } hash;
 205        u8 *cur_digest = NULL;
 206        u32 cur_digestsize = 0;
 207        struct inode *inode;
 208        int result;
 209
 210        memset(&hash, 0, sizeof(hash));
 211
 212        if (event_data->violation)      /* recording a violation. */
 213                goto out;
 214
 215        if (ima_template_hash_algo_allowed(event_data->iint->ima_hash->algo)) {
 216                cur_digest = event_data->iint->ima_hash->digest;
 217                cur_digestsize = event_data->iint->ima_hash->length;
 218                goto out;
 219        }
 220
 221        if (!event_data->file)  /* missing info to re-calculate the digest */
 222                return -EINVAL;
 223
 224        inode = file_inode(event_data->file);
 225        hash.hdr.algo = ima_template_hash_algo_allowed(ima_hash_algo) ?
 226            ima_hash_algo : HASH_ALGO_SHA1;
 227        result = ima_calc_file_hash(event_data->file, &hash.hdr);
 228        if (result) {
 229                integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
 230                                    event_data->filename, "collect_data",
 231                                    "failed", result, 0);
 232                return result;
 233        }
 234        cur_digest = hash.hdr.digest;
 235        cur_digestsize = hash.hdr.length;
 236out:
 237        return ima_eventdigest_init_common(cur_digest, cur_digestsize,
 238                                           HASH_ALGO__LAST, field_data);
 239}
 240
 241/*
 242 * This function writes the digest of an event (without size limit).
 243 */
 244int ima_eventdigest_ng_init(struct ima_event_data *event_data,
 245                            struct ima_field_data *field_data)
 246{
 247        u8 *cur_digest = NULL, hash_algo = HASH_ALGO_SHA1;
 248        u32 cur_digestsize = 0;
 249
 250        if (event_data->violation)      /* recording a violation. */
 251                goto out;
 252
 253        cur_digest = event_data->iint->ima_hash->digest;
 254        cur_digestsize = event_data->iint->ima_hash->length;
 255
 256        hash_algo = event_data->iint->ima_hash->algo;
 257out:
 258        return ima_eventdigest_init_common(cur_digest, cur_digestsize,
 259                                           hash_algo, field_data);
 260}
 261
 262static int ima_eventname_init_common(struct ima_event_data *event_data,
 263                                     struct ima_field_data *field_data,
 264                                     bool size_limit)
 265{
 266        const char *cur_filename = NULL;
 267        u32 cur_filename_len = 0;
 268
 269        BUG_ON(event_data->filename == NULL && event_data->file == NULL);
 270
 271        if (event_data->filename) {
 272                cur_filename = event_data->filename;
 273                cur_filename_len = strlen(event_data->filename);
 274
 275                if (!size_limit || cur_filename_len <= IMA_EVENT_NAME_LEN_MAX)
 276                        goto out;
 277        }
 278
 279        if (event_data->file) {
 280                cur_filename = event_data->file->f_path.dentry->d_name.name;
 281                cur_filename_len = strlen(cur_filename);
 282        } else
 283                /*
 284                 * Truncate filename if the latter is too long and
 285                 * the file descriptor is not available.
 286                 */
 287                cur_filename_len = IMA_EVENT_NAME_LEN_MAX;
 288out:
 289        return ima_write_template_field_data(cur_filename, cur_filename_len,
 290                                             DATA_FMT_STRING, field_data);
 291}
 292
 293/*
 294 * This function writes the name of an event (with size limit).
 295 */
 296int ima_eventname_init(struct ima_event_data *event_data,
 297                       struct ima_field_data *field_data)
 298{
 299        return ima_eventname_init_common(event_data, field_data, true);
 300}
 301
 302/*
 303 * This function writes the name of an event (without size limit).
 304 */
 305int ima_eventname_ng_init(struct ima_event_data *event_data,
 306                          struct ima_field_data *field_data)
 307{
 308        return ima_eventname_init_common(event_data, field_data, false);
 309}
 310
 311/*
 312 *  ima_eventsig_init - include the file signature as part of the template data
 313 */
 314int ima_eventsig_init(struct ima_event_data *event_data,
 315                      struct ima_field_data *field_data)
 316{
 317        enum data_formats fmt = DATA_FMT_HEX;
 318        struct evm_ima_xattr_data *xattr_value = event_data->xattr_value;
 319        int xattr_len = event_data->xattr_len;
 320        int rc = 0;
 321
 322        if ((!xattr_value) || (xattr_value->type != EVM_IMA_XATTR_DIGSIG))
 323                goto out;
 324
 325        rc = ima_write_template_field_data(xattr_value, xattr_len, fmt,
 326                                           field_data);
 327out:
 328        return rc;
 329}
 330