Commit 23c836ce authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security

Pull keyring/nfs fixes from James Morris:
 "From David Howells:

  The first one fixes the handling of maximum buffer size for key
  descriptions, fixing the size at 4095 + NUL char rather than whatever
  PAGE_SIZE happens to be and permits you to read back the full
  description without it getting clipped because some extra information
  got prepended.

  The second and third fix a bug in NFS idmapper handling whereby a key
  representing a mapping between an id and a name expires and causing
  EKEYEXPIRED to be seen internally in NFS (which prevents the mapping
  from happening) rather than re-looking up the mapping"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security:
  KEYS: request_key() should reget expired keys rather than give EKEYEXPIRED
  KEYS: Simplify KEYRING_SEARCH_{NO,DO}_STATE_CHECK flags
  KEYS: Fix the size of the key description passed to/from userspace
parents 1dd909af 18832480
...@@ -117,6 +117,7 @@ struct keyring_search_context { ...@@ -117,6 +117,7 @@ struct keyring_search_context {
#define KEYRING_SEARCH_NO_UPDATE_TIME 0x0004 /* Don't update times */ #define KEYRING_SEARCH_NO_UPDATE_TIME 0x0004 /* Don't update times */
#define KEYRING_SEARCH_NO_CHECK_PERM 0x0008 /* Don't check permissions */ #define KEYRING_SEARCH_NO_CHECK_PERM 0x0008 /* Don't check permissions */
#define KEYRING_SEARCH_DETECT_TOO_DEEP 0x0010 /* Give an error on excessive depth */ #define KEYRING_SEARCH_DETECT_TOO_DEEP 0x0010 /* Give an error on excessive depth */
#define KEYRING_SEARCH_SKIP_EXPIRED 0x0020 /* Ignore expired keys (intention to replace) */
int (*iterator)(const void *object, void *iterator_data); int (*iterator)(const void *object, void *iterator_data);
......
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "internal.h" #include "internal.h"
#define KEY_MAX_DESC_SIZE 4096
static int key_get_type_from_user(char *type, static int key_get_type_from_user(char *type,
const char __user *_type, const char __user *_type,
unsigned len) unsigned len)
...@@ -78,7 +80,7 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type, ...@@ -78,7 +80,7 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
description = NULL; description = NULL;
if (_description) { if (_description) {
description = strndup_user(_description, PAGE_SIZE); description = strndup_user(_description, KEY_MAX_DESC_SIZE);
if (IS_ERR(description)) { if (IS_ERR(description)) {
ret = PTR_ERR(description); ret = PTR_ERR(description);
goto error; goto error;
...@@ -177,7 +179,7 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type, ...@@ -177,7 +179,7 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type,
goto error; goto error;
/* pull the description into kernel space */ /* pull the description into kernel space */
description = strndup_user(_description, PAGE_SIZE); description = strndup_user(_description, KEY_MAX_DESC_SIZE);
if (IS_ERR(description)) { if (IS_ERR(description)) {
ret = PTR_ERR(description); ret = PTR_ERR(description);
goto error; goto error;
...@@ -287,7 +289,7 @@ long keyctl_join_session_keyring(const char __user *_name) ...@@ -287,7 +289,7 @@ long keyctl_join_session_keyring(const char __user *_name)
/* fetch the name from userspace */ /* fetch the name from userspace */
name = NULL; name = NULL;
if (_name) { if (_name) {
name = strndup_user(_name, PAGE_SIZE); name = strndup_user(_name, KEY_MAX_DESC_SIZE);
if (IS_ERR(name)) { if (IS_ERR(name)) {
ret = PTR_ERR(name); ret = PTR_ERR(name);
goto error; goto error;
...@@ -562,8 +564,9 @@ long keyctl_describe_key(key_serial_t keyid, ...@@ -562,8 +564,9 @@ long keyctl_describe_key(key_serial_t keyid,
{ {
struct key *key, *instkey; struct key *key, *instkey;
key_ref_t key_ref; key_ref_t key_ref;
char *tmpbuf; char *infobuf;
long ret; long ret;
int desclen, infolen;
key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_NEED_VIEW); key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_NEED_VIEW);
if (IS_ERR(key_ref)) { if (IS_ERR(key_ref)) {
...@@ -586,38 +589,31 @@ long keyctl_describe_key(key_serial_t keyid, ...@@ -586,38 +589,31 @@ long keyctl_describe_key(key_serial_t keyid,
} }
okay: okay:
/* calculate how much description we're going to return */
ret = -ENOMEM;
tmpbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!tmpbuf)
goto error2;
key = key_ref_to_ptr(key_ref); key = key_ref_to_ptr(key_ref);
desclen = strlen(key->description);
ret = snprintf(tmpbuf, PAGE_SIZE - 1, /* calculate how much information we're going to return */
"%s;%d;%d;%08x;%s", ret = -ENOMEM;
infobuf = kasprintf(GFP_KERNEL,
"%s;%d;%d;%08x;",
key->type->name, key->type->name,
from_kuid_munged(current_user_ns(), key->uid), from_kuid_munged(current_user_ns(), key->uid),
from_kgid_munged(current_user_ns(), key->gid), from_kgid_munged(current_user_ns(), key->gid),
key->perm, key->perm);
key->description ?: ""); if (!infobuf)
goto error2;
/* include a NUL char at the end of the data */ infolen = strlen(infobuf);
if (ret > PAGE_SIZE - 1) ret = infolen + desclen + 1;
ret = PAGE_SIZE - 1;
tmpbuf[ret] = 0;
ret++;
/* consider returning the data */ /* consider returning the data */
if (buffer && buflen > 0) { if (buffer && buflen >= ret) {
if (buflen > ret) if (copy_to_user(buffer, infobuf, infolen) != 0 ||
buflen = ret; copy_to_user(buffer + infolen, key->description,
desclen + 1) != 0)
if (copy_to_user(buffer, tmpbuf, buflen) != 0)
ret = -EFAULT; ret = -EFAULT;
} }
kfree(tmpbuf); kfree(infobuf);
error2: error2:
key_ref_put(key_ref); key_ref_put(key_ref);
error: error:
...@@ -649,7 +645,7 @@ long keyctl_keyring_search(key_serial_t ringid, ...@@ -649,7 +645,7 @@ long keyctl_keyring_search(key_serial_t ringid,
if (ret < 0) if (ret < 0)
goto error; goto error;
description = strndup_user(_description, PAGE_SIZE); description = strndup_user(_description, KEY_MAX_DESC_SIZE);
if (IS_ERR(description)) { if (IS_ERR(description)) {
ret = PTR_ERR(description); ret = PTR_ERR(description);
goto error; goto error;
......
...@@ -546,6 +546,7 @@ static int keyring_search_iterator(const void *object, void *iterator_data) ...@@ -546,6 +546,7 @@ static int keyring_search_iterator(const void *object, void *iterator_data)
} }
if (key->expiry && ctx->now.tv_sec >= key->expiry) { if (key->expiry && ctx->now.tv_sec >= key->expiry) {
if (!(ctx->flags & KEYRING_SEARCH_SKIP_EXPIRED))
ctx->result = ERR_PTR(-EKEYEXPIRED); ctx->result = ERR_PTR(-EKEYEXPIRED);
kleave(" = %d [expire]", ctx->skipped_ret); kleave(" = %d [expire]", ctx->skipped_ret);
goto skipped; goto skipped;
...@@ -628,6 +629,10 @@ static bool search_nested_keyrings(struct key *keyring, ...@@ -628,6 +629,10 @@ static bool search_nested_keyrings(struct key *keyring,
ctx->index_key.type->name, ctx->index_key.type->name,
ctx->index_key.description); ctx->index_key.description);
#define STATE_CHECKS (KEYRING_SEARCH_NO_STATE_CHECK | KEYRING_SEARCH_DO_STATE_CHECK)
BUG_ON((ctx->flags & STATE_CHECKS) == 0 ||
(ctx->flags & STATE_CHECKS) == STATE_CHECKS);
if (ctx->index_key.description) if (ctx->index_key.description)
ctx->index_key.desc_len = strlen(ctx->index_key.description); ctx->index_key.desc_len = strlen(ctx->index_key.description);
...@@ -637,7 +642,6 @@ static bool search_nested_keyrings(struct key *keyring, ...@@ -637,7 +642,6 @@ static bool search_nested_keyrings(struct key *keyring,
if (ctx->match_data.lookup_type == KEYRING_SEARCH_LOOKUP_ITERATE || if (ctx->match_data.lookup_type == KEYRING_SEARCH_LOOKUP_ITERATE ||
keyring_compare_object(keyring, &ctx->index_key)) { keyring_compare_object(keyring, &ctx->index_key)) {
ctx->skipped_ret = 2; ctx->skipped_ret = 2;
ctx->flags |= KEYRING_SEARCH_DO_STATE_CHECK;
switch (ctx->iterator(keyring_key_to_ptr(keyring), ctx)) { switch (ctx->iterator(keyring_key_to_ptr(keyring), ctx)) {
case 1: case 1:
goto found; goto found;
...@@ -649,8 +653,6 @@ static bool search_nested_keyrings(struct key *keyring, ...@@ -649,8 +653,6 @@ static bool search_nested_keyrings(struct key *keyring,
} }
ctx->skipped_ret = 0; ctx->skipped_ret = 0;
if (ctx->flags & KEYRING_SEARCH_NO_STATE_CHECK)
ctx->flags &= ~KEYRING_SEARCH_DO_STATE_CHECK;
/* Start processing a new keyring */ /* Start processing a new keyring */
descend_to_keyring: descend_to_keyring:
......
...@@ -516,6 +516,8 @@ struct key *request_key_and_link(struct key_type *type, ...@@ -516,6 +516,8 @@ struct key *request_key_and_link(struct key_type *type,
.match_data.cmp = key_default_cmp, .match_data.cmp = key_default_cmp,
.match_data.raw_data = description, .match_data.raw_data = description,
.match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
.flags = (KEYRING_SEARCH_DO_STATE_CHECK |
KEYRING_SEARCH_SKIP_EXPIRED),
}; };
struct key *key; struct key *key;
key_ref_t key_ref; key_ref_t key_ref;
......
...@@ -249,6 +249,7 @@ struct key *key_get_instantiation_authkey(key_serial_t target_id) ...@@ -249,6 +249,7 @@ struct key *key_get_instantiation_authkey(key_serial_t target_id)
.match_data.cmp = key_default_cmp, .match_data.cmp = key_default_cmp,
.match_data.raw_data = description, .match_data.raw_data = description,
.match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
.flags = KEYRING_SEARCH_DO_STATE_CHECK,
}; };
struct key *authkey; struct key *authkey;
key_ref_t authkey_ref; key_ref_t authkey_ref;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment