Skip to content

Commit 7938cd1

Browse files
Richard Gobertdavem330
authored andcommitted
net: gro: fix misuse of CB in udp socket lookup
This patch fixes a misuse of IP{6}CB(skb) in GRO, while calling to `udp6_lib_lookup2` when handling udp tunnels. `udp6_lib_lookup2` fetch the device from CB. The fix changes it to fetch the device from `skb->dev`. l3mdev case requires special attention since it has a master and a slave device. Fixes: a602456 ("udp: Add GRO functions to UDP socket") Reported-by: Gal Pressman <[email protected]> Signed-off-by: Richard Gobert <[email protected]> Reviewed-by: David Ahern <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent e346e23 commit 7938cd1

File tree

5 files changed

+65
-8
lines changed

5 files changed

+65
-8
lines changed

include/net/gro.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,49 @@ static inline void gro_normal_one(struct napi_struct *napi, struct sk_buff *skb,
452452
gro_normal_list(napi);
453453
}
454454

455+
/* This function is the alternative of 'inet_iif' and 'inet_sdif'
456+
* functions in case we can not rely on fields of IPCB.
457+
*
458+
* The caller must verify skb_valid_dst(skb) is false and skb->dev is initialized.
459+
* The caller must hold the RCU read lock.
460+
*/
461+
static inline void inet_get_iif_sdif(const struct sk_buff *skb, int *iif, int *sdif)
462+
{
463+
*iif = inet_iif(skb) ?: skb->dev->ifindex;
464+
*sdif = 0;
465+
466+
#if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV)
467+
if (netif_is_l3_slave(skb->dev)) {
468+
struct net_device *master = netdev_master_upper_dev_get_rcu(skb->dev);
469+
470+
*sdif = *iif;
471+
*iif = master ? master->ifindex : 0;
472+
}
473+
#endif
474+
}
475+
476+
/* This function is the alternative of 'inet6_iif' and 'inet6_sdif'
477+
* functions in case we can not rely on fields of IP6CB.
478+
*
479+
* The caller must verify skb_valid_dst(skb) is false and skb->dev is initialized.
480+
* The caller must hold the RCU read lock.
481+
*/
482+
static inline void inet6_get_iif_sdif(const struct sk_buff *skb, int *iif, int *sdif)
483+
{
484+
/* using skb->dev->ifindex because skb_dst(skb) is not initialized */
485+
*iif = skb->dev->ifindex;
486+
*sdif = 0;
487+
488+
#if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV)
489+
if (netif_is_l3_slave(skb->dev)) {
490+
struct net_device *master = netdev_master_upper_dev_get_rcu(skb->dev);
491+
492+
*sdif = *iif;
493+
*iif = master ? master->ifindex : 0;
494+
}
495+
#endif
496+
}
497+
455498
extern struct list_head offload_base;
456499

457500
#endif /* _NET_IPV6_GRO_H */

net/ipv4/udp.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@
114114
#include <net/sock_reuseport.h>
115115
#include <net/addrconf.h>
116116
#include <net/udp_tunnel.h>
117+
#include <net/gro.h>
117118
#if IS_ENABLED(CONFIG_IPV6)
118119
#include <net/ipv6_stubs.h>
119120
#endif
@@ -555,10 +556,13 @@ struct sock *udp4_lib_lookup_skb(const struct sk_buff *skb,
555556
{
556557
const struct iphdr *iph = ip_hdr(skb);
557558
struct net *net = dev_net(skb->dev);
559+
int iif, sdif;
560+
561+
inet_get_iif_sdif(skb, &iif, &sdif);
558562

559563
return __udp4_lib_lookup(net, iph->saddr, sport,
560-
iph->daddr, dport, inet_iif(skb),
561-
inet_sdif(skb), net->ipv4.udp_table, NULL);
564+
iph->daddr, dport, iif,
565+
sdif, net->ipv4.udp_table, NULL);
562566
}
563567

564568
/* Must be called under rcu_read_lock().

net/ipv4/udp_offload.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -609,10 +609,13 @@ static struct sock *udp4_gro_lookup_skb(struct sk_buff *skb, __be16 sport,
609609
{
610610
const struct iphdr *iph = skb_gro_network_header(skb);
611611
struct net *net = dev_net(skb->dev);
612+
int iif, sdif;
613+
614+
inet_get_iif_sdif(skb, &iif, &sdif);
612615

613616
return __udp4_lib_lookup(net, iph->saddr, sport,
614-
iph->daddr, dport, inet_iif(skb),
615-
inet_sdif(skb), net->ipv4.udp_table, NULL);
617+
iph->daddr, dport, iif,
618+
sdif, net->ipv4.udp_table, NULL);
616619
}
617620

618621
INDIRECT_CALLABLE_SCOPE

net/ipv6/udp.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
#include <net/inet6_hashtables.h>
5252
#include <net/busy_poll.h>
5353
#include <net/sock_reuseport.h>
54+
#include <net/gro.h>
5455

5556
#include <linux/proc_fs.h>
5657
#include <linux/seq_file.h>
@@ -300,10 +301,13 @@ struct sock *udp6_lib_lookup_skb(const struct sk_buff *skb,
300301
{
301302
const struct ipv6hdr *iph = ipv6_hdr(skb);
302303
struct net *net = dev_net(skb->dev);
304+
int iif, sdif;
305+
306+
inet6_get_iif_sdif(skb, &iif, &sdif);
303307

304308
return __udp6_lib_lookup(net, &iph->saddr, sport,
305-
&iph->daddr, dport, inet6_iif(skb),
306-
inet6_sdif(skb), net->ipv4.udp_table, NULL);
309+
&iph->daddr, dport, iif,
310+
sdif, net->ipv4.udp_table, NULL);
307311
}
308312

309313
/* Must be called under rcu_read_lock().

net/ipv6/udp_offload.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,13 @@ static struct sock *udp6_gro_lookup_skb(struct sk_buff *skb, __be16 sport,
118118
{
119119
const struct ipv6hdr *iph = skb_gro_network_header(skb);
120120
struct net *net = dev_net(skb->dev);
121+
int iif, sdif;
122+
123+
inet6_get_iif_sdif(skb, &iif, &sdif);
121124

122125
return __udp6_lib_lookup(net, &iph->saddr, sport,
123-
&iph->daddr, dport, inet6_iif(skb),
124-
inet6_sdif(skb), net->ipv4.udp_table, NULL);
126+
&iph->daddr, dport, iif,
127+
sdif, net->ipv4.udp_table, NULL);
125128
}
126129

127130
INDIRECT_CALLABLE_SCOPE

0 commit comments

Comments
 (0)