diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-05 11:26:35 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-05 11:26:35 -0700 |
commit | e24dd9ee5399747b71c1d982a484fc7601795f31 (patch) | |
tree | 14fcec8728916092a9f6dbeb0f2b8d5c5a4e5c9a /security/integrity/ima/ima_template.c | |
parent | 7391786a64dcfe9c609a1f8e2204c1abf42ded23 (diff) | |
parent | c4758fa59285fe4dbfeab4364a6957936d040fbf (diff) |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security layer updates from James Morris:
- a major update for AppArmor. From JJ:
* several bug fixes and cleanups
* the patch to add symlink support to securityfs that was floated
on the list earlier and the apparmorfs changes that make use of
securityfs symlinks
* it introduces the domain labeling base code that Ubuntu has been
carrying for several years, with several cleanups applied. And it
converts the current mediation over to using the domain labeling
base, which brings domain stacking support with it. This finally
will bring the base upstream code in line with Ubuntu and provide
a base to upstream the new feature work that Ubuntu carries.
* This does _not_ contain any of the newer apparmor mediation
features/controls (mount, signals, network, keys, ...) that
Ubuntu is currently carrying, all of which will be RFC'd on top
of this.
- Notable also is the Infiniband work in SELinux, and the new file:map
permission. From Paul:
"While we're down to 21 patches for v4.13 (it was 31 for v4.12),
the diffstat jumps up tremendously with over 2k of line changes.
Almost all of these changes are the SELinux/IB work done by
Daniel Jurgens; some other noteworthy changes include a NFS v4.2
labeling fix, a new file:map permission, and reporting of policy
capabilities on policy load"
There's also now genfscon labeling support for tracefs, which was
lost in v4.1 with the separation from debugfs.
- Smack incorporates a safer socket check in file_receive, and adds a
cap_capable call in privilege check.
- TPM as usual has a bunch of fixes and enhancements.
- Multiple calls to security_add_hooks() can now be made for the same
LSM, to allow LSMs to have hook declarations across multiple files.
- IMA now supports different "ima_appraise=" modes (eg. log, fix) from
the boot command line.
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (126 commits)
apparmor: put back designators in struct initialisers
seccomp: Switch from atomic_t to recount_t
seccomp: Adjust selftests to avoid double-join
seccomp: Clean up core dump logic
IMA: update IMA policy documentation to include pcr= option
ima: Log the same audit cause whenever a file has no signature
ima: Simplify policy_func_show.
integrity: Small code improvements
ima: fix get_binary_runtime_size()
ima: use ima_parse_buf() to parse template data
ima: use ima_parse_buf() to parse measurements headers
ima: introduce ima_parse_buf()
ima: Add cgroups2 to the defaults list
ima: use memdup_user_nul
ima: fix up #endif comments
IMA: Correct Kconfig dependencies for hash selection
ima: define is_ima_appraise_enabled()
ima: define Kconfig IMA_APPRAISE_BOOTPARAM option
ima: define a set of appraisal rules requiring file signatures
ima: extend the "ima_policy" boot command line to support multiple policies
...
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; |