All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2 for 3.18/4.1] KEYS: Don't permit request_key() to construct a new keyring
@ 2017-12-15 20:44 Eric Biggers
  2017-12-15 20:44 ` [PATCH 2/2 for 3.18/4.1] KEYS: add missing permission check for request_key() destination Eric Biggers
  2017-12-18 12:07 ` [PATCH 1/2 for 3.18/4.1] KEYS: Don't permit request_key() to construct a new keyring Greg KH
  0 siblings, 2 replies; 4+ messages in thread
From: Eric Biggers @ 2017-12-15 20:44 UTC (permalink / raw)
  To: stable; +Cc: David Howells, Eric Biggers

From: David Howells <dhowells@redhat.com>

commit 911b79cde95c7da0ec02f48105358a36636b7a71 upstream.
[Please apply to 3.18-stable and 4.1-stable.]

If request_key() is used to find a keyring, only do the search part - don't
do the construction part if the keyring was not found by the search.  We
don't really want keyrings in the negative instantiated state since the
rejected/negative instantiation error value in the payload is unioned with
keyring metadata.

Now the kernel gives an error:

	request_key("keyring", "#selinux,bdekeyring", "keyring", KEY_SPEC_USER_SESSION_KEYRING) = -1 EPERM (Operation not permitted)

Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Eric Biggers <ebiggers@google.com>
---
 security/keys/request_key.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index 486ef6fa393b..0d6253124278 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -440,6 +440,9 @@ static struct key *construct_key_and_link(struct keyring_search_context *ctx,
 
 	kenter("");
 
+	if (ctx->index_key.type == &key_type_keyring)
+		return ERR_PTR(-EPERM);
+	
 	user = key_user_lookup(current_fsuid());
 	if (!user)
 		return ERR_PTR(-ENOMEM);
-- 
2.15.1.504.g5279b80103-goog

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/2 for 3.18/4.1] KEYS: add missing permission check for request_key() destination
  2017-12-15 20:44 [PATCH 1/2 for 3.18/4.1] KEYS: Don't permit request_key() to construct a new keyring Eric Biggers
