VYPR
Unrated severityNVD Advisory· Published May 28, 2026

CVE-2026-46193

CVE-2026-46193

Description

In the Linux kernel, the following vulnerability has been resolved:

xfrm: ah: account for ESN high bits in async callbacks

AH allocates its temporary auth/ICV layout differently when ESN is enabled: the async ahash setup appends a 4-byte seqhi slot before the ICV or auth_data area, but the async completion callbacks still reconstruct the temporary layout as if seqhi were absent.

With an async AH implementation selected, that makes AH copy or compare the wrong bytes on both the IPv4 and IPv6 paths. In UML repro on IPv4 AH with ESN and forced async hmac(sha1), ping fails with 100% packet loss, and the callback logs show the pre-fix drift:

ah4 output_done: esn=1 err=0 icv_off=20 expected_off=24 ah4 input_done: esn=1 auth_off=20 expected_auth_off=24 icv_off=32 expected_icv_off=36

Reconstruct the callback-side layout the same way the setup path built it by skipping the ESN seqhi slot before locating the saved auth_data or ICV. Per RFC 4302, the ESN high-order 32 bits participate in the AH ICV computation, so the async callbacks must account for the seqhi slot.

Post-fix, the same IPv4 AH+ESN+forced-async-hmac(sha1) UML repro shows the corrected offset (ah4 output_done: esn=1 err=0 icv_off=24 expected_off=24) and ping succeeds; net/ipv4/ah4.o and net/ipv6/ah6.o build clean at W=1. IPv6 AH+ESN was not exercised at runtime, and the change has not been tested against a real async hardware AH engine.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Linux kernel xfrm AH async callbacks misalign ICV offsets when ESN is enabled, causing IPsec packet drops.

Vulnerability

In the Linux kernel's xfrm AH (Authentication Header) implementation, when Extended Sequence Numbers (ESN) are enabled, the asynchronous ahash setup path appends a 4-byte seqhi slot before the ICV or auth_data area. However, the async completion callbacks (ah4_output_done, ah4_input_done, ah6_output_done, ah6_input_done) reconstruct the temporary layout without accounting for this slot, leading to a 4-byte offset mismatch. This affects both IPv4 and IPv6 AH paths. The bug is present in kernel versions that include async AH support with ESN, as described in the fix commit [1].

Exploitation

An attacker can trigger this vulnerability by sending IPsec AH packets with ESN enabled to a system that uses an asynchronous AH implementation (e.g., hardware offload or forced async via crypto_ahash). No authentication or special privileges are required beyond network access. The attacker only needs to send valid AH+ESN packets; the kernel's incorrect offset calculation will cause the ICV comparison to fail, resulting in packet drops. In a UML repro with IPv4 AH, ESN, and forced async hmac(sha1), ping fails with 100% packet loss [1].

Impact

Successful exploitation leads to denial of service for IPsec AH traffic with ESN enabled. All incoming and outgoing AH packets are dropped due to incorrect ICV validation, effectively breaking IPsec connectivity. No information disclosure, privilege escalation, or code execution is indicated. The impact is limited to systems using async AH implementations with ESN.

Mitigation

The fix is included in Linux kernel commit ec54093e6a8f [1]. Users should update to a kernel version containing this commit (e.g., stable releases that backport the fix). No workaround is available; systems not using async AH or ESN are unaffected. The vulnerability is not listed on CISA's Known Exploited Vulnerabilities (KEV) catalog as of publication.

AI Insight generated on May 28, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

2

Patches

10
0555d4f52623

