Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1626441 > unrolled thread
| Started by | David Howells <dhowells@redhat.com> |
|---|---|
| First post | 2017-04-19 18:20 +0200 |
| Last post | 2017-04-19 18:20 +0200 |
| Articles | 3 — 1 participant |
Back to article view | Back to linux.kernel
[PATCH 0/3] KEYS: Fixes David Howells <dhowells@redhat.com> - 2017-04-19 18:20 +0200
[PATCH 3/3] KEYS: fix keyctl_set_reqkey_keyring() to not leak thread keyrings David Howells <dhowells@redhat.com> - 2017-04-19 18:20 +0200
[PATCH 2/3] KEYS: Change the name of the dead type to ".dead" to prevent user access David Howells <dhowells@redhat.com> - 2017-04-19 18:20 +0200
| From | David Howells <dhowells@redhat.com> |
|---|---|
| Date | 2017-04-19 18:20 +0200 |
| Subject | [PATCH 0/3] KEYS: Fixes |
| Message-ID | <ty0uJ-5Cb-9@gated-at.bofh.it> |
Hi James,
Can you pass these patches onto Linus, please?
(1) Disallow keyrings whose name begins with a '.' to be joined
[CVE-2016-9604].
(2) Change the name of the dead type to ".dead" to prevent user access
[CVE-2017-6951].
(3) Fix keyctl_set_reqkey_keyring() to not leak thread keyrings
[CVE-2017-7472].
The patches can be found here also:
http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=keys-fixes
Tagged thusly:
git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs.git
keys-fixes-20170419
David
---
David Howells (2):
KEYS: Disallow keyrings beginning with '.' to be joined as session keyrings
KEYS: Change the name of the dead type to ".dead" to prevent user access
Eric Biggers (1):
KEYS: fix keyctl_set_reqkey_keyring() to not leak thread keyrings
security/keys/gc.c | 2 +-
security/keys/keyctl.c | 20 +++++++++++--------
security/keys/process_keys.c | 44 ++++++++++++++++++++++++++----------------
3 files changed, 39 insertions(+), 27 deletions(-)
[toc] | [next] | [standalone]
| From | David Howells <dhowells@redhat.com> |
|---|---|
| Date | 2017-04-19 18:20 +0200 |
| Subject | [PATCH 3/3] KEYS: fix keyctl_set_reqkey_keyring() to not leak thread keyrings |
| Message-ID | <ty0uL-5Cb-37@gated-at.bofh.it> |
| In reply to | #1626441 |
From: Eric Biggers <ebiggers@google.com>
This fixes CVE-2017-7472.
Running the following program as an unprivileged user exhausts kernel
memory by leaking thread keyrings:
#include <keyutils.h>
int main()
{
for (;;)
keyctl_set_reqkey_keyring(KEY_REQKEY_DEFL_THREAD_KEYRING);
}
Fix it by only creating a new thread keyring if there wasn't one before.
To make things more consistent, make install_thread_keyring_to_cred()
and install_process_keyring_to_cred() both return 0 if the corresponding
keyring is already present.
Fixes: d84f4f992cbd ("CRED: Inaugurate COW credentials")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: David Howells <dhowells@redhat.com>
---
security/keys/keyctl.c | 11 ++++-------
security/keys/process_keys.c | 44 ++++++++++++++++++++++++++----------------
2 files changed, 31 insertions(+), 24 deletions(-)
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index ab082a2e8fdd..4ad3212adebe 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -1258,8 +1258,8 @@ long keyctl_reject_key(key_serial_t id, unsigned timeout, unsigned error,
* Read or set the default keyring in which request_key() will cache keys and
* return the old setting.
*
- * If a process keyring is specified then this will be created if it doesn't
- * yet exist. The old setting will be returned if successful.
+ * If a thread or process keyring is specified then it will be created if it
+ * doesn't yet exist. The old setting will be returned if successful.
*/
long keyctl_set_reqkey_keyring(int reqkey_defl)
{
@@ -1284,11 +1284,8 @@ long keyctl_set_reqkey_keyring(int reqkey_defl)
case KEY_REQKEY_DEFL_PROCESS_KEYRING:
ret = install_process_keyring_to_cred(new);
- if (ret < 0) {
- if (ret != -EEXIST)
- goto error;
- ret = 0;
- }
+ if (ret < 0)
+ goto error;
goto set;
case KEY_REQKEY_DEFL_DEFAULT:
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index b6fdd22205b1..9139b18fc863 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -128,13 +128,18 @@ int install_user_keyrings(void)
}
/*
- * Install a fresh thread keyring directly to new credentials. This keyring is
- * allowed to overrun the quota.
+ * Install a thread keyring to the given credentials struct if it didn't have
+ * one already. This is allowed to overrun the quota.
+ *
+ * Return: 0 if a thread keyring is now present; -errno on failure.
*/
int install_thread_keyring_to_cred(struct cred *new)
{
struct key *keyring;
+ if (new->thread_keyring)
+ return 0;
+
keyring = keyring_alloc("_tid", new->uid, new->gid, new,
KEY_POS_ALL | KEY_USR_VIEW,
KEY_ALLOC_QUOTA_OVERRUN,
@@ -147,7 +152,9 @@ int install_thread_keyring_to_cred(struct cred *new)
}
/*
- * Install a fresh thread keyring, discarding the old one.
+ * Install a thread keyring to the current task if it didn't have one already.
+ *
+ * Return: 0 if a thread keyring is now present; -errno on failure.
*/
static int install_thread_keyring(void)
{
@@ -158,8 +165,6 @@ static int install_thread_keyring(void)
if (!new)
return -ENOMEM;
- BUG_ON(new->thread_keyring);
-
ret = install_thread_keyring_to_cred(new);
if (ret < 0) {
abort_creds(new);
@@ -170,17 +175,17 @@ static int install_thread_keyring(void)
}
/*
- * Install a process keyring directly to a credentials struct.
+ * Install a process keyring to the given credentials struct if it didn't have
+ * one already. This is allowed to overrun the quota.
*
- * Returns -EEXIST if there was already a process keyring, 0 if one installed,
- * and other value on any other error
+ * Return: 0 if a process keyring is now present; -errno on failure.
*/
int install_process_keyring_to_cred(struct cred *new)
{
struct key *keyring;
if (new->process_keyring)
- return -EEXIST;
+ return 0;
keyring = keyring_alloc("_pid", new->uid, new->gid, new,
KEY_POS_ALL | KEY_USR_VIEW,
@@ -194,11 +199,9 @@ int install_process_keyring_to_cred(struct cred *new)
}
/*
- * Make sure a process keyring is installed for the current process. The
- * existing process keyring is not replaced.
+ * Install a process keyring to the current task if it didn't have one already.
*
- * Returns 0 if there is a process keyring by the end of this function, some
- * error otherwise.
+ * Return: 0 if a process keyring is now present; -errno on failure.
*/
static int install_process_keyring(void)
{
@@ -212,14 +215,18 @@ static int install_process_keyring(void)
ret = install_process_keyring_to_cred(new);
if (ret < 0) {
abort_creds(new);
- return ret != -EEXIST ? ret : 0;
+ return ret;
}
return commit_creds(new);
}
/*
- * Install a session keyring directly to a credentials struct.
+ * Install the given keyring as the session keyring of the given credentials
+ * struct, replacing the existing one if any. If the given keyring is NULL,
+ * then install a new anonymous session keyring.
+ *
+ * Return: 0 on success; -errno on failure.
*/
int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
{
@@ -254,8 +261,11 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
}
/*
- * Install a session keyring, discarding the old one. If a keyring is not
- * supplied, an empty one is invented.
+ * Install the given keyring as the session keyring of the current task,
+ * replacing the existing one if any. If the given keyring is NULL, then
+ * install a new anonymous session keyring.
+ *
+ * Return: 0 on success; -errno on failure.
*/
static int install_session_keyring(struct key *keyring)
{
[toc] | [prev] | [next] | [standalone]
| From | David Howells <dhowells@redhat.com> |
|---|---|
| Date | 2017-04-19 18:20 +0200 |
| Subject | [PATCH 2/3] KEYS: Change the name of the dead type to ".dead" to prevent user access |
| Message-ID | <ty0uL-5Cb-49@gated-at.bofh.it> |
| In reply to | #1626441 |
This fixes CVE-2017-6951.
Userspace should not be able to do things with the "dead" key type as it
doesn't have some of the helper functions set upon it that the kernel
needs. Attempting to use it may cause the kernel to crash.
Fix this by changing the name of the type to ".dead" so that it's rejected
up front on userspace syscalls by key_get_type_from_user().
Though this doesn't seem to affect recent kernels, it does affect older
ones, certainly those prior to:
commit c06cfb08b88dfbe13be44a69ae2fdc3a7c902d81
Author: David Howells <dhowells@redhat.com>
Date: Tue Sep 16 17:36:06 2014 +0100
KEYS: Remove key_type::match in favour of overriding default by match_preparse
which went in before 3.18-rc1.
Signed-off-by: David Howells <dhowells@redhat.com>
cc: stable@vger.kernel.org
---
security/keys/gc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/security/keys/gc.c b/security/keys/gc.c
index addf060399e0..9cb4fe4478a1 100644
--- a/security/keys/gc.c
+++ b/security/keys/gc.c
@@ -46,7 +46,7 @@ static unsigned long key_gc_flags;
* immediately unlinked.
*/
struct key_type key_type_dead = {
- .name = "dead",
+ .name = ".dead",
};
/*
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web