* [PATCH v2] sctp: reject forged cookie peer_addr with unknown address family
@ 2026-09-15 21:29 Xingyuan Mo
2026-09-16 1:02 ` Xin Long
2026-09-19 1:36 ` netdev-bot+sashiko
0 siblings, 2 replies; 3+ messages in thread
From: Xingyuan Mo @ 2026-09-15 21:29 UTC (permalink / raw)
To: Marcelo Ricardo Leitner, Xin Long, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman
Cc: open list:SCTP PROTOCOL, open list:NETWORKING [GENERAL],
Xingyuan Mo
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, and bail in
sctp_transport_new() if af_specific is missing. 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>
---
Changes since v1 [1]:
- 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)
[1] https://lore.kernel.org/netdev/20260913113522.2674588-1-hdthky0@gmail.com/
net/sctp/ipv6.c | 3 +++
net/sctp/sm_make_chunk.c | 25 +++++++++++++++++--------
net/sctp/transport.c | 3 +++
3 files changed, 23 insertions(+), 8 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..cfc4973f4d4a 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,15 @@ struct sctp_association *sctp_unpack_cookie(
goto fail;
}
+ /* peer_addr is peer-controlled when cookie authentication is
+ * disabled. Validate a copy, as addr_valid() may rewrite a
+ * v4-mapped address in place.
+ */
+ 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,6 +2392,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)
+ continue;
if (!af->from_addr_param(&addr, param.addr,
chunk->sctp_hdr->source, 0))
continue;
@@ -2554,18 +2567,14 @@ 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)
+ break;
if (!af->from_addr_param(&addr, param.addr, htons(asoc->peer.port), 0))
break;
+ if (!af->addr_valid(&addr, sctp_sk(asoc->base.sk), NULL))
+ break;
scope = sctp_scope(peer_addr);
if (sctp_in_scope(net, &addr, scope))
if (!sctp_assoc_add_peer(asoc, &addr, gfp, SCTP_UNCONFIRMED))
diff --git a/net/sctp/transport.c b/net/sctp/transport.c
index 6ea55b9fbde4..cd1a604d6f8e 100644
--- a/net/sctp/transport.c
+++ b/net/sctp/transport.c
@@ -92,6 +92,9 @@ struct sctp_transport *sctp_transport_new(struct net *net,
{
struct sctp_transport *transport;
+ if (!sctp_get_af_specific(addr->sa.sa_family))
+ return NULL;
+
transport = kzalloc_obj(*transport, gfp);
if (!transport)
return NULL;
--
2.43.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH v2] sctp: reject forged cookie peer_addr with unknown address family
2026-09-15 21:29 [PATCH v2] sctp: reject forged cookie peer_addr with unknown address family Xingyuan Mo
@ 2026-09-16 1:02 ` Xin Long
2026-09-19 1:36 ` netdev-bot+sashiko
1 sibling, 0 replies; 3+ messages in thread
From: Xin Long @ 2026-09-16 1:02 UTC (permalink / raw)
To: Xingyuan Mo
Cc: Marcelo Ricardo Leitner, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman,
open list:SCTP PROTOCOL, open list:NETWORKING [GENERAL]
On Tue, Sep 15, 2026 at 5:29 PM Xingyuan Mo <hdthky0@gmail.com> wrote:
>
> 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, and bail in
> sctp_transport_new() if af_specific is missing. 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>
> ---
>
> Changes since v1 [1]:
> - 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)
>
> [1] https://lore.kernel.org/netdev/20260913113522.2674588-1-hdthky0@gmail.com/
>
> net/sctp/ipv6.c | 3 +++
> net/sctp/sm_make_chunk.c | 25 +++++++++++++++++--------
> net/sctp/transport.c | 3 +++
> 3 files changed, 23 insertions(+), 8 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..cfc4973f4d4a 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,15 @@ struct sctp_association *sctp_unpack_cookie(
> goto fail;
> }
>
> + /* peer_addr is peer-controlled when cookie authentication is
> + * disabled. Validate a copy, as addr_valid() may rewrite a
> + * v4-mapped address in place.
> + */
af->addr_valid() is more like ensuring the address is a unicast address
and the socket supports the address family. You can either improve
the inline comment above or just remove it.
> + 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,6 +2392,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)
> + continue;
> if (!af->from_addr_param(&addr, param.addr,
> chunk->sctp_hdr->source, 0))
> continue;
You can merge these 2 checks with (!af || !af->from_addr_param()).
> @@ -2554,18 +2567,14 @@ 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)
> + break;
> if (!af->from_addr_param(&addr, param.addr, htons(asoc->peer.port), 0))
> break;
Same here.
> + if (!af->addr_valid(&addr, sctp_sk(asoc->base.sk), NULL))
> + break;
> scope = sctp_scope(peer_addr);
> if (sctp_in_scope(net, &addr, scope))
> if (!sctp_assoc_add_peer(asoc, &addr, gfp, SCTP_UNCONFIRMED))
> diff --git a/net/sctp/transport.c b/net/sctp/transport.c
> index 6ea55b9fbde4..cd1a604d6f8e 100644
> --- a/net/sctp/transport.c
> +++ b/net/sctp/transport.c
> @@ -92,6 +92,9 @@ struct sctp_transport *sctp_transport_new(struct net *net,
> {
> struct sctp_transport *transport;
>
> + if (!sctp_get_af_specific(addr->sa.sa_family))
> + return NULL;
> +
Any reason why we need this check?
Thanks.
> transport = kzalloc_obj(*transport, gfp);
> if (!transport)
> return NULL;
> --
> 2.43.0
>
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH v2] sctp: reject forged cookie peer_addr with unknown address family
2026-09-15 21:29 [PATCH v2] sctp: reject forged cookie peer_addr with unknown address family Xingyuan Mo
2026-09-16 1:02 ` Xin Long
@ 2026-09-19 1:36 ` netdev-bot+sashiko
1 sibling, 0 replies; 3+ messages in thread
From: netdev-bot+sashiko @ 2026-09-19 1:36 UTC (permalink / raw)
To: hdthky0
Cc: marcelo.leitner, lucien.xin, davem, edumazet, kuba, pabeni, horms,
linux-sctp, netdev
Thank you for your contribution! Sashiko AI review found 3 potential
issue(s) to consider:
Critical: 0 · High: 0 · Medium: 2 · Low: 1
- [Medium] sctp_unpack_cookie() validates a *copy* (`paddr`) of the
attacker-controlled `bear_cookie->peer_addr` and then discards it.
- [Medium] The new `if (sp && sctp_opt2sk(sp)->sk_family != PF_INET6)
return 0;` is placed *before* the IPV6_ADDR_MAPPED handling in…
- [Low] A minimal crash fix (validate the attacker-controlled cookie
peer_addr, guard the missing af_specific) is bundled with a semantic…
--
sctp: reject forged cookie peer_addr with unknown address family
This validates the attacker-controlled COOKIE-ECHO peer_addr with
af->addr_valid() in sctp_unpack_cookie(), makes sctp_v6_addr_valid()
return 0 for non-PF_INET6 sockets, reuses addr_valid() in
sctp_process_param(), and adds missing sctp_get_af_specific() NULL
checks in sctp_process_init() and sctp_transport_new().
Previous posting: https://lore.kernel.org/netdev/20260913113522.2674588-1-hdthky0@gmail.com/
> diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
> index ef26878f1282a..c45ac15f3b79d 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
[Severity: Medium]
The new test runs before the IPV6_ADDR_MAPPED branch, so it also rejects
v4-mapped addresses that used to be normalised to AF_INET and accepted.
Can this change the return value of two existing socket option paths that
take the address family straight from user data?
sctp_setsockopt_bindx() only checks sctp_get_af_specific() on the buffer
walk (there is no sctp_sockaddr_af()/af_supported() gate on the remove
path), and then sctp_bindx_rem() does:
af = sctp_get_af_specific(sa_addr->sa.sa_family);
if (!af) {
retval = -EINVAL;
goto err_bindx_rem;
}
if (!af->addr_valid(sa_addr, sp, NULL)) {
retval = -EADDRNOTAVAIL;
sctp_setsockopt_primary_addr() has the same shape:
af = sctp_get_af_specific(prim->sspp_addr.ss_family);
if (!af)
return -EINVAL;
if (!af->addr_valid((union sctp_addr *)&prim->sspp_addr, sp, NULL))
return -EADDRNOTAVAIL;
On a PF_INET socket with a v4-mapped AF_INET6 sockaddr, the old code took
the IPV6_ADDR_MAPPED branch, rewrote the kernel copy with sctp_v6_map_v4()
and returned sctp_v4_addr_valid() == 1, so sctp_del_bind_addr() and
sctp_assoc_lookup_laddr() matched the real AF_INET address. With the new
test firing first (sk_family == PF_INET), do SCTP_BINDX_REM_ADDR and
SCTP_SET_PEER_PRIMARY_ADDR now return -EADDRNOTAVAIL where they used to
succeed?
Note that simply moving the new test below the IPV6_ADDR_MAPPED block does
not look sufficient on its own, given the cookie path validates a throw-away
copy (see below): a v4-mapped AF_INET6 cookie peer_addr on an IPv4 socket
would then be accepted un-normalised and reach sctp_v6_get_dst(), where
inet6_sk() returns NULL for an AF_INET socket. Would restricting the
socket-family test to the new caller, or propagating the normalised address
to the consumer, avoid touching the setsockopt paths?
> diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
> index 84a4c97d0f755..cfc4973f4d4ac 100644
> --- a/net/sctp/sm_make_chunk.c
> +++ b/net/sctp/sm_make_chunk.c
[ ... ]
> @@ -1841,6 +1843,15 @@ struct sctp_association *sctp_unpack_cookie(
> goto fail;
> }
>
> + /* peer_addr is peer-controlled when cookie authentication is
> + * disabled. Validate a copy, as addr_valid() may rewrite a
> + * v4-mapped address in place.
> + */
> + 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;
> +
[Severity: Medium]
Is the value that gets validated here the value that is actually used?
paddr is a local copy and is dropped after the check, so only the accept or
reject decision survives. For an AF_INET6 peer_addr holding a v4-mapped
address on a dual-stack (PF_INET6, non v6only) listener, sctp_v6_addr_valid()
accepts it only because it rewrites the copy:
net/sctp/ipv6.c:sctp_v6_addr_valid() {
if (ret == IPV6_ADDR_MAPPED) {
if (sp && ipv6_only_sock(sctp_opt2sk(sp)))
return 0;
sctp_v6_map_v4(addr);
return sctp_get_af_specific(AF_INET)->addr_valid(addr, sp, skb);
}
/* Is this a non-unicast address */
if (!(ret & IPV6_ADDR_UNICAST))
return 0;
Without that rewrite the same address would be rejected by the
!(ret & IPV6_ADDR_UNICAST) test.
The AF_INET6 form is what the rest of the path consumes:
memcpy(&retval->c, bear_cookie, sizeof(*bear_cookie));
and sctp_sf_do_5_1D_ce() feeds the raw in-skb cookie address to
sctp_process_init():
if (!sctp_process_init(new_asoc, chunk,
&chunk->subh.cookie_hdr->c.peer_addr,
peer_init, GFP_ATOMIC))
which reaches sctp_assoc_add_peer() -> sctp_transport_new(). Does the
resulting transport therefore end up with af_specific = sctp_af_v6_specific
and the peer-supplied sin6_flowinfo as its flowlabel, from a representation
that was never validated as-is?
if (addr->sa.sa_family == AF_INET6) {
__be32 info = addr->v6.sin6_flowinfo;
if (info) {
peer->flowlabel = ntohl(info & IPV6_FLOWLABEL_MASK);
The new sctp_get_af_specific() guard in sctp_transport_new() only rejects
unknown families, so it does not catch this case either.
The sibling path fixed in the same patch (sctp_process_param(), below) keeps
the normalised AF_INET address it hands to sctp_assoc_add_peer(). Can the
two peer-controlled feeders of sctp_assoc_add_peer() then disagree on the
stored representation, so sctp_cmp_addr_exact() and
sctp_assoc_lookup_paddr() produce two transports for one peer address, and
asoc->c.peer_addr keeps a family that does not match the wire?
Would propagating paddr into retval->c.peer_addr (with sctp_sf_do_5_1D_ce()
using the association copy), or rejecting v4-mapped cookie addresses
outright, be a way to keep the validated and the used value identical?
[ ... ]
> @@ -2554,18 +2567,14 @@ 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)
> + break;
> if (!af->from_addr_param(&addr, param.addr, htons(asoc->peer.port), 0))
> break;
> + if (!af->addr_valid(&addr, sctp_sk(asoc->base.sk), NULL))
> + break;
> scope = sctp_scope(peer_addr);
> if (sctp_in_scope(net, &addr, scope))
> if (!sctp_assoc_add_peer(asoc, &addr, gfp, SCTP_UNCONFIRMED))
[Severity: Low]
This isn't a bug, but could the crash fix and this rework be split into
separate patches?
The crash fix itself is the peer_addr validation in sctp_unpack_cookie()
plus the missing af_specific checks. This hunk additionally changes what
happens on the wire for INIT and INIT-ACK address parameters:
- a v4-mapped value in an SCTP_PARAM_IPV6_ADDRESS is now rewritten in
place to AF_INET by sctp_v6_map_v4() before sctp_assoc_add_peer(), so
the created transport's family, its af_specific and route selection,
and getpaddrs() output change
- a v4-mapped value on an ipv6-only socket and IPv6 non-unicast
parameters are now dropped instead of creating a transport, where
before sctp_v6_scope() could return SCTP_SCOPE_LINK for a multicast
parameter and sctp_in_scope() could accept it
The change to sctp_v6_addr_valid() also alters the meaning of the generic
sctp_af::addr_valid() callback for all existing callers: its comment says
"Return 0 - If the address is a non-unicast or an illegal address", and it
is now also a socket-policy predicate.
With Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") the whole series will be
picked up by every stable tree, including the normalisation change and the
setsockopt behaviour change noted above. Would keeping the fix minimal and
sending the addr_valid() reuse as a follow-up on top make the stable
backport safer?
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260915212917.3775248-1-hdthky0%40gmail.com
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-09-19 1:36 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-15 21:29 [PATCH v2] sctp: reject forged cookie peer_addr with unknown address family Xingyuan Mo
2026-09-16 1:02 ` Xin Long
2026-09-19 1:36 ` netdev-bot+sashiko
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox