Isolate the IMA digest list code by using macros.
Signed-off-by: Zhou Shuiqing <zhoushuiqing2(a)huawei.com>
---
fs/xattr.c | 4 +
include/linux/ima.h | 8 +
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 | 146 +++++++++++++
security/integrity/iint.c | 4 +
security/integrity/ima/ima.h | 80 ++++++-
security/integrity/ima/ima_api.c | 39 ++++
security/integrity/ima/ima_appraise.c | 128 ++++++++++-
security/integrity/ima/ima_fs.c | 247 +++++++++++++++++++++-
security/integrity/ima/ima_init.c | 8 +
security/integrity/ima/ima_main.c | 36 +++-
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 | 15 +-
security/security.c | 2 +
19 files changed, 840 insertions(+), 13 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/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/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..fa8147c2294e 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_XATTR_PORTABLE_DIGSIG)
+#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..fe767feb722d 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>
@@ -28,8 +30,12 @@
int evm_initialized;
static const char * const integrity_status_msg[] = {
+#ifdef CONFIG_IMA_DIGEST_LIST
"pass", "pass_immutable", "fail", "fail_immutable", "no_label",
"no_xattrs", "unknown"
+#else
+ "pass", "pass_immutable", "fail", "no_label", "no_xattrs", "unknown"
+#endif
};
int evm_hmac_attrs;
@@ -57,6 +63,7 @@ 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)
{
if (strncmp(str, "fix", 3) == 0)
@@ -73,6 +80,18 @@ static int __init evm_set_param(char *str)
return 1;
}
__setup("evm=", evm_set_param);
+#else
+static int __init evm_set_fixmode(char *str)
+{
+ if (strncmp(str, "fix", 3) == 0)
+ evm_fixmode = 1;
+ else
+ pr_err("invalid \"%s\" mode", str);
+
+ return 0;
+}
+__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,6 +255,7 @@ 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) {
evm_status = INTEGRITY_FAIL;
goto out;
@@ -231,6 +274,25 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
evm_immutable = 1;
fallthrough;
case EVM_IMA_XATTR_DIGSIG:
+#else
+ if (xattr_len != sizeof(struct evm_xattr)) {
+ evm_status = INTEGRITY_FAIL;
+ goto out;
+ }
+
+ digest.hdr.algo = HASH_ALGO_SHA1;
+ rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
+ xattr_value_len, &digest);
+ if (rc)
+ break;
+ rc = crypto_memneq(xattr_data->data, digest.digest,
+ SHA1_DIGEST_SIZE);
+ if (rc)
+ rc = -EINVAL;
+ break;
+ case EVM_IMA_XATTR_DIGSIG:
+ case EVM_XATTR_PORTABLE_DIGSIG:
+#endif
/* accept xattr with non-empty signature field */
if (xattr_len <= sizeof(struct signature_v2_hdr)) {
evm_status = INTEGRITY_FAIL;
@@ -262,6 +324,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 +365,13 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
evm_status = INTEGRITY_PASS;
}
break;
+#endif
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 +380,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 +469,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 +541,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 +593,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 +607,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 +645,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 +685,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 +710,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 +728,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 +758,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 +788,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,6 +811,7 @@ 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);
+#ifdef CONFIG_IMA_DIGEST_LIST
/*
* Writing attrs is safe for portable signatures, as portable signatures
* are immutable and can never be updated.
@@ -727,6 +825,11 @@ int evm_inode_setattr(struct dentry *dentry, struct iattr *attr)
if (evm_status == INTEGRITY_PASS_IMMUTABLE &&
!evm_attr_change(dentry, attr))
return 0;
+#else
+ if ((evm_status == INTEGRITY_PASS) ||
+ (evm_status == INTEGRITY_NOXATTRS))
+ return 0;
+#endif
integrity_audit_msg(AUDIT_INTEGRITY_METADATA, d_backing_inode(dentry),
dentry->d_name.name, "appraise_metadata",
@@ -747,15 +850,21 @@ 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))
return;
evm_reset_status(dentry->d_inode);
+#else
+ if (!evm_key_loaded())
+ return;
+#endif
if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID))
evm_update_evmxattr(dentry, NULL, NULL, 0);
}
+#ifdef CONFIG_IMA_DIGEST_LIST
/*
* evm_inode_init_security - initializes security.evm HMAC value
*/
@@ -787,6 +896,38 @@ int evm_inode_init_security(struct inode *inode,
kfree(xattr_data);
return rc;
}
+#else
+/*
+ * evm_inode_init_security - initializes security.evm
+ */
+int evm_inode_init_security(struct inode *inode,
+ const struct xattr *lsm_xattr,
+ struct xattr *evm_xattr)
+{
+ struct evm_xattr *xattr_data;
+ int rc;
+
+ if (!evm_key_loaded() || !evm_protected_xattr(lsm_xattr->name))
+ return 0;
+
+ xattr_data = kzalloc(sizeof(*xattr_data), GFP_NOFS);
+ if (!xattr_data)
+ return -ENOMEM;
+
+ xattr_data->data.type = EVM_XATTR_HMAC;
+ rc = evm_init_hmac(inode, lsm_xattr, xattr_data->digest);
+ if (rc < 0)
+ goto out;
+
+ evm_xattr->value = xattr_data;
+ evm_xattr->value_len = sizeof(*xattr_data);
+ evm_xattr->name = XATTR_EVM_SUFFIX;
+ return 0;
+out:
+ kfree(xattr_data);
+ return rc;
+}
+#endif
EXPORT_SYMBOL_GPL(evm_inode_init_security);
#ifdef CONFIG_EVM_LOAD_X509
@@ -802,6 +943,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 +951,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..df994202ac0f 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))
evm_load_x509();
ima_load_digest_lists();
+#else
+ evm_load_x509();
+#endif
}
static int __init integrity_fs_init(void)
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 46afb6bef45b..e512a17b09dd 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
#define __ima_hook_enumify(ENUM, str) ENUM,
#define __ima_stringify(arg) (#arg)
@@ -264,12 +282,20 @@ int ima_must_measure(struct inode *inode, int mask, enum ima_hooks func);
int ima_collect_measurement(struct integrity_iint_cache *iint,
struct file *file, void *buf, loff_t size,
enum hash_algo algo, struct modsig *modsig);
+#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
void process_buffer_measurement(struct inode *inode, const void *buf, int size,
const char *eventname, enum ima_hooks func,
int pcr, const char *keyring);
@@ -278,9 +304,15 @@ void ima_audit_measurement(struct integrity_iint_cache *iint,
int ima_alloc_init_template(struct ima_event_data *event_data,
struct ima_template_entry **entry,
struct ima_template_desc *template_desc);
+#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
void ima_free_template_entry(struct ima_template_entry *entry);
const char *ima_d_path(const struct path *path, char **pathbuf, char *filename);
@@ -308,21 +340,41 @@ 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,
const struct modsig *modsig, int pcr);
+
+#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
+
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)
@@ -330,6 +382,7 @@ static inline int ima_check_blacklist(struct integrity_iint_cache *iint,
return 0;
}
+#ifndef CONFIG_IMA_DIGEST_LIST
static inline int ima_appraise_measurement(enum ima_hooks func,
struct integrity_iint_cache *iint,
struct file *file,
@@ -338,6 +391,15 @@ static inline int ima_appraise_measurement(enum ima_hooks func,
int xattr_len,
const struct modsig *modsig,
struct ima_digest *found_digest)
+#else
+static inline 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
{
return INTEGRITY_UNKNOWN;
}
@@ -360,6 +422,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..e5e071fa8565 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;
+ break;
+ 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
+
/*
* 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,22 +286,27 @@ 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))) {
+#endif
if (iint->flags & IMA_DIGSIG_REQUIRED) {
*cause = "IMA-signature-required";
*status = INTEGRITY_FAIL;
break;
}
clear_bit(IMA_DIGSIG, &iint->atomic_flags);
+#ifdef CONFIG_IMA_DIGEST_LIST
} else {
set_bit(IMA_DIGSIG, &iint->atomic_flags);
}
+#endif
if (xattr_len - sizeof(xattr_value->type) - hash_start >=
iint->ima_hash->length)
/*
@@ -352,26 +426,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 +481,7 @@ int ima_appraise_measurement(enum ima_hooks func,
rc = xattr_len;
}
}
+#endif
/* If reading the xattr failed and there's no modsig, error out. */
if (rc <= 0 && !try_modsig) {
@@ -417,11 +505,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 +521,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 +539,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 +554,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 +563,16 @@ int ima_appraise_measurement(enum ima_hooks func,
filename, op, cause, rc, 0);
goto out;
}
+#endif
if (xattr_value)
+#ifdef CONFIG_IMA_DIGEST_LIST
rc = xattr_verify(func, iint, xattr_value, xattr_len, &status,
&cause, found_digest);
+#else
+ rc = xattr_verify(func, iint, xattr_value, xattr_len, &status,
+ &cause);
+#endif
/*
* If we have a modsig and either no imasig or the imasig's key isn't
@@ -503,6 +606,7 @@ int ima_appraise_measurement(enum ima_hooks func,
status = INTEGRITY_PASS;
}
+#ifdef CONFIG_IMA_DIGEST_LIST
/*
* Permit new files with file/EVM portable signatures, but
* without data.
@@ -511,6 +615,13 @@ int ima_appraise_measurement(enum ima_hooks func,
test_bit(IMA_DIGSIG, &iint->atomic_flags)) {
status = INTEGRITY_PASS;
}
+#else
+ /* Permit new files with file signatures, but without data. */
+ if (inode->i_size == 0 && iint->flags & IMA_NEW_FILE &&
+ xattr_value && xattr_value->type == EVM_IMA_XATTR_DIGSIG) {
+ status = INTEGRITY_PASS;
+ }
+#endif
integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, filename,
op, cause, rc, 0);
@@ -567,6 +678,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 +735,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 +761,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 +769,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 +786,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..4ceee381d58b 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,6 +58,7 @@ __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)
{
@@ -63,19 +70,54 @@ static ssize_t ima_show_htable_value(struct file *filp, char __user *buf,
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
len = scnprintf(tmpbuf, sizeof(tmpbuf), "%li\n", atomic_long_read(val));
return simple_read_from_buffer(buf, count, ppos, tmpbuf, len);
}
+#else
+static ssize_t ima_show_htable_value(char __user *buf, size_t count,
+ loff_t *ppos, atomic_long_t *val)
+{
+ char tmpbuf[32]; /* greater than largest 'long' string value */
+ ssize_t len;
+ len = scnprintf(tmpbuf, sizeof(tmpbuf), "%li\n", atomic_long_read(val));
+ return simple_read_from_buffer(buf, count, ppos, tmpbuf, len);
+}
+#endif
+#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
/* returns pointer to hlist_node */
static void *ima_measurements_start(struct seq_file *m, loff_t *pos)
@@ -275,6 +317,7 @@ 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)
{
void *data = NULL;
@@ -320,7 +363,6 @@ static ssize_t ima_read_file(char *path, struct dentry *dentry)
rc = ima_parse_add_rule(p);
} 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 +370,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.
@@ -343,12 +384,10 @@ static ssize_t ima_read_file(char *path, struct dentry *dentry)
if (rc < 0)
break;
-#ifdef CONFIG_IMA_DIGEST_LIST
else if (dentry == digest_list_data)
pr_debug("digest imported, current DB size: %d\n", ima_digest_db_size);
else if (dentry == digest_list_data_del)
pr_debug("digest deleted, current DB size: %d\n", ima_digest_db_size);
-#endif
size -= rc;
}
@@ -461,6 +500,104 @@ static enum ima_fs_flags ima_get_dentry_flag(struct dentry *dentry)
return flag;
}
+#else
+static ssize_t ima_read_policy(char *path)
+{
+ void *data = NULL;
+ char *datap;
+ size_t size;
+ int rc, pathlen = strlen(path);
+
+ char *p;
+
+ /* remove \n */
+ datap = path;
+ strsep(&datap, "\n");
+
+ rc = kernel_read_file_from_path(path, 0, &data, INT_MAX, NULL,
+ READING_POLICY);
+ if (rc < 0) {
+ pr_err("Unable to open file: %s (%d)", path, rc);
+ return rc;
+ }
+ size = rc;
+ rc = 0;
+
+ datap = data;
+ while (size > 0 && (p = strsep(&datap, "\n"))) {
+ pr_debug("rule: %s\n", p);
+ rc = ima_parse_add_rule(p);
+ if (rc < 0)
+ break;
+ size -= rc;
+ }
+
+ vfree(data);
+ if (rc < 0)
+ return rc;
+ else if (size)
+ return -EINVAL;
+ else
+ return pathlen;
+}
+
+static ssize_t ima_write_policy(struct file *file, const char __user *buf,
+ size_t datalen, loff_t *ppos)
+{
+ char *data;
+ ssize_t result;
+
+ if (datalen >= PAGE_SIZE)
+ datalen = PAGE_SIZE - 1;
+
+ /* No partial writes. */
+ result = -EINVAL;
+ if (*ppos != 0)
+ goto out;
+
+ data = memdup_user_nul(buf, datalen);
+ if (IS_ERR(data)) {
+ result = PTR_ERR(data);
+ goto out;
+ }
+
+ result = mutex_lock_interruptible(&ima_write_mutex);
+ if (result < 0)
+ goto out_free;
+
+ if (data[0] == '/') {
+ 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);
+ }
+ mutex_unlock(&ima_write_mutex);
+out_free:
+ kfree(data);
+out:
+ if (result < 0)
+ valid_policy = 0;
+
+ return result;
+}
+
+static struct dentry *ima_dir;
+static struct dentry *ima_symlink;
+static struct dentry *binary_runtime_measurements;
+static struct dentry *ascii_runtime_measurements;
+static struct dentry *runtime_measurements_count;
+static struct dentry *violations;
+static struct dentry *ima_policy;
+
+enum ima_fs_flags {
+ IMA_FS_BUSY,
+};
+#endif
static unsigned long ima_fs_flags;
@@ -473,6 +610,7 @@ 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
*/
@@ -568,6 +706,79 @@ static const struct file_operations ima_data_upload_ops = {
.release = ima_release_data_upload,
.llseek = generic_file_llseek,
};
+#else
+/*
+ * ima_open_policy: sequentialize access to the policy file
+ */
+static int ima_open_policy(struct inode *inode, struct file *filp)
+{
+ if (!(filp->f_flags & O_WRONLY)) {
+#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
+ }
+ if (test_and_set_bit(IMA_FS_BUSY, &ima_fs_flags))
+ return -EBUSY;
+ return 0;
+}
+
+/*
+ * 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)
+{
+ const char *cause = valid_policy ? "completed" : "failed";
+
+ if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+ return seq_release(inode, file);
+
+ if (valid_policy && ima_check_policy() < 0) {
+ cause = "failed";
+ valid_policy = 0;
+ }
+
+ pr_info("policy update %s\n", cause);
+ integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL,
+ "policy_update", cause, !valid_policy, 0);
+
+ if (!valid_policy) {
+ ima_delete_rules();
+ valid_policy = 1;
+ clear_bit(IMA_FS_BUSY, &ima_fs_flags);
+ return 0;
+ }
+
+ ima_update_policy();
+#if !defined(CONFIG_IMA_WRITE_POLICY) && !defined(CONFIG_IMA_READ_POLICY)
+ securityfs_remove(ima_policy);
+ ima_policy = NULL;
+#elif defined(CONFIG_IMA_WRITE_POLICY)
+ clear_bit(IMA_FS_BUSY, &ima_fs_flags);
+#elif defined(CONFIG_IMA_READ_POLICY)
+ inode->i_mode &= ~S_IWUSR;
+#endif
+ return 0;
+}
+
+static const struct file_operations ima_measure_policy_ops = {
+ .open = ima_open_policy,
+ .write = ima_write_policy,
+ .read = seq_read,
+ .release = ima_release_policy,
+ .llseek = generic_file_llseek,
+};
+
+#endif
int __init ima_fs_init(void)
{
@@ -594,6 +805,7 @@ int __init ima_fs_init(void)
if (IS_ERR(ascii_runtime_measurements))
goto out;
+#ifdef CONFIG_IMA_DIGEST_LIST
runtime_measurements_count =
securityfs_create_file("runtime_measurements_count",
S_IRUSR | S_IRGRP, ima_dir, NULL,
@@ -613,7 +825,6 @@ int __init ima_fs_init(void)
if (IS_ERR(ima_policy))
goto out;
-#ifdef CONFIG_IMA_DIGEST_LIST
digests_count = securityfs_create_file("digests_count",
S_IRUSR | S_IRGRP, ima_dir,
NULL, &ima_htable_value_ops);
@@ -631,12 +842,34 @@ int __init ima_fs_init(void)
&ima_data_upload_ops);
if (IS_ERR(digest_list_data_del))
goto out;
+#else
+ runtime_measurements_count =
+ securityfs_create_file("runtime_measurements_count",
+ S_IRUSR | S_IRGRP, ima_dir, NULL,
+ &ima_measurements_count_ops);
+ if (IS_ERR(runtime_measurements_count))
+ goto out;
+
+ violations =
+ securityfs_create_file("violations", S_IRUSR | S_IRGRP,
+ ima_dir, NULL, &ima_htable_violations_ops);
+ if (IS_ERR(violations))
+ goto out;
+
+ ima_policy = securityfs_create_file("policy", POLICY_FILE_FLAGS,
+ ima_dir, NULL,
+ &ima_measure_policy_ops);
+ if (IS_ERR(ima_policy))
+ goto out;
+
#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..085e8a049f51 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -84,9 +84,15 @@ static int __init ima_add_boot_aggregate(void)
goto err_out;
}
+#ifdef CONFIG_IMA_DIGEST_LIST
result = ima_store_template(entry, violation, NULL,
boot_aggregate_name,
CONFIG_IMA_MEASURE_PCR_IDX, NULL);
+#else
+ result = ima_store_template(entry, violation, NULL,
+ boot_aggregate_name,
+ CONFIG_IMA_MEASURE_PCR_IDX);
+#endif
if (result < 0) {
ima_free_template_entry(entry);
audit_cause = "store_entry";
@@ -107,8 +113,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..c4121330a647 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
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,42 @@ 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)
+#ifdef CONFIG_IMA_DIGEST_LIST
ima_store_measurement(iint, file, pathname,
xattr_value, xattr_len, modsig, pcr,
template_desc,
ima_digest_allow(found_digest,
IMA_MEASURE));
+#else
+ ima_store_measurement(iint, file, pathname,
+ xattr_value, xattr_len, modsig, pcr,
+ template_desc);
+#endif
if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) {
rc = ima_check_blacklist(iint, modsig, pcr);
if (rc != -EPERM) {
inode_lock(inode);
+#ifdef CONFIG_IMA_DIGEST_LIST
rc = ima_appraise_measurement(func, iint, file,
pathname, xattr_value,
xattr_len, modsig,
ima_digest_allow(found_digest,
IMA_APPRAISE));
+#else
+ rc = ima_appraise_measurement(func, iint, file,
+ pathname, xattr_value,
+ xattr_len, modsig);
+#endif
inode_unlock(inode);
}
if (!rc)
@@ -568,15 +590,21 @@ int ima_bprm_check(struct linux_binprm *bprm)
int ima_file_check(struct file *file, int mask)
{
u32 secid;
- int rc;
security_task_getsecid(current, &secid);
+#ifdef CONFIG_IMA_DIGEST_LIST
+ int rc;
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 +767,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 +971,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..3e14b55ecf0f 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
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..a40098347f81 100644
--- a/security/integrity/ima/ima_template.c
+++ b/security/integrity/ima/ima_template.c
@@ -45,8 +45,10 @@ static const struct ima_template_field supported_fields[] = {
{.field_id = "d-modsig", .field_init = ima_eventdigest_modsig_init,
.field_show = ima_show_template_digest_ng},
{.field_id = "modsig", .field_init = ima_eventmodsig_init,
+#ifdef CONFIG_IMA_DIGEST_LIST
.field_show = ima_show_template_sig},
{.field_id = "evmsig", .field_init = ima_eventevmsig_init,
+#endif
.field_show = ima_show_template_sig},
};
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..5313a8a22e45 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
#endif /* __LINUX_IMA_TEMPLATE_LIB_H */
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 77e6819e8db8..d9cf29e286a9 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,7 +176,6 @@ 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);
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);
}
--
2.33.0