lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Date:	Fri, 9 Feb 2007 09:55:38 -0600
From:	Matt Mitchell <matt@...oritemo.com>
To:	Matt Mitchell <mmitchell@...tualproperties.com>
Subject: [PATCH] security/keys: correct handling of key->serial collisions

The randomized key->serial choice algorithm introduced in 2.6.18  
exposed some bugs in the handling of collisions in the rbtree of  
allocated key->serials.  Collisions then resulted in eventual kernel  
oopses (due to rbtree corruption) once cleanup was attempted.  This  
patch corrects the collision handling to behave correctly.   
Additionally, the (admittedly unlikely) scenario in which there are  
no more key->serials available results in a return of -ENOMEM rather  
than an oops.

Signed-off-by: Matt Mitchell <matt@...oritemo.com>
---
The collision resolution procedure works like the old one was  
intended to -- if you get a collision on your random serial  
selection, try the next serial (wrapping at 2^31) until you either  
(a) find a hole or (b) wrap completely around the keyspace.  Since  
the keyspace is 2^31, collisions are fairly rare -- however, with  
certain workloads, they happen with some frequency.  Samba in  
particular is a common culprit among those of us that ran across this  
bug due to its need to masquerade as many users (and therefore create  
lots of session keyrings and the like).

This patch could/should be applied to 2.6.18 and 2.6.19 as well.

diff --git a/security/keys/key.c b/security/keys/key.c
index 700400d..bdc7837 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -178,17 +178,21 @@ static inline void key_alloc_serial(struct key  
*key)
	struct rb_node *parent, **p;
	struct key *xkey;
+	key_serial_t orig;
+	int keyspace_loop;
+
	/* propose a random serial number and look for a hole for it in the
	 * serial number tree */
	do {
		get_random_bytes(&key->serial, sizeof(key->serial));
		key->serial >>= 1; /* negative numbers are not permitted */
+		orig = key->serial;
+		keyspace_loop = 0;
	} while (key->serial < 3);
	spin_lock(&key_serial_lock);
-attempt_insertion:
	parent = NULL;
	p = &key_serial_tree.rb_node;
@@ -200,8 +204,26 @@ attempt_insertion:
			p = &(*p)->rb_left;
		else if (key->serial > xkey->serial)
			p = &(*p)->rb_right;
-		else
-			goto serial_exists;
+		else {	
+			/* if we have already looped, check for exhausted
+			 * keyspace */
+			if ((keyspace_loop == 1) && (key->serial >= orig)) {
+				/* this is just a dummy */
+				key->serial = -1;
+				spin_unlock(&key_serial_lock);
+				printk(KERN_WARNING "key_alloc_serial: "
+						"keyspace exhausted\n");
+				return;
+			}
+
+			key->serial++;
+			if (key->serial < 2) {
+				keyspace_loop = 1;
+				key->serial = 2;
+			}
+			parent = NULL;
+			p = &key_serial_tree.rb_node;
+		}
	}
	/* we've found a suitable hole - arrange for this key to occupy it */
@@ -209,26 +231,6 @@ attempt_insertion:
	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++;
-		if (key->serial < 3) {
-			key->serial = 3;
-			goto attempt_insertion;
-		}
-
-		parent = rb_next(parent);
-		if (!parent)
-			goto attempt_insertion;
-
-		xkey = rb_entry(parent, struct key, serial_node);
-		if (key->serial < xkey->serial)
-			goto attempt_insertion;
-	}
} /* end key_alloc_serial() */
@@ -319,9 +321,14 @@ struct key *key_alloc(struct key_type *type,  
const char *desc,
		goto security_error;
	/* publish the key by giving it a serial number */
-	atomic_inc(&user->nkeys);
	key_alloc_serial(key);
+	/* check for success */
+	if (key->serial == -1)
+		goto no_memory_3;
+	else
+		atomic_inc(&user->nkeys);
+
error:
	return key;


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists