From mboxrd@z Thu Jan 1 00:00:00 1970 From: David Miller Subject: Re: [PATCH net] ipv6: Fix SO_REUSEPORT UDP socket with implicit sk_ipv6only Date: Mon, 29 Jan 2018 11:38:44 -0500 (EST) Message-ID: <20180129.113844.760548840166915366.davem@davemloft.net> References: <20180125071527.1185439-1-kafai@fb.com> Mime-Version: 1.0 Content-Type: Text/Plain; charset=us-ascii Content-Transfer-Encoding: 7bit Cc: netdev@vger.kernel.org, kraig@google.com, kernel-team@fb.com To: kafai@fb.com Return-path: Received: from shards.monkeyblade.net ([184.105.139.130]:44990 "EHLO shards.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751204AbeA2Qip (ORCPT ); Mon, 29 Jan 2018 11:38:45 -0500 In-Reply-To: <20180125071527.1185439-1-kafai@fb.com> Sender: netdev-owner@vger.kernel.org List-ID: From: Martin KaFai Lau Date: Wed, 24 Jan 2018 23:15:27 -0800 > If a sk_v6_rcv_saddr is !IPV6_ADDR_ANY and !IPV6_ADDR_MAPPED, it > implicitly implies it is an ipv6only socket. However, in inet6_bind(), > this addr_type checking and setting sk->sk_ipv6only to 1 are only done > after sk->sk_prot->get_port(sk, snum) has been completed successfully. > > This inconsistency between sk_v6_rcv_saddr and sk_ipv6only confuses > the 'get_port()'. > > In particular, when binding SO_REUSEPORT UDP sockets, > udp_reuseport_add_sock(sk,...) is called. udp_reuseport_add_sock() > checks "ipv6_only_sock(sk2) == ipv6_only_sock(sk)" before adding sk to > sk2->sk_reuseport_cb. In this case, ipv6_only_sock(sk2) could be > 1 while ipv6_only_sock(sk) is still 0 here. The end result is, > reuseport_alloc(sk) is called instead of adding sk to the existing > sk2->sk_reuseport_cb. > > It can be reproduced by binding two SO_REUSEPORT UDP sockets on an > IPv6 address (!ANY and !MAPPED). Only one of the socket will > receive packet. > > The fix is to set the implicit sk_ipv6only before calling get_port(). > The original sk_ipv6only has to be saved such that it can be restored > in case get_port() failed. The situation is similar to the > inet_reset_saddr(sk) after get_port() has failed. > > Thanks to Calvin Owens who created an easy > reproduction which leads to a fix. > > Fixes: e32ea7e74727 ("soreuseport: fast reuseport UDP socket selection") > Signed-off-by: Martin KaFai Lau Applied and queued up for -stable, thanks Martin.