diff mbox series

[net-next,v2,1/5] udp_tunnel: properly deal with xfrm gro encap.

Message ID f4659f17b136eaec554d8678de0034c3578580c1.1742557254.git.pabeni@redhat.com (mailing list archive)
State New
Delegated to: Netdev Maintainers
Headers show
Series udp_tunnel: GRO optimization follow-up | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net-next
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 0 this patch: 0
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers success CCed 7 of 7 maintainers
netdev/build_clang success Errors and warnings before: 0 this patch: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success Fixes tag looks correct
netdev/build_allmodconfig_warn success Errors and warnings before: 11 this patch: 11
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 27 lines checked
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 3 this patch: 3
netdev/source_inline success Was 0 now: 0
netdev/contest warning net-next-2025-03-21--18-00 (tests: 896)

Commit Message

Paolo Abeni March 21, 2025, 11:52 a.m. UTC
The blamed commit below does not take in account that xfrm
can enable GRO over UDP encapsulation without going through
setup_udp_tunnel_sock().

At deletion time such socket will still go through
udp_tunnel_cleanup_gro(), and the failed GRO type lookup will
trigger the reported warning.

Add the GRO accounting for XFRM tunnel when GRO is enabled, and
adjust the known gro types accordingly.

Note that we can't use setup_udp_tunnel_sock() here, as the xfrm
tunnel setup can be "incremental" - e.g. the encapsulation is created
first and GRO is enabled later.

Also we can not allow GRO sk lookup optimization for XFRM tunnels, as
the socket could match the selection criteria at enable time, and
later on the user-space could disconnect/bind it breaking such
criteria.

Reported-by: syzbot+8c469a2260132cd095c1@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=8c469a2260132cd095c1
Fixes: 311b36574ceac ("udp_tunnel: use static call for GRO hooks when possible")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
---
v1 -> v2:
 - do proper account for xfrm, retain the warning
---
 net/ipv4/udp.c         | 5 +++++
 net/ipv4/udp_offload.c | 4 +++-
 2 files changed, 8 insertions(+), 1 deletion(-)

Comments

Willem de Bruijn March 21, 2025, 4:33 p.m. UTC | #1
Paolo Abeni wrote:
> The blamed commit below does not take in account that xfrm
> can enable GRO over UDP encapsulation without going through
> setup_udp_tunnel_sock().
> 
> At deletion time such socket will still go through
> udp_tunnel_cleanup_gro(), and the failed GRO type lookup will
> trigger the reported warning.
> 
> Add the GRO accounting for XFRM tunnel when GRO is enabled, and
> adjust the known gro types accordingly.
> 
> Note that we can't use setup_udp_tunnel_sock() here, as the xfrm
> tunnel setup can be "incremental" - e.g. the encapsulation is created
> first and GRO is enabled later.
> 
> Also we can not allow GRO sk lookup optimization for XFRM tunnels, as
> the socket could match the selection criteria at enable time, and
> later on the user-space could disconnect/bind it breaking such
> criteria.
> 
> Reported-by: syzbot+8c469a2260132cd095c1@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=8c469a2260132cd095c1
> Fixes: 311b36574ceac ("udp_tunnel: use static call for GRO hooks when possible")
> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
> ---
> v1 -> v2:
>  - do proper account for xfrm, retain the warning
> ---
>  net/ipv4/udp.c         | 5 +++++
>  net/ipv4/udp_offload.c | 4 +++-
>  2 files changed, 8 insertions(+), 1 deletion(-)
> 
> diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
> index db606f7e41638..79efbf465fb04 100644
> --- a/net/ipv4/udp.c
> +++ b/net/ipv4/udp.c
> @@ -2903,10 +2903,15 @@ static void set_xfrm_gro_udp_encap_rcv(__u16 encap_type, unsigned short family,
>  {
>  #ifdef CONFIG_XFRM
>  	if (udp_test_bit(GRO_ENABLED, sk) && encap_type == UDP_ENCAP_ESPINUDP) {
> +		bool old_enabled = !!udp_sk(sk)->gro_receive;
> +
>  		if (family == AF_INET)
>  			WRITE_ONCE(udp_sk(sk)->gro_receive, xfrm4_gro_udp_encap_rcv);
>  		else if (IS_ENABLED(CONFIG_IPV6) && family == AF_INET6)
>  			WRITE_ONCE(udp_sk(sk)->gro_receive, ipv6_stub->xfrm6_gro_udp_encap_rcv);
> +
> +		if (!old_enabled && udp_sk(sk)->gro_receive)
> +			udp_tunnel_update_gro_rcv(sk, true);

The second part of the condition is always true right?
diff mbox series

Patch

diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index db606f7e41638..79efbf465fb04 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -2903,10 +2903,15 @@  static void set_xfrm_gro_udp_encap_rcv(__u16 encap_type, unsigned short family,
 {
 #ifdef CONFIG_XFRM
 	if (udp_test_bit(GRO_ENABLED, sk) && encap_type == UDP_ENCAP_ESPINUDP) {
+		bool old_enabled = !!udp_sk(sk)->gro_receive;
+
 		if (family == AF_INET)
 			WRITE_ONCE(udp_sk(sk)->gro_receive, xfrm4_gro_udp_encap_rcv);
 		else if (IS_ENABLED(CONFIG_IPV6) && family == AF_INET6)
 			WRITE_ONCE(udp_sk(sk)->gro_receive, ipv6_stub->xfrm6_gro_udp_encap_rcv);
+
+		if (!old_enabled && udp_sk(sk)->gro_receive)
+			udp_tunnel_update_gro_rcv(sk, true);
 	}
 #endif
 }
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
index 088aa8cb8ac0c..02365b818f1af 100644
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -37,9 +37,11 @@  struct udp_tunnel_type_entry {
 	refcount_t count;
 };
 
+/* vxlan, fou and xfrm have 2 different gro_receive hooks each */
 #define UDP_MAX_TUNNEL_TYPES (IS_ENABLED(CONFIG_GENEVE) + \
 			      IS_ENABLED(CONFIG_VXLAN) * 2 + \
-			      IS_ENABLED(CONFIG_NET_FOU) * 2)
+			      IS_ENABLED(CONFIG_NET_FOU) * 2 + \
+			      IS_ENABLED(CONFIG_XFRM) * 2)
 
 DEFINE_STATIC_CALL(udp_tunnel_gro_rcv, dummy_gro_rcv);
 static DEFINE_STATIC_KEY_FALSE(udp_tunnel_static_call);