aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6_output.c
diff options
context:
space:
mode:
authorDavid Miller <davem@davemloft.net>2015-04-05 22:19:04 -0400
committerDavid S. Miller <davem@davemloft.net>2015-04-07 15:25:55 -0400
commit7026b1ddb6b8d4e6ee33dc2bd06c0ca8746fa7ab (patch)
tree3e11ed0f186ea6066a3f7efecb88d85bc732ee51 /net/ipv6/ip6_output.c
parent1c984f8a5df085bcf35364a8a870bd4db4da4ed3 (diff)
netfilter: Pass socket pointer down through okfn().
On the output paths in particular, we have to sometimes deal with two socket contexts. First, and usually skb->sk, is the local socket that generated the frame. And second, is potentially the socket used to control a tunneling socket, such as one the encapsulates using UDP. We do not want to disassociate skb->sk when encapsulating in order to fix this, because that would break socket memory accounting. The most extreme case where this can cause huge problems is an AF_PACKET socket transmitting over a vxlan device. We hit code paths doing checks that assume they are dealing with an ipv4 socket, but are actually operating upon the AF_PACKET one. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r--net/ipv6/ip6_output.c33
1 files changed, 18 insertions, 15 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 654f245aa930..7fde1f265c90 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -56,7 +56,7 @@
56#include <net/checksum.h> 56#include <net/checksum.h>
57#include <linux/mroute6.h> 57#include <linux/mroute6.h>
58 58
59static int ip6_finish_output2(struct sk_buff *skb) 59static int ip6_finish_output2(struct sock *sk, struct sk_buff *skb)
60{ 60{
61 struct dst_entry *dst = skb_dst(skb); 61 struct dst_entry *dst = skb_dst(skb);
62 struct net_device *dev = dst->dev; 62 struct net_device *dev = dst->dev;
@@ -70,7 +70,7 @@ static int ip6_finish_output2(struct sk_buff *skb)
70 if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr)) { 70 if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr)) {
71 struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); 71 struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
72 72
73 if (!(dev->flags & IFF_LOOPBACK) && sk_mc_loop(skb->sk) && 73 if (!(dev->flags & IFF_LOOPBACK) && sk_mc_loop(sk) &&
74 ((mroute6_socket(dev_net(dev), skb) && 74 ((mroute6_socket(dev_net(dev), skb) &&
75 !(IP6CB(skb)->flags & IP6SKB_FORWARDED)) || 75 !(IP6CB(skb)->flags & IP6SKB_FORWARDED)) ||
76 ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr, 76 ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr,
@@ -82,7 +82,7 @@ static int ip6_finish_output2(struct sk_buff *skb)
82 */ 82 */
83 if (newskb) 83 if (newskb)
84 NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, 84 NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING,
85 newskb, NULL, newskb->dev, 85 sk, newskb, NULL, newskb->dev,
86 dev_loopback_xmit); 86 dev_loopback_xmit);
87 87
88 if (ipv6_hdr(skb)->hop_limit == 0) { 88 if (ipv6_hdr(skb)->hop_limit == 0) {
@@ -122,14 +122,14 @@ static int ip6_finish_output2(struct sk_buff *skb)
122 return -EINVAL; 122 return -EINVAL;
123} 123}
124 124
125static int ip6_finish_output(struct sk_buff *skb) 125static int ip6_finish_output(struct sock *sk, struct sk_buff *skb)
126{ 126{
127 if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) || 127 if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) ||
128 dst_allfrag(skb_dst(skb)) || 128 dst_allfrag(skb_dst(skb)) ||
129 (IP6CB(skb)->frag_max_size && skb->len > IP6CB(skb)->frag_max_size)) 129 (IP6CB(skb)->frag_max_size && skb->len > IP6CB(skb)->frag_max_size))
130 return ip6_fragment(skb, ip6_finish_output2); 130 return ip6_fragment(sk, skb, ip6_finish_output2);
131 else 131 else
132 return ip6_finish_output2(skb); 132 return ip6_finish_output2(sk, skb);
133} 133}
134 134
135int ip6_output(struct sock *sk, struct sk_buff *skb) 135int ip6_output(struct sock *sk, struct sk_buff *skb)
@@ -143,7 +143,8 @@ int ip6_output(struct sock *sk, struct sk_buff *skb)
143 return 0; 143 return 0;
144 } 144 }
145 145
146 return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL, dev, 146 return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING, sk, skb,
147 NULL, dev,
147 ip6_finish_output, 148 ip6_finish_output,
148 !(IP6CB(skb)->flags & IP6SKB_REROUTED)); 149 !(IP6CB(skb)->flags & IP6SKB_REROUTED));
149} 150}
@@ -223,8 +224,8 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
223 if ((skb->len <= mtu) || skb->ignore_df || skb_is_gso(skb)) { 224 if ((skb->len <= mtu) || skb->ignore_df || skb_is_gso(skb)) {
224 IP6_UPD_PO_STATS(net, ip6_dst_idev(skb_dst(skb)), 225 IP6_UPD_PO_STATS(net, ip6_dst_idev(skb_dst(skb)),
225 IPSTATS_MIB_OUT, skb->len); 226 IPSTATS_MIB_OUT, skb->len);
226 return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, 227 return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, sk, skb,
227 dst->dev, dst_output); 228 NULL, dst->dev, dst_output_sk);
228 } 229 }
229 230
230 skb->dev = dst->dev; 231 skb->dev = dst->dev;
@@ -316,10 +317,10 @@ static int ip6_forward_proxy_check(struct sk_buff *skb)
316 return 0; 317 return 0;
317} 318}
318 319
319static inline int ip6_forward_finish(struct sk_buff *skb) 320static inline int ip6_forward_finish(struct sock *sk, struct sk_buff *skb)
320{ 321{
321 skb_sender_cpu_clear(skb); 322 skb_sender_cpu_clear(skb);
322 return dst_output(skb); 323 return dst_output_sk(sk, skb);
323} 324}
324 325
325static unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst) 326static unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst)
@@ -511,7 +512,8 @@ int ip6_forward(struct sk_buff *skb)
511 512
512 IP6_INC_STATS_BH(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS); 513 IP6_INC_STATS_BH(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS);
513 IP6_ADD_STATS_BH(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTOCTETS, skb->len); 514 IP6_ADD_STATS_BH(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTOCTETS, skb->len);
514 return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD, skb, skb->dev, dst->dev, 515 return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD, NULL, skb,
516 skb->dev, dst->dev,
515 ip6_forward_finish); 517 ip6_forward_finish);
516 518
517error: 519error:
@@ -538,7 +540,8 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from)
538 skb_copy_secmark(to, from); 540 skb_copy_secmark(to, from);
539} 541}
540 542
541int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) 543int ip6_fragment(struct sock *sk, struct sk_buff *skb,
544 int (*output)(struct sock *, struct sk_buff *))
542{ 545{
543 struct sk_buff *frag; 546 struct sk_buff *frag;
544 struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); 547 struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
@@ -667,7 +670,7 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
667 ip6_copy_metadata(frag, skb); 670 ip6_copy_metadata(frag, skb);
668 } 671 }
669 672
670 err = output(skb); 673 err = output(sk, skb);
671 if (!err) 674 if (!err)
672 IP6_INC_STATS(net, ip6_dst_idev(&rt->dst), 675 IP6_INC_STATS(net, ip6_dst_idev(&rt->dst),
673 IPSTATS_MIB_FRAGCREATES); 676 IPSTATS_MIB_FRAGCREATES);
@@ -800,7 +803,7 @@ slow_path:
800 /* 803 /*
801 * Put this fragment into the sending queue. 804 * Put this fragment into the sending queue.
802 */ 805 */
803 err = output(frag); 806 err = output(sk, frag);
804 if (err) 807 if (err)
805 goto fail; 808 goto fail;
806 809