From: Xingyuan Mo <hdthky0@gmail.com>
To: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>,
Xin Long <lucien.xin@gmail.com>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Simon Horman <horms@kernel.org>
Cc: "open list:SCTP PROTOCOL" <linux-sctp@vger.kernel.org>,
"open list:NETWORKING [GENERAL]" <netdev@vger.kernel.org>,
Xingyuan Mo <hdthky0@gmail.com>
Subject: [PATCH v3] sctp: reject forged cookie peer_addr with unknown address family
Date: Thu, 17 Sep 2026 11:05:10 +0800 [thread overview]
Message-ID: <20260917030505.4176635-1-hdthky0@gmail.com> (raw)
When cookie authentication is disabled, COOKIE-ECHO peer_addr is
attacker-controlled. An invalid sa_family made sctp_get_af_specific()
return NULL and crash in sctp_transport_init() on
af_specific->sockaddr_len. Validate it with af->addr_valid() in
sctp_unpack_cookie(), which also rejects a mismatched family, e.g.
an AF_INET6 peer_addr on an IPv4 socket that would later crash in
sctp_v6_get_dst() on inet6_sk(sk)->opt. Validate a copy of peer_addr,
since addr_valid() rewrites a v4-mapped v6 address in
place and the cookie still lives in the received skb, which is not
guaranteed to be unshared.
For that, sctp_v6_addr_valid() has to return 0 when it is called with
a socket that is not PF_INET6, so that IPv6 addresses are never used
on IPv4 sockets. As addr_valid() now also checks sk_family and
ipv6_only_sock, simplify the address handling in sctp_process_param()
with it, as it additionally filters out non-unicast addresses. As a
side effect, a v4-mapped address in an IPv6 address parameter is now
normalised to AF_INET before the transport is created, matching what
the socket API paths already do.
Also add the missing !af check in sctp_process_init(), as
sctp_get_af_specific(AF_INET6) returns NULL on CONFIG_IPV6=n builds.
BUG: KASAN: null-ptr-deref in sctp_transport_new+0xa7/0x350
Read of size 4 at addr 00000000000000b4 by task poc/682
Call Trace:
<IRQ>
sctp_transport_new+0xa7/0x350
sctp_assoc_add_peer+0x153/0x850
sctp_process_init+0xf9/0x1180
sctp_sf_do_5_1D_ce+0x464/0xbc0
sctp_do_sm+0x114/0x2990
sctp_endpoint_bh_rcv+0x280/0x430
sctp_inq_push+0xdd/0x100
sctp_rcv+0x17f5/0x1ae0
sctp4_rcv+0x2b/0x40
ip_protocol_deliver_rcu+0x25b/0x270
ip_local_deliver+0xd1/0xe0
</IRQ>
Kernel panic - not syncing: Fatal exception in interrupt
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Assisted-by: opencode:deepseek-v4
Signed-off-by: Xingyuan Mo <hdthky0@gmail.com>
---
v2: https://lore.kernel.org/netdev/20260913113522.2674588-1-hdthky0@gmail.com/
- validate the forged cookie peer_addr with af->addr_valid() instead of
a family whitelist, and make sctp_v6_addr_valid() reject non-PF_INET6
sockets, so a forged AF_INET6 cookie can no longer crash an IPv4
socket in sctp_v6_get_dst() (found by Sashiko)
- simplify sctp_process_param() address handling with addr_valid(), as
addr_valid() now also checks sk_family and ipv6_only_sock
- add the missing !af check in sctp_process_init() for CONFIG_IPV6=n
builds (suggested by Xin Long)
v3: https://lore.kernel.org/netdev/20260915212917.3775248-1-hdthky0@gmail.com/
- drop the sctp_transport_new() check
- merge the !af checks into the conditions they guard with ||
- drop the comment above the sctp_unpack_cookie() check
net/sctp/ipv6.c | 3 +++
net/sctp/sm_make_chunk.c | 23 ++++++++++++-----------
2 files changed, 15 insertions(+), 11 deletions(-)
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index ef26878f1282..c45ac15f3b79 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -734,6 +734,9 @@ static int sctp_v6_addr_valid(union sctp_addr *addr,
{
int ret = ipv6_addr_type(&addr->v6.sin6_addr);
+ if (sp && sctp_opt2sk(sp)->sk_family != PF_INET6)
+ return 0;
+
/* Support v4-mapped-v6 address. */
if (ret == IPV6_ADDR_MAPPED) {
/* Note: This routine is used in input, so v4-mapped-v6
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 84a4c97d0f75..20c093894884 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -1732,7 +1732,9 @@ struct sctp_association *sctp_unpack_cookie(
struct sctp_cookie *bear_cookie;
struct sctp_chunkhdr *ch;
unsigned int len, chlen;
+ union sctp_addr paddr;
enum sctp_scope scope;
+ struct sctp_af *af;
ktime_t kt;
/* Header size is static data prior to the actual cookie, including
@@ -1841,6 +1843,11 @@ struct sctp_association *sctp_unpack_cookie(
goto fail;
}
+ paddr = bear_cookie->peer_addr;
+ af = sctp_get_af_specific(paddr.sa.sa_family);
+ if (!af || !af->addr_valid(&paddr, sctp_sk(ep->base.sk), NULL))
+ goto malformed;
+
/* Make a new base association. */
scope = sctp_scope(sctp_source(chunk));
retval = sctp_association_new(ep, ep->base.sk, scope, gfp);
@@ -2381,8 +2388,8 @@ int sctp_process_init(struct sctp_association *asoc, struct sctp_chunk *chunk,
(param.p->type == SCTP_PARAM_IPV4_ADDRESS ||
param.p->type == SCTP_PARAM_IPV6_ADDRESS)) {
af = sctp_get_af_specific(param_type2af(param.p->type));
- if (!af->from_addr_param(&addr, param.addr,
- chunk->sctp_hdr->source, 0))
+ if (!af || !af->from_addr_param(&addr, param.addr,
+ chunk->sctp_hdr->source, 0))
continue;
if (sctp_cmp_addr_exact(sctp_source(chunk), &addr))
src_match = 1;
@@ -2554,17 +2561,11 @@ static int sctp_process_param(struct sctp_association *asoc,
*/
switch (param.p->type) {
case SCTP_PARAM_IPV6_ADDRESS:
- if (PF_INET6 != asoc->base.sk->sk_family)
- break;
- goto do_addr_param;
-
case SCTP_PARAM_IPV4_ADDRESS:
- /* v4 addresses are not allowed on v6-only socket */
- if (ipv6_only_sock(asoc->base.sk))
- break;
-do_addr_param:
af = sctp_get_af_specific(param_type2af(param.p->type));
- if (!af->from_addr_param(&addr, param.addr, htons(asoc->peer.port), 0))
+ if (!af || !af->from_addr_param(&addr, param.addr,
+ htons(asoc->peer.port), 0) ||
+ !af->addr_valid(&addr, sctp_sk(asoc->base.sk), NULL))
break;
scope = sctp_scope(peer_addr);
if (sctp_in_scope(net, &addr, scope))
--
2.43.0
next reply other threads:[~2026-09-17 3:05 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-17 3:05 Xingyuan Mo [this message]
2026-09-21 3:25 ` [PATCH v3] sctp: reject forged cookie peer_addr with unknown address family netdev-bot+sashiko
2026-09-21 13:22 ` Xin Long
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260917030505.4176635-1-hdthky0@gmail.com \
--to=hdthky0@gmail.com \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-sctp@vger.kernel.org \
--cc=lucien.xin@gmail.com \
--cc=marcelo.leitner@gmail.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox