]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.1-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 20 Jan 2016 16:59:13 +0000 (08:59 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 20 Jan 2016 16:59:13 +0000 (08:59 -0800)
added patches:
keys-fix-crash-when-attempt-to-garbage-collect-an-uninstantiated-keyring.patch
keys-fix-keyring-ref-leak-in-join_session_keyring.patch
keys-fix-race-between-key-destruction-and-finding-a-keyring-by-name.patch
keys-fix-race-between-read-and-revoke.patch
keys-prevent-keys-from-being-removed-from-specified-keyrings.patch
keys-refcount-bug-fix.patch

queue-4.1/keys-fix-crash-when-attempt-to-garbage-collect-an-uninstantiated-keyring.patch [new file with mode: 0644]
queue-4.1/keys-fix-keyring-ref-leak-in-join_session_keyring.patch [new file with mode: 0644]
queue-4.1/keys-fix-race-between-key-destruction-and-finding-a-keyring-by-name.patch [new file with mode: 0644]
queue-4.1/keys-fix-race-between-read-and-revoke.patch [new file with mode: 0644]
queue-4.1/keys-prevent-keys-from-being-removed-from-specified-keyrings.patch [new file with mode: 0644]
queue-4.1/keys-refcount-bug-fix.patch [new file with mode: 0644]
queue-4.1/series

diff --git a/queue-4.1/keys-fix-crash-when-attempt-to-garbage-collect-an-uninstantiated-keyring.patch b/queue-4.1/keys-fix-crash-when-attempt-to-garbage-collect-an-uninstantiated-keyring.patch
new file mode 100644 (file)
index 0000000..4b0625a
--- /dev/null
@@ -0,0 +1,79 @@
+From f05819df10d7b09f6d1eb6f8534a8f68e5a4fe61 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Thu, 15 Oct 2015 17:21:37 +0100
+Subject: KEYS: Fix crash when attempt to garbage collect an uninstantiated keyring
+
+From: David Howells <dhowells@redhat.com>
+
+commit f05819df10d7b09f6d1eb6f8534a8f68e5a4fe61 upstream.
+
+The following sequence of commands:
+
+    i=`keyctl add user a a @s`
+    keyctl request2 keyring foo bar @t
+    keyctl unlink $i @s
+
+tries to invoke an upcall to instantiate a keyring if one doesn't already
+exist by that name within the user's keyring set.  However, if the upcall
+fails, the code sets keyring->type_data.reject_error to -ENOKEY or some
+other error code.  When the key is garbage collected, the key destroy
+function is called unconditionally and keyring_destroy() uses list_empty()
+on keyring->type_data.link - which is in a union with reject_error.
+Subsequently, the kernel tries to unlink the keyring from the keyring names
+list - which oopses like this:
+
+       BUG: unable to handle kernel paging request at 00000000ffffff8a
+       IP: [<ffffffff8126e051>] keyring_destroy+0x3d/0x88
+       ...
+       Workqueue: events key_garbage_collector
+       ...
+       RIP: 0010:[<ffffffff8126e051>] keyring_destroy+0x3d/0x88
+       RSP: 0018:ffff88003e2f3d30  EFLAGS: 00010203
+       RAX: 00000000ffffff82 RBX: ffff88003bf1a900 RCX: 0000000000000000
+       RDX: 0000000000000000 RSI: 000000003bfc6901 RDI: ffffffff81a73a40
+       RBP: ffff88003e2f3d38 R08: 0000000000000152 R09: 0000000000000000
+       R10: ffff88003e2f3c18 R11: 000000000000865b R12: ffff88003bf1a900
+       R13: 0000000000000000 R14: ffff88003bf1a908 R15: ffff88003e2f4000
+       ...
+       CR2: 00000000ffffff8a CR3: 000000003e3ec000 CR4: 00000000000006f0
+       ...
+       Call Trace:
+        [<ffffffff8126c756>] key_gc_unused_keys.constprop.1+0x5d/0x10f
+        [<ffffffff8126ca71>] key_garbage_collector+0x1fa/0x351
+        [<ffffffff8105ec9b>] process_one_work+0x28e/0x547
+        [<ffffffff8105fd17>] worker_thread+0x26e/0x361
+        [<ffffffff8105faa9>] ? rescuer_thread+0x2a8/0x2a8
+        [<ffffffff810648ad>] kthread+0xf3/0xfb
+        [<ffffffff810647ba>] ? kthread_create_on_node+0x1c2/0x1c2
+        [<ffffffff815f2ccf>] ret_from_fork+0x3f/0x70
+        [<ffffffff810647ba>] ? kthread_create_on_node+0x1c2/0x1c2
+
+Note the value in RAX.  This is a 32-bit representation of -ENOKEY.
+
+The solution is to only call ->destroy() if the key was successfully
+instantiated.
+
+Reported-by: Dmitry Vyukov <dvyukov@google.com>
+Signed-off-by: David Howells <dhowells@redhat.com>
+Tested-by: Dmitry Vyukov <dvyukov@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ security/keys/gc.c |    6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/security/keys/gc.c
++++ b/security/keys/gc.c
+@@ -134,8 +134,10 @@ static noinline void key_gc_unused_keys(
+               kdebug("- %u", key->serial);
+               key_check(key);
+-              /* Throw away the key data */
+-              if (key->type->destroy)
++              /* Throw away the key data if the key is instantiated */
++              if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags) &&
++                  !test_bit(KEY_FLAG_NEGATIVE, &key->flags) &&
++                  key->type->destroy)
+                       key->type->destroy(key);
+               security_key_free(key);
diff --git a/queue-4.1/keys-fix-keyring-ref-leak-in-join_session_keyring.patch b/queue-4.1/keys-fix-keyring-ref-leak-in-join_session_keyring.patch
new file mode 100644 (file)
index 0000000..6285e4c
--- /dev/null
@@ -0,0 +1,82 @@
+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;
+       }
diff --git a/queue-4.1/keys-fix-race-between-key-destruction-and-finding-a-keyring-by-name.patch b/queue-4.1/keys-fix-race-between-key-destruction-and-finding-a-keyring-by-name.patch
new file mode 100644 (file)
index 0000000..49fc01a
--- /dev/null
@@ -0,0 +1,53 @@
+From 94c4554ba07adbdde396748ee7ae01e86cf2d8d7 Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Fri, 25 Sep 2015 16:30:08 +0100
+Subject: KEYS: Fix race between key destruction and finding a keyring by name
+
+From: David Howells <dhowells@redhat.com>
+
+commit 94c4554ba07adbdde396748ee7ae01e86cf2d8d7 upstream.
+
+There appears to be a race between:
+
+ (1) key_gc_unused_keys() which frees key->security and then calls
+     keyring_destroy() to unlink the name from the name list
+
+ (2) find_keyring_by_name() which calls key_permission(), thus accessing
+     key->security, on a key before checking to see whether the key usage is 0
+     (ie. the key is dead and might be cleaned up).
+
+Fix this by calling ->destroy() before cleaning up the core key data -
+including key->security.
+
+Reported-by: Petr Matousek <pmatouse@redhat.com>
+Signed-off-by: David Howells <dhowells@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ security/keys/gc.c |    8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/security/keys/gc.c
++++ b/security/keys/gc.c
+@@ -134,6 +134,10 @@ static noinline void key_gc_unused_keys(
+               kdebug("- %u", key->serial);
+               key_check(key);
++              /* Throw away the key data */
++              if (key->type->destroy)
++                      key->type->destroy(key);
++
+               security_key_free(key);
+               /* deal with the user's key tracking and quota */
+@@ -148,10 +152,6 @@ static noinline void key_gc_unused_keys(
+               if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
+                       atomic_dec(&key->user->nikeys);
+-              /* now throw away the key memory */
+-              if (key->type->destroy)
+-                      key->type->destroy(key);
+-
+               key_user_put(key->user);
+               kfree(key->description);
diff --git a/queue-4.1/keys-fix-race-between-read-and-revoke.patch b/queue-4.1/keys-fix-race-between-read-and-revoke.patch
new file mode 100644 (file)
index 0000000..c7cbb7c
--- /dev/null
@@ -0,0 +1,115 @@
+From b4a1b4f5047e4f54e194681125c74c0aa64d637d Mon Sep 17 00:00:00 2001
+From: David Howells <dhowells@redhat.com>
+Date: Fri, 18 Dec 2015 01:34:26 +0000
+Subject: KEYS: Fix race between read and revoke
+
+From: David Howells <dhowells@redhat.com>
+
+commit b4a1b4f5047e4f54e194681125c74c0aa64d637d upstream.
+
+This fixes CVE-2015-7550.
+
+There's a race between keyctl_read() and keyctl_revoke().  If the revoke
+happens between keyctl_read() checking the validity of a key and the key's
+semaphore being taken, then the key type read method will see a revoked key.
+
+This causes a problem for the user-defined key type because it assumes in
+its read method that there will always be a payload in a non-revoked key
+and doesn't check for a NULL pointer.
+
+Fix this by making keyctl_read() check the validity of a key after taking
+semaphore instead of before.
+
+I think the bug was introduced with the original keyrings code.
+
+This was discovered by a multithreaded test program generated by syzkaller
+(http://github.com/google/syzkaller).  Here's a cleaned up version:
+
+       #include <sys/types.h>
+       #include <keyutils.h>
+       #include <pthread.h>
+       void *thr0(void *arg)
+       {
+               key_serial_t key = (unsigned long)arg;
+               keyctl_revoke(key);
+               return 0;
+       }
+       void *thr1(void *arg)
+       {
+               key_serial_t key = (unsigned long)arg;
+               char buffer[16];
+               keyctl_read(key, buffer, 16);
+               return 0;
+       }
+       int main()
+       {
+               key_serial_t key = add_key("user", "%", "foo", 3, KEY_SPEC_USER_KEYRING);
+               pthread_t th[5];
+               pthread_create(&th[0], 0, thr0, (void *)(unsigned long)key);
+               pthread_create(&th[1], 0, thr1, (void *)(unsigned long)key);
+               pthread_create(&th[2], 0, thr0, (void *)(unsigned long)key);
+               pthread_create(&th[3], 0, thr1, (void *)(unsigned long)key);
+               pthread_join(th[0], 0);
+               pthread_join(th[1], 0);
+               pthread_join(th[2], 0);
+               pthread_join(th[3], 0);
+               return 0;
+       }
+
+Build as:
+
+       cc -o keyctl-race keyctl-race.c -lkeyutils -lpthread
+
+Run as:
+
+       while keyctl-race; do :; done
+
+as it may need several iterations to crash the kernel.  The crash can be
+summarised as:
+
+       BUG: unable to handle kernel NULL pointer dereference at 0000000000000010
+       IP: [<ffffffff81279b08>] user_read+0x56/0xa3
+       ...
+       Call Trace:
+        [<ffffffff81276aa9>] keyctl_read_key+0xb6/0xd7
+        [<ffffffff81277815>] SyS_keyctl+0x83/0xe0
+        [<ffffffff815dbb97>] entry_SYSCALL_64_fastpath+0x12/0x6f
+
+Reported-by: Dmitry Vyukov <dvyukov@google.com>
+Signed-off-by: David Howells <dhowells@redhat.com>
+Tested-by: Dmitry Vyukov <dvyukov@google.com>
+Signed-off-by: James Morris <james.l.morris@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ security/keys/keyctl.c |   18 +++++++++---------
+ 1 file changed, 9 insertions(+), 9 deletions(-)
+
+--- a/security/keys/keyctl.c
++++ b/security/keys/keyctl.c
+@@ -757,16 +757,16 @@ long keyctl_read_key(key_serial_t keyid,
+       /* 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:
diff --git a/queue-4.1/keys-prevent-keys-from-being-removed-from-specified-keyrings.patch b/queue-4.1/keys-prevent-keys-from-being-removed-from-specified-keyrings.patch
new file mode 100644 (file)
index 0000000..4a08cea
--- /dev/null
@@ -0,0 +1,205 @@
+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
+@@ -172,6 +172,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
+@@ -364,11 +364,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);
+@@ -383,8 +386,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:
+@@ -398,11 +406,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);
+@@ -426,8 +437,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:
+@@ -439,12 +455,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);
+@@ -466,7 +483,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:
+@@ -517,11 +538,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);
+@@ -536,7 +560,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:
+@@ -1295,6 +1325,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)
+@@ -1326,10 +1358,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;
+ }
diff --git a/queue-4.1/keys-refcount-bug-fix.patch b/queue-4.1/keys-refcount-bug-fix.patch
new file mode 100644 (file)
index 0000000..c5ed3f3
--- /dev/null
@@ -0,0 +1,84 @@
+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
+@@ -387,12 +387,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:
+@@ -438,12 +437,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:
+@@ -1358,12 +1356,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:
index c0f8671aa0cfb10eeb584b727f050ad7815d2746..37cf5d57fd288249fa1db5416f733d69662a9660 100644 (file)
@@ -37,3 +37,9 @@ fou-clean-up-socket-with-kfree_rcu.patch
 af_unix-revert-lock_interruptible-in-stream-receive-code.patch
 tcp-restore-fastopen-with-no-data-in-syn-packet.patch
 rhashtable-fix-walker-list-corruption.patch
+keys-fix-race-between-key-destruction-and-finding-a-keyring-by-name.patch
+keys-fix-crash-when-attempt-to-garbage-collect-an-uninstantiated-keyring.patch
+keys-fix-race-between-read-and-revoke.patch
+keys-prevent-keys-from-being-removed-from-specified-keyrings.patch
+keys-refcount-bug-fix.patch
+keys-fix-keyring-ref-leak-in-join_session_keyring.patch