diff options
author | Dave Airlie <airlied@redhat.com> | 2010-05-19 09:35:51 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2010-05-19 09:35:51 +1000 |
commit | 05ea893c46805b2981ea8ba6df881e3d65edd63b (patch) | |
tree | ea381e22d99f49bd2c95238f88491d48b797a17b /security/keys/keyring.c | |
parent | 26481fb15644b5fd85d4cea020f74a234cdf6803 (diff) | |
parent | a7c542782e92f9487c62a571565637be3d6b0ffd (diff) |
Merge remote branch 'anholt/drm-intel-next' into drm-next
* anholt/drm-intel-next: (515 commits)
drm/i915: Fix out of tree builds
drm/i915: move fence lru to struct drm_i915_fence_reg
drm/i915: don't allow tiling changes on pinned buffers v2
drm/i915: Be extra careful about A/D matching for multifunction SDVO
drm/i915: Fix DDC bus selection for multifunction SDVO
drm/i915: cleanup mode setting before unmapping registers
drm/i915: Make fbc control wrapper functions
drm/i915: Wait for the GPU whilst shrinking, if truly desperate.
drm/i915: Use spatio-temporal dithering on PCH
[MTD] Remove zero-length files mtdbdi.c and internal.ho
pata_pcmcia / ide-cs: Fix bad hashes for Transcend and kingston IDs
libata: Fix several inaccuracies in developer's guide
slub: Fix bad boundary check in init_kmem_cache_nodes()
raid6: fix recovery performance regression
KEYS: call_sbin_request_key() must write lock keyrings before modifying them
KEYS: Use RCU dereference wrappers in keyring key type code
KEYS: find_keyring_by_name() can gain access to a freed keyring
ALSA: hda: Fix 0 dB for Packard Bell models using Conexant CX20549 (Venice)
ALSA: hda - Add quirk for Dell Inspiron 19T using a Conexant CX20582
ALSA: take tu->qlock with irqs disabled
...
Diffstat (limited to 'security/keys/keyring.c')
-rw-r--r-- | security/keys/keyring.c | 41 |
1 files changed, 22 insertions, 19 deletions
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index e814d2109f8e..1e4b0037935c 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c @@ -20,6 +20,11 @@ #include <asm/uaccess.h> #include "internal.h" +#define rcu_dereference_locked_keyring(keyring) \ + (rcu_dereference_protected( \ + (keyring)->payload.subscriptions, \ + rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem))) + /* * when plumbing the depths of the key tree, this sets a hard limit set on how * deep we're willing to go @@ -201,8 +206,7 @@ static long keyring_read(const struct key *keyring, int loop, ret; ret = 0; - klist = rcu_dereference(keyring->payload.subscriptions); - + klist = rcu_dereference_locked_keyring(keyring); if (klist) { /* calculate how much data we could return */ qty = klist->nkeys * sizeof(key_serial_t); @@ -526,9 +530,8 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check) struct key *keyring; int bucket; - keyring = ERR_PTR(-EINVAL); if (!name) - goto error; + return ERR_PTR(-EINVAL); bucket = keyring_hash(name); @@ -555,17 +558,18 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check) KEY_SEARCH) < 0) continue; - /* we've got a match */ - atomic_inc(&keyring->usage); - read_unlock(&keyring_name_lock); - goto error; + /* we've got a match but we might end up racing with + * key_cleanup() if the keyring is currently 'dead' + * (ie. it has a zero usage count) */ + if (!atomic_inc_not_zero(&keyring->usage)) + continue; + goto out; } } - read_unlock(&keyring_name_lock); keyring = ERR_PTR(-ENOKEY); - - error: +out: + read_unlock(&keyring_name_lock); return keyring; } /* end find_keyring_by_name() */ @@ -720,8 +724,7 @@ int __key_link(struct key *keyring, struct key *key) } /* see if there's a matching key we can displace */ - klist = keyring->payload.subscriptions; - + klist = rcu_dereference_locked_keyring(keyring); if (klist && klist->nkeys > 0) { struct key_type *type = key->type; @@ -765,8 +768,6 @@ int __key_link(struct key *keyring, struct key *key) if (ret < 0) goto error2; - klist = keyring->payload.subscriptions; - if (klist && klist->nkeys < klist->maxkeys) { /* there's sufficient slack space to add directly */ atomic_inc(&key->usage); @@ -868,7 +869,7 @@ int key_unlink(struct key *keyring, struct key *key) down_write(&keyring->sem); - klist = keyring->payload.subscriptions; + klist = rcu_dereference_locked_keyring(keyring); if (klist) { /* search the keyring for the key */ for (loop = 0; loop < klist->nkeys; loop++) @@ -959,7 +960,7 @@ int keyring_clear(struct key *keyring) /* detach the pointer block with the locks held */ down_write(&keyring->sem); - klist = keyring->payload.subscriptions; + klist = rcu_dereference_locked_keyring(keyring); if (klist) { /* adjust the quota */ key_payload_reserve(keyring, @@ -991,7 +992,9 @@ EXPORT_SYMBOL(keyring_clear); */ static void keyring_revoke(struct key *keyring) { - struct keyring_list *klist = keyring->payload.subscriptions; + struct keyring_list *klist; + + klist = rcu_dereference_locked_keyring(keyring); /* adjust the quota */ key_payload_reserve(keyring, 0); @@ -1025,7 +1028,7 @@ void keyring_gc(struct key *keyring, time_t limit) down_write(&keyring->sem); - klist = keyring->payload.subscriptions; + klist = rcu_dereference_locked_keyring(keyring); if (!klist) goto no_klist; |