Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Hannes Frederic Sowa and committed by
David S. Miller
82b276cd 446fab59

+24 -2
+2
include/net/ipv6.h
··· 783 783 char __user *optval, int __user *optlen); 784 784 785 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 789 int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, 788 790 int *addr_len);
+3
net/ipv4/ping.c
··· 320 320 if (addr_len < sizeof(*addr)) 321 321 return -EINVAL; 322 322 323 + if (addr->sin6_family != AF_INET6) 324 + return -EINVAL; 325 + 323 326 pr_debug("ping_check_bind_addr(sk=%p,addr=%pI6c,port=%d)\n", 324 327 sk, addr->sin6_addr.s6_addr, ntohs(addr->sin6_port)); 325 328
+10
net/ipv6/datagram.c
··· 205 205 } 206 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 218 void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, 209 219 __be16 port, u32 info, u8 *payload) 210 220 {
+1 -1
net/ipv6/ping.c
··· 31 31 .owner = THIS_MODULE, 32 32 .init = ping_init_sock, 33 33 .close = ping_close, 34 - .connect = ip6_datagram_connect, 34 + .connect = ip6_datagram_connect_v6_only, 35 35 .disconnect = udp_disconnect, 36 36 .setsockopt = ipv6_setsockopt, 37 37 .getsockopt = ipv6_getsockopt,
+5 -1
net/ipv6/raw.c
··· 250 250 251 251 if (addr_len < SIN6_LEN_RFC2133) 252 252 return -EINVAL; 253 + 254 + if (addr->sin6_family != AF_INET6) 255 + return -EINVAL; 256 + 253 257 addr_type = ipv6_addr_type(&addr->sin6_addr); 254 258 255 259 /* Raw sockets are IPv6 only */ ··· 1213 1209 .owner = THIS_MODULE, 1214 1210 .close = rawv6_close, 1215 1211 .destroy = raw6_destroy, 1216 - .connect = ip6_datagram_connect, 1212 + .connect = ip6_datagram_connect_v6_only, 1217 1213 .disconnect = udp_disconnect, 1218 1214 .ioctl = rawv6_ioctl, 1219 1215 .init = rawv6_init_sk,
+3
net/l2tp/l2tp_ip6.c
··· 371 371 if (addr_len < sizeof(*lsa)) 372 372 return -EINVAL; 373 373 374 + if (usin->sin6_family != AF_INET6) 375 + return -EINVAL; 376 + 374 377 addr_type = ipv6_addr_type(&usin->sin6_addr); 375 378 if (addr_type & IPV6_ADDR_MULTICAST) 376 379 return -EINVAL;