Skip to content

Commit 4b8474a

Browse files
edumazetkuba-moo
authored andcommitted
ipv4: icmp: convert to dev_net_rcu()
__icmp_send() must ensure rcu_read_lock() is held, as spotted by Jakub. Other ICMP uses of dev_net() seem safe, change them to dev_net_rcu() to get LOCKDEP support. Fixes: dde1bc0 ("[NETNS]: Add namespace for ICMP replying code.") Closes: https://lore.kernel.org/netdev/[email protected]/ Reported-by: Jakub Kicinski <[email protected]> Signed-off-by: Eric Dumazet <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 1395121 commit 4b8474a

File tree

1 file changed

+17
-14
lines changed

1 file changed

+17
-14
lines changed

net/ipv4/icmp.c

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -399,10 +399,10 @@ static void icmp_push_reply(struct sock *sk,
399399

400400
static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
401401
{
402-
struct ipcm_cookie ipc;
403402
struct rtable *rt = skb_rtable(skb);
404-
struct net *net = dev_net(rt->dst.dev);
403+
struct net *net = dev_net_rcu(rt->dst.dev);
405404
bool apply_ratelimit = false;
405+
struct ipcm_cookie ipc;
406406
struct flowi4 fl4;
407407
struct sock *sk;
408408
struct inet_sock *inet;
@@ -608,12 +608,14 @@ void __icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info,
608608
struct sock *sk;
609609

610610
if (!rt)
611-
goto out;
611+
return;
612+
613+
rcu_read_lock();
612614

613615
if (rt->dst.dev)
614-
net = dev_net(rt->dst.dev);
616+
net = dev_net_rcu(rt->dst.dev);
615617
else if (skb_in->dev)
616-
net = dev_net(skb_in->dev);
618+
net = dev_net_rcu(skb_in->dev);
617619
else
618620
goto out;
619621

@@ -785,7 +787,8 @@ void __icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info,
785787
icmp_xmit_unlock(sk);
786788
out_bh_enable:
787789
local_bh_enable();
788-
out:;
790+
out:
791+
rcu_read_unlock();
789792
}
790793
EXPORT_SYMBOL(__icmp_send);
791794

@@ -834,7 +837,7 @@ static void icmp_socket_deliver(struct sk_buff *skb, u32 info)
834837
* avoid additional coding at protocol handlers.
835838
*/
836839
if (!pskb_may_pull(skb, iph->ihl * 4 + 8)) {
837-
__ICMP_INC_STATS(dev_net(skb->dev), ICMP_MIB_INERRORS);
840+
__ICMP_INC_STATS(dev_net_rcu(skb->dev), ICMP_MIB_INERRORS);
838841
return;
839842
}
840843

@@ -868,7 +871,7 @@ static enum skb_drop_reason icmp_unreach(struct sk_buff *skb)
868871
struct net *net;
869872
u32 info = 0;
870873

871-
net = dev_net(skb_dst(skb)->dev);
874+
net = dev_net_rcu(skb_dst(skb)->dev);
872875

873876
/*
874877
* Incomplete header ?
@@ -979,7 +982,7 @@ static enum skb_drop_reason icmp_unreach(struct sk_buff *skb)
979982
static enum skb_drop_reason icmp_redirect(struct sk_buff *skb)
980983
{
981984
if (skb->len < sizeof(struct iphdr)) {
982-
__ICMP_INC_STATS(dev_net(skb->dev), ICMP_MIB_INERRORS);
985+
__ICMP_INC_STATS(dev_net_rcu(skb->dev), ICMP_MIB_INERRORS);
983986
return SKB_DROP_REASON_PKT_TOO_SMALL;
984987
}
985988

@@ -1011,7 +1014,7 @@ static enum skb_drop_reason icmp_echo(struct sk_buff *skb)
10111014
struct icmp_bxm icmp_param;
10121015
struct net *net;
10131016

1014-
net = dev_net(skb_dst(skb)->dev);
1017+
net = dev_net_rcu(skb_dst(skb)->dev);
10151018
/* should there be an ICMP stat for ignored echos? */
10161019
if (READ_ONCE(net->ipv4.sysctl_icmp_echo_ignore_all))
10171020
return SKB_NOT_DROPPED_YET;
@@ -1040,9 +1043,9 @@ static enum skb_drop_reason icmp_echo(struct sk_buff *skb)
10401043

10411044
bool icmp_build_probe(struct sk_buff *skb, struct icmphdr *icmphdr)
10421045
{
1046+
struct net *net = dev_net_rcu(skb->dev);
10431047
struct icmp_ext_hdr *ext_hdr, _ext_hdr;
10441048
struct icmp_ext_echo_iio *iio, _iio;
1045-
struct net *net = dev_net(skb->dev);
10461049
struct inet6_dev *in6_dev;
10471050
struct in_device *in_dev;
10481051
struct net_device *dev;
@@ -1181,7 +1184,7 @@ static enum skb_drop_reason icmp_timestamp(struct sk_buff *skb)
11811184
return SKB_NOT_DROPPED_YET;
11821185

11831186
out_err:
1184-
__ICMP_INC_STATS(dev_net(skb_dst(skb)->dev), ICMP_MIB_INERRORS);
1187+
__ICMP_INC_STATS(dev_net_rcu(skb_dst(skb)->dev), ICMP_MIB_INERRORS);
11851188
return SKB_DROP_REASON_PKT_TOO_SMALL;
11861189
}
11871190

@@ -1198,7 +1201,7 @@ int icmp_rcv(struct sk_buff *skb)
11981201
{
11991202
enum skb_drop_reason reason = SKB_DROP_REASON_NOT_SPECIFIED;
12001203
struct rtable *rt = skb_rtable(skb);
1201-
struct net *net = dev_net(rt->dst.dev);
1204+
struct net *net = dev_net_rcu(rt->dst.dev);
12021205
struct icmphdr *icmph;
12031206

12041207
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
@@ -1371,9 +1374,9 @@ int icmp_err(struct sk_buff *skb, u32 info)
13711374
struct iphdr *iph = (struct iphdr *)skb->data;
13721375
int offset = iph->ihl<<2;
13731376
struct icmphdr *icmph = (struct icmphdr *)(skb->data + offset);
1377+
struct net *net = dev_net_rcu(skb->dev);
13741378
int type = icmp_hdr(skb)->type;
13751379
int code = icmp_hdr(skb)->code;
1376-
struct net *net = dev_net(skb->dev);
13771380

13781381
/*
13791382
* Use ping_err to handle all icmp errors except those

0 commit comments

Comments
 (0)