aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2013-08-29 16:05:30 -0400
committerDavid S. Miller <davem@davemloft.net>2013-08-29 16:05:30 -0400
commit79f9ab7e0a8ec452e58b5a5267b9eb019ff493d0 (patch)
tree650d432ab57882fa022b0edaee058fe8044e68c0 /net/ipv6
parent1f324e38870cc09659cf23bc626f1b8869e201f2 (diff)
parent302a50bc941010d7a67f288fd0db31981e4d722d (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec
Steffen Klassert says: ==================== This pull request fixes some issues that arise when 6in4 or 4in6 tunnels are used in combination with IPsec, all from Hannes Frederic Sowa and a null pointer dereference when queueing packets to the policy hold queue. 1) We might access the local error handler of the wrong address family if 6in4 or 4in6 tunnel is protected by ipsec. Fix this by addind a pointer to the correct local_error to xfrm_state_afinet. 2) Add a helper function to always refer to the correct interpretation of skb->sk. 3) Call skb_reset_inner_headers to record the position of the inner headers when adding a new one in various ipv6 tunnels. This is needed to identify the addresses where to send back errors in the xfrm layer. 4) Dereference inner ipv6 header if encapsulated to always call the right error handler. 5) Choose protocol family by skb protocol to not call the wrong xfrm{4,6}_local_error handler in case an ipv6 sockets is used in ipv4 mode. 6) Partly revert "xfrm: introduce helper for safe determination of mtu" because this introduced pmtu discovery problems. 7) Set skb->protocol on tcp, raw and ip6_append_data genereated skbs. We need this to get the correct mtu informations in xfrm. 8) Fix null pointer dereference in xdst_queue_output. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/ip6_gre.c5
-rw-r--r--net/ipv6/ip6_output.c3
-rw-r--r--net/ipv6/ip6_tunnel.c6
-rw-r--r--net/ipv6/raw.c1
-rw-r--r--net/ipv6/sit.c5
-rw-r--r--net/ipv6/xfrm6_output.c21
-rw-r--r--net/ipv6/xfrm6_state.c1
7 files changed, 36 insertions, 6 deletions
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index ecd60733e5e2..90747f1973fe 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -724,6 +724,11 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
724 ipv6_push_nfrag_opts(skb, &opt.ops, &proto, NULL); 724 ipv6_push_nfrag_opts(skb, &opt.ops, &proto, NULL);
725 } 725 }
726 726
727 if (likely(!skb->encapsulation)) {
728 skb_reset_inner_headers(skb);
729 skb->encapsulation = 1;
730 }
731
727 skb_push(skb, gre_hlen); 732 skb_push(skb, gre_hlen);
728 skb_reset_network_header(skb); 733 skb_reset_network_header(skb);
729 skb_set_transport_header(skb, sizeof(*ipv6h)); 734 skb_set_transport_header(skb, sizeof(*ipv6h));
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 6e3ddf806ec2..e7ceb6c871d1 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -238,6 +238,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
238 hdr->saddr = fl6->saddr; 238 hdr->saddr = fl6->saddr;
239 hdr->daddr = *first_hop; 239 hdr->daddr = *first_hop;
240 240
241 skb->protocol = htons(ETH_P_IPV6);
241 skb->priority = sk->sk_priority; 242 skb->priority = sk->sk_priority;
242 skb->mark = sk->sk_mark; 243 skb->mark = sk->sk_mark;
243 244
@@ -1057,6 +1058,7 @@ static inline int ip6_ufo_append_data(struct sock *sk,
1057 /* initialize protocol header pointer */ 1058 /* initialize protocol header pointer */
1058 skb->transport_header = skb->network_header + fragheaderlen; 1059 skb->transport_header = skb->network_header + fragheaderlen;
1059 1060
1061 skb->protocol = htons(ETH_P_IPV6);
1060 skb->ip_summed = CHECKSUM_PARTIAL; 1062 skb->ip_summed = CHECKSUM_PARTIAL;
1061 skb->csum = 0; 1063 skb->csum = 0;
1062 } 1064 }
@@ -1359,6 +1361,7 @@ alloc_new_skb:
1359 /* 1361 /*
1360 * Fill in the control structures 1362 * Fill in the control structures
1361 */ 1363 */
1364 skb->protocol = htons(ETH_P_IPV6);
1362 skb->ip_summed = CHECKSUM_NONE; 1365 skb->ip_summed = CHECKSUM_NONE;
1363 skb->csum = 0; 1366 skb->csum = 0;
1364 /* reserve for fragmentation and ipsec header */ 1367 /* reserve for fragmentation and ipsec header */
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 1e55866cead7..46ba243605a3 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -1027,6 +1027,12 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
1027 init_tel_txopt(&opt, encap_limit); 1027 init_tel_txopt(&opt, encap_limit);
1028 ipv6_push_nfrag_opts(skb, &opt.ops, &proto, NULL); 1028 ipv6_push_nfrag_opts(skb, &opt.ops, &proto, NULL);
1029 } 1029 }
1030
1031 if (likely(!skb->encapsulation)) {
1032 skb_reset_inner_headers(skb);
1033 skb->encapsulation = 1;
1034 }
1035
1030 skb_push(skb, sizeof(struct ipv6hdr)); 1036 skb_push(skb, sizeof(struct ipv6hdr));
1031 skb_reset_network_header(skb); 1037 skb_reset_network_header(skb);
1032 ipv6h = ipv6_hdr(skb); 1038 ipv6h = ipv6_hdr(skb);
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index c45f7a5c36e9..cdaed47ba932 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -628,6 +628,7 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
628 goto error; 628 goto error;
629 skb_reserve(skb, hlen); 629 skb_reserve(skb, hlen);
630 630
631 skb->protocol = htons(ETH_P_IPV6);
631 skb->priority = sk->sk_priority; 632 skb->priority = sk->sk_priority;
632 skb->mark = sk->sk_mark; 633 skb->mark = sk->sk_mark;
633 skb_dst_set(skb, &rt->dst); 634 skb_dst_set(skb, &rt->dst);
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index a3437a4cd07e..fbfc5a83867f 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -888,6 +888,11 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
888 ttl = iph6->hop_limit; 888 ttl = iph6->hop_limit;
889 tos = INET_ECN_encapsulate(tos, ipv6_get_dsfield(iph6)); 889 tos = INET_ECN_encapsulate(tos, ipv6_get_dsfield(iph6));
890 890
891 if (likely(!skb->encapsulation)) {
892 skb_reset_inner_headers(skb);
893 skb->encapsulation = 1;
894 }
895
891 err = iptunnel_xmit(dev_net(dev), rt, skb, fl4.saddr, fl4.daddr, 896 err = iptunnel_xmit(dev_net(dev), rt, skb, fl4.saddr, fl4.daddr,
892 IPPROTO_IPV6, tos, ttl, df); 897 IPPROTO_IPV6, tos, ttl, df);
893 iptunnel_xmit_stats(err, &dev->stats, dev->tstats); 898 iptunnel_xmit_stats(err, &dev->stats, dev->tstats);
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
index 8755a3079d0f..6cd625e37706 100644
--- a/net/ipv6/xfrm6_output.c
+++ b/net/ipv6/xfrm6_output.c
@@ -34,8 +34,10 @@ static int xfrm6_local_dontfrag(struct sk_buff *skb)
34 struct sock *sk = skb->sk; 34 struct sock *sk = skb->sk;
35 35
36 if (sk) { 36 if (sk) {
37 proto = sk->sk_protocol; 37 if (sk->sk_family != AF_INET6)
38 return 0;
38 39
40 proto = sk->sk_protocol;
39 if (proto == IPPROTO_UDP || proto == IPPROTO_RAW) 41 if (proto == IPPROTO_UDP || proto == IPPROTO_RAW)
40 return inet6_sk(sk)->dontfrag; 42 return inet6_sk(sk)->dontfrag;
41 } 43 }
@@ -54,13 +56,15 @@ static void xfrm6_local_rxpmtu(struct sk_buff *skb, u32 mtu)
54 ipv6_local_rxpmtu(sk, &fl6, mtu); 56 ipv6_local_rxpmtu(sk, &fl6, mtu);
55} 57}
56 58
57static void xfrm6_local_error(struct sk_buff *skb, u32 mtu) 59void xfrm6_local_error(struct sk_buff *skb, u32 mtu)
58{ 60{
59 struct flowi6 fl6; 61 struct flowi6 fl6;
62 const struct ipv6hdr *hdr;
60 struct sock *sk = skb->sk; 63 struct sock *sk = skb->sk;
61 64
65 hdr = skb->encapsulation ? inner_ipv6_hdr(skb) : ipv6_hdr(skb);
62 fl6.fl6_dport = inet_sk(sk)->inet_dport; 66 fl6.fl6_dport = inet_sk(sk)->inet_dport;
63 fl6.daddr = ipv6_hdr(skb)->daddr; 67 fl6.daddr = hdr->daddr;
64 68
65 ipv6_local_error(sk, EMSGSIZE, &fl6, mtu); 69 ipv6_local_error(sk, EMSGSIZE, &fl6, mtu);
66} 70}
@@ -80,7 +84,7 @@ static int xfrm6_tunnel_check_size(struct sk_buff *skb)
80 if (xfrm6_local_dontfrag(skb)) 84 if (xfrm6_local_dontfrag(skb))
81 xfrm6_local_rxpmtu(skb, mtu); 85 xfrm6_local_rxpmtu(skb, mtu);
82 else if (skb->sk) 86 else if (skb->sk)
83 xfrm6_local_error(skb, mtu); 87 xfrm_local_error(skb, mtu);
84 else 88 else
85 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); 89 icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
86 ret = -EMSGSIZE; 90 ret = -EMSGSIZE;
@@ -136,13 +140,18 @@ static int __xfrm6_output(struct sk_buff *skb)
136{ 140{
137 struct dst_entry *dst = skb_dst(skb); 141 struct dst_entry *dst = skb_dst(skb);
138 struct xfrm_state *x = dst->xfrm; 142 struct xfrm_state *x = dst->xfrm;
139 int mtu = ip6_skb_dst_mtu(skb); 143 int mtu;
144
145 if (skb->protocol == htons(ETH_P_IPV6))
146 mtu = ip6_skb_dst_mtu(skb);
147 else
148 mtu = dst_mtu(skb_dst(skb));
140 149
141 if (skb->len > mtu && xfrm6_local_dontfrag(skb)) { 150 if (skb->len > mtu && xfrm6_local_dontfrag(skb)) {
142 xfrm6_local_rxpmtu(skb, mtu); 151 xfrm6_local_rxpmtu(skb, mtu);
143 return -EMSGSIZE; 152 return -EMSGSIZE;
144 } else if (!skb->local_df && skb->len > mtu && skb->sk) { 153 } else if (!skb->local_df && skb->len > mtu && skb->sk) {
145 xfrm6_local_error(skb, mtu); 154 xfrm_local_error(skb, mtu);
146 return -EMSGSIZE; 155 return -EMSGSIZE;
147 } 156 }
148 157
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c
index d8c70b8efc24..3fc970135fc6 100644
--- a/net/ipv6/xfrm6_state.c
+++ b/net/ipv6/xfrm6_state.c
@@ -183,6 +183,7 @@ static struct xfrm_state_afinfo xfrm6_state_afinfo = {
183 .extract_input = xfrm6_extract_input, 183 .extract_input = xfrm6_extract_input,
184 .extract_output = xfrm6_extract_output, 184 .extract_output = xfrm6_extract_output,
185 .transport_finish = xfrm6_transport_finish, 185 .transport_finish = xfrm6_transport_finish,
186 .local_error = xfrm6_local_error,
186}; 187};
187 188
188int __init xfrm6_state_init(void) 189int __init xfrm6_state_init(void)