@@ -49,7 +49,8 @@ static bool init_keyring __initdata;
#endif
int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
- const char *digest, int digestlen)
+ const char *digest, int digestlen,
+ struct integrity_iint_cache *iint)
{
if (id >= INTEGRITY_KEYRING_MAX)
return -EINVAL;
@@ -72,7 +73,7 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
digest, digestlen);
case 2:
return asymmetric_verify(keyring[id], sig, siglen,
- digest, digestlen);
+ digest, digestlen, iint);
}
return -EOPNOTSUPP;
@@ -80,7 +80,8 @@ static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid)
}
int asymmetric_verify(struct key *keyring, const char *sig,
- int siglen, const char *data, int datalen)
+ int siglen, const char *data, int datalen,
+ struct integrity_iint_cache *iint)
{
struct public_key_signature pks;
struct signature_v2_hdr *hdr = (struct signature_v2_hdr *)sig;
@@ -113,5 +114,11 @@ int asymmetric_verify(struct key *keyring, const char *sig,
ret = verify_signature(key, &pks);
key_put(key);
pr_debug("%s() = %d\n", __func__, ret);
+#ifdef CONFIG_IMA_BLACKLIST_KEYRING
+ if (!ret && iint) {
+ iint->key = key;
+ iint->last_time = current_kernel_time().tv_sec;
+ }
+#endif
return ret;
}
@@ -161,7 +161,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
break;
rc = integrity_digsig_verify(INTEGRITY_KEYRING_EVM,
(const char *)xattr_data, xattr_len,
- calc.digest, sizeof(calc.digest));
+ calc.digest, sizeof(calc.digest), NULL);
if (!rc) {
/* Replace RSA with HMAC if not mounted readonly and
* not immutable
@@ -237,7 +237,7 @@ enum integrity_status evm_verifyxattr(struct dentry *dentry,
if (!iint) {
iint = integrity_iint_find(d_backing_inode(dentry));
- if (!iint)
+ if (!iint || IS_ERR(iint))
return INTEGRITY_UNKNOWN;
}
return evm_verify_hmac(dentry, xattr_name, xattr_value,
@@ -295,6 +295,8 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
struct integrity_iint_cache *iint;
iint = integrity_iint_find(d_backing_inode(dentry));
+ if (IS_ERR(iint))
+ return -EPERM;
if (iint && (iint->flags & IMA_NEW_FILE))
return 0;
@@ -364,6 +366,8 @@ static void evm_reset_status(struct inode *inode)
struct integrity_iint_cache *iint;
iint = integrity_iint_find(inode);
+ if (IS_ERR(iint))
+ return;
if (iint)
iint->evm_status = INTEGRITY_UNKNOWN;
}
@@ -21,12 +21,62 @@
#include <linux/rbtree.h>
#include <linux/file.h>
#include <linux/uaccess.h>
+#include <linux/audit.h>
+#include <keys/system_keyring.h>
+#include <keys/asymmetric-type.h>
#include "integrity.h"
static struct rb_root integrity_iint_tree = RB_ROOT;
static DEFINE_RWLOCK(integrity_iint_lock);
static struct kmem_cache *iint_cache __read_mostly;
+#ifdef CONFIG_IMA_BLACKLIST_KEYRING
+static int keys_in_keyring(struct key *keyring)
+{
+ if (key_is_instantiated(keyring)) {
+ return keyring->keys.nr_leaves_on_tree;
+ }
+
+ return -EINVAL;
+}
+
+/*
+ * returns negative if the key is not blacklisted and 0 if it is;
+ */
+static int iint_bl_check(struct integrity_iint_cache *iint)
+{
+ struct key *bl;
+ key_ref_t bl_t, key=ERR_PTR(-ENOKEY);
+
+ if (!iint)
+ return -1;
+
+ if (iint->flags & IMA_IINT_BLACKLISTED)
+ return 0;
+
+ bl = get_ima_blacklist_keyring();
+ if (!bl)
+ return -2;
+
+ if (!keys_in_keyring(bl))
+ return -3;
+
+ if (iint->last_time > bl->last_used_at)
+ return -4;
+
+ bl_t = make_key_ref(bl, 1);
+ if (iint->key)
+ key = keyring_search(bl_t, &key_type_asymmetric, iint->key->description);
+
+ if (IS_ERR(key))
+ return -5;
+
+ iint->flags |= IMA_IINT_BLACKLISTED;
+
+ return 0;
+}
+#endif /* CONFIG_IMA_BLACKLIST_KEYRING */
+
/*
* __integrity_iint_find - return the iint associated with an inode
*/
@@ -52,7 +102,8 @@ static struct integrity_iint_cache *__integrity_iint_find(struct inode *inode)
}
/*
- * integrity_iint_find - return the iint associated with an inode
+ * integrity_iint_find - return the iint associated with an inode, NULL or
+ * an error if the corrsponding key has been blacklisted in the meantime.
*/
struct integrity_iint_cache *integrity_iint_find(struct inode *inode)
{
@@ -65,6 +116,14 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode)
iint = __integrity_iint_find(inode);
read_unlock(&integrity_iint_lock);
+#ifdef CONFIG_IMA_BLACKLIST_KEYRING
+ if (!iint_bl_check(iint)) {
+ integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, NULL,
+ "appraise_data", "blacklisted-key",
+ -EINVAL, 0);
+ return ERR_PTR(-EINVAL);
+ }
+#endif
return iint;
}
@@ -79,6 +138,10 @@ static void iint_free(struct integrity_iint_cache *iint)
iint->ima_bprm_status = INTEGRITY_UNKNOWN;
iint->ima_read_status = INTEGRITY_UNKNOWN;
iint->evm_status = INTEGRITY_UNKNOWN;
+#ifdef CONFIG_IMA_BLACKLIST_KEYRING
+ iint->key = NULL;
+ iint->last_time = 0;
+#endif
kmem_cache_free(iint_cache, iint);
}
@@ -159,6 +222,10 @@ static void init_once(void *foo)
iint->ima_bprm_status = INTEGRITY_UNKNOWN;
iint->ima_read_status = INTEGRITY_UNKNOWN;
iint->evm_status = INTEGRITY_UNKNOWN;
+#ifdef CONFIG_IMA_BLACKLIST_KEYRING
+ iint->key = NULL;
+ iint->last_time = 0;
+#endif
}
static int __init integrity_iintcache_init(void)
@@ -252,7 +252,7 @@ int ima_appraise_measurement(enum ima_hooks func,
rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA,
(const char *)xattr_value, rc,
iint->ima_hash->digest,
- iint->ima_hash->length);
+ iint->ima_hash->length, iint);
if (rc == -EOPNOTSUPP) {
status = INTEGRITY_UNKNOWN;
} else if (rc) {
@@ -330,7 +330,7 @@ void ima_inode_post_setattr(struct dentry *dentry)
must_appraise = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR);
iint = integrity_iint_find(inode);
- if (iint) {
+ if (iint && !IS_ERR(iint)) {
iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED |
IMA_APPRAISE_SUBMASK | IMA_APPRAISED_SUBMASK |
IMA_ACTION_RULE_FLAGS);
@@ -366,7 +366,7 @@ static void ima_reset_appraise_flags(struct inode *inode, int digsig)
return;
iint = integrity_iint_find(inode);
- if (!iint)
+ if (!iint || IS_ERR(iint))
return;
iint->flags &= ~IMA_DONE_MASK;
@@ -90,6 +90,8 @@ static void ima_rdwr_violation_check(struct file *file,
if (atomic_read(&inode->i_readcount) && IS_IMA(inode)) {
if (!iint)
iint = integrity_iint_find(inode);
+ if (IS_ERR(iint))
+ return;
/* IMA_MEASURE is set from reader side */
if (iint && (iint->flags & IMA_MEASURE))
send_tomtou = true;
@@ -147,7 +149,7 @@ void ima_file_free(struct file *file)
return;
iint = integrity_iint_find(inode);
- if (!iint)
+ if (!iint || IS_ERR(iint))
return;
ima_check_last_writer(iint, inode, file);
@@ -190,7 +192,7 @@ static int process_measurement(struct file *file, char *buf, loff_t size,
if (action) {
iint = integrity_inode_get(inode);
- if (!iint)
+ if (!iint || IS_ERR(iint))
goto out;
}
@@ -334,7 +336,7 @@ void ima_post_path_mknod(struct dentry *dentry)
return;
iint = integrity_inode_get(inode);
- if (iint)
+ if (iint && !IS_ERR(iint))
iint->flags |= IMA_NEW_FILE;
}
@@ -53,6 +53,9 @@
#define IMA_APPRAISED_SUBMASK (IMA_FILE_APPRAISED | IMA_MMAP_APPRAISED | \
IMA_BPRM_APPRAISED | IMA_READ_APPRAISED)
+#define IMA_IINT_BLACKLISTED_BIT (BITS_PER_LONG - 1)
+#define IMA_IINT_BLACKLISTED (1UL << IMA_IINT_BLACKLISTED_BIT)
+
enum evm_ima_xattr_type {
IMA_XATTR_DIGEST = 0x01,
EVM_XATTR_HMAC,
@@ -109,6 +112,10 @@ struct integrity_iint_cache {
enum integrity_status ima_read_status:4;
enum integrity_status evm_status:4;
struct ima_digest_data *ima_hash;
+#ifdef CONFIG_IMA_BLACKLIST_KEYRING
+ struct key *key;
+ time_t last_time;
+#endif
};
/* rbtree tree calls to lookup, insert, delete
@@ -128,7 +135,8 @@ int __init integrity_read_file(const char *path, char **data);
#ifdef CONFIG_INTEGRITY_SIGNATURE
int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
- const char *digest, int digestlen);
+ const char *digest, int digestlen,
+ struct integrity_iint_cache *iint);
int __init integrity_init_keyring(const unsigned int id);
int __init integrity_load_x509(const unsigned int id, const char *path);
@@ -136,7 +144,8 @@ int __init integrity_load_x509(const unsigned int id, const char *path);
static inline int integrity_digsig_verify(const unsigned int id,
const char *sig, int siglen,
- const char *digest, int digestlen)
+ const char *digest, int digestlen,
+ struct integrity_iint_cache *iint)
{
return -EOPNOTSUPP;
}
@@ -149,10 +158,12 @@ static inline int integrity_init_keyring(const unsigned int id)
#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
int asymmetric_verify(struct key *keyring, const char *sig,
- int siglen, const char *data, int datalen);
+ int siglen, const char *data, int datalen,
+ struct integrity_iint_cache *);
#else
static inline int asymmetric_verify(struct key *keyring, const char *sig,
- int siglen, const char *data, int datalen)
+ int siglen, const char *data, int datalen,
+ struct integrity_iint_cache *)
{
return -EOPNOTSUPP;
}
--
2.8.1
From d80057badc1f987dc2ba244da43fbf0e3edd7294 Mon Sep 17 00:00:00 2001
From: Petko Manolov <petkan@mip-labs.com>
Date: Mon, 27 Jun 2016 15:21:17 +0300
Subject: [PATCH 2/2] make use of the system blacklist keyring, if available;
Signed-off-by: Petko Manolov <petkan@mip-labs.com>
---
certs/blacklist.c | 4 ++--
include/keys/system_keyring.h | 2 ++
security/integrity/iint.c | 17 +++++++++++------
3 files changed, 15 insertions(+), 8 deletions(-)
@@ -21,7 +21,7 @@
#include <keys/system_keyring.h>
#include "blacklist.h"
-static struct key *blacklist_keyring;
+struct key *blacklist_keyring;
/*
* The description must be a type prefix, a colon and then an even number of
@@ -71,7 +71,7 @@ static void blacklist_describe(const struct key *key, struct seq_file *m)
seq_puts(m, key->description);
}
-static struct key_type key_type_blacklist = {
+struct key_type key_type_blacklist = {
.name = "blacklist",
.vet_description = blacklist_vet_description,
.preparse = blacklist_preparse,
@@ -34,6 +34,8 @@ extern int restrict_link_by_builtin_and_secondary_trusted(
#endif
#ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING
+extern struct key *blacklist_keyring;
+extern struct key_type key_type_blacklist;
extern int mark_hash_blacklisted(const char *hash);
extern int is_hash_blacklisted(const u8 *hash, size_t hash_len,
const char *type);
@@ -46,7 +46,7 @@ static int keys_in_keyring(struct key *keyring)
static int iint_bl_check(struct integrity_iint_cache *iint)
{
struct key *bl;
- key_ref_t bl_t, key=ERR_PTR(-ENOKEY);
+ key_ref_t bl_t, ima=ERR_PTR(-ENOKEY), sys=ERR_PTR(-ENOKEY);
if (!iint)
return -1;
@@ -64,11 +64,16 @@ static int iint_bl_check(struct integrity_iint_cache *iint)
if (iint->last_time > bl->last_used_at)
return -4;
- bl_t = make_key_ref(bl, 1);
- if (iint->key)
- key = keyring_search(bl_t, &key_type_asymmetric, iint->key->description);
-
- if (IS_ERR(key))
+ if (iint->key) {
+ bl_t = make_key_ref(bl, true);
+ ima = keyring_search(bl_t, &key_type_asymmetric, iint->key->description);
+#ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING
+ bl_t = make_key_ref(blacklist_keyring, true);
+ sys = keyring_search(bl_t, &key_type_blacklist, iint->key->description);
+#endif
+ }
+ printk("%s: ima %p, sys %p\n", __func__, ima, sys);
+ if (IS_ERR(ima) && IS_ERR(sys))
return -5;
iint->flags |= IMA_IINT_BLACKLISTED;