summary refs log tree commit diff
path: root/security
diff options
context:
space:
mode:
Diffstat (limited to 'security')
-rw-r--r--security/commoncap.c7
-rw-r--r--security/inode.c10
-rw-r--r--security/integrity/Kconfig11
-rw-r--r--security/integrity/digsig.c14
-rw-r--r--security/integrity/digsig_asymmetric.c14
-rw-r--r--security/integrity/evm/Kconfig17
-rw-r--r--security/integrity/evm/evm.h3
-rw-r--r--security/integrity/evm/evm_crypto.c54
-rw-r--r--security/integrity/evm/evm_main.c35
-rw-r--r--security/integrity/evm/evm_secfs.c12
-rw-r--r--security/integrity/iint.c12
-rw-r--r--security/integrity/ima/Kconfig44
-rw-r--r--security/integrity/ima/Makefile1
-rw-r--r--security/integrity/ima/ima.h24
-rw-r--r--security/integrity/ima/ima_fs.c53
-rw-r--r--security/integrity/ima/ima_init.c2
-rw-r--r--security/integrity/ima/ima_main.c8
-rw-r--r--security/integrity/ima/ima_mok.c55
-rw-r--r--security/integrity/ima/ima_policy.c301
-rw-r--r--security/integrity/integrity.h13
-rw-r--r--security/keys/Kconfig1
-rw-r--r--security/keys/encrypted-keys/encrypted.c2
-rw-r--r--security/keys/key.c6
-rw-r--r--security/keys/keyctl.c67
-rw-r--r--security/keys/process_keys.c1
-rw-r--r--security/keys/trusted.c61
-rw-r--r--security/keys/user_defined.c5
-rw-r--r--security/selinux/nlmsgtab.c1
-rw-r--r--security/selinux/selinuxfs.c118
-rw-r--r--security/selinux/ss/conditional.c4
-rw-r--r--security/smack/smack_lsm.c34
-rw-r--r--security/smack/smackfs.c114
-rw-r--r--security/tomoyo/securityfs_if.c11
-rw-r--r--security/yama/yama_lsm.c4
34 files changed, 829 insertions, 290 deletions
diff --git a/security/commoncap.c b/security/commoncap.c
index 1832cf701c3d..48071ed7c445 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -137,12 +137,17 @@ int cap_ptrace_access_check(struct task_struct *child, unsigned int mode)
 {
 	int ret = 0;
 	const struct cred *cred, *child_cred;
+	const kernel_cap_t *caller_caps;
 
 	rcu_read_lock();
 	cred = current_cred();
 	child_cred = __task_cred(child);
+	if (mode & PTRACE_MODE_FSCREDS)
+		caller_caps = &cred->cap_effective;
+	else
+		caller_caps = &cred->cap_permitted;
 	if (cred->user_ns == child_cred->user_ns &&
-	    cap_issubset(child_cred->cap_permitted, cred->cap_permitted))
+	    cap_issubset(child_cred->cap_permitted, *caller_caps))
 		goto out;
 	if (ns_capable(child_cred->user_ns, CAP_SYS_PTRACE))
 		goto out;
diff --git a/security/inode.c b/security/inode.c
index 16622aef9bde..28414b0207ce 100644
--- a/security/inode.c
+++ b/security/inode.c
@@ -99,7 +99,7 @@ struct dentry *securityfs_create_file(const char *name, umode_t mode,
 
 	dir = d_inode(parent);
 
-	mutex_lock(&dir->i_mutex);
+	inode_lock(dir);
 	dentry = lookup_one_len(name, parent, strlen(name));
 	if (IS_ERR(dentry))
 		goto out;
@@ -129,14 +129,14 @@ struct dentry *securityfs_create_file(const char *name, umode_t mode,
 	}
 	d_instantiate(dentry, inode);
 	dget(dentry);
-	mutex_unlock(&dir->i_mutex);
+	inode_unlock(dir);
 	return dentry;
 
 out1:
 	dput(dentry);
 	dentry = ERR_PTR(error);
 out:
-	mutex_unlock(&dir->i_mutex);
+	inode_unlock(dir);
 	simple_release_fs(&mount, &mount_count);
 	return dentry;
 }
@@ -195,7 +195,7 @@ void securityfs_remove(struct dentry *dentry)
 	if (!parent || d_really_is_negative(parent))
 		return;
 
-	mutex_lock(&d_inode(parent)->i_mutex);
+	inode_lock(d_inode(parent));
 	if (simple_positive(dentry)) {
 		if (d_is_dir(dentry))
 			simple_rmdir(d_inode(parent), dentry);
@@ -203,7 +203,7 @@ void securityfs_remove(struct dentry *dentry)
 			simple_unlink(d_inode(parent), dentry);
 		dput(dentry);
 	}
-	mutex_unlock(&d_inode(parent)->i_mutex);
+	inode_unlock(d_inode(parent));
 	simple_release_fs(&mount, &mount_count);
 }
 EXPORT_SYMBOL_GPL(securityfs_remove);
diff --git a/security/integrity/Kconfig b/security/integrity/Kconfig
index 73c457bf5a4a..21d756832b75 100644
--- a/security/integrity/Kconfig
+++ b/security/integrity/Kconfig
@@ -41,6 +41,17 @@ config INTEGRITY_ASYMMETRIC_KEYS
 	  This option enables digital signature verification using
 	  asymmetric keys.
 
+config INTEGRITY_TRUSTED_KEYRING
+	bool "Require all keys on the integrity keyrings be signed"
+	depends on SYSTEM_TRUSTED_KEYRING
+	depends on INTEGRITY_ASYMMETRIC_KEYS
+	select KEYS_DEBUG_PROC_KEYS
+	default y
+	help
+	   This option requires that all keys added to the .ima and
+	   .evm keyrings be signed by a key on the system trusted
+	   keyring.
+
 config INTEGRITY_AUDIT
 	bool "Enables integrity auditing support "
 	depends on AUDIT
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
index 5be9ffbe90ba..8ef15118cc78 100644
--- a/security/integrity/digsig.c
+++ b/security/integrity/digsig.c
@@ -24,15 +24,22 @@
 static struct key *keyring[INTEGRITY_KEYRING_MAX];
 
 static const char *keyring_name[INTEGRITY_KEYRING_MAX] = {
+#ifndef CONFIG_INTEGRITY_TRUSTED_KEYRING
 	"_evm",
-	"_module",
-#ifndef CONFIG_IMA_TRUSTED_KEYRING
 	"_ima",
 #else
+	".evm",
 	".ima",
 #endif
+	"_module",
 };
 
+#ifdef CONFIG_INTEGRITY_TRUSTED_KEYRING
+static bool init_keyring __initdata = true;
+#else
+static bool init_keyring __initdata;
+#endif
+
 int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
 			    const char *digest, int digestlen)
 {
@@ -68,6 +75,9 @@ int __init integrity_init_keyring(const unsigned int id)
 	const struct cred *cred = current_cred();
 	int err = 0;
 
+	if (!init_keyring)
+		return 0;
+
 	keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0),
 				    KGIDT_INIT(0), cred,
 				    ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c
index 4fec1816a2b3..5ade2a7517a6 100644
--- a/security/integrity/digsig_asymmetric.c
+++ b/security/integrity/digsig_asymmetric.c
@@ -17,6 +17,7 @@
 #include <linux/key-type.h>
 #include <crypto/public_key.h>
 #include <keys/asymmetric-type.h>
+#include <keys/system_keyring.h>
 
 #include "integrity.h"
 
@@ -32,9 +33,22 @@ static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid)
 
 	pr_debug("key search: \"%s\"\n", name);
 
+	key = get_ima_blacklist_keyring();
+	if (key) {
+		key_ref_t kref;
+
+		kref = keyring_search(make_key_ref(key, 1),
+				     &key_type_asymmetric, name);
+		if (!IS_ERR(kref)) {
+			pr_err("Key '%s' is in ima_blacklist_keyring\n", name);
+			return ERR_PTR(-EKEYREJECTED);
+		}
+	}
+
 	if (keyring) {
 		/* search in specific keyring */
 		key_ref_t kref;
+
 		kref = keyring_search(make_key_ref(keyring, 1),
 				      &key_type_asymmetric, name);
 		if (IS_ERR(kref))
diff --git a/security/integrity/evm/Kconfig b/security/integrity/evm/Kconfig
index bf19723cf117..e825e0ae78e7 100644
--- a/security/integrity/evm/Kconfig
+++ b/security/integrity/evm/Kconfig
@@ -42,3 +42,20 @@ config EVM_EXTRA_SMACK_XATTRS
 	  additional info to the calculation, requires existing EVM
 	  labeled file systems to be relabeled.
 
+config EVM_LOAD_X509
+	bool "Load an X509 certificate onto the '.evm' trusted keyring"
+	depends on EVM && INTEGRITY_TRUSTED_KEYRING
+	default n
+	help
+	   Load an X509 certificate onto the '.evm' trusted keyring.
+
+	   This option enables X509 certificate loading from the kernel
+	   onto the '.evm' trusted keyring.  A public key can be used to
+	   verify EVM integrity starting from the 'init' process.
+
+config EVM_X509_PATH
+	string "EVM X509 certificate path"
+	depends on EVM_LOAD_X509
+	default "/etc/keys/x509_evm.der"
+	help
+	   This option defines X509 certificate path.
diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h
index 88bfe77efa1c..f5f12727771a 100644
--- a/security/integrity/evm/evm.h
+++ b/security/integrity/evm/evm.h
@@ -21,6 +21,9 @@
 
 #include "../integrity.h"
 
+#define EVM_INIT_HMAC	0x0001
+#define EVM_INIT_X509	0x0002
+
 extern int evm_initialized;
 extern char *evm_hmac;
 extern char *evm_hash;
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
index 461f8d891579..30b6b7d0429f 100644
--- a/security/integrity/evm/evm_crypto.c
+++ b/security/integrity/evm/evm_crypto.c
@@ -18,6 +18,7 @@
 #include <linux/module.h>
 #include <linux/crypto.h>
 #include <linux/xattr.h>
+#include <linux/evm.h>
 #include <keys/encrypted-type.h>
 #include <crypto/hash.h>
 #include "evm.h"
@@ -32,6 +33,44 @@ struct crypto_shash *hash_tfm;
 
 static DEFINE_MUTEX(mutex);
 
+#define EVM_SET_KEY_BUSY 0
+
+static unsigned long evm_set_key_flags;
+
+/**
+ * evm_set_key() - set EVM HMAC key from the kernel
+ * @key: pointer to a buffer with the key data
+ * @size: length of the key data
+ *
+ * This function allows setting the EVM HMAC key from the kernel
+ * without using the "encrypted" key subsystem keys. It can be used
+ * by the crypto HW kernel module which has its own way of managing
+ * keys.
+ *
+ * key length should be between 32 and 128 bytes long
+ */
+int evm_set_key(void *key, size_t keylen)
+{
+	int rc;
+
+	rc = -EBUSY;
+	if (test_and_set_bit(EVM_SET_KEY_BUSY, &evm_set_key_flags))
+		goto busy;
+	rc = -EINVAL;
+	if (keylen > MAX_KEY_SIZE)
+		goto inval;
+	memcpy(evmkey, key, keylen);
+	evm_initialized |= EVM_INIT_HMAC;
+	pr_info("key initialized\n");
+	return 0;
+inval:
+	clear_bit(EVM_SET_KEY_BUSY, &evm_set_key_flags);
+busy:
+	pr_err("key initialization failed\n");
+	return rc;
+}
+EXPORT_SYMBOL_GPL(evm_set_key);
+
 static struct shash_desc *init_desc(char type)
 {
 	long rc;
@@ -40,6 +79,10 @@ static struct shash_desc *init_desc(char type)
 	struct shash_desc *desc;
 
 	if (type == EVM_XATTR_HMAC) {
+		if (!(evm_initialized & EVM_INIT_HMAC)) {
+			pr_err("HMAC key is not set\n");
+			return ERR_PTR(-ENOKEY);
+		}
 		tfm = &hmac_tfm;
 		algo = evm_hmac;
 	} else {
@@ -240,7 +283,7 @@ int evm_init_key(void)
 {
 	struct key *evm_key;
 	struct encrypted_key_payload *ekp;
-	int rc = 0;
+	int rc;
 
 	evm_key = request_key(&key_type_encrypted, EVMKEY, NULL);
 	if (IS_ERR(evm_key))
@@ -248,12 +291,9 @@ int evm_init_key(void)
 
 	down_read(&evm_key->sem);
 	ekp = evm_key->payload.data[0];
-	if (ekp->decrypted_datalen > MAX_KEY_SIZE) {
-		rc = -EINVAL;
-		goto out;
-	}
-	memcpy(evmkey, ekp->decrypted_data, ekp->decrypted_datalen);
-out:
+
+	rc = evm_set_key(ekp->decrypted_data, ekp->decrypted_datalen);
+
 	/* burn the original key contents */
 	memset(ekp->decrypted_data, 0, ekp->decrypted_datalen);
 	up_read(&evm_key->sem);
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 1334e02ae8f4..e6ea9d4b1de9 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -23,6 +23,7 @@
 #include <linux/integrity.h>
 #include <linux/evm.h>
 #include <crypto/hash.h>
+#include <crypto/algapi.h>
 #include "evm.h"
 
 int evm_initialized;
@@ -148,7 +149,7 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
 				   xattr_value_len, calc.digest);
 		if (rc)
 			break;
-		rc = memcmp(xattr_data->digest, calc.digest,
+		rc = crypto_memneq(xattr_data->digest, calc.digest,
 			    sizeof(calc.digest));
 		if (rc)
 			rc = -EINVAL;
@@ -358,6 +359,15 @@ int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name)
 	return evm_protect_xattr(dentry, xattr_name, NULL, 0);
 }
 
+static void evm_reset_status(struct inode *inode)
+{
+	struct integrity_iint_cache *iint;
+
+	iint = integrity_iint_find(inode);
+	if (iint)
+		iint->evm_status = INTEGRITY_UNKNOWN;
+}
+
 /**
  * evm_inode_post_setxattr - update 'security.evm' to reflect the changes
  * @dentry: pointer to the affected dentry
@@ -378,6 +388,8 @@ void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
 				 && !posix_xattr_acl(xattr_name)))
 		return;
 
+	evm_reset_status(dentry->d_inode);
+
 	evm_update_evmxattr(dentry, xattr_name, xattr_value, xattr_value_len);
 }
 
@@ -396,6 +408,8 @@ void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
 	if (!evm_initialized || !evm_protected_xattr(xattr_name))
 		return;
 
+	evm_reset_status(dentry->d_inode);
+
 	evm_update_evmxattr(dentry, xattr_name, NULL, 0);
 }
 
@@ -472,21 +486,34 @@ out:
 }
 EXPORT_SYMBOL_GPL(evm_inode_init_security);
 
+#ifdef CONFIG_EVM_LOAD_X509
+void __init evm_load_x509(void)
+{
+	int rc;
+
+	rc = integrity_load_x509(INTEGRITY_KEYRING_EVM, CONFIG_EVM_X509_PATH);
+	if (!rc)
+		evm_initialized |= EVM_INIT_X509;
+}
+#endif
+
 static int __init init_evm(void)
 {
 	int error;
 
 	evm_init_config();
 
+	error = integrity_init_keyring(INTEGRITY_KEYRING_EVM);
+	if (error)
+		return error;
+
 	error = evm_init_secfs();
 	if (error < 0) {
 		pr_info("Error registering secfs\n");
-		goto err;
+		return error;
 	}
 
 	return 0;
-err:
-	return error;
 }
 
 /*
diff --git a/security/integrity/evm/evm_secfs.c b/security/integrity/evm/evm_secfs.c
index cf12a04717d3..c8dccd54d501 100644
--- a/security/integrity/evm/evm_secfs.c
+++ b/security/integrity/evm/evm_secfs.c
@@ -62,9 +62,9 @@ static ssize_t evm_write_key(struct file *file, const char __user *buf,
 			     size_t count, loff_t *ppos)
 {
 	char temp[80];
-	int i, error;
+	int i;
 
-	if (!capable(CAP_SYS_ADMIN) || evm_initialized)
+	if (!capable(CAP_SYS_ADMIN) || (evm_initialized & EVM_INIT_HMAC))
 		return -EPERM;
 
 	if (count >= sizeof(temp) || count == 0)
@@ -78,12 +78,8 @@ static ssize_t evm_write_key(struct file *file, const char __user *buf,
 	if ((sscanf(temp, "%d", &i) != 1) || (i != 1))
 		return -EINVAL;
 
-	error = evm_init_key();
-	if (!error) {
-		evm_initialized = 1;
-		pr_info("initialized\n");
-	} else
-		pr_err("initialization failed\n");
+	evm_init_key();
+
 	return count;
 }
 
diff --git a/security/integrity/iint.c b/security/integrity/iint.c
index 3d2f5b45c8cb..8f1ab37f2897 100644
--- a/security/integrity/iint.c
+++ b/security/integrity/iint.c
@@ -234,12 +234,13 @@ int __init integrity_read_file(const char *path, char **data)
 	}
 
 	rc = integrity_kernel_read(file, 0, buf, size);
-	if (rc < 0)
-		kfree(buf);
-	else if (rc != size)
-		rc = -EIO;
-	else
+	if (rc == size) {
 		*data = buf;
+	} else {
+		kfree(buf);
+		if (rc >= 0)
+			rc = -EIO;
+	}
 out:
 	fput(file);
 	return rc;
@@ -254,4 +255,5 @@ out:
 void __init integrity_load_keys(void)
 {
 	ima_load_x509();
+	evm_load_x509();
 }
diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
index df303346029b..e54a8a8dae94 100644
--- a/security/integrity/ima/Kconfig
+++ b/security/integrity/ima/Kconfig
@@ -107,6 +107,27 @@ config IMA_DEFAULT_HASH
 	default "sha512" if IMA_DEFAULT_HASH_SHA512
 	default "wp512" if IMA_DEFAULT_HASH_WP512
 
+config IMA_WRITE_POLICY
+	bool "Enable multiple writes to the IMA policy"
+	depends on IMA
+	default n
+	help
+	  IMA policy can now be updated multiple times.  The new rules get
+	  appended to the original policy.  Have in mind that the rules are
+	  scanned in FIFO order so be careful when you design and add new ones.
+
+	  If unsure, say N.
+
+config IMA_READ_POLICY
+	bool "Enable reading back the current IMA policy"
+	depends on IMA
+	default y if IMA_WRITE_POLICY
+	default n if !IMA_WRITE_POLICY
+	help
+	   It is often useful to be able to read back the IMA policy.  It is
+	   even more important after introducing CONFIG_IMA_WRITE_POLICY.
+	   This option allows the root user to see the current policy rules.
+
 config IMA_APPRAISE
 	bool "Appraise integrity measurements"
 	depends on IMA
@@ -123,14 +144,35 @@ config IMA_APPRAISE
 	  If unsure, say N.
 
 config IMA_TRUSTED_KEYRING
-	bool "Require all keys on the .ima keyring be signed"
+	bool "Require all keys on the .ima keyring be signed (deprecated)"
 	depends on IMA_APPRAISE && SYSTEM_TRUSTED_KEYRING
 	depends on INTEGRITY_ASYMMETRIC_KEYS
+	select INTEGRITY_TRUSTED_KEYRING
 	default y
 	help
 	   This option requires that all keys added to the .ima
 	   keyring be signed by a key on the system trusted keyring.
 
+	   This option is deprecated in favor of INTEGRITY_TRUSTED_KEYRING
+
+config IMA_MOK_KEYRING
+	bool "Create IMA machine owner keys (MOK) and blacklist keyrings"
+	depends on SYSTEM_TRUSTED_KEYRING
+	depends on IMA_TRUSTED_KEYRING
+	default n
+	help
+	   This option creates IMA MOK and blacklist keyrings.  IMA MOK is an
+	   intermediate keyring that sits between .system and .ima keyrings,
+	   effectively forming a simple CA hierarchy.  To successfully import a
+	   key into .ima_mok it must be signed by a key which CA is in .system
+	   keyring.  On turn any key that needs to go in .ima keyring must be
+	   signed by CA in either .system or .ima_mok keyrings. IMA MOK is empty
+	   at kernel boot.
+
+	   IMA blacklist keyring contains all revoked IMA keys.  It is consulted
+	   before any other keyring.  If the search is successful the requested
+	   operation is rejected and error is returned to the caller.
+
 config IMA_LOAD_X509
 	bool "Load X509 certificate onto the '.ima' trusted keyring"
 	depends on IMA_TRUSTED_KEYRING
diff --git a/security/integrity/ima/Makefile b/security/integrity/ima/Makefile
index d79263d2fdbf..a8539f9e060f 100644
--- a/security/integrity/ima/Makefile
+++ b/security/integrity/ima/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_IMA) += ima.o
 ima-y := ima_fs.o ima_queue.o ima_init.o ima_main.o ima_crypto.o ima_api.o \
 	 ima_policy.o ima_template.o ima_template_lib.o
 ima-$(CONFIG_IMA_APPRAISE) += ima_appraise.o
+obj-$(CONFIG_IMA_MOK_KEYRING) += ima_mok.o
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index e2a60c30df44..585af61ed399 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -166,6 +166,11 @@ void ima_update_policy(void);
 void ima_update_policy_flag(void);
 ssize_t ima_parse_add_rule(char *);
 void ima_delete_rules(void);
+int ima_check_policy(void);
+void *ima_policy_start(struct seq_file *m, loff_t *pos);
+void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos);
+void ima_policy_stop(struct seq_file *m, void *v);
+int ima_policy_show(struct seq_file *m, void *v);
 
 /* Appraise integrity measurements */
 #define IMA_APPRAISE_ENFORCE	0x01
@@ -250,17 +255,12 @@ static inline int security_filter_rule_match(u32 secid, u32 field, u32 op,
 {
 	return -EINVAL;
 }
-#endif /* CONFIG_IMA_LSM_RULES */
+#endif /* CONFIG_IMA_TRUSTED_KEYRING */
 
-#ifdef CONFIG_IMA_TRUSTED_KEYRING
-static inline int ima_init_keyring(const unsigned int id)
-{
-	return integrity_init_keyring(id);
-}
+#ifdef	CONFIG_IMA_READ_POLICY
+#define	POLICY_FILE_FLAGS	(S_IWUSR | S_IRUSR)
 #else
-static inline int ima_init_keyring(const unsigned int id)
-{
-	return 0;
-}
-#endif /* CONFIG_IMA_TRUSTED_KEYRING */
-#endif
+#define	POLICY_FILE_FLAGS	S_IWUSR
+#endif /* CONFIG_IMA_WRITE_POLICY */
+
+#endif /* __LINUX_IMA_H */
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index 816d175da79a..f355231997b4 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -25,6 +25,8 @@
 
 #include "ima.h"
 
+static DEFINE_MUTEX(ima_write_mutex);
+
 static int valid_policy = 1;
 #define TMPBUFLEN 12
 static ssize_t ima_show_htable_value(char __user *buf, size_t count,
@@ -259,7 +261,7 @@ static const struct file_operations ima_ascii_measurements_ops = {
 static ssize_t ima_write_policy(struct file *file, const char __user *buf,
 				size_t datalen, loff_t *ppos)
 {
-	char *data = NULL;
+	char *data;
 	ssize_t result;
 
 	if (datalen >= PAGE_SIZE)
@@ -279,13 +281,20 @@ static ssize_t ima_write_policy(struct file *file, const char __user *buf,
 
 	result = -EFAULT;
 	if (copy_from_user(data, buf, datalen))
-		goto out;
+		goto out_free;
 
+	result = mutex_lock_interruptible(&ima_write_mutex);
+	if (result < 0)
+		goto out_free;
 	result = ima_parse_add_rule(data);
+	mutex_unlock(&ima_write_mutex);
+
+out_free:
+	kfree(data);
 out:
 	if (result < 0)
 		valid_policy = 0;
-	kfree(data);
+
 	return result;
 }
 
@@ -302,14 +311,31 @@ enum ima_fs_flags {
 
 static unsigned long ima_fs_flags;
 
+#ifdef	CONFIG_IMA_READ_POLICY
+static const struct seq_operations ima_policy_seqops = {
+		.start = ima_policy_start,
+		.next = ima_policy_next,
+		.stop = ima_policy_stop,
+		.show = ima_policy_show,
+};
+#endif
+
 /*
  * ima_open_policy: sequentialize access to the policy file
  */
 static int ima_open_policy(struct inode *inode, struct file *filp)
 {
-	/* No point in being allowed to open it if you aren't going to write */
-	if (!(filp->f_flags & O_WRONLY))
+	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;
@@ -326,6 +352,14 @@ 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 0;
+
+	if (valid_policy && ima_check_policy() < 0) {
+		cause = "failed";
+		valid_policy = 0;
+	}
+
 	pr_info("IMA: policy update %s\n", cause);
 	integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, NULL,
 			    "policy_update", cause, !valid_policy, 0);
@@ -336,15 +370,21 @@ static int ima_release_policy(struct inode *inode, struct file *file)
 		clear_bit(IMA_FS_BUSY, &ima_fs_flags);
 		return 0;
 	}
+
 	ima_update_policy();
+#ifndef	CONFIG_IMA_WRITE_POLICY
 	securityfs_remove(ima_policy);
 	ima_policy = NULL;
+#else
+	clear_bit(IMA_FS_BUSY, &ima_fs_flags);
+#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,
 };
@@ -382,8 +422,7 @@ int __init ima_fs_init(void)
 	if (IS_ERR(violations))
 		goto out;
 
-	ima_policy = securityfs_create_file("policy",
-					    S_IWUSR,
+	ima_policy = securityfs_create_file("policy", POLICY_FILE_FLAGS,
 					    ima_dir, NULL,
 					    &ima_measure_policy_ops);
 	if (IS_ERR(ima_policy))
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
index e600cadd231c..bd79f254d204 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -116,7 +116,7 @@ int __init ima_init(void)
 	if (!ima_used_chip)
 		pr_info("No TPM chip found, activating TPM-bypass!\n");
 
-	rc = ima_init_keyring(INTEGRITY_KEYRING_IMA);
+	rc = integrity_init_keyring(INTEGRITY_KEYRING_IMA);
 	if (rc)
 		return rc;
 
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index c21f09bf8b99..9d96551d0196 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -121,7 +121,7 @@ static void ima_check_last_writer(struct integrity_iint_cache *iint,
 	if (!(mode & FMODE_WRITE))
 		return;
 
-	mutex_lock(&inode->i_mutex);
+	inode_lock(inode);
 	if (atomic_read(&inode->i_writecount) == 1) {
 		if ((iint->version != inode->i_version) ||
 		    (iint->flags & IMA_NEW_FILE)) {
@@ -130,7 +130,7 @@ static void ima_check_last_writer(struct integrity_iint_cache *iint,
 				ima_update_xattr(iint, file);
 		}
 	}
-	mutex_unlock(&inode->i_mutex);
+	inode_unlock(inode);
 }
 
 /**
@@ -186,7 +186,7 @@ static int process_measurement(struct file *file, int mask, int function,
 	if (action & IMA_FILE_APPRAISE)
 		function = FILE_CHECK;
 
-	mutex_lock(&inode->i_mutex);
+	inode_lock(inode);
 
 	if (action) {
 		iint = integrity_inode_get(inode);
@@ -250,7 +250,7 @@ out_free:
 	if (pathbuf)
 		__putname(pathbuf);
 out:
-	mutex_unlock(&inode->i_mutex);
+	inode_unlock(inode);
 	if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE))
 		return -EACCES;
 	return 0;
diff --git a/security/integrity/ima/ima_mok.c b/security/integrity/ima/ima_mok.c
new file mode 100644
index 000000000000..676885e4320e
--- /dev/null
+++ b/security/integrity/ima/ima_mok.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 Juniper Networks, Inc.
+ *
+ * Author:
+ * Petko Manolov <petko.manolov@konsulko.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ *
+ */
+
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/cred.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <keys/asymmetric-type.h>
+
+
+struct key *ima_mok_keyring;
+struct key *ima_blacklist_keyring;
+
+/*
+ * Allocate the IMA MOK and blacklist keyrings
+ */
+__init int ima_mok_init(void)
+{
+	pr_notice("Allocating IMA MOK and blacklist keyrings.\n");
+
+	ima_mok_keyring = keyring_alloc(".ima_mok",
+			      KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
+			      (KEY_POS_ALL & ~KEY_POS_SETATTR) |
+			      KEY_USR_VIEW | KEY_USR_READ |
+			      KEY_USR_WRITE | KEY_USR_SEARCH,
+			      KEY_ALLOC_NOT_IN_QUOTA, NULL);
+
+	ima_blacklist_keyring = keyring_alloc(".ima_blacklist",
+				KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
+				(KEY_POS_ALL & ~KEY_POS_SETATTR) |
+				KEY_USR_VIEW | KEY_USR_READ |
+				KEY_USR_WRITE | KEY_USR_SEARCH,
+				KEY_ALLOC_NOT_IN_QUOTA, NULL);
+
+	if (IS_ERR(ima_mok_keyring) || IS_ERR(ima_blacklist_keyring))
+		panic("Can't allocate IMA MOK or blacklist keyrings.");
+	set_bit(KEY_FLAG_TRUSTED_ONLY, &ima_mok_keyring->flags);
+
+	set_bit(KEY_FLAG_TRUSTED_ONLY, &ima_blacklist_keyring->flags);
+	set_bit(KEY_FLAG_KEEP, &ima_blacklist_keyring->flags);
+	return 0;
+}
+device_initcall(ima_mok_init);
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 3997e206f82d..0a3b781f18e5 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -16,7 +16,9 @@
 #include <linux/magic.h>
 #include <linux/parser.h>
 #include <linux/slab.h>
+#include <linux/rculist.h>
 #include <linux/genhd.h>
+#include <linux/seq_file.h>
 
 #include "ima.h"
 
@@ -38,6 +40,7 @@
 #define AUDIT		0x0040
 
 int ima_policy_flag;
+static int temp_ima_appraise;
 
 #define MAX_LSM_RULES 6
 enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE,
@@ -135,11 +138,11 @@ static struct ima_rule_entry default_appraise_rules[] = {
 
 static LIST_HEAD(ima_default_rules);
 static LIST_HEAD(ima_policy_rules);
+static LIST_HEAD(ima_temp_rules);
 static struct list_head *ima_rules;
 
-static DEFINE_MUTEX(ima_rules_mutex);
-
 static int ima_policy __initdata;
+
 static int __init default_measure_policy_setup(char *str)
 {
 	if (ima_policy)
@@ -171,21 +174,18 @@ static int __init default_appraise_policy_setup(char *str)
 __setup("ima_appraise_tcb", default_appraise_policy_setup);
 
 /*
- * Although the IMA policy does not change, the LSM policy can be
- * reloaded, leaving the IMA LSM based rules referring to the old,
- * stale LSM policy.
- *
- * Update the IMA LSM based rules to reflect the reloaded LSM policy.
- * We assume the rules still exist; and BUG_ON() if they don't.
+ * The LSM policy can be reloaded, leaving the IMA LSM based rules referring
+ * to the old, stale LSM policy.  Update the IMA LSM based rules to reflect
+ * the reloaded LSM policy.  We assume the rules still exist; and BUG_ON() if
+ * they don't.
  */
 static void ima_lsm_update_rules(void)
 {
-	struct ima_rule_entry *entry, *tmp;
+	struct ima_rule_entry *entry;
 	int result;
 	int i;
 
-	mutex_lock(&ima_rules_mutex);
-	list_for_each_entry_safe(entry, tmp, &ima_policy_rules, list) {
+	list_for_each_entry(entry, &ima_policy_rules, list) {
 		for (i = 0; i < MAX_LSM_RULES; i++) {
 			if (!entry->lsm[i].rule)
 				continue;
@@ -196,7 +196,6 @@ static void ima_lsm_update_rules(void)
 			BUG_ON(!entry->lsm[i].rule);
 		}
 	}
-	mutex_unlock(&ima_rules_mutex);
 }
 
 /**
@@ -319,9 +318,9 @@ static int get_subaction(struct ima_rule_entry *rule, int func)
  * Measure decision based on func/mask/fsmagic and LSM(subj/obj/type)
  * conditions.
  *
- * (There is no need for locking when walking the policy list,
- * as elements in the list are never deleted, nor does the list
- * change.)
+ * Since the IMA policy may be updated multiple times we need to lock the
+ * list when walking it.  Reads are many orders of magnitude more numerous
+ * than writes so ima_match_policy() is classical RCU candidate.
  */
 int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
 		     int flags)
@@ -329,7 +328,8 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
 	struct ima_rule_entry *entry;
 	int action = 0, actmask = flags | (flags << 1);
 
-	list_for_each_entry(entry, ima_rules, list) {
+	rcu_read_lock();
+	list_for_each_entry_rcu(entry, ima_rules, list) {
 
 		if (!(entry->action & actmask))
 			continue;
@@ -351,6 +351,7 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,
 		if (!actmask)
 			break;
 	}
+	rcu_read_unlock();
 
 	return action;
 }
@@ -365,12 +366,12 @@ void ima_update_policy_flag(void)
 {
 	struct ima_rule_entry *entry;
 
-	ima_policy_flag = 0;
 	list_for_each_entry(entry, ima_rules, list) {
 		if (entry->action & IMA_DO_MASK)
 			ima_policy_flag |= entry->action;
 	}
 
+	ima_appraise |= temp_ima_appraise;
 	if (!ima_appraise)
 		ima_policy_flag &= ~IMA_APPRAISE;
 }
@@ -415,16 +416,48 @@ void __init ima_init_policy(void)
 	ima_rules = &ima_default_rules;
 }
 
+/* Make sure we have a valid policy, at least containing some rules. */
+int ima_check_policy()
+{
+	if (list_empty(&ima_temp_rules))
+		return -EINVAL;
+	return 0;
+}
+
 /**
  * ima_update_policy - update default_rules with new measure rules
  *
  * Called on file .release to update the default rules with a complete new
- * policy.  Once updated, the policy is locked, no additional rules can be
- * added to the policy.
+ * policy.  What we do here is to splice ima_policy_rules and ima_temp_rules so
+ * they make a queue.  The policy may be updated multiple times and this is the
+ * RCU updater.
+ *
+ * Policy rules are never deleted so ima_policy_flag gets zeroed only once when
+ * we switch from the default policy to user defined.
  */
 void ima_update_policy(void)
 {
-	ima_rules = &ima_policy_rules;
+	struct list_head *first, *last, *policy;
+
+	/* append current policy with the new rules */
+	first = (&ima_temp_rules)->next;
+	last = (&ima_temp_rules)->prev;
+	policy = &ima_policy_rules;
+
+	synchronize_rcu();
+
+	last->next = policy;
+	rcu_assign_pointer(list_next_rcu(policy->prev), first);
+	first->prev = policy->prev;
+	policy->prev = last;
+
+	/* prepare for the next policy rules addition */
+	INIT_LIST_HEAD(&ima_temp_rules);
+
+	if (ima_rules != policy) {
+		ima_policy_flag = 0;
+		ima_rules = policy;
+	}
 	ima_update_policy_flag();
 }
 
@@ -436,8 +469,8 @@ enum {
 	Opt_obj_user, Opt_obj_role, Opt_obj_type,
 	Opt_subj_user, Opt_subj_role, Opt_subj_type,
 	Opt_func, Opt_mask, Opt_fsmagic,
-	Opt_uid, Opt_euid, Opt_fowner,
-	Opt_appraise_type, Opt_fsuuid, Opt_permit_directio
+	Opt_fsuuid, Opt_uid, Opt_euid, Opt_fowner,
+	Opt_appraise_type, Opt_permit_directio
 };
 
 static match_table_t policy_tokens = {
@@ -734,9 +767,9 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
 	if (!result && (entry->action == UNKNOWN))
 		result = -EINVAL;
 	else if (entry->func == MODULE_CHECK)
-		ima_appraise |= IMA_APPRAISE_MODULES;
+		temp_ima_appraise |= IMA_APPRAISE_MODULES;
 	else if (entry->func == FIRMWARE_CHECK)
-		ima_appraise |= IMA_APPRAISE_FIRMWARE;
+		temp_ima_appraise |= IMA_APPRAISE_FIRMWARE;
 	audit_log_format(ab, "res=%d", !result);
 	audit_log_end(ab);
 	return result;
@@ -746,7 +779,7 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
  * ima_parse_add_rule - add a rule to ima_policy_rules
  * @rule - ima measurement policy rule
  *
- * Uses a mutex to protect the policy list from multiple concurrent writers.
+ * Avoid locking by allowing just one writer at a time in ima_write_policy()
  * Returns the length of the rule parsed, an error code on failure
  */
 ssize_t ima_parse_add_rule(char *rule)
@@ -782,26 +815,230 @@ ssize_t ima_parse_add_rule(char *rule)
 		return result;
 	}
 
-	mutex_lock(&ima_rules_mutex);
-	list_add_tail(&entry->list, &ima_policy_rules);
-	mutex_unlock(&ima_rules_mutex);
+	list_add_tail(&entry->list, &ima_temp_rules);
 
 	return len;
 }
 
-/* ima_delete_rules called to cleanup invalid policy */
+/**
+ * ima_delete_rules() called to cleanup invalid in-flight policy.
+ * We don't need locking as we operate on the temp list, which is
+ * different from the active one.  There is also only one user of
+ * ima_delete_rules() at a time.
+ */
 void ima_delete_rules(void)
 {
 	struct ima_rule_entry *entry, *tmp;
 	int i;
 
-	mutex_lock(&ima_rules_mutex);
-	list_for_each_entry_safe(entry, tmp, &ima_policy_rules, list) {
+	temp_ima_appraise = 0;
+	list_for_each_entry_safe(entry, tmp, &ima_temp_rules, list) {
 		for (i = 0; i < MAX_LSM_RULES; i++)
 			kfree(entry->lsm[i].args_p);
 
 		list_del(&entry->list);
 		kfree(entry);
 	}
-	mutex_unlock(&ima_rules_mutex);
 }
+
+#ifdef	CONFIG_IMA_READ_POLICY
+enum {
+	mask_exec = 0, mask_write, mask_read, mask_append
+};
+
+static char *mask_tokens[] = {
+	"MAY_EXEC",
+	"MAY_WRITE",
+	"MAY_READ",
+	"MAY_APPEND"
+};
+
+enum {
+	func_file = 0, func_mmap, func_bprm,
+	func_module, func_firmware, func_post
+};
+
+static char *func_tokens[] = {
+	"FILE_CHECK",
+	"MMAP_CHECK",
+	"BPRM_CHECK",
+	"MODULE_CHECK",
+	"FIRMWARE_CHECK",
+	"POST_SETATTR"
+};
+
+void *ima_policy_start(struct seq_file *m, loff_t *pos)
+{
+	loff_t l = *pos;
+	struct ima_rule_entry *entry;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(entry, ima_rules, list) {
+		if (!l--) {
+			rcu_read_unlock();
+			return entry;
+		}
+	}
+	rcu_read_unlock();
+	return NULL;
+}
+
+void *ima_policy_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	struct ima_rule_entry *entry = v;
+
+	rcu_read_lock();
+	entry = list_entry_rcu(entry->list.next, struct ima_rule_entry, list);
+	rcu_read_unlock();
+	(*pos)++;
+
+	return (&entry->list == ima_rules) ? NULL : entry;
+}
+
+void ima_policy_stop(struct seq_file *m, void *v)
+{
+}
+
+#define pt(token)	policy_tokens[token + Opt_err].pattern
+#define mt(token)	mask_tokens[token]
+#define ft(token)	func_tokens[token]
+
+int ima_policy_show(struct seq_file *m, void *v)
+{
+	struct ima_rule_entry *entry = v;
+	int i = 0;
+	char tbuf[64] = {0,};
+
+	rcu_read_lock();
+
+	if (entry->action & MEASURE)
+		seq_puts(m, pt(Opt_measure));
+	if (entry->action & DONT_MEASURE)
+		seq_puts(m, pt(Opt_dont_measure));
+	if (entry->action & APPRAISE)
+		seq_puts(m, pt(Opt_appraise));
+	if (entry->action & DONT_APPRAISE)
+		seq_puts(m, pt(Opt_dont_appraise));
+	if (entry->action & AUDIT)
+		seq_puts(m, pt(Opt_audit));
+
+	seq_puts(m, " ");
+
+	if (entry->flags & IMA_FUNC) {
+		switch (entry->func) {
+		case FILE_CHECK:
+			seq_printf(m, pt(Opt_func), ft(func_file));
+			break;
+		case MMAP_CHECK:
+			seq_printf(m, pt(Opt_func), ft(func_mmap));
+			break;
+		case BPRM_CHECK:
+			seq_printf(m, pt(Opt_func), ft(func_bprm));
+			break;
+		case MODULE_CHECK:
+			seq_printf(m, pt(Opt_func), ft(func_module));
+			break;
+		case FIRMWARE_CHECK:
+			seq_printf(m, pt(Opt_func), ft(func_firmware));
+			break;
+		case POST_SETATTR:
+			seq_printf(m, pt(Opt_func), ft(func_post));
+			break;
+		default:
+			snprintf(tbuf, sizeof(tbuf), "%d", entry->func);
+			seq_printf(m, pt(Opt_func), tbuf);
+			break;
+		}
+		seq_puts(m, " ");
+	}
+
+	if (entry->flags & IMA_MASK) {
+		if (entry->mask & MAY_EXEC)
+			seq_printf(m, pt(Opt_mask), mt(mask_exec));
+		if (entry->mask & MAY_WRITE)
+			seq_printf(m, pt(Opt_mask), mt(mask_write));
+		if (entry->mask & MAY_READ)
+			seq_printf(m, pt(Opt_mask), mt(mask_read));
+		if (entry->mask & MAY_APPEND)
+			seq_printf(m, pt(Opt_mask), mt(mask_append));
+		seq_puts(m, " ");
+	}
+
+	if (entry->flags & IMA_FSMAGIC) {
+		snprintf(tbuf, sizeof(tbuf), "0x%lx", entry->fsmagic);
+		seq_printf(m, pt(Opt_fsmagic), tbuf);
+		seq_puts(m, " ");
+	}
+
+	if (entry->flags & IMA_FSUUID) {
+		seq_puts(m, "fsuuid=");
+		for (i = 0; i < ARRAY_SIZE(entry->fsuuid); ++i) {
+			switch (i) {
+			case 4:
+			case 6:
+			case 8:
+			case 10:
+				seq_puts(m, "-");
+			}
+			seq_printf(m, "%x", entry->fsuuid[i]);
+		}
+		seq_puts(m, " ");
+	}
+
+	if (entry->flags & IMA_UID) {
+		snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->uid));
+		seq_printf(m, pt(Opt_uid), tbuf);
+		seq_puts(m, " ");
+	}
+
+	if (entry->flags & IMA_EUID) {
+		snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->uid));
+		seq_printf(m, pt(Opt_euid), tbuf);
+		seq_puts(m, " ");
+	}
+
+	if (entry->flags & IMA_FOWNER) {
+		snprintf(tbuf, sizeof(tbuf), "%d", __kuid_val(entry->fowner));
+		seq_printf(m, pt(Opt_fowner), tbuf);
+		seq_puts(m, " ");
+	}
+
+	for (i = 0; i < MAX_LSM_RULES; i++) {
+		if (entry->lsm[i].rule) {
+			switch (i) {
+			case LSM_OBJ_USER:
+				seq_printf(m, pt(Opt_obj_user),
+					   (char *)entry->lsm[i].args_p);
+				break;
+			case LSM_OBJ_ROLE:
+				seq_printf(m, pt(Opt_obj_role),
+					   (char *)entry->lsm[i].args_p);
+				break;
+			case LSM_OBJ_TYPE:
+				seq_printf(m, pt(Opt_obj_type),
+					   (char *)entry->lsm[i].args_p);
+				break;
+			case LSM_SUBJ_USER:
+				seq_printf(m, pt(Opt_subj_user),
+					   (char *)entry->lsm[i].args_p);
+				break;
+			case LSM_SUBJ_ROLE:
+				seq_printf(m, pt(Opt_subj_role),
+					   (char *)entry->lsm[i].args_p);
+				break;
+			case LSM_SUBJ_TYPE:
+				seq_printf(m, pt(Opt_subj_type),
+					   (char *)entry->lsm[i].args_p);
+				break;
+			}
+		}
+	}
+	if (entry->flags & IMA_DIGSIG_REQUIRED)
+		seq_puts(m, "appraise_type=imasig ");
+	if (entry->flags & IMA_PERMIT_DIRECTIO)
+		seq_puts(m, "permit_directio ");
+	rcu_read_unlock();
+	seq_puts(m, "\n");
+	return 0;
+}
+#endif	/* CONFIG_IMA_READ_POLICY */
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 9c6168709d3b..5efe2ecc538d 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -125,8 +125,8 @@ int integrity_kernel_read(struct file *file, loff_t offset,
 int __init integrity_read_file(const char *path, char **data);
 
 #define INTEGRITY_KEYRING_EVM		0
-#define INTEGRITY_KEYRING_MODULE	1
-#define INTEGRITY_KEYRING_IMA		2
+#define INTEGRITY_KEYRING_IMA		1
+#define INTEGRITY_KEYRING_MODULE	2
 #define INTEGRITY_KEYRING_MAX		3
 
 #ifdef CONFIG_INTEGRITY_SIGNATURE
@@ -149,7 +149,6 @@ static inline int integrity_init_keyring(const unsigned int id)
 {
 	return 0;
 }
-
 #endif /* CONFIG_INTEGRITY_SIGNATURE */
 
 #ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
@@ -171,6 +170,14 @@ static inline void ima_load_x509(void)
 }
 #endif
 
+#ifdef CONFIG_EVM_LOAD_X509
+void __init evm_load_x509(void);
+#else
+static inline void evm_load_x509(void)
+{
+}
+#endif
+
 #ifdef CONFIG_INTEGRITY_AUDIT
 /* declarations */
 void integrity_audit_msg(int audit_msgno, struct inode *inode,
diff --git a/security/keys/Kconfig b/security/keys/Kconfig
index 72483b8f1be5..fe4d74e126a7 100644
--- a/security/keys/Kconfig
+++ b/security/keys/Kconfig
@@ -54,6 +54,7 @@ config TRUSTED_KEYS
 	select CRYPTO
 	select CRYPTO_HMAC
 	select CRYPTO_SHA1
+	select CRYPTO_HASH_INFO
 	help
 	  This option provides support for creating, sealing, and unsealing
 	  keys in the kernel. Trusted keys are random number symmetric keys,
diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c
index 927db9f35ad6..696ccfa08d10 100644
--- a/security/keys/encrypted-keys/encrypted.c
+++ b/security/keys/encrypted-keys/encrypted.c
@@ -845,6 +845,8 @@ static int encrypted_update(struct key *key, struct key_preparsed_payload *prep)
 	size_t datalen = prep->datalen;
 	int ret = 0;
 
+	if (test_bit(KEY_FLAG_NEGATIVE, &key->flags))
+		return -ENOKEY;
 	if (datalen <= 0 || datalen > 32767 || !prep->data)
 		return -EINVAL;
 
diff --git a/security/keys/key.c b/security/keys/key.c
index ab7997ded725..09ef276c4bdc 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -429,8 +429,12 @@ static int __key_instantiate_and_link(struct key *key,
 				awaken = 1;
 
 			/* and link it into the destination keyring */
-			if (keyring)
+			if (keyring) {
+				if (test_bit(KEY_FLAG_KEEP, &keyring->flags))
+					set_bit(KEY_FLAG_KEEP, &key->flags);
+
 				__key_link(key, _edit);
+			}
 
 			/* disable the authorisation key */
 			if (authkey)
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index fb111eafcb89..ed73c6c1c326 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -358,11 +358,14 @@ error:
  * and any links to the key will be automatically garbage collected after a
  * certain amount of time (/proc/sys/kernel/keys/gc_delay).
  *
+ * Keys with KEY_FLAG_KEEP set should not be revoked.
+ *
  * If successful, 0 is returned.
  */
 long keyctl_revoke_key(key_serial_t id)
 {
 	key_ref_t key_ref;
+	struct key *key;
 	long ret;
 
 	key_ref = lookup_user_key(id, 0, KEY_NEED_WRITE);
@@ -377,8 +380,12 @@ long keyctl_revoke_key(key_serial_t id)
 		}
 	}
 
-	key_revoke(key_ref_to_ptr(key_ref));
+	key = key_ref_to_ptr(key_ref);
 	ret = 0;
+	if (test_bit(KEY_FLAG_KEEP, &key->flags))
+		ret = -EPERM;
+	else
+		key_revoke(key);
 
 	key_ref_put(key_ref);
 error:
@@ -392,11 +399,14 @@ error:
  * The key and any links to the key will be automatically garbage collected
  * immediately.
  *
+ * Keys with KEY_FLAG_KEEP set should not be invalidated.
+ *
  * If successful, 0 is returned.
  */
 long keyctl_invalidate_key(key_serial_t id)
 {
 	key_ref_t key_ref;
+	struct key *key;
 	long ret;
 
 	kenter("%d", id);
@@ -420,8 +430,12 @@ long keyctl_invalidate_key(key_serial_t id)
 	}
 
 invalidate:
-	key_invalidate(key_ref_to_ptr(key_ref));
+	key = key_ref_to_ptr(key_ref);
 	ret = 0;
+	if (test_bit(KEY_FLAG_KEEP, &key->flags))
+		ret = -EPERM;
+	else
+		key_invalidate(key);
 error_put:
 	key_ref_put(key_ref);
 error:
@@ -433,12 +447,13 @@ error:
  * Clear the specified keyring, creating an empty process keyring if one of the
  * special keyring IDs is used.
  *
- * The keyring must grant the caller Write permission for this to work.  If
- * successful, 0 will be returned.
+ * The keyring must grant the caller Write permission and not have
+ * KEY_FLAG_KEEP set for this to work.  If successful, 0 will be returned.
  */
 long keyctl_keyring_clear(key_serial_t ringid)
 {
 	key_ref_t keyring_ref;
+	struct key *keyring;
 	long ret;
 
 	keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE);
@@ -460,7 +475,11 @@ long keyctl_keyring_clear(key_serial_t ringid)
 	}
 
 clear:
-	ret = keyring_clear(key_ref_to_ptr(keyring_ref));
+	keyring = key_ref_to_ptr(keyring_ref);
+	if (test_bit(KEY_FLAG_KEEP, &keyring->flags))
+		ret = -EPERM;
+	else
+		ret = keyring_clear(keyring);
 error_put:
 	key_ref_put(keyring_ref);
 error:
@@ -511,11 +530,14 @@ error:
  * itself need not grant the caller anything.  If the last link to a key is
  * removed then that key will be scheduled for destruction.
  *
+ * Keys or keyrings with KEY_FLAG_KEEP set should not be unlinked.
+ *
  * If successful, 0 will be returned.
  */
 long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid)
 {
 	key_ref_t keyring_ref, key_ref;
+	struct key *keyring, *key;
 	long ret;
 
 	keyring_ref = lookup_user_key(ringid, 0, KEY_NEED_WRITE);
@@ -530,7 +552,13 @@ long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid)
 		goto error2;
 	}
 
-	ret = key_unlink(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref));
+	keyring = key_ref_to_ptr(keyring_ref);
+	key = key_ref_to_ptr(key_ref);
+	if (test_bit(KEY_FLAG_KEEP, &keyring->flags) &&
+	    test_bit(KEY_FLAG_KEEP, &key->flags))
+		ret = -EPERM;
+	else
+		ret = key_unlink(keyring, key);
 
 	key_ref_put(key_ref);
 error2:
