From patchwork Thu Jan 30 10:09:23 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nicolas Dichtel X-Patchwork-Id: 315293 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 3C44E2C009C for ; Thu, 30 Jan 2014 21:16:59 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752584AbaA3KP5 (ORCPT ); Thu, 30 Jan 2014 05:15:57 -0500 Received: from 33.106-14-84.ripe.coltfrance.com ([84.14.106.33]:40297 "EHLO proxy.6wind.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751180AbaA3KP4 (ORCPT ); Thu, 30 Jan 2014 05:15:56 -0500 X-Greylist: delayed 371 seconds by postgrey-1.27 at vger.kernel.org; Thu, 30 Jan 2014 05:15:56 EST Received: from schnaps.dev.6wind.com (unknown [10.16.0.249]) by proxy.6wind.com (Postfix) with ESMTPS id 70AEE282B8; Thu, 30 Jan 2014 11:09:43 +0100 (CET) Received: from root by schnaps.dev.6wind.com with local (Exim 4.80) (envelope-from ) id 1W8oZ4-0002pL-8Q; Thu, 30 Jan 2014 11:09:42 +0100 From: Nicolas Dichtel To: rostedt@goodmis.org Cc: linux-kernel@vger.kernel.org, netdev@vger.kernel.org, stable@vger.kernel.org, williams@redhat.com, lclaudio@uudg.org, jkacur@redhat.com, willemb@google.com, Nicolas Dichtel Subject: [PATCH linux-3.10.y 3/3] ip6tnl: fix double free of fb_tnl_dev on exit Date: Thu, 30 Jan 2014 11:09:23 +0100 Message-Id: <1391076563-10798-3-git-send-email-nicolas.dichtel@6wind.com> X-Mailer: git-send-email 1.8.4.1 In-Reply-To: <1391076563-10798-1-git-send-email-nicolas.dichtel@6wind.com> References: <52EA1B4B.5080403@6wind.com> <1391076563-10798-1-git-send-email-nicolas.dichtel@6wind.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This problem was fixed upstream by commit 1e9f3d6f1c40 ("ip6tnl: fix use after free of fb_tnl_dev"). The upstream patch depends on upstream commit 0bd8762824e7 ("ip6tnl: add x-netns support"), which was not backported into 3.10 branch. First, explain the problem: when the ip6_tunnel module is unloaded, ip6_tunnel_cleanup() is called. rmmod ip6_tunnel => ip6_tunnel_cleanup() => rtnl_link_unregister() => __rtnl_kill_links() => for_each_netdev(net, dev) { if (dev->rtnl_link_ops == ops) ops->dellink(dev, &list_kill); } At this point, the FB device is deleted (and all ip6tnl tunnels). => unregister_pernet_device() => unregister_pernet_operations() => ops_exit_list() => ip6_tnl_exit_net() => ip6_tnl_destroy_tunnels() => t = rtnl_dereference(ip6n->tnls_wc[0]); unregister_netdevice_queue(t->dev, &list); We delete the FB device a second time here! The previous fix removes these lines, which fix this double free. But the patch introduces a memory leak when a netns is destroyed, because the FB device is never deleted. By adding an rtnl ops which delete all ip6tnl device excepting the FB device, we can keep this exlicit removal in ip6_tnl_destroy_tunnels(). CC: Steven Rostedt CC: Willem de Bruijn Signed-off-by: Nicolas Dichtel --- net/ipv6/ip6_tunnel.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 0516ebbea80b..f21cf476b00c 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -1617,6 +1617,15 @@ static int ip6_tnl_changelink(struct net_device *dev, struct nlattr *tb[], return ip6_tnl_update(t, &p); } +static void ip6_tnl_dellink(struct net_device *dev, struct list_head *head) +{ + struct net *net = dev_net(dev); + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); + + if (dev != ip6n->fb_tnl_dev) + unregister_netdevice_queue(dev, head); +} + static size_t ip6_tnl_get_size(const struct net_device *dev) { return @@ -1681,6 +1690,7 @@ static struct rtnl_link_ops ip6_link_ops __read_mostly = { .validate = ip6_tnl_validate, .newlink = ip6_tnl_newlink, .changelink = ip6_tnl_changelink, + .dellink = ip6_tnl_dellink, .get_size = ip6_tnl_get_size, .fill_info = ip6_tnl_fill_info, };