⬢ DragonFlyBSD Kernel Audit
DF-3398 / fix.diff
← back to finding ↓ download raw
--- a/sys/net/ipfw3_nat/ip_fw3_nat.c	2026-09-12 05:04:10.941149910 +0000
+++ b/sys/net/ipfw3_nat/ip_fw3_nat.c	2026-09-12 05:04:20.617025464 +0000
@@ -212,7 +212,19 @@
 			break;
 		case IPPROTO_ICMP:
 			old_port = &L3HDR(struct icmp, ip)->icmp_id;
-			s2 = alias->icmp_in[*old_port];
+			/*
+			 * icmp_id is fully attacker controlled and in
+			 * network byte order; index the array with the
+			 * host-order value and bounds-check it (DF-3398
+			 * store-side companion; read-side bounds fix for
+			 * arbitrary ids, see also DF-0570).
+			 */
+			{
+				uint16_t idx = ntohs(*old_port);
+				if (idx >= ALIAS_RANGE)
+					goto oops;
+				s2 = alias->icmp_in[idx];
+			}
 			csum = &L3HDR(struct icmp, ip)->icmp_cksum;
 			break;
 		default:
@@ -323,7 +335,16 @@
 				s2->alias_addr = htonl(args->f_id.src_ip);
 				s2->alias_port = *old_port;
 
-				alias->icmp_in[s->alias_port] = s2;
+				/*
+				 * DF-3398: s->alias_port holds the htons()'d
+				 * residue; using it raw as the array index
+				 * walked up to 1024 slots (8 KiB) past the
+				 * end of the cfg_alias allocation on LE.
+				 * Index with the host-order residue instead,
+				 * which is always < ALIAS_RANGE.
+				 */
+				alias->icmp_in[s->src_addr * s->dst_addr %
+				    ALIAS_RANGE] = s2;
 				break;
 			default :
 				goto oops;