mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH net v2] seg6: fix HMAC validation when an extension header precedes the SRH
@ 2026-09-26 11:19 Yuya Kusakabe
  2026-09-29  0:09 ` Andrea Mayer
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Yuya Kusakabe @ 2026-09-26 11:19 UTC (permalink / raw)
  To: Andrea Mayer, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, David Ahern, Ido Schimmel,
	David Lebrun, Ahmed Abdelsalam
  Cc: netdev, linux-kernel, Yuya Kusakabe

seg6_hmac_validate_skb() derived the SRH from skb_transport_header().
That only holds while the two coincide, which is not true on the
seg6_local input path.

ip6_rcv_core() leaves the transport header just past the IPv6 header.
A Hop-by-Hop options header is consumed before the route lookup and
advances it, but a Destination Options header is not: the seg6_local
lwtunnel is entered through an input redirect from the route lookup,
which bypasses the extension header handlers. The transport header
then still points at the Destination Options header while
seg6_get_srh() has located the real SRH further down the chain.

The HMAC is therefore computed over the Destination Options header,
and a packet carrying a valid HMAC TLV is dropped when
seg6_require_hmac is set. Such a packet is legitimate: RFC 8200 allows
Destination Options before a routing header, and get_srh() has walked
the header chain since commit 5829d70b0b6c ("ipv6: sr: fix get_srh() to
comply with IPv6 standard "RFC 8200"").

With a Fragment or an Authentication header in front of the SRH, the
same mistake also reads past the data pulled by seg6_get_srh(). This
happens before seg6_require_hmac is read, so the default configuration
is affected.

Reproduce by giving a node a seg6local End SID with
net.ipv6.conf.<dev>.seg6_require_hmac=1 and a key installed with
"ip sr hmac set <keyid> sha1", then sending

  IPv6 -> Destination Options -> SRH (carrying a valid HMAC TLV) -> payload

to that SID: it is dropped, while the same packet without the
Destination Options header passes.

Fixes: 5829d70b0b6c ("ipv6: sr: fix get_srh() to comply with IPv6 standard "RFC 8200"")
Assisted-by: LLM
Signed-off-by: Yuya Kusakabe <yuya.kusakabe@gmail.com>
---
Changes in v2:
- Describe the out-of-bounds read reachable with a Fragment or an
  Authentication header before the SRH (Andrea)
- Link to v1: https://patch.msgid.link/20260923-b4-seg6-hmac-transport-header-v1-1-3ae85dc0fdb9@gmail.com
---
 include/net/seg6_hmac.h | 3 ++-
 net/ipv6/exthdrs.c      | 2 +-
 net/ipv6/seg6_hmac.c    | 5 +----
 net/ipv6/seg6_local.c   | 6 +++---
 4 files changed, 7 insertions(+), 9 deletions(-)

diff --git a/include/net/seg6_hmac.h b/include/net/seg6_hmac.h
index e9f41725933e..3161a8104b89 100644
--- a/include/net/seg6_hmac.h
+++ b/include/net/seg6_hmac.h
@@ -48,7 +48,8 @@ extern int seg6_hmac_info_add(struct net *net, u32 key,
 extern int seg6_hmac_info_del(struct net *net, u32 key);
 extern int seg6_push_hmac(struct net *net, struct in6_addr *saddr,
 			  struct ipv6_sr_hdr *srh);
-extern bool seg6_hmac_validate_skb(struct sk_buff *skb);
+extern bool seg6_hmac_validate_skb(struct sk_buff *skb,
+				   struct ipv6_sr_hdr *srh);
 #ifdef CONFIG_IPV6_SEG6_HMAC
 extern int seg6_hmac_net_init(struct net *net);
 extern void seg6_hmac_net_exit(struct net *net);
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 09a4552f7f08..3ef3c2635581 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -387,7 +387,7 @@ static int ipv6_srh_rcv(struct sk_buff *skb, struct inet6_dev *idev)
 	}
 
 #ifdef CONFIG_IPV6_SEG6_HMAC
-	if (!seg6_hmac_validate_skb(skb)) {
+	if (!seg6_hmac_validate_skb(skb, hdr)) {
 		kfree_skb(skb);
 		return -1;
 	}
diff --git a/net/ipv6/seg6_hmac.c b/net/ipv6/seg6_hmac.c
index e6964c6b0d38..bd2704d4c7a0 100644
--- a/net/ipv6/seg6_hmac.c
+++ b/net/ipv6/seg6_hmac.c
@@ -173,13 +173,12 @@ EXPORT_SYMBOL(seg6_hmac_compute);
  *
  * called with rcu_read_lock()
  */
-bool seg6_hmac_validate_skb(struct sk_buff *skb)
+bool seg6_hmac_validate_skb(struct sk_buff *skb, struct ipv6_sr_hdr *srh)
 {
 	u8 hmac_output[SEG6_HMAC_FIELD_LEN];
 	struct net *net = dev_net(skb->dev);
 	struct seg6_hmac_info *hinfo;
 	struct sr6_tlv_hmac *tlv;
-	struct ipv6_sr_hdr *srh;
 	struct inet6_dev *idev;
 	int require_hmac;
 
@@ -187,8 +186,6 @@ bool seg6_hmac_validate_skb(struct sk_buff *skb)
 	if (!idev)
 		return false;
 
-	srh = (struct ipv6_sr_hdr *)skb_transport_header(skb);
-
 	tlv = seg6_get_tlv_hmac(srh);
 
 	require_hmac = READ_ONCE(idev->cnf.seg6_require_hmac);
diff --git a/net/ipv6/seg6_local.c b/net/ipv6/seg6_local.c
index d1070aec7b72..67eeb27ee43a 100644
--- a/net/ipv6/seg6_local.c
+++ b/net/ipv6/seg6_local.c
@@ -222,7 +222,7 @@ static struct ipv6_sr_hdr *get_and_validate_srh(struct sk_buff *skb)
 		return NULL;
 
 #ifdef CONFIG_IPV6_SEG6_HMAC
-	if (!seg6_hmac_validate_skb(skb))
+	if (!seg6_hmac_validate_skb(skb, srh))
 		return NULL;
 #endif
 
@@ -239,7 +239,7 @@ static bool decap_and_validate(struct sk_buff *skb, int proto)
 		return false;
 
 #ifdef CONFIG_IPV6_SEG6_HMAC
-	if (srh && !seg6_hmac_validate_skb(skb))
+	if (srh && !seg6_hmac_validate_skb(skb, srh))
 		return false;
 #endif
 
@@ -771,7 +771,7 @@ static int end_flv8986_core(struct sk_buff *skb, struct seg6_local_lwt *slwt)
 	srhoff = srh ? ((unsigned char *)srh - skb->data) : 0;
 	pinfo = seg6_get_srh_pktinfo(srh);
 #ifdef CONFIG_IPV6_SEG6_HMAC
-	if (srh && !seg6_hmac_validate_skb(skb))
+	if (srh && !seg6_hmac_validate_skb(skb, srh))
 		goto drop;
 #endif
 	flvmask = finfo->flv_ops;

---
base-commit: 17741334d00bf5ebd37f8c1c36bc9c146a351deb
change-id: 20260922-b4-seg6-hmac-transport-header-2158048b4bc6

Best regards,
--  
Yuya Kusakabe <yuya.kusakabe@gmail.com>


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH net v2] seg6: fix HMAC validation when an extension header precedes the SRH
  2026-09-26 11:19 [PATCH net v2] seg6: fix HMAC validation when an extension header precedes the SRH Yuya Kusakabe
@ 2026-09-29  0:09 ` Andrea Mayer
  2026-10-01 10:58 ` Paolo Abeni
  2026-10-01 11:10 ` patchwork-bot+netdevbpf
  2 siblings, 0 replies; 4+ messages in thread
