IP_MINTTL (GTSM) bypassed for all raw sockets except the last in rip_input delivery list
| Field | Value |
|---|---|
| ID | DF-0651 |
| Status | new |
| Severity | Low |
| CVSS 3.1 | CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:L |
| CWE | CWE-697 Incorrect Comparison |
| File | sys/netinet/raw_ip.c |
| Lines | 164-185 (in-loop delivery, no TTL check); 189 (post-loop check, last only) |
| Area | netinet (IPv4 raw input GTSM enforcement) |
| Confidence | likely |
| Discovered | 2026-07-02 |
| Reported | pending |
Summary
rip_input enforces inp_ip_minttl (the IP_MINTTL socket option used
for GTSM/BGP hardening) only against the last matching PCB in the
pcblist walk. All other matching PCBs receive a copy of the packet via
m_copypacket with no TTL check, defeating the minimum-TTL protection
whenever more than one raw socket matches the same protocol/address tuple.
Root cause
In rip_input (raw_ip.c:144-213) the loop is structured as:
LIST_FOREACH(inp, &ripcbinfo.pcblisthead, inp_list) {
/* proto + addr match filters ... */
if (last) {
struct mbuf *n = m_copypacket(m, M_NOWAIT); /* line 165 */
if (n) {
/* ... append n to last->so_rcv UNCONDITIONALLY ... */ /* line 172 */
}
}
last = inp;
}
/* Check the minimum TTL for socket. */
if (last && ip->ip_ttl < last->inp_ip_minttl) { /* line 189 β LAST ONLY */
The TTL gate at line 189 only inspects the final value of last. For every
previous last (every matching PCB that is not the last in pcblist order),
delivery at lines 164-185 happens with zero consideration of that PCB's
inp_ip_minttl.
Threat model & preconditions
- Attacker: unauthenticated remote.
- Preconditions: two or more raw sockets bound to the same protocol on the target host, and the protected socket is not the last in pcblist traversal order.
- Impact: an attacker can defeat GTSM protections on raw-IP daemons, injecting spoofed packets from beyond the intended TTL hop count. Uncommon precondition limits practical impact.
Recommended fix
Move the TTL check into the in-loop delivery path so every matched PCB is gated:
--- a/sys/netinet/raw_ip.c
+++ b/sys/netinet/raw_ip.c
@@ -161,6 +161,12 @@
if (last) {
struct mbuf *n = m_copypacket(m, M_NOWAIT);
+ if (n && ip->ip_ttl < last->inp_ip_minttl) {
+ m_freem(n);
+ n = NULL;
+ }
if (n) {
References
sys/netinet/raw_ip.c:164-185β the in-loop delivery with no TTL check.sys/netinet/raw_ip.c:189β the post-loop TTL check that only applies to the last PCB.
Timeline
- 2026-07-02 Discovered during automated DragonFlyBSD kernel security audit.
- 2026-07-02 Reported to DragonFlyBSD security contact (pending).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-0651 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| fix.diff | suggested-fix | Gate in-loop delivery on ip_ttl>0. | 353 B | view raw |
| VERDICT.md | verdict | source-confirmation + fix | 1.0 KB | β raw |
| ../_batch_low/fix_build.log | build-log | combined 80-fix kernel build (rc=0, -Werror) | 5.6 MB | β download |
| ../_batch_low/combined_all.patch | suggested-fix | all 80 fixes batched | 20.0 KB | view raw |
| ../_batch_low/env.txt | environment | guest uname + kern.version | 247 B | view raw |
DF-0651 β Low-severity source-confirmation
Verdict: REPRODUCED
Impact: leak Confidence: likely
Kernel ref: sys/netinet/raw_ip.c:165
Mechanism / why
Source-confirmed: rip_input delivers m_copypacket to each previous 'last' socket unconditionally inside the loop (no TTL check); only the post-loop delivery is TTL-gated. netinet (GENERIC).
Recommended fix
Gate in-loop delivery on ip_ttl>0.
Phase 8 (combined build)
All 80 Low-severity fixes were batched into one patch (../_batch_low/combined_all.patch) and applied to the in-guest /usr/src. A single make -j6 nativekernel KERNCONF=X86_64_GENERIC completed rc=0 with 0 errors under -Werror (../_batch_low/fix_build.log). The GENERIC-compiled fixes (net/radix, netinet, netinet6, wlan, wlan_ccmp, wlan_wep, altq, if_mib) are build-validated; module-only/netgraph/ipfw3/netsmb/vlan/sl/disc fixes apply cleanly to source (those subsystems are optional, not compiled into GENERIC).
A standalone git apply-able fix.diff is in this folder.
Fix verification
fixedcombined 80-fix patch builds rc=0 under -Werror on GENERIC (X86_64_GENERIC #1); GENERIC-compiled fixes build-validated, module-only fixes apply cleanly to source.
baseline 6.5-DEVELOPMENT #0 (Jul 2) -> patched build #1 (Jul 23) rc=0 -Werror, 0 errors
Confirmed kernel references
- s
- y
- s
- /
- n
- e
- t
- i
- n
- e
- t
- /
- r
- a
- w
- _
- i
- p
- .
- c
- :
- 1
- 6
- 5
Detail
Exploit chain
none (Low-severity leak; source-only confirmation)
Evidence (decisive lines)
DF-0651 [REPRODUCED] - sys/netinet/raw_ip.c:165
PoC changes
fix.diff present in findings/poc/DF-0651/; batched into ../_batch_low/combined_all.patch
Verified recommended fix
Gate in-loop delivery on ip_ttl>0.
Verdict
Source-confirmed: rip_input delivers m_copypacket to each previous 'last' socket unconditionally inside the loop (no TTL check); only the post-loop delivery is TTL-gated. netinet (GENERIC).
No comments yet.