xfrm: ah: account for ESN high bits in async callbacks

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitMichael BommaritoMay 13, 2026Fixed in 6.6.140via kernel-cna
2 files changed · +24 5
  • net/ipv4/ah4.c+12 2 modified
    diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
    index cf31fb266bc10d..9f00d251770d44 100644
    --- a/net/ipv4/ah4.c
    +++ b/net/ipv4/ah4.c
    @@ -124,9 +124,14 @@ static void ah_output_done(void *data, int err)
     	struct iphdr *top_iph = ip_hdr(skb);
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	int ihl = ip_hdrlen(skb);
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	iph = AH_SKB_CB(skb)->tmp;
    -	icv = ah_tmp_icv(iph, ihl);
    +	seqhi = (__be32 *)((char *)iph + ihl);
    +	icv = ah_tmp_icv(seqhi, seqhi_len);
     	memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
     
     	top_iph->tos = iph->tos;
    @@ -270,12 +275,17 @@ static void ah_input_done(void *data, int err)
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	int ihl = ip_hdrlen(skb);
     	int ah_hlen = (ah->hdrlen + 2) << 2;
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
     	if (err)
     		goto out;
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	work_iph = AH_SKB_CB(skb)->tmp;
    -	auth_data = ah_tmp_auth(work_iph, ihl);
    +	seqhi = (__be32 *)((char *)work_iph + ihl);
    +	auth_data = ah_tmp_auth(seqhi, seqhi_len);
     	icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len);
     
     	err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
    
  • net/ipv6/ah6.c+12 3 modified
    diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
    index 1938d96e2c0fd2..c6f1ad058dd289 100644
    --- a/net/ipv6/ah6.c
    +++ b/net/ipv6/ah6.c
    @@ -317,14 +317,19 @@ static void ah6_output_done(void *data, int err)
     	struct ipv6hdr *top_iph = ipv6_hdr(skb);
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	struct tmp_ext *iph_ext;
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
     	extlen = skb_network_header_len(skb) - sizeof(struct ipv6hdr);
     	if (extlen)
     		extlen += sizeof(*iph_ext);
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	iph_base = AH_SKB_CB(skb)->tmp;
     	iph_ext = ah_tmp_ext(iph_base);
    -	icv = ah_tmp_icv(iph_ext, extlen);
    +	seqhi = (__be32 *)((char *)iph_ext + extlen);
    +	icv = ah_tmp_icv(seqhi, seqhi_len);
     
     	memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
     	memcpy(top_iph, iph_base, IPV6HDR_BASELEN);
    @@ -471,13 +476,18 @@ static void ah6_input_done(void *data, int err)
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	int hdr_len = skb_network_header_len(skb);
     	int ah_hlen = ipv6_authlen(ah);
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
     	if (err)
     		goto out;
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	work_iph = AH_SKB_CB(skb)->tmp;
     	auth_data = ah_tmp_auth(work_iph, hdr_len);
    -	icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len);
    +	seqhi = (__be32 *)(auth_data + ahp->icv_trunc_len);
    +	icv = ah_tmp_icv(seqhi, seqhi_len);
     
     	err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
     	if (err)
    -- 
    cgit 1.3-korg
    
    
    
7db99a09b3bc

xfrm: ah: account for ESN high bits in async callbacks

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitMichael BommaritoApr 19, 2026Fixed in 6.18.30via kernel-cna
2 files changed · +24 5
  • net/ipv4/ah4.c+12 2 modified
    diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
    index 64aec3dff8ec85..8b0f15abbb38ae 100644
    --- a/net/ipv4/ah4.c
    +++ b/net/ipv4/ah4.c
    @@ -124,9 +124,14 @@ static void ah_output_done(void *data, int err)
     	struct iphdr *top_iph = ip_hdr(skb);
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	int ihl = ip_hdrlen(skb);
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	iph = AH_SKB_CB(skb)->tmp;
    -	icv = ah_tmp_icv(iph, ihl);
    +	seqhi = (__be32 *)((char *)iph + ihl);
    +	icv = ah_tmp_icv(seqhi, seqhi_len);
     	memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
     
     	top_iph->tos = iph->tos;
    @@ -270,12 +275,17 @@ static void ah_input_done(void *data, int err)
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	int ihl = ip_hdrlen(skb);
     	int ah_hlen = (ah->hdrlen + 2) << 2;
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
     	if (err)
     		goto out;
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	work_iph = AH_SKB_CB(skb)->tmp;
    -	auth_data = ah_tmp_auth(work_iph, ihl);
    +	seqhi = (__be32 *)((char *)work_iph + ihl);
    +	auth_data = ah_tmp_auth(seqhi, seqhi_len);
     	icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len);
     
     	err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
    
  • net/ipv6/ah6.c+12 3 modified
    diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
    index 95372e0f1d216b..bd9ec8000f0b5c 100644
    --- a/net/ipv6/ah6.c
    +++ b/net/ipv6/ah6.c
    @@ -317,14 +317,19 @@ static void ah6_output_done(void *data, int err)
     	struct ipv6hdr *top_iph = ipv6_hdr(skb);
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	struct tmp_ext *iph_ext;
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
     	extlen = skb_network_header_len(skb) - sizeof(struct ipv6hdr);
     	if (extlen)
     		extlen += sizeof(*iph_ext);
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	iph_base = AH_SKB_CB(skb)->tmp;
     	iph_ext = ah_tmp_ext(iph_base);
    -	icv = ah_tmp_icv(iph_ext, extlen);
    +	seqhi = (__be32 *)((char *)iph_ext + extlen);
    +	icv = ah_tmp_icv(seqhi, seqhi_len);
     
     	memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
     	memcpy(top_iph, iph_base, IPV6HDR_BASELEN);
    @@ -471,13 +476,18 @@ static void ah6_input_done(void *data, int err)
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	int hdr_len = skb_network_header_len(skb);
     	int ah_hlen = ipv6_authlen(ah);
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
     	if (err)
     		goto out;
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	work_iph = AH_SKB_CB(skb)->tmp;
     	auth_data = ah_tmp_auth(work_iph, hdr_len);
    -	icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len);
    +	seqhi = (__be32 *)(auth_data + ahp->icv_trunc_len);
    +	icv = ah_tmp_icv(seqhi, seqhi_len);
     
     	err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
     	if (err)
    -- 
    cgit 1.3-korg
    
    
    
2ffaa7a94f9a

xfrm: ah: account for ESN high bits in async callbacks

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitMichael BommaritoApr 19, 2026Fixed in 7.0.7via kernel-cna
2 files changed · +24 5
  • net/ipv4/ah4.c+12 2 modified
    diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
    index 5fb812443a08f2..4366cbac3f06c5 100644
    --- a/net/ipv4/ah4.c
    +++ b/net/ipv4/ah4.c
    @@ -124,9 +124,14 @@ static void ah_output_done(void *data, int err)
     	struct iphdr *top_iph = ip_hdr(skb);
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	int ihl = ip_hdrlen(skb);
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	iph = AH_SKB_CB(skb)->tmp;
    -	icv = ah_tmp_icv(iph, ihl);
    +	seqhi = (__be32 *)((char *)iph + ihl);
    +	icv = ah_tmp_icv(seqhi, seqhi_len);
     	memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
     
     	top_iph->tos = iph->tos;
    @@ -270,12 +275,17 @@ static void ah_input_done(void *data, int err)
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	int ihl = ip_hdrlen(skb);
     	int ah_hlen = (ah->hdrlen + 2) << 2;
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
     	if (err)
     		goto out;
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	work_iph = AH_SKB_CB(skb)->tmp;
    -	auth_data = ah_tmp_auth(work_iph, ihl);
    +	seqhi = (__be32 *)((char *)work_iph + ihl);
    +	auth_data = ah_tmp_auth(seqhi, seqhi_len);
     	icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len);
     
     	err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
    
  • net/ipv6/ah6.c+12 3 modified
    diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
    index cb26beea439824..de1e68199a0145 100644
    --- a/net/ipv6/ah6.c
    +++ b/net/ipv6/ah6.c
    @@ -317,14 +317,19 @@ static void ah6_output_done(void *data, int err)
     	struct ipv6hdr *top_iph = ipv6_hdr(skb);
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	struct tmp_ext *iph_ext;
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
     	extlen = skb_network_header_len(skb) - sizeof(struct ipv6hdr);
     	if (extlen)
     		extlen += sizeof(*iph_ext);
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	iph_base = AH_SKB_CB(skb)->tmp;
     	iph_ext = ah_tmp_ext(iph_base);
    -	icv = ah_tmp_icv(iph_ext, extlen);
    +	seqhi = (__be32 *)((char *)iph_ext + extlen);
    +	icv = ah_tmp_icv(seqhi, seqhi_len);
     
     	memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
     	memcpy(top_iph, iph_base, IPV6HDR_BASELEN);
    @@ -471,13 +476,18 @@ static void ah6_input_done(void *data, int err)
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	int hdr_len = skb_network_header_len(skb);
     	int ah_hlen = ipv6_authlen(ah);
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
     	if (err)
     		goto out;
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	work_iph = AH_SKB_CB(skb)->tmp;
     	auth_data = ah_tmp_auth(work_iph, hdr_len);
    -	icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len);
    +	seqhi = (__be32 *)(auth_data + ahp->icv_trunc_len);
    +	icv = ah_tmp_icv(seqhi, seqhi_len);
     
     	err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
     	if (err)
    -- 
    cgit 1.3-korg
    
    
    
ec54093e6a8f

