[<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