diff --git a/security/keys/internal.h b/security/keys/internal.h index b8960c4959a5e53635180054d27d788105ebf134..200e37867336a3c2903437e97f591fbc302e15b7 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -117,6 +117,7 @@ struct keyring_search_context { #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_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); diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index eff88a5f5d40da17611d381bcf4e219a90bcc972..4743d71e4aa6dd12f2456a5f00496c1222775c6a 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -26,6 +26,8 @@ #include #include "internal.h" +#define KEY_MAX_DESC_SIZE 4096 + static int key_get_type_from_user(char *type, const char __user *_type, unsigned len) @@ -78,7 +80,7 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type, description = NULL; if (_description) { - description = strndup_user(_description, PAGE_SIZE); + description = strndup_user(_description, KEY_MAX_DESC_SIZE); if (IS_ERR(description)) { ret = PTR_ERR(description); goto error; @@ -177,7 +179,7 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type, goto error; /* pull the description into kernel space */ - description = strndup_user(_description, PAGE_SIZE); + description = strndup_user(_description, KEY_MAX_DESC_SIZE); if (IS_ERR(description)) { ret = PTR_ERR(description); goto error; @@ -287,7 +289,7 @@ long keyctl_join_session_keyring(const char __user *_name) /* fetch the name from userspace */ name = NULL; if (_name) { - name = strndup_user(_name, PAGE_SIZE); + name = strndup_user(_name, KEY_MAX_DESC_SIZE); if (IS_ERR(name)) { ret = PTR_ERR(name); goto error; @@ -562,8 +564,9 @@ long keyctl_describe_key(key_serial_t keyid, { struct key *key, *instkey; key_ref_t key_ref; - char *tmpbuf; + char *infobuf; long ret; + int desclen, infolen; key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_NEED_VIEW); if (IS_ERR(key_ref)) { @@ -586,38 +589,31 @@ long keyctl_describe_key(key_serial_t keyid, } 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); + desclen = strlen(key->description); - ret = snprintf(tmpbuf, PAGE_SIZE - 1, - "%s;%d;%d;%08x;%s", - key->type->name, - from_kuid_munged(current_user_ns(), key->uid), - from_kgid_munged(current_user_ns(), key->gid), - key->perm, - key->description ?: ""); - - /* include a NUL char at the end of the data */ - if (ret > PAGE_SIZE - 1) - ret = PAGE_SIZE - 1; - tmpbuf[ret] = 0; - ret++; + /* calculate how much information we're going to return */ + ret = -ENOMEM; + infobuf = kasprintf(GFP_KERNEL, + "%s;%d;%d;%08x;", + key->type->name, + from_kuid_munged(current_user_ns(), key->uid), + from_kgid_munged(current_user_ns(), key->gid), + key->perm); + if (!infobuf) + goto error2; + infolen = strlen(infobuf); + ret = infolen + desclen + 1; /* consider returning the data */ - if (buffer && buflen > 0) { - if (buflen > ret) - buflen = ret; - - if (copy_to_user(buffer, tmpbuf, buflen) != 0) + if (buffer && buflen >= ret) { + if (copy_to_user(buffer, infobuf, infolen) != 0 || + copy_to_user(buffer + infolen, key->description, + desclen + 1) != 0) ret = -EFAULT; } - kfree(tmpbuf); + kfree(infobuf); error2: key_ref_put(key_ref); error: @@ -649,7 +645,7 @@ long keyctl_keyring_search(key_serial_t ringid, if (ret < 0) goto error; - description = strndup_user(_description, PAGE_SIZE); + description = strndup_user(_description, KEY_MAX_DESC_SIZE); if (IS_ERR(description)) { ret = PTR_ERR(description); goto error; diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 8177010174f7b3d47773a43e48bf2b171b264c5f..e72548b5897ec237dd7463374871538c81a84fd7 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c @@ -546,7 +546,8 @@ static int keyring_search_iterator(const void *object, void *iterator_data) } 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); goto skipped; } @@ -628,6 +629,10 @@ static bool search_nested_keyrings(struct key *keyring, ctx->index_key.type->name, 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) 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 || keyring_compare_object(keyring, &ctx->index_key)) { ctx->skipped_ret = 2; - ctx->flags |= KEYRING_SEARCH_DO_STATE_CHECK; switch (ctx->iterator(keyring_key_to_ptr(keyring), ctx)) { case 1: goto found; @@ -649,8 +653,6 @@ static bool search_nested_keyrings(struct key *keyring, } ctx->skipped_ret = 0; - if (ctx->flags & KEYRING_SEARCH_NO_STATE_CHECK) - ctx->flags &= ~KEYRING_SEARCH_DO_STATE_CHECK; /* Start processing a new keyring */ descend_to_keyring: diff --git a/security/keys/request_key.c b/security/keys/request_key.c index bb4337c7ae1b3978fd5e36d692d8cacf27b89816..0c7aea4dea54d8d299edc09b38c9a8f7b5c82be8 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c @@ -516,6 +516,8 @@ struct key *request_key_and_link(struct key_type *type, .match_data.cmp = key_default_cmp, .match_data.raw_data = description, .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, + .flags = (KEYRING_SEARCH_DO_STATE_CHECK | + KEYRING_SEARCH_SKIP_EXPIRED), }; struct key *key; key_ref_t key_ref; diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c index 6639e2cb885322c6a43924496b2a68be25b9a5e6..5d672f7580dd5330516dd62f7d705cac46c319fb 100644 --- a/security/keys/request_key_auth.c +++ b/security/keys/request_key_auth.c @@ -249,6 +249,7 @@ struct key *key_get_instantiation_authkey(key_serial_t target_id) .match_data.cmp = key_default_cmp, .match_data.raw_data = description, .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, + .flags = KEYRING_SEARCH_DO_STATE_CHECK, }; struct key *authkey; key_ref_t authkey_ref;