From patchwork Tue Dec 11 19:32:21 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Vitaly E. Lavrov" X-Patchwork-Id: 205296 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id A06772C007C for ; Wed, 12 Dec 2012 06:32:26 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753317Ab2LKTcY (ORCPT ); Tue, 11 Dec 2012 14:32:24 -0500 Received: from mail.guap.ru ([91.151.188.3]:14143 "EHLO mail.guap.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753185Ab2LKTcX (ORCPT ); Tue, 11 Dec 2012 14:32:23 -0500 Received: from [10.150.100.7] (95-161-253-150.broadband.spb.TiERA.org [95.161.253.150]) (user=lve@guap.ru mech=CRAM-MD5 bits=0) by mail.guap.ru (8.14.4/8.14.4) with ESMTP id qBBJWLuH024075 for ; Tue, 11 Dec 2012 23:32:21 +0400 X-DKIM: OpenDKIM Filter v2.4.1 mail.guap.ru qBBJWLuH024075 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=guap.ru; s=default; t=1355254341; bh=s6btMHlT4C+UrkJrKy3mO6NvhYI+RCOAxEyCy4PU7d4=; h=Message-ID:Date:From:MIME-Version:To:Subject:Content-Type; z=Message-ID:=20<50C78A45.4040901@guap.ru>|Date:=20Tue,=2011=20Dec= 202012=2023:32:21=20+0400|From:=20"Vitaly=20E.=20Lavrov"=20|MIME-Version:=201.0|To:=20netfilter-devel@vger.kernel.org|S ubject:=20[PATCH]=20xt_hashlimit=20fix=20BUG()|Content-Type:=20mul tipart/mixed=3B=0D=0A=20boundary=3D"------------060202020706090806 030003"; b=AJSKW7EvR3td9zNQvAYeUm9/2xpr6JPkh1MeHH7Ndqle1qfa09NRNWOGYO43m625O fLG93OPXCM79wzREsiCrJVB+8dVJRDwTxBpR/lHqCR/gQs/hFTLTi26BWo201CMKcp YbPAr19y/EvvsVAWWbXMoKM68YZCFVhZrjR3cW5o= DomainKey-Signature: a=rsa-sha1; s=default; d=guap.ru; c=nofws; q=dns; b=klC2mKz7YuAHF0ge6mEI3BMIPDDKyumAybaa69gft7UhIwSQCA7zloXlPpx/eMKv7 /aUzhruFzRNgnw/x+oYc8mAMpBQCYoieSI4uHHgpVNTQeXDx10uMDAMbsJrm1n57Ood td0MkaXF32iU4kcaDZLEki2f+LOoA4yMamU42hw= Message-ID: <50C78A45.4040901@guap.ru> Date: Tue, 11 Dec 2012 23:32:21 +0400 From: "Vitaly E. Lavrov" User-Agent: Mozilla/5.0 (X11; Linux i686; rv:15.0) Gecko/20120824 Thunderbird/15.0 MIME-Version: 1.0 To: netfilter-devel@vger.kernel.org Subject: [PATCH] xt_hashlimit fix BUG() Received-SPF: pass X-Relay-level: 30 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org The following patch fixes a bug in xt_hashlimit. Bug appears at the end of work the networks namespace, provided that the tables (filter/mangle/raw) have rule with xt_hashlimit. The error occurs because the __net_exit hashlimit_net_exit() is executed before the tables are cleared. Change this order of calls is impossible, since tables must be registered earlier than extensions. Bug exists in all versions of the kernel since 2.6.35 Cleaning tables before completing the network namespace can be used as a workaround. Idea of the patch that if the files are deleted from the directory /proc/net/ip[6]t_hashlimit/" procedure XXXXX, then a flag is set "clean". If cleaning the tables occurs later and the flag "clean" is set, then the delete files is skipped. Patch for kernel 3.4.22 Signed-off-by: Vitaly Lavrov lve@guap.ru --- } @@ -784,6 +786,7 @@ static int __net_init hashlimit_net_init(struct net *net) { struct hashlimit_net *hashlimit_net = hashlimit_pernet(net); + hashlimit_net->clean = 0; INIT_HLIST_HEAD(&hashlimit_net->htables); return hashlimit_proc_net_init(net); } @@ -791,8 +794,19 @@ static int __net_init hashlimit_net_init(struct net *net) static void __net_exit hashlimit_net_exit(struct net *net) { struct hashlimit_net *hashlimit_net = hashlimit_pernet(net); + struct xt_hashlimit_htable *hinfo; + struct hlist_node *pos; + struct proc_dir_entry *pde; + + mutex_lock(&hashlimit_mutex); + hashlimit_net->clean = 1; + pde = hashlimit_net->ipt_hashlimit; + if(!pde) pde = hashlimit_net->ip6t_hashlimit; + hlist_for_each_entry(hinfo, pos, &hashlimit_net->htables, node) { + remove_proc_entry(hinfo->pde->name,pde); + } + mutex_unlock(&hashlimit_mutex); - BUG_ON(!hlist_empty(&hashlimit_net->htables)); hashlimit_proc_net_exit(net); } -- diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index 2195eb0..5416185 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -46,6 +46,7 @@ struct hashlimit_net { struct hlist_head htables; struct proc_dir_entry *ipt_hashlimit; struct proc_dir_entry *ip6t_hashlimit; + int clean; }; static int hashlimit_net_id; @@ -319,7 +320,8 @@ static void htable_destroy(struct xt_hashlimit_htable *hinfo) parent = hashlimit_net->ipt_hashlimit; else parent = hashlimit_net->ip6t_hashlimit; - remove_proc_entry(hinfo->pde->name, parent); + if(!hashlimit_net->clean) + remove_proc_entry(hinfo->pde->name, parent); htable_selective_cleanup(hinfo, select_all); vfree(hinfo); } @@ -784,6 +786,7 @@ static int __net_init hashlimit_net_init(struct net *net) { struct hashlimit_net *hashlimit_net = hashlimit_pernet(net); + hashlimit_net->clean = 0; INIT_HLIST_HEAD(&hashlimit_net->htables); return hashlimit_proc_net_init(net); } @@ -791,8 +794,19 @@ static int __net_init hashlimit_net_init(struct net *net) static void __net_exit hashlimit_net_exit(struct net *net) { struct hashlimit_net *hashlimit_net = hashlimit_pernet(net); + struct xt_hashlimit_htable *hinfo; + struct hlist_node *pos; + struct proc_dir_entry *pde; + + mutex_lock(&hashlimit_mutex); + hashlimit_net->clean = 1; + pde = hashlimit_net->ipt_hashlimit; + if(!pde) pde = hashlimit_net->ip6t_hashlimit; + hlist_for_each_entry(hinfo, pos, &hashlimit_net->htables, node) { + remove_proc_entry(hinfo->pde->name,pde); + } + mutex_unlock(&hashlimit_mutex); - BUG_ON(!hlist_empty(&hashlimit_net->htables)); hashlimit_proc_net_exit(net); } diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index 2195eb0..5416185 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -46,6 +46,7 @@ struct hashlimit_net { struct hlist_head htables; struct proc_dir_entry *ipt_hashlimit; struct proc_dir_entry *ip6t_hashlimit; + int clean; }; static int hashlimit_net_id; @@ -319,7 +320,8 @@ static void htable_destroy(struct xt_hashlimit_htable *hinfo) parent = hashlimit_net->ipt_hashlimit; else parent = hashlimit_net->ip6t_hashlimit; - remove_proc_entry(hinfo->pde->name, parent); + if(!hashlimit_net->clean) + remove_proc_entry(hinfo->pde->name, parent); htable_selective_cleanup(hinfo, select_all); vfree(hinfo);