xfrm: ah: account for ESN high bits in async callbacks

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitMichael BommaritoApr 19, 2026Fixed in 7.1-rc3via kernel-cna
2 files changed · +24 5
  • net/ipv4/ah4.c+12 2 modified
    diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
    index 5fb812443a08f2..4366cbac3f06c5 100644
    --- a/net/ipv4/ah4.c
    +++ b/net/ipv4/ah4.c
    @@ -124,9 +124,14 @@ static void ah_output_done(void *data, int err)
     	struct iphdr *top_iph = ip_hdr(skb);
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	int ihl = ip_hdrlen(skb);
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	iph = AH_SKB_CB(skb)->tmp;
    -	icv = ah_tmp_icv(iph, ihl);
    +	seqhi = (__be32 *)((char *)iph + ihl);
    +	icv = ah_tmp_icv(seqhi, seqhi_len);
     	memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
     
     	top_iph->tos = iph->tos;
    @@ -270,12 +275,17 @@ static void ah_input_done(void *data, int err)
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	int ihl = ip_hdrlen(skb);
     	int ah_hlen = (ah->hdrlen + 2) << 2;
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
     	if (err)
     		goto out;
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	work_iph = AH_SKB_CB(skb)->tmp;
    -	auth_data = ah_tmp_auth(work_iph, ihl);
    +	seqhi = (__be32 *)((char *)work_iph + ihl);
    +	auth_data = ah_tmp_auth(seqhi, seqhi_len);
     	icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len);
     
     	err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
    
  • net/ipv6/ah6.c+12 3 modified
    diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
    index cb26beea439824..de1e68199a0145 100644
    --- a/net/ipv6/ah6.c
    +++ b/net/ipv6/ah6.c
    @@ -317,14 +317,19 @@ static void ah6_output_done(void *data, int err)
     	struct ipv6hdr *top_iph = ipv6_hdr(skb);
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	struct tmp_ext *iph_ext;
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
     	extlen = skb_network_header_len(skb) - sizeof(struct ipv6hdr);
     	if (extlen)
     		extlen += sizeof(*iph_ext);
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	iph_base = AH_SKB_CB(skb)->tmp;
     	iph_ext = ah_tmp_ext(iph_base);
    -	icv = ah_tmp_icv(iph_ext, extlen);
    +	seqhi = (__be32 *)((char *)iph_ext + extlen);
    +	icv = ah_tmp_icv(seqhi, seqhi_len);
     
     	memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
     	memcpy(top_iph, iph_base, IPV6HDR_BASELEN);
    @@ -471,13 +476,18 @@ static void ah6_input_done(void *data, int err)
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	int hdr_len = skb_network_header_len(skb);
     	int ah_hlen = ipv6_authlen(ah);
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
     	if (err)
     		goto out;
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	work_iph = AH_SKB_CB(skb)->tmp;
     	auth_data = ah_tmp_auth(work_iph, hdr_len);
    -	icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len);
    +	seqhi = (__be32 *)(auth_data + ahp->icv_trunc_len);
    +	icv = ah_tmp_icv(seqhi, seqhi_len);
     
     	err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
     	if (err)
    -- 
    cgit 1.3-korg
    
    
    
729899a2aa8b

xfrm: ah: account for ESN high bits in async callbacks

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitMichael BommaritoApr 19, 2026Fixed in 6.12.88via kernel-cna
2 files changed · +24 5
  • net/ipv4/ah4.c+12 2 modified
    diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
    index 64aec3dff8ec85..8b0f15abbb38ae 100644
    --- a/net/ipv4/ah4.c
    +++ b/net/ipv4/ah4.c
    @@ -124,9 +124,14 @@ static void ah_output_done(void *data, int err)
     	struct iphdr *top_iph = ip_hdr(skb);
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	int ihl = ip_hdrlen(skb);
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	iph = AH_SKB_CB(skb)->tmp;
    -	icv = ah_tmp_icv(iph, ihl);
    +	seqhi = (__be32 *)((char *)iph + ihl);
    +	icv = ah_tmp_icv(seqhi, seqhi_len);
     	memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
     
     	top_iph->tos = iph->tos;
    @@ -270,12 +275,17 @@ static void ah_input_done(void *data, int err)
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	int ihl = ip_hdrlen(skb);
     	int ah_hlen = (ah->hdrlen + 2) << 2;
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
     	if (err)
     		goto out;
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	work_iph = AH_SKB_CB(skb)->tmp;
    -	auth_data = ah_tmp_auth(work_iph, ihl);
    +	seqhi = (__be32 *)((char *)work_iph + ihl);
    +	auth_data = ah_tmp_auth(seqhi, seqhi_len);
     	icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len);
     
     	err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
    
  • net/ipv6/ah6.c+12 3 modified
    diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
    index 95372e0f1d216b..bd9ec8000f0b5c 100644
    --- a/net/ipv6/ah6.c
    +++ b/net/ipv6/ah6.c
    @@ -317,14 +317,19 @@ static void ah6_output_done(void *data, int err)
     	struct ipv6hdr *top_iph = ipv6_hdr(skb);
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	struct tmp_ext *iph_ext;
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
     	extlen = skb_network_header_len(skb) - sizeof(struct ipv6hdr);
     	if (extlen)
     		extlen += sizeof(*iph_ext);
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	iph_base = AH_SKB_CB(skb)->tmp;
     	iph_ext = ah_tmp_ext(iph_base);
    -	icv = ah_tmp_icv(iph_ext, extlen);
    +	seqhi = (__be32 *)((char *)iph_ext + extlen);
    +	icv = ah_tmp_icv(seqhi, seqhi_len);
     
     	memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
     	memcpy(top_iph, iph_base, IPV6HDR_BASELEN);
    @@ -471,13 +476,18 @@ static void ah6_input_done(void *data, int err)
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	int hdr_len = skb_network_header_len(skb);
     	int ah_hlen = ipv6_authlen(ah);
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
     	if (err)
     		goto out;
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	work_iph = AH_SKB_CB(skb)->tmp;
     	auth_data = ah_tmp_auth(work_iph, hdr_len);
    -	icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len);
    +	seqhi = (__be32 *)(auth_data + ahp->icv_trunc_len);
    +	icv = ah_tmp_icv(seqhi, seqhi_len);
     
     	err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
     	if (err)
    -- 
    cgit 1.3-korg
    
    
    
