VYPR
Unrated severityNVD Advisory· Published May 27, 2026· Updated May 27, 2026

CVE-2026-45850

CVE-2026-45850

Description

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

ipvs: skip ipv6 extension headers for csum checks

Protocol checksum validation fails for IPv6 if there are extension headers before the protocol header. iph->len already contains its offset, so use it to fix the problem.

Affected products

1

Patches

4
a3ca27762ce8

ipvs: skip ipv6 extension headers for csum checks

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitJulian AnastasovFeb 14, 2026Fixed in 6.19.4via kernel-cna
6 files changed · +40 80
  • net/netfilter/ipvs/ip_vs_proto_sctp.c+6 12 modified
    diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c
    index 83e452916403d5..63c78a1f3918a7 100644
    --- a/net/netfilter/ipvs/ip_vs_proto_sctp.c
    +++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c
    @@ -10,7 +10,8 @@
     #include <net/ip_vs.h>
     
     static int
    -sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp);
    +sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +		unsigned int sctphoff);
     
     static int
     sctp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
    @@ -108,7 +109,7 @@ sctp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!sctp_csum_check(cp->af, skb, pp))
    +		if (!sctp_csum_check(cp->af, skb, pp, sctphoff))
     			return 0;
     
     		/* Call application helper if needed */
    @@ -156,7 +157,7 @@ sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!sctp_csum_check(cp->af, skb, pp))
    +		if (!sctp_csum_check(cp->af, skb, pp, sctphoff))
     			return 0;
     
     		/* Call application helper if needed */
    @@ -185,19 +186,12 @@ sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     }
     
     static int
    -sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
    +sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +		unsigned int sctphoff)
     {
    -	unsigned int sctphoff;
     	struct sctphdr *sh;
     	__le32 cmp, val;
     
    -#ifdef CONFIG_IP_VS_IPV6
    -	if (af == AF_INET6)
    -		sctphoff = sizeof(struct ipv6hdr);
    -	else
    -#endif
    -		sctphoff = ip_hdrlen(skb);
    -
     	sh = (struct sctphdr *)(skb->data + sctphoff);
     	cmp = sh->checksum;
     	val = sctp_compute_cksum(skb, sctphoff);
    
  • net/netfilter/ipvs/ip_vs_proto_sctp.c+6 12 modified
    diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c
    index 83e452916403d5..63c78a1f3918a7 100644
    --- a/net/netfilter/ipvs/ip_vs_proto_sctp.c
    +++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c
    @@ -10,7 +10,8 @@
     #include <net/ip_vs.h>
     
     static int
    -sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp);
    +sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +		unsigned int sctphoff);
     
     static int
     sctp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
    @@ -108,7 +109,7 @@ sctp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!sctp_csum_check(cp->af, skb, pp))
    +		if (!sctp_csum_check(cp->af, skb, pp, sctphoff))
     			return 0;
     
     		/* Call application helper if needed */
    @@ -156,7 +157,7 @@ sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!sctp_csum_check(cp->af, skb, pp))
    +		if (!sctp_csum_check(cp->af, skb, pp, sctphoff))
     			return 0;
     
     		/* Call application helper if needed */
    @@ -185,19 +186,12 @@ sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     }
     
     static int
    -sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
    +sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +		unsigned int sctphoff)
     {
    -	unsigned int sctphoff;
     	struct sctphdr *sh;
     	__le32 cmp, val;
     
    -#ifdef CONFIG_IP_VS_IPV6
    -	if (af == AF_INET6)
    -		sctphoff = sizeof(struct ipv6hdr);
    -	else
    -#endif
    -		sctphoff = ip_hdrlen(skb);
    -
     	sh = (struct sctphdr *)(skb->data + sctphoff);
     	cmp = sh->checksum;
     	val = sctp_compute_cksum(skb, sctphoff);
    
  • net/netfilter/ipvs/ip_vs_proto_tcp.c+7 14 modified
    diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c
    index f68a1533ee455e..8cc0a8ce624112 100644
    --- a/net/netfilter/ipvs/ip_vs_proto_tcp.c
    +++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c
    @@ -28,7 +28,8 @@
     #include <net/ip_vs.h>
     
     static int
    -tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp);
    +tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int tcphoff);
     
     static int
     tcp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
    @@ -165,7 +166,7 @@ tcp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!tcp_csum_check(cp->af, skb, pp))
    +		if (!tcp_csum_check(cp->af, skb, pp, tcphoff))
     			return 0;
     
     		/* Call application helper if needed */
    @@ -243,7 +244,7 @@ tcp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!tcp_csum_check(cp->af, skb, pp))
    +		if (!tcp_csum_check(cp->af, skb, pp, tcphoff))
     			return 0;
     
     		/*
    @@ -300,17 +301,9 @@ tcp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     
     
     static int
    -tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
    +tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int tcphoff)
     {
    -	unsigned int tcphoff;
    -
    -#ifdef CONFIG_IP_VS_IPV6
    -	if (af == AF_INET6)
    -		tcphoff = sizeof(struct ipv6hdr);
    -	else
    -#endif
    -		tcphoff = ip_hdrlen(skb);
    -
     	switch (skb->ip_summed) {
     	case CHECKSUM_NONE:
     		skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
    @@ -321,7 +314,7 @@ tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
     			if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
     					    &ipv6_hdr(skb)->daddr,
     					    skb->len - tcphoff,
    -					    ipv6_hdr(skb)->nexthdr,
    +					    IPPROTO_TCP,
     					    skb->csum)) {
     				IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
     						 "Failed checksum for");
    
  • net/netfilter/ipvs/ip_vs_proto_tcp.c+7 14 modified
    diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c
    index f68a1533ee455e..8cc0a8ce624112 100644
    --- a/net/netfilter/ipvs/ip_vs_proto_tcp.c
    +++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c
    @@ -28,7 +28,8 @@
     #include <net/ip_vs.h>
     
     static int
    -tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp);
    +tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int tcphoff);
     
     static int
     tcp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
    @@ -165,7 +166,7 @@ tcp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!tcp_csum_check(cp->af, skb, pp))
    +		if (!tcp_csum_check(cp->af, skb, pp, tcphoff))
     			return 0;
     
     		/* Call application helper if needed */
    @@ -243,7 +244,7 @@ tcp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!tcp_csum_check(cp->af, skb, pp))
    +		if (!tcp_csum_check(cp->af, skb, pp, tcphoff))
     			return 0;
     
     		/*
    @@ -300,17 +301,9 @@ tcp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     
     
     static int
    -tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
    +tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int tcphoff)
     {
    -	unsigned int tcphoff;
    -
    -#ifdef CONFIG_IP_VS_IPV6
    -	if (af == AF_INET6)
    -		tcphoff = sizeof(struct ipv6hdr);
    -	else
    -#endif
    -		tcphoff = ip_hdrlen(skb);
    -
     	switch (skb->ip_summed) {
     	case CHECKSUM_NONE:
     		skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
    @@ -321,7 +314,7 @@ tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
     			if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
     					    &ipv6_hdr(skb)->daddr,
     					    skb->len - tcphoff,
    -					    ipv6_hdr(skb)->nexthdr,
    +					    IPPROTO_TCP,
     					    skb->csum)) {
     				IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
     						 "Failed checksum for");
    
  • net/netfilter/ipvs/ip_vs_proto_udp.c+7 14 modified
    diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c
    index 0f0107c80dd235..f9de632e38cdd6 100644
    --- a/net/netfilter/ipvs/ip_vs_proto_udp.c
    +++ b/net/netfilter/ipvs/ip_vs_proto_udp.c
    @@ -24,7 +24,8 @@
     #include <net/ip6_checksum.h>
     
     static int
    -udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp);
    +udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int udphoff);
     
     static int
     udp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
    @@ -154,7 +155,7 @@ udp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!udp_csum_check(cp->af, skb, pp))
    +		if (!udp_csum_check(cp->af, skb, pp, udphoff))
     			return 0;
     
     		/*
    @@ -237,7 +238,7 @@ udp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!udp_csum_check(cp->af, skb, pp))
    +		if (!udp_csum_check(cp->af, skb, pp, udphoff))
     			return 0;
     
     		/*
    @@ -296,17 +297,10 @@ udp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     
     
     static int
    -udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
    +udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int udphoff)
     {
     	struct udphdr _udph, *uh;
    -	unsigned int udphoff;
    -
    -#ifdef CONFIG_IP_VS_IPV6
    -	if (af == AF_INET6)
    -		udphoff = sizeof(struct ipv6hdr);
    -	else
    -#endif
    -		udphoff = ip_hdrlen(skb);
     
     	uh = skb_header_pointer(skb, udphoff, sizeof(_udph), &_udph);
     	if (uh == NULL)
    @@ -324,7 +318,7 @@ udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
     				if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
     						    &ipv6_hdr(skb)->daddr,
     						    skb->len - udphoff,
    -						    ipv6_hdr(skb)->nexthdr,
    +						    IPPROTO_UDP,
     						    skb->csum)) {
     					IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
     							 "Failed checksum for");
    -- 
    cgit 1.3-korg
    
    
    
  • net/netfilter/ipvs/ip_vs_proto_udp.c+7 14 modified
    diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c
    index 0f0107c80dd235..f9de632e38cdd6 100644
    --- a/net/netfilter/ipvs/ip_vs_proto_udp.c
    +++ b/net/netfilter/ipvs/ip_vs_proto_udp.c
    @@ -24,7 +24,8 @@
     #include <net/ip6_checksum.h>
     
     static int
    -udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp);
    +udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int udphoff);
     
     static int
     udp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
    @@ -154,7 +155,7 @@ udp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!udp_csum_check(cp->af, skb, pp))
    +		if (!udp_csum_check(cp->af, skb, pp, udphoff))
     			return 0;
     
     		/*
    @@ -237,7 +238,7 @@ udp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!udp_csum_check(cp->af, skb, pp))
    +		if (!udp_csum_check(cp->af, skb, pp, udphoff))
     			return 0;
     
     		/*
    @@ -296,17 +297,10 @@ udp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     
     
     static int
    -udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
    +udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int udphoff)
     {
     	struct udphdr _udph, *uh;
    -	unsigned int udphoff;
    -
    -#ifdef CONFIG_IP_VS_IPV6
    -	if (af == AF_INET6)
    -		udphoff = sizeof(struct ipv6hdr);
    -	else
    -#endif
    -		udphoff = ip_hdrlen(skb);
     
     	uh = skb_header_pointer(skb, udphoff, sizeof(_udph), &_udph);
     	if (uh == NULL)
    @@ -324,7 +318,7 @@ udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
     				if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
     						    &ipv6_hdr(skb)->daddr,
     						    skb->len - udphoff,
    -						    ipv6_hdr(skb)->nexthdr,
    +						    IPPROTO_UDP,
     						    skb->csum)) {
     					IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
     							 "Failed checksum for");
    -- 
    cgit 1.3-korg
    
    
    
05cfe9863ef0

ipvs: skip ipv6 extension headers for csum checks

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitJulian AnastasovFeb 14, 2026Fixed in 7.0via kernel-cna
6 files changed · +40 80
  • net/netfilter/ipvs/ip_vs_proto_sctp.c+6 12 modified
    diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c
    index 83e452916403d5..63c78a1f3918a7 100644
    --- a/net/netfilter/ipvs/ip_vs_proto_sctp.c
    +++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c
    @@ -10,7 +10,8 @@
     #include <net/ip_vs.h>
     
     static int
    -sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp);
    +sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +		unsigned int sctphoff);
     
     static int
     sctp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
    @@ -108,7 +109,7 @@ sctp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!sctp_csum_check(cp->af, skb, pp))
    +		if (!sctp_csum_check(cp->af, skb, pp, sctphoff))
     			return 0;
     
     		/* Call application helper if needed */
    @@ -156,7 +157,7 @@ sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!sctp_csum_check(cp->af, skb, pp))
    +		if (!sctp_csum_check(cp->af, skb, pp, sctphoff))
     			return 0;
     
     		/* Call application helper if needed */
    @@ -185,19 +186,12 @@ sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     }
     
     static int
    -sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
    +sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +		unsigned int sctphoff)
     {
    -	unsigned int sctphoff;
     	struct sctphdr *sh;
     	__le32 cmp, val;
     
    -#ifdef CONFIG_IP_VS_IPV6
    -	if (af == AF_INET6)
    -		sctphoff = sizeof(struct ipv6hdr);
    -	else
    -#endif
    -		sctphoff = ip_hdrlen(skb);
    -
     	sh = (struct sctphdr *)(skb->data + sctphoff);
     	cmp = sh->checksum;
     	val = sctp_compute_cksum(skb, sctphoff);
    
  • net/netfilter/ipvs/ip_vs_proto_sctp.c+6 12 modified
    diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c
    index 83e452916403d5..63c78a1f3918a7 100644
    --- a/net/netfilter/ipvs/ip_vs_proto_sctp.c
    +++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c
    @@ -10,7 +10,8 @@
     #include <net/ip_vs.h>
     
     static int
    -sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp);
    +sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +		unsigned int sctphoff);
     
     static int
     sctp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
    @@ -108,7 +109,7 @@ sctp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!sctp_csum_check(cp->af, skb, pp))
    +		if (!sctp_csum_check(cp->af, skb, pp, sctphoff))
     			return 0;
     
     		/* Call application helper if needed */
    @@ -156,7 +157,7 @@ sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!sctp_csum_check(cp->af, skb, pp))
    +		if (!sctp_csum_check(cp->af, skb, pp, sctphoff))
     			return 0;
     
     		/* Call application helper if needed */
    @@ -185,19 +186,12 @@ sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     }
     
     static int
    -sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
    +sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +		unsigned int sctphoff)
     {
    -	unsigned int sctphoff;
     	struct sctphdr *sh;
     	__le32 cmp, val;
     
    -#ifdef CONFIG_IP_VS_IPV6
    -	if (af == AF_INET6)
    -		sctphoff = sizeof(struct ipv6hdr);
    -	else
    -#endif
    -		sctphoff = ip_hdrlen(skb);
    -
     	sh = (struct sctphdr *)(skb->data + sctphoff);
     	cmp = sh->checksum;
     	val = sctp_compute_cksum(skb, sctphoff);
    
  • net/netfilter/ipvs/ip_vs_proto_tcp.c+7 14 modified
    diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c
    index f68a1533ee455e..8cc0a8ce624112 100644
    --- a/net/netfilter/ipvs/ip_vs_proto_tcp.c
    +++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c
    @@ -28,7 +28,8 @@
     #include <net/ip_vs.h>
     
     static int
    -tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp);
    +tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int tcphoff);
     
     static int
     tcp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
    @@ -165,7 +166,7 @@ tcp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!tcp_csum_check(cp->af, skb, pp))
    +		if (!tcp_csum_check(cp->af, skb, pp, tcphoff))
     			return 0;
     
     		/* Call application helper if needed */
    @@ -243,7 +244,7 @@ tcp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!tcp_csum_check(cp->af, skb, pp))
    +		if (!tcp_csum_check(cp->af, skb, pp, tcphoff))
     			return 0;
     
     		/*
    @@ -300,17 +301,9 @@ tcp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     
     
     static int
    -tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
    +tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int tcphoff)
     {
    -	unsigned int tcphoff;
    -
    -#ifdef CONFIG_IP_VS_IPV6
    -	if (af == AF_INET6)
    -		tcphoff = sizeof(struct ipv6hdr);
    -	else
    -#endif
    -		tcphoff = ip_hdrlen(skb);
    -
     	switch (skb->ip_summed) {
     	case CHECKSUM_NONE:
     		skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
    @@ -321,7 +314,7 @@ tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
     			if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
     					    &ipv6_hdr(skb)->daddr,
     					    skb->len - tcphoff,
    -					    ipv6_hdr(skb)->nexthdr,
    +					    IPPROTO_TCP,
     					    skb->csum)) {
     				IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
     						 "Failed checksum for");
    
  • net/netfilter/ipvs/ip_vs_proto_tcp.c+7 14 modified
    diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c
    index f68a1533ee455e..8cc0a8ce624112 100644
    --- a/net/netfilter/ipvs/ip_vs_proto_tcp.c
    +++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c
    @@ -28,7 +28,8 @@
     #include <net/ip_vs.h>
     
     static int
    -tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp);
    +tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int tcphoff);
     
     static int
     tcp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
    @@ -165,7 +166,7 @@ tcp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!tcp_csum_check(cp->af, skb, pp))
    +		if (!tcp_csum_check(cp->af, skb, pp, tcphoff))
     			return 0;
     
     		/* Call application helper if needed */
    @@ -243,7 +244,7 @@ tcp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!tcp_csum_check(cp->af, skb, pp))
    +		if (!tcp_csum_check(cp->af, skb, pp, tcphoff))
     			return 0;
     
     		/*
    @@ -300,17 +301,9 @@ tcp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     
     
     static int
    -tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
    +tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int tcphoff)
     {
    -	unsigned int tcphoff;
    -
    -#ifdef CONFIG_IP_VS_IPV6
    -	if (af == AF_INET6)
    -		tcphoff = sizeof(struct ipv6hdr);
    -	else
    -#endif
    -		tcphoff = ip_hdrlen(skb);
    -
     	switch (skb->ip_summed) {
     	case CHECKSUM_NONE:
     		skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
    @@ -321,7 +314,7 @@ tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
     			if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
     					    &ipv6_hdr(skb)->daddr,
     					    skb->len - tcphoff,
    -					    ipv6_hdr(skb)->nexthdr,
    +					    IPPROTO_TCP,
     					    skb->csum)) {
     				IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
     						 "Failed checksum for");
    
  • net/netfilter/ipvs/ip_vs_proto_udp.c+7 14 modified
    diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c
    index 0f0107c80dd235..f9de632e38cdd6 100644
    --- a/net/netfilter/ipvs/ip_vs_proto_udp.c
    +++ b/net/netfilter/ipvs/ip_vs_proto_udp.c
    @@ -24,7 +24,8 @@
     #include <net/ip6_checksum.h>
     
     static int
    -udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp);
    +udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int udphoff);
     
     static int
     udp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
    @@ -154,7 +155,7 @@ udp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!udp_csum_check(cp->af, skb, pp))
    +		if (!udp_csum_check(cp->af, skb, pp, udphoff))
     			return 0;
     
     		/*
    @@ -237,7 +238,7 @@ udp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!udp_csum_check(cp->af, skb, pp))
    +		if (!udp_csum_check(cp->af, skb, pp, udphoff))
     			return 0;
     
     		/*
    @@ -296,17 +297,10 @@ udp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     
     
     static int
    -udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
    +udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int udphoff)
     {
     	struct udphdr _udph, *uh;
    -	unsigned int udphoff;
    -
    -#ifdef CONFIG_IP_VS_IPV6
    -	if (af == AF_INET6)
    -		udphoff = sizeof(struct ipv6hdr);
    -	else
    -#endif
    -		udphoff = ip_hdrlen(skb);
     
     	uh = skb_header_pointer(skb, udphoff, sizeof(_udph), &_udph);
     	if (uh == NULL)
    @@ -324,7 +318,7 @@ udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
     				if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
     						    &ipv6_hdr(skb)->daddr,
     						    skb->len - udphoff,
    -						    ipv6_hdr(skb)->nexthdr,
    +						    IPPROTO_UDP,
     						    skb->csum)) {
     					IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
     							 "Failed checksum for");
    -- 
    cgit 1.3-korg
    
    
    
  • net/netfilter/ipvs/ip_vs_proto_udp.c+7 14 modified
    diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c
    index 0f0107c80dd235..f9de632e38cdd6 100644
    --- a/net/netfilter/ipvs/ip_vs_proto_udp.c
    +++ b/net/netfilter/ipvs/ip_vs_proto_udp.c
    @@ -24,7 +24,8 @@
     #include <net/ip6_checksum.h>
     
     static int
    -udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp);
    +udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int udphoff);
     
     static int
     udp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
    @@ -154,7 +155,7 @@ udp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!udp_csum_check(cp->af, skb, pp))
    +		if (!udp_csum_check(cp->af, skb, pp, udphoff))
     			return 0;
     
     		/*
    @@ -237,7 +238,7 @@ udp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!udp_csum_check(cp->af, skb, pp))
    +		if (!udp_csum_check(cp->af, skb, pp, udphoff))
     			return 0;
     
     		/*
    @@ -296,17 +297,10 @@ udp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     
     
     static int
    -udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
    +udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int udphoff)
     {
     	struct udphdr _udph, *uh;
    -	unsigned int udphoff;
    -
    -#ifdef CONFIG_IP_VS_IPV6
    -	if (af == AF_INET6)
    -		udphoff = sizeof(struct ipv6hdr);
    -	else
    -#endif
    -		udphoff = ip_hdrlen(skb);
     
     	uh = skb_header_pointer(skb, udphoff, sizeof(_udph), &_udph);
     	if (uh == NULL)
    @@ -324,7 +318,7 @@ udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
     				if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
     						    &ipv6_hdr(skb)->daddr,
     						    skb->len - udphoff,
    -						    ipv6_hdr(skb)->nexthdr,
    +						    IPPROTO_UDP,
     						    skb->csum)) {
     					IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
     							 "Failed checksum for");
    -- 
    cgit 1.3-korg
    
    
    
a3ca27762ce8

ipvs: skip ipv6 extension headers for csum checks

6 files changed · +40 80
  • net/netfilter/ipvs/ip_vs_proto_sctp.c+6 12 modified
    diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c
    index 83e452916403d5..63c78a1f3918a7 100644
    --- a/net/netfilter/ipvs/ip_vs_proto_sctp.c
    +++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c
    @@ -10,7 +10,8 @@
     #include <net/ip_vs.h>
     
     static int
    -sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp);
    +sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +		unsigned int sctphoff);
     
     static int
     sctp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
    @@ -108,7 +109,7 @@ sctp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!sctp_csum_check(cp->af, skb, pp))
    +		if (!sctp_csum_check(cp->af, skb, pp, sctphoff))
     			return 0;
     
     		/* Call application helper if needed */
    @@ -156,7 +157,7 @@ sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!sctp_csum_check(cp->af, skb, pp))
    +		if (!sctp_csum_check(cp->af, skb, pp, sctphoff))
     			return 0;
     
     		/* Call application helper if needed */
    @@ -185,19 +186,12 @@ sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     }
     
     static int
    -sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
    +sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +		unsigned int sctphoff)
     {
    -	unsigned int sctphoff;
     	struct sctphdr *sh;
     	__le32 cmp, val;
     
    -#ifdef CONFIG_IP_VS_IPV6
    -	if (af == AF_INET6)
    -		sctphoff = sizeof(struct ipv6hdr);
    -	else
    -#endif
    -		sctphoff = ip_hdrlen(skb);
    -
     	sh = (struct sctphdr *)(skb->data + sctphoff);
     	cmp = sh->checksum;
     	val = sctp_compute_cksum(skb, sctphoff);
    
  • net/netfilter/ipvs/ip_vs_proto_sctp.c+6 12 modified
    diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c
    index 83e452916403d5..63c78a1f3918a7 100644
    --- a/net/netfilter/ipvs/ip_vs_proto_sctp.c
    +++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c
    @@ -10,7 +10,8 @@
     #include <net/ip_vs.h>
     
     static int
    -sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp);
    +sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +		unsigned int sctphoff);
     
     static int
     sctp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
    @@ -108,7 +109,7 @@ sctp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!sctp_csum_check(cp->af, skb, pp))
    +		if (!sctp_csum_check(cp->af, skb, pp, sctphoff))
     			return 0;
     
     		/* Call application helper if needed */
    @@ -156,7 +157,7 @@ sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!sctp_csum_check(cp->af, skb, pp))
    +		if (!sctp_csum_check(cp->af, skb, pp, sctphoff))
     			return 0;
     
     		/* Call application helper if needed */
    @@ -185,19 +186,12 @@ sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     }
     
     static int
    -sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
    +sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +		unsigned int sctphoff)
     {
    -	unsigned int sctphoff;
     	struct sctphdr *sh;
     	__le32 cmp, val;
     
    -#ifdef CONFIG_IP_VS_IPV6
    -	if (af == AF_INET6)
    -		sctphoff = sizeof(struct ipv6hdr);
    -	else
    -#endif
    -		sctphoff = ip_hdrlen(skb);
    -
     	sh = (struct sctphdr *)(skb->data + sctphoff);
     	cmp = sh->checksum;
     	val = sctp_compute_cksum(skb, sctphoff);
    
  • net/netfilter/ipvs/ip_vs_proto_tcp.c+7 14 modified
    diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c
    index f68a1533ee455e..8cc0a8ce624112 100644
    --- a/net/netfilter/ipvs/ip_vs_proto_tcp.c
    +++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c
    @@ -28,7 +28,8 @@
     #include <net/ip_vs.h>
     
     static int
    -tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp);
    +tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int tcphoff);
     
     static int
     tcp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
    @@ -165,7 +166,7 @@ tcp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!tcp_csum_check(cp->af, skb, pp))
    +		if (!tcp_csum_check(cp->af, skb, pp, tcphoff))
     			return 0;
     
     		/* Call application helper if needed */
    @@ -243,7 +244,7 @@ tcp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!tcp_csum_check(cp->af, skb, pp))
    +		if (!tcp_csum_check(cp->af, skb, pp, tcphoff))
     			return 0;
     
     		/*
    @@ -300,17 +301,9 @@ tcp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     
     
     static int
    -tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
    +tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int tcphoff)
     {
    -	unsigned int tcphoff;
    -
    -#ifdef CONFIG_IP_VS_IPV6
    -	if (af == AF_INET6)
    -		tcphoff = sizeof(struct ipv6hdr);
    -	else
    -#endif
    -		tcphoff = ip_hdrlen(skb);
    -
     	switch (skb->ip_summed) {
     	case CHECKSUM_NONE:
     		skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
    @@ -321,7 +314,7 @@ tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
     			if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
     					    &ipv6_hdr(skb)->daddr,
     					    skb->len - tcphoff,
    -					    ipv6_hdr(skb)->nexthdr,
    +					    IPPROTO_TCP,
     					    skb->csum)) {
     				IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
     						 "Failed checksum for");
    
  • net/netfilter/ipvs/ip_vs_proto_tcp.c+7 14 modified
    diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c
    index f68a1533ee455e..8cc0a8ce624112 100644
    --- a/net/netfilter/ipvs/ip_vs_proto_tcp.c
    +++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c
    @@ -28,7 +28,8 @@
     #include <net/ip_vs.h>
     
     static int
    -tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp);
    +tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int tcphoff);
     
     static int
     tcp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
    @@ -165,7 +166,7 @@ tcp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!tcp_csum_check(cp->af, skb, pp))
    +		if (!tcp_csum_check(cp->af, skb, pp, tcphoff))
     			return 0;
     
     		/* Call application helper if needed */
    @@ -243,7 +244,7 @@ tcp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!tcp_csum_check(cp->af, skb, pp))
    +		if (!tcp_csum_check(cp->af, skb, pp, tcphoff))
     			return 0;
     
     		/*
    @@ -300,17 +301,9 @@ tcp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     
     
     static int
    -tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
    +tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int tcphoff)
     {
    -	unsigned int tcphoff;
    -
    -#ifdef CONFIG_IP_VS_IPV6
    -	if (af == AF_INET6)
    -		tcphoff = sizeof(struct ipv6hdr);
    -	else
    -#endif
    -		tcphoff = ip_hdrlen(skb);
    -
     	switch (skb->ip_summed) {
     	case CHECKSUM_NONE:
     		skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
    @@ -321,7 +314,7 @@ tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
     			if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
     					    &ipv6_hdr(skb)->daddr,
     					    skb->len - tcphoff,
    -					    ipv6_hdr(skb)->nexthdr,
    +					    IPPROTO_TCP,
     					    skb->csum)) {
     				IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
     						 "Failed checksum for");
    
  • net/netfilter/ipvs/ip_vs_proto_udp.c+7 14 modified
    diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c
    index 0f0107c80dd235..f9de632e38cdd6 100644
    --- a/net/netfilter/ipvs/ip_vs_proto_udp.c
    +++ b/net/netfilter/ipvs/ip_vs_proto_udp.c
    @@ -24,7 +24,8 @@
     #include <net/ip6_checksum.h>
     
     static int
    -udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp);
    +udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int udphoff);
     
     static int
     udp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
    @@ -154,7 +155,7 @@ udp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!udp_csum_check(cp->af, skb, pp))
    +		if (!udp_csum_check(cp->af, skb, pp, udphoff))
     			return 0;
     
     		/*
    @@ -237,7 +238,7 @@ udp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!udp_csum_check(cp->af, skb, pp))
    +		if (!udp_csum_check(cp->af, skb, pp, udphoff))
     			return 0;
     
     		/*
    @@ -296,17 +297,10 @@ udp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     
     
     static int
    -udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
    +udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int udphoff)
     {
     	struct udphdr _udph, *uh;
    -	unsigned int udphoff;
    -
    -#ifdef CONFIG_IP_VS_IPV6
    -	if (af == AF_INET6)
    -		udphoff = sizeof(struct ipv6hdr);
    -	else
    -#endif
    -		udphoff = ip_hdrlen(skb);
     
     	uh = skb_header_pointer(skb, udphoff, sizeof(_udph), &_udph);
     	if (uh == NULL)
    @@ -324,7 +318,7 @@ udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
     				if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
     						    &ipv6_hdr(skb)->daddr,
     						    skb->len - udphoff,
    -						    ipv6_hdr(skb)->nexthdr,
    +						    IPPROTO_UDP,
     						    skb->csum)) {
     					IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
     							 "Failed checksum for");
    -- 
    cgit 1.3-korg
    
    
    
  • net/netfilter/ipvs/ip_vs_proto_udp.c+7 14 modified
    diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c
    index 0f0107c80dd235..f9de632e38cdd6 100644
    --- a/net/netfilter/ipvs/ip_vs_proto_udp.c
    +++ b/net/netfilter/ipvs/ip_vs_proto_udp.c
    @@ -24,7 +24,8 @@
     #include <net/ip6_checksum.h>
     
     static int
    -udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp);
    +udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int udphoff);
     
     static int
     udp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
    @@ -154,7 +155,7 @@ udp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!udp_csum_check(cp->af, skb, pp))
    +		if (!udp_csum_check(cp->af, skb, pp, udphoff))
     			return 0;
     
     		/*
    @@ -237,7 +238,7 @@ udp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!udp_csum_check(cp->af, skb, pp))
    +		if (!udp_csum_check(cp->af, skb, pp, udphoff))
     			return 0;
     
     		/*
    @@ -296,17 +297,10 @@ udp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     
     
     static int
    -udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
    +udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int udphoff)
     {
     	struct udphdr _udph, *uh;
    -	unsigned int udphoff;
    -
    -#ifdef CONFIG_IP_VS_IPV6
    -	if (af == AF_INET6)
    -		udphoff = sizeof(struct ipv6hdr);
    -	else
    -#endif
    -		udphoff = ip_hdrlen(skb);
     
     	uh = skb_header_pointer(skb, udphoff, sizeof(_udph), &_udph);
     	if (uh == NULL)
    @@ -324,7 +318,7 @@ udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
     				if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
     						    &ipv6_hdr(skb)->daddr,
     						    skb->len - udphoff,
    -						    ipv6_hdr(skb)->nexthdr,
    +						    IPPROTO_UDP,
     						    skb->csum)) {
     					IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
     							 "Failed checksum for");
    -- 
    cgit 1.3-korg
    
    
    
05cfe9863ef0

ipvs: skip ipv6 extension headers for csum checks

6 files changed · +40 80
  • net/netfilter/ipvs/ip_vs_proto_sctp.c+6 12 modified
    diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c
    index 83e452916403d5..63c78a1f3918a7 100644
    --- a/net/netfilter/ipvs/ip_vs_proto_sctp.c
    +++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c
    @@ -10,7 +10,8 @@
     #include <net/ip_vs.h>
     
     static int
    -sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp);
    +sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +		unsigned int sctphoff);
     
     static int
     sctp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
    @@ -108,7 +109,7 @@ sctp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!sctp_csum_check(cp->af, skb, pp))
    +		if (!sctp_csum_check(cp->af, skb, pp, sctphoff))
     			return 0;
     
     		/* Call application helper if needed */
    @@ -156,7 +157,7 @@ sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!sctp_csum_check(cp->af, skb, pp))
    +		if (!sctp_csum_check(cp->af, skb, pp, sctphoff))
     			return 0;
     
     		/* Call application helper if needed */
    @@ -185,19 +186,12 @@ sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     }
     
     static int
    -sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
    +sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +		unsigned int sctphoff)
     {
    -	unsigned int sctphoff;
     	struct sctphdr *sh;
     	__le32 cmp, val;
     
    -#ifdef CONFIG_IP_VS_IPV6
    -	if (af == AF_INET6)
    -		sctphoff = sizeof(struct ipv6hdr);
    -	else
    -#endif
    -		sctphoff = ip_hdrlen(skb);
    -
     	sh = (struct sctphdr *)(skb->data + sctphoff);
     	cmp = sh->checksum;
     	val = sctp_compute_cksum(skb, sctphoff);
    
  • net/netfilter/ipvs/ip_vs_proto_sctp.c+6 12 modified
    diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c
    index 83e452916403d5..63c78a1f3918a7 100644
    --- a/net/netfilter/ipvs/ip_vs_proto_sctp.c
    +++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c
    @@ -10,7 +10,8 @@
     #include <net/ip_vs.h>
     
     static int
    -sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp);
    +sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +		unsigned int sctphoff);
     
     static int
     sctp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
    @@ -108,7 +109,7 @@ sctp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!sctp_csum_check(cp->af, skb, pp))
    +		if (!sctp_csum_check(cp->af, skb, pp, sctphoff))
     			return 0;
     
     		/* Call application helper if needed */
    @@ -156,7 +157,7 @@ sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!sctp_csum_check(cp->af, skb, pp))
    +		if (!sctp_csum_check(cp->af, skb, pp, sctphoff))
     			return 0;
     
     		/* Call application helper if needed */
    @@ -185,19 +186,12 @@ sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     }
     
     static int
    -sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
    +sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +		unsigned int sctphoff)
     {
    -	unsigned int sctphoff;
     	struct sctphdr *sh;
     	__le32 cmp, val;
     
    -#ifdef CONFIG_IP_VS_IPV6
    -	if (af == AF_INET6)
    -		sctphoff = sizeof(struct ipv6hdr);
    -	else
    -#endif
    -		sctphoff = ip_hdrlen(skb);
    -
     	sh = (struct sctphdr *)(skb->data + sctphoff);
     	cmp = sh->checksum;
     	val = sctp_compute_cksum(skb, sctphoff);
    
  • net/netfilter/ipvs/ip_vs_proto_tcp.c+7 14 modified
    diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c
    index f68a1533ee455e..8cc0a8ce624112 100644
    --- a/net/netfilter/ipvs/ip_vs_proto_tcp.c
    +++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c
    @@ -28,7 +28,8 @@
     #include <net/ip_vs.h>
     
     static int
    -tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp);
    +tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int tcphoff);
     
     static int
     tcp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
    @@ -165,7 +166,7 @@ tcp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!tcp_csum_check(cp->af, skb, pp))
    +		if (!tcp_csum_check(cp->af, skb, pp, tcphoff))
     			return 0;
     
     		/* Call application helper if needed */
    @@ -243,7 +244,7 @@ tcp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!tcp_csum_check(cp->af, skb, pp))
    +		if (!tcp_csum_check(cp->af, skb, pp, tcphoff))
     			return 0;
     
     		/*
    @@ -300,17 +301,9 @@ tcp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     
     
     static int
    -tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
    +tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int tcphoff)
     {
    -	unsigned int tcphoff;
    -
    -#ifdef CONFIG_IP_VS_IPV6
    -	if (af == AF_INET6)
    -		tcphoff = sizeof(struct ipv6hdr);
    -	else
    -#endif
    -		tcphoff = ip_hdrlen(skb);
    -
     	switch (skb->ip_summed) {
     	case CHECKSUM_NONE:
     		skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
    @@ -321,7 +314,7 @@ tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
     			if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
     					    &ipv6_hdr(skb)->daddr,
     					    skb->len - tcphoff,
    -					    ipv6_hdr(skb)->nexthdr,
    +					    IPPROTO_TCP,
     					    skb->csum)) {
     				IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
     						 "Failed checksum for");
    
  • net/netfilter/ipvs/ip_vs_proto_tcp.c+7 14 modified
    diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c
    index f68a1533ee455e..8cc0a8ce624112 100644
    --- a/net/netfilter/ipvs/ip_vs_proto_tcp.c
    +++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c
    @@ -28,7 +28,8 @@
     #include <net/ip_vs.h>
     
     static int
    -tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp);
    +tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int tcphoff);
     
     static int
     tcp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
    @@ -165,7 +166,7 @@ tcp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!tcp_csum_check(cp->af, skb, pp))
    +		if (!tcp_csum_check(cp->af, skb, pp, tcphoff))
     			return 0;
     
     		/* Call application helper if needed */
    @@ -243,7 +244,7 @@ tcp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!tcp_csum_check(cp->af, skb, pp))
    +		if (!tcp_csum_check(cp->af, skb, pp, tcphoff))
     			return 0;
     
     		/*
    @@ -300,17 +301,9 @@ tcp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     
     
     static int
    -tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
    +tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int tcphoff)
     {
    -	unsigned int tcphoff;
    -
    -#ifdef CONFIG_IP_VS_IPV6
    -	if (af == AF_INET6)
    -		tcphoff = sizeof(struct ipv6hdr);
    -	else
    -#endif
    -		tcphoff = ip_hdrlen(skb);
    -
     	switch (skb->ip_summed) {
     	case CHECKSUM_NONE:
     		skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
    @@ -321,7 +314,7 @@ tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
     			if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
     					    &ipv6_hdr(skb)->daddr,
     					    skb->len - tcphoff,
    -					    ipv6_hdr(skb)->nexthdr,
    +					    IPPROTO_TCP,
     					    skb->csum)) {
     				IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
     						 "Failed checksum for");
    
  • net/netfilter/ipvs/ip_vs_proto_udp.c+7 14 modified
    diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c
    index 0f0107c80dd235..f9de632e38cdd6 100644
    --- a/net/netfilter/ipvs/ip_vs_proto_udp.c
    +++ b/net/netfilter/ipvs/ip_vs_proto_udp.c
    @@ -24,7 +24,8 @@
     #include <net/ip6_checksum.h>
     
     static int
    -udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp);
    +udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int udphoff);
     
     static int
     udp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
    @@ -154,7 +155,7 @@ udp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!udp_csum_check(cp->af, skb, pp))
    +		if (!udp_csum_check(cp->af, skb, pp, udphoff))
     			return 0;
     
     		/*
    @@ -237,7 +238,7 @@ udp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!udp_csum_check(cp->af, skb, pp))
    +		if (!udp_csum_check(cp->af, skb, pp, udphoff))
     			return 0;
     
     		/*
    @@ -296,17 +297,10 @@ udp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     
     
     static int
    -udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
    +udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int udphoff)
     {
     	struct udphdr _udph, *uh;
    -	unsigned int udphoff;
    -
    -#ifdef CONFIG_IP_VS_IPV6
    -	if (af == AF_INET6)
    -		udphoff = sizeof(struct ipv6hdr);
    -	else
    -#endif
    -		udphoff = ip_hdrlen(skb);
     
     	uh = skb_header_pointer(skb, udphoff, sizeof(_udph), &_udph);
     	if (uh == NULL)
    @@ -324,7 +318,7 @@ udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
     				if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
     						    &ipv6_hdr(skb)->daddr,
     						    skb->len - udphoff,
    -						    ipv6_hdr(skb)->nexthdr,
    +						    IPPROTO_UDP,
     						    skb->csum)) {
     					IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
     							 "Failed checksum for");
    -- 
    cgit 1.3-korg
    
    
    
  • net/netfilter/ipvs/ip_vs_proto_udp.c+7 14 modified
    diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c
    index 0f0107c80dd235..f9de632e38cdd6 100644
    --- a/net/netfilter/ipvs/ip_vs_proto_udp.c
    +++ b/net/netfilter/ipvs/ip_vs_proto_udp.c
    @@ -24,7 +24,8 @@
     #include <net/ip6_checksum.h>
     
     static int
    -udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp);
    +udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int udphoff);
     
     static int
     udp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
    @@ -154,7 +155,7 @@ udp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!udp_csum_check(cp->af, skb, pp))
    +		if (!udp_csum_check(cp->af, skb, pp, udphoff))
     			return 0;
     
     		/*
    @@ -237,7 +238,7 @@ udp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     		int ret;
     
     		/* Some checks before mangling */
    -		if (!udp_csum_check(cp->af, skb, pp))
    +		if (!udp_csum_check(cp->af, skb, pp, udphoff))
     			return 0;
     
     		/*
    @@ -296,17 +297,10 @@ udp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
     
     
     static int
    -udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
    +udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
    +	       unsigned int udphoff)
     {
     	struct udphdr _udph, *uh;
    -	unsigned int udphoff;
    -
    -#ifdef CONFIG_IP_VS_IPV6
    -	if (af == AF_INET6)
    -		udphoff = sizeof(struct ipv6hdr);
    -	else
    -#endif
    -		udphoff = ip_hdrlen(skb);
     
     	uh = skb_header_pointer(skb, udphoff, sizeof(_udph), &_udph);
     	if (uh == NULL)
    @@ -324,7 +318,7 @@ udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
     				if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
     						    &ipv6_hdr(skb)->daddr,
     						    skb->len - udphoff,
    -						    ipv6_hdr(skb)->nexthdr,
    +						    IPPROTO_UDP,
     						    skb->csum)) {
     					IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
     							 "Failed checksum for");
    -- 
    cgit 1.3-korg
    
    
    

Vulnerability mechanics

Root cause

"Incorrect protocol header offset calculation for IPv6 packets with extension headers causes checksum validation to fail."

Attack vector

An attacker can send crafted IPv6 packets that include extension headers (such as Hop-by-Hop, Routing, or Destination Options) before the TCP, UDP, or SCTP protocol header. Because the old code used a fixed offset (`sizeof(struct ipv6hdr)`) to locate the protocol header, the checksum validation would compute over the wrong byte range and use the wrong protocol identifier, causing legitimate packets to be incorrectly rejected as having bad checksums [patch_id=2662109]. This can disrupt IPVS load-balancing for IPv6 traffic that traverses paths inserting extension headers, effectively causing denial of service for those connections. No authentication is required; the attacker only needs the ability to send IPv6 packets to a system running IPVS with IPv6 support enabled.

Affected code

The vulnerability is in the IPVS protocol checksum validation functions in `net/netfilter/ipvs/ip_vs_proto_tcp.c`, `net/netfilter/ipvs/ip_vs_proto_udp.c`, and `net/netfilter/ipvs/ip_vs_proto_sctp.c` [patch_id=2662109]. The `tcp_csum_check`, `udp_csum_check`, and `sctp_csum_check` functions incorrectly computed the protocol header offset for IPv6 by using `sizeof(struct ipv6hdr)` instead of the actual offset that accounts for IPv6 extension headers [patch_id=2662109]. Additionally, the TCP and UDP checksum functions passed `ipv6_hdr(skb)->nexthdr` (which may point to an extension header) to `csum_ipv6_magic` instead of the actual protocol number (e.g., `IPPROTO_TCP` or `IPPROTO_UDP`) [patch_id=2662109].

What the fix does

The patch removes the local computation of `tcphoff`/`udphoff`/`sctphoff` inside each `*_csum_check` function and instead accepts the offset as a parameter from the caller [patch_id=2662109]. The callers (`tcp_snat_handler`, `tcp_dnat_handler`, etc.) already have the correct `tcphoff`/`udphoff`/`sctphoff` value that accounts for IPv6 extension headers via `iph->len`. For the TCP and UDP `csum_ipv6_magic` calls, the hardcoded `ipv6_hdr(skb)->nexthdr` is replaced with the literal protocol constant (`IPPROTO_TCP` or `IPPROTO_UDP`) so that the checksum is verified against the correct upper-layer protocol regardless of any extension headers present [patch_id=2662109].

Preconditions

  • configThe system must be running IPVS (IP Virtual Server) with IPv6 support enabled (CONFIG_IP_VS_IPV6).
  • networkThe attacker must be able to send IPv6 packets to a service managed by IPVS.
  • inputThe IPv6 packets must include extension headers before the TCP/UDP/SCTP protocol header.

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

References

2

News mentions

0

No linked articles in our index yet.