Subject: Re: [PATCH net v2] vxlan: fix NULL dereference in vxlan_igmp_join() and vxlan_igmp_leave()

From: Ido Schimmel <[email-masked]>
Date: Tue, 24 Mar 2026 15:34:49 +0200

On Mon, Mar 23, 2026 at 05:55:47PM +0800, Weiming Shi wrote:
> vxlan_sock_add() tolerates IPv6 socket creation failure with
> -EAFNOSUPPORT and brings the VXLAN device up with only an IPv4
> socket, leaving vn6_sock as NULL.
> 
> However, vxlan_igmp_join() and vxlan_igmp_leave() unconditionally
> dereference vn6_sock when handling multicast group operations for
> IPv6. When a VNI filter entry with an IPv6 multicast group is
> added via RTM_NEWTUNNEL on a collect-metadata VXLAN device where
> the IPv6 socket was not created, the NULL vn6_sock pointer is
> dereferenced, causing a kernel crash.
> 
> This can be triggered by booting with ipv6.disable=1, creating a
> collect-metadata VXLAN device with vnifilter, and adding a VNI
> filter entry with an IPv6 multicast group.
> 
>  BUG: kernel NULL pointer dereference, address: 0000000000000010
>  Oops: Oops: 0000 [#1] SMP NOPTI
>  RIP: 0010:vxlan_igmp_join (drivers/net/vxlan/vxlan_multicast.c:40)
>  Call Trace:
>   <TASK>
>   vxlan_vni_update_group (drivers/net/vxlan/vxlan_vnifilter.c:573)
>   vxlan_vnifilter_process (drivers/net/vxlan/vxlan_vnifilter.c:976)
>   rtnetlink_rcv_msg (net/core/rtnetlink.c:6986)
>   netlink_rcv_skb (net/netlink/af_netlink.c:2550)
>   rtnetlink_rcv (net/core/rtnetlink.c:7005)
>   netlink_unicast (net/netlink/af_netlink.c:1344)
>   netlink_sendmsg (net/netlink/af_netlink.c:1894)
>   ____sys_sendmsg (net/socket.c:2592)
>   ___sys_sendmsg (net/socket.c:2648)
>   __sys_sendmsg (net/socket.c:2678)
>   do_syscall_64 (arch/x86/entry/syscall_64.c:94)
>   entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130)
>   </TASK>
> 
> Fix this by adding NULL checks for vn6_sock in both
> vxlan_igmp_join() and vxlan_igmp_leave() before dereferencing.
> Return 0 rather than an error code because all callers treat
> non-zero returns as fatal -- vxlan_vni_update_group() would
> abort a VNI add that already inserted into the hash table,
> and vxlan_multicast_join_vnigrp() would fail vxlan_open().
> Since vxlan_sock_add() already accepts -EAFNOSUPPORT as a
> non-error condition, the multicast helpers should do the same
> by simply skipping the join/leave when the socket is absent.

I don't think this is the right fix. An error should be returned if the
user disabled IPv6 and is now trying to join an IPv6 multicast group.

The situation in vxlan_igmp_{join,leave}() is not the same as in
vxlan_sock_add(). EAFNOSUPPORT errors are suppressed in vxlan_sock_add()
since in collect metadata (external) mode the driver tries to open
sockets for both address families and if IPv6 is disabled the device
should still be able to work with IPv4.

Regarding "vxlan_vni_update_group() would abort a VNI add that already
inserted into the hash table", the fact that there is no rollback in
vxlan_vni_add() upon vxlan_vni_update_group() returning an error seems
like an omission that should also be fixed.

> 
> Fixes: f9c4bb0b245c ("vxlan: vni filtering support on collect metadata device")
> Reported-by: Xiang Mei <[email-masked]>
> Signed-off-by: Weiming Shi <[email-masked]>
> ---
> v2:
>  - Drop unnecessary sock4 NULL checksjjj
> ---
>  drivers/net/vxlan/vxlan_multicast.c | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/drivers/net/vxlan/vxlan_multicast.c b/drivers/net/vxlan/vxlan_multicast.c
> index a7f2d67dc61b8..a442c9e6d1a72 100644
> --- a/drivers/net/vxlan/vxlan_multicast.c
> +++ b/drivers/net/vxlan/vxlan_multicast.c
> @@ -37,6 +37,8 @@ int vxlan_igmp_join(struct vxlan_dev *vxlan, union vxlan_addr *rip,
>  	} else {
>  		struct vxlan_sock *sock6 = rtnl_dereference(vxlan->vn6_sock);
> 
> +		if (!sock6)
> +			return 0;
>  		sk = sock6->sock->sk;
>  		lock_sock(sk);
>  		ret = ipv6_stub->ipv6_sock_mc_join(sk, ifindex,
> @@ -71,6 +73,8 @@ int vxlan_igmp_leave(struct vxlan_dev *vxlan, union vxlan_addr *rip,
>  	} else {
>  		struct vxlan_sock *sock6 = rtnl_dereference(vxlan->vn6_sock);
> 
> +		if (!sock6)
> +			return 0;
>  		sk = sock6->sock->sk;
>  		lock_sock(sk);
>  		ret = ipv6_stub->ipv6_sock_mc_drop(sk, ifindex,
> --
> 2.43.0