DragonFlyBSD Kernel Audit
DF-2455 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/disk/fd/fd.c b/sys/dev/disk/fd/fd.c
--- a/sys/dev/disk/fd/fd.c
+++ b/sys/dev/disk/fd/fd.c
@@ -2326,7 +2326,25 @@
 		/* this is considered harmful; only allow for superuser */
 		if (caps_priv_check(ap->a_cred, SYSCAP_RESTRICTEDROOT))
 			return EPERM;
-		fd->ft = *(struct fd_type *)ap->a_data;
+		/*
+		 * Validate the caller-supplied type before installing it.
+		 * sectrac and heads are used as divisors (d_secpercyl =
+		 * sectrac*heads; d_ncylinders = size / d_secpercyl; and
+		 * blknum/(sectrac*heads), sec/sectrac in fdstate), and
+		 * secsize is a left-shift count (128 << secsize).  Without
+		 * these checks a planted type with sectrac==0 or heads==0
+		 * arms a kernel divide-by-zero trap on the next open/I/O,
+		 * and secsize>=25 (signed overflow) / >=32 (shift >= width)
+		 * is undefined behaviour.
+		 */
+		{
+			struct fd_type *nft = (struct fd_type *)ap->a_data;
+			if (nft->sectrac <= 0 || nft->heads <= 0 ||
+			    nft->secsize < 0 || nft->secsize > 7) {
+				return EINVAL;
+			}
+			fd->ft = *nft;
+		}
 		break;
 
 	case FD_GOPTS:			/* get drive options */