[PATCH nf-next] netfilter: conntrack: sctp: validate vtag before state changes
Yizhou Zhao <[email protected]> Fri, 31 Jul 2026 22:53:41 +0800
| Newsgroups | gmane.linux.network,gmane.comp.security.firewalls.netfilter.devel,gmane.linux.kernel |
|---|---|
| Message-ID | <[email protected]> |
The packet-wide vtag check in nf_conntrack_sctp_packet() is skipped when the bundle map contains a chunk type with special vtag handling. The per-chunk path re-checks INIT, ABORT, SHUTDOWN_COMPLETE, and COOKIE_ECHO, but other state-changing chunks can still reach sctp_new_state() without validating sh->vtag. This lets a wrong-vtag packet bundle HEARTBEAT with COOKIE_ACK, ERROR, SHUTDOWN, or SHUTDOWN_ACK and update SCTP conntrack state. The resulting state can diverge from that of the SCTP association. Check sh->vtag before processing those chunks when conntrack already knows the expected direction vtag. This keeps the existing HEARTBEAT/HEARTBEAT_ACK learning and connection-reuse behavior for the `vtag == 0` cases. Reported-by: Yizhou Zhao <[email protected]> Reported-by: Yuxiang Yang <[email protected]> Reported-by: Ao Wang <[email protected]> Reported-by: Xuewei Feng <[email protected]> Reported-by: Qi Li <[email protected]> Reported-by: Ke Xu <[email protected]> Assisted-by: Claude Code:GLM-5.2 Suggested-by: Pablo Neira Ayuso <[email protected]> Link: https://lore.kernel.org/netfilter-devel/amx58O5Jb6B29XDJ@chamomile/ Signed-off-by: Yizhou Zhao <[email protected]> --- net/netfilter/nf_conntrack_proto_sctp.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c index 7e10fa65cbdd..9978ecd05b1e 100644 --- a/net/netfilter/nf_conntrack_proto_sctp.c +++ b/net/netfilter/nf_conntrack_proto_sctp.c @@ -407,9 +407,17 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct, /* (D) vtag must be same as init_vtag as found in INIT_ACK */ if (sh->vtag != ct->proto.sctp.vtag[dir]) goto out_unlock; - } else if (sch->type == SCTP_CID_COOKIE_ACK) { - ct->proto.sctp.init[dir] = 0; - ct->proto.sctp.init[!dir] = 0; + } else if (sch->type == SCTP_CID_COOKIE_ACK || + sch->type == SCTP_CID_ERROR || + sch->type == SCTP_CID_SHUTDOWN || + sch->type == SCTP_CID_SHUTDOWN_ACK) { + if (ct->proto.sctp.vtag[dir] && + sh->vtag != ct->proto.sctp.vtag[dir]) + goto out_unlock; + if (sch->type == SCTP_CID_COOKIE_ACK) { + ct->proto.sctp.init[dir] = 0; + ct->proto.sctp.init[!dir] = 0; + } } else if (sch->type == SCTP_CID_HEARTBEAT) { if (ct->proto.sctp.vtag[dir] == 0) { pr_debug("Setting %d vtag %x for dir %d\n", sch->type, sh->vtag, dir); -- 2.47.3