@ 2017-12-15 20:44 ` Eric Biggers
  2017-12-18 12:06   ` Greg KH
  2017-12-18 12:07 ` [PATCH 1/2 for 3.18/4.1] KEYS: Don't permit request_key() to construct a new keyring Greg KH
  1 sibling, 1 reply; 4+ messages in thread
From: Eric Biggers @ 2017-12-15 20:44 UTC (permalink / raw)
  To: stable; +Cc: Eric Biggers, David Howells

From: Eric Biggers <ebiggers@google.com>

commit 4dca6ea1d9432052afb06baf2e3ae78188a4410b upstream.
[Please apply to 3.18-stable and 4.1-stable.]

When the request_key() syscall is not passed a destination keyring, it
links the requested key (if constructed) into the "default" request-key
keyring.  This should require Write permission to the keyring.  However,
there is actually no permission check.

This can be abused to add keys to any keyring to which only Search
permission is granted.  This is because Search permission allows joining
the keyring.  keyctl_set_reqkey_keyring(KEY_REQKEY_DEFL_SESSION_KEYRING)
then will set the default request-key keyring to the session keyring.
Then, request_key() can be used to add keys to the keyring.

Both negatively and positively instantiated keys can be added using this
method.  Adding negative keys is trivial.  Adding a positive key is a
bit trickier.  It requires that either /sbin/request-key positively
instantiates the key, or that another thread adds the key to the process
keyring at just the right time, such that request_key() misses it
initially but then finds it in construct_alloc_key().

Fix this bug by checking for Write permission to the keyring in
construct_get_dest_keyring() when the default keyring is being used.

We don't do the permission check for non-default keyrings because that
was already done by the earlier call to lookup_user_key().  Also,
request_key_and_link() is currently passed a 'struct key *' rather than
a key_ref_t, so the "possessed" bit is unavailable.

We also don't do the permission check for the "requestor keyring", to
continue to support the use case described by commit 8bbf4976b59f
("KEYS: Alter use of key instantiation link-to-keyring argument") where
/sbin/request-key recursively calls request_key() to add keys to the
original requestor's destination keyring.  (I don't know of any users
who actually do that, though...)

Fixes: 3e30148c3d52 ("[PATCH] Keys: Make request-key create an authorisation key")
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: David Howells <dhowells@redhat.com>
---
 security/keys/request_key.c | 48 +++++++++++++++++++++++++++++++++++----------
 1 file changed, 38 insertions(+), 10 deletions(-)

diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index 0d6253124278..edc367ef0bd6 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -250,11 +250,12 @@ static int construct_key(struct key *key, const void *callout_info,
  * The keyring selected is returned with an extra reference upon it which the
  * caller must release.
  */
-static void construct_get_dest_keyring(struct key **_dest_keyring)
+static int construct_get_dest_keyring(struct key **_dest_keyring)
 {
 	struct request_key_auth *rka;
 	const struct cred *cred = current_cred();
 	struct key *dest_keyring = *_dest_keyring, *authkey;
+	int ret;
 
 	kenter("%p", dest_keyring);
 
@@ -263,6 +264,8 @@ static void construct_get_dest_keyring(struct key **_dest_keyring)
 		/* the caller supplied one */
 		key_get(dest_keyring);
 	} else {
+		bool do_perm_check = true;
+
 		/* use a default keyring; falling through the cases until we
 		 * find one that we actually have */
 		switch (cred->jit_keyring) {
@@ -277,8 +280,10 @@ static void construct_get_dest_keyring(struct key **_dest_keyring)
 					dest_keyring =
 						key_get(rka->dest_keyring);
 				up_read(&authkey->sem);
-				if (dest_keyring)
+				if (dest_keyring) {
+					do_perm_check = false;
 					break;
+				}
 			}
 
 		case KEY_REQKEY_DEFL_THREAD_KEYRING:
@@ -313,11 +318,29 @@ static void construct_get_dest_keyring(struct key **_dest_keyring)
 		default:
 			BUG();
 		}
+
+		/*
+		 * Require Write permission on the keyring.  This is essential
+		 * because the default keyring may be the session keyring, and
+		 * joining a keyring only requires Search permission.
+		 *
+		 * However, this check is skipped for the "requestor keyring" so
+		 * that /sbin/request-key can itself use request_key() to add
+		 * keys to the original requestor's destination keyring.
+		 */
+		if (dest_keyring && do_perm_check) {
+			ret = key_permission(make_key_ref(dest_keyring, 1),
+					     KEY_NEED_WRITE);
+			if (ret) {
+				key_put(dest_keyring);
+				return ret;
+			}
+		}
 	}
 
 	*_dest_keyring = dest_keyring;
 	kleave(" [dk %d]", key_serial(dest_keyring));
-	return;
+	return 0;
 }
 
 /*
@@ -442,12 +465,16 @@ static struct key *construct_key_and_link(struct keyring_search_context *ctx,
 
 	if (ctx->index_key.type == &key_type_keyring)
 		return ERR_PTR(-EPERM);
-	
-	user = key_user_lookup(current_fsuid());
-	if (!user)
-		return ERR_PTR(-ENOMEM);
 
-	construct_get_dest_keyring(&dest_keyring);
+	ret = construct_get_dest_keyring(&dest_keyring);
+	if (ret)
+		goto error;
+
+	user = key_user_lookup(current_fsuid());
+	if (!user) {
+		ret = -ENOMEM;
+		goto error_put_dest_keyring;
+	}
 
 	ret = construct_alloc_key(ctx, dest_keyring, flags, user, &key);
 	key_user_put(user);
@@ -462,7 +489,7 @@ static struct key *construct_key_and_link(struct keyring_search_context *ctx,
 	} else if (ret == -EINPROGRESS) {
 		ret = 0;
 	} else {
-		goto couldnt_alloc_key;
+		goto error_put_dest_keyring;
 	}
 
 	key_put(dest_keyring);
@@ -472,8 +499,9 @@ static struct key *construct_key_and_link(struct keyring_search_context *ctx,
 construction_failed:
 	key_negate_and_link(key, key_negative_timeout, NULL, NULL);
 	key_put(key);
-couldnt_alloc_key:
+error_put_dest_keyring:
 	key_put(dest_keyring);
+error:
 	kleave(" = %d", ret);
 	return ERR_PTR(ret);
 }
-- 
2.15.1.504.g5279b80103-goog

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH 2/2 for 3.18/4.1] KEYS: add missing permission check for request_key() destination
  2017-12-15 20:44 ` [PATCH 2/2 for 3.18/4.1] KEYS: add missing permission check for request_key() destination Eric Biggers
@ 2017-12-18 12:06   ` Greg KH
  0 siblings, 0 replies; 4+ messages in thread
From: Greg KH @ 2017-12-18 12:06 UTC (permalink / raw)
  To: Eric Biggers; +Cc: stable, Eric Biggers, David Howells

On Fri, Dec 15, 2017 at 12:44:18PM -0800, Eric Biggers wrote:
> From: Eric Biggers <ebiggers@google.com>
> 
> commit 4dca6ea1d9432052afb06baf2e3ae78188a4410b upstream.
> [Please apply to 3.18-stable and 4.1-stable.]
> 
> When the request_key() syscall is not passed a destination keyring, it
> links the requested key (if constructed) into the "default" request-key
> keyring.  This should require Write permission to the keyring.  However,
> there is actually no permission check.
> 
> This can be abused to add keys to any keyring to which only Search
> permission is granted.  This is because Search permission allows joining
> the keyring.  keyctl_set_reqkey_keyring(KEY_REQKEY_DEFL_SESSION_KEYRING)
> then will set the default request-key keyring to the session keyring.
> Then, request_key() can be used to add keys to the keyring.
> 
> Both negatively and positively instantiated keys can be added using this
> method.  Adding negative keys is trivial.  Adding a positive key is a
> bit trickier.  It requires that either /sbin/request-key positively
> instantiates the key, or that another thread adds the key to the process
> keyring at just the right time, such that request_key() misses it
> initially but then finds it in construct_alloc_key().
> 
> Fix this bug by checking for Write permission to the keyring in
> construct_get_dest_keyring() when the default keyring is being used.
> 
> We don't do the permission check for non-default keyrings because that
> was already done by the earlier call to lookup_user_key().  Also,
> request_key_and_link() is currently passed a 'struct key *' rather than
> a key_ref_t, so the "possessed" bit is unavailable.
> 
> We also don't do the permission check for the "requestor keyring", to
> continue to support the use case described by commit 8bbf4976b59f
> ("KEYS: Alter use of key instantiation link-to-keyring argument") where
> /sbin/request-key recursively calls request_key() to add keys to the
> original requestor's destination keyring.  (I don't know of any users
> who actually do that, though...)
> 
> Fixes: 3e30148c3d52 ("[PATCH] Keys: Make request-key create an authorisation key")
> Signed-off-by: Eric Biggers <ebiggers@google.com>
> Signed-off-by: David Howells <dhowells@redhat.com>
> ---
>  security/keys/request_key.c | 48 +++++++++++++++++++++++++++++++++++----------
>  1 file changed, 38 insertions(+), 10 deletions(-)
> 

Thanks for the patch, but this was already in the 3.18.88 release.

greg k-h

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 1/2 for 3.18/4.1] KEYS: Don't permit request_key() to construct a new keyring
  2017-12-15 20:44 [PATCH 1/2 for 3.18/4.1] KEYS: Don't permit request_key() to construct a new keyring Eric Biggers
  2017-12-15 20:44 ` [PATCH 2/2 for 3.18/4.1] KEYS: add missing permission check for request_key() destination Eric Biggers
@ 2017-12-18 12:07 ` Greg KH
  1 sibling, 0 replies; 4+ messages in thread
From: Greg KH @ 2017-12-18 12:07 UTC (permalink / raw)
  To: Eric Biggers; +Cc: stable, David Howells, Eric Biggers

On Fri, Dec 15, 2017 at 12:44:17PM -0800, Eric Biggers wrote:
> From: David Howells <dhowells@redhat.com>
> 
> commit 911b79cde95c7da0ec02f48105358a36636b7a71 upstream.
> [Please apply to 3.18-stable and 4.1-stable.]
> 
> If request_key() is used to find a keyring, only do the search part - don't
> do the construction part if the keyring was not found by the search.  We
> don't really want keyrings in the negative instantiated state since the
> rejected/negative instantiation error value in the payload is unioned with
> keyring metadata.
> 
> Now the kernel gives an error:
> 
> 	request_key("keyring", "#selinux,bdekeyring", "keyring", KEY_SPEC_USER_SESSION_KEYRING) = -1 EPERM (Operation not permitted)
> 
> Signed-off-by: David Howells <dhowells@redhat.com>
> Signed-off-by: Eric Biggers <ebiggers@google.com>
> ---
>  security/keys/request_key.c | 3 +++
>  1 file changed, 3 insertions(+)

Now applied to 3.18, thanks.

greg k-h

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2017-12-18 12:07 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-12-15 20:44 [PATCH 1/2 for 3.18/4.1] KEYS: Don't permit request_key() to construct a new keyring Eric Biggers
2017-12-15 20:44 ` [PATCH 2/2 for 3.18/4.1] KEYS: add missing permission check for request_key() destination Eric Biggers
2017-12-18 12:06   ` Greg KH
2017-12-18 12:07 ` [PATCH 1/2 for 3.18/4.1] KEYS: Don't permit request_key() to construct a new keyring Greg KH

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.