DragonFlyBSD Kernel Audit
DF-2797 / fix.diff
← back to finding ↓ download raw
--- a/sys/kern/subr_alist.c
+++ b/sys/kern/subr_alist.c
@@ -146,6 +146,9 @@
 	alist_blk_t radix;
 	alist_blk_t skip = 0;
 
+	if (blocks == 0 || blocks > ALIST_BLOCKS_MAX)
+		return(NULL);
+
 	/*
 	 * Calculate radix and skip field used for scanning.
 	 */
@@ -190,6 +193,9 @@
 	alist_blk_t radix;
 	alist_blk_t skip = 0;
 
+	if (blocks == 0 || blocks > ALIST_BLOCKS_MAX)
+		panic("alist_init: invalid block count %d", blocks);
+
 	/*
 	 * Calculate radix and skip field used for scanning.
 	 */
@@ -245,9 +251,12 @@
 	alist_blk_t blk = ALIST_BLOCK_NONE;
 
 	/*
-	 * Check non power-of-2
+	 * Check non power-of-2.  NOTE: count == 0 must be rejected
+	 * explicitly, the power-of-2 test below cannot distinguish it
+	 * and the allocator arithmetic is undefined for it.
 	 */
-	KKASSERT(count);
+	if (count == 0)
+		return(ALIST_BLOCK_NONE);
 	if ((count | (count - 1)) != (count << 1) - 1) {
 		alist_blk_t ncount = (count < 256) ? 1 : 256;
 		while (ncount < count)
@@ -261,7 +270,7 @@
 	/*
 	 * Power of 2
 	 */
-	if (bl && count < bl->bl_radix) {
+	if (bl && count <= bl->bl_radix) {
 		if (bl->bl_radix == ALIST_BMAP_RADIX) {
 			blk = alst_leaf_alloc(bl->bl_root, 0, start, count);
 		} else {
--- a/sys/sys/alist.h
+++ b/sys/sys/alist.h
@@ -92,6 +92,12 @@
 #define ALIST_BLOCK_NONE	((alist_blk_t)-1)
 
 /*
+ * Largest block count whose radix computation cannot wrap
+ * (32 * 16^6 = 2^29; anything larger overflows alist_blk_t).
+ */
+#define ALIST_BLOCKS_MAX	((alist_blk_t)1 << 29)
+
+/*
  * When alist_init() is used the caller can pre-allocate the records
  * array.
  */