aboutsummaryrefslogtreecommitdiffstats
path: root/security/keys/request_key.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2005-06-24 01:00:49 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-24 03:05:18 -0400
commit76d8aeabfeb1c42641a81c44280177b9a08670d8 (patch)
tree0a584439bb44e440717aa77a1398ba9eea24a137 /security/keys/request_key.c
parent7286aa9b9ab35f20b1ff16d867f4535701df99b5 (diff)
[PATCH] keys: Discard key spinlock and use RCU for key payload
The attached patch changes the key implementation in a number of ways: (1) It removes the spinlock from the key structure. (2) The key flags are now accessed using atomic bitops instead of write-locking the key spinlock and using C bitwise operators. The three instantiation flags are dealt with with the construction semaphore held during the request_key/instantiate/negate sequence, thus rendering the spinlock superfluous. The key flags are also now bit numbers not bit masks. (3) The key payload is now accessed using RCU. This permits the recursive keyring search algorithm to be simplified greatly since no locks need be taken other than the usual RCU preemption disablement. Searching now does not require any locks or semaphores to be held; merely that the starting keyring be pinned. (4) The keyring payload now includes an RCU head so that it can be disposed of by call_rcu(). This requires that the payload be copied on unlink to prevent introducing races in copy-down vs search-up. (5) The user key payload is now a structure with the data following it. It includes an RCU head like the keyring payload and for the same reason. It also contains a data length because the data length in the key may be changed on another CPU whilst an RCU protected read is in progress on the payload. This would then see the supposed RCU payload and the on-key data length getting out of sync. I'm tempted to drop the key's datalen entirely, except that it's used in conjunction with quota management and so is a little tricky to get rid of. (6) Update the keys documentation. Signed-Off-By: David Howells <dhowells@redhat.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'security/keys/request_key.c')
-rw-r--r--security/keys/request_key.c32
1 files changed, 15 insertions, 17 deletions
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index 9705b1aeba5d..1f6c0940297f 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -105,7 +105,7 @@ static struct key *__request_key_construction(struct key_type *type,
105 struct key_construction cons; 105 struct key_construction cons;
106 struct timespec now; 106 struct timespec now;
107 struct key *key; 107 struct key *key;
108 int ret, negative; 108 int ret, negated;
109 109
110 /* create a key and add it to the queue */ 110 /* create a key and add it to the queue */
111 key = key_alloc(type, description, 111 key = key_alloc(type, description,
@@ -113,9 +113,7 @@ static struct key *__request_key_construction(struct key_type *type,
113 if (IS_ERR(key)) 113 if (IS_ERR(key))
114 goto alloc_failed; 114 goto alloc_failed;
115 115
116 write_lock(&key->lock); 116 set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags);
117 key->flags |= KEY_FLAG_USER_CONSTRUCT;
118 write_unlock(&key->lock);
119 117
120 cons.key = key; 118 cons.key = key;
121 list_add_tail(&cons.link, &key->user->consq); 119 list_add_tail(&cons.link, &key->user->consq);
@@ -130,7 +128,7 @@ static struct key *__request_key_construction(struct key_type *type,
130 128
131 /* if the key wasn't instantiated, then we want to give an error */ 129 /* if the key wasn't instantiated, then we want to give an error */
132 ret = -ENOKEY; 130 ret = -ENOKEY;
133 if (!(key->flags & KEY_FLAG_INSTANTIATED)) 131 if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
134 goto request_failed; 132 goto request_failed;
135 133
136 down_write(&key_construction_sem); 134 down_write(&key_construction_sem);
@@ -139,7 +137,7 @@ static struct key *__request_key_construction(struct key_type *type,
139 137
140 /* also give an error if the key was negatively instantiated */ 138 /* also give an error if the key was negatively instantiated */
141 check_not_negative: 139 check_not_negative:
142 if (key->flags & KEY_FLAG_NEGATIVE) { 140 if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) {
143 key_put(key); 141 key_put(key);
144 key = ERR_PTR(-ENOKEY); 142 key = ERR_PTR(-ENOKEY);
145 } 143 }
@@ -152,24 +150,23 @@ static struct key *__request_key_construction(struct key_type *type,
152 * - remove from construction queue 150 * - remove from construction queue
153 * - mark the key as dead 151 * - mark the key as dead
154 */ 152 */
155 negative = 0; 153 negated = 0;
156 down_write(&key_construction_sem); 154 down_write(&key_construction_sem);
157 155
158 list_del(&cons.link); 156 list_del(&cons.link);
159 157
160 write_lock(&key->lock);
161 key->flags &= ~KEY_FLAG_USER_CONSTRUCT;
162
163 /* check it didn't get instantiated between the check and the down */ 158 /* check it didn't get instantiated between the check and the down */
164 if (!(key->flags & KEY_FLAG_INSTANTIATED)) { 159 if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
165 key->flags |= KEY_FLAG_INSTANTIATED | KEY_FLAG_NEGATIVE; 160 set_bit(KEY_FLAG_NEGATIVE, &key->flags);
166 negative = 1; 161 set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
162 negated = 1;
167 } 163 }
168 164
169 write_unlock(&key->lock); 165 clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags);
166
170 up_write(&key_construction_sem); 167 up_write(&key_construction_sem);
171 168
172 if (!negative) 169 if (!negated)
173 goto check_not_negative; /* surprisingly, the key got 170 goto check_not_negative; /* surprisingly, the key got
174 * instantiated */ 171 * instantiated */
175 172
@@ -250,7 +247,7 @@ static struct key *request_key_construction(struct key_type *type,
250 247
251 for (;;) { 248 for (;;) {
252 set_current_state(TASK_UNINTERRUPTIBLE); 249 set_current_state(TASK_UNINTERRUPTIBLE);
253 if (!(ckey->flags & KEY_FLAG_USER_CONSTRUCT)) 250 if (!test_bit(KEY_FLAG_USER_CONSTRUCT, &ckey->flags))
254 break; 251 break;
255 schedule(); 252 schedule();
256 } 253 }
@@ -339,7 +336,8 @@ int key_validate(struct key *key)
339 if (key) { 336 if (key) {
340 /* check it's still accessible */ 337 /* check it's still accessible */
341 ret = -EKEYREVOKED; 338 ret = -EKEYREVOKED;
342 if (key->flags & (KEY_FLAG_REVOKED | KEY_FLAG_DEAD)) 339 if (test_bit(KEY_FLAG_REVOKED, &key->flags) ||
340 test_bit(KEY_FLAG_DEAD, &key->flags))
343 goto error; 341 goto error;
344 342
345 /* check it hasn't expired */ 343 /* check it hasn't expired */