From: Andrea Mayer @ 2026-09-29  0:09 UTC (permalink / raw)
  To: Yuya Kusakabe
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, David Ahern, Ido Schimmel, David Lebrun,
	Ahmed Abdelsalam, netdev, linux-kernel, stefano.salsano,
	Andrea Mayer

On Sat, 26 Sep 2026 20:19:27 +0900
Yuya Kusakabe <yuya.kusakabe@gmail.com> wrote:

> seg6_hmac_validate_skb() derived the SRH from skb_transport_header().
> That only holds while the two coincide, which is not true on the
> seg6_local input path.
> 
> ip6_rcv_core() leaves the transport header just past the IPv6 header.
> A Hop-by-Hop options header is consumed before the route lookup and
> advances it, but a Destination Options header is not: the seg6_local
> lwtunnel is entered through an input redirect from the route lookup,
> which bypasses the extension header handlers. The transport header
> then still points at the Destination Options header while
> seg6_get_srh() has located the real SRH further down the chain.
> 
> The HMAC is therefore computed over the Destination Options header,
> and a packet carrying a valid HMAC TLV is dropped when
> seg6_require_hmac is set. Such a packet is legitimate: RFC 8200 allows
> Destination Options before a routing header, and get_srh() has walked
> the header chain since commit 5829d70b0b6c ("ipv6: sr: fix get_srh() to
> comply with IPv6 standard "RFC 8200"").
> 
> With a Fragment or an Authentication header in front of the SRH, the
> same mistake also reads past the data pulled by seg6_get_srh(). This
> happens before seg6_require_hmac is read, so the default configuration
> is affected.
> 
> Reproduce by giving a node a seg6local End SID with
> net.ipv6.conf.<dev>.seg6_require_hmac=1 and a key installed with
> "ip sr hmac set <keyid> sha1", then sending
> 
>   IPv6 -> Destination Options -> SRH (carrying a valid HMAC TLV) -> payload
> 
> to that SID: it is dropped, while the same packet without the
> Destination Options header passes.
> 
> Fixes: 5829d70b0b6c ("ipv6: sr: fix get_srh() to comply with IPv6 standard "RFC 8200"")
> Assisted-by: LLM
> Signed-off-by: Yuya Kusakabe <yuya.kusakabe@gmail.com>
> ---
> Changes in v2:
> - Describe the out-of-bounds read reachable with a Fragment or an
>   Authentication header before the SRH (Andrea)
> - Link to v1: https://patch.msgid.link/20260923-b4-seg6-hmac-transport-header-v1-1-3ae85dc0fdb9@gmail.com
> ---
>  include/net/seg6_hmac.h | 3 ++-
>  net/ipv6/exthdrs.c      | 2 +-
>  net/ipv6/seg6_hmac.c    | 5 +----
>  net/ipv6/seg6_local.c   | 6 +++---
>  4 files changed, 7 insertions(+), 9 deletions(-)

Thanks for the v2, and for addressing the v1 comment.

The code looks good to me.

For the record, the v1 Sashiko review noted another effect of the same
bug. A captured HMAC can be reused in a Destination Options header in
front of a forged SRH with no HMAC. With seg6_require_hmac=1 that forged
SRH was accepted before this patch. After the patch the HMAC check runs
on the SRH the behavior uses, not on the header in front of it.

Reviewed-by: Andrea Mayer <andrea.mayer@uniroma2.it>

Ciao,
Andrea

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH net v2] seg6: fix HMAC validation when an extension header precedes the SRH
  2026-09-26 11:19 [PATCH net v2] seg6: fix HMAC validation when an extension header precedes the SRH Yuya Kusakabe
  2026-09-29  0:09 ` Andrea Mayer
@ 2026-10-01 10:58 ` Paolo Abeni
  2026-10-01 11:10 ` patchwork-bot+netdevbpf
  2 siblings, 0 replies; 4+ messages in thread
From: Paolo Abeni @ 2026-10-01 10:58 UTC (permalink / raw)
  To: Yuya Kusakabe, Andrea Mayer, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Simon Horman, David Ahern, Ido Schimmel,
	David Lebrun, Ahmed Abdelsalam
  Cc: netdev, linux-kernel

On 9/26/26 13:19, Yuya Kusakabe wrote:
> seg6_hmac_validate_skb() derived the SRH from skb_transport_header().
> That only holds while the two coincide, which is not true on the
> seg6_local input path.
> 
> ip6_rcv_core() leaves the transport header just past the IPv6 header.
> A Hop-by-Hop options header is consumed before the route lookup and
> advances it, but a Destination Options header is not: the seg6_local
> lwtunnel is entered through an input redirect from the route lookup,
> which bypasses the extension header handlers. The transport header
> then still points at the Destination Options header while
> seg6_get_srh() has located the real SRH further down the chain.
> 
> The HMAC is therefore computed over the Destination Options header,
> and a packet carrying a valid HMAC TLV is dropped when
> seg6_require_hmac is set. Such a packet is legitimate: RFC 8200 allows
> Destination Options before a routing header, and get_srh() has walked
> the header chain since commit 5829d70b0b6c ("ipv6: sr: fix get_srh() to
> comply with IPv6 standard "RFC 8200"").
> 
> With a Fragment or an Authentication header in front of the SRH, the
> same mistake also reads past the data pulled by seg6_get_srh(). This
> happens before seg6_require_hmac is read, so the default configuration
> is affected.
> 
> Reproduce by giving a node a seg6local End SID with
> net.ipv6.conf.<dev>.seg6_require_hmac=1 and a key installed with
> "ip sr hmac set <keyid> sha1", then sending
> 
>    IPv6 -> Destination Options -> SRH (carrying a valid HMAC TLV) -> payload
> 
> to that SID: it is dropped, while the same packet without the
> Destination Options header passes.
> 
> Fixes: 5829d70b0b6c ("ipv6: sr: fix get_srh() to comply with IPv6 standard "RFC 8200"")
> Assisted-by: LLM
> Signed-off-by: Yuya Kusakabe <yuya.kusakabe@gmail.com>
FTR applying this to net-next, as it looks really an always broken
corner-case, and Linus is asking for really critical fixes only at
this point of the cycle.

/P


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH net v2] seg6: fix HMAC validation when an extension header precedes the SRH
  2026-09-26 11:19 [PATCH net v2] seg6: fix HMAC validation when an extension header precedes the SRH Yuya Kusakabe
  2026-09-29  0:09 ` Andrea Mayer
  2026-10-01 10:58 ` Paolo Abeni
@ 2026-10-01 11:10 ` patchwork-bot+netdevbpf
  2 siblings, 0 replies; 4+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-10-01 11:10 UTC (permalink / raw)
  To: Yuya Kusakabe
  Cc: andrea.mayer, davem, edumazet, kuba, pabeni, horms, dsahern,
	idosch, david.lebrun, amsalam20, netdev, linux-kernel

