diff options
author | Hannes Frederic Sowa <hannes@stressinduktion.org> | 2013-08-14 07:05:23 -0400 |
---|---|---|
committer | Steffen Klassert <steffen.klassert@secunet.com> | 2013-08-14 07:07:12 -0400 |
commit | 628e341f319f1a64a4639088faba952e4ec8f0a8 (patch) | |
tree | 28fd4b1a02ca00a1abe0b1e71898ab8db6a81dad /net/ipv4 | |
parent | d9bf5f130946695063469749bfd190087b7fad39 (diff) |
xfrm: make local error reporting more robust
In xfrm4 and xfrm6 we need to take care about sockets of the other
address family. This could happen because a 6in4 or 4in6 tunnel could
get protected by ipsec.
Because we don't want to have a run-time dependency on ipv6 when only
using ipv4 xfrm we have to embed a pointer to the correct local_error
function in xfrm_state_afinet and look it up when returning an error
depending on the socket address family.
Thanks to vi0ss for the great bug report:
<https://bugzilla.kernel.org/show_bug.cgi?id=58691>
v2:
a) fix two more unsafe interpretations of skb->sk as ipv6 socket
(xfrm6_local_dontfrag and __xfrm6_output)
v3:
a) add an EXPORT_SYMBOL_GPL(xfrm_local_error) to fix a link error when
building ipv6 as a module (thanks to Steffen Klassert)
Reported-by: <vi0oss@gmail.com>
Cc: Steffen Klassert <steffen.klassert@secunet.com>
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/xfrm4_output.c | 12 | ||||
-rw-r--r-- | net/ipv4/xfrm4_state.c | 1 |
2 files changed, 11 insertions, 2 deletions
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c index 327a617d594c..7a5491ffa4de 100644 --- a/net/ipv4/xfrm4_output.c +++ b/net/ipv4/xfrm4_output.c | |||
@@ -33,8 +33,7 @@ static int xfrm4_tunnel_check_size(struct sk_buff *skb) | |||
33 | mtu = dst_mtu(dst); | 33 | mtu = dst_mtu(dst); |
34 | if (skb->len > mtu) { | 34 | if (skb->len > mtu) { |
35 | if (skb->sk) | 35 | if (skb->sk) |
36 | ip_local_error(skb->sk, EMSGSIZE, ip_hdr(skb)->daddr, | 36 | xfrm_local_error(skb, mtu); |
37 | inet_sk(skb->sk)->inet_dport, mtu); | ||
38 | else | 37 | else |
39 | icmp_send(skb, ICMP_DEST_UNREACH, | 38 | icmp_send(skb, ICMP_DEST_UNREACH, |
40 | ICMP_FRAG_NEEDED, htonl(mtu)); | 39 | ICMP_FRAG_NEEDED, htonl(mtu)); |
@@ -99,3 +98,12 @@ int xfrm4_output(struct sk_buff *skb) | |||
99 | x->outer_mode->afinfo->output_finish, | 98 | x->outer_mode->afinfo->output_finish, |
100 | !(IPCB(skb)->flags & IPSKB_REROUTED)); | 99 | !(IPCB(skb)->flags & IPSKB_REROUTED)); |
101 | } | 100 | } |
101 | |||
102 | void xfrm4_local_error(struct sk_buff *skb, u32 mtu) | ||
103 | { | ||
104 | struct iphdr *hdr; | ||
105 | |||
106 | hdr = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb); | ||
107 | ip_local_error(skb->sk, EMSGSIZE, hdr->daddr, | ||
108 | inet_sk(skb->sk)->inet_dport, mtu); | ||
109 | } | ||
diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c index 9258e751baba..0b2a0641526a 100644 --- a/net/ipv4/xfrm4_state.c +++ b/net/ipv4/xfrm4_state.c | |||
@@ -83,6 +83,7 @@ static struct xfrm_state_afinfo xfrm4_state_afinfo = { | |||
83 | .extract_input = xfrm4_extract_input, | 83 | .extract_input = xfrm4_extract_input, |
84 | .extract_output = xfrm4_extract_output, | 84 | .extract_output = xfrm4_extract_output, |
85 | .transport_finish = xfrm4_transport_finish, | 85 | .transport_finish = xfrm4_transport_finish, |
86 | .local_error = xfrm4_local_error, | ||
86 | }; | 87 | }; |
87 | 88 | ||
88 | void __init xfrm4_state_init(void) | 89 | void __init xfrm4_state_init(void) |