Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ipv6: protect skb->sk accesses from recursive dereference inside the stack

We should not consult skb->sk for output decisions in xmit recursion
levels > 0 in the stack. Otherwise local socket settings could influence
the result of e.g. tunnel encapsulation process.

ipv6 does not conform with this in three places:

1) ip6_fragment: we do consult ipv6_npinfo for frag_size

2) sk_mc_loop in ipv6 uses skb->sk and checks if we should
loop the packet back to the local socket

3) ip6_skb_dst_mtu could query the settings from the user socket and
force a wrong MTU

Furthermore:
In sk_mc_loop we could potentially land in WARN_ON(1) if we use a
PF_PACKET socket ontop of an IPv6-backed vxlan device.

Reuse xmit_recursion as we are currently only interested in protecting
tunnel devices.

Cc: Jiri Pirko <jiri@resnulli.us>
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

hannes@stressinduktion.org and committed by
David S. Miller
f60e5990 576b7cd2

+34 -19
+6
include/linux/netdevice.h
··· 2185 2185 void synchronize_net(void); 2186 2186 int init_dummy_netdev(struct net_device *dev); 2187 2187 2188 + DECLARE_PER_CPU(int, xmit_recursion); 2189 + static inline int dev_recursion_level(void) 2190 + { 2191 + return this_cpu_read(xmit_recursion); 2192 + } 2193 + 2188 2194 struct net_device *dev_get_by_index(struct net *net, int ifindex); 2189 2195 struct net_device *__dev_get_by_index(struct net *net, int ifindex); 2190 2196 struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex);
-16
include/net/ip.h
··· 453 453 454 454 #endif 455 455 456 - static inline int sk_mc_loop(struct sock *sk) 457 - { 458 - if (!sk) 459 - return 1; 460 - switch (sk->sk_family) { 461 - case AF_INET: 462 - return inet_sk(sk)->mc_loop; 463 - #if IS_ENABLED(CONFIG_IPV6) 464 - case AF_INET6: 465 - return inet6_sk(sk)->mc_loop; 466 - #endif 467 - } 468 - WARN_ON(1); 469 - return 1; 470 - } 471 - 472 456 bool ip_call_ra_chain(struct sk_buff *skb); 473 457 474 458 /*
+2 -1
include/net/ip6_route.h
··· 174 174 175 175 static inline int ip6_skb_dst_mtu(struct sk_buff *skb) 176 176 { 177 - struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL; 177 + struct ipv6_pinfo *np = skb->sk && !dev_recursion_level() ? 178 + inet6_sk(skb->sk) : NULL; 178 179 179 180 return (np && np->pmtudisc >= IPV6_PMTUDISC_PROBE) ? 180 181 skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb));
+2
include/net/sock.h
··· 1762 1762 1763 1763 struct dst_entry *sk_dst_check(struct sock *sk, u32 cookie); 1764 1764 1765 + bool sk_mc_loop(struct sock *sk); 1766 + 1765 1767 static inline bool sk_can_gso(const struct sock *sk) 1766 1768 { 1767 1769 return net_gso_ok(sk->sk_route_caps, sk->sk_gso_type);
+3 -1
net/core/dev.c
··· 2848 2848 #define skb_update_prio(skb) 2849 2849 #endif 2850 2850 2851 - static DEFINE_PER_CPU(int, xmit_recursion); 2851 + DEFINE_PER_CPU(int, xmit_recursion); 2852 + EXPORT_SYMBOL(xmit_recursion); 2853 + 2852 2854 #define RECURSION_LIMIT 10 2853 2855 2854 2856 /**
+19
net/core/sock.c
··· 653 653 sock_reset_flag(sk, bit); 654 654 } 655 655 656 + bool sk_mc_loop(struct sock *sk) 657 + { 658 + if (dev_recursion_level()) 659 + return false; 660 + if (!sk) 661 + return true; 662 + switch (sk->sk_family) { 663 + case AF_INET: 664 + return inet_sk(sk)->mc_loop; 665 + #if IS_ENABLED(CONFIG_IPV6) 666 + case AF_INET6: 667 + return inet6_sk(sk)->mc_loop; 668 + #endif 669 + } 670 + WARN_ON(1); 671 + return true; 672 + } 673 + EXPORT_SYMBOL(sk_mc_loop); 674 + 656 675 /* 657 676 * This is meant for all protocols to use and covers goings on 658 677 * at the socket level. Everything here is generic.
+2 -1
net/ipv6/ip6_output.c
··· 542 542 { 543 543 struct sk_buff *frag; 544 544 struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); 545 - struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL; 545 + struct ipv6_pinfo *np = skb->sk && !dev_recursion_level() ? 546 + inet6_sk(skb->sk) : NULL; 546 547 struct ipv6hdr *tmp_hdr; 547 548 struct frag_hdr *fh; 548 549 unsigned int mtu, hlen, left, len;