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: dde1bc0e6f
("[NETNS]: Add namespace for ICMP replying code.")
Closes: https://lore.kernel.org/netdev/20250203153633.46ce0337@kernel.org/
Reported-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20250205155120.1676781-9-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
139512191b
commit
4b8474a095
1 changed files with 17 additions and 14 deletions
|
@ -399,10 +399,10 @@ static void icmp_push_reply(struct sock *sk,
|
||||||
|
|
||||||
static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
|
static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct ipcm_cookie ipc;
|
|
||||||
struct rtable *rt = skb_rtable(skb);
|
struct rtable *rt = skb_rtable(skb);
|
||||||
struct net *net = dev_net(rt->dst.dev);
|
struct net *net = dev_net_rcu(rt->dst.dev);
|
||||||
bool apply_ratelimit = false;
|
bool apply_ratelimit = false;
|
||||||
|
struct ipcm_cookie ipc;
|
||||||
struct flowi4 fl4;
|
struct flowi4 fl4;
|
||||||
struct sock *sk;
|
struct sock *sk;
|
||||||
struct inet_sock *inet;
|
struct inet_sock *inet;
|
||||||
|
@ -608,12 +608,14 @@ void __icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info,
|
||||||
struct sock *sk;
|
struct sock *sk;
|
||||||
|
|
||||||
if (!rt)
|
if (!rt)
|
||||||
goto out;
|
return;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
|
||||||
if (rt->dst.dev)
|
if (rt->dst.dev)
|
||||||
net = dev_net(rt->dst.dev);
|
net = dev_net_rcu(rt->dst.dev);
|
||||||
else if (skb_in->dev)
|
else if (skb_in->dev)
|
||||||
net = dev_net(skb_in->dev);
|
net = dev_net_rcu(skb_in->dev);
|
||||||
else
|
else
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -785,7 +787,8 @@ out_unlock:
|
||||||
icmp_xmit_unlock(sk);
|
icmp_xmit_unlock(sk);
|
||||||
out_bh_enable:
|
out_bh_enable:
|
||||||
local_bh_enable();
|
local_bh_enable();
|
||||||
out:;
|
out:
|
||||||
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(__icmp_send);
|
EXPORT_SYMBOL(__icmp_send);
|
||||||
|
|
||||||
|
@ -834,7 +837,7 @@ static void icmp_socket_deliver(struct sk_buff *skb, u32 info)
|
||||||
* avoid additional coding at protocol handlers.
|
* avoid additional coding at protocol handlers.
|
||||||
*/
|
*/
|
||||||
if (!pskb_may_pull(skb, iph->ihl * 4 + 8)) {
|
if (!pskb_may_pull(skb, iph->ihl * 4 + 8)) {
|
||||||
__ICMP_INC_STATS(dev_net(skb->dev), ICMP_MIB_INERRORS);
|
__ICMP_INC_STATS(dev_net_rcu(skb->dev), ICMP_MIB_INERRORS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -868,7 +871,7 @@ static enum skb_drop_reason icmp_unreach(struct sk_buff *skb)
|
||||||
struct net *net;
|
struct net *net;
|
||||||
u32 info = 0;
|
u32 info = 0;
|
||||||
|
|
||||||
net = dev_net(skb_dst(skb)->dev);
|
net = dev_net_rcu(skb_dst(skb)->dev);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Incomplete header ?
|
* Incomplete header ?
|
||||||
|
@ -979,7 +982,7 @@ out_err:
|
||||||
static enum skb_drop_reason icmp_redirect(struct sk_buff *skb)
|
static enum skb_drop_reason icmp_redirect(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
if (skb->len < sizeof(struct iphdr)) {
|
if (skb->len < sizeof(struct iphdr)) {
|
||||||
__ICMP_INC_STATS(dev_net(skb->dev), ICMP_MIB_INERRORS);
|
__ICMP_INC_STATS(dev_net_rcu(skb->dev), ICMP_MIB_INERRORS);
|
||||||
return SKB_DROP_REASON_PKT_TOO_SMALL;
|
return SKB_DROP_REASON_PKT_TOO_SMALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1011,7 +1014,7 @@ static enum skb_drop_reason icmp_echo(struct sk_buff *skb)
|
||||||
struct icmp_bxm icmp_param;
|
struct icmp_bxm icmp_param;
|
||||||
struct net *net;
|
struct net *net;
|
||||||
|
|
||||||
net = dev_net(skb_dst(skb)->dev);
|
net = dev_net_rcu(skb_dst(skb)->dev);
|
||||||
/* should there be an ICMP stat for ignored echos? */
|
/* should there be an ICMP stat for ignored echos? */
|
||||||
if (READ_ONCE(net->ipv4.sysctl_icmp_echo_ignore_all))
|
if (READ_ONCE(net->ipv4.sysctl_icmp_echo_ignore_all))
|
||||||
return SKB_NOT_DROPPED_YET;
|
return SKB_NOT_DROPPED_YET;
|
||||||
|
@ -1040,9 +1043,9 @@ static enum skb_drop_reason icmp_echo(struct sk_buff *skb)
|
||||||
|
|
||||||
bool icmp_build_probe(struct sk_buff *skb, struct icmphdr *icmphdr)
|
bool icmp_build_probe(struct sk_buff *skb, struct icmphdr *icmphdr)
|
||||||
{
|
{
|
||||||
|
struct net *net = dev_net_rcu(skb->dev);
|
||||||
struct icmp_ext_hdr *ext_hdr, _ext_hdr;
|
struct icmp_ext_hdr *ext_hdr, _ext_hdr;
|
||||||
struct icmp_ext_echo_iio *iio, _iio;
|
struct icmp_ext_echo_iio *iio, _iio;
|
||||||
struct net *net = dev_net(skb->dev);
|
|
||||||
struct inet6_dev *in6_dev;
|
struct inet6_dev *in6_dev;
|
||||||
struct in_device *in_dev;
|
struct in_device *in_dev;
|
||||||
struct net_device *dev;
|
struct net_device *dev;
|
||||||
|
@ -1181,7 +1184,7 @@ static enum skb_drop_reason icmp_timestamp(struct sk_buff *skb)
|
||||||
return SKB_NOT_DROPPED_YET;
|
return SKB_NOT_DROPPED_YET;
|
||||||
|
|
||||||
out_err:
|
out_err:
|
||||||
__ICMP_INC_STATS(dev_net(skb_dst(skb)->dev), ICMP_MIB_INERRORS);
|
__ICMP_INC_STATS(dev_net_rcu(skb_dst(skb)->dev), ICMP_MIB_INERRORS);
|
||||||
return SKB_DROP_REASON_PKT_TOO_SMALL;
|
return SKB_DROP_REASON_PKT_TOO_SMALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1198,7 +1201,7 @@ int icmp_rcv(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
enum skb_drop_reason reason = SKB_DROP_REASON_NOT_SPECIFIED;
|
enum skb_drop_reason reason = SKB_DROP_REASON_NOT_SPECIFIED;
|
||||||
struct rtable *rt = skb_rtable(skb);
|
struct rtable *rt = skb_rtable(skb);
|
||||||
struct net *net = dev_net(rt->dst.dev);
|
struct net *net = dev_net_rcu(rt->dst.dev);
|
||||||
struct icmphdr *icmph;
|
struct icmphdr *icmph;
|
||||||
|
|
||||||
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
|
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
|
||||||
|
@ -1371,9 +1374,9 @@ int icmp_err(struct sk_buff *skb, u32 info)
|
||||||
struct iphdr *iph = (struct iphdr *)skb->data;
|
struct iphdr *iph = (struct iphdr *)skb->data;
|
||||||
int offset = iph->ihl<<2;
|
int offset = iph->ihl<<2;
|
||||||
struct icmphdr *icmph = (struct icmphdr *)(skb->data + offset);
|
struct icmphdr *icmph = (struct icmphdr *)(skb->data + offset);
|
||||||
|
struct net *net = dev_net_rcu(skb->dev);
|
||||||
int type = icmp_hdr(skb)->type;
|
int type = icmp_hdr(skb)->type;
|
||||||
int code = icmp_hdr(skb)->code;
|
int code = icmp_hdr(skb)->code;
|
||||||
struct net *net = dev_net(skb->dev);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Use ping_err to handle all icmp errors except those
|
* Use ping_err to handle all icmp errors except those
|
||||||
|
|
Loading…
Add table
Reference in a new issue