From patchwork Thu Oct 21 10:12:10 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Timo Teras X-Patchwork-Id: 68564 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3A40DB70FB for ; Thu, 21 Oct 2010 21:13:15 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756210Ab0JUKMU (ORCPT ); Thu, 21 Oct 2010 06:12:20 -0400 Received: from mail-ey0-f174.google.com ([209.85.215.174]:60064 "EHLO mail-ey0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756014Ab0JUKMP (ORCPT ); Thu, 21 Oct 2010 06:12:15 -0400 Received: by eyx24 with SMTP id 24so1876953eyx.19 for ; Thu, 21 Oct 2010 03:12:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:sender:from:to:cc:subject :date:message-id:x-mailer:mime-version:content-type :content-transfer-encoding; bh=bs4NCJALtVOmI2UJjVrD7ZgoJvG+AHJksfvbHhUZidg=; b=csPUK3odhb4UARjZNYzoWlzqgFjvoXjGnll1cvS/PQUMnt6YmDxSfz5w9le2Dg1R95 wk2A52lBdSdnW1/I8xWLQHXGseocwTD1YjgnML6ILFgGorc9JHfAqwOb9Ztd2LU1/fpQ JTzjZVPd1XkFdr8IEnkVARXgHVFI8XJlIxZLA= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=sender:from:to:cc:subject:date:message-id:x-mailer:mime-version :content-type:content-transfer-encoding; b=tRZRijH5h5LT6WsQs5nBlAizMhr/MvO60GzIpmFkochqMBX/1/3nqqqg4OVAn/1Vct ZFiwSibdJaeQLZaYsTFf14TfCNFcDCjLS9DGOazmBIhNU6/yaKi75P4sqxW2bVojAScA PwOkVffZpuP3d60vyhiQGRM1cKgPZSBPXgJMQ= Received: by 10.14.37.10 with SMTP id x10mr414054eea.31.1287655934187; Thu, 21 Oct 2010 03:12:14 -0700 (PDT) Received: from vostro.ism.fin.wtbts.net (mail.fi.jw.org [83.145.235.193]) by mx.google.com with ESMTPS id v56sm1578739eeh.2.2010.10.21.03.12.13 (version=SSLv3 cipher=RC4-MD5); Thu, 21 Oct 2010 03:12:13 -0700 (PDT) From: =?UTF-8?q?Timo=20Ter=C3=A4s?= To: netdev@vger.kernel.org Cc: =?UTF-8?q?Timo=20Ter=C3=A4s?= Subject: [PATCH] ipv4: synchronize bind() with RTM_NEWADDR notifications Date: Thu, 21 Oct 2010 13:12:10 +0300 Message-Id: <1287655930-16879-1-git-send-email-timo.teras@iki.fi> X-Mailer: git-send-email 1.7.1 MIME-Version: 1.0 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Otherwise we have race condition to user land: 1. process A changes IP address 2. kernel sends RTM_NEWADDR 3. process B gets notification 4. process B tries to bind() to new IP but that fails with EADDRNOTAVAIL because FIB is not yet updated and inet_addr_type() in inet_bind() does not recognize the IP as local 5. kernel calls inetaddr_chain notifiers which updates FIB IPv6 side seems to handle the notifications properly: bind() immediately after RTM_NEWADDR succeeds as expected. This is because ipv6_chk_addr() uses inet6_addr_lst which is updated before address notification. Signed-off-by: Timo Teräs --- net/ipv4/af_inet.c | 9 +++++++++ net/ipv6/af_inet6.c | 4 +++- 2 files changed, 12 insertions(+), 1 deletions(-) diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 6a1100c..21200e4 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -466,6 +466,15 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) if (addr_len < sizeof(struct sockaddr_in)) goto out; + /* Acquire rtnl_lock to synchronize with possible simultaneous + * IP-address changes. This is needed because when RTM_NEWADDR + * is sent the new IP is not yet in FIB, but alas inet_addr_type + * checks the address type using FIB. Acquiring rtnl lock once + * makse sure that any address for which RTM_NEWADDR was sent + * earlier exists also in FIB. */ + rtnl_lock(); + rtnl_unlock(); + chk_addr_ret = inet_addr_type(sock_net(sk), addr->sin_addr.s_addr); /* Not specified by any standard per-se, however it breaks too diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 56b9bf2..6fc37f4 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -300,7 +300,9 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) goto out; } - /* Reproduce AF_INET checks to make the bindings consitant */ + /* Reproduce AF_INET checks to make the bindings consistent */ + rtnl_lock(); + rtnl_unlock(); v4addr = addr->sin6_addr.s6_addr32[3]; chk_addr_ret = inet_addr_type(net, v4addr); if (!sysctl_ip_nonlocal_bind &&