diff options
Diffstat (limited to 'security/integrity/ima/ima_template.c')
-rw-r--r-- | security/integrity/ima/ima_template.c | 124 |
1 files changed, 41 insertions, 83 deletions
diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c index cebb37c63629..7412d0291ab9 100644 --- a/security/integrity/ima/ima_template.c +++ b/security/integrity/ima/ima_template.c @@ -19,6 +19,9 @@ #include "ima.h" #include "ima_template_lib.h" +enum header_fields { HDR_PCR, HDR_DIGEST, HDR_TEMPLATE_NAME, + HDR_TEMPLATE_DATA, HDR__LAST }; + static struct ima_template_desc builtin_templates[] = { {.name = IMA_TEMPLATE_IMA_NAME, .fmt = IMA_TEMPLATE_IMA_FMT}, {.name = "ima-ng", .fmt = "d-ng|n-ng"}, @@ -274,13 +277,6 @@ static int ima_restore_template_data(struct ima_template_desc *template_desc, int template_data_size, struct ima_template_entry **entry) { - struct binary_field_data { - u32 len; - u8 data[0]; - } __packed; - - struct binary_field_data *field_data; - int offset = 0; int ret = 0; int i; @@ -290,30 +286,19 @@ static int ima_restore_template_data(struct ima_template_desc *template_desc, if (!*entry) return -ENOMEM; + ret = ima_parse_buf(template_data, template_data + template_data_size, + NULL, template_desc->num_fields, + (*entry)->template_data, NULL, NULL, + ENFORCE_FIELDS | ENFORCE_BUFEND, "template data"); + if (ret < 0) { + kfree(*entry); + return ret; + } + (*entry)->template_desc = template_desc; for (i = 0; i < template_desc->num_fields; i++) { - field_data = template_data + offset; - - /* Each field of the template data is prefixed with a length. */ - if (offset > (template_data_size - sizeof(*field_data))) { - pr_err("Restoring the template field failed\n"); - ret = -EINVAL; - break; - } - offset += sizeof(*field_data); - - if (ima_canonical_fmt) - field_data->len = le32_to_cpu(field_data->len); - - if (offset > (template_data_size - field_data->len)) { - pr_err("Restoring the template field data failed\n"); - ret = -EINVAL; - break; - } - offset += field_data->len; - - (*entry)->template_data[i].len = field_data->len; - (*entry)->template_data_len += sizeof(field_data->len); + struct ima_field_data *field_data = &(*entry)->template_data[i]; + u8 *data = field_data->data; (*entry)->template_data[i].data = kzalloc(field_data->len + 1, GFP_KERNEL); @@ -321,8 +306,8 @@ static int ima_restore_template_data(struct ima_template_desc *template_desc, ret = -ENOMEM; break; } - memcpy((*entry)->template_data[i].data, field_data->data, - field_data->len); + memcpy((*entry)->template_data[i].data, data, field_data->len); + (*entry)->template_data_len += sizeof(field_data->len); (*entry)->template_data_len += field_data->len; } @@ -337,27 +322,19 @@ static int ima_restore_template_data(struct ima_template_desc *template_desc, /* Restore the serialized binary measurement list without extending PCRs. */ int ima_restore_measurement_list(loff_t size, void *buf) { - struct binary_hdr_v1 { - u32 pcr; - u8 digest[TPM_DIGEST_SIZE]; - u32 template_name_len; - char template_name[0]; - } __packed; char template_name[MAX_TEMPLATE_NAME_LEN]; - struct binary_data_v1 { - u32 template_data_size; - char template_data[0]; - } __packed; - struct ima_kexec_hdr *khdr = buf; - struct binary_hdr_v1 *hdr_v1; - struct binary_data_v1 *data_v1; + struct ima_field_data hdr[HDR__LAST] = { + [HDR_PCR] = {.len = sizeof(u32)}, + [HDR_DIGEST] = {.len = TPM_DIGEST_SIZE}, + }; void *bufp = buf + sizeof(*khdr); void *bufendp; struct ima_template_entry *entry; struct ima_template_desc *template_desc; + DECLARE_BITMAP(hdr_mask, HDR__LAST); unsigned long count = 0; int ret = 0; @@ -380,6 +357,10 @@ int ima_restore_measurement_list(loff_t size, void *buf) return -EINVAL; } + bitmap_zero(hdr_mask, HDR__LAST); + bitmap_set(hdr_mask, HDR_PCR, 1); + bitmap_set(hdr_mask, HDR_DIGEST, 1); + /* * ima kexec buffer prefix: version, buffer size, count * v1 format: pcr, digest, template-name-len, template-name, @@ -387,31 +368,25 @@ int ima_restore_measurement_list(loff_t size, void *buf) */ bufendp = buf + khdr->buffer_size; while ((bufp < bufendp) && (count++ < khdr->count)) { - hdr_v1 = bufp; - if (bufp > (bufendp - sizeof(*hdr_v1))) { - pr_err("attempting to restore partial measurement\n"); - ret = -EINVAL; - break; - } - bufp += sizeof(*hdr_v1); + int enforce_mask = ENFORCE_FIELDS; - if (ima_canonical_fmt) - hdr_v1->template_name_len = - le32_to_cpu(hdr_v1->template_name_len); + enforce_mask |= (count == khdr->count) ? ENFORCE_BUFEND : 0; + ret = ima_parse_buf(bufp, bufendp, &bufp, HDR__LAST, hdr, NULL, + hdr_mask, enforce_mask, "entry header"); + if (ret < 0) + break; - if ((hdr_v1->template_name_len >= MAX_TEMPLATE_NAME_LEN) || - (bufp > (bufendp - hdr_v1->template_name_len))) { + if (hdr[HDR_TEMPLATE_NAME].len >= MAX_TEMPLATE_NAME_LEN) { pr_err("attempting to restore a template name \ that is too long\n"); ret = -EINVAL; break; } - data_v1 = bufp += (u_int8_t)hdr_v1->template_name_len; /* template name is not null terminated */ - memcpy(template_name, hdr_v1->template_name, - hdr_v1->template_name_len); - template_name[hdr_v1->template_name_len] = 0; + memcpy(template_name, hdr[HDR_TEMPLATE_NAME].data, + hdr[HDR_TEMPLATE_NAME].len); + template_name[hdr[HDR_TEMPLATE_NAME].len] = 0; if (strcmp(template_name, "ima") == 0) { pr_err("attempting to restore an unsupported \ @@ -441,34 +416,17 @@ int ima_restore_measurement_list(loff_t size, void *buf) break; } - if (bufp > (bufendp - sizeof(data_v1->template_data_size))) { - pr_err("restoring the template data size failed\n"); - ret = -EINVAL; - break; - } - bufp += (u_int8_t) sizeof(data_v1->template_data_size); - - if (ima_canonical_fmt) - data_v1->template_data_size = - le32_to_cpu(data_v1->template_data_size); - - if (bufp > (bufendp - data_v1->template_data_size)) { - pr_err("restoring the template data failed\n"); - ret = -EINVAL; - break; - } - bufp += data_v1->template_data_size; - ret = ima_restore_template_data(template_desc, - data_v1->template_data, - data_v1->template_data_size, + hdr[HDR_TEMPLATE_DATA].data, + hdr[HDR_TEMPLATE_DATA].len, &entry); if (ret < 0) break; - memcpy(entry->digest, hdr_v1->digest, TPM_DIGEST_SIZE); - entry->pcr = - !ima_canonical_fmt ? hdr_v1->pcr : le32_to_cpu(hdr_v1->pcr); + memcpy(entry->digest, hdr[HDR_DIGEST].data, + hdr[HDR_DIGEST].len); + entry->pcr = !ima_canonical_fmt ? *(hdr[HDR_PCR].data) : + le32_to_cpu(*(hdr[HDR_PCR].data)); ret = ima_restore_measurement_entry(entry); if (ret < 0) break; |