[IMA,RFC] blacklist keyring
diff mbox

Message ID 20160627134844.GA6417@p310
State New
Headers show

Commit Message

Petko Manolov June 27, 2016, 1:48 p.m. UTC
On 16-06-26 23:36:41, David Howells wrote:
> Petko Manolov <petkan@mip-labs.com> wrote:
> 
> > Speaking from IMA perspective, the key (or rather the certificate) may be 
> > blacklisted at any time.  Do you propose to keep the key into whatever 
> > keyring it has been put (.ima, .secondary_trusted_keys, etc.) and blacklist 
> > it's TBS hash?
> 
> Note that you don't necessarily have to blacklist the TBS hash - that's why 
> the description is prefixed with "tbs:".  You can prefix it with something 
> else to use some other attribute.  It's just that's what the UEFI database 
> uses as its attribute of choice.

I don't (yet) see a good reason not to comply with what UEFI is using as a 
prefix.  In the future "ima:..." may be added for clarity where the key came 
from, but that's some time away.

> > Isn't it easier to move the actual certificate from one keyring to another, 
> > since it is already taking space?  Or maybe i am missing something important?
> 
> That could be done also.  There is no limitation that *only* blacklist-type 
> keys can be put on the blacklist keyring.

So far i see no need to pollute the system blacklist.  For keys used by the IMA 
subsystem i assume .ima_blacklist is the right place to go.

> However, you're also potentially trading memory for lookup efficiency, and 
> when you permanently blacklist a asymmetric key, you could just ditch it and 
> merely remember the attribute by which it is blacklisted.

The current patch looks up the key only once.  If the key is blacklisted then 
the iint->flags gets updated so next time we walk the tree we fail early.

I do like the idea of dumping 1~2KB of data in exchange for 32 bytes, assuming 
we use SHA256.  However, as of now there is no such infrastructure.  Maybe we 
should introduce a "blacklist" procedure where the key (or rather its payload) 
is kfree()-ed and only the digest (and/or the description) is kept around for 
reference.

I am not entirely sure the above isn't an overkill.

> > > to be a way to get the X.509 parser to generate blacklist type keys 
> > > instead of asymmetric keys.
> > 
> > If i understand correctly you mean the x.509 parser should be taught to 
> > extract the TBSCertificate hash?  If true then some poor bugger would have 
> > to implement the functionality. :)
> 
> It has to do this already.  "TBS" stands for "To Be Signed".  That's the 
> element of the X.509 cert over which the signature is calculated and it's now 
> retained for trust calculation purposes.

Yep, i got to realize this by looking at your code.  Sometimes i am too slow.


Below you'll find the two patches that i've applied on top of your most recent 
'keys-next' branch.  The first is the one i already sent for review, while the 
second is making use of the system blacklist keyring if it is configured.

You can also take them from https://github.com/petkan/linux, branch 'keys'.

I could not test them as your branch oopses with something like (stock -rc4 is 
fine):

