DF-3398 / fix.diff
--- 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; |