aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/security/integrity/ima
diff options
context:
space:
mode:
Diffstat (limited to 'security/integrity/ima')
-rw-r--r--security/integrity/ima/Kconfig16
-rw-r--r--security/integrity/ima/ima.h31
-rw-r--r--security/integrity/ima/ima_appraise.c16
-rw-r--r--security/integrity/ima/ima_fs.c13
-rw-r--r--security/integrity/ima/ima_policy.c106
-rw-r--r--security/integrity/ima/ima_queue.c2
-rw-r--r--security/integrity/ima/ima_template.c124
-rw-r--r--security/integrity/ima/ima_template_lib.c61
-rw-r--r--security/integrity/ima/ima_template_lib.h6
9 files changed, 204 insertions, 171 deletions
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
index 370eb2f4dd37..35ef69312811 100644
--- a/security/integrity/ima/Kconfig
+++ b/security/integrity/ima/Kconfig
@@ -96,19 +96,19 @@ choice
config IMA_DEFAULT_HASH_SHA1
bool "SHA1 (default)"
- depends on CRYPTO_SHA1
+ depends on CRYPTO_SHA1=y
config IMA_DEFAULT_HASH_SHA256
bool "SHA256"
- depends on CRYPTO_SHA256 && !IMA_TEMPLATE
+ depends on CRYPTO_SHA256=y && !IMA_TEMPLATE
config IMA_DEFAULT_HASH_SHA512
bool "SHA512"
- depends on CRYPTO_SHA512 && !IMA_TEMPLATE
+ depends on CRYPTO_SHA512=y && !IMA_TEMPLATE
config IMA_DEFAULT_HASH_WP512
bool "WP512"
- depends on CRYPTO_WP512 && !IMA_TEMPLATE
+ depends on CRYPTO_WP512=y && !IMA_TEMPLATE
endchoice
config IMA_DEFAULT_HASH
@@ -155,6 +155,14 @@ config IMA_APPRAISE
<http://linux-ima.sourceforge.net>
If unsure, say N.
+config IMA_APPRAISE_BOOTPARAM
+ bool "ima_appraise boot parameter"
+ depends on IMA_APPRAISE
+ default y
+ help
+ This option enables the different "ima_appraise=" modes
+ (eg. fix, log) from the boot command line.
+
config IMA_TRUSTED_KEYRING
bool "Require all keys on the .ima keyring be signed (deprecated)"
depends on IMA_APPRAISE && SYSTEM_TRUSTED_KEYRING
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index b563fbd4d122..d52b487ad259 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -172,17 +172,22 @@ static inline unsigned long ima_hash_key(u8 *digest)
return hash_long(*digest, IMA_HASH_BITS);
}
+#define __ima_hooks(hook) \
+ hook(NONE) \
+ hook(FILE_CHECK) \
+ hook(MMAP_CHECK) \
+ hook(BPRM_CHECK) \
+ hook(POST_SETATTR) \
+ hook(MODULE_CHECK) \
+ hook(FIRMWARE_CHECK) \
+ hook(KEXEC_KERNEL_CHECK) \
+ hook(KEXEC_INITRAMFS_CHECK) \
+ hook(POLICY_CHECK) \
+ hook(MAX_CHECK)
+#define __ima_hook_enumify(ENUM) ENUM,
+
enum ima_hooks {
- FILE_CHECK = 1,
- MMAP_CHECK,
- BPRM_CHECK,
- POST_SETATTR,
- MODULE_CHECK,
- FIRMWARE_CHECK,
- KEXEC_KERNEL_CHECK,
- KEXEC_INITRAMFS_CHECK,
- POLICY_CHECK,
- MAX_CHECK
+ __ima_hooks(__ima_hook_enumify)
};
/* LIM API function definitions */
@@ -284,7 +289,7 @@ static inline int ima_read_xattr(struct dentry *dentry,
return 0;
}
-#endif
+#endif /* CONFIG_IMA_APPRAISE */
/* LSM based policy rules require audit */
#ifdef CONFIG_IMA_LSM_RULES
@@ -306,12 +311,12 @@ static inline int security_filter_rule_match(u32 secid, u32 field, u32 op,
{
return -EINVAL;
}
-#endif /* CONFIG_IMA_TRUSTED_KEYRING */
+#endif /* CONFIG_IMA_LSM_RULES */
#ifdef CONFIG_IMA_READ_POLICY
#define POLICY_FILE_FLAGS (S_IWUSR | S_IRUSR)
#else
#define POLICY_FILE_FLAGS S_IWUSR
-#endif /* CONFIG_IMA_WRITE_POLICY */
+#endif /* CONFIG_IMA_READ_POLICY */
#endif /* __LINUX_IMA_H */
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 5d0785cfe063..809ba70fbbbf 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -20,18 +20,30 @@
static int __init default_appraise_setup(char *str)
{
+#ifdef CONFIG_IMA_APPRAISE_BOOTPARAM
if (strncmp(str, "off", 3) == 0)
ima_appraise = 0;
else if (strncmp(str, "log", 3) == 0)
ima_appraise = IMA_APPRAISE_LOG;
else if (strncmp(str, "fix", 3) == 0)
ima_appraise = IMA_APPRAISE_FIX;
+#endif
return 1;
}
__setup("ima_appraise=", default_appraise_setup);
/*
+ * is_ima_appraise_enabled - return appraise status
+ *
+ * Only return enabled, if not in ima_appraise="fix" or "log" modes.
+ */
+bool is_ima_appraise_enabled(void)
+{
+ return (ima_appraise & IMA_APPRAISE_ENFORCE) ? 1 : 0;
+}
+
+/*
* ima_must_appraise - set appraise flag
*
* Return 1 to appraise
@@ -205,7 +217,8 @@ int ima_appraise_measurement(enum ima_hooks func,
if (rc && rc != -ENODATA)
goto out;
- cause = "missing-hash";
+ cause = iint->flags & IMA_DIGSIG_REQUIRED ?
+ "IMA-signature-required" : "missing-hash";
status = INTEGRITY_NOLABEL;
if (opened & FILE_CREATED)
iint->flags |= IMA_NEW_FILE;
@@ -228,6 +241,7 @@ int ima_appraise_measurement(enum ima_hooks func,
case IMA_XATTR_DIGEST_NG:
/* first byte contains algorithm id */
hash_start = 1;
+ /* fall through */
case IMA_XATTR_DIGEST:
if (iint->flags & IMA_DIGSIG_REQUIRED) {
cause = "IMA-signature-required";
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index ca303e5d2b94..ad491c51e833 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -323,16 +323,11 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf,
if (*ppos != 0)
goto out;
- result = -ENOMEM;
- data = kmalloc(datalen + 1, GFP_KERNEL);
- if (!data)
+ data = memdup_user_nul(buf, datalen);
+ if (IS_ERR(data)) {
+ result = PTR_ERR(data);
goto out;
-
- *(data + datalen) = '\0';
-
- result = -EFAULT;
- if (copy_from_user(data, buf, datalen))
- goto out_free;
+ }
result = mutex_lock_interruptible(&ima_write_mutex);
if (result < 0)
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 6f885fab9d84..95209a5f8595 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -96,6 +96,8 @@ static struct ima_rule_entry dont_measure_rules[] __ro_after_init = {
{.action = DONT_MEASURE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC},
{.action = DONT_MEASURE, .fsmagic = CGROUP_SUPER_MAGIC,
.flags = IMA_FSMAGIC},
+ {.action = DONT_MEASURE, .fsmagic = CGROUP2_SUPER_MAGIC,
+ .flags = IMA_FSMAGIC},
{.action = DONT_MEASURE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC}
};
@@ -139,6 +141,7 @@ static struct ima_rule_entry default_appraise_rules[] __ro_after_init = {
{.action = DONT_APPRAISE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC},
{.action = DONT_APPRAISE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC},
{.action = DONT_APPRAISE, .fsmagic = CGROUP_SUPER_MAGIC, .flags = IMA_FSMAGIC},
+ {.action = DONT_APPRAISE, .fsmagic = CGROUP2_SUPER_MAGIC, .flags = IMA_FSMAGIC},
#ifdef CONFIG_IMA_WRITE_POLICY
{.action = APPRAISE, .func = POLICY_CHECK,
.flags = IMA_FUNC | IMA_DIGSIG_REQUIRED},
@@ -153,6 +156,17 @@ static struct ima_rule_entry default_appraise_rules[] __ro_after_init = {
#endif
};
+static struct ima_rule_entry secure_boot_rules[] __ro_after_init = {
+ {.action = APPRAISE, .func = MODULE_CHECK,
+ .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED},
+ {.action = APPRAISE, .func = FIRMWARE_CHECK,
+ .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED},
+ {.action = APPRAISE, .func = KEXEC_KERNEL_CHECK,
+ .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED},
+ {.action = APPRAISE, .func = POLICY_CHECK,
+ .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED},
+};
+
static LIST_HEAD(ima_default_rules);
static LIST_HEAD(ima_policy_rules);
static LIST_HEAD(ima_temp_rules);
@@ -170,19 +184,27 @@ static int __init default_measure_policy_setup(char *str)
}
__setup("ima_tcb", default_measure_policy_setup);
+static bool ima_use_appraise_tcb __initdata;
+static bool ima_use_secure_boot __initdata;
static int __init policy_setup(char *str)
{
- if (ima_policy)
- return 1;
+ char *p;
- if (strcmp(str, "tcb") == 0)
- ima_policy = DEFAULT_TCB;
+ while ((p = strsep(&str, " |\n")) != NULL) {
+ if (*p == ' ')
+ continue;
+ if ((strcmp(p, "tcb") == 0) && !ima_policy)
+ ima_policy = DEFAULT_TCB;
+ else if (strcmp(p, "appraise_tcb") == 0)
+ ima_use_appraise_tcb = 1;
+ else if (strcmp(p, "secure_boot") == 0)
+ ima_use_secure_boot = 1;
+ }
return 1;
}
__setup("ima_policy=", policy_setup);
-static bool ima_use_appraise_tcb __initdata;
static int __init default_appraise_policy_setup(char *str)
{
ima_use_appraise_tcb = 1;
@@ -405,12 +427,14 @@ void ima_update_policy_flag(void)
*/
void __init ima_init_policy(void)
{
- int i, measure_entries, appraise_entries;
+ int i, measure_entries, appraise_entries, secure_boot_entries;
/* if !ima_policy set entries = 0 so we load NO default rules */
measure_entries = ima_policy ? ARRAY_SIZE(dont_measure_rules) : 0;
appraise_entries = ima_use_appraise_tcb ?
ARRAY_SIZE(default_appraise_rules) : 0;
+ secure_boot_entries = ima_use_secure_boot ?
+ ARRAY_SIZE(secure_boot_rules) : 0;
for (i = 0; i < measure_entries; i++)
list_add_tail(&dont_measure_rules[i].list, &ima_default_rules);
@@ -429,6 +453,14 @@ void __init ima_init_policy(void)
break;
}
+ /*
+ * Insert the appraise rules requiring file signatures, prior to
+ * any other appraise rules.
+ */
+ for (i = 0; i < secure_boot_entries; i++)
+ list_add_tail(&secure_boot_rules[i].list,
+ &ima_default_rules);
+
for (i = 0; i < appraise_entries; i++) {
list_add_tail(&default_appraise_rules[i].list,
&ima_default_rules);
@@ -931,30 +963,17 @@ enum {
mask_exec = 0, mask_write, mask_read, mask_append
};
-static char *mask_tokens[] = {
+static const char *const mask_tokens[] = {
"MAY_EXEC",
"MAY_WRITE",
"MAY_READ",
"MAY_APPEND"
};
-enum {
- func_file = 0, func_mmap, func_bprm,
- func_module, func_firmware, func_post,
- func_kexec_kernel, func_kexec_initramfs,
- func_policy
-};
+#define __ima_hook_stringify(str) (#str),
-static char *func_tokens[] = {
- "FILE_CHECK",
- "MMAP_CHECK",
- "BPRM_CHECK",
- "MODULE_CHECK",
- "FIRMWARE_CHECK",
- "POST_SETATTR",
- "KEXEC_KERNEL_CHECK",
- "KEXEC_INITRAMFS_CHECK",
- "POLICY_CHECK"
+static const char *const func_tokens[] = {
+ __ima_hooks(__ima_hook_stringify)
};
void *ima_policy_start(struct seq_file *m, loff_t *pos)
@@ -991,49 +1010,16 @@ void ima_policy_stop(struct seq_file *m, void *v)
#define pt(token) policy_tokens[token + Opt_err].pattern
#define mt(token) mask_tokens[token]
-#define ft(token) func_tokens[token]
/*
* policy_func_show - display the ima_hooks policy rule
*/
static void policy_func_show(struct seq_file *m, enum ima_hooks func)
{
- char tbuf[64] = {0,};
-
- switch (func) {
- case FILE_CHECK:
- seq_printf(m, pt(Opt_func), ft(func_file));
- break;
- case MMAP_CHECK:
- seq_printf(m, pt(Opt_func), ft(func_mmap));
- break;
- case BPRM_CHECK:
- seq_printf(m, pt(Opt_func), ft(func_bprm));
- break;
- case MODULE_CHECK:
- seq_printf(m, pt(Opt_func), ft(func_module));
- break;
- case FIRMWARE_CHECK:
- seq_printf(m, pt(Opt_func), ft(func_firmware));
- break;
- case POST_SETATTR:
- seq_printf(m, pt(Opt_func), ft(func_post));
- break;
- case KEXEC_KERNEL_CHECK:
- seq_printf(m, pt(Opt_func), ft(func_kexec_kernel));
- break;
- case KEXEC_INITRAMFS_CHECK:
- seq_printf(m, pt(Opt_func), ft(func_kexec_initramfs));
- break;
- case POLICY_CHECK:
- seq_printf(m, pt(Opt_func), ft(func_policy));
- break;
- default:
- snprintf(tbuf, sizeof(tbuf), "%d", func);
- seq_printf(m, pt(Opt_func), tbuf);
- break;
- }
- seq_puts(m, " ");
+ if (func > 0 && func < MAX_CHECK)
+ seq_printf(m, "func=%s ", func_tokens[func]);
+ else
+ seq_printf(m, "func=%d ", func);
}
int ima_policy_show(struct seq_file *m, void *v)
diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c
index d9aa5ab71204..a02a86d51102 100644
--- a/security/integrity/ima/ima_queue.c
+++ b/security/integrity/ima/ima_queue.c
@@ -81,7 +81,7 @@ static int get_binary_runtime_size(struct ima_template_entry *entry)
size += sizeof(u32); /* pcr */
size += sizeof(entry->digest);
size += sizeof(int); /* template name size field */
- size += strlen(entry->template_desc->name) + 1;
+ size += strlen(entry->template_desc->name);
size += sizeof(entry->template_data_len);
size += entry->template_data_len;
return size;
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;
diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c
index f9ba37b3928d..28af43f63572 100644
--- a/security/integrity/ima/ima_template_lib.c
+++ b/security/integrity/ima/ima_template_lib.c
@@ -159,6 +159,67 @@ void ima_show_template_sig(struct seq_file *m, enum ima_show_type show,
ima_show_template_field_data(m, show, DATA_FMT_HEX, field_data);
}
+/**
+ * ima_parse_buf() - Parses lengths and data from an input buffer
+ * @bufstartp: Buffer start address.
+ * @bufendp: Buffer end address.
+ * @bufcurp: Pointer to remaining (non-parsed) data.
+ * @maxfields: Length of fields array.
+ * @fields: Array containing lengths and pointers of parsed data.
+ * @curfields: Number of array items containing parsed data.
+ * @len_mask: Bitmap (if bit is set, data length should not be parsed).
+ * @enforce_mask: Check if curfields == maxfields and/or bufcurp == bufendp.
+ * @bufname: String identifier of the input buffer.
+ *
+ * Return: 0 on success, -EINVAL on error.
+ */
+int ima_parse_buf(void *bufstartp, void *bufendp, void **bufcurp,
+ int maxfields, struct ima_field_data *fields, int *curfields,
+ unsigned long *len_mask, int enforce_mask, char *bufname)
+{
+ void *bufp = bufstartp;
+ int i;
+
+ for (i = 0; i < maxfields; i++) {
+ if (len_mask == NULL || !test_bit(i, len_mask)) {
+ if (bufp > (bufendp - sizeof(u32)))
+ break;
+
+ fields[i].len = *(u32 *)bufp;
+ if (ima_canonical_fmt)
+ fields[i].len = le32_to_cpu(fields[i].len);
+
+ bufp += sizeof(u32);
+ }
+
+ if (bufp > (bufendp - fields[i].len))
+ break;
+
+ fields[i].data = bufp;
+ bufp += fields[i].len;
+ }
+
+ if ((enforce_mask & ENFORCE_FIELDS) && i != maxfields) {
+ pr_err("%s: nr of fields mismatch: expected: %d, current: %d\n",
+ bufname, maxfields, i);
+ return -EINVAL;
+ }
+
+ if ((enforce_mask & ENFORCE_BUFEND) && bufp != bufendp) {
+ pr_err("%s: buf end mismatch: expected: %p, current: %p\n",
+ bufname, bufendp, bufp);
+ return -EINVAL;
+ }
+
+ if (curfields)
+ *curfields = i;
+
+ if (bufcurp)
+ *bufcurp = bufp;
+
+ return 0;
+}
+
static int ima_eventdigest_init_common(u8 *digest, u32 digestsize, u8 hash_algo,
struct ima_field_data *field_data)
{
diff --git a/security/integrity/ima/ima_template_lib.h b/security/integrity/ima/ima_template_lib.h
index c344530c1d69..6a3d8b831deb 100644
--- a/security/integrity/ima/ima_template_lib.h
+++ b/security/integrity/ima/ima_template_lib.h
@@ -18,6 +18,9 @@
#include <linux/seq_file.h>
#include "ima.h"
+#define ENFORCE_FIELDS 0x00000001
+#define ENFORCE_BUFEND 0x00000002
+
void ima_show_template_digest(struct seq_file *m, enum ima_show_type show,
struct ima_field_data *field_data);
void ima_show_template_digest_ng(struct seq_file *m, enum ima_show_type show,
@@ -26,6 +29,9 @@ void ima_show_template_string(struct seq_file *m, enum ima_show_type show,
struct ima_field_data *field_data);
void ima_show_template_sig(struct seq_file *m, enum ima_show_type show,
struct ima_field_data *field_data);
+int ima_parse_buf(void *bufstartp, void *bufendp, void **bufcurp,
+ int maxfields, struct ima_field_data *fields, int *curfields,
+ unsigned long *len_mask, int enforce_mask, char *bufname);
int ima_eventdigest_init(struct ima_event_data *event_data,
struct ima_field_data *field_data);
int ima_eventname_init(struct ima_event_data *event_data,