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
This commit is contained in:
commit
23c836ce5c
5 changed files with 36 additions and 34 deletions
|
@ -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 @@
|
||||||
#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,
|
||||||
|
|
||||||
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,
|
||||||
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)
|
||||||
/* 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,
|
||||||
{
|
{
|
||||||
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
key->type->name,
|
infobuf = kasprintf(GFP_KERNEL,
|
||||||
from_kuid_munged(current_user_ns(), key->uid),
|
"%s;%d;%d;%08x;",
|
||||||
from_kgid_munged(current_user_ns(), key->gid),
|
key->type->name,
|
||||||
key->perm,
|
from_kuid_munged(current_user_ns(), key->uid),
|
||||||
key->description ?: "");
|
from_kgid_munged(current_user_ns(), key->gid),
|
||||||
|
key->perm);
|
||||||
/* include a NUL char at the end of the data */
|
if (!infobuf)
|
||||||
if (ret > PAGE_SIZE - 1)
|
goto error2;
|
||||||
ret = PAGE_SIZE - 1;
|
infolen = strlen(infobuf);
|
||||||
tmpbuf[ret] = 0;
|
ret = infolen + desclen + 1;
|
||||||
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,
|
||||||
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,7 +546,8 @@ 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) {
|
||||||
ctx->result = ERR_PTR(-EKEYEXPIRED);
|
if (!(ctx->flags & KEYRING_SEARCH_SKIP_EXPIRED))
|
||||||
|
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,
|
||||||
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,
|
||||||
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
.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)
|
||||||
.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;
|
||||||
|
|
Loading…
Add table
Reference in a new issue