0555d4f52623

xfrm: ah: account for ESN high bits in async callbacks

2 files changed · +24 5
  • net/ipv4/ah4.c+12 2 modified
    diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
    index cf31fb266bc10d..9f00d251770d44 100644
    --- a/net/ipv4/ah4.c
    +++ b/net/ipv4/ah4.c
    @@ -124,9 +124,14 @@ static void ah_output_done(void *data, int err)
     	struct iphdr *top_iph = ip_hdr(skb);
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	int ihl = ip_hdrlen(skb);
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	iph = AH_SKB_CB(skb)->tmp;
    -	icv = ah_tmp_icv(iph, ihl);
    +	seqhi = (__be32 *)((char *)iph + ihl);
    +	icv = ah_tmp_icv(seqhi, seqhi_len);
     	memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
     
     	top_iph->tos = iph->tos;
    @@ -270,12 +275,17 @@ static void ah_input_done(void *data, int err)
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	int ihl = ip_hdrlen(skb);
     	int ah_hlen = (ah->hdrlen + 2) << 2;
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
     	if (err)
     		goto out;
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	work_iph = AH_SKB_CB(skb)->tmp;
    -	auth_data = ah_tmp_auth(work_iph, ihl);
    +	seqhi = (__be32 *)((char *)work_iph + ihl);
    +	auth_data = ah_tmp_auth(seqhi, seqhi_len);
     	icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len);
     
     	err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
    
  • net/ipv6/ah6.c+12 3 modified
    diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
    index 1938d96e2c0fd2..c6f1ad058dd289 100644
    --- a/net/ipv6/ah6.c
    +++ b/net/ipv6/ah6.c
    @@ -317,14 +317,19 @@ static void ah6_output_done(void *data, int err)
     	struct ipv6hdr *top_iph = ipv6_hdr(skb);
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	struct tmp_ext *iph_ext;
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
     	extlen = skb_network_header_len(skb) - sizeof(struct ipv6hdr);
     	if (extlen)
     		extlen += sizeof(*iph_ext);
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	iph_base = AH_SKB_CB(skb)->tmp;
     	iph_ext = ah_tmp_ext(iph_base);
    -	icv = ah_tmp_icv(iph_ext, extlen);
    +	seqhi = (__be32 *)((char *)iph_ext + extlen);
    +	icv = ah_tmp_icv(seqhi, seqhi_len);
     
     	memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
     	memcpy(top_iph, iph_base, IPV6HDR_BASELEN);
    @@ -471,13 +476,18 @@ static void ah6_input_done(void *data, int err)
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	int hdr_len = skb_network_header_len(skb);
     	int ah_hlen = ipv6_authlen(ah);
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
     	if (err)
     		goto out;
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	work_iph = AH_SKB_CB(skb)->tmp;
     	auth_data = ah_tmp_auth(work_iph, hdr_len);
    -	icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len);
    +	seqhi = (__be32 *)(auth_data + ahp->icv_trunc_len);
    +	icv = ah_tmp_icv(seqhi, seqhi_len);
     
     	err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
     	if (err)
    -- 
    cgit 1.3-korg
    
    
    
ec54093e6a8f

xfrm: ah: account for ESN high bits in async callbacks

2 files changed · +24 5
  • net/ipv4/ah4.c+12 2 modified
    diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
    index 5fb812443a08f2..4366cbac3f06c5 100644
    --- a/net/ipv4/ah4.c
    +++ b/net/ipv4/ah4.c
    @@ -124,9 +124,14 @@ static void ah_output_done(void *data, int err)
     	struct iphdr *top_iph = ip_hdr(skb);
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	int ihl = ip_hdrlen(skb);
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	iph = AH_SKB_CB(skb)->tmp;
    -	icv = ah_tmp_icv(iph, ihl);
    +	seqhi = (__be32 *)((char *)iph + ihl);
    +	icv = ah_tmp_icv(seqhi, seqhi_len);
     	memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
     
     	top_iph->tos = iph->tos;
    @@ -270,12 +275,17 @@ static void ah_input_done(void *data, int err)
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	int ihl = ip_hdrlen(skb);
     	int ah_hlen = (ah->hdrlen + 2) << 2;
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
     	if (err)
     		goto out;
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	work_iph = AH_SKB_CB(skb)->tmp;
    -	auth_data = ah_tmp_auth(work_iph, ihl);
    +	seqhi = (__be32 *)((char *)work_iph + ihl);
    +	auth_data = ah_tmp_auth(seqhi, seqhi_len);
     	icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len);
     
     	err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
    
  • net/ipv6/ah6.c+12 3 modified
    diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
    index cb26beea439824..de1e68199a0145 100644
    --- a/net/ipv6/ah6.c
    +++ b/net/ipv6/ah6.c
    @@ -317,14 +317,19 @@ static void ah6_output_done(void *data, int err)
     	struct ipv6hdr *top_iph = ipv6_hdr(skb);
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	struct tmp_ext *iph_ext;
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
     	extlen = skb_network_header_len(skb) - sizeof(struct ipv6hdr);
     	if (extlen)
     		extlen += sizeof(*iph_ext);
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	iph_base = AH_SKB_CB(skb)->tmp;
     	iph_ext = ah_tmp_ext(iph_base);
    -	icv = ah_tmp_icv(iph_ext, extlen);
    +	seqhi = (__be32 *)((char *)iph_ext + extlen);
    +	icv = ah_tmp_icv(seqhi, seqhi_len);
     
     	memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
     	memcpy(top_iph, iph_base, IPV6HDR_BASELEN);
    @@ -471,13 +476,18 @@ static void ah6_input_done(void *data, int err)
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	int hdr_len = skb_network_header_len(skb);
     	int ah_hlen = ipv6_authlen(ah);
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
     	if (err)
     		goto out;
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	work_iph = AH_SKB_CB(skb)->tmp;
     	auth_data = ah_tmp_auth(work_iph, hdr_len);
    -	icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len);
    +	seqhi = (__be32 *)(auth_data + ahp->icv_trunc_len);
    +	icv = ah_tmp_icv(seqhi, seqhi_len);
     
     	err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
     	if (err)
    -- 
    cgit 1.3-korg
    
    
    
2ffaa7a94f9a

xfrm: ah: account for ESN high bits in async callbacks

2 files changed · +24 5
  • net/ipv4/ah4.c+12 2 modified
    diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
    index 5fb812443a08f2..4366cbac3f06c5 100644
    --- a/net/ipv4/ah4.c
    +++ b/net/ipv4/ah4.c
    @@ -124,9 +124,14 @@ static void ah_output_done(void *data, int err)
     	struct iphdr *top_iph = ip_hdr(skb);
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	int ihl = ip_hdrlen(skb);
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	iph = AH_SKB_CB(skb)->tmp;
    -	icv = ah_tmp_icv(iph, ihl);
    +	seqhi = (__be32 *)((char *)iph + ihl);
    +	icv = ah_tmp_icv(seqhi, seqhi_len);
     	memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
     
     	top_iph->tos = iph->tos;
    @@ -270,12 +275,17 @@ static void ah_input_done(void *data, int err)
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	int ihl = ip_hdrlen(skb);
     	int ah_hlen = (ah->hdrlen + 2) << 2;
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
     	if (err)
     		goto out;
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	work_iph = AH_SKB_CB(skb)->tmp;
    -	auth_data = ah_tmp_auth(work_iph, ihl);
    +	seqhi = (__be32 *)((char *)work_iph + ihl);
    +	auth_data = ah_tmp_auth(seqhi, seqhi_len);
     	icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len);
     
     	err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
    
  • net/ipv6/ah6.c+12 3 modified
    diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
    index cb26beea439824..de1e68199a0145 100644
    --- a/net/ipv6/ah6.c
    +++ b/net/ipv6/ah6.c
    @@ -317,14 +317,19 @@ static void ah6_output_done(void *data, int err)
     	struct ipv6hdr *top_iph = ipv6_hdr(skb);
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	struct tmp_ext *iph_ext;
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
     	extlen = skb_network_header_len(skb) - sizeof(struct ipv6hdr);
     	if (extlen)
     		extlen += sizeof(*iph_ext);
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	iph_base = AH_SKB_CB(skb)->tmp;
     	iph_ext = ah_tmp_ext(iph_base);
    -	icv = ah_tmp_icv(iph_ext, extlen);
    +	seqhi = (__be32 *)((char *)iph_ext + extlen);
    +	icv = ah_tmp_icv(seqhi, seqhi_len);
     
     	memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
     	memcpy(top_iph, iph_base, IPV6HDR_BASELEN);
    @@ -471,13 +476,18 @@ static void ah6_input_done(void *data, int err)
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	int hdr_len = skb_network_header_len(skb);
     	int ah_hlen = ipv6_authlen(ah);
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
     	if (err)
     		goto out;
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	work_iph = AH_SKB_CB(skb)->tmp;
     	auth_data = ah_tmp_auth(work_iph, hdr_len);
    -	icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len);
    +	seqhi = (__be32 *)(auth_data + ahp->icv_trunc_len);
    +	icv = ah_tmp_icv(seqhi, seqhi_len);
     
     	err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
     	if (err)
    -- 
    cgit 1.3-korg
    
    
    
