Skip to content

Commit 1dbf1d5

Browse files
Sharath Chandra Vurukalakuba-moo
authored andcommitted
net: Add locking to protect skb->dev access in ip_output
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 <[email protected]> Reviewed-by: Eric Dumazet <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent ae8508b commit 1dbf1d5

File tree

2 files changed

+22
-5
lines changed

2 files changed

+22
-5
lines changed

include/net/dst.h

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

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

583+
static inline struct net_device *skb_dst_dev_rcu(const struct sk_buff *skb)
584+
{
585+
return dst_dev_rcu(skb_dst(skb));
586+
}
587+
576588
static inline struct net *skb_dst_dev_net(const struct sk_buff *skb)
577589
{
578590
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
@@ -425,15 +425,20 @@ int ip_mc_output(struct net *net, struct sock *sk, struct sk_buff *skb)
425425

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

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

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

0 commit comments

Comments
 (0)