summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2007-02-21 01:20:05 +0100
committerAdrian Bunk <bunk@stusta.de>2007-02-21 01:20:05 +0100
commita0cd22f8e3a0cd4f6d8b08103629cbbc29a0c9fb (patch)
tree6af0e30e52857db7df8da35c290f12754b8b834c
parente48d2dd437e8f5c1fd4ae7ef8c77142e58491151 (diff)
Keys: Fix key serial number collision handling (CVE-2007-0006)
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, n 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 rathe than trying to be clever and attempting to work out the insertion point pointer directly. This fixes kernel Bugzilla #7727. Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Adrian Bunk <bunk@stusta.de>
-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 0e2584e11308..d364c3ca022d 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -186,6 +186,7 @@ static inline void key_alloc_serial(struct key *key)
key->serial = 3;
key_serial_next = key->serial + 1;
+attempt_insertion:
parent = NULL;
p = &key_serial_tree.rb_node;
@@ -200,40 +201,34 @@ static inline void key_alloc_serial(struct key *key)
else
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
* that point looking for the next unused serial number */
serial_exists:
for (;;) {
key->serial = key_serial_next;
- if (key->serial < 2)
- key->serial = 2;
+ if (key->serial < 3)
+ key->serial = 3;
key_serial_next = key->serial + 1;
-
- if (!parent->rb_parent)
- p = &key_serial_tree.rb_node;
- else if (parent->rb_parent->rb_left == parent)
- p = &parent->rb_parent->rb_left;
- else
- p = &parent->rb_parent->rb_right;
+ if (key->serial == 3)
+ goto attempt_insertion;
parent = rb_next(parent);
if (!parent)
- break;
+ goto attempt_insertion;
xkey = rb_entry(parent, struct key, serial_node);
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() */
/*****************************************************************************/