]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/netinet6/in6_pcb.c
xnu-4903.221.2.tar.gz
[apple/xnu.git] / bsd / netinet6 / in6_pcb.c
index 29cbedd508336d8055245d47959790aba1107faf..db72c5c35c402b26f016de7469c3ca00772948ab 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2003-2017 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
@@ -198,13 +198,17 @@ in6_pcbbind(struct inpcb *inp, struct sockaddr *nam, struct proc *p)
 
        if (!in6_ifaddrs) /* XXX broken! */
                return (EADDRNOTAVAIL);
-       if (inp->inp_lport || !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
-               return (EINVAL);
        if (!(so->so_options & (SO_REUSEADDR|SO_REUSEPORT)))
                wild = 1;
 
        socket_unlock(so, 0); /* keep reference */
        lck_rw_lock_exclusive(pcbinfo->ipi_lock);
+       if (inp->inp_lport || !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) {
+               /* another thread completed the bind */
+               lck_rw_done(pcbinfo->ipi_lock);
+               socket_lock(so, 0);
+               return (EINVAL);
+       }
 
        bzero(&sin6, sizeof (sin6));
        if (nam != NULL) {
@@ -266,8 +270,8 @@ in6_pcbbind(struct inpcb *inp, struct sockaddr *nam, struct proc *p)
                                 */
                                IFA_LOCK_SPIN(ifa);
                                if (((struct in6_ifaddr *)ifa)->ia6_flags &
-                                   (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
-                                   IN6_IFF_DETACHED)) {
+                                   (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY|
+                                   IN6_IFF_DETACHED | IN6_IFF_CLAT46)) {
                                        IFA_UNLOCK(ifa);
                                        IFA_REMREF(ifa);
                                        lck_rw_done(pcbinfo->ipi_lock);
@@ -291,9 +295,9 @@ in6_pcbbind(struct inpcb *inp, struct sockaddr *nam, struct proc *p)
                        struct inpcb *t;
                        uid_t u;
 
-                       /* GROSS */
 #if !CONFIG_EMBEDDED
-                       if (ntohs(lport) < IPV6PORT_RESERVED) {
+                       if (ntohs(lport) < IPV6PORT_RESERVED &&
+                               !IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr)) {
                                cred = kauth_cred_proc_ref(p);
                                error = priv_check_cred(cred,
                                    PRIV_NETINET_RESERVEDPORT, 0);
@@ -529,6 +533,11 @@ in6_pcbconnect(struct inpcb *inp, struct sockaddr *nam, struct proc *p)
        struct ifnet *outif = NULL;
        struct socket *so = inp->inp_socket;
 
+#if CONTENT_FILTER
+       if (so)
+               so->so_state_change_cnt++;
+#endif
+
        if (so->so_proto->pr_protocol == IPPROTO_UDP &&
            sin6->sin6_port == htons(53) && !(so->so_flags1 & SOF1_DNS_COUNTED)) {
                so->so_flags1 |= SOF1_DNS_COUNTED;
@@ -594,6 +603,11 @@ in6_pcbdisconnect(struct inpcb *inp)
 {
        struct socket *so = inp->inp_socket;
 
+#if CONTENT_FILTER
+       if (so)
+               so->so_state_change_cnt++;
+#endif
+
        if (!lck_rw_try_lock_exclusive(inp->inp_pcbinfo->ipi_lock)) {
                /* lock inversion issue, mostly with udp multicast packets */
                socket_unlock(so, 0);