Call ima_read_and_process_file() to measure and appraise the IMA policy. This patch defines a new policy hook named POLICY_CHECK.
Signed-off-by: Mimi Zohar <zo...@linux.vnet.ibm.com> --- include/linux/ima.h | 2 +- security/integrity/digsig.c | 2 +- security/integrity/iint.c | 21 ++++++++++++++++----- security/integrity/ima/ima.h | 1 + security/integrity/ima/ima_appraise.c | 3 +++ security/integrity/ima/ima_fs.c | 12 +++++++++--- security/integrity/ima/ima_policy.c | 15 +++++++++++++-- security/integrity/integrity.h | 4 +++- 8 files changed, 47 insertions(+), 13 deletions(-) diff --git a/include/linux/ima.h b/include/linux/ima.h index 7bd4e07..27d960c 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h @@ -13,7 +13,7 @@ #include <linux/fs.h> struct linux_binprm; -enum ima_read_hooks { KEXEC_CHECK = 1, INITRAMFS_CHECK, FIRMWARE_CHECK, IMA_MAX_READ_CHECK}; +enum ima_read_hooks { KEXEC_CHECK = 1, INITRAMFS_CHECK, FIRMWARE_CHECK, POLICY_CHECK, IMA_MAX_READ_CHECK}; #ifdef CONFIG_IMA extern int ima_bprm_check(struct linux_binprm *bprm); diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c index 8ef1511..e58a5f6 100644 --- a/security/integrity/digsig.c +++ b/security/integrity/digsig.c @@ -104,7 +104,7 @@ int __init integrity_load_x509(const unsigned int id, const char *path) if (!keyring[id]) return -EINVAL; - rc = integrity_read_file(path, &data); + rc = integrity_read_file(path, &data, 0); if (rc < 0) return rc; diff --git a/security/integrity/iint.c b/security/integrity/iint.c index 8a45576..4d149c9 100644 --- a/security/integrity/iint.c +++ b/security/integrity/iint.c @@ -205,7 +205,8 @@ int integrity_kernel_read(struct file *file, loff_t offset, * size, read entire file content to the buffer and closes the file * */ -int integrity_read_file(const char *path, char **data) +int integrity_read_file(const char *path, char **data, + enum ima_read_hooks read_func) { struct file *file; loff_t size; @@ -222,6 +223,11 @@ int integrity_read_file(const char *path, char **data) return rc; } + if (!S_ISREG(file_inode(file)->i_mode)) { + rc = -EACCES; + goto out; + } + size = i_size_read(file_inode(file)); if (size <= 0) goto out; @@ -232,13 +238,18 @@ int integrity_read_file(const char *path, char **data) goto out; } - rc = integrity_kernel_read(file, 0, buf, size); + rc = ima_read_and_process_file(file, read_func, buf, size); + if (rc == -EOPNOTSUPP) { + rc = integrity_kernel_read(file, 0, buf, size); + if (rc > 0 && rc != size) + rc = -EIO; + } if (rc < 0) kfree(buf); - else if (rc != size) - rc = -EIO; - else + else { + rc = size; *data = buf; + } out: fput(file); return rc; diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 548b258..40a24c3 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -180,6 +180,7 @@ int ima_policy_show(struct seq_file *m, void *v); #define IMA_APPRAISE_LOG 0x04 #define IMA_APPRAISE_MODULES 0x08 #define IMA_APPRAISE_FIRMWARE 0x10 +#define IMA_APPRAISE_POLICY 0x20 #ifdef CONFIG_IMA_APPRAISE int ima_appraise_measurement(int func, struct integrity_iint_cache *iint, diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index b83049b..1e1a759 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -79,6 +79,7 @@ enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, case FIRMWARE_CHECK: case KEXEC_CHECK: case INITRAMFS_CHECK: + case POLICY_CHECK: return iint->ima_read_status; case FILE_CHECK: default: @@ -102,6 +103,7 @@ static void ima_set_cache_status(struct integrity_iint_cache *iint, case FIRMWARE_CHECK: case KEXEC_CHECK: case INITRAMFS_CHECK: + case POLICY_CHECK: iint->ima_read_status = status; break; case FILE_CHECK: @@ -126,6 +128,7 @@ static void ima_cache_flags(struct integrity_iint_cache *iint, int func) case FIRMWARE_CHECK: case KEXEC_CHECK: case INITRAMFS_CHECK: + case POLICY_CHECK: iint->flags |= (IMA_READ_APPRAISED | IMA_APPRAISED); break; case FILE_CHECK: diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index f902b6b..fdc5326 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -268,13 +268,12 @@ static ssize_t ima_read_policy(char *path) datap = path; strsep(&datap, "\n"); - rc = integrity_read_file(path, &data); + rc = integrity_read_file(path, &data, POLICY_CHECK); if (rc < 0) return rc; size = rc; datap = data; - while (size > 0 && (p = strsep(&datap, "\n"))) { pr_debug("rule: %s\n", p); rc = ima_parse_add_rule(p); @@ -324,7 +323,14 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf, if (data[0] == '/') result = ima_read_policy(data); - else + else if (ima_appraise & IMA_APPRAISE_POLICY) { + pr_err("IMA: signed policy required\n"); + integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL, + "policy_update", "signed policy required", + 1, 0); + if (ima_appraise & IMA_APPRAISE_ENFORCE) + result = -EACCES; + } else result = ima_parse_add_rule(data); out: if (result < 0) diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index a65cb2a..87614a6 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -116,6 +116,7 @@ static struct ima_rule_entry default_measurement_rules[] = { .uid = GLOBAL_ROOT_UID, .flags = IMA_FUNC | IMA_INMASK | IMA_UID}, {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC}, {.action = MEASURE, .read_func = FIRMWARE_CHECK, .flags = IMA_FUNC}, + {.action = MEASURE, .read_func = POLICY_CHECK, .flags = IMA_FUNC}, }; static struct ima_rule_entry default_appraise_rules[] = { @@ -307,6 +308,7 @@ static int get_subaction(struct ima_rule_entry *rule, int func) case FIRMWARE_CHECK: case KEXEC_CHECK: case INITRAMFS_CHECK: + case POLICY_CHECK: return IMA_READ_APPRAISE; case FILE_CHECK: default: @@ -613,6 +615,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) entry->read_func = INITRAMFS_CHECK; else if (strcmp(args[0].from, "FIRMWARE_CHECK") == 0) entry->read_func = FIRMWARE_CHECK; + else if (strcmp(args[0].from, "POLICY_CHECK") == 0) + entry->read_func = POLICY_CHECK; else result = -EINVAL; if (!result) @@ -771,6 +775,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) temp_ima_appraise |= IMA_APPRAISE_MODULES; else if (entry->read_func == FIRMWARE_CHECK) temp_ima_appraise |= IMA_APPRAISE_FIRMWARE; + else if (entry->read_func == POLICY_CHECK) + temp_ima_appraise |= IMA_APPRAISE_POLICY; audit_log_format(ab, "res=%d", !result); audit_log_end(ab); return result; @@ -857,7 +863,8 @@ static char *mask_tokens[] = { enum { func_file = 0, func_mmap, func_bprm, func_module, func_post, - func_kexec, func_initramfs, func_firmware + func_kexec, func_initramfs, func_firmware, + func_policy }; static char *func_tokens[] = { @@ -868,7 +875,8 @@ static char *func_tokens[] = { "POST_SETATTR", "KEXEC_CHECK", "INITRAMFS_CHECK", - "FIRMWARE_CHECK" + "FIRMWARE_CHECK", + "POLICY_CHECK" }; void *ima_policy_start(struct seq_file *m, loff_t *pos) @@ -956,6 +964,9 @@ int ima_policy_show(struct seq_file *m, void *v) case FIRMWARE_CHECK: seq_printf(m, pt(Opt_func), ft(func_firmware)); break; + case POLICY_CHECK: + seq_printf(m, pt(Opt_func), ft(func_policy)); + break; default: snprintf(tbuf, sizeof(tbuf), "%d", entry->func); seq_printf(m, pt(Opt_func), tbuf); diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index e6c37a4..a11d37c 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -15,6 +15,7 @@ #include <linux/integrity.h> #include <crypto/sha.h> #include <linux/key.h> +#include <linux/ima.h> /* iint action cache flags */ #define IMA_MEASURE 0x00000001 @@ -122,7 +123,8 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode); int integrity_kernel_read(struct file *file, loff_t offset, char *addr, unsigned long count); -int integrity_read_file(const char *path, char **data); +int integrity_read_file(const char *path, char **data, + enum ima_read_hooks read_hooks); #define INTEGRITY_KEYRING_EVM 0 #define INTEGRITY_KEYRING_IMA 1 -- 2.1.0 -- To unsubscribe from this list: send the line "unsubscribe linux-security-module" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html