--- /dev/null
+From 23567fd052a9abb6d67fe8e7a9ccdd9800a540f2 Mon Sep 17 00:00:00 2001
+From: Yevgeny Pats <yevgeny@perception-point.io>
+Date: Tue, 19 Jan 2016 22:09:04 +0000
+Subject: KEYS: Fix keyring ref leak in join_session_keyring()
+
+From: Yevgeny Pats <yevgeny@perception-point.io>
+
+commit 23567fd052a9abb6d67fe8e7a9ccdd9800a540f2 upstream.
+
+This fixes CVE-2016-0728.
+
+If a thread is asked to join as a session keyring the keyring that's already
+set as its session, we leak a keyring reference.
+
+This can be tested with the following program:
+
+ #include <stddef.h>
+ #include <stdio.h>
+ #include <sys/types.h>
+ #include <keyutils.h>
+
+ int main(int argc, const char *argv[])
+ {
+ int i = 0;
+ key_serial_t serial;
+
+ serial = keyctl(KEYCTL_JOIN_SESSION_KEYRING,
+ "leaked-keyring");
+ if (serial < 0) {
+ perror("keyctl");
+ return -1;
+ }
+
+ if (keyctl(KEYCTL_SETPERM, serial,
+ KEY_POS_ALL | KEY_USR_ALL) < 0) {
+ perror("keyctl");
+ return -1;
+ }
+
+ for (i = 0; i < 100; i++) {
+ serial = keyctl(KEYCTL_JOIN_SESSION_KEYRING,
+ "leaked-keyring");
+ if (serial < 0) {
+ perror("keyctl");
+ return -1;
+ }
+ }
+
+ return 0;
+ }
+
+If, after the program has run, there something like the following line in
+/proc/keys:
+
+3f3d898f I--Q--- 100 perm 3f3f0000 0 0 keyring leaked-keyring: empty
+
+with a usage count of 100 * the number of times the program has been run,
+then the kernel is malfunctioning. If leaked-keyring has zero usages or
+has been garbage collected, then the problem is fixed.
+
+Reported-by: Yevgeny Pats <yevgeny@perception-point.io>
+Signed-off-by: David Howells <dhowells@redhat.com>
+Acked-by: Don Zickus <dzickus@redhat.com>
+Acked-by: Prarit Bhargava <prarit@redhat.com>
+Acked-by: Jarod Wilson <jarod@redhat.com>
+Signed-off-by: James Morris <james.l.morris@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ security/keys/process_keys.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/security/keys/process_keys.c
++++ b/security/keys/process_keys.c
+@@ -794,6 +794,7 @@ long join_session_keyring(const char *na
+ ret = PTR_ERR(keyring);
+ goto error2;
+ } else if (keyring == new->session_keyring) {
++ key_put(keyring);
+ ret = 0;
+ goto error2;
+ }
--- /dev/null
+From d3600bcf9d64d88dc1d189a754dcfab960ce751f Mon Sep 17 00:00:00 2001
+From: Mimi Zohar <zohar@linux.vnet.ibm.com>
+Date: Tue, 10 Nov 2015 08:34:46 -0500
+Subject: KEYS: prevent keys from being removed from specified keyrings
+
+From: Mimi Zohar <zohar@linux.vnet.ibm.com>
+
+commit d3600bcf9d64d88dc1d189a754dcfab960ce751f upstream.
+
+Userspace should not be allowed to remove keys from certain keyrings
+(eg. blacklist), though the keys themselves can expire.
+
+This patch defines a new key flag named KEY_FLAG_KEEP to prevent
+userspace from being able to unlink, revoke, invalidate or timed
+out a key on a keyring. When this flag is set on the keyring, all
+keys subsequently added are flagged.
+
+In addition, when this flag is set, the keyring itself can not be
+cleared.
+
+Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
+Cc: David Howells <dhowells@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ include/linux/key.h | 1
+ security/keys/key.c | 6 ++++-
+ security/keys/keyctl.c | 56 ++++++++++++++++++++++++++++++++++++++++---------
+ 3 files changed, 52 insertions(+), 11 deletions(-)
+
+--- a/include/linux/key.h
++++ b/include/linux/key.h
+@@ -177,6 +177,7 @@ struct key {
+ #define KEY_FLAG_TRUSTED_ONLY 9 /* set if keyring only accepts links to trusted keys */
+ #define KEY_FLAG_BUILTIN 10 /* set if key is builtin */
+ #define KEY_FLAG_ROOT_CAN_INVAL 11 /* set if key can be invalidated by root without permission */
++#define KEY_FLAG_KEEP 12 /* set if key should not be removed */
+
+ /* the key type and key description string
+ * - the desc is used to match a key against search criteria
+--- a/security/keys/key.c
++++ b/security/keys/key.c
+@@ -429,8 +429,12 @@ static int __key_instantiate_and_link(st
+ 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)
+--- 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,13 @@ long keyctl_revoke_key(key_serial_t id)
+ }
+ }
+
+- key_revoke(key_ref_to_ptr(key_ref));
+- ret = 0;
++ key = key_ref_to_ptr(key_ref);
++ if (test_bit(KEY_FLAG_KEEP, &key->flags))
++ return -EPERM;
++ else {
++ key_revoke(key);
++ ret = 0;
++ }
+
+ key_ref_put(key_ref);
+ error:
+@@ -392,11 +400,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 +431,13 @@ long keyctl_invalidate_key(key_serial_t
+ }
+
+ invalidate:
+- key_invalidate(key_ref_to_ptr(key_ref));
+- ret = 0;
++ key = key_ref_to_ptr(key_ref);
++ if (test_bit(KEY_FLAG_KEEP, &key->flags))
++ ret = -EPERM;
++ else {
++ key_invalidate(key);
++ ret = 0;
++ }
+ error_put:
+ key_ref_put(key_ref);
+ error:
+@@ -433,12 +449,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 +477,11 @@ long keyctl_keyring_clear(key_serial_t r
+ }
+
+ 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 +532,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 +554,13 @@ long keyctl_keyring_unlink(key_serial_t
+ 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:
+@@ -1289,6 +1319,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 +1352,14 @@ long keyctl_set_timeout(key_serial_t id,
+
+ okay:
+ key = key_ref_to_ptr(key_ref);
+- key_set_timeout(key, timeout);
++ if (test_bit(KEY_FLAG_KEEP, &key->flags))
++ ret = -EPERM;
++ else {
++ key_set_timeout(key, timeout);
++ ret = 0;
++ }
+ key_put(key);
+
+- ret = 0;
+ error:
+ return ret;
+ }
--- /dev/null
+From 1d6d167c2efcfe9539d9cffb1a1be9c92e39c2c0 Mon Sep 17 00:00:00 2001
+From: Mimi Zohar <zohar@linux.vnet.ibm.com>
+Date: Thu, 7 Jan 2016 07:46:36 -0500
+Subject: KEYS: refcount bug fix
+
+From: Mimi Zohar <zohar@linux.vnet.ibm.com>
+
+commit 1d6d167c2efcfe9539d9cffb1a1be9c92e39c2c0 upstream.
+
+This patch fixes the key_ref leak, removes the unnecessary KEY_FLAG_KEEP
+test before setting the flag, and cleans up the if/then brackets style
+introduced in commit:
+d3600bc KEYS: prevent keys from being removed from specified keyrings
+
+Reported-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
+Acked-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ security/keys/key.c | 3 +--
+ security/keys/keyctl.c | 17 +++++++----------
+ 2 files changed, 8 insertions(+), 12 deletions(-)
+
+--- a/security/keys/key.c
++++ b/security/keys/key.c
+@@ -430,8 +430,7 @@ static int __key_instantiate_and_link(st
+
+ /* and link it into the destination keyring */
+ if (keyring) {
+- if (test_bit(KEY_FLAG_KEEP, &keyring->flags))
+- set_bit(KEY_FLAG_KEEP, &key->flags);
++ set_bit(KEY_FLAG_KEEP, &key->flags);
+
+ __key_link(key, _edit);
+ }
+--- a/security/keys/keyctl.c
++++ b/security/keys/keyctl.c
+@@ -381,12 +381,11 @@ long keyctl_revoke_key(key_serial_t id)
+ }
+
+ key = key_ref_to_ptr(key_ref);
++ ret = 0;
+ if (test_bit(KEY_FLAG_KEEP, &key->flags))
+- return -EPERM;
+- else {
++ ret = -EPERM;
++ else
+ key_revoke(key);
+- ret = 0;
+- }
+
+ key_ref_put(key_ref);
+ error:
+@@ -432,12 +431,11 @@ long keyctl_invalidate_key(key_serial_t
+
+ invalidate:
+ key = key_ref_to_ptr(key_ref);
++ ret = 0;
+ if (test_bit(KEY_FLAG_KEEP, &key->flags))
+ ret = -EPERM;
+- else {
++ else
+ key_invalidate(key);
+- ret = 0;
+- }
+ error_put:
+ key_ref_put(key_ref);
+ error:
+@@ -1352,12 +1350,11 @@ long keyctl_set_timeout(key_serial_t id,
+
+ okay:
+ key = key_ref_to_ptr(key_ref);
++ ret = 0;
+ if (test_bit(KEY_FLAG_KEEP, &key->flags))
+ ret = -EPERM;
+- else {
++ else
+ key_set_timeout(key, timeout);
+- ret = 0;
+- }
+ key_put(key);
+
+ error: