Commit ceb73c12 authored by David Howells's avatar David Howells Committed by Linus Torvalds

KEYS: Fix __key_link_end() quota fixup on error

Fix __key_link_end()'s attempt to fix up the quota if an error occurs.

There are two erroneous cases: Firstly, we always decrease the quota if
the preallocated replacement keyring needs cleaning up, irrespective of
whether or not we should (we may have replaced a pointer rather than
adding another pointer).

Secondly, we never clean up the quota if we added a pointer without the
keyring storage being extended (we allocate multiple pointers at a time,
even if we're not going to use them all immediately).

We handle this by setting the bottom bit of the preallocation pointer in
__key_link_begin() to indicate that the quota needs fixing up, which is
then passed to __key_link() (which clears the whole thing) and
__key_link_end().
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent f5c66d70
...@@ -87,13 +87,13 @@ extern void key_type_put(struct key_type *ktype); ...@@ -87,13 +87,13 @@ extern void key_type_put(struct key_type *ktype);
extern int __key_link_begin(struct key *keyring, extern int __key_link_begin(struct key *keyring,
const struct key_type *type, const struct key_type *type,
const char *description, const char *description,
struct keyring_list **_prealloc); unsigned long *_prealloc);
extern int __key_link_check_live_key(struct key *keyring, struct key *key); extern int __key_link_check_live_key(struct key *keyring, struct key *key);
extern void __key_link(struct key *keyring, struct key *key, extern void __key_link(struct key *keyring, struct key *key,
struct keyring_list **_prealloc); unsigned long *_prealloc);
extern void __key_link_end(struct key *keyring, extern void __key_link_end(struct key *keyring,
struct key_type *type, struct key_type *type,
struct keyring_list *prealloc); unsigned long prealloc);
extern key_ref_t __keyring_search_one(key_ref_t keyring_ref, extern key_ref_t __keyring_search_one(key_ref_t keyring_ref,
const struct key_type *type, const struct key_type *type,
......
...@@ -415,7 +415,7 @@ static int __key_instantiate_and_link(struct key *key, ...@@ -415,7 +415,7 @@ static int __key_instantiate_and_link(struct key *key,
size_t datalen, size_t datalen,
struct key *keyring, struct key *keyring,
struct key *authkey, struct key *authkey,
struct keyring_list **_prealloc) unsigned long *_prealloc)
{ {
int ret, awaken; int ret, awaken;
...@@ -481,7 +481,7 @@ int key_instantiate_and_link(struct key *key, ...@@ -481,7 +481,7 @@ int key_instantiate_and_link(struct key *key,
struct key *keyring, struct key *keyring,
struct key *authkey) struct key *authkey)
{ {
struct keyring_list *prealloc; unsigned long prealloc;
int ret; int ret;
if (keyring) { if (keyring) {
...@@ -526,7 +526,7 @@ int key_negate_and_link(struct key *key, ...@@ -526,7 +526,7 @@ int key_negate_and_link(struct key *key,
struct key *keyring, struct key *keyring,
struct key *authkey) struct key *authkey)
{ {
struct keyring_list *prealloc; unsigned long prealloc;
struct timespec now; struct timespec now;
int ret, awaken, link_ret = 0; int ret, awaken, link_ret = 0;
...@@ -814,7 +814,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, ...@@ -814,7 +814,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
key_perm_t perm, key_perm_t perm,
unsigned long flags) unsigned long flags)
{ {
struct keyring_list *prealloc; unsigned long prealloc;
const struct cred *cred = current_cred(); const struct cred *cred = current_cred();
struct key_type *ktype; struct key_type *ktype;
struct key *keyring, *key = NULL; struct key *keyring, *key = NULL;
......
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
(keyring)->payload.subscriptions, \ (keyring)->payload.subscriptions, \
rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem))) rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem)))
#define KEY_LINK_FIXQUOTA 1UL
/* /*
* When plumbing the depths of the key tree, this sets a hard limit * When plumbing the depths of the key tree, this sets a hard limit
* set on how deep we're willing to go. * set on how deep we're willing to go.
...@@ -699,11 +701,11 @@ static void keyring_unlink_rcu_disposal(struct rcu_head *rcu) ...@@ -699,11 +701,11 @@ static void keyring_unlink_rcu_disposal(struct rcu_head *rcu)
* Preallocate memory so that a key can be linked into to a keyring. * Preallocate memory so that a key can be linked into to a keyring.
*/ */
int __key_link_begin(struct key *keyring, const struct key_type *type, int __key_link_begin(struct key *keyring, const struct key_type *type,
const char *description, const char *description, unsigned long *_prealloc)
struct keyring_list **_prealloc)
__acquires(&keyring->sem) __acquires(&keyring->sem)
{ {
struct keyring_list *klist, *nklist; struct keyring_list *klist, *nklist;
unsigned long prealloc;
unsigned max; unsigned max;
size_t size; size_t size;
int loop, ret; int loop, ret;
...@@ -746,6 +748,7 @@ int __key_link_begin(struct key *keyring, const struct key_type *type, ...@@ -746,6 +748,7 @@ int __key_link_begin(struct key *keyring, const struct key_type *type,
/* note replacement slot */ /* note replacement slot */
klist->delkey = nklist->delkey = loop; klist->delkey = nklist->delkey = loop;
prealloc = (unsigned long)nklist;
goto done; goto done;
} }
} }
...@@ -760,6 +763,7 @@ int __key_link_begin(struct key *keyring, const struct key_type *type, ...@@ -760,6 +763,7 @@ int __key_link_begin(struct key *keyring, const struct key_type *type,
if (klist && klist->nkeys < klist->maxkeys) { if (klist && klist->nkeys < klist->maxkeys) {
/* there's sufficient slack space to append directly */ /* there's sufficient slack space to append directly */
nklist = NULL; nklist = NULL;
prealloc = KEY_LINK_FIXQUOTA;
} else { } else {
/* grow the key list */ /* grow the key list */
max = 4; max = 4;
...@@ -794,8 +798,9 @@ int __key_link_begin(struct key *keyring, const struct key_type *type, ...@@ -794,8 +798,9 @@ int __key_link_begin(struct key *keyring, const struct key_type *type,
nklist->keys[nklist->delkey] = NULL; nklist->keys[nklist->delkey] = NULL;
} }
prealloc = (unsigned long)nklist | KEY_LINK_FIXQUOTA;
done: done:
*_prealloc = nklist; *_prealloc = prealloc;
kleave(" = 0"); kleave(" = 0");
return 0; return 0;
...@@ -836,12 +841,12 @@ int __key_link_check_live_key(struct key *keyring, struct key *key) ...@@ -836,12 +841,12 @@ int __key_link_check_live_key(struct key *keyring, struct key *key)
* combination. * combination.
*/ */
void __key_link(struct key *keyring, struct key *key, void __key_link(struct key *keyring, struct key *key,
struct keyring_list **_prealloc) unsigned long *_prealloc)
{ {
struct keyring_list *klist, *nklist; struct keyring_list *klist, *nklist;
nklist = *_prealloc; nklist = (struct keyring_list *)(*_prealloc & ~KEY_LINK_FIXQUOTA);
*_prealloc = NULL; *_prealloc = 0;
kenter("%d,%d,%p", keyring->serial, key->serial, nklist); kenter("%d,%d,%p", keyring->serial, key->serial, nklist);
...@@ -881,20 +886,22 @@ void __key_link(struct key *keyring, struct key *key, ...@@ -881,20 +886,22 @@ void __key_link(struct key *keyring, struct key *key,
* Must be called with __key_link_begin() having being called. * Must be called with __key_link_begin() having being called.
*/ */
void __key_link_end(struct key *keyring, struct key_type *type, void __key_link_end(struct key *keyring, struct key_type *type,
struct keyring_list *prealloc) unsigned long prealloc)
__releases(&keyring->sem) __releases(&keyring->sem)
{ {
BUG_ON(type == NULL); BUG_ON(type == NULL);
BUG_ON(type->name == NULL); BUG_ON(type->name == NULL);
kenter("%d,%s,%p", keyring->serial, type->name, prealloc); kenter("%d,%s,%lx", keyring->serial, type->name, prealloc);
if (type == &key_type_keyring) if (type == &key_type_keyring)
up_write(&keyring_serialise_link_sem); up_write(&keyring_serialise_link_sem);
if (prealloc) { if (prealloc) {
kfree(prealloc); if (prealloc & KEY_LINK_FIXQUOTA)
key_payload_reserve(keyring, key_payload_reserve(keyring,
keyring->datalen - KEYQUOTA_LINK_BYTES); keyring->datalen -
KEYQUOTA_LINK_BYTES);
kfree((struct keyring_list *)(prealloc & ~KEY_LINK_FIXQUOTA));
} }
up_write(&keyring->sem); up_write(&keyring->sem);
} }
...@@ -921,7 +928,7 @@ void __key_link_end(struct key *keyring, struct key_type *type, ...@@ -921,7 +928,7 @@ void __key_link_end(struct key *keyring, struct key_type *type,
*/ */
int key_link(struct key *keyring, struct key *key) int key_link(struct key *keyring, struct key *key)
{ {
struct keyring_list *prealloc; unsigned long prealloc;
int ret; int ret;
key_check(keyring); key_check(keyring);
......
...@@ -352,8 +352,8 @@ static int construct_alloc_key(struct key_type *type, ...@@ -352,8 +352,8 @@ static int construct_alloc_key(struct key_type *type,
struct key_user *user, struct key_user *user,
struct key **_key) struct key **_key)
{ {
struct keyring_list *prealloc;
const struct cred *cred = current_cred(); const struct cred *cred = current_cred();
unsigned long prealloc;
struct key *key; struct key *key;
key_ref_t key_ref; key_ref_t key_ref;
int ret; int ret;
......
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