@@ -751,16 +779,16 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
 
 	/* the key is probably readable - now try to read it */
 can_read_key:
-	ret = key_validate(key);
-	if (ret == 0) {
-		ret = -EOPNOTSUPP;
-		if (key->type->read) {
-			/* read the data with the semaphore held (since we
-			 * might sleep) */
-			down_read(&key->sem);
+	ret = -EOPNOTSUPP;
+	if (key->type->read) {
+		/* Read the data with the semaphore held (since we might sleep)
+		 * to protect against the key being updated or revoked.
+		 */
+		down_read(&key->sem);
+		ret = key_validate(key);
+		if (ret == 0)
 			ret = key->type->read(key, buffer, buflen);
-			up_read(&key->sem);
-		}
+		up_read(&key->sem);
 	}
 
 error2:
@@ -1289,6 +1317,8 @@ error:
  * the current time.  The key and any links to the key will be automatically
  * garbage collected after the timeout expires.
  *
+ * Keys with KEY_FLAG_KEEP set should not be timed out.
+ *
  * If successful, 0 is returned.
  */
 long keyctl_set_timeout(key_serial_t id, unsigned timeout)
@@ -1320,10 +1350,13 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout)
 
 okay:
 	key = key_ref_to_ptr(key_ref);
-	key_set_timeout(key, timeout);
+	ret = 0;
+	if (test_bit(KEY_FLAG_KEEP, &key->flags))
+		ret = -EPERM;
+	else
+		key_set_timeout(key, timeout);
 	key_put(key);
 
