Isolate the IMA digest list code by using macros.
v2:
Exclude some macros for code that has already been merged into upstream kernel.
Signed-off-by: Zhou Shuiqing <zhoushuiqing2(a)huawei.com>
---
fs/xattr.c | 4 +
include/linux/evm.h | 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 | 79 +++++++-
security/integrity/iint.c | 2 +
security/integrity/ima/ima.h | 80 +++++++-
security/integrity/ima/ima_api.c | 39 ++++
security/integrity/ima/ima_appraise.c | 154 ++++++++++++++-
security/integrity/ima/ima_fs.c | 247 ++++++++++++++++++++++++-
security/integrity/ima/ima_init.c | 6 +
security/integrity/ima/ima_main.c | 36 ++++
security/integrity/ima/ima_policy.c | 80 ++++++++
security/integrity/integrity.h | 15 +-
security/security.c | 2 +
17 files changed, 779 insertions(+), 21 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..39bb17a8236b 100644
--- a/include/linux/evm.h
+++ b/include/linux/evm.h
@@ -35,7 +35,7 @@ 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);
-extern bool evm_status_revalidate(const char *xattr_name);
+extern bool evm_revalidate_status(const char *xattr_name);
#ifdef CONFIG_FS_POSIX_ACL
extern int posix_xattr_acl(const char *xattrname);
#else
@@ -105,7 +105,7 @@ static inline int evm_inode_init_security(struct inode *inode,
return 0;
}
-static inline bool evm_status_revalidate(const char *xattr_name)
+static inline bool evm_revalidate_status(const char *xattr_name)
{
return false;
}
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..46d90da6169d 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -57,6 +57,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 +74,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 +111,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 +129,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 +152,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 +184,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 +194,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, evm_immutable = 0;;
+#endif
+
if (iint && (iint->evm_status == INTEGRITY_PASS ||
iint->evm_status == INTEGRITY_PASS_IMMUTABLE))
return iint->evm_status;
@@ -184,7 +212,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 +224,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 +239,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;
@@ -262,6 +298,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 +339,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 +354,22 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
evm_status = evm_immutable ?
INTEGRITY_FAIL_IMMUTABLE : INTEGRITY_FAIL;
}
+#else
+ if (rc) {
+ if (rc == -ENODATA)
+ evm_status = INTEGRITY_NOXATTRS;
+ else if (evm_immutable)
+ evm_status = INTEGRITY_FAIL_IMMUTABLE;
+ else
+ evm_status = 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;
}
@@ -569,8 +620,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,
@@ -606,7 +661,7 @@ static void evm_reset_status(struct inode *inode)
}
/**
- * evm_status_revalidate - report whether EVM status re-validation is necessary
+ * evm_revalidate_status - report whether EVM status re-validation is necessary
* @xattr_name: pointer to the affected extended attribute name
*
* Report whether callers of evm_verifyxattr() should re-validate the
@@ -614,7 +669,7 @@ static void evm_reset_status(struct inode *inode)
*
* Return true if re-validation is necessary, false otherwise.
*/
-bool evm_status_revalidate(const char *xattr_name)
+bool evm_revalidate_status(const char *xattr_name)
{
if (!evm_key_loaded())
return false;
@@ -646,7 +701,7 @@ 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)
{
- if (!evm_status_revalidate(xattr_name))
+ if (!evm_revalidate_status(xattr_name))
return;
evm_reset_status(dentry->d_inode);
@@ -669,7 +724,7 @@ void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
*/
void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
{
- if (!evm_status_revalidate(xattr_name))
+ if (!evm_revalidate_status(xattr_name))
return;
evm_reset_status(dentry->d_inode);
@@ -714,6 +769,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.
@@ -723,6 +779,12 @@ int evm_inode_setattr(struct dentry *dentry, struct iattr *attr)
(evm_status == INTEGRITY_FAIL_IMMUTABLE) ||
(evm_ignore_error_safe(evm_status)))
return 0;
+#else
+ if ((evm_status == INTEGRITY_PASS) ||
+ (evm_status == INTEGRITY_NOXATTRS) ||
+ (evm_status == INTEGRITY_FAIL_IMMUTABLE))
+ return 0;
+#endif
if (evm_status == INTEGRITY_PASS_IMMUTABLE &&
!evm_attr_change(dentry, attr))
@@ -747,7 +809,7 @@ int evm_inode_setattr(struct dentry *dentry, struct iattr *attr)
*/
void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
{
- if (!evm_status_revalidate(NULL))
+ if (!evm_revalidate_status(NULL))
return;
evm_reset_status(dentry->d_inode);
@@ -780,7 +842,9 @@ 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;
+#endif
evm_xattr->name = XATTR_EVM_SUFFIX;
return 0;
out:
@@ -802,6 +866,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 +874,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..22dc1eb63f78 100644
--- a/security/integrity/iint.c
+++ b/security/integrity/iint.c
@@ -212,7 +212,9 @@ void __init integrity_load_keys(void)
if (!IS_ENABLED(CONFIG_IMA_LOAD_X509))
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..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..000b4c338ba4 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,13 +286,18 @@ 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;
@@ -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,6 +539,7 @@ int ima_appraise_measurement(enum ima_hooks func,
ima_digest_is_immutable(found_digest))
break;
}
+#endif
cause = "missing-HMAC";
goto out;
case INTEGRITY_FAIL_IMMUTABLE:
@@ -458,6 +552,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 +561,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
@@ -609,6 +710,7 @@ static void ima_reset_appraise_flags(struct inode *inode, int digsig)
clear_bit(IMA_DIGSIG, &iint->atomic_flags);
}
+#ifdef CONFIG_IMA_DIGEST_LIST
int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
const void *xattr_value, size_t xattr_value_len)
{
@@ -624,7 +726,35 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
}
return result;
}
+#else
+int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
+ const void *xattr_value, size_t xattr_value_len)
+{
+ const struct evm_ima_xattr_data *xvalue = xattr_value;
+ int digsig = 0;
+ int result;
+ result = ima_protect_xattr(dentry, xattr_name, xattr_value,
+ xattr_value_len);
+ if (result == 1) {
+ if (!xattr_value_len || (xvalue->type >= IMA_XATTR_LAST))
+ return -EINVAL;
+ digsig = (xvalue->type == EVM_IMA_XATTR_DIGSIG);
+#ifndef CONFIG_IMA_DIGEST_LIST
+ } else if (!strcmp(xattr_name, XATTR_NAME_EVM) && xattr_value_len > 0) {
+ digsig = (xvalue->type == EVM_XATTR_PORTABLE_DIGSIG);
+#endif
+ }
+ if (result == 1 || evm_revalidate_status(xattr_name)) {
+ ima_reset_appraise_flags(d_backing_inode(dentry), digsig);
+ if (result == 1)
+ result = 0;
+ }
+ return result;
+}
+#endif
+
+#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)
{
@@ -638,10 +768,12 @@ void ima_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
digsig = (xvalue->type == EVM_IMA_XATTR_DIGSIG);
if (!strcmp(xattr_name, XATTR_NAME_EVM) && xattr_value_len > 0)
digsig = (xvalue->type == EVM_XATTR_PORTABLE_DIGSIG);
- if (result == 1 || evm_status_revalidate(xattr_name))
+ if (result == 1 || evm_revalidate_status(xattr_name))
ima_reset_appraise_flags(d_backing_inode(dentry), digsig);
}
+#endif
+#ifdef CONFIG_IMA_DIGEST_LIST
int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name)
{
int result;
@@ -652,12 +784,28 @@ int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name)
}
return result;
}
+#else
+int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name)
+{
+ int result;
+ result = ima_protect_xattr(dentry, xattr_name, NULL, 0);
+ if (result == 1 || evm_revalidate_status(xattr_name)) {
+ ima_reset_appraise_flags(d_backing_inode(dentry), 0);
+ if (result == 1)
+ result = 0;
+ }
+ return result;
+}
+#endif
+
+#ifdef CONFIG_IMA_DIGEST_LIST
void ima_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
{
int result;
result = ima_protect_xattr(dentry, xattr_name, NULL, 0);
- if (result == 1 || evm_status_revalidate(xattr_name))
+ if (result == 1 || evm_revalidate_status(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..da47d366a98c 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";
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 999d5904cce0..fc1af21b3ad8 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,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 +769,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 +973,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/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