Skip to content

Commit

Permalink
Merge tag 'keys-next-6.10-rc1' of git://git.kernel.org/pub/scm/linux/…
Browse files Browse the repository at this point in the history
…kernel/git/jarkko/linux-tpmdd

Pull keys updates from Jarkko Sakkinen:

 - do not overwrite the key expiration once it is set

 - move key quota updates earlier into key_put(), instead of updating
   them in key_gc_unused_keys()

* tag 'keys-next-6.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd:
  keys: Fix overwrite of key expiration on instantiation
  keys: update key quotas in key_put()
  • Loading branch information
torvalds committed May 13, 2024
2 parents b192391 + 9da27fb commit 25c7364
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 24 deletions.
8 changes: 0 additions & 8 deletions security/keys/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,14 +155,6 @@ static noinline void key_gc_unused_keys(struct list_head *keys)

security_key_free(key);

/* deal with the user's key tracking and quota */
if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
spin_lock(&key->user->lock);
key->user->qnkeys--;
key->user->qnbytes -= key->quotalen;
spin_unlock(&key->user->lock);
}

atomic_dec(&key->user->nkeys);
if (state != KEY_IS_UNINSTANTIATED)
atomic_dec(&key->user->nikeys);
Expand Down
35 changes: 24 additions & 11 deletions security/keys/key.c
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
struct key *key;
size_t desclen, quotalen;
int ret;
unsigned long irqflags;

key = ERR_PTR(-EINVAL);
if (!desc || !*desc)
Expand Down Expand Up @@ -259,7 +260,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
unsigned maxbytes = uid_eq(uid, GLOBAL_ROOT_UID) ?
key_quota_root_maxbytes : key_quota_maxbytes;

spin_lock(&user->lock);
spin_lock_irqsave(&user->lock, irqflags);
if (!(flags & KEY_ALLOC_QUOTA_OVERRUN)) {
if (user->qnkeys + 1 > maxkeys ||
user->qnbytes + quotalen > maxbytes ||
Expand All @@ -269,7 +270,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,

user->qnkeys++;
user->qnbytes += quotalen;
spin_unlock(&user->lock);
spin_unlock_irqrestore(&user->lock, irqflags);
}

/* allocate and initialise the key and its description */
Expand Down Expand Up @@ -327,10 +328,10 @@ struct key *key_alloc(struct key_type *type, const char *desc,
kfree(key->description);
kmem_cache_free(key_jar, key);
if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
spin_lock(&user->lock);
spin_lock_irqsave(&user->lock, irqflags);
user->qnkeys--;
user->qnbytes -= quotalen;
spin_unlock(&user->lock);
spin_unlock_irqrestore(&user->lock, irqflags);
}
key_user_put(user);
key = ERR_PTR(ret);
Expand All @@ -340,18 +341,18 @@ struct key *key_alloc(struct key_type *type, const char *desc,
kmem_cache_free(key_jar, key);
no_memory_2:
if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
spin_lock(&user->lock);
spin_lock_irqsave(&user->lock, irqflags);
user->qnkeys--;
user->qnbytes -= quotalen;
spin_unlock(&user->lock);
spin_unlock_irqrestore(&user->lock, irqflags);
}
key_user_put(user);
no_memory_1:
key = ERR_PTR(-ENOMEM);
goto error;

no_quota:
spin_unlock(&user->lock);
spin_unlock_irqrestore(&user->lock, irqflags);
key_user_put(user);
key = ERR_PTR(-EDQUOT);
goto error;
Expand Down Expand Up @@ -380,8 +381,9 @@ int key_payload_reserve(struct key *key, size_t datalen)
if (delta != 0 && test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
unsigned maxbytes = uid_eq(key->user->uid, GLOBAL_ROOT_UID) ?
key_quota_root_maxbytes : key_quota_maxbytes;
unsigned long flags;

spin_lock(&key->user->lock);
spin_lock_irqsave(&key->user->lock, flags);

if (delta > 0 &&
(key->user->qnbytes + delta > maxbytes ||
Expand All @@ -392,7 +394,7 @@ int key_payload_reserve(struct key *key, size_t datalen)
key->user->qnbytes += delta;
key->quotalen += delta;
}
spin_unlock(&key->user->lock);
spin_unlock_irqrestore(&key->user->lock, flags);
}

/* change the recorded data length if that didn't generate an error */
Expand Down Expand Up @@ -463,7 +465,8 @@ static int __key_instantiate_and_link(struct key *key,
if (authkey)
key_invalidate(authkey);

key_set_expiry(key, prep->expiry);
if (prep->expiry != TIME64_MAX)
key_set_expiry(key, prep->expiry);
}
}

Expand Down Expand Up @@ -645,8 +648,18 @@ void key_put(struct key *key)
if (key) {
key_check(key);

if (refcount_dec_and_test(&key->usage))
if (refcount_dec_and_test(&key->usage)) {
unsigned long flags;

/* deal with the user's key tracking and quota */
if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
spin_lock_irqsave(&key->user->lock, flags);
key->user->qnkeys--;
key->user->qnbytes -= key->quotalen;
spin_unlock_irqrestore(&key->user->lock, flags);
}
schedule_work(&key_gc_work);
}
}
}
EXPORT_SYMBOL(key_put);
Expand Down
11 changes: 6 additions & 5 deletions security/keys/keyctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -954,6 +954,7 @@ long keyctl_chown_key(key_serial_t id, uid_t user, gid_t group)
long ret;
kuid_t uid;
kgid_t gid;
unsigned long flags;

uid = make_kuid(current_user_ns(), user);
gid = make_kgid(current_user_ns(), group);
Expand Down Expand Up @@ -1010,7 +1011,7 @@ long keyctl_chown_key(key_serial_t id, uid_t user, gid_t group)
unsigned maxbytes = uid_eq(uid, GLOBAL_ROOT_UID) ?
key_quota_root_maxbytes : key_quota_maxbytes;

spin_lock(&newowner->lock);
spin_lock_irqsave(&newowner->lock, flags);
if (newowner->qnkeys + 1 > maxkeys ||
newowner->qnbytes + key->quotalen > maxbytes ||
newowner->qnbytes + key->quotalen <
Expand All @@ -1019,12 +1020,12 @@ long keyctl_chown_key(key_serial_t id, uid_t user, gid_t group)

newowner->qnkeys++;
newowner->qnbytes += key->quotalen;
spin_unlock(&newowner->lock);
spin_unlock_irqrestore(&newowner->lock, flags);

spin_lock(&key->user->lock);
spin_lock_irqsave(&key->user->lock, flags);
key->user->qnkeys--;
key->user->qnbytes -= key->quotalen;
spin_unlock(&key->user->lock);
spin_unlock_irqrestore(&key->user->lock, flags);
}

atomic_dec(&key->user->nkeys);
Expand Down Expand Up @@ -1056,7 +1057,7 @@ long keyctl_chown_key(key_serial_t id, uid_t user, gid_t group)
return ret;

quota_overrun:
spin_unlock(&newowner->lock);
spin_unlock_irqrestore(&newowner->lock, flags);
zapowner = newowner;
ret = -EDQUOT;
goto error_put;
Expand Down

0 comments on commit 25c7364

Please sign in to comment.