7db99a09b3bc

xfrm: ah: account for ESN high bits in async callbacks

2 files changed · +24 5
  • net/ipv4/ah4.c+12 2 modified
    diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
    index 64aec3dff8ec85..8b0f15abbb38ae 100644
    --- a/net/ipv4/ah4.c
    +++ b/net/ipv4/ah4.c
    @@ -124,9 +124,14 @@ static void ah_output_done(void *data, int err)
     	struct iphdr *top_iph = ip_hdr(skb);
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	int ihl = ip_hdrlen(skb);
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	iph = AH_SKB_CB(skb)->tmp;
    -	icv = ah_tmp_icv(iph, ihl);
    +	seqhi = (__be32 *)((char *)iph + ihl);
    +	icv = ah_tmp_icv(seqhi, seqhi_len);
     	memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
     
     	top_iph->tos = iph->tos;
    @@ -270,12 +275,17 @@ static void ah_input_done(void *data, int err)
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	int ihl = ip_hdrlen(skb);
     	int ah_hlen = (ah->hdrlen + 2) << 2;
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
     	if (err)
     		goto out;
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	work_iph = AH_SKB_CB(skb)->tmp;
    -	auth_data = ah_tmp_auth(work_iph, ihl);
    +	seqhi = (__be32 *)((char *)work_iph + ihl);
    +	auth_data = ah_tmp_auth(seqhi, seqhi_len);
     	icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len);
     
     	err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
    
  • net/ipv6/ah6.c+12 3 modified
    diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
    index 95372e0f1d216b..bd9ec8000f0b5c 100644
    --- a/net/ipv6/ah6.c
    +++ b/net/ipv6/ah6.c
    @@ -317,14 +317,19 @@ static void ah6_output_done(void *data, int err)
     	struct ipv6hdr *top_iph = ipv6_hdr(skb);
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	struct tmp_ext *iph_ext;
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
     	extlen = skb_network_header_len(skb) - sizeof(struct ipv6hdr);
     	if (extlen)
     		extlen += sizeof(*iph_ext);
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	iph_base = AH_SKB_CB(skb)->tmp;
     	iph_ext = ah_tmp_ext(iph_base);
    -	icv = ah_tmp_icv(iph_ext, extlen);
    +	seqhi = (__be32 *)((char *)iph_ext + extlen);
    +	icv = ah_tmp_icv(seqhi, seqhi_len);
     
     	memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
     	memcpy(top_iph, iph_base, IPV6HDR_BASELEN);
    @@ -471,13 +476,18 @@ static void ah6_input_done(void *data, int err)
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	int hdr_len = skb_network_header_len(skb);
     	int ah_hlen = ipv6_authlen(ah);
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
     	if (err)
     		goto out;
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	work_iph = AH_SKB_CB(skb)->tmp;
     	auth_data = ah_tmp_auth(work_iph, hdr_len);
    -	icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len);
    +	seqhi = (__be32 *)(auth_data + ahp->icv_trunc_len);
    +	icv = ah_tmp_icv(seqhi, seqhi_len);
     
     	err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
     	if (err)
    -- 
    cgit 1.3-korg
    
    
    
729899a2aa8b

xfrm: ah: account for ESN high bits in async callbacks

