Skip to content
/ linux Public

Commit e0987b6

Browse files
edumazetSasha Levin
authored andcommitted
icmp: move icmp_global.credit and icmp_global.stamp to per netns storage
[ Upstream commit b056b4c ] 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: 034bbd8 ("icmp: prevent possible overflow in icmp_global_allow()") Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 19c7d8a commit e0987b6

File tree

4 files changed

+17
-20
lines changed

4 files changed

+17
-20
lines changed

include/net/ip.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -790,8 +790,8 @@ static inline void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
790790
ip_cmsg_recv_offset(msg, skb->sk, skb, 0, 0);
791791
}
792792

793-
bool icmp_global_allow(void);
794-
void icmp_global_consume(void);
793+
bool icmp_global_allow(struct net *net);
794+
void icmp_global_consume(struct net *net);
795795

796796
extern int sysctl_icmp_msgs_per_sec;
797797
extern int sysctl_icmp_msgs_burst;

include/net/netns/ipv4.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ struct netns_ipv4 {
8484
u8 sysctl_icmp_errors_use_inbound_ifaddr;
8585
int sysctl_icmp_ratelimit;
8686
int sysctl_icmp_ratemask;
87-
87+
atomic_t icmp_global_credit;
88+
u32 icmp_global_stamp;
8889
u32 ip_rt_min_pmtu;
8990
int ip_rt_mtu_expires;
9091
int ip_rt_min_advmss;

net/ipv4/icmp.c

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -224,19 +224,15 @@ static inline void icmp_xmit_unlock(struct sock *sk)
224224
int sysctl_icmp_msgs_per_sec __read_mostly = 1000;
225225
int sysctl_icmp_msgs_burst __read_mostly = 50;
226226

227-
static struct {
228-
atomic_t credit;
229-
u32 stamp;
230-
} icmp_global;
231-
232227
/**
233228
* icmp_global_allow - Are we allowed to send one more ICMP message ?
229+
* @net: network namespace
234230
*
235231
* Uses a token bucket to limit our ICMP messages to ~sysctl_icmp_msgs_per_sec.
236232
* Returns false if we reached the limit and can not send another packet.
237233
* Works in tandem with icmp_global_consume().
238234
*/
239-
bool icmp_global_allow(void)
235+
bool icmp_global_allow(struct net *net)
240236
{
241237
u32 delta, now, oldstamp;
242238
int incr, new, old;
@@ -245,11 +241,11 @@ bool icmp_global_allow(void)
245241
* Then later icmp_global_consume() could consume more credits,
246242
* this is an acceptable race.
247243
*/
248-
if (atomic_read(&icmp_global.credit) > 0)
244+
if (atomic_read(&net->ipv4.icmp_global_credit) > 0)
249245
return true;
250246

251247
now = jiffies;
252-
oldstamp = READ_ONCE(icmp_global.stamp);
248+
oldstamp = READ_ONCE(net->ipv4.icmp_global_stamp);
253249
delta = min_t(u32, now - oldstamp, HZ);
254250
if (delta < HZ / 50)
255251
return false;
@@ -258,23 +254,23 @@ bool icmp_global_allow(void)
258254
if (!incr)
259255
return false;
260256

261-
if (cmpxchg(&icmp_global.stamp, oldstamp, now) == oldstamp) {
262-
old = atomic_read(&icmp_global.credit);
257+
if (cmpxchg(&net->ipv4.icmp_global_stamp, oldstamp, now) == oldstamp) {
258+
old = atomic_read(&net->ipv4.icmp_global_credit);
263259
do {
264260
new = min(old + incr, READ_ONCE(sysctl_icmp_msgs_burst));
265-
} while (!atomic_try_cmpxchg(&icmp_global.credit, &old, new));
261+
} while (!atomic_try_cmpxchg(&net->ipv4.icmp_global_credit, &old, new));
266262
}
267263
return true;
268264
}
269265
EXPORT_SYMBOL(icmp_global_allow);
270266

271-
void icmp_global_consume(void)
267+
void icmp_global_consume(struct net *net)
272268
{
273269
int credits = get_random_u32_below(3);
274270

275271
/* Note: this might make icmp_global.credit negative. */
276272
if (credits)
277-
atomic_sub(credits, &icmp_global.credit);
273+
atomic_sub(credits, &net->ipv4.icmp_global_credit);
278274
}
279275
EXPORT_SYMBOL(icmp_global_consume);
280276

@@ -300,7 +296,7 @@ static bool icmpv4_global_allow(struct net *net, int type, int code,
300296
if (icmpv4_mask_allow(net, type, code))
301297
return true;
302298

303-
if (icmp_global_allow()) {
299+
if (icmp_global_allow(net)) {
304300
*apply_ratelimit = true;
305301
return true;
306302
}
@@ -337,7 +333,7 @@ static bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt,
337333
if (!rc)
338334
__ICMP_INC_STATS(net, ICMP_MIB_RATELIMITHOST);
339335
else
340-
icmp_global_consume();
336+
icmp_global_consume(net);
341337
return rc;
342338
}
343339

net/ipv6/icmp.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ static bool icmpv6_global_allow(struct net *net, int type,
181181
if (icmpv6_mask_allow(net, type))
182182
return true;
183183

184-
if (icmp_global_allow()) {
184+
if (icmp_global_allow(net)) {
185185
*apply_ratelimit = true;
186186
return true;
187187
}
@@ -231,7 +231,7 @@ static bool icmpv6_xrlim_allow(struct sock *sk, u8 type,
231231
__ICMP6_INC_STATS(net, ip6_dst_idev(dst),
232232
ICMP6_MIB_RATELIMITHOST);
233233
else
234-
icmp_global_consume();
234+
icmp_global_consume(net);
235235
dst_release(dst);
236236
return res;
237237
}

0 commit comments

Comments
 (0)