Fix a buffer overflow where extension headers are incorrectly copied to the IPv6 address fields, resulting in a field-spanning write of up to 40 bytes into a 16-byte field (IPv6 address). memcpy: detected field-spanning write (size 40) of single field "&top_iph->saddr" at net/ipv6/ah6.c:439 (size 16) WARNING: CPU: 0 PID: 8838 at net/ipv6/ah6.c:439 ah6_output+0xe7e/0x14e0 net/ipv6/ah6.c:439 The issue occurs in ah6_output() and ah6_output_done() where the code attempts to save/restore extension headers by copying them to/from the IPv6 source/destination address fields based on the CONFIG_IPV6_MIP6 setting. Reported-by: syzbot+01b0667934cdceb4451c@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=01b0667934cdceb4451c Signed-off-by: Charalampos Mitrodimas --- Changes in v2: - Link correct syzbot dashboard link in patch tags - Link to v1: https://lore.kernel.org/r/20250727-ah6-buffer-overflow-v1-1-1f3e11fa98db@posteo.net --- net/ipv6/ah6.c | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index eb474f0987ae016b9d800e9f83d70d73171b21d2..0fa3ed3c64c4ed1a1907d73fb3477e11ef0bd5b8 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -301,13 +301,8 @@ static void ah6_output_done(void *data, int err) memcpy(ah->auth_data, icv, ahp->icv_trunc_len); memcpy(top_iph, iph_base, IPV6HDR_BASELEN); - if (extlen) { -#if IS_ENABLED(CONFIG_IPV6_MIP6) - memcpy(&top_iph->saddr, iph_ext, extlen); -#else - memcpy(&top_iph->daddr, iph_ext, extlen); -#endif - } + if (extlen) + memcpy((u8 *)(top_iph + 1), iph_ext, extlen); kfree(AH_SKB_CB(skb)->tmp); xfrm_output_resume(skb->sk, skb, err); @@ -379,11 +374,7 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) memcpy(iph_base, top_iph, IPV6HDR_BASELEN); if (extlen) { -#if IS_ENABLED(CONFIG_IPV6_MIP6) - memcpy(iph_ext, &top_iph->saddr, extlen); -#else - memcpy(iph_ext, &top_iph->daddr, extlen); -#endif + memcpy(iph_ext, (u8 *)(top_iph + 1), extlen); err = ipv6_clear_mutable_options(top_iph, extlen - sizeof(*iph_ext) + sizeof(*top_iph), @@ -434,13 +425,8 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) memcpy(ah->auth_data, icv, ahp->icv_trunc_len); memcpy(top_iph, iph_base, IPV6HDR_BASELEN); - if (extlen) { -#if IS_ENABLED(CONFIG_IPV6_MIP6) - memcpy(&top_iph->saddr, iph_ext, extlen); -#else - memcpy(&top_iph->daddr, iph_ext, extlen); -#endif - } + if (extlen) + memcpy((u8 *)(top_iph + 1), iph_ext, extlen); out_free: kfree(iph_base); --- base-commit: b711733e89a3f84c8e1e56e2328f9a0fa5facc7c change-id: 20250727-ah6-buffer-overflow-ff795b87398d Best regards, -- Charalampos Mitrodimas