2 files changed · +24 5
  • net/ipv4/ah4.c+12 2 modified
    diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
    index 64aec3dff8ec85..8b0f15abbb38ae 100644
    --- a/net/ipv4/ah4.c
    +++ b/net/ipv4/ah4.c
    @@ -124,9 +124,14 @@ static void ah_output_done(void *data, int err)
     	struct iphdr *top_iph = ip_hdr(skb);
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	int ihl = ip_hdrlen(skb);
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	iph = AH_SKB_CB(skb)->tmp;
    -	icv = ah_tmp_icv(iph, ihl);
    +	seqhi = (__be32 *)((char *)iph + ihl);
    +	icv = ah_tmp_icv(seqhi, seqhi_len);
     	memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
     
     	top_iph->tos = iph->tos;
    @@ -270,12 +275,17 @@ static void ah_input_done(void *data, int err)
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	int ihl = ip_hdrlen(skb);
     	int ah_hlen = (ah->hdrlen + 2) << 2;
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
     	if (err)
     		goto out;
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	work_iph = AH_SKB_CB(skb)->tmp;
    -	auth_data = ah_tmp_auth(work_iph, ihl);
    +	seqhi = (__be32 *)((char *)work_iph + ihl);
    +	auth_data = ah_tmp_auth(seqhi, seqhi_len);
     	icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len);
     
     	err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
    
  • net/ipv6/ah6.c+12 3 modified
    diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
    index 95372e0f1d216b..bd9ec8000f0b5c 100644
    --- a/net/ipv6/ah6.c
    +++ b/net/ipv6/ah6.c
    @@ -317,14 +317,19 @@ static void ah6_output_done(void *data, int err)
     	struct ipv6hdr *top_iph = ipv6_hdr(skb);
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	struct tmp_ext *iph_ext;
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
     	extlen = skb_network_header_len(skb) - sizeof(struct ipv6hdr);
     	if (extlen)
     		extlen += sizeof(*iph_ext);
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	iph_base = AH_SKB_CB(skb)->tmp;
     	iph_ext = ah_tmp_ext(iph_base);
    -	icv = ah_tmp_icv(iph_ext, extlen);
    +	seqhi = (__be32 *)((char *)iph_ext + extlen);
    +	icv = ah_tmp_icv(seqhi, seqhi_len);
     
     	memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
     	memcpy(top_iph, iph_base, IPV6HDR_BASELEN);
    @@ -471,13 +476,18 @@ static void ah6_input_done(void *data, int err)
     	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
     	int hdr_len = skb_network_header_len(skb);
     	int ah_hlen = ipv6_authlen(ah);
    +	int seqhi_len = 0;
    +	__be32 *seqhi;
     
     	if (err)
     		goto out;
     
    +	if (x->props.flags & XFRM_STATE_ESN)
    +		seqhi_len = sizeof(*seqhi);
     	work_iph = AH_SKB_CB(skb)->tmp;
     	auth_data = ah_tmp_auth(work_iph, hdr_len);
    -	icv = ah_tmp_icv(auth_data, ahp->icv_trunc_len);
    +	seqhi = (__be32 *)(auth_data + ahp->icv_trunc_len);
    +	icv = ah_tmp_icv(seqhi, seqhi_len);
     
     	err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
     	if (err)
    -- 
    cgit 1.3-korg
    
    
    

Vulnerability mechanics

Root cause

"The async completion callbacks in ah4.c and ah6.c fail to account for the 4-byte ESN seqhi slot when reconstructing the temporary auth/ICV layout, causing them to read/write at wrong offsets."

Attack vector

An attacker who can send IPsec AH packets that trigger an asynchronous ahash operation (e.g., using a software crypto driver that runs asynchronously, or a hardware AH engine) against a system with Extended Sequence Numbers (ESN) enabled will cause the kernel to copy or compare the wrong bytes during ICV verification. On the output path, the wrong bytes are copied into the AH authentication data field; on the input path, the wrong bytes are compared, leading to ICV mismatch and 100% packet loss. The bug affects both IPv4 AH (net/ipv4/ah4.c) and IPv6 AH (net/ipv6/ah6.c) [patch_id=2897881][patch_id=2897885].

Affected code

The bug is in the async completion callbacks `ah_output_done` and `ah_input_done` in `net/ipv4/ah4.c`, and `ah6_output_done` and `ah6_input_done` in `net/ipv6/ah6.c` [patch_id=2897881][patch_id=2897885]. These functions reconstruct the temporary auth/ICV layout without accounting for the ESN seqhi slot that the setup path (the synchronous ahash request builder) appends.

What the fix does

The patch adds a conditional `seqhi_len` variable (set to `sizeof(__be32)` when `XFRM_STATE_ESN` is set) and inserts a pointer arithmetic step to skip over the seqhi slot before calling `ah_tmp_icv()` or `ah_tmp_auth()`. In `ah_output_done` and `ah_input_done` for both IPv4 and IPv6, the old code passed the previous buffer pointer directly as the base for the next layout element; the new code computes a `seqhi` pointer at the boundary and passes it as the base, so the helper macros account for the 4-byte ESN slot. This makes the callback-side layout match the setup-side layout that already included the seqhi slot [patch_id=2897881][patch_id=2897885].

Preconditions

  • configThe IPsec SA must have Extended Sequence Numbers (ESN) enabled (XFRM_STATE_ESN flag set).
  • configAn asynchronous AH implementation must be in use (e.g., forced async hmac(sha1) or a hardware AH engine).
  • networkThe attacker must be able to send or receive IPsec AH packets that traverse the affected SA.

Generated on May 28, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.