⬢ DragonFlyBSD Kernel Audit
DF-2606 / fix.diff
← back to finding ↓ download raw
--- a/sys/vfs/hammer2/hammer2_chain.c
+++ b/sys/vfs/hammer2/hammer2_chain.c
@@ -938,6 +938,24 @@
 	if ((chain->bref.data_off & ~HAMMER2_OFF_MASK_RADIX) == 0)
 		return;
 
+	/*
+	 * Media integrity check.  keybits must be 0..63.  A larger value
+	 * cannot encode a valid radix for a 64-bit key and makes every
+	 * (hammer2_key_t)1 << keybits computation in the chain code
+	 * undefined behavior.  Refuse to load the chain.
+	 */
+	if (chain->bref.keybits > 63) {
+		krateprintf(&krate_h2chk,
+			"chain %016jx.%02x (%s) keybits=%d CHECK FAIL "
+			"(> 63, illegal radix)\n",
+			chain->bref.data_off,
+			chain->bref.type,
+			hammer2_bref_type_str(chain->bref.type),
+			chain->bref.keybits);
+		chain->error = HAMMER2_ERROR_CHECK;
+		return;
+	}
+
 	hmp = chain->hmp;
 	KKASSERT(hmp != NULL);
 
@@ -4974,6 +4992,19 @@
 	 */
 	while (i < count) {
 		if (scan->type != HAMMER2_BREF_TYPE_EMPTY) {
+			/*
+			 * Media integrity check.  keybits > 63 is illegal
+			 * (it cannot encode a radix for a 64-bit key) and
+			 * any range computed from it would be undefined
+			 * behavior.  Skip the entry entirely.
+			 */
+			if (scan->keybits > 63) {
+				if (i >= limit)
+					return (count);
+				++scan;
+				++i;
+				continue;
+			}
 			scan_end = scan->key +
 				   ((hammer2_key_t)1 << scan->keybits) - 1;
 			if (scan->key > key_beg || scan_end >= key_beg)
@@ -5353,6 +5384,12 @@
 	key_next = 0;
 	for (l = 0; l < count; ++l) {
 		if (base[l].type != HAMMER2_BREF_TYPE_EMPTY) {
+			/*
+			 * Illegal radix; ordering cannot be checked without
+			 * undefined behavior (see hammer2_base_find).
+			 */
+			if (base[l].keybits > 63)
+				continue;
 			key_next = base[l].key +
 				   ((hammer2_key_t)1 << base[l].keybits) - 1;
 			break;
@@ -5362,6 +5399,12 @@
 		if (base[l].type != HAMMER2_BREF_TYPE_EMPTY) {
 			if (base[l].key <= key_next)
 				panic("base_insert %d %d,%d,%d fail %p:%d", u, i, j, k, base, l);
+			/*
+			 * Illegal radix; do not update key_next (would be
+			 * undefined behavior, see hammer2_base_find).
+			 */
+			if (base[l].keybits > 63)
+				continue;
 			key_next = base[l].key +
 				   ((hammer2_key_t)1 << base[l].keybits) - 1;