Commit dbd60d51 authored by David Howells's avatar David Howells Committed by Greg Kroah-Hartman

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: default avatarDavid Howells <dhowells@redhat.com>
Cc: Chuck Ebbert <cebbert@redhat.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent b3725e12
...@@ -188,6 +188,7 @@ static inline void key_alloc_serial(struct key *key) ...@@ -188,6 +188,7 @@ static inline void key_alloc_serial(struct key *key)
spin_lock(&key_serial_lock); spin_lock(&key_serial_lock);
attempt_insertion:
parent = NULL; parent = NULL;
p = &key_serial_tree.rb_node; p = &key_serial_tree.rb_node;
...@@ -202,39 +203,33 @@ static inline void key_alloc_serial(struct key *key) ...@@ -202,39 +203,33 @@ static inline void key_alloc_serial(struct key *key)
else else
goto serial_exists; goto serial_exists;
} }
goto insert_here;
/* we've found a suitable hole - arrange for this key to occupy it */
rb_link_node(&key->serial_node, parent, p);
rb_insert_color(&key->serial_node, &key_serial_tree);
spin_unlock(&key_serial_lock);
return;
/* we found a key with the proposed serial number - walk the tree from /* we found a key with the proposed serial number - walk the tree from
* that point looking for the next unused serial number */ * that point looking for the next unused serial number */
serial_exists: serial_exists:
for (;;) { for (;;) {
key->serial++; key->serial++;
if (key->serial < 2) if (key->serial < 3) {
key->serial = 2; key->serial = 3;
goto attempt_insertion;
if (!rb_parent(parent)) }
p = &key_serial_tree.rb_node;
else if (rb_parent(parent)->rb_left == parent)
p = &(rb_parent(parent)->rb_left);
else
p = &(rb_parent(parent)->rb_right);
parent = rb_next(parent); parent = rb_next(parent);
if (!parent) if (!parent)
break; goto attempt_insertion;
xkey = rb_entry(parent, struct key, serial_node); xkey = rb_entry(parent, struct key, serial_node);
if (key->serial < xkey->serial) if (key->serial < xkey->serial)
goto insert_here; goto attempt_insertion;
} }
/* we've found a suitable hole - arrange for this key to occupy it */
insert_here:
rb_link_node(&key->serial_node, parent, p);
rb_insert_color(&key->serial_node, &key_serial_tree);
spin_unlock(&key_serial_lock);
} /* end key_alloc_serial() */ } /* end key_alloc_serial() */
/*****************************************************************************/ /*****************************************************************************/
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment