linux/security/integrity/ima/ima_template_lib.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2013 Politecnico di Torino, Italy
   4 *                    TORSEC group -- https://security.polito.it
   5 *
   6 * Author: Roberto Sassu <roberto.sassu@polito.it>
   7 *
   8 * File: ima_template_lib.c
   9 *      Library of supported template fields.
  10 */
  11
  12#include "ima_template_lib.h"
  13
  14static bool ima_template_hash_algo_allowed(u8 algo)
  15{
  16        if (algo == HASH_ALGO_SHA1 || algo == HASH_ALGO_MD5)
  17                return true;
  18
  19        return false;
  20}
  21
  22enum data_formats {
  23        DATA_FMT_DIGEST = 0,
  24        DATA_FMT_DIGEST_WITH_ALGO,
  25        DATA_FMT_STRING,
  26        DATA_FMT_HEX
  27};
  28
  29static int ima_write_template_field_data(const void *data, const u32 datalen,
  30                                         enum data_formats datafmt,
  31                                         struct ima_field_data *field_data)
  32{
  33        u8 *buf, *buf_ptr;
  34        u32 buflen = datalen;
  35
  36        if (datafmt == DATA_FMT_STRING)
  37                buflen = datalen + 1;
  38
  39        buf = kzalloc(buflen, GFP_KERNEL);
  40        if (!buf)
  41                return -ENOMEM;
  42
  43        memcpy(buf, data, datalen);
  44
  45        /*
  46         * Replace all space characters with underscore for event names and
  47         * strings. This avoid that, during the parsing of a measurements list,
  48         * filenames with spaces or that end with the suffix ' (deleted)' are
  49         * split into multiple template fields (the space is the delimitator
  50         * character for measurements lists in ASCII format).
  51         */
  52        if (datafmt == DATA_FMT_STRING) {
  53                for (buf_ptr = buf; buf_ptr - buf < datalen; buf_ptr++)
  54                        if (*buf_ptr == ' ')
  55                                *buf_ptr = '_';
  56        }
  57
  58        field_data->data = buf;
  59        field_data->len = buflen;
  60        return 0;
  61}
  62
  63static void ima_show_template_data_ascii(struct seq_file *m,
  64                                         enum ima_show_type show,
  65                                         enum data_formats datafmt,
  66                                         struct ima_field_data *field_data)
  67{
  68        u8 *buf_ptr = field_data->data;
  69        u32 buflen = field_data->len;
  70
  71        switch (datafmt) {
  72        case DATA_FMT_DIGEST_WITH_ALGO:
  73                buf_ptr = strnchr(field_data->data, buflen, ':');
  74                if (buf_ptr != field_data->data)
  75                        seq_printf(m, "%s", field_data->data);
  76
  77                /* skip ':' and '\0' */
  78                buf_ptr += 2;
  79                buflen -= buf_ptr - field_data->data;
  80                fallthrough;
  81        case DATA_FMT_DIGEST:
  82        case DATA_FMT_HEX:
  83                if (!buflen)
  84                        break;
  85                ima_print_digest(m, buf_ptr, buflen);
  86                break;
  87        case DATA_FMT_STRING:
  88                seq_printf(m, "%s", buf_ptr);
  89                break;
  90        default:
  91                break;
  92        }
  93}
  94
  95static void ima_show_template_data_binary(struct seq_file *m,
  96                                          enum ima_show_type show,
  97                                          enum data_formats datafmt,
  98                                          struct ima_field_data *field_data)
  99{
 100        u32 len = (show == IMA_SHOW_BINARY_OLD_STRING_FMT) ?
 101            strlen(field_data->data) : field_data->len;
 102
 103        if (show != IMA_SHOW_BINARY_NO_FIELD_LEN) {
 104                u32 field_len = !ima_canonical_fmt ? len : cpu_to_le32(len);
 105
 106                ima_putc(m, &field_len, sizeof(field_len));
 107        }
 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
 159void ima_show_template_buf(struct seq_file *m, enum ima_show_type show,
 160                           struct ima_field_data *field_data)
 161{
 162        ima_show_template_field_data(m, show, DATA_FMT_HEX, field_data);
 163}
 164
 165/**
 166 * ima_parse_buf() - Parses lengths and data from an input buffer
 167 * @bufstartp:       Buffer start address.
 168 * @bufendp:         Buffer end address.
 169 * @bufcurp:         Pointer to remaining (non-parsed) data.
 170 * @maxfields:       Length of fields array.
 171 * @fields:          Array containing lengths and pointers of parsed data.
 172 * @curfields:       Number of array items containing parsed data.
 173 * @len_mask:        Bitmap (if bit is set, data length should not be parsed).
 174 * @enforce_mask:    Check if curfields == maxfields and/or bufcurp == bufendp.
 175 * @bufname:         String identifier of the input buffer.
 176 *
 177 * Return: 0 on success, -EINVAL on error.
 178 */
 179int ima_parse_buf(void *bufstartp, void *bufendp, void **bufcurp,
 180                  int maxfields, struct ima_field_data *fields, int *curfields,
 181                  unsigned long *len_mask, int enforce_mask, char *bufname)
 182{
 183        void *bufp = bufstartp;
 184        int i;
 185
 186        for (i = 0; i < maxfields; i++) {
 187                if (len_mask == NULL || !test_bit(i, len_mask)) {
 188                        if (bufp > (bufendp - sizeof(u32)))
 189                                break;
 190
 191                        fields[i].len = *(u32 *)bufp;
 192                        if (ima_canonical_fmt)
 193                                fields[i].len = le32_to_cpu(fields[i].len);
 194
 195                        bufp += sizeof(u32);
 196                }
 197
 198                if (bufp > (bufendp - fields[i].len))
 199                        break;
 200
 201                fields[i].data = bufp;
 202                bufp += fields[i].len;
 203        }
 204
 205        if ((enforce_mask & ENFORCE_FIELDS) && i != maxfields) {
 206                pr_err("%s: nr of fields mismatch: expected: %d, current: %d\n",
 207                       bufname, maxfields, i);
 208                return -EINVAL;
 209        }
 210
 211        if ((enforce_mask & ENFORCE_BUFEND) && bufp != bufendp) {
 212                pr_err("%s: buf end mismatch: expected: %p, current: %p\n",
 213                       bufname, bufendp, bufp);
 214                return -EINVAL;
 215        }
 216
 217        if (curfields)
 218                *curfields = i;
 219
 220        if (bufcurp)
 221                *bufcurp = bufp;
 222
 223        return 0;
 224}
 225
 226static int ima_eventdigest_init_common(const u8 *digest, u32 digestsize,
 227                                       u8 hash_algo,
 228                                       struct ima_field_data *field_data)
 229{
 230        /*
 231         * digest formats:
 232         *  - DATA_FMT_DIGEST: digest
 233         *  - DATA_FMT_DIGEST_WITH_ALGO: [<hash algo>] + ':' + '\0' + digest,
 234         *    where <hash algo> is provided if the hash algoritm is not
 235         *    SHA1 or MD5
 236         */
 237        u8 buffer[CRYPTO_MAX_ALG_NAME + 2 + IMA_MAX_DIGEST_SIZE] = { 0 };
 238        enum data_formats fmt = DATA_FMT_DIGEST;
 239        u32 offset = 0;
 240
 241        if (hash_algo < HASH_ALGO__LAST) {
 242                fmt = DATA_FMT_DIGEST_WITH_ALGO;
 243                offset += snprintf(buffer, CRYPTO_MAX_ALG_NAME + 1, "%s",
 244                                   hash_algo_name[hash_algo]);
 245                buffer[offset] = ':';
 246                offset += 2;
 247        }
 248
 249        if (digest)
 250                memcpy(buffer + offset, digest, digestsize);
 251        else
 252                /*
 253                 * If digest is NULL, the event being recorded is a violation.
 254                 * Make room for the digest by increasing the offset of
 255                 * IMA_DIGEST_SIZE.
 256                 */
 257                offset += IMA_DIGEST_SIZE;
 258
 259        return ima_write_template_field_data(buffer, offset + digestsize,
 260                                             fmt, field_data);
 261}
 262
 263/*
 264 * This function writes the digest of an event (with size limit).
 265 */
 266int ima_eventdigest_init(struct ima_event_data *event_data,
 267                         struct ima_field_data *field_data)
 268{
 269        struct {
 270                struct ima_digest_data hdr;
 271                char digest[IMA_MAX_DIGEST_SIZE];
 272        } hash;
 273        u8 *cur_digest = NULL;
 274        u32 cur_digestsize = 0;
 275        struct inode *inode;
 276        int result;
 277
 278        memset(&hash, 0, sizeof(hash));
 279
 280        if (event_data->violation)      /* recording a violation. */
 281                goto out;
 282
 283        if (ima_template_hash_algo_allowed(event_data->iint->ima_hash->algo)) {
 284                cur_digest = event_data->iint->ima_hash->digest;
 285                cur_digestsize = event_data->iint->ima_hash->length;
 286                goto out;
 287        }
 288
 289        if ((const char *)event_data->filename == boot_aggregate_name) {
 290                if (ima_tpm_chip) {
 291                        hash.hdr.algo = HASH_ALGO_SHA1;
 292                        result = ima_calc_boot_aggregate(&hash.hdr);
 293
 294                        /* algo can change depending on available PCR banks */
 295                        if (!result && hash.hdr.algo != HASH_ALGO_SHA1)
 296                                result = -EINVAL;
 297
 298                        if (result < 0)
 299                                memset(&hash, 0, sizeof(hash));
 300                }
 301
 302                cur_digest = hash.hdr.digest;
 303                cur_digestsize = hash_digest_size[HASH_ALGO_SHA1];
 304                goto out;
 305        }
 306
 307        if (!event_data->file)  /* missing info to re-calculate the digest */
 308                return -EINVAL;
 309
 310        inode = file_inode(event_data->file);
 311        hash.hdr.algo = ima_template_hash_algo_allowed(ima_hash_algo) ?
 312            ima_hash_algo : HASH_ALGO_SHA1;
 313        result = ima_calc_file_hash(event_data->file, &hash.hdr);
 314        if (result) {
 315                integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
 316                                    event_data->filename, "collect_data",
 317                                    "failed", result, 0);
 318                return result;
 319        }
 320        cur_digest = hash.hdr.digest;
 321        cur_digestsize = hash.hdr.length;
 322out:
 323        return ima_eventdigest_init_common(cur_digest, cur_digestsize,
 324                                           HASH_ALGO__LAST, field_data);
 325}
 326
 327/*
 328 * This function writes the digest of an event (without size limit).
 329 */
 330int ima_eventdigest_ng_init(struct ima_event_data *event_data,
 331                            struct ima_field_data *field_data)
 332{
 333        u8 *cur_digest = NULL, hash_algo = HASH_ALGO_SHA1;
 334        u32 cur_digestsize = 0;
 335
 336        if (event_data->violation)      /* recording a violation. */
 337                goto out;
 338
 339        cur_digest = event_data->iint->ima_hash->digest;
 340        cur_digestsize = event_data->iint->ima_hash->length;
 341
 342        hash_algo = event_data->iint->ima_hash->algo;
 343out:
 344        return ima_eventdigest_init_common(cur_digest, cur_digestsize,
 345                                           hash_algo, field_data);
 346}
 347
 348/*
 349 * This function writes the digest of the file which is expected to match the
 350 * digest contained in the file's appended signature.
 351 */
 352int ima_eventdigest_modsig_init(struct ima_event_data *event_data,
 353                                struct ima_field_data *field_data)
 354{
 355        enum hash_algo hash_algo;
 356        const u8 *cur_digest;
 357        u32 cur_digestsize;
 358
 359        if (!event_data->modsig)
 360                return 0;
 361
 362        if (event_data->violation) {
 363                /* Recording a violation. */
 364                hash_algo = HASH_ALGO_SHA1;
 365                cur_digest = NULL;
 366                cur_digestsize = 0;
 367        } else {
 368                int rc;
 369
 370                rc = ima_get_modsig_digest(event_data->modsig, &hash_algo,
 371                                           &cur_digest, &cur_digestsize);
 372                if (rc)
 373                        return rc;
 374                else if (hash_algo == HASH_ALGO__LAST || cur_digestsize == 0)
 375                        /* There was some error collecting the digest. */
 376                        return -EINVAL;
 377        }
 378
 379        return ima_eventdigest_init_common(cur_digest, cur_digestsize,
 380                                           hash_algo, field_data);
 381}
 382
 383static int ima_eventname_init_common(struct ima_event_data *event_data,
 384                                     struct ima_field_data *field_data,
 385                                     bool size_limit)
 386{
 387        const char *cur_filename = NULL;
 388        u32 cur_filename_len = 0;
 389
 390        BUG_ON(event_data->filename == NULL && event_data->file == NULL);
 391
 392        if (event_data->filename) {
 393                cur_filename = event_data->filename;
 394                cur_filename_len = strlen(event_data->filename);
 395
 396                if (!size_limit || cur_filename_len <= IMA_EVENT_NAME_LEN_MAX)
 397                        goto out;
 398        }
 399
 400        if (event_data->file) {
 401                cur_filename = event_data->file->f_path.dentry->d_name.name;
 402                cur_filename_len = strlen(cur_filename);
 403        } else
 404                /*
 405                 * Truncate filename if the latter is too long and
 406                 * the file descriptor is not available.
 407                 */
 408                cur_filename_len = IMA_EVENT_NAME_LEN_MAX;
 409out:
 410        return ima_write_template_field_data(cur_filename, cur_filename_len,
 411                                             DATA_FMT_STRING, field_data);
 412}
 413
 414/*
 415 * This function writes the name of an event (with size limit).
 416 */
 417int ima_eventname_init(struct ima_event_data *event_data,
 418                       struct ima_field_data *field_data)
 419{
 420        return ima_eventname_init_common(event_data, field_data, true);
 421}
 422
 423/*
 424 * This function writes the name of an event (without size limit).
 425 */
 426int ima_eventname_ng_init(struct ima_event_data *event_data,
 427                          struct ima_field_data *field_data)
 428{
 429        return ima_eventname_init_common(event_data, field_data, false);
 430}
 431
 432/*
 433 *  ima_eventsig_init - include the file signature as part of the template data
 434 */
 435int ima_eventsig_init(struct ima_event_data *event_data,
 436                      struct ima_field_data *field_data)
 437{
 438        struct evm_ima_xattr_data *xattr_value = event_data->xattr_value;
 439
 440        if ((!xattr_value) || (xattr_value->type != EVM_IMA_XATTR_DIGSIG))
 441                return 0;
 442
 443        return ima_write_template_field_data(xattr_value, event_data->xattr_len,
 444                                             DATA_FMT_HEX, field_data);
 445}
 446
 447/*
 448 *  ima_eventbuf_init - include the buffer(kexec-cmldine) as part of the
 449 *  template data.
 450 */
 451int ima_eventbuf_init(struct ima_event_data *event_data,
 452                      struct ima_field_data *field_data)
 453{
 454        if ((!event_data->buf) || (event_data->buf_len == 0))
 455                return 0;
 456
 457        return ima_write_template_field_data(event_data->buf,
 458                                             event_data->buf_len, DATA_FMT_HEX,
 459                                             field_data);
 460}
 461
 462/*
 463 *  ima_eventmodsig_init - include the appended file signature as part of the
 464 *  template data
 465 */
 466int ima_eventmodsig_init(struct ima_event_data *event_data,
 467                         struct ima_field_data *field_data)
 468{
 469        const void *data;
 470        u32 data_len;
 471        int rc;
 472
 473        if (!event_data->modsig)
 474                return 0;
 475
 476        /*
 477         * modsig is a runtime structure containing pointers. Get its raw data
 478         * instead.
 479         */
 480        rc = ima_get_raw_modsig(event_data->modsig, &data, &data_len);
 481        if (rc)
 482                return rc;
 483
 484        return ima_write_template_field_data(data, data_len, DATA_FMT_HEX,
 485                                             field_data);
 486}
 487