Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 16956
b: refs/heads/master
c: cab8eb5
h: refs/heads/master
v: v3
  • Loading branch information
David Howells authored and Linus Torvalds committed Jan 9, 2006
1 parent 936d49f commit 1026672
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 24 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 017679c4d45783158dba1dd6f79e712c22bb3d9a
refs/heads/master: cab8eb594e84b434d20412fc5a3985b0bee3ab9f
4 changes: 4 additions & 0 deletions trunk/Documentation/keys.txt
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,10 @@ The keyctl syscall functions are:
The link procedure checks the nesting of the keyrings, returning ELOOP if
it appears too deep or EDEADLK if the link would introduce a cycle.

Any links within the keyring to keys that match the new key in terms of
type and description will be discarded from the keyring as the new one is
added.


(*) Unlink a key or keyring from another keyring:

Expand Down
87 changes: 64 additions & 23 deletions trunk/security/keys/keyring.c
Original file line number Diff line number Diff line change
Expand Up @@ -682,17 +682,33 @@ static void keyring_link_rcu_disposal(struct rcu_head *rcu)

} /* end keyring_link_rcu_disposal() */

/*****************************************************************************/
/*
* dispose of a keyring list after the RCU grace period, freeing the unlinked
* key
*/
static void keyring_unlink_rcu_disposal(struct rcu_head *rcu)
{
struct keyring_list *klist =
container_of(rcu, struct keyring_list, rcu);

key_put(klist->keys[klist->delkey]);
kfree(klist);

} /* end keyring_unlink_rcu_disposal() */

/*****************************************************************************/
/*
* link a key into to a keyring
* - must be called with the keyring's semaphore write-locked
* - discard already extant link to matching key if there is one
*/
int __key_link(struct key *keyring, struct key *key)
{
struct keyring_list *klist, *nklist;
unsigned max;
size_t size;
int ret;
int loop, ret;

ret = -EKEYREVOKED;
if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
Expand All @@ -714,6 +730,48 @@ int __key_link(struct key *keyring, struct key *key)
goto error2;
}

/* see if there's a matching key we can displace */
klist = keyring->payload.subscriptions;

if (klist && klist->nkeys > 0) {
struct key_type *type = key->type;

for (loop = klist->nkeys - 1; loop >= 0; loop--) {
if (klist->keys[loop]->type == type &&
strcmp(klist->keys[loop]->description,
key->description) == 0
) {
/* found a match - replace with new key */
size = sizeof(struct key *) * klist->maxkeys;
size += sizeof(*klist);
BUG_ON(size > PAGE_SIZE);

ret = -ENOMEM;
nklist = kmalloc(size, GFP_KERNEL);
if (!nklist)
goto error2;

memcpy(nklist, klist, size);

/* replace matched key */
atomic_inc(&key->usage);
nklist->keys[loop] = key;

rcu_assign_pointer(
keyring->payload.subscriptions,
nklist);

/* dispose of the old keyring list and the
* displaced key */
klist->delkey = loop;
call_rcu(&klist->rcu,
keyring_unlink_rcu_disposal);

goto done;
}
}
}

/* check that we aren't going to overrun the user's quota */
ret = key_payload_reserve(keyring,
keyring->datalen + KEYQUOTA_LINK_BYTES);
Expand All @@ -730,8 +788,6 @@ int __key_link(struct key *keyring, struct key *key)
smp_wmb();
klist->nkeys++;
smp_wmb();

ret = 0;
}
else {
/* grow the key list */
Expand Down Expand Up @@ -769,16 +825,16 @@ int __key_link(struct key *keyring, struct key *key)
/* dispose of the old keyring list */
if (klist)
call_rcu(&klist->rcu, keyring_link_rcu_disposal);

ret = 0;
}

error2:
done:
ret = 0;
error2:
up_write(&keyring_serialise_link_sem);
error:
error:
return ret;

error3:
error3:
/* undo the quota changes */
key_payload_reserve(keyring,
keyring->datalen - KEYQUOTA_LINK_BYTES);
Expand Down Expand Up @@ -807,21 +863,6 @@ int key_link(struct key *keyring, struct key *key)

EXPORT_SYMBOL(key_link);

/*****************************************************************************/
/*
* dispose of a keyring list after the RCU grace period, freeing the unlinked
* key
*/
static void keyring_unlink_rcu_disposal(struct rcu_head *rcu)
{
struct keyring_list *klist =
container_of(rcu, struct keyring_list, rcu);

key_put(klist->keys[klist->delkey]);
kfree(klist);

} /* end keyring_unlink_rcu_disposal() */

/*****************************************************************************/
/*
* unlink the first link to a key from a keyring
Expand Down

0 comments on commit 1026672

Please sign in to comment.