-	ret = 0;
 error:
 	return ret;
 }
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index a3f85d2a00bb..e6d50172872f 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -794,6 +794,7 @@ long join_session_keyring(const char *name)
 		ret = PTR_ERR(keyring);
 		goto error2;
 	} else if (keyring == new->session_keyring) {
+		key_put(keyring);
 		ret = 0;
 		goto error2;
 	}
diff --git a/security/keys/trusted.c b/security/keys/trusted.c
index 903dace648a1..0dcab20cdacd 100644
--- a/security/keys/trusted.c
+++ b/security/keys/trusted.c
@@ -11,6 +11,7 @@
  * See Documentation/security/keys-trusted-encrypted.txt
  */
 
+#include <crypto/hash_info.h>
 #include <linux/uaccess.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -710,7 +711,10 @@ enum {
 	Opt_err = -1,
 	Opt_new, Opt_load, Opt_update,
 	Opt_keyhandle, Opt_keyauth, Opt_blobauth,
-	Opt_pcrinfo, Opt_pcrlock, Opt_migratable
+	Opt_pcrinfo, Opt_pcrlock, Opt_migratable,
+	Opt_hash,
+	Opt_policydigest,
+	Opt_policyhandle,
 };
 
 static const match_table_t key_tokens = {
@@ -723,6 +727,9 @@ static const match_table_t key_tokens = {
 	{Opt_pcrinfo, "pcrinfo=%s"},
 	{Opt_pcrlock, "pcrlock=%s"},
 	{Opt_migratable, "migratable=%s"},
+	{Opt_hash, "hash=%s"},
+	{Opt_policydigest, "policydigest=%s"},
+	{Opt_policyhandle, "policyhandle=%s"},
 	{Opt_err, NULL}
 };
 
@@ -736,11 +743,23 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
 	int res;
 	unsigned long handle;
 	unsigned long lock;
+	unsigned long token_mask = 0;
+	int i;
+	int tpm2;
+
+	tpm2 = tpm_is_tpm2(TPM_ANY_NUM);
+	if (tpm2 < 0)
+		return tpm2;
+
+	opt->hash = tpm2 ? HASH_ALGO_SHA256 : HASH_ALGO_SHA1;
+	opt->digest_len = hash_digest_size[opt->hash];
 
 	while ((p = strsep(&c, " \t"))) {
 		if (*p == '\0' || *p == ' ' || *p == '\t')
 			continue;
 		token = match_token(p, key_tokens, args);
+		if (test_and_set_bit(token, &token_mask))
+			return -EINVAL;
 
 		switch (token) {
 		case Opt_pcrinfo:
@@ -787,6 +806,41 @@ static int getoptions(char *c, struct trusted_key_payload *pay,
 				return -EINVAL;
 			opt->pcrlock = lock;
 			break;
+		case Opt_hash:
+			if (test_bit(Opt_policydigest, &token_mask))
+				return -EINVAL;
+			for (i = 0; i < HASH_ALGO__LAST; i++) {
+				if (!strcmp(args[0].from, hash_algo_name[i])) {
+					opt->hash = i;
+					opt->digest_len =
+						hash_digest_size[opt->hash];
+					break;
+				}
+			}
+			if (i == HASH_ALGO__LAST)
+				return -EINVAL;
+			if  (!tpm2 && i != HASH_ALGO_SHA1) {
+				pr_info("trusted_key: TPM 1.x only supports SHA-1.\n");
+				return -EINVAL;
+			}
+			break;
+		case Opt_policydigest:
+			if (!tpm2 ||
+			    strlen(args[0].from) != (2 * opt->digest_len))
+				return -EINVAL;
+			res = hex2bin(opt->policydigest, args[0].from,
+				      opt->digest_len);
+			if (res < 0)
+				return -EINVAL;
+			break;
+		case Opt_policyhandle:
+			if (!tpm2)
+				return -EINVAL;
+			res = kstrtoul(args[0].from, 16, &handle);
+			if (res < 0)
+				return -EINVAL;
+			opt->policyhandle = handle;
+			break;
 		default:
 			return -EINVAL;
 		}
@@ -1007,13 +1061,16 @@ static void trusted_rcu_free(struct rcu_head *rcu)
  */
 static int trusted_update(struct key *key, struct key_preparsed_payload *prep)
 {
-	struct trusted_key_payload *p = key->payload.data[0];
+	struct trusted_key_payload *p;
 	struct trusted_key_payload *new_p;
 	struct trusted_key_options *new_o;
 	size_t datalen = prep->datalen;
 	char *datablob;
 	int ret = 0;
 
+	if (test_bit(KEY_FLAG_NEGATIVE, &key->flags))
+		return -ENOKEY;
+	p = key->payload.data[0];
 	if (!p->migratable)
 		return -EPERM;
 	if (datalen <= 0 || datalen > 32767 || !prep->data)
diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c
index 28cb30f80256..8705d79b2c6f 100644
--- a/security/keys/user_defined.c
+++ b/security/keys/user_defined.c
@@ -120,7 +120,10 @@ int user_update(struct key *key, struct key_preparsed_payload *prep)
 
 	if (ret == 0) {
 		/* attach the new data, displacing the old */
-		zap = key->payload.data[0];
+		if (!test_bit(KEY_FLAG_NEGATIVE, &key->flags))
+			zap = key->payload.data[0];
+		else
+			zap = NULL;
 		rcu_assign_keypointer(key, upayload);
 		key->expiry = 0;
 	}
diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c
index 2bbb41822d8e..8495b9368190 100644
--- a/security/selinux/nlmsgtab.c
+++ b/security/selinux/nlmsgtab.c
@@ -83,6 +83,7 @@ static struct nlmsg_perm nlmsg_tcpdiag_perms[] =
 	{ TCPDIAG_GETSOCK,	NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
 	{ DCCPDIAG_GETSOCK,	NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
 	{ SOCK_DIAG_BY_FAMILY,	NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
+	{ SOCK_DESTROY,		NETLINK_TCPDIAG_SOCKET__NLMSG_WRITE },
 };
 
 static struct nlmsg_perm nlmsg_xfrm_perms[] =
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 0dc407dac3b9..1b1fd27de632 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -148,23 +148,16 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
 	ssize_t length;
 	int new_value;
 
-	length = -ENOMEM;
 	if (count >= PAGE_SIZE)
-		goto out;
+		return -ENOMEM;
 
 	/* No partial writes. */
-	length = -EINVAL;
 	if (*ppos != 0)
-		goto out;
-
-	length = -ENOMEM;
-	page = (char *)get_zeroed_page(GFP_KERNEL);
-	if (!page)
-		goto out;
+		return -EINVAL;
 
-	length = -EFAULT;
-	if (copy_from_user(page, buf, count))
-		goto out;
+	page = memdup_user_nul(buf, count);
+	if (IS_ERR(page))
+		return PTR_ERR(page);
 
 	length = -EINVAL;
 	if (sscanf(page, "%d", &new_value) != 1)
@@ -187,7 +180,7 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
 	}
 	length = count;
 out:
-	free_page((unsigned long) page);
+	kfree(page);
 	return length;
 }
 #else
@@ -276,27 +269,20 @@ static ssize_t sel_write_disable(struct file *file, const char __user *buf,
 				 size_t count, loff_t *ppos)
 
 {
-	char *page = NULL;
+	char *page;
 	ssize_t length;
 	int new_value;
 
-	length = -ENOMEM;
 	if (count >= PAGE_SIZE)
-		goto out;
+		return -ENOMEM;
 
 	/* No partial writes. */
-	length = -EINVAL;
 	if (*ppos != 0)
-		goto out;
-
-	length = -ENOMEM;
-	page = (char *)get_zeroed_page(GFP_KERNEL);
-	if (!page)
-		goto out;
+		return -EINVAL;
 
-	length = -EFAULT;
-	if (copy_from_user(page, buf, count))
-		goto out;
+	page = memdup_user_nul(buf, count);
+	if (IS_ERR(page))
+		return PTR_ERR(page);
 
 	length = -EINVAL;
 	if (sscanf(page, "%d", &new_value) != 1)
@@ -314,7 +300,7 @@ static ssize_t sel_write_disable(struct file *file, const char __user *buf,
 
 	length = count;
 out:
-	free_page((unsigned long) page);
+	kfree(page);
 	return length;
 }
 #else
@@ -394,9 +380,9 @@ static int sel_open_policy(struct inode *inode, struct file *filp)
 		goto err;
 
 	if (i_size_read(inode) != security_policydb_len()) {
-		mutex_lock(&inode->i_mutex);
+		inode_lock(inode);
 		i_size_write(inode, security_policydb_len());
-		mutex_unlock(&inode->i_mutex);
+		inode_unlock(inode);
 	}
 
 	rc = security_read_policy(&plm->data, &plm->len);
@@ -612,31 +598,24 @@ static ssize_t sel_read_checkreqprot(struct file *filp, char __user *buf,
 static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
 				      size_t count, loff_t *ppos)
 {
-	char *page = NULL;
+	char *page;
 	ssize_t length;
 	unsigned int new_value;
 
 	length = task_has_security(current, SECURITY__SETCHECKREQPROT);
 	if (length)
-		goto out;
+		return length;
 
-	length = -ENOMEM;
 	if (count >= PAGE_SIZE)
-		goto out;
+		return -ENOMEM;
 
 	/* No partial writes. */
-	length = -EINVAL;
 	if (*ppos != 0)
-		goto out;
-
-	length = -ENOMEM;
-	page = (char *)get_zeroed_page(GFP_KERNEL);
-	if (!page)
-		goto out;
+		return -EINVAL;
 
-	length = -EFAULT;
-	if (copy_from_user(page, buf, count))
-		goto out;
+	page = memdup_user_nul(buf, count);
+	if (IS_ERR(page))
+		return PTR_ERR(page);
 
 	length = -EINVAL;
 	if (sscanf(page, "%u", &new_value) != 1)
@@ -645,7 +624,7 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
 	selinux_checkreqprot = new_value ? 1 : 0;
 	length = count;
 out:
-	free_page((unsigned long) page);
+	kfree(page);
 	return length;
 }
 static const struct file_operations sel_checkreqprot_ops = {
@@ -1178,14 +1157,12 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
 	if (*ppos != 0)
 		goto out;
 
-	length = -ENOMEM;
-	page = (char *)get_zeroed_page(GFP_KERNEL);
-	if (!page)
-		goto out;
-
-	length = -EFAULT;
-	if (copy_from_user(page, buf, count))
+	page = memdup_user_nul(buf, count);
+	if (IS_ERR(page)) {
+		length = PTR_ERR(page);
+		page = NULL;
 		goto out;
+	}
 
 	length = -EINVAL;
 	if (sscanf(page, "%d", &new_value) != 1)
@@ -1199,7 +1176,7 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
 
 out:
 	mutex_unlock(&sel_mutex);
-	free_page((unsigned long) page);
+	kfree(page);
 	return length;
 }
 
@@ -1232,14 +1209,12 @@ static ssize_t sel_commit_bools_write(struct file *filep,
 	if (*ppos != 0)
 		goto out;
 
-	length = -ENOMEM;
-	page = (char *)get_zeroed_page(GFP_KERNEL);
-	if (!page)
-		goto out;
-
-	length = -EFAULT;
-	if (copy_from_user(page, buf, count))
+	page = memdup_user_nul(buf, count);
+	if (IS_ERR(page)) {
+		length = PTR_ERR(page);
+		page = NULL;
 		goto out;
+	}
 
 	length = -EINVAL;
 	if (sscanf(page, "%d", &new_value) != 1)
@@ -1254,7 +1229,7 @@ static ssize_t sel_commit_bools_write(struct file *filep,
 
 out:
 	mutex_unlock(&sel_mutex);
-	free_page((unsigned long) page);
+	kfree(page);
 	return length;
 }
 
@@ -1370,31 +1345,24 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file,
 					     size_t count, loff_t *ppos)
 
 {
-	char *page = NULL;
+	char *page;
 	ssize_t ret;
 	int new_value;
 
 	ret = task_has_security(current, SECURITY__SETSECPARAM);
 	if (ret)
-		goto out;
+		return ret;
 
-	ret = -ENOMEM;
 	if (count >= PAGE_SIZE)
-		goto out;
+		return -ENOMEM;
 
 	/* No partial writes. */
-	ret = -EINVAL;
 	if (*ppos != 0)
-		goto out;
-
-	ret = -ENOMEM;
-	page = (char *)get_zeroed_page(GFP_KERNEL);
-	if (!page)
-		goto out;
+		return -EINVAL;
 
-	ret = -EFAULT;
-	if (copy_from_user(page, buf, count))
-		goto out;
+	page = memdup_user_nul(buf, count);
+	if (IS_ERR(page))
+		return PTR_ERR(page);
 
 	ret = -EINVAL;
 	if (sscanf(page, "%u", &new_value) != 1)
@@ -1404,7 +1372,7 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file,
 
 	ret = count;
 out:
-	free_page((unsigned long)page);
+	kfree(page);
 	return ret;
 }
 
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c
index 18643bf9894d..456e1a9bcfde 100644
--- a/security/selinux/ss/conditional.c
+++ b/security/selinux/ss/conditional.c
@@ -638,7 +638,7 @@ void cond_compute_av(struct avtab *ctab, struct avtab_key *key,
 {
 	struct avtab_node *node;
 
-	if (!ctab || !key || !avd || !xperms)
+	if (!ctab || !key || !avd)
 		return;
 
 	for (node = avtab_search_node(ctab, key); node;
@@ -657,7 +657,7 @@ void cond_compute_av(struct avtab *ctab, struct avtab_key *key,
 		if ((u16)(AVTAB_AUDITALLOW|AVTAB_ENABLED) ==
 		    (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED)))
 			avd->auditallow |= node->datum.u.data;
-		if ((node->key.specified & AVTAB_ENABLED) &&
+		if (xperms && (node->key.specified & AVTAB_ENABLED) &&
 				(node->key.specified & AVTAB_XPERMS))
 			services_compute_xperms_drivers(xperms, node);
 	}
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index ac7436f1bc2b..2d6e9bdea398 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -398,12 +398,10 @@ static int smk_copy_relabel(struct list_head *nhead, struct list_head *ohead,
  */
 static inline unsigned int smk_ptrace_mode(unsigned int mode)
 {
-	switch (mode) {
-	case PTRACE_MODE_READ:
-		return MAY_READ;
-	case PTRACE_MODE_ATTACH:
+	if (mode & PTRACE_MODE_ATTACH)
 		return MAY_READWRITE;
-	}
+	if (mode & PTRACE_MODE_READ)
+		return MAY_READ;
 
 	return 0;
 }
@@ -1519,8 +1517,6 @@ static int smack_inode_getsecurity(struct inode *inode,
  * @inode: the object
  * @buffer: where they go
  * @buffer_size: size of buffer
- *
- * Returns 0 on success, -EINVAL otherwise
  */
 static int smack_inode_listsecurity(struct inode *inode, char *buffer,
 				    size_t buffer_size)
@@ -1860,12 +1856,34 @@ static int smack_file_receive(struct file *file)
 	int may = 0;
 	struct smk_audit_info ad;
 	struct inode *inode = file_inode(file);
+	struct socket *sock;
+	struct task_smack *tsp;
+	struct socket_smack *ssp;
 
 	if (unlikely(IS_PRIVATE(inode)))
 		return 0;
 
 	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
 	smk_ad_setfield_u_fs_path(&ad, file->f_path);
+
+	if (S_ISSOCK(inode->i_mode)) {
+		sock = SOCKET_I(inode);
+		ssp = sock->sk->sk_security;
+		tsp = current_security();
+		/*
+		 * If the receiving process can't write to the
+		 * passed socket or if the passed socket can't
+		 * write to the receiving process don't accept
+		 * the passed socket.
+		 */
+		rc = smk_access(tsp->smk_task, ssp->smk_out, MAY_WRITE, &ad);
+		rc = smk_bu_file(file, may, rc);
+		if (rc < 0)
+			return rc;
+		rc = smk_access(ssp->smk_in, tsp->smk_task, MAY_WRITE, &ad);
+		rc = smk_bu_file(file, may, rc);
+		return rc;
+	}
 	/*
 	 * This code relies on bitmasks.
 	 */
@@ -3758,7 +3776,7 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
 	if (sip == NULL)
 		return 0;
 
-	switch (sip->sin_family) {
+	switch (sock->sk->sk_family) {
 	case AF_INET:
 		rc = smack_netlabel_send(sock->sk, sip);
 		break;
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 94bd9e41c9ec..e249a66db533 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -497,14 +497,9 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
 		}
 	}
 
-	data = kmalloc(count + 1, GFP_KERNEL);
-	if (data == NULL)
-		return -ENOMEM;
-
-	if (copy_from_user(data, buf, count) != 0) {
-		rc = -EFAULT;
-		goto out;
-	}
+	data = memdup_user_nul(buf, count);
+	if (IS_ERR(data))
+		return PTR_ERR(data);
 
 	/*
 	 * In case of parsing only part of user buf,
@@ -884,16 +879,10 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf,
 	    (count < SMK_CIPSOMIN || count > SMK_CIPSOMAX))
 		return -EINVAL;
 
-	data = kzalloc(count + 1, GFP_KERNEL);
-	if (data == NULL)
-		return -ENOMEM;
-
-	if (copy_from_user(data, buf, count) != 0) {
-		rc = -EFAULT;
-		goto unlockedout;
-	}
+	data = memdup_user_nul(buf, count);
+	if (IS_ERR(data))
+		return PTR_ERR(data);
 
-	data[count] = '\0';
 	rule = data;
 	/*
 	 * Only allow one writer at a time. Writes should be
@@ -946,7 +935,6 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf,
 
 out:
 	mutex_unlock(&smack_cipso_lock);
-unlockedout:
 	kfree(data);
 	return rc;
 }
@@ -1187,14 +1175,9 @@ static ssize_t smk_write_net4addr(struct file *file, const char __user *buf,
 	if (count < SMK_NETLBLADDRMIN)
 		return -EINVAL;
 
-	data = kzalloc(count + 1, GFP_KERNEL);
-	if (data == NULL)
-		return -ENOMEM;
-
-	if (copy_from_user(data, buf, count) != 0) {
-		rc = -EFAULT;
-		goto free_data_out;
-	}
+	data = memdup_user_nul(buf, count);
+	if (IS_ERR(data))
+		return PTR_ERR(data);
 
 	smack = kzalloc(count + 1, GFP_KERNEL);
 	if (smack == NULL) {
@@ -1202,8 +1185,6 @@ static ssize_t smk_write_net4addr(struct file *file, const char __user *buf,
 		goto free_data_out;
 	}
 
-	data[count] = '\0';
-
 	rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd/%u %s",
 		&host[0], &host[1], &host[2], &host[3], &masks, smack);
 	if (rc != 6) {
@@ -1454,14 +1435,9 @@ static ssize_t smk_write_net6addr(struct file *file, const char __user *buf,
 	if (count < SMK_NETLBLADDRMIN)
 		return -EINVAL;
 
-	data = kzalloc(count + 1, GFP_KERNEL);
-	if (data == NULL)
-		return -ENOMEM;
-
-	if (copy_from_user(data, buf, count) != 0) {
-		rc = -EFAULT;
-		goto free_data_out;
-	}
+	data = memdup_user_nul(buf, count);
+	if (IS_ERR(data))
+		return PTR_ERR(data);
 
 	smack = kzalloc(count + 1, GFP_KERNEL);
 	if (smack == NULL) {
@@ -1469,8 +1445,6 @@ static ssize_t smk_write_net6addr(struct file *file, const char __user *buf,
 		goto free_data_out;
 	}
 
-	data[count] = '\0';
-
 	i = sscanf(data, "%x:%x:%x:%x:%x:%x:%x:%x/%u %s",
 			&scanned[0], &scanned[1], &scanned[2], &scanned[3],
 			&scanned[4], &scanned[5], &scanned[6], &scanned[7],
@@ -1865,14 +1839,9 @@ static ssize_t smk_write_ambient(struct file *file, const char __user *buf,
 	if (!smack_privileged(CAP_MAC_ADMIN))
 		return -EPERM;
 
-	data = kzalloc(count + 1, GFP_KERNEL);
-	if (data == NULL)
-		return -ENOMEM;
-
-	if (copy_from_user(data, buf, count) != 0) {
-		rc = -EFAULT;
-		goto out;
-	}
+	data = memdup_user_nul(buf, count);
+	if (IS_ERR(data))
+		return PTR_ERR(data);
 
 	skp = smk_import_entry(data, count);
 	if (IS_ERR(skp)) {
@@ -2041,14 +2010,9 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
 	if (!smack_privileged(CAP_MAC_ADMIN))
 		return -EPERM;
 
-	data = kzalloc(count + 1, GFP_KERNEL);
-	if (data == NULL)
-		return -ENOMEM;
-
-	if (copy_from_user(data, buf, count) != 0) {
-		kfree(data);
-		return -EFAULT;
-	}
+	data = memdup_user_nul(buf, count);
+	if (IS_ERR(data))
+		return PTR_ERR(data);
 
 	rc = smk_parse_label_list(data, &list_tmp);
 	kfree(data);
@@ -2133,14 +2097,9 @@ static ssize_t smk_write_unconfined(struct file *file, const char __user *buf,
 	if (!smack_privileged(CAP_MAC_ADMIN))
 		return -EPERM;
 
-	data = kzalloc(count + 1, GFP_KERNEL);
-	if (data == NULL)
-		return -ENOMEM;
-
-	if (copy_from_user(data, buf, count) != 0) {
-		rc = -EFAULT;
-		goto freeout;
-	}
+	data = memdup_user_nul(buf, count);
+	if (IS_ERR(data))
+		return PTR_ERR(data);
 
 	/*
 	 * Clear the smack_unconfined on invalid label errors. This means
@@ -2696,19 +2655,15 @@ static ssize_t smk_write_syslog(struct file *file, const char __user *buf,
 	if (!smack_privileged(CAP_MAC_ADMIN))
 		return -EPERM;
 
-	data = kzalloc(count + 1, GFP_KERNEL);
-	if (data == NULL)
-		return -ENOMEM;
+	data = memdup_user_nul(buf, count);
+	if (IS_ERR(data))
+		return PTR_ERR(data);
 
-	if (copy_from_user(data, buf, count) != 0)
-		rc = -EFAULT;
-	else {
-		skp = smk_import_entry(data, count);
-		if (IS_ERR(skp))
-			rc = PTR_ERR(skp);
-		else
-			smack_syslog_label = skp;
-	}
+	skp = smk_import_entry(data, count);
+	if (IS_ERR(skp))
+		rc = PTR_ERR(skp);
+	else
+		smack_syslog_label = skp;
 
 	kfree(data);
 	return rc;
@@ -2798,14 +2753,9 @@ static ssize_t smk_write_relabel_self(struct file *file, const char __user *buf,
 	if (*ppos != 0)
 		return -EINVAL;
 
-	data = kzalloc(count + 1, GFP_KERNEL);
-	if (data == NULL)
-		return -ENOMEM;
-
-	if (copy_from_user(data, buf, count) != 0) {
-		kfree(data);
-		return -EFAULT;
-	}
+	data = memdup_user_nul(buf, count);
+	if (IS_ERR(data))
+		return PTR_ERR(data);
 
 	rc = smk_parse_label_list(data, &list_tmp);
 	kfree(data);
diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c
index 179a955b319d..06ab41b1ff28 100644
--- a/security/tomoyo/securityfs_if.c
+++ b/security/tomoyo/securityfs_if.c
@@ -43,13 +43,9 @@ static ssize_t tomoyo_write_self(struct file *file, const char __user *buf,
 	int error;
 	if (!count || count >= TOMOYO_EXEC_TMPSIZE - 10)
 		return -ENOMEM;
-	data = kzalloc(count + 1, GFP_NOFS);
-	if (!data)
-		return -ENOMEM;
-	if (copy_from_user(data, buf, count)) {
-		error = -EFAULT;
-		goto out;
-	}
+	data = memdup_user_nul(buf, count);
+	if (IS_ERR(data))
+		return PTR_ERR(data);
 	tomoyo_normalize_line(data);
 	if (tomoyo_correct_domain(data)) {
 		const int idx = tomoyo_read_lock();
@@ -87,7 +83,6 @@ static ssize_t tomoyo_write_self(struct file *file, const char __user *buf,
 		tomoyo_read_unlock(idx);
 	} else
 		error = -EINVAL;
-out:
 	kfree(data);
 	return error ? error : count;
 }
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c
index d3c19c970a06..cb6ed10816d4 100644
--- a/security/yama/yama_lsm.c
+++ b/security/yama/yama_lsm.c
@@ -281,7 +281,7 @@ static int yama_ptrace_access_check(struct task_struct *child,
 	int rc = 0;
 
 	/* require ptrace target be a child of ptracer on attach */
-	if (mode == PTRACE_MODE_ATTACH) {
+	if (mode & PTRACE_MODE_ATTACH) {
 		switch (ptrace_scope) {
 		case YAMA_SCOPE_DISABLED:
 			/* No additional restrictions. */
@@ -307,7 +307,7 @@ static int yama_ptrace_access_check(struct task_struct *child,
 		}
 	}
 
-	if (rc) {
+	if (rc && (mode & PTRACE_MODE_NOAUDIT) == 0) {
 		printk_ratelimited(KERN_NOTICE
 			"ptrace of pid %d was attempted by: %s (pid %d)\n",
 			child->pid, current->comm, current->pid);