diff options
author | Dan McDonald <danmcd@omniti.com> | 2014-02-14 11:27:16 -0500 |
---|---|---|
committer | Dan McDonald <danmcd@omniti.com> | 2014-03-05 10:54:10 -0500 |
commit | a1ca8b43681e3163e9f085ab65b8b6de1848d8ac (patch) | |
tree | 116b6fc2cff4ac6b6e952a344371b80a11b5af39 /usr/src | |
parent | 7298ed33f6dda314aee9fee22d0dccfb09cc0ef6 (diff) | |
download | illumos-joyent-a1ca8b43681e3163e9f085ab65b8b6de1848d8ac.tar.gz |
4596 Callers of ip_srcid_find_id() need to be more careful
Reviewed by: Garrett D'Amore <garrett@damore.org>
Reviewed by: Sebastien Roy <sebastien.roy@delphix.com>
Approved by: Robert Mustacchi <rm@joyent.com>
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/uts/common/inet/ip.h | 4 | ||||
-rw-r--r-- | usr/src/uts/common/inet/ip/icmp.c | 52 | ||||
-rw-r--r-- | usr/src/uts/common/inet/ip/ip_srcid.c | 29 | ||||
-rw-r--r-- | usr/src/uts/common/inet/tcp/tcp.c | 15 | ||||
-rw-r--r-- | usr/src/uts/common/inet/udp/udp.c | 53 |
5 files changed, 111 insertions, 42 deletions
diff --git a/usr/src/uts/common/inet/ip.h b/usr/src/uts/common/inet/ip.h index fcf70368c8..fde3dc3ad3 100644 --- a/usr/src/uts/common/inet/ip.h +++ b/usr/src/uts/common/inet/ip.h @@ -24,6 +24,7 @@ * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, Joyent, Inc. All rights reserved. * Copyright 2014 Nexenta Systems, Inc. All rights reserved. + * Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved. */ #ifndef _INET_IP_H @@ -3453,7 +3454,8 @@ extern void ire_untrace_ref(ire_t *); extern int ip_srcid_insert(const in6_addr_t *, zoneid_t, ip_stack_t *); extern int ip_srcid_remove(const in6_addr_t *, zoneid_t, ip_stack_t *); -extern void ip_srcid_find_id(uint_t, in6_addr_t *, zoneid_t, netstack_t *); +extern boolean_t ip_srcid_find_id(uint_t, in6_addr_t *, zoneid_t, boolean_t, + netstack_t *); extern uint_t ip_srcid_find_addr(const in6_addr_t *, zoneid_t, netstack_t *); extern uint8_t ipoptp_next(ipoptp_t *); diff --git a/usr/src/uts/common/inet/ip/icmp.c b/usr/src/uts/common/inet/ip/icmp.c index 9f6bc8b22f..8da126f7dc 100644 --- a/usr/src/uts/common/inet/ip/icmp.c +++ b/usr/src/uts/common/inet/ip/icmp.c @@ -21,6 +21,7 @@ /* * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013 by Delphix. All rights reserved. + * Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved. */ /* Copyright (c) 1990 Mentat Inc. */ @@ -768,8 +769,12 @@ rawip_do_connect(conn_t *connp, const struct sockaddr *sa, socklen_t len, scopeid = sin6->sin6_scope_id; srcid = sin6->__sin6_src_id; if (srcid != 0 && IN6_IS_ADDR_UNSPECIFIED(&v6src)) { - ip_srcid_find_id(srcid, &v6src, IPCL_ZONEID(connp), - connp->conn_netstack); + /* Due to check above, we know sin6_addr is v6-only. */ + if (!ip_srcid_find_id(srcid, &v6src, IPCL_ZONEID(connp), + B_FALSE, connp->conn_netstack)) { + /* Mismatch - v6src would be v4mapped. */ + return (EADDRNOTAVAIL); + } } break; } @@ -3337,7 +3342,6 @@ icmp_output_ancillary(conn_t *connp, sin_t *sin, sin6_t *sin6, mblk_t *mp, in6_addr_t v6nexthop; in_port_t dstport; uint32_t flowinfo; - uint_t srcid; int is_absreq_failure = 0; conn_opt_arg_t coas, *coa; @@ -3440,6 +3444,9 @@ icmp_output_ancillary(conn_t *connp, sin_t *sin, sin6_t *sin6, mblk_t *mp, ixa->ixa_flags &= ~IXAF_SCOPEID_SET; ixa->ixa_flags |= IXAF_IS_IPV4; } else if (sin6 != NULL) { + boolean_t v4mapped; + uint_t srcid; + v6dst = sin6->sin6_addr; dstport = sin6->sin6_port; flowinfo = sin6->sin6_flowinfo; @@ -3450,14 +3457,20 @@ icmp_output_ancillary(conn_t *connp, sin_t *sin, sin6_t *sin6, mblk_t *mp, } else { ixa->ixa_flags &= ~IXAF_SCOPEID_SET; } - if (srcid != 0 && IN6_IS_ADDR_UNSPECIFIED(&v6src)) { - ip_srcid_find_id(srcid, &v6src, IPCL_ZONEID(connp), - connp->conn_netstack); - } - if (IN6_IS_ADDR_V4MAPPED(&v6dst)) + v4mapped = IN6_IS_ADDR_V4MAPPED(&v6dst); + if (v4mapped) ixa->ixa_flags |= IXAF_IS_IPV4; else ixa->ixa_flags &= ~IXAF_IS_IPV4; + if (srcid != 0 && IN6_IS_ADDR_UNSPECIFIED(&v6src)) { + if (ip_srcid_find_id(srcid, &v6src, IPCL_ZONEID(connp), + v4mapped, connp->conn_netstack)) { + /* Mismatched v4mapped/v6 specified by srcid. */ + mutex_exit(&connp->conn_lock); + error = EADDRNOTAVAIL; + goto failed; /* Does freemsg() and mib. */ + } + } } else { /* Connected case */ v6dst = connp->conn_faddr_v6; @@ -4419,14 +4432,13 @@ icmp_output_newdst(conn_t *connp, mblk_t *data_mp, sin_t *sin, sin6_t *sin6, IN6_IPADDR_TO_V4MAPPED(sin->sin_addr.s_addr, &v6dst); dstport = sin->sin_port; flowinfo = 0; + /* Don't bother with ip_srcid_find_id(), but indicate anyway. */ srcid = 0; ixa->ixa_flags &= ~IXAF_SCOPEID_SET; - if (srcid != 0 && V4_PART_OF_V6(&v6src) == INADDR_ANY) { - ip_srcid_find_id(srcid, &v6src, IPCL_ZONEID(connp), - connp->conn_netstack); - } ixa->ixa_flags |= IXAF_IS_IPV4; } else { + boolean_t v4mapped; + v6dst = sin6->sin6_addr; dstport = sin6->sin6_port; flowinfo = sin6->sin6_flowinfo; @@ -4437,14 +4449,20 @@ icmp_output_newdst(conn_t *connp, mblk_t *data_mp, sin_t *sin, sin6_t *sin6, } else { ixa->ixa_flags &= ~IXAF_SCOPEID_SET; } - if (srcid != 0 && IN6_IS_ADDR_UNSPECIFIED(&v6src)) { - ip_srcid_find_id(srcid, &v6src, IPCL_ZONEID(connp), - connp->conn_netstack); - } - if (IN6_IS_ADDR_V4MAPPED(&v6dst)) + v4mapped = IN6_IS_ADDR_V4MAPPED(&v6dst); + if (v4mapped) ixa->ixa_flags |= IXAF_IS_IPV4; else ixa->ixa_flags &= ~IXAF_IS_IPV4; + if (srcid != 0 && IN6_IS_ADDR_UNSPECIFIED(&v6src)) { + if (ip_srcid_find_id(srcid, &v6src, IPCL_ZONEID(connp), + v4mapped, connp->conn_netstack)) { + /* Mismatched v4mapped/v6 specified by srcid. */ + mutex_exit(&connp->conn_lock); + error = EADDRNOTAVAIL; + goto ud_error; + } + } } /* Handle IP_PKTINFO/IPV6_PKTINFO setting source address. */ if (connp->conn_xmit_ipp.ipp_fields & IPPF_ADDR) { diff --git a/usr/src/uts/common/inet/ip/ip_srcid.c b/usr/src/uts/common/inet/ip/ip_srcid.c index f6507d6413..efb49f20e0 100644 --- a/usr/src/uts/common/inet/ip/ip_srcid.c +++ b/usr/src/uts/common/inet/ip/ip_srcid.c @@ -21,6 +21,8 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved. */ /* @@ -223,14 +225,22 @@ ip_srcid_find_addr(const in6_addr_t *addr, zoneid_t zoneid, /* * Map from a source id to an address. * If the id is unknown return the unspecified address. + * + * For known IDs, check if the returned address is v4mapped or not, and + * return B_TRUE if it matches the desired v4mapped state or not. This + * prevents a broken app from requesting (via __sin6_src_id) a v4mapped + * address for a v6 destination, or vice versa. + * + * "addr" will not be set if we return B_FALSE. */ -void +boolean_t ip_srcid_find_id(uint_t id, in6_addr_t *addr, zoneid_t zoneid, - netstack_t *ns) + boolean_t v4mapped, netstack_t *ns) { srcid_map_t **smpp; srcid_map_t *smp; ip_stack_t *ipst = ns->netstack_ip; + boolean_t rc; rw_enter(&ipst->ips_srcid_lock, RW_READER); smpp = srcid_lookup_id(id, ipst); @@ -239,11 +249,24 @@ ip_srcid_find_id(uint_t id, in6_addr_t *addr, zoneid_t zoneid, /* Not preset */ ip1dbg(("ip_srcid_find_id: unknown %u or in wrong zone\n", id)); *addr = ipv6_all_zeros; + rc = B_TRUE; } else { ASSERT(smp->sm_refcnt != 0); - *addr = smp->sm_addr; + /* + * The caller tells us if it expects a v4mapped address. + * Use it, along with the property of "addr" to set the rc. + */ + if (IN6_IS_ADDR_V4MAPPED(addr)) + rc = v4mapped; /* We want a v4mapped address. */ + else + rc = !v4mapped; /* We don't want a v4mapped address. */ + + if (rc) + *addr = smp->sm_addr; + } rw_exit(&ipst->ips_srcid_lock); + return (rc); } /* Assign the next available ID */ diff --git a/usr/src/uts/common/inet/tcp/tcp.c b/usr/src/uts/common/inet/tcp/tcp.c index 5ba1c603c0..7d48fd1c49 100644 --- a/usr/src/uts/common/inet/tcp/tcp.c +++ b/usr/src/uts/common/inet/tcp/tcp.c @@ -24,6 +24,7 @@ * Copyright (c) 2011, Joyent Inc. All rights reserved. * Copyright (c) 2011 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2013 by Delphix. All rights reserved. + * Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved. */ /* Copyright (c) 1990 Mentat Inc. */ @@ -1583,8 +1584,11 @@ tcp_connect_ipv4(tcp_t *tcp, ipaddr_t *dstaddrp, in_port_t dstport, /* Handle __sin6_src_id if socket not bound to an IP address */ if (srcid != 0 && connp->conn_laddr_v4 == INADDR_ANY) { - ip_srcid_find_id(srcid, &connp->conn_laddr_v6, - IPCL_ZONEID(connp), tcps->tcps_netstack); + if (!ip_srcid_find_id(srcid, &connp->conn_laddr_v6, + IPCL_ZONEID(connp), B_TRUE, tcps->tcps_netstack)) { + /* Mismatch - conn_laddr_v6 would be v6 address. */ + return (EADDRNOTAVAIL); + } connp->conn_saddr_v6 = connp->conn_laddr_v6; } @@ -1665,8 +1669,11 @@ tcp_connect_ipv6(tcp_t *tcp, in6_addr_t *dstaddrp, in_port_t dstport, /* Handle __sin6_src_id if socket not bound to an IP address */ if (srcid != 0 && IN6_IS_ADDR_UNSPECIFIED(&connp->conn_laddr_v6)) { - ip_srcid_find_id(srcid, &connp->conn_laddr_v6, - IPCL_ZONEID(connp), tcps->tcps_netstack); + if (!ip_srcid_find_id(srcid, &connp->conn_laddr_v6, + IPCL_ZONEID(connp), B_FALSE, tcps->tcps_netstack)) { + /* Mismatch - conn_laddr_v6 would be v4-mapped. */ + return (EADDRNOTAVAIL); + } connp->conn_saddr_v6 = connp->conn_laddr_v6; } diff --git a/usr/src/uts/common/inet/udp/udp.c b/usr/src/uts/common/inet/udp/udp.c index e6dfd3efe9..4a6e835b67 100644 --- a/usr/src/uts/common/inet/udp/udp.c +++ b/usr/src/uts/common/inet/udp/udp.c @@ -21,6 +21,7 @@ /* * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2013 Nexenta Systems, Inc. All rights reserved. + * Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved. */ /* Copyright (c) 1990 Mentat Inc. */ @@ -2714,6 +2715,8 @@ udp_output_ancillary(conn_t *connp, sin_t *sin, sin6_t *sin6, mblk_t *mp, ixa->ixa_flags &= ~IXAF_SCOPEID_SET; ixa->ixa_flags |= IXAF_IS_IPV4; } else if (sin6 != NULL) { + boolean_t v4mapped; + v6dst = sin6->sin6_addr; dstport = sin6->sin6_port; flowinfo = sin6->sin6_flowinfo; @@ -2724,14 +2727,20 @@ udp_output_ancillary(conn_t *connp, sin_t *sin, sin6_t *sin6, mblk_t *mp, } else { ixa->ixa_flags &= ~IXAF_SCOPEID_SET; } - if (srcid != 0 && IN6_IS_ADDR_UNSPECIFIED(&v6src)) { - ip_srcid_find_id(srcid, &v6src, IPCL_ZONEID(connp), - connp->conn_netstack); - } - if (IN6_IS_ADDR_V4MAPPED(&v6dst)) + v4mapped = IN6_IS_ADDR_V4MAPPED(&v6dst); + if (v4mapped) ixa->ixa_flags |= IXAF_IS_IPV4; else ixa->ixa_flags &= ~IXAF_IS_IPV4; + if (srcid != 0 && IN6_IS_ADDR_UNSPECIFIED(&v6src)) { + if (ip_srcid_find_id(srcid, &v6src, IPCL_ZONEID(connp), + v4mapped, connp->conn_netstack)) { + /* Mismatch - v4mapped/v6 specified by srcid. */ + mutex_exit(&connp->conn_lock); + error = EADDRNOTAVAIL; + goto failed; /* Does freemsg() and mib. */ + } + } } else { /* Connected case */ v6dst = connp->conn_faddr_v6; @@ -3722,14 +3731,13 @@ udp_output_newdst(conn_t *connp, mblk_t *data_mp, sin_t *sin, sin6_t *sin6, IN6_IPADDR_TO_V4MAPPED(sin->sin_addr.s_addr, &v6dst); dstport = sin->sin_port; flowinfo = 0; + /* Don't bother with ip_srcid_find_id(), but indicate anyway. */ srcid = 0; ixa->ixa_flags &= ~IXAF_SCOPEID_SET; - if (srcid != 0 && V4_PART_OF_V6(&v6src) == INADDR_ANY) { - ip_srcid_find_id(srcid, &v6src, IPCL_ZONEID(connp), - connp->conn_netstack); - } ixa->ixa_flags |= IXAF_IS_IPV4; } else { + boolean_t v4mapped; + v6dst = sin6->sin6_addr; dstport = sin6->sin6_port; flowinfo = sin6->sin6_flowinfo; @@ -3740,14 +3748,20 @@ udp_output_newdst(conn_t *connp, mblk_t *data_mp, sin_t *sin, sin6_t *sin6, } else { ixa->ixa_flags &= ~IXAF_SCOPEID_SET; } - if (srcid != 0 && IN6_IS_ADDR_UNSPECIFIED(&v6src)) { - ip_srcid_find_id(srcid, &v6src, IPCL_ZONEID(connp), - connp->conn_netstack); - } - if (IN6_IS_ADDR_V4MAPPED(&v6dst)) + v4mapped = IN6_IS_ADDR_V4MAPPED(&v6dst); + if (v4mapped) ixa->ixa_flags |= IXAF_IS_IPV4; else ixa->ixa_flags &= ~IXAF_IS_IPV4; + if (srcid != 0 && IN6_IS_ADDR_UNSPECIFIED(&v6src)) { + if (ip_srcid_find_id(srcid, &v6src, IPCL_ZONEID(connp), + v4mapped, connp->conn_netstack)) { + /* Mismatched v4mapped/v6 specified by srcid. */ + mutex_exit(&connp->conn_lock); + error = EADDRNOTAVAIL; + goto ud_error; + } + } } /* Handle IP_PKTINFO/IPV6_PKTINFO setting source address. */ if (connp->conn_xmit_ipp.ipp_fields & IPPF_ADDR) { @@ -5526,6 +5540,7 @@ udp_do_connect(conn_t *connp, const struct sockaddr *sa, socklen_t len, uint_t scopeid = 0; uint_t srcid = 0; in6_addr_t v6src = connp->conn_saddr_v6; + boolean_t v4mapped; udp = connp->conn_udp; us = udp->udp_us; @@ -5554,11 +5569,15 @@ udp_do_connect(conn_t *connp, const struct sockaddr *sa, socklen_t len, v6dst = sin6->sin6_addr; dstport = sin6->sin6_port; srcid = sin6->__sin6_src_id; + v4mapped = IN6_IS_ADDR_V4MAPPED(&v6dst); if (srcid != 0 && IN6_IS_ADDR_UNSPECIFIED(&v6src)) { - ip_srcid_find_id(srcid, &v6src, IPCL_ZONEID(connp), - connp->conn_netstack); + if (ip_srcid_find_id(srcid, &v6src, IPCL_ZONEID(connp), + v4mapped, connp->conn_netstack)) { + /* Mismatch v4mapped/v6 specified by srcid. */ + return (EADDRNOTAVAIL); + } } - if (IN6_IS_ADDR_V4MAPPED(&v6dst)) { + if (v4mapped) { if (connp->conn_ipv6_v6only) return (EADDRNOTAVAIL); |