summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorEric Dumazet2024-08-29 14:46:40 +0000
committerSasha Levin2026-03-04 07:20:07 -0500
commitde5703be2c61e6a90c5b91dfc852a5a09e1026c2 (patch)
tree7886f6957474c9f1fcd10bb0803b4c29c66a3f59 /net
parent721eb342d9ba19bad5c4815ea3921465158b7362 (diff)
icmp: move icmp_global.credit and icmp_global.stamp to per netns storage
[ Upstream commit b056b4cd9178f7a1d5d57f7b48b073c29729ddaa ] Host wide ICMP ratelimiter should be per netns, to provide better isolation. Following patch in this series makes the sysctl per netns. Signed-off-by: Eric Dumazet <edumazet@google.com> Reviewed-by: David Ahern <dsahern@kernel.org> Link: https://patch.msgid.link/20240829144641.3880376-3-edumazet@google.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> Stable-dep-of: 034bbd806298 ("icmp: prevent possible overflow in icmp_global_allow()") Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/icmp.c26
-rw-r--r--net/ipv6/icmp.c4
2 files changed, 13 insertions, 17 deletions
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 56b240e7f083..d1660c426a44 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -224,19 +224,15 @@ static inline void icmp_xmit_unlock(struct sock *sk)
int sysctl_icmp_msgs_per_sec __read_mostly = 1000;
int sysctl_icmp_msgs_burst __read_mostly = 50;
-static struct {
- atomic_t credit;
- u32 stamp;
-} icmp_global;
-
/**
* icmp_global_allow - Are we allowed to send one more ICMP message ?
+ * @net: network namespace
*
* Uses a token bucket to limit our ICMP messages to ~sysctl_icmp_msgs_per_sec.
* Returns false if we reached the limit and can not send another packet.
* Works in tandem with icmp_global_consume().
*/
-bool icmp_global_allow(void)
+bool icmp_global_allow(struct net *net)
{
u32 delta, now, oldstamp;
int incr, new, old;
@@ -245,11 +241,11 @@ bool icmp_global_allow(void)
* Then later icmp_global_consume() could consume more credits,
* this is an acceptable race.
*/
- if (atomic_read(&icmp_global.credit) > 0)
+ if (atomic_read(&net->ipv4.icmp_global_credit) > 0)
return true;
now = jiffies;
- oldstamp = READ_ONCE(icmp_global.stamp);
+ oldstamp = READ_ONCE(net->ipv4.icmp_global_stamp);
delta = min_t(u32, now - oldstamp, HZ);
if (delta < HZ / 50)
return false;
@@ -258,23 +254,23 @@ bool icmp_global_allow(void)
if (!incr)
return false;
- if (cmpxchg(&icmp_global.stamp, oldstamp, now) == oldstamp) {
- old = atomic_read(&icmp_global.credit);
+ if (cmpxchg(&net->ipv4.icmp_global_stamp, oldstamp, now) == oldstamp) {
+ old = atomic_read(&net->ipv4.icmp_global_credit);
do {
new = min(old + incr, READ_ONCE(sysctl_icmp_msgs_burst));
- } while (!atomic_try_cmpxchg(&icmp_global.credit, &old, new));
+ } while (!atomic_try_cmpxchg(&net->ipv4.icmp_global_credit, &old, new));
}
return true;
}
EXPORT_SYMBOL(icmp_global_allow);
-void icmp_global_consume(void)
+void icmp_global_consume(struct net *net)
{
int credits = get_random_u32_below(3);
/* Note: this might make icmp_global.credit negative. */
if (credits)
- atomic_sub(credits, &icmp_global.credit);
+ atomic_sub(credits, &net->ipv4.icmp_global_credit);
}
EXPORT_SYMBOL(icmp_global_consume);
@@ -300,7 +296,7 @@ static bool icmpv4_global_allow(struct net *net, int type, int code,
if (icmpv4_mask_allow(net, type, code))
return true;
- if (icmp_global_allow()) {
+ if (icmp_global_allow(net)) {
*apply_ratelimit = true;
return true;
}
@@ -337,7 +333,7 @@ out:
if (!rc)
__ICMP_INC_STATS(net, ICMP_MIB_RATELIMITHOST);
else
- icmp_global_consume();
+ icmp_global_consume(net);
return rc;
}
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 7ba3c642ab3c..ea1cdacbdcf1 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -181,7 +181,7 @@ static bool icmpv6_global_allow(struct net *net, int type,
if (icmpv6_mask_allow(net, type))
return true;
- if (icmp_global_allow()) {
+ if (icmp_global_allow(net)) {
*apply_ratelimit = true;
return true;
}
@@ -231,7 +231,7 @@ static bool icmpv6_xrlim_allow(struct sock *sk, u8 type,
__ICMP6_INC_STATS(net, ip6_dst_idev(dst),
ICMP6_MIB_RATELIMITHOST);
else
- icmp_global_consume();
+ icmp_global_consume(net);
dst_release(dst);
return res;
}