lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-Id: <20250423181245.14794-1-pimenoveu12@gmail.com>
Date: Wed, 23 Apr 2025 21:12:46 +0300
From: Evgeny Pimenov <pimenoveu12@...il.com>
To: Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
	stable@...r.kernel.org,
	Pablo Neira Ayuso <pablo@...filter.org>
Cc: Evgeny Pimenov <pimenoveu12@...il.com>,
	Jozsef Kadlecsik <kadlec@...filter.org>,
	Florian Westphal <fw@...len.de>,
	"David S. Miller" <davem@...emloft.net>,
	Hideaki YOSHIFUJI <yoshfuji@...ux-ipv6.org>,
	David Ahern <dsahern@...nel.org>,
	Eric Dumazet <edumazet@...gle.com>,
	Jakub Kicinski <kuba@...nel.org>,
	Paolo Abeni <pabeni@...hat.com>,
	Taehee Yoo <ap420073@...il.com>,
	netfilter-devel@...r.kernel.org,
	coreteam@...filter.org,
	netdev@...r.kernel.org,
	linux-kernel@...r.kernel.org,
	Fedor Pchelkin <pchelkin@...ras.ru>,
	Alexey Khoroshilov <khoroshilov@...ras.ru>
Subject: [PATCH 5.10/5.15/6.1] netfilter: ipt_CLUSTERIP: change mutex location

No upstream commit exists for this patch.

The file ipt_CLUSTERIP.c was deleted in commit 9db5d918e2c0
("netfilter: ip_tables: remove clusterip target"), but races still exist
in stable branches.

Thread A in clusterip_config_entry_put() decrements refcount and removes
config from the list but doesn't call proc_remove(). Thread B searches
the config, doesn't find it, re-adds it to the list, and calls
proc_create_data() with an IP that still exists in the tree.

|A| refcount_dec_and_lock()
|A| list_del_rcu()
=== Must be here
|A| proc_remove()
===
|B| __clusterip_config_find()
|B| list_add_rcu()
|B| proc_create_data()
|B| WARN()

As a fix, also cover with mutex the places of interaction with the list of
configs before proc_remove() and proc_create_data() functions.

------------[ cut here ]------------
proc_dir_entry 'ipt_CLUSTERIP/100.1.1.2' already registered
WARNING: CPU: 0 PID: 2597 at fs/proc/generic.c:381 proc_register+0x517/0x6e0 fs/proc/generic.c:381
[...]
Call Trace:
 proc_create_data+0x130/0x1a0 fs/proc/generic.c:583
 clusterip_config_init net/ipv4/netfilter/ipt_CLUSTERIP.c:281 [inline]
 clusterip_tg_check+0xb8d/0x1380 net/ipv4/netfilter/ipt_CLUSTERIP.c:502
 xt_check_target+0x27c/0xa00 net/netfilter/x_tables.c:1018
 check_target net/ipv4/netfilter/ip_tables.c:511 [inline]
 find_check_entry.constprop.0+0x7b0/0x9b0 net/ipv4/netfilter/ip_tables.c:553
 translate_table+0xc6a/0x16a0 net/ipv4/netfilter/ip_tables.c:717
 do_replace net/ipv4/netfilter/ip_tables.c:1138 [inline]
 do_ipt_set_ctl+0x54e/0xb00 net/ipv4/netfilter/ip_tables.c:1636
 nf_setsockopt+0x88/0xf0 net/netfilter/nf_sockopt.c:101
 ip_setsockopt+0xe4d/0x3d10 net/ipv4/ip_sockglue.c:1442
 sctp_setsockopt+0x135/0xa390 net/sctp/socket.c:4475
 __sys_setsockopt+0x234/0x5a0 net/socket.c:2145
 __do_sys_setsockopt net/socket.c:2156 [inline]
 __se_sys_setsockopt net/socket.c:2153 [inline]
 __x64_sys_setsockopt+0xb9/0x150 net/socket.c:2153
 do_syscall_64+0x30/0x40 arch/x86/entry/common.c:46
 entry_SYSCALL_64_after_hwframe+0x67/0xd1

Found by Linux Verification Center (linuxtesting.org) with Syzkaller.

