aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2007-02-06 08:45:51 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-06 17:45:00 -0500
commit9ad0830f307bcd8dc285cfae58998d43b21727f4 (patch)
tree237119861640847301c6af758650b05ea353a1da
parent768c242b30d9ec5581dd245e8289acb6b77815d1 (diff)
[PATCH] Keys: Fix key serial number collision handling
Fix the key serial number collision avoidance code in key_alloc_serial(). This didn't use to be so much of a problem as the key serial numbers were allocated from a simple incremental counter, and it would have to go through two billion keys before it could possibly encounter a collision. However, now that random numbers are used instead, collisions are much more likely. This is fixed by finding a hole in the rbtree where the next unused serial number ought to be and using that by going almost back to the top of the insertion routine and redoing the insertion with the new serial number rather than trying to be clever and attempting to work out the insertion point pointer directly. This fixes kernel BZ #7727. Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--security/keys/key.c33
1 files changed, 14 insertions, 19 deletions
diff --git a/security/keys/key.c b/security/keys/key.c
index ac9326c5f1da..700400d801dc 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -188,6 +188,7 @@ static inline void key_alloc_serial(struct key *key)
188 188
189 spin_lock(&key_serial_lock); 189 spin_lock(&key_serial_lock);
190 190
191attempt_insertion:
191 parent = NULL; 192 parent = NULL;
192 p = &key_serial_tree.rb_node; 193 p = &key_serial_tree.rb_node;
193 194
@@ -202,39 +203,33 @@ static inline void key_alloc_serial(struct key *key)
202 else 203 else
203 goto serial_exists; 204 goto serial_exists;
204 } 205 }
205 goto insert_here; 206
207 /* we've found a suitable hole - arrange for this key to occupy it */
208 rb_link_node(&key->serial_node, parent, p);
209 rb_insert_color(&key->serial_node, &key_serial_tree);
210
211 spin_unlock(&key_serial_lock);
212 return;
206 213
207 /* we found a key with the proposed serial number - walk the tree from 214 /* we found a key with the proposed serial number - walk the tree from
208 * that point looking for the next unused serial number */ 215 * that point looking for the next unused serial number */
209serial_exists: 216serial_exists:
210 for (;;) { 217 for (;;) {
211 key->serial++; 218 key->serial++;
212 if (key->serial < 2) 219 if (key->serial < 3) {
213 key->serial = 2; 220 key->serial = 3;
214 221 goto attempt_insertion;
215 if (!rb_parent(parent)) 222 }
216 p = &key_serial_tree.rb_node;
217 else if (rb_parent(parent)->rb_left == parent)
218 p = &(rb_parent(parent)->rb_left);
219 else
220 p = &(rb_parent(parent)->rb_right);
221 223
222 parent = rb_next(parent); 224 parent = rb_next(parent);
223 if (!parent) 225 if (!parent)
224 break; 226 goto attempt_insertion;
225 227
226 xkey = rb_entry(parent, struct key, serial_node); 228 xkey = rb_entry(parent, struct key, serial_node);
227 if (key->serial < xkey->serial) 229 if (key->serial < xkey->serial)
228 goto insert_here; 230 goto attempt_insertion;
229 } 231 }
230 232
231 /* we've found a suitable hole - arrange for this key to occupy it */
232insert_here:
233 rb_link_node(&key->serial_node, parent, p);
234 rb_insert_color(&key->serial_node, &key_serial_tree);
235
236 spin_unlock(&key_serial_lock);
237
238} /* end key_alloc_serial() */ 233} /* end key_alloc_serial() */
239 234
240/*****************************************************************************/ 235/*****************************************************************************/