Commit 628e341f319f1a64a4639088faba952e4ec8f0a8
Committed by
Steffen Klassert
1 parent
d9bf5f1309
Exists in
smarc-imx_3.14.28_1.0.0_ga
and in
1 other branch
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>
Showing 7 changed files with 39 additions and 11 deletions Side-by-side Diff
include/net/xfrm.h
... | ... | @@ -341,10 +341,13 @@ |
341 | 341 | struct sk_buff *skb); |
342 | 342 | int (*transport_finish)(struct sk_buff *skb, |
343 | 343 | int async); |
344 | + void (*local_error)(struct sk_buff *skb, u32 mtu); | |
344 | 345 | }; |
345 | 346 | |
346 | 347 | extern int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo); |
347 | 348 | extern int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo); |
349 | +extern struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family); | |
350 | +extern void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); | |
348 | 351 | |
349 | 352 | extern void xfrm_state_delete_tunnel(struct xfrm_state *x); |
350 | 353 | |
... | ... | @@ -1477,6 +1480,7 @@ |
1477 | 1480 | extern int xfrm_output_resume(struct sk_buff *skb, int err); |
1478 | 1481 | extern int xfrm_output(struct sk_buff *skb); |
1479 | 1482 | extern int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb); |
1483 | +extern void xfrm_local_error(struct sk_buff *skb, int mtu); | |
1480 | 1484 | extern int xfrm4_extract_header(struct sk_buff *skb); |
1481 | 1485 | extern int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb); |
1482 | 1486 | extern int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi, |
... | ... | @@ -1497,6 +1501,7 @@ |
1497 | 1501 | extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family); |
1498 | 1502 | extern int xfrm4_mode_tunnel_input_register(struct xfrm_tunnel *handler); |
1499 | 1503 | extern int xfrm4_mode_tunnel_input_deregister(struct xfrm_tunnel *handler); |
1504 | +extern void xfrm4_local_error(struct sk_buff *skb, u32 mtu); | |
1500 | 1505 | extern int xfrm6_extract_header(struct sk_buff *skb); |
1501 | 1506 | extern int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb); |
1502 | 1507 | extern int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi); |
... | ... | @@ -1514,6 +1519,7 @@ |
1514 | 1519 | extern int xfrm6_output_finish(struct sk_buff *skb); |
1515 | 1520 | extern int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb, |
1516 | 1521 | u8 **prevhdr); |
1522 | +extern void xfrm6_local_error(struct sk_buff *skb, u32 mtu); | |
1517 | 1523 | |
1518 | 1524 | #ifdef CONFIG_XFRM |
1519 | 1525 | extern int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb); |
net/ipv4/xfrm4_output.c
... | ... | @@ -33,8 +33,7 @@ |
33 | 33 | mtu = dst_mtu(dst); |
34 | 34 | if (skb->len > mtu) { |
35 | 35 | if (skb->sk) |
36 | - ip_local_error(skb->sk, EMSGSIZE, ip_hdr(skb)->daddr, | |
37 | - inet_sk(skb->sk)->inet_dport, mtu); | |
36 | + xfrm_local_error(skb, mtu); | |
38 | 37 | else |
39 | 38 | icmp_send(skb, ICMP_DEST_UNREACH, |
40 | 39 | ICMP_FRAG_NEEDED, htonl(mtu)); |
... | ... | @@ -98,5 +97,14 @@ |
98 | 97 | NULL, dst->dev, |
99 | 98 | x->outer_mode->afinfo->output_finish, |
100 | 99 | !(IPCB(skb)->flags & IPSKB_REROUTED)); |
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); | |
101 | 109 | } |
net/ipv4/xfrm4_state.c
net/ipv6/xfrm6_output.c
... | ... | @@ -34,8 +34,10 @@ |
34 | 34 | struct sock *sk = skb->sk; |
35 | 35 | |
36 | 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 | 41 | if (proto == IPPROTO_UDP || proto == IPPROTO_RAW) |
40 | 42 | return inet6_sk(sk)->dontfrag; |
41 | 43 | } |
... | ... | @@ -54,7 +56,7 @@ |
54 | 56 | ipv6_local_rxpmtu(sk, &fl6, mtu); |
55 | 57 | } |
56 | 58 | |
57 | -static void xfrm6_local_error(struct sk_buff *skb, u32 mtu) | |
59 | +void xfrm6_local_error(struct sk_buff *skb, u32 mtu) | |
58 | 60 | { |
59 | 61 | struct flowi6 fl6; |
60 | 62 | struct sock *sk = skb->sk; |
... | ... | @@ -80,7 +82,7 @@ |
80 | 82 | if (xfrm6_local_dontfrag(skb)) |
81 | 83 | xfrm6_local_rxpmtu(skb, mtu); |
82 | 84 | else if (skb->sk) |
83 | - xfrm6_local_error(skb, mtu); | |
85 | + xfrm_local_error(skb, mtu); | |
84 | 86 | else |
85 | 87 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); |
86 | 88 | ret = -EMSGSIZE; |
... | ... | @@ -142,7 +144,7 @@ |
142 | 144 | xfrm6_local_rxpmtu(skb, mtu); |
143 | 145 | return -EMSGSIZE; |
144 | 146 | } else if (!skb->local_df && skb->len > mtu && skb->sk) { |
145 | - xfrm6_local_error(skb, mtu); | |
147 | + xfrm_local_error(skb, mtu); | |
146 | 148 | return -EMSGSIZE; |
147 | 149 | } |
148 | 150 |
net/ipv6/xfrm6_state.c
net/xfrm/xfrm_output.c
... | ... | @@ -214,6 +214,19 @@ |
214 | 214 | return inner_mode->afinfo->extract_output(x, skb); |
215 | 215 | } |
216 | 216 | |
217 | +void xfrm_local_error(struct sk_buff *skb, int mtu) | |
218 | +{ | |
219 | + struct xfrm_state_afinfo *afinfo; | |
220 | + | |
221 | + afinfo = xfrm_state_get_afinfo(skb->sk->sk_family); | |
222 | + if (!afinfo) | |
223 | + return; | |
224 | + | |
225 | + afinfo->local_error(skb, mtu); | |
226 | + xfrm_state_put_afinfo(afinfo); | |
227 | +} | |
228 | + | |
217 | 229 | EXPORT_SYMBOL_GPL(xfrm_output); |
218 | 230 | EXPORT_SYMBOL_GPL(xfrm_inner_extract_output); |
231 | +EXPORT_SYMBOL_GPL(xfrm_local_error); |
net/xfrm/xfrm_state.c
... | ... | @@ -39,9 +39,6 @@ |
39 | 39 | |
40 | 40 | static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024; |
41 | 41 | |
42 | -static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family); | |
43 | -static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); | |
44 | - | |
45 | 42 | static inline unsigned int xfrm_dst_hash(struct net *net, |
46 | 43 | const xfrm_address_t *daddr, |
47 | 44 | const xfrm_address_t *saddr, |
... | ... | @@ -1860,7 +1857,7 @@ |
1860 | 1857 | } |
1861 | 1858 | EXPORT_SYMBOL(xfrm_state_unregister_afinfo); |
1862 | 1859 | |
1863 | -static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family) | |
1860 | +struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family) | |
1864 | 1861 | { |
1865 | 1862 | struct xfrm_state_afinfo *afinfo; |
1866 | 1863 | if (unlikely(family >= NPROTO)) |
... | ... | @@ -1872,7 +1869,7 @@ |
1872 | 1869 | return afinfo; |
1873 | 1870 | } |
1874 | 1871 | |
1875 | -static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo) | |
1872 | +void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo) | |
1876 | 1873 | { |
1877 | 1874 | rcu_read_unlock(); |
1878 | 1875 | } |