diff options
| author | Hannes Frederic Sowa <hannes@stressinduktion.org> | 2014-01-19 23:16:39 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2014-01-21 19:59:19 -0500 |
| commit | 82b276cd2b0bacd58e7c307bf8856925a68c4d14 (patch) | |
| tree | ffc8648efa91f83f81c94ac83447dc5246a835cf | |
| parent | 446fab59333dea91e54688f033dd8d788d0486fb (diff) | |
ipv6: protect protocols not handling ipv4 from v4 connection/bind attempts
Some ipv6 protocols cannot handle ipv4 addresses, so we must not allow
connecting and binding to them. sendmsg logic does already check msg->name
for this but must trust already connected sockets which could be set up
for connection to ipv4 address family.
Per-socket flag ipv6only is of no use here, as it is under users control
by setsockopt.
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | include/net/ipv6.h | 2 | ||||
| -rw-r--r-- | net/ipv4/ping.c | 3 | ||||
| -rw-r--r-- | net/ipv6/datagram.c | 10 | ||||
| -rw-r--r-- | net/ipv6/ping.c | 2 | ||||
| -rw-r--r-- | net/ipv6/raw.c | 6 | ||||
| -rw-r--r-- | net/l2tp/l2tp_ip6.c | 3 |
6 files changed, 24 insertions, 2 deletions
diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 78d3d5124918..4f541f11ce63 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h | |||
| @@ -783,6 +783,8 @@ int compat_ipv6_getsockopt(struct sock *sk, int level, int optname, | |||
| 783 | char __user *optval, int __user *optlen); | 783 | char __user *optval, int __user *optlen); |
| 784 | 784 | ||
| 785 | int ip6_datagram_connect(struct sock *sk, struct sockaddr *addr, int addr_len); | 785 | int ip6_datagram_connect(struct sock *sk, struct sockaddr *addr, int addr_len); |
| 786 | int ip6_datagram_connect_v6_only(struct sock *sk, struct sockaddr *addr, | ||
| 787 | int addr_len); | ||
| 786 | 788 | ||
| 787 | int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, | 789 | int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, |
| 788 | int *addr_len); | 790 | int *addr_len); |
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 4a9e4266a0c3..2d11c094296e 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c | |||
| @@ -320,6 +320,9 @@ static int ping_check_bind_addr(struct sock *sk, struct inet_sock *isk, | |||
| 320 | if (addr_len < sizeof(*addr)) | 320 | if (addr_len < sizeof(*addr)) |
| 321 | return -EINVAL; | 321 | return -EINVAL; |
| 322 | 322 | ||
| 323 | if (addr->sin6_family != AF_INET6) | ||
| 324 | return -EINVAL; | ||
| 325 | |||
| 323 | pr_debug("ping_check_bind_addr(sk=%p,addr=%pI6c,port=%d)\n", | 326 | pr_debug("ping_check_bind_addr(sk=%p,addr=%pI6c,port=%d)\n", |
| 324 | sk, addr->sin6_addr.s6_addr, ntohs(addr->sin6_port)); | 327 | sk, addr->sin6_addr.s6_addr, ntohs(addr->sin6_port)); |
| 325 | 328 | ||
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index cd8699bd2e6b..2f5e2f154d21 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c | |||
| @@ -205,6 +205,16 @@ out: | |||
| 205 | } | 205 | } |
| 206 | EXPORT_SYMBOL_GPL(ip6_datagram_connect); | 206 | EXPORT_SYMBOL_GPL(ip6_datagram_connect); |
| 207 | 207 | ||
| 208 | int ip6_datagram_connect_v6_only(struct sock *sk, struct sockaddr *uaddr, | ||
| 209 | int addr_len) | ||
| 210 | { | ||
| 211 | DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, uaddr); | ||
| 212 | if (sin6->sin6_family != AF_INET6) | ||
| 213 | return -EAFNOSUPPORT; | ||
| 214 | return ip6_datagram_connect(sk, uaddr, addr_len); | ||
| 215 | } | ||
| 216 | EXPORT_SYMBOL_GPL(ip6_datagram_connect_v6_only); | ||
| 217 | |||
| 208 | void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, | 218 | void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, |
| 209 | __be16 port, u32 info, u8 *payload) | 219 | __be16 port, u32 info, u8 *payload) |
| 210 | { | 220 | { |
diff --git a/net/ipv6/ping.c b/net/ipv6/ping.c index 94a3d04c3200..fb9beb78f00b 100644 --- a/net/ipv6/ping.c +++ b/net/ipv6/ping.c | |||
| @@ -31,7 +31,7 @@ struct proto pingv6_prot = { | |||
| 31 | .owner = THIS_MODULE, | 31 | .owner = THIS_MODULE, |
| 32 | .init = ping_init_sock, | 32 | .init = ping_init_sock, |
| 33 | .close = ping_close, | 33 | .close = ping_close, |
| 34 | .connect = ip6_datagram_connect, | 34 | .connect = ip6_datagram_connect_v6_only, |
| 35 | .disconnect = udp_disconnect, | 35 | .disconnect = udp_disconnect, |
| 36 | .setsockopt = ipv6_setsockopt, | 36 | .setsockopt = ipv6_setsockopt, |
| 37 | .getsockopt = ipv6_getsockopt, | 37 | .getsockopt = ipv6_getsockopt, |
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index b4523117aeae..1f29996e368a 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
| @@ -250,6 +250,10 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) | |||
| 250 | 250 | ||
| 251 | if (addr_len < SIN6_LEN_RFC2133) | 251 | if (addr_len < SIN6_LEN_RFC2133) |
| 252 | return -EINVAL; | 252 | return -EINVAL; |
| 253 | |||
| 254 | if (addr->sin6_family != AF_INET6) | ||
| 255 | return -EINVAL; | ||
| 256 | |||
| 253 | addr_type = ipv6_addr_type(&addr->sin6_addr); | 257 | addr_type = ipv6_addr_type(&addr->sin6_addr); |
| 254 | 258 | ||
| 255 | /* Raw sockets are IPv6 only */ | 259 | /* Raw sockets are IPv6 only */ |
| @@ -1209,7 +1213,7 @@ struct proto rawv6_prot = { | |||
| 1209 | .owner = THIS_MODULE, | 1213 | .owner = THIS_MODULE, |
| 1210 | .close = rawv6_close, | 1214 | .close = rawv6_close, |
| 1211 | .destroy = raw6_destroy, | 1215 | .destroy = raw6_destroy, |
| 1212 | .connect = ip6_datagram_connect, | 1216 | .connect = ip6_datagram_connect_v6_only, |
| 1213 | .disconnect = udp_disconnect, | 1217 | .disconnect = udp_disconnect, |
| 1214 | .ioctl = rawv6_ioctl, | 1218 | .ioctl = rawv6_ioctl, |
| 1215 | .init = rawv6_init_sk, | 1219 | .init = rawv6_init_sk, |
diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c index aab5f74e91e6..7704ea9502fd 100644 --- a/net/l2tp/l2tp_ip6.c +++ b/net/l2tp/l2tp_ip6.c | |||
| @@ -371,6 +371,9 @@ static int l2tp_ip6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
| 371 | if (addr_len < sizeof(*lsa)) | 371 | if (addr_len < sizeof(*lsa)) |
| 372 | return -EINVAL; | 372 | return -EINVAL; |
| 373 | 373 | ||
| 374 | if (usin->sin6_family != AF_INET6) | ||
| 375 | return -EINVAL; | ||
| 376 | |||
| 374 | addr_type = ipv6_addr_type(&usin->sin6_addr); | 377 | addr_type = ipv6_addr_type(&usin->sin6_addr); |
| 375 | if (addr_type & IPV6_ADDR_MULTICAST) | 378 | if (addr_type & IPV6_ADDR_MULTICAST) |
| 376 | return -EINVAL; | 379 | return -EINVAL; |
