euleros inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I7YT6U
--------------------------------
Isolate the IMA digest list code by using macros.
changelog v2: Exclude some macros for code that has already been merged into upstream kernel v3: add patch header and fix some simple code warnings v4: merge some duplicate code and add macro comments v5: format the code and update the issue number v6: merge duplicate code instead of isolating the entire function Signed-off-by: Zhou Shuiqing zhoushuiqing2@huawei.com --- fs/xattr.c | 4 + include/linux/evm.h | 5 +- include/linux/ima.h | 8 + include/linux/integrity.h | 2 + security/integrity/digsig_asymmetric.c | 4 + security/integrity/evm/evm.h | 2 + security/integrity/evm/evm_crypto.c | 38 ++++- security/integrity/evm/evm_main.c | 117 ++++++++++++++ security/integrity/iint.c | 4 + security/integrity/ima/ima.h | 62 ++++++- security/integrity/ima/ima_api.c | 39 +++++ security/integrity/ima/ima_appraise.c | 125 ++++++++++++++- security/integrity/ima/ima_fs.c | 187 +++++++++++++++++++++- security/integrity/ima/ima_init.c | 6 + security/integrity/ima/ima_main.c | 33 ++++ security/integrity/ima/ima_policy.c | 80 +++++++++ security/integrity/ima/ima_template.c | 2 + security/integrity/ima/ima_template_lib.c | 8 + security/integrity/ima/ima_template_lib.h | 2 + security/integrity/integrity.h | 32 ++-- security/security.c | 2 + 21 files changed, 736 insertions(+), 26 deletions(-)
diff --git a/fs/xattr.c b/fs/xattr.c index 149b8cf5f99f..c31266a83391 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -16,7 +16,9 @@ #include <linux/namei.h> #include <linux/security.h> #include <linux/evm.h> +#ifdef CONFIG_IMA_DIGEST_LIST #include <linux/ima.h> +#endif #include <linux/syscalls.h> #include <linux/export.h> #include <linux/fsnotify.h> @@ -475,7 +477,9 @@ __vfs_removexattr_locked(struct dentry *dentry, const char *name,
if (!error) { fsnotify_xattr(dentry); +#ifdef CONFIG_IMA_DIGEST_LIST ima_inode_post_removexattr(dentry, name); +#endif evm_inode_post_removexattr(dentry, name); }
diff --git a/include/linux/evm.h b/include/linux/evm.h index e5b7bcb152b9..fbaebb01b8a6 100644 --- a/include/linux/evm.h +++ b/include/linux/evm.h @@ -35,7 +35,9 @@ extern void evm_inode_post_removexattr(struct dentry *dentry, extern int evm_inode_init_security(struct inode *inode, const struct xattr *xattr_array, struct xattr *evm); +#ifdef CONFIG_IMA_DIGEST_LIST extern bool evm_status_revalidate(const char *xattr_name); +#endif #ifdef CONFIG_FS_POSIX_ACL extern int posix_xattr_acl(const char *xattrname); #else @@ -105,10 +107,11 @@ static inline int evm_inode_init_security(struct inode *inode, return 0; }
+#ifdef CONFIG_IMA_DIGEST_LIST static inline bool evm_status_revalidate(const char *xattr_name) { return false; } - +#endif /* CONFIG_IMA_DIGEST_LIST */ #endif /* CONFIG_EVM */ #endif /* LINUX_EVM_H */ diff --git a/include/linux/ima.h b/include/linux/ima.h index f7a088b2579e..713c6f9696cb 100644 --- a/include/linux/ima.h +++ b/include/linux/ima.h @@ -144,13 +144,17 @@ extern bool is_ima_appraise_enabled(void); extern void ima_inode_post_setattr(struct dentry *dentry); extern int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, const void *xattr_value, size_t xattr_value_len); +#ifdef CONFIG_IMA_DIGEST_LIST extern void ima_inode_post_setxattr(struct dentry *dentry, const char *xattr_name, const void *xattr_value, size_t xattr_value_len); +#endif extern int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name); +#ifdef CONFIG_IMA_DIGEST_LIST extern void ima_inode_post_removexattr(struct dentry *dentry, const char *xattr_name); +#endif #else static inline bool is_ima_appraise_enabled(void) { @@ -170,12 +174,14 @@ static inline int ima_inode_setxattr(struct dentry *dentry, return 0; }
+#ifdef CONFIG_IMA_DIGEST_LIST static inline void ima_inode_post_setxattr(struct dentry *dentry, const char *xattr_name, const void *xattr_value, size_t xattr_value_len) { } +#endif
static inline int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name) @@ -183,10 +189,12 @@ static inline int ima_inode_removexattr(struct dentry *dentry, return 0; }
+#ifdef CONFIG_IMA_DIGEST_LIST static inline void ima_inode_post_removexattr(struct dentry *dentry, const char *xattr_name) { } +#endif #endif /* CONFIG_IMA_APPRAISE */
#if defined(CONFIG_IMA_APPRAISE) && defined(CONFIG_INTEGRITY_TRUSTED_KEYRING) diff --git a/include/linux/integrity.h b/include/linux/integrity.h index 2ea0f2f65ab6..b3e403f214f0 100644 --- a/include/linux/integrity.h +++ b/include/linux/integrity.h @@ -13,7 +13,9 @@ enum integrity_status { INTEGRITY_PASS = 0, INTEGRITY_PASS_IMMUTABLE, INTEGRITY_FAIL, +#ifdef CONFIG_IMA_DIGEST_LIST INTEGRITY_FAIL_IMMUTABLE, +#endif INTEGRITY_NOLABEL, INTEGRITY_NOXATTRS, INTEGRITY_UNKNOWN, diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c index 92dc64755e53..72941f9b1b99 100644 --- a/security/integrity/digsig_asymmetric.c +++ b/security/integrity/digsig_asymmetric.c @@ -9,7 +9,9 @@ #include <linux/err.h> #include <linux/ratelimit.h> #include <linux/key-type.h> +#ifdef CONFIG_IMA_DIGEST_LIST #include <linux/verification.h> +#endif #include <crypto/public_key.h> #include <crypto/hash_info.h> #include <keys/asymmetric-type.h> @@ -55,6 +57,7 @@ static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid) key = request_key(&key_type_asymmetric, name, NULL); }
+#ifdef CONFIG_IMA_DIGEST_LIST if (IS_ERR(key)) { #ifdef CONFIG_IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY keyring = VERIFY_USE_SECONDARY_KEYRING; @@ -63,6 +66,7 @@ static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid) #endif key = search_trusted_key(keyring, &key_type_asymmetric, name); } +#endif
if (IS_ERR(key)) { if (keyring) diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h index ca7ed2e532dc..f8b1627708a1 100644 --- a/security/integrity/evm/evm.h +++ b/security/integrity/evm/evm.h @@ -32,7 +32,9 @@ struct xattr_list { };
extern int evm_initialized; +#ifdef CONFIG_IMA_DIGEST_LIST extern enum hash_algo evm_hash_algo; +#endif
#define EVM_ATTR_FSUUID 0x0001
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c index 7c36dbb96d24..8632b05145a7 100644 --- a/security/integrity/evm/evm_crypto.c +++ b/security/integrity/evm/evm_crypto.c @@ -33,7 +33,11 @@ static DEFINE_MUTEX(mutex);
static unsigned long evm_set_key_flags;
+#ifdef CONFIG_IMA_DIGEST_LIST enum hash_algo evm_hash_algo __ro_after_init = HASH_ALGO_SHA1; +#else +static const char evm_hmac[] = "hmac(sha1)"; +#endif
/** * evm_set_key() - set EVM HMAC key from the kernel @@ -74,11 +78,13 @@ static struct shash_desc *init_desc(char type, uint8_t hash_algo) long rc; const char *algo; struct crypto_shash **tfm, *tmp_tfm; - char evm_hmac[CRYPTO_MAX_ALG_NAME]; struct shash_desc *desc; +#ifdef CONFIG_IMA_DIGEST_LIST + char evm_hmac[CRYPTO_MAX_ALG_NAME];
snprintf(evm_hmac, sizeof(evm_hmac), "hmac(%s)", CONFIG_EVM_DEFAULT_HASH); +#endif
if (type == EVM_XATTR_HMAC) { if (!(evm_initialized & EVM_INIT_HMAC)) { @@ -156,8 +162,12 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode, /* Don't include the inode or generation number in portable * signatures */ +#ifdef CONFIG_IMA_DIGEST_LIST if (type != EVM_XATTR_PORTABLE_DIGSIG && type != EVM_IMA_XATTR_DIGEST_LIST) { +#else + if (type != EVM_XATTR_PORTABLE_DIGSIG) { +#endif hmac_misc.ino = inode->i_ino; hmac_misc.generation = inode->i_generation; } @@ -174,8 +184,12 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode, hmac_misc.mode = inode->i_mode; crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof(hmac_misc)); if ((evm_hmac_attrs & EVM_ATTR_FSUUID) && +#ifdef CONFIG_IMA_DIGEST_LIST type != EVM_XATTR_PORTABLE_DIGSIG && type != EVM_IMA_XATTR_DIGEST_LIST) +#else + type != EVM_IMA_XATTR_DIGEST_LIST) +#endif crypto_shash_update(desc, (u8 *)&inode->i_sb->s_uuid, UUID_SIZE); crypto_shash_final(desc, digest); } @@ -288,8 +302,12 @@ static int evm_is_immutable(struct dentry *dentry, struct inode *inode) return 0; return rc; } +#ifdef CONFIG_IMA_DIGEST_LIST if (xattr_data->type == EVM_XATTR_PORTABLE_DIGSIG || xattr_data->type == EVM_IMA_XATTR_DIGEST_LIST) +#else + if (xattr_data->type == EVM_XATTR_PORTABLE_DIGSIG) +#endif rc = 1; else rc = 0; @@ -321,15 +339,23 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name, if (rc) return -EPERM;
+#ifdef CONFIG_IMA_DIGEST_LIST data.hdr.algo = evm_hash_algo; +#else + data.hdr.algo = HASH_ALGO_SHA1; +#endif rc = evm_calc_hmac(dentry, xattr_name, xattr_value, xattr_value_len, &data); if (rc == 0) { data.hdr.xattr.sha1.type = EVM_XATTR_HMAC; rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_EVM, &data.hdr.xattr.data[1], +#ifdef CONFIG_IMA_DIGEST_LIST hash_digest_size[evm_hash_algo] + 1, 0); +#else + SHA1_DIGEST_SIZE + 1, 0); +#endif } else if (rc == -ENODATA && (inode->i_opflags & IOP_XATTR)) { rc = __vfs_removexattr(dentry, XATTR_NAME_EVM); } @@ -341,7 +367,11 @@ int evm_init_hmac(struct inode *inode, const struct xattr *lsm_xattr, { struct shash_desc *desc;
+#ifdef CONFIG_IMA_DIGEST_LIST desc = init_desc(EVM_XATTR_HMAC, evm_hash_algo); +#else + desc = init_desc(EVM_XATTR_HMAC, HASH_ALGO_SHA1); +#endif if (IS_ERR(desc)) { pr_info("init_desc failed\n"); return PTR_ERR(desc); @@ -353,9 +383,15 @@ int evm_init_hmac(struct inode *inode, const struct xattr *lsm_xattr, return 0; }
+#ifdef CONFIG_IMA_DIGEST_LIST /* * Get the key from the TPM for the HMAC */ +#else +/* + * Get the key from the TPM for the SHA1-HMAC + */ +#endif int evm_init_key(void) { struct key *evm_key; diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index cddfc0e43a80..c67271c45e50 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c @@ -18,7 +18,9 @@ #include <linux/integrity.h> #include <linux/evm.h> #include <linux/magic.h> +#ifdef CONFIG_IMA_DIGEST_LIST #include <linux/posix_acl_xattr.h> +#endif
#include <crypto/hash.h> #include <crypto/hash_info.h> @@ -27,10 +29,17 @@
int evm_initialized;
+#ifdef CONFIG_IMA_DIGEST_LIST static const char * const integrity_status_msg[] = { "pass", "pass_immutable", "fail", "fail_immutable", "no_label", "no_xattrs", "unknown" }; +#else +static const char * const integrity_status_msg[] = { + "pass", "pass_immutable", "fail", "no_label", "no_xattrs", "unknown" +}; +#endif + int evm_hmac_attrs;
static struct xattr_list evm_config_default_xattrnames[] = { @@ -57,22 +66,32 @@ static struct xattr_list evm_config_default_xattrnames[] = { LIST_HEAD(evm_config_xattrnames);
static int evm_fixmode __ro_after_init; +#ifdef CONFIG_IMA_DIGEST_LIST static int __init evm_set_param(char *str) +#else +static int __init evm_set_fixmode(char *str) +#endif { if (strncmp(str, "fix", 3) == 0) evm_fixmode = 1; +#ifdef CONFIG_IMA_DIGEST_LIST else if (strncmp(str, "x509", 4) == 0) evm_initialized |= EVM_INIT_X509; else if (strncmp(str, "allow_metadata_writes", 21) == 0) evm_initialized |= EVM_ALLOW_METADATA_WRITES; else if (strncmp(str, "complete", 8) == 0) evm_initialized |= EVM_SETUP_COMPLETE; +#endif else pr_err("invalid "%s" mode", str);
return 1; } +#ifdef CONFIG_IMA_DIGEST_LIST __setup("evm=", evm_set_param); +#else +__setup("evm=", evm_set_fixmode); +#endif
static void __init evm_init_config(void) { @@ -98,6 +117,7 @@ static bool evm_key_loaded(void) return (bool)(evm_initialized & EVM_KEY_MASK); }
+#ifdef CONFIG_IMA_DIGEST_LIST /* * Ignoring INTEGRITY_NOLABEL/INTEGRITY_NOXATTRS is safe if no HMAC key * is loaded and the EVM_SETUP_COMPLETE initialization flag is set. @@ -115,8 +135,13 @@ static bool evm_ignore_error_safe(enum integrity_status evm_status)
return true; } +#endif
+#ifdef CONFIG_IMA_DIGEST_LIST static int evm_find_protected_xattrs(struct dentry *dentry, int *ima_present) +#else +static int evm_find_protected_xattrs(struct dentry *dentry) +#endif { struct inode *inode = d_backing_inode(dentry); struct xattr_list *xattr; @@ -133,8 +158,10 @@ static int evm_find_protected_xattrs(struct dentry *dentry, int *ima_present) continue; return error; } +#ifdef CONFIG_IMA_DIGEST_LIST if (!strcmp(xattr->name, XATTR_NAME_IMA)) *ima_present = 1; +#endif count++; }
@@ -163,6 +190,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, struct evm_ima_xattr_data *xattr_data = NULL; struct signature_v2_hdr *hdr; enum integrity_status evm_status = INTEGRITY_PASS; +#ifdef CONFIG_IMA_DIGEST_LIST enum integrity_status saved_evm_status = INTEGRITY_UNKNOWN; struct evm_digest digest; struct ima_digest *found_digest; @@ -172,6 +200,12 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, .version = 2, .hash_algo = HASH_ALGO_SHA256 }; int rc, xattr_len, evm_immutable = 0, ima_present = 0;
+#else + struct evm_digest digest; + struct inode *inode; + int rc, xattr_len; +#endif + if (iint && (iint->evm_status == INTEGRITY_PASS || iint->evm_status == INTEGRITY_PASS_IMMUTABLE)) return iint->evm_status; @@ -184,7 +218,11 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, if (rc <= 0) { evm_status = INTEGRITY_FAIL; if (rc == -ENODATA) { +#ifdef CONFIG_IMA_DIGEST_LIST rc = evm_find_protected_xattrs(dentry, &ima_present); +#else + rc = evm_find_protected_xattrs(dentry); +#endif if (rc > 0) evm_status = INTEGRITY_NOLABEL; else if (rc == 0) @@ -192,6 +230,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, } else if (rc == -EOPNOTSUPP) { evm_status = INTEGRITY_UNKNOWN; } +#ifdef CONFIG_IMA_DIGEST_LIST /* IMA added a fake xattr, set also EVM fake xattr */ if (!ima_present && xattr_name && !strcmp(xattr_name, XATTR_NAME_IMA) && @@ -206,6 +245,9 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, goto out;
saved_evm_status = evm_status; +#else + goto out; +#endif }
xattr_len = rc; @@ -213,23 +255,37 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, /* check value type */ switch (xattr_data->type) { case EVM_XATTR_HMAC: +#ifdef CONFIG_IMA_DIGEST_LIST if (xattr_len != hash_digest_size[evm_hash_algo] + 1) { +#else + if (xattr_len != sizeof(struct evm_xattr)) { +#endif evm_status = INTEGRITY_FAIL; goto out; } +#ifdef CONFIG_IMA_DIGEST_LIST digest.hdr.algo = evm_hash_algo; +#else + digest.hdr.algo = HASH_ALGO_SHA1; +#endif rc = evm_calc_hmac(dentry, xattr_name, xattr_value, xattr_value_len, &digest); if (rc) break; rc = crypto_memneq(xattr_data->data, digest.digest, +#ifdef CONFIG_IMA_DIGEST_LIST hash_digest_size[evm_hash_algo]); +#else + SHA1_DIGEST_SIZE); +#endif if (rc) rc = -EINVAL; break; case EVM_XATTR_PORTABLE_DIGSIG: +#ifdef CONFIG_IMA_DIGEST_LIST evm_immutable = 1; fallthrough; +#endif case EVM_IMA_XATTR_DIGSIG: /* accept xattr with non-empty signature field */ if (xattr_len <= sizeof(struct signature_v2_hdr)) { @@ -262,6 +318,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, } } break; +#ifdef CONFIG_IMA_DIGEST_LIST case EVM_IMA_XATTR_DIGEST_LIST: /* At this point, we cannot determine whether metadata are * immutable or not. However, it is safe to return the @@ -302,11 +359,13 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, evm_status = INTEGRITY_PASS; } break; +#endif /* CONFIG_IMA_DIGEST_LIST */ default: rc = -EINVAL; break; }
+#ifdef CONFIG_IMA_DIGEST_LIST if (rc && xattr_data == (struct evm_ima_xattr_data *)&evm_fake_xattr) { evm_status = saved_evm_status; } else if (rc) { @@ -315,10 +374,17 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry, evm_status = evm_immutable ? INTEGRITY_FAIL_IMMUTABLE : INTEGRITY_FAIL; } +#else + if (rc) + evm_status = (rc == -ENODATA) ? + INTEGRITY_NOXATTRS : INTEGRITY_FAIL; +#endif out: if (iint) iint->evm_status = evm_status; +#ifdef CONFIG_IMA_DIGEST_LIST if (xattr_data != (struct evm_ima_xattr_data *)&evm_fake_xattr) +#endif kfree(xattr_data); return evm_status; } @@ -397,6 +463,7 @@ static enum integrity_status evm_verify_current_integrity(struct dentry *dentry) return evm_verify_hmac(dentry, NULL, NULL, 0, NULL); }
+#ifdef CONFIG_IMA_DIGEST_LIST /* * evm_xattr_acl_change - check if passed ACL changes the inode mode * @dentry: pointer to the affected dentry @@ -468,6 +535,7 @@ static int evm_xattr_change(struct dentry *dentry, const char *xattr_name, kfree(xattr_data); return rc; } +#endif
/* * evm_protect_xattr - protect the EVM extended attribute @@ -519,6 +587,7 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name, -EPERM, 0); } out: +#ifdef CONFIG_IMA_DIGEST_LIST if (evm_ignore_error_safe(evm_status)) return 0;
@@ -532,6 +601,7 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name, if (evm_status == INTEGRITY_PASS_IMMUTABLE && !evm_xattr_change(dentry, xattr_name, xattr_value, xattr_value_len)) return 0; +#endif
if (evm_status != INTEGRITY_PASS) integrity_audit_msg(AUDIT_INTEGRITY_METADATA, d_backing_inode(dentry), @@ -569,8 +639,12 @@ int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name, if (!xattr_value_len) return -EINVAL; if (xattr_data->type != EVM_IMA_XATTR_DIGSIG && +#ifdef CONFIG_IMA_DIGEST_LIST xattr_data->type != EVM_XATTR_PORTABLE_DIGSIG && xattr_data->type != EVM_IMA_XATTR_DIGEST_LIST) +#else + xattr_data->type != EVM_XATTR_PORTABLE_DIGSIG) +#endif return -EPERM; } return evm_protect_xattr(dentry, xattr_name, xattr_value, @@ -605,6 +679,7 @@ static void evm_reset_status(struct inode *inode) iint->evm_status = INTEGRITY_UNKNOWN; }
+#ifdef CONFIG_IMA_DIGEST_LIST /** * evm_status_revalidate - report whether EVM status re-validation is necessary * @xattr_name: pointer to the affected extended attribute name @@ -629,6 +704,7 @@ bool evm_status_revalidate(const char *xattr_name)
return true; } +#endif
/** * evm_inode_post_setxattr - update 'security.evm' to reflect the changes @@ -646,13 +722,20 @@ bool evm_status_revalidate(const char *xattr_name) void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name, const void *xattr_value, size_t xattr_value_len) { +#ifdef CONFIG_IMA_DIGEST_LIST if (!evm_status_revalidate(xattr_name)) +#else + if (!evm_key_loaded() || (!evm_protected_xattr(xattr_name) + && !posix_xattr_acl(xattr_name))) +#endif return;
evm_reset_status(dentry->d_inode);
+#ifdef CONFIG_IMA_DIGEST_LIST if (!strcmp(xattr_name, XATTR_NAME_EVM)) return; +#endif
evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len); } @@ -669,17 +752,24 @@ void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name, */ void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name) { +#ifdef CONFIG_IMA_DIGEST_LIST if (!evm_status_revalidate(xattr_name)) +#else + if (!evm_key_loaded() || !evm_protected_xattr(xattr_name)) +#endif return;
evm_reset_status(dentry->d_inode);
+#ifdef CONFIG_IMA_DIGEST_LIST if (!strcmp(xattr_name, XATTR_NAME_EVM)) return; +#endif
evm_update_evmxattr(dentry, xattr_name, NULL, 0); }
+#ifdef CONFIG_IMA_DIGEST_LIST static int evm_attr_change(struct dentry *dentry, struct iattr *attr) { struct inode *inode = d_backing_inode(dentry); @@ -692,6 +782,7 @@ static int evm_attr_change(struct dentry *dentry, struct iattr *attr)
return 1; } +#endif
/** * evm_inode_setattr - prevent updating an invalid EVM extended attribute @@ -714,19 +805,26 @@ int evm_inode_setattr(struct dentry *dentry, struct iattr *attr) if (!(ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))) return 0; evm_status = evm_verify_current_integrity(dentry); + /* * Writing attrs is safe for portable signatures, as portable signatures * are immutable and can never be updated. */ if ((evm_status == INTEGRITY_PASS) || +#ifdef CONFIG_IMA_DIGEST_LIST (evm_status == INTEGRITY_NOXATTRS) || (evm_status == INTEGRITY_FAIL_IMMUTABLE) || (evm_ignore_error_safe(evm_status))) +#else + (evm_status == INTEGRITY_NOXATTRS)) +#endif return 0;
+#ifdef CONFIG_IMA_DIGEST_LIST if (evm_status == INTEGRITY_PASS_IMMUTABLE && !evm_attr_change(dentry, attr)) return 0; +#endif
integrity_audit_msg(AUDIT_INTEGRITY_METADATA, d_backing_inode(dentry), dentry->d_name.name, "appraise_metadata", @@ -747,10 +845,16 @@ int evm_inode_setattr(struct dentry *dentry, struct iattr *attr) */ void evm_inode_post_setattr(struct dentry *dentry, int ia_valid) { +#ifdef CONFIG_IMA_DIGEST_LIST if (!evm_status_revalidate(NULL)) +#else + if (!evm_key_loaded()) +#endif return;
+#ifdef CONFIG_IMA_DIGEST_LIST evm_reset_status(dentry->d_inode); +#endif
if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)) evm_update_evmxattr(dentry, NULL, NULL, 0); @@ -766,8 +870,12 @@ int evm_inode_init_security(struct inode *inode, struct evm_xattr *xattr_data; int rc;
+#ifdef CONFIG_IMA_DIGEST_LIST if (!(evm_initialized & EVM_INIT_HMAC) || !evm_protected_xattr(lsm_xattr->name)) +#else + if (!evm_key_loaded() || !evm_protected_xattr(lsm_xattr->name)) +#endif return 0;
xattr_data = kzalloc(sizeof(*xattr_data), GFP_NOFS); @@ -780,7 +888,11 @@ int evm_inode_init_security(struct inode *inode, goto out;
evm_xattr->value = xattr_data; +#ifdef CONFIG_IMA_DIGEST_LIST evm_xattr->value_len = hash_digest_size[evm_hash_algo] + 1; +#else + evm_xattr->value_len = sizeof(*xattr_data); +#endif evm_xattr->name = XATTR_EVM_SUFFIX; return 0; out: @@ -802,6 +914,7 @@ void __init evm_load_x509(void)
static int __init init_evm(void) { +#ifdef CONFIG_IMA_DIGEST_LIST int error, i; struct list_head *pos, *q;
@@ -809,6 +922,10 @@ static int __init init_evm(void) CONFIG_EVM_DEFAULT_HASH); if (i >= 0) evm_hash_algo = i; +#else + int error; + struct list_head *pos, *q; +#endif
evm_init_config();
diff --git a/security/integrity/iint.c b/security/integrity/iint.c index 8953ac6412c3..bd66cadc4a3a 100644 --- a/security/integrity/iint.c +++ b/security/integrity/iint.c @@ -209,10 +209,14 @@ void __init integrity_load_keys(void) { ima_load_x509();
+#ifdef CONFIG_IMA_DIGEST_LIST if (!IS_ENABLED(CONFIG_IMA_LOAD_X509)) +#endif evm_load_x509();
+#ifdef CONFIG_IMA_DIGEST_LIST ima_load_digest_lists(); +#endif }
static int __init integrity_fs_init(void) diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h index 46afb6bef45b..2145eb0c76e0 100644 --- a/security/integrity/ima/ima.h +++ b/security/integrity/ima/ima.h @@ -53,11 +53,11 @@ extern int ima_hash_algo_idx __ro_after_init; extern int ima_extra_slots __ro_after_init; extern int ima_appraise; extern struct tpm_chip *ima_tpm_chip; +extern const char boot_aggregate_name[]; +#ifdef CONFIG_IMA_DIGEST_LIST extern int ima_digest_list_pcr; extern bool ima_plus_standard_pcr; -extern const char boot_aggregate_name[]; extern int ima_digest_list_actions; -#ifdef CONFIG_IMA_DIGEST_LIST extern int ima_digest_db_max_size __ro_after_init; extern int ima_digest_db_size; #endif @@ -189,6 +189,7 @@ static inline unsigned int ima_hash_key(u8 *digest) return (digest[0] | digest[1] << 8) % IMA_MEASURE_HTABLE_SIZE; }
+#ifdef CONFIG_IMA_DIGEST_LIST #define __ima_hooks(hook) \ hook(NONE, none) \ hook(FILE_CHECK, file) \ @@ -205,6 +206,23 @@ static inline unsigned int ima_hash_key(u8 *digest) hook(KEY_CHECK, key) \ hook(DIGEST_LIST_CHECK, digest_list) \ hook(MAX_CHECK, none) +#else +#define __ima_hooks(hook) \ + hook(NONE, none) \ + hook(FILE_CHECK, file) \ + hook(MMAP_CHECK, mmap) \ + hook(BPRM_CHECK, bprm) \ + hook(CREDS_CHECK, creds) \ + hook(POST_SETATTR, post_setattr) \ + hook(MODULE_CHECK, module) \ + hook(FIRMWARE_CHECK, firmware) \ + hook(KEXEC_KERNEL_CHECK, kexec_kernel) \ + hook(KEXEC_INITRAMFS_CHECK, kexec_initramfs) \ + hook(POLICY_CHECK, policy) \ + hook(KEXEC_CMDLINE, kexec_cmdline) \ + hook(KEY_CHECK, key) \ + hook(MAX_CHECK, none) +#endif /* CONFIG_IMA_DIGEST_LIST */
#define __ima_hook_enumify(ENUM, str) ENUM, #define __ima_stringify(arg) (#arg) @@ -268,8 +286,12 @@ void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file, const unsigned char *filename, struct evm_ima_xattr_data *xattr_value, int xattr_len, const struct modsig *modsig, int pcr, +#ifdef CONFIG_IMA_DIGEST_LIST struct ima_template_desc *template_desc, struct ima_digest *digest); +#else + struct ima_template_desc *template_desc); +#endif void process_buffer_measurement(struct inode *inode, const void *buf, int size, const char *eventname, enum ima_hooks func, int pcr, const char *keyring); @@ -280,7 +302,11 @@ int ima_alloc_init_template(struct ima_event_data *event_data, struct ima_template_desc *template_desc); int ima_store_template(struct ima_template_entry *entry, int violation, struct inode *inode, const unsigned char *filename, +#ifdef CONFIG_IMA_DIGEST_LIST int pcr, struct ima_digest *digest); +#else + int pcr); +#endif void ima_free_template_entry(struct ima_template_entry *entry); const char *ima_d_path(const struct path *path, char **pathbuf, char *filename);
@@ -308,7 +334,9 @@ int ima_policy_show(struct seq_file *m, void *v); #define IMA_APPRAISE_FIRMWARE 0x10 #define IMA_APPRAISE_POLICY 0x20 #define IMA_APPRAISE_KEXEC 0x40 +#ifdef CONFIG_IMA_DIGEST_LIST #define IMA_APPRAISE_DIGEST_LIST 0x80 +#endif
#ifdef CONFIG_IMA_APPRAISE int ima_check_blacklist(struct integrity_iint_cache *iint, @@ -317,12 +345,24 @@ int ima_appraise_measurement(enum ima_hooks func, struct integrity_iint_cache *iint, struct file *file, const unsigned char *filename, struct evm_ima_xattr_data *xattr_value, +#ifdef CONFIG_IMA_DIGEST_LIST int xattr_len, const struct modsig *modsig, struct ima_digest *found_digest); +#else + int xattr_len, const struct modsig *modsig); +#endif + int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func); void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file); enum integrity_status ima_get_cache_status(struct integrity_iint_cache *iint, enum ima_hooks func); +#ifndef CONFIG_IMA_DIGEST_LIST +enum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, + int xattr_len); +int ima_read_xattr(struct dentry *dentry, + struct evm_ima_xattr_data **xattr_value); +#endif + #else static inline int ima_check_blacklist(struct integrity_iint_cache *iint, const struct modsig *modsig, int pcr) @@ -336,8 +376,12 @@ static inline int ima_appraise_measurement(enum ima_hooks func, const unsigned char *filename, struct evm_ima_xattr_data *xattr_value, int xattr_len, +#ifndef CONFIG_IMA_DIGEST_LIST const struct modsig *modsig, struct ima_digest *found_digest) +#else + const struct modsig *modsig) +#endif { return INTEGRITY_UNKNOWN; } @@ -360,6 +404,20 @@ static inline enum integrity_status ima_get_cache_status(struct integrity_iint_c return INTEGRITY_UNKNOWN; }
+#ifndef CONFIG_IMA_DIGEST_LIST +static inline enum hash_algo +ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, int xattr_len) +{ + return ima_hash_algo; +} + +static inline int ima_read_xattr(struct dentry *dentry, + struct evm_ima_xattr_data **xattr_value) +{ + return 0; +} +#endif + #endif /* CONFIG_IMA_APPRAISE */
#ifdef CONFIG_IMA_APPRAISE_MODSIG diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index 6ecaf6834844..1b8d3696d873 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -99,15 +99,23 @@ int ima_alloc_init_template(struct ima_event_data *event_data, * * Returns 0 on success, error code otherwise */ +#ifdef CONFIG_IMA_DIGEST_LIST int ima_store_template(struct ima_template_entry *entry, int violation, struct inode *inode, const unsigned char *filename, int pcr, struct ima_digest *digest) +#else +int ima_store_template(struct ima_template_entry *entry, + int violation, struct inode *inode, + const unsigned char *filename, int pcr) +#endif { static const char op[] = "add_template_measure"; static const char audit_cause[] = "hashing_error"; char *template_name = entry->template_desc->name; +#ifdef CONFIG_IMA_DIGEST_LIST struct ima_template_entry *duplicated_entry = NULL; +#endif int result;
if (!violation) { @@ -121,6 +129,7 @@ int ima_store_template(struct ima_template_entry *entry, } }
+#ifdef CONFIG_IMA_DIGEST_LIST if (ima_plus_standard_pcr && !digest) { duplicated_entry = kmemdup(entry, sizeof(*entry) + entry->template_desc->num_fields * @@ -130,9 +139,11 @@ int ima_store_template(struct ima_template_entry *entry, } else if (!ima_plus_standard_pcr && ima_digest_list_pcr >= 0) { pcr = ima_digest_list_pcr; } +#endif
entry->pcr = pcr; result = ima_add_template_entry(entry, violation, op, inode, filename); +#ifdef CONFIG_IMA_DIGEST_LIST if (result) { kfree(duplicated_entry); } else if (duplicated_entry) { @@ -141,6 +152,7 @@ int ima_store_template(struct ima_template_entry *entry, if (result < 0) kfree(duplicated_entry); } +#endif
return result; } @@ -173,8 +185,13 @@ void ima_add_violation(struct file *file, const unsigned char *filename, result = -ENOMEM; goto err_out; } +#ifdef CONFIG_IMA_DIGEST_LIST result = ima_store_template(entry, violation, inode, filename, CONFIG_IMA_MEASURE_PCR_IDX, NULL); +#else + result = ima_store_template(entry, violation, inode, + filename, CONFIG_IMA_MEASURE_PCR_IDX); +#endif if (result < 0) ima_free_template_entry(entry); err_out: @@ -315,18 +332,30 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, * * Must be called with iint->mutex held. */ +#ifdef CONFIG_IMA_DIGEST_LIST void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file, const unsigned char *filename, struct evm_ima_xattr_data *xattr_value, int xattr_len, const struct modsig *modsig, int pcr, struct ima_template_desc *template_desc, struct ima_digest *digest) +#else +void ima_store_measurement(struct integrity_iint_cache *iint, + struct file *file, const unsigned char *filename, + struct evm_ima_xattr_data *xattr_value, + int xattr_len, const struct modsig *modsig, int pcr, + struct ima_template_desc *template_desc) +#endif { static const char op[] = "add_template_measure"; static const char audit_cause[] = "ENOMEM"; int result = -ENOMEM; struct inode *inode = file_inode(file); +#ifdef CONFIG_IMA_DIGEST_LIST struct ima_template_entry *entry = NULL; +#else + struct ima_template_entry *entry; +#endif struct ima_event_data event_data = { .iint = iint, .file = file, .filename = filename, @@ -344,10 +373,12 @@ void ima_store_measurement(struct integrity_iint_cache *iint, if (iint->measured_pcrs & (0x1 << pcr) && !modsig) return;
+#ifdef CONFIG_IMA_DIGEST_LIST if (digest && !ima_plus_standard_pcr && ima_digest_list_pcr >= 0) { result = -EEXIST; goto out; } +#endif
result = ima_alloc_init_template(&event_data, &entry, template_desc); if (result < 0) { @@ -356,14 +387,22 @@ void ima_store_measurement(struct integrity_iint_cache *iint, return; }
+#ifdef CONFIG_IMA_DIGEST_LIST result = ima_store_template(entry, violation, inode, filename, pcr, digest); out: +#else + result = ima_store_template(entry, violation, inode, filename, pcr); +#endif if ((!result || result == -EEXIST) && !(file->f_flags & O_DIRECT)) { iint->flags |= IMA_MEASURED; iint->measured_pcrs |= (0x1 << pcr); } +#ifdef CONFIG_IMA_DIGEST_LIST if (result < 0 && entry) +#else + if (result < 0) +#endif ima_free_template_entry(entry); }
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 956fb0f4c006..3c59049e58ad 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -15,9 +15,11 @@ #include <keys/system_keyring.h>
#include "ima.h" +#ifdef CONFIG_IMA_DIGEST_LIST #include "ima_digest_list.h"
static bool ima_appraise_req_evm __ro_after_init; +#endif static int __init default_appraise_setup(char *str) { #ifdef CONFIG_IMA_APPRAISE_BOOTPARAM @@ -45,16 +47,18 @@ static int __init default_appraise_setup(char *str) ima_appraise = appraisal_state; } #endif +#ifdef CONFIG_IMA_DIGEST_LIST if (strcmp(str, "enforce-evm") == 0 || strcmp(str, "log-evm") == 0) ima_appraise_req_evm = true; +#endif return 1; }
__setup("ima_appraise=", default_appraise_setup);
-static bool ima_appraise_no_metadata __ro_after_init; #ifdef CONFIG_IMA_DIGEST_LIST +static bool ima_appraise_no_metadata __ro_after_init; static int __init appraise_digest_list_setup(char *str) { if (!strncmp(str, "digest", 6)) { @@ -108,9 +112,11 @@ static int ima_fix_xattr(struct dentry *dentry, } else { offset = 0; iint->ima_hash->xattr.ng.type = IMA_XATTR_DIGEST_NG; +#ifdef CONFIG_IMA_DIGEST_LIST if (test_bit(IMA_DIGEST_LIST, &iint->atomic_flags)) iint->ima_hash->xattr.ng.type = EVM_IMA_XATTR_DIGEST_LIST; +#endif iint->ima_hash->xattr.ng.algo = algo; } rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_IMA, @@ -189,6 +195,60 @@ static void ima_cache_flags(struct integrity_iint_cache *iint, } }
+#ifndef CONFIG_IMA_DIGEST_LIST +enum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, + int xattr_len) +{ + struct signature_v2_hdr *sig; + enum hash_algo ret; + + if (!xattr_value || xattr_len < 2) + /* return default hash algo */ + return ima_hash_algo; + + switch (xattr_value->type) { + case EVM_IMA_XATTR_DIGSIG: + sig = (typeof(sig))xattr_value; + if (sig->version != 2 || xattr_len <= sizeof(*sig)) + return ima_hash_algo; + return sig->hash_algo; + case IMA_XATTR_DIGEST_NG: + /* first byte contains algorithm id */ + ret = xattr_value->data[0]; + if (ret < HASH_ALGO__LAST) + return ret; + break; + case IMA_XATTR_DIGEST: + /* this is for backward compatibility */ + if (xattr_len == 21) { + unsigned int zero = 0; + + if (!memcmp(&xattr_value->data[16], &zero, 4)) + return HASH_ALGO_MD5; + else + return HASH_ALGO_SHA1; + } else if (xattr_len == 17) + return HASH_ALGO_MD5; + break; + } + + /* return default hash algo */ + return ima_hash_algo; +} + +int ima_read_xattr(struct dentry *dentry, + struct evm_ima_xattr_data **xattr_value) +{ + ssize_t ret; + + ret = vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)xattr_value, + 0, GFP_NOFS); + if (ret == -EOPNOTSUPP) + ret = 0; + return ret; +} +#endif /* CONFIG_IMA_DIGEST_LIST */ + /* * xattr_verify - verify xattr digest or signature * @@ -196,18 +256,27 @@ static void ima_cache_flags(struct integrity_iint_cache *iint, * * Return 0 on success, error code otherwise. */ +#ifdef CONFIG_IMA_DIGEST_LIST static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint, struct evm_ima_xattr_data *xattr_value, int xattr_len, enum integrity_status *status, const char **cause, struct ima_digest *found_digest) +#else +static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint, + struct evm_ima_xattr_data *xattr_value, int xattr_len, + enum integrity_status *status, const char **cause) +#endif { int rc = -EINVAL, hash_start = 0;
+#ifdef CONFIG_IMA_DIGEST_LIST if (found_digest && *status != INTEGRITY_PASS && *status != INTEGRITY_PASS_IMMUTABLE) set_bit(IMA_DIGEST_LIST, &iint->atomic_flags); +#endif
switch (xattr_value->type) { +#ifdef CONFIG_IMA_DIGEST_LIST case EVM_IMA_XATTR_DIGEST_LIST: set_bit(IMA_DIGEST_LIST, &iint->atomic_flags);
@@ -217,21 +286,28 @@ static int xattr_verify(enum ima_hooks func, struct integrity_iint_cache *iint, break; } fallthrough; +#endif case IMA_XATTR_DIGEST_NG: /* first byte contains algorithm id */ hash_start = 1; fallthrough; case IMA_XATTR_DIGEST: +#ifdef CONFIG_IMA_DIGEST_LIST if (*status != INTEGRITY_PASS_IMMUTABLE && (!found_digest || !ima_digest_is_immutable(found_digest))) { +#else + if (*status != INTEGRITY_PASS_IMMUTABLE) { +#endif if (iint->flags & IMA_DIGSIG_REQUIRED) { *cause = "IMA-signature-required"; *status = INTEGRITY_FAIL; break; } +#ifdef CONFIG_IMA_DIGEST_LIST clear_bit(IMA_DIGSIG, &iint->atomic_flags); } else { set_bit(IMA_DIGSIG, &iint->atomic_flags); +#endif } if (xattr_len - sizeof(xattr_value->type) - hash_start >= iint->ima_hash->length) @@ -352,26 +428,39 @@ int ima_check_blacklist(struct integrity_iint_cache *iint, * * Return 0 on success, error code otherwise */ +#ifdef CONFIG_IMA_DIGEST_LIST int ima_appraise_measurement(enum ima_hooks func, struct integrity_iint_cache *iint, struct file *file, const unsigned char *filename, struct evm_ima_xattr_data *xattr_value, int xattr_len, const struct modsig *modsig, struct ima_digest *found_digest) +#else +int ima_appraise_measurement(enum ima_hooks func, + struct integrity_iint_cache *iint, + struct file *file, const unsigned char *filename, + struct evm_ima_xattr_data *xattr_value, + int xattr_len, const struct modsig *modsig) +#endif { static const char op[] = "appraise_data"; const char *cause = "unknown"; struct dentry *dentry = file_dentry(file); struct inode *inode = d_backing_inode(dentry); enum integrity_status status = INTEGRITY_UNKNOWN; +#ifdef CONFIG_IMA_DIGEST_LIST int rc = xattr_len, rc_evm; char _buf[sizeof(struct evm_ima_xattr_data) + 1 + SHA512_DIGEST_SIZE]; +#else + int rc = xattr_len; +#endif bool try_modsig = iint->flags & IMA_MODSIG_ALLOWED && modsig;
/* If not appraising a modsig, we need an xattr. */ if (!(inode->i_opflags & IOP_XATTR) && !try_modsig) return INTEGRITY_UNKNOWN;
+#ifdef CONFIG_IMA_DIGEST_LIST if (xattr_value && xattr_value->type == EVM_IMA_XATTR_DIGSIG && xattr_len == sizeof(struct signature_v2_hdr)) rc = -ENODATA; @@ -394,6 +483,7 @@ int ima_appraise_measurement(enum ima_hooks func, rc = xattr_len; } } +#endif /* CONFIG_IMA_DIGEST_LIST */
/* If reading the xattr failed and there's no modsig, error out. */ if (rc <= 0 && !try_modsig) { @@ -417,11 +507,15 @@ int ima_appraise_measurement(enum ima_hooks func, switch (status) { case INTEGRITY_PASS: case INTEGRITY_PASS_IMMUTABLE: +#ifdef CONFIG_IMA_DIGEST_LIST break; case INTEGRITY_UNKNOWN: if (ima_appraise_req_evm && xattr_value->type != EVM_IMA_XATTR_DIGSIG && !found_digest) goto out; +#else + case INTEGRITY_UNKNOWN: +#endif break; case INTEGRITY_NOXATTRS: /* No EVM protected xattrs. */ /* It's fine not to have xattrs when using a modsig. */ @@ -429,6 +523,7 @@ int ima_appraise_measurement(enum ima_hooks func, break; fallthrough; case INTEGRITY_NOLABEL: /* No security.evm xattr. */ +#ifdef CONFIG_IMA_DIGEST_LIST /* * If the digest-nometadata mode is selected, allow access * without metadata check. EVM will eventually create an HMAC @@ -446,11 +541,14 @@ int ima_appraise_measurement(enum ima_hooks func, ima_digest_is_immutable(found_digest)) break; } +#endif cause = "missing-HMAC"; goto out; +#ifdef CONFIG_IMA_DIGEST_LIST case INTEGRITY_FAIL_IMMUTABLE: set_bit(IMA_DIGSIG, &iint->atomic_flags); fallthrough; +#endif case INTEGRITY_FAIL: /* Invalid HMAC/signature. */ cause = "invalid-HMAC"; goto out; @@ -458,6 +556,7 @@ int ima_appraise_measurement(enum ima_hooks func, WARN_ONCE(true, "Unexpected integrity status %d\n", status); }
+#ifdef CONFIG_IMA_DIGEST_LIST if ((iint->flags & IMA_META_IMMUTABLE_REQUIRED) && status != INTEGRITY_PASS_IMMUTABLE) { status = INTEGRITY_FAIL; @@ -466,10 +565,15 @@ int ima_appraise_measurement(enum ima_hooks func, filename, op, cause, rc, 0); goto out; } +#endif
if (xattr_value) rc = xattr_verify(func, iint, xattr_value, xattr_len, &status, +#ifdef CONFIG_IMA_DIGEST_LIST &cause, found_digest); +#else + &cause); +#endif
/* * If we have a modsig and either no imasig or the imasig's key isn't @@ -508,7 +612,11 @@ int ima_appraise_measurement(enum ima_hooks func, * without data. */ if (inode->i_size == 0 && iint->flags & IMA_NEW_FILE && +#ifdef CONFIG_IMA_DIGEST_LIST test_bit(IMA_DIGSIG, &iint->atomic_flags)) { +#else + xattr_value && xattr_value->type == EVM_IMA_XATTR_DIGSIG) { +#endif status = INTEGRITY_PASS; }
@@ -567,6 +675,10 @@ void ima_inode_post_setattr(struct dentry *dentry) return;
action = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR); +#ifndef CONFIG_IMA_DIGEST_LIST + if (!action) + __vfs_removexattr(dentry, XATTR_NAME_IMA); +#endif iint = integrity_iint_find(inode); if (iint) { set_bit(IMA_CHANGE_ATTR, &iint->atomic_flags); @@ -620,11 +732,16 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, if (result == 1) { if (!xattr_value_len || (xvalue->type >= IMA_XATTR_LAST)) return -EINVAL; +#ifndef CONFIG_IMA_DIGEST_LIST + ima_reset_appraise_flags(d_backing_inode(dentry), + xvalue->type == EVM_IMA_XATTR_DIGSIG); +#endif result = 0; } return result; }
+#ifdef CONFIG_IMA_DIGEST_LIST void ima_inode_post_setxattr(struct dentry *dentry, const char *xattr_name, const void *xattr_value, size_t xattr_value_len) { @@ -641,6 +758,7 @@ void ima_inode_post_setxattr(struct dentry *dentry, const char *xattr_name, if (result == 1 || evm_status_revalidate(xattr_name)) ima_reset_appraise_flags(d_backing_inode(dentry), digsig); } +#endif
int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name) { @@ -648,11 +766,15 @@ int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name)
result = ima_protect_xattr(dentry, xattr_name, NULL, 0); if (result == 1) { +#ifndef CONFIG_IMA_DIGEST_LIST + ima_reset_appraise_flags(d_backing_inode(dentry), 0); +#endif result = 0; } return result; }
+#ifdef CONFIG_IMA_DIGEST_LIST void ima_inode_post_removexattr(struct dentry *dentry, const char *xattr_name) { int result; @@ -661,3 +783,4 @@ void ima_inode_post_removexattr(struct dentry *dentry, const char *xattr_name) if (result == 1 || evm_status_revalidate(xattr_name)) ima_reset_appraise_flags(d_backing_inode(dentry), 0); } +#endif diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index f1bc3e201bd8..dd577ae68381 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c @@ -21,11 +21,15 @@ #include <linux/rcupdate.h> #include <linux/parser.h> #include <linux/vmalloc.h> +#ifdef CONFIG_IMA_DIGEST_LIST #include <linux/file.h> +#endif #include <linux/ctype.h>
#include "ima.h" +#ifdef CONFIG_IMA_DIGEST_LIST #include "ima_digest_list.h" +#endif
static DEFINE_MUTEX(ima_write_mutex);
@@ -36,9 +40,11 @@ static struct dentry *ascii_runtime_measurements; static struct dentry *runtime_measurements_count; static struct dentry *violations; static struct dentry *ima_policy; +#ifdef CONFIG_IMA_DIGEST_LIST static struct dentry *digests_count; static struct dentry *digest_list_data; static struct dentry *digest_list_data_del; +#endif
bool ima_canonical_fmt; static int __init default_canonical_fmt_setup(char *str) @@ -52,18 +58,24 @@ __setup("ima_canonical_fmt", default_canonical_fmt_setup);
static int valid_policy = 1;
+#ifdef CONFIG_IMA_DIGEST_LIST static ssize_t ima_show_htable_value(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { atomic_long_t *val = NULL; +#else +static ssize_t ima_show_htable_value(char __user *buf, size_t count, + loff_t *ppos, atomic_long_t *val) +{ +#endif char tmpbuf[32]; /* greater than largest 'long' string value */ ssize_t len;
+#ifdef CONFIG_IMA_DIGEST_LIST if (filp->f_path.dentry == violations) val = &ima_htable.violations; else if (filp->f_path.dentry == runtime_measurements_count) val = &ima_htable.len; -#ifdef CONFIG_IMA_DIGEST_LIST else if (filp->f_path.dentry == digests_count) val = &ima_digests_htable.len; #endif @@ -72,10 +84,37 @@ static ssize_t ima_show_htable_value(struct file *filp, char __user *buf, return simple_read_from_buffer(buf, count, ppos, tmpbuf, len); }
+#ifdef CONFIG_IMA_DIGEST_LIST static const struct file_operations ima_htable_value_ops = { .read = ima_show_htable_value, .llseek = generic_file_llseek, }; +#else +static ssize_t ima_show_htable_violations(struct file *filp, + char __user *buf, + size_t count, loff_t *ppos) +{ + return ima_show_htable_value(buf, count, ppos, &ima_htable.violations); +} + +static const struct file_operations ima_htable_violations_ops = { + .read = ima_show_htable_violations, + .llseek = generic_file_llseek, +}; + +static ssize_t ima_show_measurements_count(struct file *filp, + char __user *buf, + size_t count, loff_t *ppos) +{ + return ima_show_htable_value(buf, count, ppos, &ima_htable.len); + +} + +static const struct file_operations ima_measurements_count_ops = { + .read = ima_show_measurements_count, + .llseek = generic_file_llseek, +}; +#endif /* CONFIG_IMA_DIGEST_LIST */
/* returns pointer to hlist_node */ static void *ima_measurements_start(struct seq_file *m, loff_t *pos) @@ -275,14 +314,20 @@ static const struct file_operations ima_ascii_measurements_ops = { .release = seq_release, };
+#ifdef CONFIG_IMA_DIGEST_LIST static ssize_t ima_read_file(char *path, struct dentry *dentry) +#else +static ssize_t ima_read_policy(char *path) +#endif { void *data = NULL; char *datap; size_t size; +#ifdef CONFIG_IMA_DIGEST_LIST struct file *file; enum kernel_read_file_id file_id = READING_POLICY; int op = DIGEST_LIST_OP_ADD; +#endif int rc, pathlen = strlen(path);
char *p; @@ -291,6 +336,7 @@ static ssize_t ima_read_file(char *path, struct dentry *dentry) datap = path; strsep(&datap, "\n");
+#ifdef CONFIG_IMA_DIGEST_LIST if (dentry == digest_list_data || dentry == digest_list_data_del) file_id = READING_DIGEST_LIST;
@@ -301,26 +347,38 @@ static ssize_t ima_read_file(char *path, struct dentry *dentry) }
rc = kernel_read_file(file, 0, &data, INT_MAX, NULL, file_id); +#else + rc = kernel_read_file_from_path(path, 0, &data, INT_MAX, NULL, + READING_POLICY); +#endif if (rc < 0) { +#ifdef CONFIG_IMA_DIGEST_LIST pr_err("Unable to read file: %s (%d)", path, rc); fput(file); +#else + pr_err("Unable to open file: %s (%d)", path, rc); +#endif return rc; } size = rc; rc = 0;
datap = data; +#ifdef CONFIG_IMA_DIGEST_LIST while (size > 0) { if (dentry == ima_policy) { p = strsep(&datap, "\n"); if (p == NULL) break;
+#else + while (size > 0 && (p = strsep(&datap, "\n"))) { +#endif pr_debug("rule: %s\n", p); rc = ima_parse_add_rule(p); +#ifdef CONFIG_IMA_DIGEST_LIST } else if (dentry == digest_list_data || dentry == digest_list_data_del) { -#ifdef CONFIG_IMA_DIGEST_LIST /* Only check size when adding digest lists */ if (dentry == digest_list_data && size > ima_digest_db_max_size - ima_digest_db_size) { @@ -328,7 +386,6 @@ static ssize_t ima_read_file(char *path, struct dentry *dentry) rc = -ENOMEM; break; } -#endif /* * Disable usage of digest lists if not measured * or appraised. @@ -340,7 +397,7 @@ static ssize_t ima_read_file(char *path, struct dentry *dentry)
rc = ima_parse_compact_list(size, data, op); } - +#endif if (rc < 0) break; #ifdef CONFIG_IMA_DIGEST_LIST @@ -353,7 +410,9 @@ static ssize_t ima_read_file(char *path, struct dentry *dentry) }
vfree(data); +#ifdef CONFIG_IMA_DIGEST_LIST fput(file); +#endif if (rc < 0) return rc; else if (size) @@ -362,19 +421,31 @@ static ssize_t ima_read_file(char *path, struct dentry *dentry) return pathlen; }
+#ifdef CONFIG_IMA_DIGEST_LIST static ssize_t ima_write_data(struct file *file, const char __user *buf, size_t datalen, loff_t *ppos) +#else +static ssize_t ima_write_policy(struct file *file, const char __user *buf, + size_t datalen, loff_t *ppos) +#endif { char *data; ssize_t result; +#ifdef CONFIG_IMA_DIGEST_LIST struct dentry *dentry = file_dentry(file); int i; +#else + + if (datalen >= PAGE_SIZE) + datalen = PAGE_SIZE - 1; +#endif
/* No partial writes. */ result = -EINVAL; if (*ppos != 0) goto out;
+#ifdef CONFIG_IMA_DIGEST_LIST result = -EFBIG; if (datalen > 64 * 1024 * 1024 - 1) goto out; @@ -389,12 +460,20 @@ static ssize_t ima_write_data(struct file *file, const char __user *buf, goto out_free;
data[datalen] = '\0'; +#else + data = memdup_user_nul(buf, datalen); + if (IS_ERR(data)) { + result = PTR_ERR(data); + goto out; + } +#endif
result = mutex_lock_interruptible(&ima_write_mutex); if (result < 0) goto out_free;
if (data[0] == '/') { +#ifdef CONFIG_IMA_DIGEST_LIST for (i = 0; data[i] != '\n' && data[i] != '\0'; i++) { if (iscntrl(data[i])) { pr_err_once("invalid path (control characters are not allowed)\n"); @@ -434,22 +513,45 @@ static ssize_t ima_write_data(struct file *file, const char __user *buf, pr_err("Unknown data type\n"); result = -EINVAL; } +#else + result = ima_read_policy(data); + } else if (ima_appraise & IMA_APPRAISE_POLICY) { + pr_err("signed policy file (specified as an absolute pathname) required\n"); + integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL, + "policy_update", "signed policy required", + 1, 0); + result = -EACCES; + } else { + result = ima_parse_add_rule(data); + } +#endif mutex_unlock(&ima_write_mutex); out_free: +#ifdef CONFIG_IMA_DIGEST_LIST vfree(data); +#else + kfree(data); +#endif out: +#ifdef CONFIG_IMA_DIGEST_LIST if (dentry == ima_policy && result < 0) +#else + if (result < 0) +#endif valid_policy = 0;
return result; }
enum ima_fs_flags { +#ifdef CONFIG_IMA_DIGEST_LIST IMA_POLICY_BUSY, IMA_DIGEST_LIST_DATA_BUSY, +#endif IMA_FS_BUSY, };
+#ifdef CONFIG_IMA_DIGEST_LIST static enum ima_fs_flags ima_get_dentry_flag(struct dentry *dentry) { enum ima_fs_flags flag = IMA_FS_BUSY; @@ -461,6 +563,7 @@ static enum ima_fs_flags ima_get_dentry_flag(struct dentry *dentry)
return flag; } +#endif
static unsigned long ima_fs_flags;
@@ -473,11 +576,19 @@ static const struct seq_operations ima_policy_seqops = { }; #endif
+#ifdef CONFIG_IMA_DIGEST_LIST /* * ima_open_data_upload: sequentialize access to the data upload interface */ static int ima_open_data_upload(struct inode *inode, struct file *filp) +#else +/* + * ima_open_policy: sequentialize access to the policy file + */ +static int ima_open_policy(struct inode *inode, struct file *filp) +#endif { +#ifdef CONFIG_IMA_DIGEST_LIST struct dentry *dentry = file_dentry(filp); const struct seq_operations *seq_ops = NULL; enum ima_fs_flags flag = ima_get_dentry_flag(dentry); @@ -489,8 +600,10 @@ static int ima_open_data_upload(struct inode *inode, struct file *filp) seq_ops = &ima_policy_seqops; #endif } +#endif
if (!(filp->f_flags & O_WRONLY)) { +#ifdef CONFIG_IMA_DIGEST_LIST if (!read_allowed) return -EACCES; if ((filp->f_flags & O_ACCMODE) != O_RDONLY) @@ -498,17 +611,35 @@ static int ima_open_data_upload(struct inode *inode, struct file *filp) if (!capable(CAP_SYS_ADMIN)) return -EPERM; return seq_open(filp, seq_ops); +#else +#ifndef CONFIG_IMA_READ_POLICY + return -EACCES; +#else + if ((filp->f_flags & O_ACCMODE) != O_RDONLY) + return -EACCES; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + return seq_open(filp, &ima_policy_seqops); +#endif /*CONFIG_IMA_READ_POLICY*/ +#endif /* CONFIG_IMA_DIGEST_LIST */ } +#ifdef CONFIG_IMA_DIGEST_LIST if (test_and_set_bit(flag, &ima_fs_flags)) +#else + if (test_and_set_bit(IMA_FS_BUSY, &ima_fs_flags)) +#endif return -EBUSY;
+#ifdef CONFIG_IMA_DIGEST_LIST if (dentry == digest_list_data || dentry == digest_list_data_del) if (ima_check_current_is_parser()) ima_set_parser(); +#endif
return 0; }
+#ifdef CONFIG_IMA_DIGEST_LIST /* * ima_release_data_upload - start using the new measure policy rules. * @@ -517,14 +648,29 @@ static int ima_open_data_upload(struct inode *inode, struct file *filp) * assuming a valid policy. */ static int ima_release_data_upload(struct inode *inode, struct file *file) +#else +/* + * ima_release_policy - start using the new measure policy rules. + * + * Initially, ima_measure points to the default policy rules, now + * point to the new policy rules, and remove the securityfs policy file, + * assuming a valid policy. + */ +static int ima_release_policy(struct inode *inode, struct file *file) +#endif { +#ifdef CONFIG_IMA_DIGEST_LIST struct dentry *dentry = file_dentry(file); +#endif const char *cause = valid_policy ? "completed" : "failed"; +#ifdef CONFIG_IMA_DIGEST_LIST enum ima_fs_flags flag = ima_get_dentry_flag(dentry); +#endif
if ((file->f_flags & O_ACCMODE) == O_RDONLY) return seq_release(inode, file);
+#ifdef CONFIG_IMA_DIGEST_LIST if (dentry == digest_list_data || dentry == digest_list_data_del) ima_unset_parser();
@@ -532,6 +678,7 @@ static int ima_release_data_upload(struct inode *inode, struct file *file) clear_bit(flag, &ima_fs_flags); return 0; } +#endif
if (valid_policy && ima_check_policy() < 0) { cause = "failed"; @@ -545,7 +692,11 @@ static int ima_release_data_upload(struct inode *inode, struct file *file) if (!valid_policy) { ima_delete_rules(); valid_policy = 1; +#ifdef CONFIG_IMA_DIGEST_LIST clear_bit(flag, &ima_fs_flags); +#else + clear_bit(IMA_FS_BUSY, &ima_fs_flags); +#endif return 0; }
@@ -554,18 +705,32 @@ static int ima_release_data_upload(struct inode *inode, struct file *file) securityfs_remove(ima_policy); ima_policy = NULL; #elif defined(CONFIG_IMA_WRITE_POLICY) +#ifdef CONFIG_IMA_DIGEST_LIST clear_bit(flag, &ima_fs_flags); +#else + clear_bit(IMA_FS_BUSY, &ima_fs_flags); +#endif #elif defined(CONFIG_IMA_READ_POLICY) inode->i_mode &= ~S_IWUSR; #endif return 0; }
+#ifdef CONFIG_IMA_DIGEST_LIST static const struct file_operations ima_data_upload_ops = { .open = ima_open_data_upload, .write = ima_write_data, +#else +static const struct file_operations ima_measure_policy_ops = { + .open = ima_open_policy, + .write = ima_write_policy, +#endif .read = seq_read, +#ifdef CONFIG_IMA_DIGEST_LIST .release = ima_release_data_upload, +#else + .release = ima_release_policy, +#endif .llseek = generic_file_llseek, };
@@ -597,19 +762,31 @@ int __init ima_fs_init(void) runtime_measurements_count = securityfs_create_file("runtime_measurements_count", S_IRUSR | S_IRGRP, ima_dir, NULL, +#ifdef CONFIG_IMA_DIGEST_LIST &ima_htable_value_ops); +#else + &ima_measurements_count_ops); +#endif if (IS_ERR(runtime_measurements_count)) goto out;
violations = securityfs_create_file("violations", S_IRUSR | S_IRGRP, +#ifdef CONFIG_IMA_DIGEST_LIST ima_dir, NULL, &ima_htable_value_ops); +#else + ima_dir, NULL, &ima_htable_violations_ops); +#endif if (IS_ERR(violations)) goto out;
ima_policy = securityfs_create_file("policy", POLICY_FILE_FLAGS, ima_dir, NULL, +#ifdef CONFIG_IMA_DIGEST_LIST &ima_data_upload_ops); +#else + &ima_measure_policy_ops); +#endif if (IS_ERR(ima_policy)) goto out;
@@ -634,9 +811,11 @@ int __init ima_fs_init(void) #endif return 0; out: +#ifdef CONFIG_IMA_DIGEST_LIST securityfs_remove(digest_list_data_del); securityfs_remove(digest_list_data); securityfs_remove(digests_count); +#endif securityfs_remove(ima_policy); securityfs_remove(violations); securityfs_remove(runtime_measurements_count); diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index 913d6b879b0b..7ab87713a2e4 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c @@ -86,7 +86,11 @@ static int __init ima_add_boot_aggregate(void)
result = ima_store_template(entry, violation, NULL, boot_aggregate_name, +#ifdef CONFIG_IMA_DIGEST_LIST CONFIG_IMA_MEASURE_PCR_IDX, NULL); +#else + CONFIG_IMA_MEASURE_PCR_IDX); +#endif if (result < 0) { ima_free_template_entry(entry); audit_cause = "store_entry"; @@ -107,8 +111,10 @@ void __init ima_load_x509(void) ima_policy_flag &= ~unset_flags; integrity_load_x509(INTEGRITY_KEYRING_IMA, CONFIG_IMA_X509_PATH);
+#ifdef CONFIG_IMA_DIGEST_LIST /* load also EVM key to avoid appraisal */ evm_load_x509(); +#endif
ima_policy_flag |= unset_flags; } diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 999d5904cce0..0afcbd5dd196 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -28,7 +28,9 @@ #include <linux/fs.h>
#include "ima.h" +#ifdef CONFIG_IMA_DIGEST_LIST #include "ima_digest_list.h" +#endif
#ifdef CONFIG_IMA_APPRAISE int ima_appraise = IMA_APPRAISE_ENFORCE; @@ -38,12 +40,14 @@ int ima_appraise;
int ima_hash_algo = HASH_ALGO_SHA1;
+#ifdef CONFIG_IMA_DIGEST_LIST /* Actions (measure/appraisal) for which digest lists can be used */ int ima_digest_list_actions; /* PCR used for digest list measurements */ int ima_digest_list_pcr = -1; /* Flag to include standard measurement if digest list PCR is specified */ bool ima_plus_standard_pcr; +#endif
static int hash_setup_done;
@@ -156,6 +160,7 @@ static void ima_rdwr_violation_check(struct file *file, "invalid_pcr", "open_writers"); }
+#ifdef CONFIG_IMA_DIGEST_LIST static enum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, int xattr_len) { @@ -209,6 +214,7 @@ static int ima_read_xattr(struct dentry *dentry, ret = 0; return ret; } +#endif /* CONFIG_IMA_DIGEST_LIST */
static void ima_check_last_writer(struct integrity_iint_cache *iint, struct inode *inode, struct file *file) @@ -268,7 +274,9 @@ static int process_measurement(struct file *file, const struct cred *cred, const char *pathname = NULL; int rc = 0, action, must_appraise = 0; int pcr = CONFIG_IMA_MEASURE_PCR_IDX; +#ifdef CONFIG_IMA_DIGEST_LIST struct ima_digest *found_digest; +#endif struct evm_ima_xattr_data *xattr_value = NULL; struct modsig *modsig = NULL; int xattr_len = 0; @@ -398,28 +406,39 @@ static int process_measurement(struct file *file, const struct cred *cred, if (!pathbuf) /* ima_rdwr_violation possibly pre-fetched */ pathname = ima_d_path(&file->f_path, &pathbuf, filename);
+#ifdef CONFIG_IMA_DIGEST_LIST if (!pathname || strlen(pathname) > IMA_EVENT_NAME_LEN_MAX) pathname = file->f_path.dentry->d_name.name;
found_digest = ima_lookup_digest(iint->ima_hash->digest, hash_algo, COMPACT_FILE); +#endif
if (action & IMA_MEASURE) ima_store_measurement(iint, file, pathname, xattr_value, xattr_len, modsig, pcr, +#ifdef CONFIG_IMA_DIGEST_LIST template_desc, ima_digest_allow(found_digest, IMA_MEASURE)); +#else + template_desc); +#endif
if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) { rc = ima_check_blacklist(iint, modsig, pcr); if (rc != -EPERM) { inode_lock(inode); + rc = ima_appraise_measurement(func, iint, file, pathname, xattr_value, +#ifdef CONFIG_IMA_DIGEST_LIST xattr_len, modsig, ima_digest_allow(found_digest, IMA_APPRAISE)); +#else + xattr_len, modsig); +#endif inode_unlock(inode); } if (!rc) @@ -568,15 +587,23 @@ int ima_bprm_check(struct linux_binprm *bprm) int ima_file_check(struct file *file, int mask) { u32 secid; +#ifdef CONFIG_IMA_DIGEST_LIST int rc; +#endif
security_task_getsecid(current, &secid); +#ifdef CONFIG_IMA_DIGEST_LIST rc = process_measurement(file, current_cred(), secid, NULL, 0, mask & (MAY_READ | MAY_WRITE | MAY_EXEC | MAY_APPEND), FILE_CHECK); if (ima_current_is_parser() && !rc) ima_check_measured_appraised(file); return rc; +#else + return process_measurement(file, current_cred(), secid, NULL, 0, + mask & (MAY_READ | MAY_WRITE | MAY_EXEC | + MAY_APPEND), FILE_CHECK); +#endif } EXPORT_SYMBOL_GPL(ima_file_check);
@@ -739,7 +766,9 @@ const int read_idmap[READING_MAX_ID] = { [READING_KEXEC_IMAGE] = KEXEC_KERNEL_CHECK, [READING_KEXEC_INITRAMFS] = KEXEC_INITRAMFS_CHECK, [READING_POLICY] = POLICY_CHECK, +#ifdef CONFIG_IMA_DIGEST_LIST [READING_DIGEST_LIST] = DIGEST_LIST_CHECK +#endif };
/** @@ -941,7 +970,11 @@ void process_buffer_measurement(struct inode *inode, const void *buf, int size, goto out; }
+#ifdef CONFIG_IMA_DIGEST_LIST ret = ima_store_template(entry, violation, NULL, buf, pcr, NULL); +#else + ret = ima_store_template(entry, violation, NULL, buf, pcr); +#endif if (ret < 0) { audit_cause = "store_entry"; ima_free_template_entry(entry); diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 274f4c7c99f4..84528e1413ad 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -21,7 +21,9 @@ #include <linux/ima.h>
#include "ima.h" +#ifdef CONFIG_IMA_DIGEST_LIST #include "ima_digest_list.h" +#endif
/* flags definitions */ #define IMA_FUNC 0x0001 @@ -35,7 +37,9 @@ #define IMA_PCR 0x0100 #define IMA_FSNAME 0x0200 #define IMA_KEYRINGS 0x0400 +#ifdef CONFIG_IMA_DIGEST_LIST #define IMA_PARSER 0x0800 +#endif
#define UNKNOWN 0 #define MEASURE 0x0001 /* same as IMA_MEASURE */ @@ -58,7 +62,11 @@ enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE, LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE };
+#ifdef CONFIG_IMA_DIGEST_LIST enum policy_types { ORIGINAL_TCB = 1, DEFAULT_TCB, EXEC_TCB }; +#else +enum policy_types { ORIGINAL_TCB = 1, DEFAULT_TCB }; +#endif
enum policy_rule_list { IMA_DEFAULT_POLICY = 1, IMA_CUSTOM_POLICY };
@@ -145,11 +153,13 @@ static struct ima_rule_entry default_measurement_rules[] __ro_after_init = { {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC}, {.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC}, {.action = MEASURE, .func = POLICY_CHECK, .flags = IMA_FUNC}, +#ifdef CONFIG_IMA_DIGEST_LIST {.action = MEASURE, .func = DIGEST_LIST_CHECK, .flags = IMA_FUNC}, };
static struct ima_rule_entry ima_parser_measure_rule __ro_after_init = { .action = MEASURE, .flags = IMA_PARSER +#endif };
static struct ima_rule_entry default_appraise_rules[] __ro_after_init = { @@ -181,12 +191,14 @@ static struct ima_rule_entry default_appraise_rules[] __ro_after_init = { #endif };
+#ifdef CONFIG_IMA_DIGEST_LIST static struct ima_rule_entry appraise_exec_rules[] __ro_after_init = { {.action = APPRAISE, .func = BPRM_CHECK, .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, {.action = APPRAISE, .func = MMAP_CHECK, .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, }; +#endif
static struct ima_rule_entry build_appraise_rules[] __ro_after_init = { #ifdef CONFIG_IMA_APPRAISE_REQUIRE_MODULE_SIGS @@ -216,6 +228,7 @@ static struct ima_rule_entry secure_boot_rules[] __ro_after_init = { .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, {.action = APPRAISE, .func = POLICY_CHECK, .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, +#ifdef CONFIG_IMA_DIGEST_LIST {.action = APPRAISE, .func = DIGEST_LIST_CHECK, .flags = IMA_FUNC | IMA_DIGSIG_REQUIRED}, }; @@ -223,6 +236,7 @@ static struct ima_rule_entry secure_boot_rules[] __ro_after_init = { static struct ima_rule_entry ima_parser_appraise_rule __ro_after_init = { .action = APPRAISE, .flags = IMA_PARSER | IMA_DIGSIG_REQUIRED +#endif };
/* An array of architecture specific rules */ @@ -246,8 +260,10 @@ static int __init default_measure_policy_setup(char *str) __setup("ima_tcb", default_measure_policy_setup);
static bool ima_use_appraise_tcb __initdata; +#ifdef CONFIG_IMA_DIGEST_LIST static bool ima_use_appraise_exec_tcb __initdata; static bool ima_use_appraise_exec_immutable __initdata; +#endif static bool ima_use_secure_boot __initdata; static bool ima_fail_unverifiable_sigs __ro_after_init; static int __init policy_setup(char *str) @@ -259,14 +275,18 @@ static int __init policy_setup(char *str) continue; if ((strcmp(p, "tcb") == 0) && !ima_policy) ima_policy = DEFAULT_TCB; +#ifdef CONFIG_IMA_DIGEST_LIST else if ((strcmp(p, "exec_tcb") == 0) && !ima_policy) ima_policy = EXEC_TCB; +#endif else if (strcmp(p, "appraise_tcb") == 0) ima_use_appraise_tcb = true; +#ifdef CONFIG_IMA_DIGEST_LIST else if (strcmp(p, "appraise_exec_tcb") == 0) ima_use_appraise_exec_tcb = true; else if (strcmp(p, "appraise_exec_immutable") == 0) ima_use_appraise_exec_immutable = true; +#endif else if (strcmp(p, "secure_boot") == 0) ima_use_secure_boot = true; else if (strcmp(p, "fail_securely") == 0) @@ -569,9 +589,11 @@ static bool ima_match_rules(struct ima_rule_entry *rule, struct inode *inode, if ((rule->flags & IMA_FOWNER) && !rule->fowner_op(inode->i_uid, rule->fowner)) return false; +#ifdef CONFIG_IMA_DIGEST_LIST if ((rule->flags & IMA_PARSER) && !ima_current_is_parser()) return false; +#endif for (i = 0; i < MAX_LSM_RULES; i++) { int rc = 0; u32 osid; @@ -752,19 +774,27 @@ static int ima_appraise_flag(enum ima_hooks func) return IMA_APPRAISE_POLICY; else if (func == KEXEC_KERNEL_CHECK) return IMA_APPRAISE_KEXEC; +#ifdef CONFIG_IMA_DIGEST_LIST else if (func == DIGEST_LIST_CHECK) return IMA_APPRAISE_DIGEST_LIST; +#endif return 0; }
+#ifdef CONFIG_IMA_DIGEST_LIST static void __init add_rules(struct ima_rule_entry *entries, int count, enum policy_rule_list policy_rule) +#else +static void add_rules(struct ima_rule_entry *entries, int count, + enum policy_rule_list policy_rule) +#endif { int i = 0;
for (i = 0; i < count; i++) { struct ima_rule_entry *entry;
+#ifdef CONFIG_IMA_DIGEST_LIST if (ima_policy == EXEC_TCB) { if (entries == dont_measure_rules) if ((entries[i].flags & IMA_FSMAGIC) && @@ -792,6 +822,7 @@ static void __init add_rules(struct ima_rule_entry *entries, int count, (entries[i].flags & IMA_FUNC) && entries[i].func == BPRM_CHECK) entries[i].flags |= IMA_META_IMMUTABLE_REQUIRED; +#endif /* CONFIG_IMA_DIGEST_LIST */
if (policy_rule & IMA_DEFAULT_POLICY) list_add_tail(&entries[i].list, &ima_default_rules); @@ -879,8 +910,10 @@ void __init ima_init_policy(void) ARRAY_SIZE(original_measurement_rules), IMA_DEFAULT_POLICY); break; +#ifdef CONFIG_IMA_DIGEST_LIST case EXEC_TCB: fallthrough; +#endif case DEFAULT_TCB: add_rules(default_measurement_rules, ARRAY_SIZE(default_measurement_rules), @@ -889,8 +922,10 @@ void __init ima_init_policy(void) break; }
+#ifdef CONFIG_IMA_DIGEST_LIST if (ima_policy) add_rules(&ima_parser_measure_rule, 1, IMA_DEFAULT_POLICY); +#endif
/* * Based on runtime secure boot flags, insert arch specific measurement @@ -909,7 +944,11 @@ void __init ima_init_policy(void) * Insert the builtin "secure_boot" policy rules requiring file * signatures, prior to other appraise rules. */ +#ifdef CONFIG_IMA_DIGEST_LIST if (ima_use_secure_boot || ima_use_appraise_exec_tcb) +#else + if (ima_use_secure_boot) +#endif add_rules(secure_boot_rules, ARRAY_SIZE(secure_boot_rules), IMA_DEFAULT_POLICY);
@@ -929,11 +968,16 @@ void __init ima_init_policy(void) IMA_DEFAULT_POLICY | IMA_CUSTOM_POLICY); }
+#ifdef CONFIG_IMA_DIGEST_LIST if (ima_use_appraise_tcb || ima_use_appraise_exec_tcb) +#else + if (ima_use_appraise_tcb) +#endif add_rules(default_appraise_rules, ARRAY_SIZE(default_appraise_rules), IMA_DEFAULT_POLICY);
+#ifdef CONFIG_IMA_DIGEST_LIST if (ima_use_appraise_exec_tcb) add_rules(appraise_exec_rules, ARRAY_SIZE(appraise_exec_rules), @@ -942,6 +986,7 @@ void __init ima_init_policy(void) if (ima_use_secure_boot || ima_use_appraise_tcb || ima_use_appraise_exec_tcb) add_rules(&ima_parser_appraise_rule, 1, IMA_DEFAULT_POLICY); +#endif
ima_update_policy_flag(); } @@ -1002,7 +1047,11 @@ enum { Opt_uid_lt, Opt_euid_lt, Opt_fowner_lt, Opt_appraise_type, Opt_appraise_flag, Opt_permit_directio, Opt_pcr, Opt_template, Opt_keyrings, +#ifdef CONFIG_IMA_DIGEST_LIST Opt_parser, Opt_err +#else + Opt_err +#endif };
static const match_table_t policy_tokens = { @@ -1039,7 +1088,9 @@ static const match_table_t policy_tokens = { {Opt_pcr, "pcr=%s"}, {Opt_template, "template=%s"}, {Opt_keyrings, "keyrings=%s"}, +#ifdef CONFIG_IMA_DIGEST_LIST {Opt_parser, "parser"}, +#endif {Opt_err, NULL} };
@@ -1134,9 +1185,14 @@ static bool ima_validate_rule(struct ima_rule_entry *entry) if (entry->action != MEASURE && entry->flags & IMA_PCR) return false;
+#ifdef CONFIG_IMA_DIGEST_LIST if (entry->action != APPRAISE && entry->flags & (IMA_DIGSIG_REQUIRED | IMA_MODSIG_ALLOWED | IMA_CHECK_BLACKLIST | IMA_META_IMMUTABLE_REQUIRED)) +#else + if (entry->action != APPRAISE && + entry->flags & (IMA_DIGSIG_REQUIRED | IMA_MODSIG_ALLOWED | IMA_CHECK_BLACKLIST)) +#endif return false;
/* @@ -1162,13 +1218,19 @@ static bool ima_validate_rule(struct ima_rule_entry *entry) case POST_SETATTR: case FIRMWARE_CHECK: case POLICY_CHECK: +#ifdef CONFIG_IMA_DIGEST_LIST case DIGEST_LIST_CHECK: +#endif if (entry->flags & ~(IMA_FUNC | IMA_MASK | IMA_FSMAGIC | IMA_UID | IMA_FOWNER | IMA_FSUUID | IMA_INMASK | IMA_EUID | IMA_PCR | IMA_FSNAME | IMA_DIGSIG_REQUIRED | +#ifdef CONFIG_IMA_DIGEST_LIST IMA_PERMIT_DIRECTIO | IMA_META_IMMUTABLE_REQUIRED | IMA_PARSER)) +#else + IMA_PERMIT_DIRECTIO)) +#endif return false;
break; @@ -1180,8 +1242,12 @@ static bool ima_validate_rule(struct ima_rule_entry *entry) IMA_INMASK | IMA_EUID | IMA_PCR | IMA_FSNAME | IMA_DIGSIG_REQUIRED | IMA_PERMIT_DIRECTIO | IMA_MODSIG_ALLOWED | +#ifdef CONFIG_IMA_DIGEST_LIST IMA_CHECK_BLACKLIST | IMA_META_IMMUTABLE_REQUIRED)) +#else + IMA_CHECK_BLACKLIST)) +#endif return false;
break; @@ -1338,8 +1404,10 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) else if (IS_ENABLED(CONFIG_IMA_MEASURE_ASYMMETRIC_KEYS) && strcmp(args[0].from, "KEY_CHECK") == 0) entry->func = KEY_CHECK; +#ifdef CONFIG_IMA_DIGEST_LIST else if (strcmp(args[0].from, "DIGEST_LIST_CHECK") == 0) entry->func = DIGEST_LIST_CHECK; +#endif else result = -EINVAL; if (!result) @@ -1526,8 +1594,10 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) strcmp(args[0].from, "imasig|modsig") == 0) entry->flags |= IMA_DIGSIG_REQUIRED | IMA_MODSIG_ALLOWED; +#ifdef CONFIG_IMA_DIGEST_LIST else if (strcmp(args[0].from, "meta_immutable") == 0) entry->flags |= IMA_META_IMMUTABLE_REQUIRED; +#endif else result = -EINVAL; break; @@ -1546,8 +1616,12 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) ima_log_string(ab, "pcr", args[0].from);
result = kstrtoint(args[0].from, 10, &entry->pcr); +#ifdef CONFIG_IMA_DIGEST_LIST if (result || INVALID_PCR(entry->pcr) || entry->pcr == ima_digest_list_pcr) +#else + if (result || INVALID_PCR(entry->pcr)) +#endif result = -EINVAL; else entry->flags |= IMA_PCR; @@ -1574,10 +1648,12 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry) &(template_desc->fields), &(template_desc->num_fields)); entry->template = template_desc; +#ifdef CONFIG_IMA_DIGEST_LIST break; case Opt_parser: audit_log_format(ab, "parser "); entry->flags |= IMA_PARSER; +#endif break; case Opt_err: ima_log_string(ab, "UNKNOWN", p); @@ -1849,8 +1925,10 @@ int ima_policy_show(struct seq_file *m, void *v) seq_puts(m, " "); }
+#ifdef CONFIG_IMA_DIGEST_LIST if (entry->flags & IMA_PARSER) seq_puts(m, "parser "); +#endif
for (i = 0; i < MAX_LSM_RULES; i++) { if (entry->lsm[i].rule) { @@ -1893,8 +1971,10 @@ int ima_policy_show(struct seq_file *m, void *v) } if (entry->flags & IMA_CHECK_BLACKLIST) seq_puts(m, "appraise_flag=check_blacklist "); +#ifdef CONFIG_IMA_DIGEST_LIST if (entry->flags & IMA_META_IMMUTABLE_REQUIRED) seq_puts(m, "appraise_type=meta_immutable "); +#endif if (entry->flags & IMA_PERMIT_DIRECTIO) seq_puts(m, "permit_directio "); rcu_read_unlock(); diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c index 6f126dbd2b39..4a7b5df58863 100644 --- a/security/integrity/ima/ima_template.c +++ b/security/integrity/ima/ima_template.c @@ -46,8 +46,10 @@ static const struct ima_template_field supported_fields[] = { .field_show = ima_show_template_digest_ng}, {.field_id = "modsig", .field_init = ima_eventmodsig_init, .field_show = ima_show_template_sig}, +#ifdef CONFIG_IMA_DIGEST_LIST {.field_id = "evmsig", .field_init = ima_eventevmsig_init, .field_show = ima_show_template_sig}, +#endif };
/* diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c index 90040fac150b..7308ee587314 100644 --- a/security/integrity/ima/ima_template_lib.c +++ b/security/integrity/ima/ima_template_lib.c @@ -10,7 +10,9 @@ */
#include "ima_template_lib.h" +#ifdef CONFIG_IMA_DIGEST_LIST #include <linux/xattr.h> +#endif
static bool ima_template_hash_algo_allowed(u8 algo) { @@ -439,7 +441,11 @@ int ima_eventsig_init(struct ima_event_data *event_data, struct evm_ima_xattr_data *xattr_value = event_data->xattr_value;
if ((!xattr_value) || (xattr_value->type != EVM_IMA_XATTR_DIGSIG)) +#ifdef CONFIG_IMA_DIGEST_LIST return ima_eventevmsig_init(event_data, field_data); +#else + return 0; +#endif
return ima_write_template_field_data(xattr_value, event_data->xattr_len, DATA_FMT_HEX, field_data); @@ -486,6 +492,7 @@ int ima_eventmodsig_init(struct ima_event_data *event_data, field_data); }
+#ifdef CONFIG_IMA_DIGEST_LIST /* * ima_eventevmsig_init - include the EVM portable signature as part of the * template data @@ -514,3 +521,4 @@ int ima_eventevmsig_init(struct ima_event_data *event_data, kfree(xattr_data); return rc; } +#endif diff --git a/security/integrity/ima/ima_template_lib.h b/security/integrity/ima/ima_template_lib.h index f4b2a2056d1d..7d0d5be28908 100644 --- a/security/integrity/ima/ima_template_lib.h +++ b/security/integrity/ima/ima_template_lib.h @@ -46,6 +46,8 @@ int ima_eventbuf_init(struct ima_event_data *event_data, struct ima_field_data *field_data); int ima_eventmodsig_init(struct ima_event_data *event_data, struct ima_field_data *field_data); +#ifdef CONFIG_IMA_DIGEST_LIST int ima_eventevmsig_init(struct ima_event_data *event_data, struct ima_field_data *field_data); +#endif /* CONFIG_IMA_DIGEST_LIST */ #endif /* __LINUX_IMA_TEMPLATE_LIB_H */ diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index 77e6819e8db8..cb1c178f8ac4 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -14,10 +14,13 @@
#include <linux/types.h> #include <linux/integrity.h> +#include <crypto/sha1.h> #include <crypto/sha2.h> #include <linux/key.h> #include <linux/audit.h> +#ifdef CONFIG_IMA_DIGEST_LIST #include <linux/hash_info.h> +#endif
/* iint action cache flags */ #define IMA_MEASURE 0x00000001 @@ -40,7 +43,9 @@ #define IMA_FAIL_UNVERIFIABLE_SIGS 0x10000000 #define IMA_MODSIG_ALLOWED 0x20000000 #define IMA_CHECK_BLACKLIST 0x40000000 +#ifdef CONFIG_IMA_DIGEST_LIST #define IMA_META_IMMUTABLE_REQUIRED 0x80000000 +#endif
#define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \ IMA_HASH | IMA_APPRAISE_SUBMASK) @@ -72,7 +77,9 @@ #define IMA_CHANGE_ATTR 2 #define IMA_DIGSIG 3 #define IMA_MUST_MEASURE 4 +#ifdef CONFIG_IMA_DIGEST_LIST #define IMA_DIGEST_LIST 5 +#endif
enum evm_ima_xattr_type { IMA_XATTR_DIGEST = 0x01, @@ -80,7 +87,9 @@ enum evm_ima_xattr_type { EVM_IMA_XATTR_DIGSIG, IMA_XATTR_DIGEST_NG, EVM_XATTR_PORTABLE_DIGSIG, +#ifdef CONFIG_IMA_DIGEST_LIST EVM_IMA_XATTR_DIGEST_LIST, +#endif IMA_XATTR_LAST };
@@ -92,7 +101,11 @@ struct evm_ima_xattr_data { /* Only used in the EVM HMAC code. */ struct evm_xattr { struct evm_ima_xattr_data data; +#ifdef CONFIG_IMA_DIGEST_LIST u8 digest[SHA512_DIGEST_SIZE]; +#else + u8 digest[SHA1_DIGEST_SIZE]; +#endif } __packed;
#define IMA_MAX_DIGEST_SIZE 64 @@ -144,6 +157,7 @@ struct integrity_iint_cache { struct ima_digest_data *ima_hash; };
+#ifdef CONFIG_IMA_DIGEST_LIST enum compact_types { COMPACT_KEY, COMPACT_PARSER, COMPACT_FILE, COMPACT_METADATA, COMPACT__LAST }; enum compact_modifiers { COMPACT_MOD_IMMUTABLE, COMPACT_MOD__LAST }; @@ -162,27 +176,11 @@ static inline bool ima_digest_is_immutable(struct ima_digest *digest) return (digest->modifiers & (1 << COMPACT_MOD_IMMUTABLE)); }
-#ifdef CONFIG_IMA_DIGEST_LIST struct ima_digest *ima_lookup_digest(u8 *digest, enum hash_algo algo, enum compact_types type); struct ima_digest *ima_digest_allow(struct ima_digest *digest, int action); void __init ima_load_digest_lists(void); -#else -static inline struct ima_digest *ima_lookup_digest(u8 *digest, - enum hash_algo algo, - enum compact_types type) -{ - return NULL; -} -static inline struct ima_digest *ima_digest_allow(struct ima_digest *digest, - int action) -{ - return NULL; -} -static inline void ima_load_digest_lists(void) -{ -} -#endif +#endif /* CONFIG_IMA_DIGEST_LIST */
/* rbtree tree calls to lookup, insert, delete * integrity data associated with an inode. diff --git a/security/security.c b/security/security.c index 5678d4e334fb..11c859a9b8ed 100644 --- a/security/security.c +++ b/security/security.c @@ -1362,7 +1362,9 @@ void security_inode_post_setxattr(struct dentry *dentry, const char *name, if (unlikely(IS_PRIVATE(d_backing_inode(dentry)))) return; call_void_hook(inode_post_setxattr, dentry, name, value, size, flags); +#ifdef CONFIG_IMA_DIGEST_LIST ima_inode_post_setxattr(dentry, name, value, size); +#endif evm_inode_post_setxattr(dentry, name, value, size); }