linux/security/integrity/ima/ima_template.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.c
  13 *      Helpers to manage template descriptors.
  14 */
  15
  16#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  17
  18#include <linux/rculist.h>
  19#include "ima.h"
  20#include "ima_template_lib.h"
  21
  22enum header_fields { HDR_PCR, HDR_DIGEST, HDR_TEMPLATE_NAME,
  23                     HDR_TEMPLATE_DATA, HDR__LAST };
  24
  25static struct ima_template_desc builtin_templates[] = {
  26        {.name = IMA_TEMPLATE_IMA_NAME, .fmt = IMA_TEMPLATE_IMA_FMT},
  27        {.name = "ima-ng", .fmt = "d-ng|n-ng"},
  28        {.name = "ima-sig", .fmt = "d-ng|n-ng|sig"},
  29        {.name = "ima-buf", .fmt = "d-ng|n-ng|buf"},
  30        {.name = "ima-modsig", .fmt = "d-ng|n-ng|sig|d-modsig|modsig"},
  31        {.name = "", .fmt = ""},        /* placeholder for a custom format */
  32};
  33
  34static LIST_HEAD(defined_templates);
  35static DEFINE_SPINLOCK(template_list);
  36
  37static const struct ima_template_field supported_fields[] = {
  38        {.field_id = "d", .field_init = ima_eventdigest_init,
  39         .field_show = ima_show_template_digest},
  40        {.field_id = "n", .field_init = ima_eventname_init,
  41         .field_show = ima_show_template_string},
  42        {.field_id = "d-ng", .field_init = ima_eventdigest_ng_init,
  43         .field_show = ima_show_template_digest_ng},
  44        {.field_id = "n-ng", .field_init = ima_eventname_ng_init,
  45         .field_show = ima_show_template_string},
  46        {.field_id = "sig", .field_init = ima_eventsig_init,
  47         .field_show = ima_show_template_sig},
  48        {.field_id = "buf", .field_init = ima_eventbuf_init,
  49         .field_show = ima_show_template_buf},
  50        {.field_id = "d-modsig", .field_init = ima_eventdigest_modsig_init,
  51         .field_show = ima_show_template_digest_ng},
  52        {.field_id = "modsig", .field_init = ima_eventmodsig_init,
  53         .field_show = ima_show_template_sig},
  54};
  55
  56/*
  57 * Used when restoring measurements carried over from a kexec. 'd' and 'n' don't
  58 * need to be accounted for since they shouldn't be defined in the same template
  59 * description as 'd-ng' and 'n-ng' respectively.
  60 */
  61#define MAX_TEMPLATE_NAME_LEN sizeof("d-ng|n-ng|sig|buf|d-modisg|modsig")
  62
  63static struct ima_template_desc *ima_template;
  64
  65/**
  66 * ima_template_has_modsig - Check whether template has modsig-related fields.
  67 * @ima_template: IMA template to check.
  68 *
  69 * Tells whether the given template has fields referencing a file's appended
  70 * signature.
  71 */
  72bool ima_template_has_modsig(const struct ima_template_desc *ima_template)
  73{
  74        int i;
  75
  76        for (i = 0; i < ima_template->num_fields; i++)
  77                if (!strcmp(ima_template->fields[i]->field_id, "modsig") ||
  78                    !strcmp(ima_template->fields[i]->field_id, "d-modsig"))
  79                        return true;
  80
  81        return false;
  82}
  83
  84static int __init ima_template_setup(char *str)
  85{
  86        struct ima_template_desc *template_desc;
  87        int template_len = strlen(str);
  88
  89        if (ima_template)
  90                return 1;
  91
  92        ima_init_template_list();
  93
  94        /*
  95         * Verify that a template with the supplied name exists.
  96         * If not, use CONFIG_IMA_DEFAULT_TEMPLATE.
  97         */
  98        template_desc = lookup_template_desc(str);
  99        if (!template_desc) {
 100                pr_err("template %s not found, using %s\n",
 101                       str, CONFIG_IMA_DEFAULT_TEMPLATE);
 102                return 1;
 103        }
 104
 105        /*
 106         * Verify whether the current hash algorithm is supported
 107         * by the 'ima' template.
 108         */
 109        if (template_len == 3 && strcmp(str, IMA_TEMPLATE_IMA_NAME) == 0 &&
 110            ima_hash_algo != HASH_ALGO_SHA1 && ima_hash_algo != HASH_ALGO_MD5) {
 111                pr_err("template does not support hash alg\n");
 112                return 1;
 113        }
 114
 115        ima_template = template_desc;
 116        return 1;
 117}
 118__setup("ima_template=", ima_template_setup);
 119
 120static int __init ima_template_fmt_setup(char *str)
 121{
 122        int num_templates = ARRAY_SIZE(builtin_templates);
 123
 124        if (ima_template)
 125                return 1;
 126
 127        if (template_desc_init_fields(str, NULL, NULL) < 0) {
 128                pr_err("format string '%s' not valid, using template %s\n",
 129                       str, CONFIG_IMA_DEFAULT_TEMPLATE);
 130                return 1;
 131        }
 132
 133        builtin_templates[num_templates - 1].fmt = str;
 134        ima_template = builtin_templates + num_templates - 1;
 135
 136        return 1;
 137}
 138__setup("ima_template_fmt=", ima_template_fmt_setup);
 139
 140struct ima_template_desc *lookup_template_desc(const char *name)
 141{
 142        struct ima_template_desc *template_desc;
 143        int found = 0;
 144
 145        rcu_read_lock();
 146        list_for_each_entry_rcu(template_desc, &defined_templates, list) {
 147                if ((strcmp(template_desc->name, name) == 0) ||
 148                    (strcmp(template_desc->fmt, name) == 0)) {
 149                        found = 1;
 150                        break;
 151                }
 152        }
 153        rcu_read_unlock();
 154        return found ? template_desc : NULL;
 155}
 156
 157static const struct ima_template_field *
 158lookup_template_field(const char *field_id)
 159{
 160        int i;
 161
 162        for (i = 0; i < ARRAY_SIZE(supported_fields); i++)
 163                if (strncmp(supported_fields[i].field_id, field_id,
 164                            IMA_TEMPLATE_FIELD_ID_MAX_LEN) == 0)
 165                        return &supported_fields[i];
 166        return NULL;
 167}
 168
 169static int template_fmt_size(const char *template_fmt)
 170{
 171        char c;
 172        int template_fmt_len = strlen(template_fmt);
 173        int i = 0, j = 0;
 174
 175        while (i < template_fmt_len) {
 176                c = template_fmt[i];
 177                if (c == '|')
 178                        j++;
 179                i++;
 180        }
 181
 182        return j + 1;
 183}
 184
 185int template_desc_init_fields(const char *template_fmt,
 186                              const struct ima_template_field ***fields,
 187                              int *num_fields)
 188{
 189        const char *template_fmt_ptr;
 190        const struct ima_template_field *found_fields[IMA_TEMPLATE_NUM_FIELDS_MAX];
 191        int template_num_fields;
 192        int i, len;
 193
 194        if (num_fields && *num_fields > 0) /* already initialized? */
 195                return 0;
 196
 197        template_num_fields = template_fmt_size(template_fmt);
 198
 199        if (template_num_fields > IMA_TEMPLATE_NUM_FIELDS_MAX) {
 200                pr_err("format string '%s' contains too many fields\n",
 201                       template_fmt);
 202                return -EINVAL;
 203        }
 204
 205        for (i = 0, template_fmt_ptr = template_fmt; i < template_num_fields;
 206             i++, template_fmt_ptr += len + 1) {
 207                char tmp_field_id[IMA_TEMPLATE_FIELD_ID_MAX_LEN + 1];
 208
 209                len = strchrnul(template_fmt_ptr, '|') - template_fmt_ptr;
 210                if (len == 0 || len > IMA_TEMPLATE_FIELD_ID_MAX_LEN) {
 211                        pr_err("Invalid field with length %d\n", len);
 212                        return -EINVAL;
 213                }
 214
 215                memcpy(tmp_field_id, template_fmt_ptr, len);
 216                tmp_field_id[len] = '\0';
 217                found_fields[i] = lookup_template_field(tmp_field_id);
 218                if (!found_fields[i]) {
 219                        pr_err("field '%s' not found\n", tmp_field_id);
 220                        return -ENOENT;
 221                }
 222        }
 223
 224        if (fields && num_fields) {
 225                *fields = kmalloc_array(i, sizeof(*fields), GFP_KERNEL);
 226                if (*fields == NULL)
 227                        return -ENOMEM;
 228
 229                memcpy(*fields, found_fields, i * sizeof(*fields));
 230                *num_fields = i;
 231        }
 232
 233        return 0;
 234}
 235
 236void ima_init_template_list(void)
 237{
 238        int i;
 239
 240        if (!list_empty(&defined_templates))
 241                return;
 242
 243        spin_lock(&template_list);
 244        for (i = 0; i < ARRAY_SIZE(builtin_templates); i++) {
 245                list_add_tail_rcu(&builtin_templates[i].list,
 246                                  &defined_templates);
 247        }
 248        spin_unlock(&template_list);
 249}
 250
 251struct ima_template_desc *ima_template_desc_current(void)
 252{
 253        if (!ima_template) {
 254                ima_init_template_list();
 255                ima_template =
 256                    lookup_template_desc(CONFIG_IMA_DEFAULT_TEMPLATE);
 257        }
 258        return ima_template;
 259}
 260
 261int __init ima_init_template(void)
 262{
 263        struct ima_template_desc *template = ima_template_desc_current();
 264        int result;
 265
 266        result = template_desc_init_fields(template->fmt,
 267                                           &(template->fields),
 268                                           &(template->num_fields));
 269        if (result < 0)
 270                pr_err("template %s init failed, result: %d\n",
 271                       (strlen(template->name) ?
 272                       template->name : template->fmt), result);
 273
 274        return result;
 275}
 276
 277static struct ima_template_desc *restore_template_fmt(char *template_name)
 278{
 279        struct ima_template_desc *template_desc = NULL;
 280        int ret;
 281
 282        ret = template_desc_init_fields(template_name, NULL, NULL);
 283        if (ret < 0) {
 284                pr_err("attempting to initialize the template \"%s\" failed\n",
 285                        template_name);
 286                goto out;
 287        }
 288
 289        template_desc = kzalloc(sizeof(*template_desc), GFP_KERNEL);
 290        if (!template_desc)
 291                goto out;
 292
 293        template_desc->name = "";
 294        template_desc->fmt = kstrdup(template_name, GFP_KERNEL);
 295        if (!template_desc->fmt)
 296                goto out;
 297
 298        spin_lock(&template_list);
 299        list_add_tail_rcu(&template_desc->list, &defined_templates);
 300        spin_unlock(&template_list);
 301out:
 302        return template_desc;
 303}
 304
 305static int ima_restore_template_data(struct ima_template_desc *template_desc,
 306                                     void *template_data,
 307                                     int template_data_size,
 308                                     struct ima_template_entry **entry)
 309{
 310        int ret = 0;
 311        int i;
 312
 313        *entry = kzalloc(struct_size(*entry, template_data,
 314                                     template_desc->num_fields), GFP_NOFS);
 315        if (!*entry)
 316                return -ENOMEM;
 317
 318        ret = ima_parse_buf(template_data, template_data + template_data_size,
 319                            NULL, template_desc->num_fields,
 320                            (*entry)->template_data, NULL, NULL,
 321                            ENFORCE_FIELDS | ENFORCE_BUFEND, "template data");
 322        if (ret < 0) {
 323                kfree(*entry);
 324                return ret;
 325        }
 326
 327        (*entry)->template_desc = template_desc;
 328        for (i = 0; i < template_desc->num_fields; i++) {
 329                struct ima_field_data *field_data = &(*entry)->template_data[i];
 330                u8 *data = field_data->data;
 331
 332                (*entry)->template_data[i].data =
 333                        kzalloc(field_data->len + 1, GFP_KERNEL);
 334                if (!(*entry)->template_data[i].data) {
 335                        ret = -ENOMEM;
 336                        break;
 337                }
 338                memcpy((*entry)->template_data[i].data, data, field_data->len);
 339                (*entry)->template_data_len += sizeof(field_data->len);
 340                (*entry)->template_data_len += field_data->len;
 341        }
 342
 343        if (ret < 0) {
 344                ima_free_template_entry(*entry);
 345                *entry = NULL;
 346        }
 347
 348        return ret;
 349}
 350
 351/* Restore the serialized binary measurement list without extending PCRs. */
 352int ima_restore_measurement_list(loff_t size, void *buf)
 353{
 354        char template_name[MAX_TEMPLATE_NAME_LEN];
 355
 356        struct ima_kexec_hdr *khdr = buf;
 357        struct ima_field_data hdr[HDR__LAST] = {
 358                [HDR_PCR] = {.len = sizeof(u32)},
 359                [HDR_DIGEST] = {.len = TPM_DIGEST_SIZE},
 360        };
 361
 362        void *bufp = buf + sizeof(*khdr);
 363        void *bufendp;
 364        struct ima_template_entry *entry;
 365        struct ima_template_desc *template_desc;
 366        DECLARE_BITMAP(hdr_mask, HDR__LAST);
 367        unsigned long count = 0;
 368        int ret = 0;
 369
 370        if (!buf || size < sizeof(*khdr))
 371                return 0;
 372
 373        if (ima_canonical_fmt) {
 374                khdr->version = le16_to_cpu(khdr->version);
 375                khdr->count = le64_to_cpu(khdr->count);
 376                khdr->buffer_size = le64_to_cpu(khdr->buffer_size);
 377        }
 378
 379        if (khdr->version != 1) {
 380                pr_err("attempting to restore a incompatible measurement list");
 381                return -EINVAL;
 382        }
 383
 384        if (khdr->count > ULONG_MAX - 1) {
 385                pr_err("attempting to restore too many measurements");
 386                return -EINVAL;
 387        }
 388
 389        bitmap_zero(hdr_mask, HDR__LAST);
 390        bitmap_set(hdr_mask, HDR_PCR, 1);
 391        bitmap_set(hdr_mask, HDR_DIGEST, 1);
 392
 393        /*
 394         * ima kexec buffer prefix: version, buffer size, count
 395         * v1 format: pcr, digest, template-name-len, template-name,
 396         *            template-data-size, template-data
 397         */
 398        bufendp = buf + khdr->buffer_size;
 399        while ((bufp < bufendp) && (count++ < khdr->count)) {
 400                int enforce_mask = ENFORCE_FIELDS;
 401
 402                enforce_mask |= (count == khdr->count) ? ENFORCE_BUFEND : 0;
 403                ret = ima_parse_buf(bufp, bufendp, &bufp, HDR__LAST, hdr, NULL,
 404                                    hdr_mask, enforce_mask, "entry header");
 405                if (ret < 0)
 406                        break;
 407
 408                if (hdr[HDR_TEMPLATE_NAME].len >= MAX_TEMPLATE_NAME_LEN) {
 409                        pr_err("attempting to restore a template name that is too long\n");
 410                        ret = -EINVAL;
 411                        break;
 412                }
 413
 414                /* template name is not null terminated */
 415                memcpy(template_name, hdr[HDR_TEMPLATE_NAME].data,
 416                       hdr[HDR_TEMPLATE_NAME].len);
 417                template_name[hdr[HDR_TEMPLATE_NAME].len] = 0;
 418
 419                if (strcmp(template_name, "ima") == 0) {
 420                        pr_err("attempting to restore an unsupported template \"%s\" failed\n",
 421                               template_name);
 422                        ret = -EINVAL;
 423                        break;
 424                }
 425
 426                template_desc = lookup_template_desc(template_name);
 427                if (!template_desc) {
 428                        template_desc = restore_template_fmt(template_name);
 429                        if (!template_desc)
 430                                break;
 431                }
 432
 433                /*
 434                 * Only the running system's template format is initialized
 435                 * on boot.  As needed, initialize the other template formats.
 436                 */
 437                ret = template_desc_init_fields(template_desc->fmt,
 438                                                &(template_desc->fields),
 439                                                &(template_desc->num_fields));
 440                if (ret < 0) {
 441                        pr_err("attempting to restore the template fmt \"%s\" failed\n",
 442                               template_desc->fmt);
 443                        ret = -EINVAL;
 444                        break;
 445                }
 446
 447                ret = ima_restore_template_data(template_desc,
 448                                                hdr[HDR_TEMPLATE_DATA].data,
 449                                                hdr[HDR_TEMPLATE_DATA].len,
 450                                                &entry);
 451                if (ret < 0)
 452                        break;
 453
 454                memcpy(entry->digest, hdr[HDR_DIGEST].data,
 455                       hdr[HDR_DIGEST].len);
 456                entry->pcr = !ima_canonical_fmt ? *(hdr[HDR_PCR].data) :
 457                             le32_to_cpu(*(hdr[HDR_PCR].data));
 458                ret = ima_restore_measurement_entry(entry);
 459                if (ret < 0)
 460                        break;
 461
 462        }
 463        return ret;
 464}
 465