Fixes: 2a61d8b883bb ("netfilter: ipt_CLUSTERIP: fix sleep-in-atomic bug in clusterip_config_entry_put()")
Cc: stable@...r.kernel.org # v5.4+
Suggested-by: Fedor Pchelkin <pchelkin@...ras.ru>
Suggested-by: Alexey Khoroshilov <khoroshilov@...ras.ru>
Signed-off-by: Evgeny Pimenov <pimenoveu12@...il.com>
---
 net/ipv4/netfilter/ipt_CLUSTERIP.c | 30 ++++++++++++++++++++++++------
 1 file changed, 24 insertions(+), 6 deletions(-)

diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index 77e3b67e8790..61ccfd97841f 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -79,6 +79,22 @@ static inline struct clusterip_net *clusterip_pernet(struct net *net)
 	return net_generic(net, clusterip_net_id);
 }
 
+static inline void
+clusterip_net_lock(struct clusterip_net *cn)
+{
+#ifdef CONFIG_PROC_FS
+	mutex_lock(&cn->mutex);
+#endif
+};
+
+static inline void
+clusterip_net_unlock(struct clusterip_net *cn)
+{
+#ifdef CONFIG_PROC_FS
+	mutex_unlock(&cn->mutex);
+#endif
+};
+
 static inline void
 clusterip_config_get(struct clusterip_config *c)
 {
@@ -114,6 +130,7 @@ clusterip_config_entry_put(struct clusterip_config *c)
 {
 	struct clusterip_net *cn = clusterip_pernet(c->net);
 
+	clusterip_net_lock(cn);
 	local_bh_disable();
 	if (refcount_dec_and_lock(&c->entries, &cn->lock)) {
 		list_del_rcu(&c->list);
@@ -123,14 +140,14 @@ clusterip_config_entry_put(struct clusterip_config *c)
 		 * functions are also incrementing the refcount on their own,
 		 * so it's safe to remove the entry even if it's in use. */
 #ifdef CONFIG_PROC_FS
-		mutex_lock(&cn->mutex);
 		if (cn->procdir)
 			proc_remove(c->pde);
-		mutex_unlock(&cn->mutex);
 #endif
+		clusterip_net_unlock(cn);
 		return;
 	}
 	local_bh_enable();
+	clusterip_net_unlock(cn);
 }
 
 static struct clusterip_config *
@@ -262,6 +279,7 @@ clusterip_config_init(struct net *net, const struct ipt_clusterip_tgt_info *i,
 	c->net = net;
 	refcount_set(&c->refcount, 1);
 
+	clusterip_net_lock(cn);
 	spin_lock_bh(&cn->lock);
 	if (__clusterip_config_find(net, ip)) {
 		err = -EBUSY;
@@ -277,11 +295,9 @@ clusterip_config_init(struct net *net, const struct ipt_clusterip_tgt_info *i,
 
 		/* create proc dir entry */
 		sprintf(buffer, "%pI4", &ip);
-		mutex_lock(&cn->mutex);
 		c->pde = proc_create_data(buffer, 0600,
 					  cn->procdir,
 					  &clusterip_proc_ops, c);
-		mutex_unlock(&cn->mutex);
 		if (!c->pde) {
 			err = -ENOMEM;
 			goto err;
@@ -290,6 +306,7 @@ clusterip_config_init(struct net *net, const struct ipt_clusterip_tgt_info *i,
 #endif
 
 	refcount_set(&c->entries, 1);
+	clusterip_net_unlock(cn);
 	return c;
 
 #ifdef CONFIG_PROC_FS
@@ -300,6 +317,7 @@ clusterip_config_init(struct net *net, const struct ipt_clusterip_tgt_info *i,
 out_config_put:
 	spin_unlock_bh(&cn->lock);
 	clusterip_config_put(c);
+	clusterip_net_unlock(cn);
 	return ERR_PTR(err);
 }
 
@@ -848,10 +866,10 @@ static void clusterip_net_exit(struct net *net)
 #ifdef CONFIG_PROC_FS
 	struct clusterip_net *cn = clusterip_pernet(net);
 
-	mutex_lock(&cn->mutex);
+	clusterip_net_lock(cn);
 	proc_remove(cn->procdir);
 	cn->procdir = NULL;
-	mutex_unlock(&cn->mutex);
+	clusterip_net_unlock(cn);
 #endif
 	nf_unregister_net_hook(net, &cip_arp_ops);
 }
-- 
2.39.5

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