Hello:

This patch was applied to netdev/net-next.git (main)
by Paolo Abeni <pabeni@redhat.com>:

On Sat, 26 Sep 2026 20:19:27 +0900 you wrote:
> seg6_hmac_validate_skb() derived the SRH from skb_transport_header().
> That only holds while the two coincide, which is not true on the
> seg6_local input path.
> 
> ip6_rcv_core() leaves the transport header just past the IPv6 header.
> A Hop-by-Hop options header is consumed before the route lookup and
> advances it, but a Destination Options header is not: the seg6_local
> lwtunnel is entered through an input redirect from the route lookup,
> which bypasses the extension header handlers. The transport header
> then still points at the Destination Options header while
> seg6_get_srh() has located the real SRH further down the chain.
> 
> [...]

Here is the summary with links:
  - [net,v2] seg6: fix HMAC validation when an extension header precedes the SRH
    https://git.kernel.org/netdev/net-next/c/f9cb4d296d81

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-10-01 11:10 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-26 11:19 [PATCH net v2] seg6: fix HMAC validation when an extension header precedes the SRH Yuya Kusakabe
2026-09-29  0:09 ` Andrea Mayer
2026-10-01 10:58 ` Paolo Abeni
2026-10-01 11:10 ` patchwork-bot+netdevbpf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®