---
[    0.000000] Linux version 4.7.0-rc2-ima+ (petkan@p310) (gcc version 6.1.1 20160620 (Debian 6.1.1-7) ) #74 SMP Mon Jun 27 14:33:54 EEST 2016
[    0.000000] Command line: BOOT_IMAGE=/boot/vmlinuz-4.7.0-rc2-ima+ root=/dev/sda1 ro quiet
...
[  245.157373] audit: type=1805 audit(1467027525.416:2): action="dont_measure" fsmagic="0x9fa0" res=1
[  245.157383] audit: type=1805 audit(1467027525.416:3): action="dont_appraise" fsmagic="0x9fa0" res=1
[  245.157389] audit: type=1805 audit(1467027525.416:4): action="dont_measure" fsmagic="0x62656572" res=1
[  245.157395] audit: type=1805 audit(1467027525.416:5): action="dont_appraise" fsmagic="0x62656572" res=1
[  245.157401] audit: type=1805 audit(1467027525.416:6): action="dont_measure" fsmagic="0x64626720" res=1
[  245.157407] audit: type=1805 audit(1467027525.416:7): action="dont_appraise" fsmagic="0x64626720" res=1
[  245.157412] audit: type=1805 audit(1467027525.416:8): action="dont_measure" fsmagic="0x01021994" res=1
[  245.157418] audit: type=1805 audit(1467027525.416:9): action="dont_appraise" fsmagic="0x01021994" res=1
[  245.157423] audit: type=1805 audit(1467027525.416:10): action="dont_measure" fsmagic="0x858458f6" res=1
[  245.157429] audit: type=1805 audit(1467027525.416:11): action="dont_appraise" fsmagic="0x858458f6" res=1
[  245.157571] IMA: policy update completed
[  246.736871] IMA: policy update completed
[  250.409772] integrity: Request for unknown key 'id:ca52fbf2' err -11
[  250.409901] audit_printk_skb: 18 callbacks suppressed
[  250.409902] audit: type=1800 audit(1467027530.666:18): pid=1319 uid=1001 auid=1001 ses=2 op="appraise_data" cause="invalid-signature" comm="busybox-a" name="/home/user/crap/busybox-a" dev="sda1" ino=1076 res=0
[  250.936938] integrity: Request for unknown key 'id:ca52fbf2' err -11
[  250.937319] audit: type=1800 audit(1467027531.196:19): pid=1320 uid=1001 auid=1001 ses=2 op="appraise_data" cause="invalid-signature" comm="busybox-a" name="/home/user/crap/busybox-a" dev="sda1" ino=1076 res=0
[  251.470857] integrity: Request for unknown key 'id:ca52fbf2' err -11
[  251.471238] audit: type=1800 audit(1467027531.726:20): pid=1321 uid=1001 auid=1001 ses=2 op="appraise_data" cause="invalid-signature" comm="busybox-a" name="/home/user/crap/busybox-a" dev="sda1" ino=1076 res=0
[  253.099136] BUG: unable to handle kernel NULL pointer dereference at           (null)
[  253.099395] IP: [<ffffffff812002f9>] software_key_determine_akcipher.isra.0+0x19/0xb0
[  253.099592] PGD 0 
[  253.099689] Oops: 0000 [#1] SMP
[  253.099760] Modules linked in:
[  253.099875] CPU: 0 PID: 1322 Comm: busybox-b Not tainted 4.7.0-rc2-ima+ #74
[  253.100010] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Debian-1.8.2-1 04/01/2014
[  253.100176] task: ffff88003d771ec0 ti: ffff88003d950000 task.ti: ffff88003d950000
[  253.100319] RIP: 0010:[<ffffffff812002f9>]  [<ffffffff812002f9>] software_key_determine_akcipher.isra.0+0x19/0xb0
[  253.100553] RSP: 0018:ffff88003d953b00  EFLAGS: 00010282
[  253.100660] RAX: 0000000000000000 RBX: ffff88003d953c00 RCX: 0000000000000006
[  253.100797] RDX: ffff88003e110198 RSI: 0000000000000000 RDI: ffffffff814cc22e
[  253.100935] RBP: ffff88003d953c80 R08: ffffffff814caaf6 R09: ffff88003d953b78
[  253.101072] R10: ffffea0000f8e880 R11: ffff88003e001e00 R12: ffff88003d953c00
[  253.101209] R13: ffff88003e110180 R14: ffff88003e21ea00 R15: ffff88003db60cc0
[  253.101347] FS:  00007f4c2a806700(0000) GS:ffff88003fc00000(0000) knlGS:0000000000000000
[  253.101500] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  253.101614] CR2: 0000000000000000 CR3: 000000003d4de000 CR4: 00000000000006b0
[  253.101753] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[  253.101898] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[  253.102011] Stack:
[  253.102055]  ffff88003d953c00 ffffffff812003e5 ffff88003e2da6c0 ffff88003daf5058
[  253.102414]  ffff88003e21ea00 ffff88003e2da6c0 ffffffff811dbcc1 ffff88003d953b60
[  253.102773]  ffff88003e2da6c1 ffff88003d953b60 ffffffff811dbd76 ffff88003db60cc1
[  253.103137] Call Trace:
[  253.103282]  [<ffffffff812003e5>] ? public_key_verify_signature+0x55/0x200
[  253.103487]  [<ffffffff811dbcc1>] ? keyring_search_aux+0x61/0x90
[  253.103677]  [<ffffffff811dbd76>] ? keyring_search+0x86/0xa0
[  253.103864]  [<ffffffff811ffeb0>] ? asymmetric_key_id_partial+0x40/0x40
[  253.104063]  [<ffffffff811db6a0>] ? key_default_cmp+0x20/0x20
[  253.104252]  [<ffffffff811e84c2>] ? asymmetric_verify+0x172/0x2a0
[  253.104445]  [<ffffffff811ecb63>] ? ima_appraise_measurement+0x363/0x3d0
[  253.104646]  [<ffffffff811e9558>] ? process_measurement+0x508/0x5c0
[  253.104841]  [<ffffffff81104c5d>] ? vm_mmap_pgoff+0x3d/0xd0
[  253.105036]  [<ffffffff8112aebb>] ? setup_arg_pages+0x1ab/0x210
[  253.105221]  [<ffffffff8116bf56>] ? load_elf_binary+0x5f6/0x1660
[  253.105406]  [<ffffffff8112bd8b>] ? search_binary_handler+0x9b/0x1c0
[  253.105595]  [<ffffffff8112c694>] ? do_execveat_common+0x4f4/0x640
[  253.105782]  [<ffffffff8112ca13>] ? SyS_execve+0x23/0x30
[  253.105959]  [<ffffffff81001565>] ? do_syscall_64+0x45/0x90
[  253.106140]  [<ffffffff813d2361>] ? entry_SYSCALL64_slow_path+0x25/0x25
[  253.106332] Code: 8b 50 10 e9 9a 67 f4 ff c3 66 0f 1f 84 00 00 00 00 00 48 89 f8 53 49 89 f0 49 89 c9 48 c7 c7 2e c2 4c 81 b9 06 00 00 00 48 89 c6 <f3> a6 0f 97 c3 0f 92 c1 29 cb 0f be db 85 db 75 2b 4d 85 c0 48 
[  253.109023] RIP  [<ffffffff812002f9>] software_key_determine_akcipher.isra.0+0x19/0xb0
[  253.109260]  RSP <ffff88003d953b00>
[  253.109410] CR2: 0000000000000000
[  253.109563] ---[ end trace ebb97510ccea56f8 ]---


--- patch one ---


From b0d6a735884af6b7ef4d20730635aae8768e9b29 Mon Sep 17 00:00:00 2001
From: Petko Manolov <petkan@mip-labs.com>
Date: Sun, 26 Jun 2016 13:39:09 +0300
Subject: [PATCH 1/2] WIP: a stab at IMA blacklist functionality;

Signed-off-by: Petko Manolov <petkan@mip-labs.com>
---
 security/integrity/digsig.c            |  5 ++-
 security/integrity/digsig_asymmetric.c |  9 ++++-
 security/integrity/evm/evm_main.c      |  8 +++-
 security/integrity/iint.c              | 69 +++++++++++++++++++++++++++++++++-
 security/integrity/ima/ima_appraise.c  |  6 +--
 security/integrity/ima/ima_main.c      |  8 ++--
 security/integrity/integrity.h         | 19 ++++++++--
 7 files changed, 108 insertions(+), 16 deletions(-)

Comments

Petko Manolov June 27, 2016, 2:01 p.m. UTC | #1
On 16-06-27 16:48:44, Petko Manolov wrote:
> 
> Below you'll find the two patches that i've applied on top of your most recent 
> 'keys-next' branch.  The first is the one i already sent for review, while the 
> second is making use of the system blacklist keyring if it is configured.
> 
> You can also take them from https://github.com/petkan/linux, branch 'keys'.
> 
> I could not test them as your branch oopses with something like (stock -rc4 is 
> fine):

FYI: the patches i sent earlier work fine with your kernel.org 'keys-blacklist' 
branch.


		Petko
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Howells June 28, 2016, 7:36 a.m. UTC | #2
Petko Manolov <petkan@mip-labs.com> wrote:

> > I could not test them as your branch oopses with something like (stock
> > -rc4 is fine):
> 
> FYI: the patches i sent earlier work fine with your kernel.org
> 'keys-blacklist' branch.

Where did the oops come from?  Should I ignore it?

David
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Petko Manolov June 28, 2016, 9:13 a.m. UTC | #3
On 16-06-28 08:36:42, David Howells wrote:
> Petko Manolov <petkan@mip-labs.com> wrote:
> 
> > > I could not test them as your branch oopses with something like (stock 
> > > -rc4 is fine):
> > 
> > FYI: the patches i sent earlier work fine with your kernel.org 
> > 'keys-blacklist' branch.
> 
> Where did the oops come from?  Should I ignore it?

I was experimenting with IMA blacklist patches applied on top of your 
'keys-next' branch.  It crashed.  Since 'keys-next' has a bunch of other key 
handling commits i decided to try 'keys-blacklist'.  This time i managed to run 
my tests successfully.

The above makes me think the bug was introduced sometime after commit 5b8286d9.  
If you like i can try to bisect it for you in the afternoon.


		Petko
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Howells June 28, 2016, 9:42 a.m. UTC | #4
Petko Manolov <petkan@mip-labs.com> wrote:

> If you like i can try to bisect it for you in the afternoon.

That would be useful if you could, thanks.

David
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch
diff mbox

diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
index 4304372..483f870 100644
--- a/security/integrity/digsig.c
+++ b/security/integrity/digsig.c
@@ -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;
diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c
index 80052ed..40657df 100644
--- a/security/integrity/digsig_asymmetric.c
+++ b/security/integrity/digsig_asymmetric.c
@@ -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;
 }
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index b9e2628..0c0a93a 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -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;
 }
diff --git a/security/integrity/iint.c b/security/integrity/iint.c
index 345b759..68f95f3 100644
--- a/security/integrity/iint.c
+++ b/security/integrity/iint.c
@@ -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)
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 1bcbc12..4c8bca2 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -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;
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index 68b26c3..7c866d8 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -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;
 }
 
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 90bc57d..6076762 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -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


--- patch two ---


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(-)

diff --git a/certs/blacklist.c b/certs/blacklist.c
index 3eddce0..bbabd86b 100644
--- a/certs/blacklist.c
+++ b/certs/blacklist.c
@@ -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,
diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
index 0d87626..8bc3ff4 100644
--- a/include/keys/system_keyring.h
+++ b/include/keys/system_keyring.h
@@ -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);
diff --git a/security/integrity/iint.c b/security/integrity/iint.c
index 68f95f3..e690873 100644
--- a/security/integrity/iint.c
+++ b/security/integrity/iint.c
@@ -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;