Skip to content

Commit 4388b7f

Browse files
Sharath Chandra Vurukalagregkh
authored andcommitted
net: Add locking to protect skb->dev access in ip_output
[ Upstream commit 1dbf1d5 ] In ip_output() skb->dev is updated from the skb_dst(skb)->dev this can become invalid when the interface is unregistered and freed, Introduced new skb_dst_dev_rcu() function to be used instead of skb_dst_dev() within rcu_locks in ip_output.This will ensure that all the skb's associated with the dev being deregistered will be transnmitted out first, before freeing the dev. Given that ip_output() is called within an rcu_read_lock() critical section or from a bottom-half context, it is safe to introduce an RCU read-side critical section within it. Multiple panic call stacks were observed when UL traffic was run in concurrency with device deregistration from different functions, pasting one sample for reference. [496733.627565][T13385] Call trace: [496733.627570][T13385] bpf_prog_ce7c9180c3b128ea_cgroupskb_egres+0x24c/0x7f0 [496733.627581][T13385] __cgroup_bpf_run_filter_skb+0x128/0x498 [496733.627595][T13385] ip_finish_output+0xa4/0xf4 [496733.627605][T13385] ip_output+0x100/0x1a0 [496733.627613][T13385] ip_send_skb+0x68/0x100 [496733.627618][T13385] udp_send_skb+0x1c4/0x384 [496733.627625][T13385] udp_sendmsg+0x7b0/0x898 [496733.627631][T13385] inet_sendmsg+0x5c/0x7c [496733.627639][T13385] __sys_sendto+0x174/0x1e4 [496733.627647][T13385] __arm64_sys_sendto+0x28/0x3c [496733.627653][T13385] invoke_syscall+0x58/0x11c [496733.627662][T13385] el0_svc_common+0x88/0xf4 [496733.627669][T13385] do_el0_svc+0x2c/0xb0 [496733.627676][T13385] el0_svc+0x2c/0xa4 [496733.627683][T13385] el0t_64_sync_handler+0x68/0xb4 [496733.627689][T13385] el0t_64_sync+0x1a4/0x1a8 Changes in v3: - Replaced WARN_ON() with WARN_ON_ONCE(), as suggested by Willem de Bruijn. - Dropped legacy lines mistakenly pulled in from an outdated branch. Changes in v2: - Addressed review comments from Eric Dumazet - Used READ_ONCE() to prevent potential load/store tearing - Added skb_dst_dev_rcu() and used along with rcu_read_lock() in ip_output Signed-off-by: Sharath Chandra Vurukala <quic_sharathv@quicinc.com> Reviewed-by: Eric Dumazet <edumazet@google.com> Link: https://patch.msgid.link/20250730105118.GA26100@hu-sharathv-hyd.qualcomm.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> Stable-dep-of: 833d431 ("mptcp: reset blackhole on success with non-loopback ifaces") Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 95d4308 commit 4388b7f

2 files changed

Lines changed: 22 additions & 5 deletions

File tree

include/net/dst.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,11 +566,23 @@ static inline struct net_device *dst_dev(const struct dst_entry *dst)
566566
return READ_ONCE(dst->dev);
567567
}
568568

569+
static inline struct net_device *dst_dev_rcu(const struct dst_entry *dst)
570+
{
571+
/* In the future, use rcu_dereference(dst->dev) */
572+
WARN_ON_ONCE(!rcu_read_lock_held());
573+
return READ_ONCE(dst->dev);
574+
}
575+
569576
static inline struct net_device *skb_dst_dev(const struct sk_buff *skb)
570577
{
571578
return dst_dev(skb_dst(skb));
572579
}
573580

581+
static inline struct net_device *skb_dst_dev_rcu(const struct sk_buff *skb)
582+
{
583+
return dst_dev_rcu(skb_dst(skb));
584+
}
585+
574586
static inline struct net *skb_dst_dev_net(const struct sk_buff *skb)
575587
{
576588
return dev_net(skb_dst_dev(skb));

net/ipv4/ip_output.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -426,15 +426,20 @@ int ip_mc_output(struct net *net, struct sock *sk, struct sk_buff *skb)
426426

427427
int ip_output(struct net *net, struct sock *sk, struct sk_buff *skb)
428428
{
429-
struct net_device *dev = skb_dst_dev(skb), *indev = skb->dev;
429+
struct net_device *dev, *indev = skb->dev;
430+
int ret_val;
430431

432+
rcu_read_lock();
433+
dev = skb_dst_dev_rcu(skb);
431434
skb->dev = dev;
432435
skb->protocol = htons(ETH_P_IP);
433436

434-
return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING,
435-
net, sk, skb, indev, dev,
436-
ip_finish_output,
437-
!(IPCB(skb)->flags & IPSKB_REROUTED));
437+
ret_val = NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING,
438+
net, sk, skb, indev, dev,
439+
ip_finish_output,
440+
!(IPCB(skb)->flags & IPSKB_REROUTED));
441+
rcu_read_unlock();
442+
return ret_val;
438443
}
439444
EXPORT_SYMBOL(ip_output);
440445

0 commit comments

Comments
 (0)