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