KEYS: Add garbage collection for dead, revoked and expired keys. [try #6]
Add garbage collection for dead, revoked and expired keys. This involved erasing all links to such keys from keyrings that point to them. At that point, the key will be deleted in the normal manner. Keyrings from which garbage collection occurs are shrunk and their quota consumption reduced as appropriate. Dead keys (for which the key type has been removed) will be garbage collected immediately. Revoked and expired keys will hang around for a number of seconds, as set in /proc/sys/kernel/keys/gc_delay before being automatically removed. The default is 5 minutes. Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: James Morris <jmorris@namei.org>
This commit is contained in:

committed by
James Morris

parent
f041ae2f99
commit
5d135440fa
@@ -1000,3 +1000,88 @@ static void keyring_revoke(struct key *keyring)
|
||||
}
|
||||
|
||||
} /* end keyring_revoke() */
|
||||
|
||||
/*
|
||||
* Determine whether a key is dead
|
||||
*/
|
||||
static bool key_is_dead(struct key *key, time_t limit)
|
||||
{
|
||||
return test_bit(KEY_FLAG_DEAD, &key->flags) ||
|
||||
(key->expiry > 0 && key->expiry <= limit);
|
||||
}
|
||||
|
||||
/*
|
||||
* Collect garbage from the contents of a keyring
|
||||
*/
|
||||
void keyring_gc(struct key *keyring, time_t limit)
|
||||
{
|
||||
struct keyring_list *klist, *new;
|
||||
struct key *key;
|
||||
int loop, keep, max;
|
||||
|
||||
kenter("%x", key_serial(keyring));
|
||||
|
||||
down_write(&keyring->sem);
|
||||
|
||||
klist = keyring->payload.subscriptions;
|
||||
if (!klist)
|
||||
goto just_return;
|
||||
|
||||
/* work out how many subscriptions we're keeping */
|
||||
keep = 0;
|
||||
for (loop = klist->nkeys - 1; loop >= 0; loop--)
|
||||
if (!key_is_dead(klist->keys[loop], limit));
|
||||
keep++;
|
||||
|
||||
if (keep == klist->nkeys)
|
||||
goto just_return;
|
||||
|
||||
/* allocate a new keyring payload */
|
||||
max = roundup(keep, 4);
|
||||
new = kmalloc(sizeof(struct keyring_list) + max * sizeof(struct key *),
|
||||
GFP_KERNEL);
|
||||
if (!new)
|
||||
goto just_return;
|
||||
new->maxkeys = max;
|
||||
new->nkeys = 0;
|
||||
new->delkey = 0;
|
||||
|
||||
/* install the live keys
|
||||
* - must take care as expired keys may be updated back to life
|
||||
*/
|
||||
keep = 0;
|
||||
for (loop = klist->nkeys - 1; loop >= 0; loop--) {
|
||||
key = klist->keys[loop];
|
||||
if (!key_is_dead(key, limit)) {
|
||||
if (keep >= max)
|
||||
goto discard_new;
|
||||
new->keys[keep++] = key_get(key);
|
||||
}
|
||||
}
|
||||
new->nkeys = keep;
|
||||
|
||||
/* adjust the quota */
|
||||
key_payload_reserve(keyring,
|
||||
sizeof(struct keyring_list) +
|
||||
KEYQUOTA_LINK_BYTES * keep);
|
||||
|
||||
if (keep == 0) {
|
||||
rcu_assign_pointer(keyring->payload.subscriptions, NULL);
|
||||
kfree(new);
|
||||
} else {
|
||||
rcu_assign_pointer(keyring->payload.subscriptions, new);
|
||||
}
|
||||
|
||||
up_write(&keyring->sem);
|
||||
|
||||
call_rcu(&klist->rcu, keyring_clear_rcu_disposal);
|
||||
kleave(" [yes]");
|
||||
return;
|
||||
|
||||
discard_new:
|
||||
new->nkeys = keep;
|
||||
keyring_clear_rcu_disposal(&new->rcu);
|
||||
just_return:
|
||||
up_write(&keyring->sem);
|
||||
kleave(" [no]");
|
||||
}
|
||||
|
Reference in New Issue
Block a user