DragonFlyBSD Kernel Audit
DF-0701 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/net/ipfw3_basic/ip_fw3_sync.c b/sys/net/ipfw3_basic/ip_fw3_sync.c
--- a/sys/net/ipfw3_basic/ip_fw3_sync.c
+++ b/sys/net/ipfw3_basic/ip_fw3_sync.c
@@ -137,19 +137,31 @@
 ip_fw3_ctl_sync_centre_conf(struct sockopt *sopt)
 {
 	struct ipfw3_ioc_sync_centre *ioc_centre;
-	int size;
+	size_t size, need;
 
 	ioc_centre = sopt->sopt_val;
-	size = ioc_centre->count * LEN_SYNC_EDGE;
+	/* DF-0701: validate count vs MAX_EDGES (centre_socks[] bound) and vs
+	   sopt_valsize (user buffer only holds sopt_valsize bytes; old bcopy read
+	   count*LEN_SYNC_EDGE off the end of sopt_val). size_t so count*LEN_SYNC_EDGE
+	   cannot wrap a signed int and cause a tiny kmalloc + huge bcopy. */
+	if (ioc_centre->count < 0 || ioc_centre->count > MAX_EDGES)
+		return EINVAL;
+	need = sizeof(*ioc_centre) + (size_t)ioc_centre->count * LEN_SYNC_EDGE;
+	if (sopt->sopt_valsize < need)
+		return EINVAL;
+	size = (size_t)ioc_centre->count * LEN_SYNC_EDGE;
 	if (fw3_sync_ctx.count == 0) {
 		fw3_sync_ctx.edges = kmalloc(size, M_IPFW3_SYNC, M_NOWAIT | M_ZERO);
 	} else {
 		fw3_sync_ctx.edges = krealloc(fw3_sync_ctx.edges,
 				size, M_TEMP, M_WAITOK);
 	}
+	if (fw3_sync_ctx.edges == NULL) {
+		fw3_sync_ctx.count = 0;
+		return ENOMEM;
+	}
 	fw3_sync_ctx.count = ioc_centre->count;
-	bcopy(ioc_centre->edges, fw3_sync_ctx.edges,
-			ioc_centre->count * LEN_SYNC_EDGE);
+	bcopy(ioc_centre->edges, fw3_sync_ctx.edges, size);
 	return 0;
 }