ICMP PULLUP_TO(hlen+4) reads icmp_id at hlen+4..hlen+5: 2-byte mbuf backing-store over-read on crafted short ICMP packets
Summary
ip_fw3_chk pulls up only 4 bytes of ICMP header PULLUP_TO(hlen+4) at :400 but reads icmp->icmp_id at :403 uint16_t spanning offsets hlen+4..hlen+5. For ICMP packet with 4-byte ICMP body (ip_len=hlen+4=24 for 20-byte IP header) reads 2 bytes past guaranteed m_len sourcing stale mbuf backing-store data into dst_port/src_port used for firewall matching. PULLUP_TO only guarantees m->m_len>=hlen+4. struct icmp has icmp_hun(icd_id) at offset 4..7. Remote-triggerable firewall misclassification primitive driven by kernel heap contents. pfil hook runs before ip_input validates ICMP length. [VERIFIED pass2: reproduced on live path - count rule matched exactly the 20 short 4-byte-ICMP packets after stale mbuf backing-store seeding, firewall classified on residue; pullup-deny fix A/B only legit matches remain]
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2577 Β· 1 files| File | Type | Description | Size | |
|---|---|---|---|---|
| fw3_icmp_oob.c | β | 2.8 KB | view raw |
Fix verification
not_testableConfirmed kernel references
Detail
Evidence (decisive lines)
fw3_icmp_oob run: rule 100 counter == exactly the 20 short packets; phase-0 control matched 0
PoC changes
real module (kldload) + raw-socket crafted ICMP + ipfw3 counters as the oracle
Verified recommended fix
PULLUP_TO(hlen + 8) for IPPROTO_ICMP (in the rebuilt ipfw3 module fix)
Verdict
ip_fw3_chk pulls up only hlen+4 for ICMP (ip_fw3.c:400) but reads icmp->icmp_id at hlen+4..hlen+5 (:403). Live-path proof on the stock kernel with ipfw3+ipfw3_basic kldloaded and rule 100 count icmp dst-port 4660: (1) 5 short ICMPs on a fresh boot matched NOTHING; (2) after 5 full echo requests with icmp_id=0x1234 warmed the mbuf backing store, ALL 20 short (4-byte-body) echo requests -- which contain NO icmp_id bytes at all -- matched rule 100. The firewall read the stale mbuf backing-store bytes and classified on them: remote-triggerable rule misclassification driven by kernel heap residue (src_port/dst_port are set from the same read). No bytes are returned to the sender, so no direct disclosure; impact is misclassification/bypass potential for icmp port-keyed rules.
No comments yet.