X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/55e303ae13a4cf49d70f2294092726f2fffb9ef2..89b3af67bb32e691275bf6fa803d1834b2284115:/bsd/netinet6/udp6_usrreq.c?ds=sidebyside diff --git a/bsd/netinet6/udp6_usrreq.c b/bsd/netinet6/udp6_usrreq.c index 9bab08c72..3be50feec 100644 --- a/bsd/netinet6/udp6_usrreq.c +++ b/bsd/netinet6/udp6_usrreq.c @@ -78,6 +78,7 @@ #include #include #include +#include #include #include @@ -102,6 +103,8 @@ #include #include extern int ipsec_bypass; +extern lck_mtx_t *sadb_mutex; +extern lck_mtx_t *nd6_mutex; #endif /*IPSEC*/ #include "faith.h" @@ -115,14 +118,26 @@ extern int ipsec_bypass; */ extern struct protosw inetsw[]; -static int in6_mcmatch __P((struct inpcb *, struct in6_addr *, struct ifnet *)); -static int udp6_detach __P((struct socket *so)); +static int in6_mcmatch(struct inpcb *, struct in6_addr *, struct ifnet *); +static int udp6_detach(struct socket *so); + + +extern void ipfwsyslog( int level, char *format,...); +extern int fw_verbose; + +#define log_in_vain_log( a ) { \ + if ( (log_in_vain == 3 ) && (fw_verbose == 2)) { /* Apple logging, log to ipfw.log */ \ + ipfwsyslog a ; \ + } \ + else log a ; \ +} + static int -in6_mcmatch(in6p, ia6, ifp) - struct inpcb *in6p; - register struct in6_addr *ia6; - struct ifnet *ifp; +in6_mcmatch( + struct inpcb *in6p, + register struct in6_addr *ia6, + struct ifnet *ifp) { struct ip6_moptions *im6o = in6p->in6p_moptions; struct in6_multi_mship *imm; @@ -130,21 +145,25 @@ in6_mcmatch(in6p, ia6, ifp) if (im6o == NULL) return 0; + lck_mtx_lock(nd6_mutex); for (imm = im6o->im6o_memberships.lh_first; imm != NULL; imm = imm->i6mm_chain.le_next) { if ((ifp == NULL || imm->i6mm_maddr->in6m_ifp == ifp) && IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr, - ia6)) + ia6)) { + lck_mtx_unlock(nd6_mutex); return 1; + } } + lck_mtx_unlock(nd6_mutex); return 0; } int -udp6_input(mp, offp) - struct mbuf **mp; - int *offp; +udp6_input( + struct mbuf **mp, + int *offp) { struct mbuf *m = *mp; register struct ip6_hdr *ip6; @@ -154,8 +173,9 @@ udp6_input(mp, offp) int off = *offp; int plen, ulen; struct sockaddr_in6 udp_in6; + struct inpcbinfo *pcbinfo = &udbinfo; - IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), IPPROTO_DONE); + IP6_EXTHDR_CHECK(m, off, sizeof(struct udphdr), return IPPROTO_DONE); ip6 = mtod(m, struct ip6_hdr *); @@ -234,23 +254,42 @@ udp6_input(mp, offp) * (Algorithm copied from raw_intr().) */ last = NULL; + lck_rw_lock_shared(pcbinfo->mtx); + LIST_FOREACH(in6p, &udb, inp_list) { + if ((in6p->inp_vflag & INP_IPV6) == 0) continue; - if (in6p->in6p_lport != uh->uh_dport) + + if (in_pcb_checkstate(in6p, WNT_ACQUIRE, 0) == WNT_STOPUSING) + continue; + + udp_lock(in6p->in6p_socket, 1, 0); + + if (in_pcb_checkstate(in6p, WNT_RELEASE, 1) == WNT_STOPUSING) { + udp_unlock(in6p->in6p_socket, 1, 0); + continue; + } + if (in6p->in6p_lport != uh->uh_dport) { + udp_unlock(in6p->in6p_socket, 1, 0); continue; + } if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) { if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, &ip6->ip6_dst) && !in6_mcmatch(in6p, &ip6->ip6_dst, - m->m_pkthdr.rcvif)) + m->m_pkthdr.rcvif)) { + udp_unlock(in6p->in6p_socket, 1, 0); continue; + } } if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &ip6->ip6_src) || - in6p->in6p_fport != uh->uh_sport) + in6p->in6p_fport != uh->uh_sport) { + udp_unlock(in6p->in6p_socket, 1, 0); continue; + } } if (last != NULL) { @@ -260,9 +299,13 @@ udp6_input(mp, offp) /* * Check AH/ESP integrity. */ - if (ipsec_bypass == 0 && ipsec6_in_reject_so(m, last->inp_socket)) - ipsec6stat.in_polvio++; + if (ipsec_bypass == 0) { + lck_mtx_lock(sadb_mutex); + if (ipsec6_in_reject_so(m, last->inp_socket)) + ipsec6stat.in_polvio++; /* do not inject data into pcb */ + lck_mtx_unlock(sadb_mutex); + } else #endif /*IPSEC*/ if ((n = m_copy(m, 0, M_COPYALL)) != NULL) { @@ -281,15 +324,13 @@ udp6_input(mp, offp) m_adj(n, off + sizeof(struct udphdr)); if (sbappendaddr(&last->in6p_socket->so_rcv, (struct sockaddr *)&udp_in6, - n, opts) == 0) { - m_freem(n); - if (opts) - m_freem(opts); + n, opts, NULL) == 0) { udpstat.udps_fullsock++; } else sorwakeup(last->in6p_socket); opts = NULL; } + udp_unlock(last->in6p_socket, 1, 0); } last = in6p; /* @@ -304,6 +345,7 @@ udp6_input(mp, offp) (SO_REUSEPORT|SO_REUSEADDR)) == 0) break; } + lck_rw_done(pcbinfo->mtx); if (last == NULL) { /* @@ -321,9 +363,15 @@ udp6_input(mp, offp) /* * Check AH/ESP integrity. */ - if (ipsec_bypass == 0 && ipsec6_in_reject_so(m, last->inp_socket)) { - ipsec6stat.in_polvio++; - goto bad; + if (ipsec_bypass == 0) { + lck_mtx_lock(sadb_mutex); + if (ipsec6_in_reject_so(m, last->inp_socket)) { + ipsec6stat.in_polvio++; + lck_mtx_unlock(sadb_mutex); + udp_unlock(last->in6p_socket, 1, 0); + goto bad; + } + lck_mtx_unlock(sadb_mutex); } #endif /*IPSEC*/ if (last->in6p_flags & IN6P_CONTROLOPTS @@ -333,11 +381,15 @@ udp6_input(mp, offp) m_adj(m, off + sizeof(struct udphdr)); if (sbappendaddr(&last->in6p_socket->so_rcv, (struct sockaddr *)&udp_in6, - m, opts) == 0) { + m, opts, NULL) == 0) { udpstat.udps_fullsock++; + m = NULL; + opts = NULL; + udp_unlock(last->in6p_socket, 1, 0); goto bad; } sorwakeup(last->in6p_socket); + udp_unlock(last->in6p_socket, 1, 0); return IPPROTO_DONE; } /* @@ -351,10 +403,17 @@ udp6_input(mp, offp) char buf[INET6_ADDRSTRLEN]; strcpy(buf, ip6_sprintf(&ip6->ip6_dst)); - log(LOG_INFO, - "Connection attempt to UDP %s:%d from %s:%d\n", - buf, ntohs(uh->uh_dport), - ip6_sprintf(&ip6->ip6_src), ntohs(uh->uh_sport)); + if (log_in_vain != 3) + log(LOG_INFO, + "Connection attempt to UDP %s:%d from %s:%d\n", + buf, ntohs(uh->uh_dport), + ip6_sprintf(&ip6->ip6_src), ntohs(uh->uh_sport)); + else if (!(m->m_flags & (M_BCAST | M_MCAST)) && + !IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &ip6->ip6_src)) + log_in_vain_log((LOG_INFO, + "Connection attempt to UDP %s:%d from %s:%d\n", + buf, ntohs(uh->uh_dport), + ip6_sprintf(&ip6->ip6_src), ntohs(uh->uh_sport))); } udpstat.udps_noport++; if (m->m_flags & M_MCAST) { @@ -371,9 +430,15 @@ udp6_input(mp, offp) /* * Check AH/ESP integrity. */ - if (ipsec_bypass == 0 && ipsec6_in_reject_so(m, in6p->in6p_socket)) { - ipsec6stat.in_polvio++; - goto bad; + if (ipsec_bypass == 0) { + lck_mtx_lock(sadb_mutex); + if (ipsec6_in_reject_so(m, in6p->in6p_socket)) { + ipsec6stat.in_polvio++; + lck_mtx_unlock(sadb_mutex); + in_pcb_checkstate(in6p, WNT_RELEASE, 0); + goto bad; + } + lck_mtx_unlock(sadb_mutex); } #endif /*IPSEC*/ @@ -381,6 +446,13 @@ udp6_input(mp, offp) * Construct sockaddr format source address. * Stuff source address and datagram in user buffer. */ + udp_lock(in6p->in6p_socket, 1, 0); + + if (in_pcb_checkstate(in6p, WNT_RELEASE, 1) == WNT_STOPUSING) { + udp_unlock(in6p->in6p_socket, 1, 0); + goto bad; + } + init_sin6(&udp_in6, m); /* general init */ udp_in6.sin6_port = uh->uh_sport; if (in6p->in6p_flags & IN6P_CONTROLOPTS @@ -389,11 +461,15 @@ udp6_input(mp, offp) m_adj(m, off + sizeof(struct udphdr)); if (sbappendaddr(&in6p->in6p_socket->so_rcv, (struct sockaddr *)&udp_in6, - m, opts) == 0) { + m, opts, NULL) == 0) { + m = NULL; + opts = NULL; udpstat.udps_fullsock++; + udp_unlock(in6p->in6p_socket, 1, 0); goto bad; } sorwakeup(in6p->in6p_socket); + udp_unlock(in6p->in6p_socket, 1, 0); return IPPROTO_DONE; bad: if (m) @@ -404,10 +480,10 @@ bad: } void -udp6_ctlinput(cmd, sa, d) - int cmd; - struct sockaddr *sa; - void *d; +udp6_ctlinput( + int cmd, + struct sockaddr *sa, + void *d) { struct udphdr uh; struct ip6_hdr *ip6; @@ -415,7 +491,7 @@ udp6_ctlinput(cmd, sa, d) int off = 0; struct ip6ctlparam *ip6cp = NULL; const struct sockaddr_in6 *sa6_src = NULL; - void (*notify) __P((struct inpcb *, int)) = udp_notify; + void (*notify)(struct inpcb *, int) = udp_notify; struct udp_portonly { u_int16_t uh_sport; u_int16_t uh_dport; @@ -460,11 +536,11 @@ udp6_ctlinput(cmd, sa, d) bzero(&uh, sizeof(uh)); m_copydata(m, off, sizeof(*uhp), (caddr_t)&uh); - (void) in6_pcbnotify(&udb, sa, uh.uh_dport, + (void) in6_pcbnotify(&udbinfo, sa, uh.uh_dport, (struct sockaddr*)ip6cp->ip6c_src, uh.uh_sport, cmd, notify); } else - (void) in6_pcbnotify(&udb, sa, 0, (struct sockaddr *)&sa6_src, + (void) in6_pcbnotify(&udbinfo, sa, 0, (struct sockaddr *)&sa6_src, 0, cmd, notify); } @@ -482,7 +558,7 @@ udp6_getcred SYSCTL_HANDLER_ARGS if (req->newlen != sizeof(addrs)) return (EINVAL); - if (req->oldlen != sizeof(struct ucred)) + if (req->oldlen != sizeof(*(kauth_cred_t)0)) return (EINVAL); error = SYSCTL_IN(req, addrs, sizeof(addrs)); if (error) @@ -497,7 +573,7 @@ udp6_getcred SYSCTL_HANDLER_ARGS goto out; } error = SYSCTL_OUT(req, inp->inp_socket->so_cred->pc_ucred, - sizeof(struct ucred)); + sizeof(*(kauth_cred_t)0)); out: splx(s); @@ -513,15 +589,12 @@ static int udp6_abort(struct socket *so) { struct inpcb *inp; - int s; inp = sotoinpcb(so); if (inp == 0) return EINVAL; /* ??? possible? panic instead? */ soisdisconnected(so); - s = splnet(); in6_pcbdetach(inp); - splx(s); return 0; } @@ -529,22 +602,21 @@ static int udp6_attach(struct socket *so, int proto, struct proc *p) { struct inpcb *inp; - int s, error; + int error; inp = sotoinpcb(so); if (inp != 0) return EINVAL; + error = in_pcballoc(so, &udbinfo, p); + if (error) + return error; + if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { error = soreserve(so, udp_sendspace, udp_recvspace); if (error) return error; } - s = splnet(); - error = in_pcballoc(so, &udbinfo, p); - splx(s); - if (error) - return error; inp = (struct inpcb *)so->so_pcb; inp->inp_vflag |= INP_IPV6; if (ip6_mapped_addr_on) @@ -565,7 +637,7 @@ static int udp6_bind(struct socket *so, struct sockaddr *nam, struct proc *p) { struct inpcb *inp; - int s, error; + int error; inp = sotoinpcb(so); if (inp == 0) @@ -586,16 +658,12 @@ udp6_bind(struct socket *so, struct sockaddr *nam, struct proc *p) in6_sin6_2_sin(&sin, sin6_p); inp->inp_vflag |= INP_IPV4; inp->inp_vflag &= ~INP_IPV6; - s = splnet(); error = in_pcbbind(inp, (struct sockaddr *)&sin, p); - splx(s); return error; } } - s = splnet(); error = in6_pcbbind(inp, nam, p); - splx(s); return error; } @@ -603,7 +671,7 @@ static int udp6_connect(struct socket *so, struct sockaddr *nam, struct proc *p) { struct inpcb *inp; - int s, error; + int error; inp = sotoinpcb(so); if (inp == 0) @@ -619,9 +687,7 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct proc *p) if (inp->inp_faddr.s_addr != INADDR_ANY) return EISCONN; in6_sin6_2_sin(&sin, sin6_p); - s = splnet(); error = in_pcbconnect(inp, (struct sockaddr *)&sin, p); - splx(s); if (error == 0) { inp->inp_vflag |= INP_IPV4; inp->inp_vflag &= ~INP_IPV6; @@ -633,9 +699,7 @@ udp6_connect(struct socket *so, struct sockaddr *nam, struct proc *p) if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) return EISCONN; - s = splnet(); error = in6_pcbconnect(inp, nam, p); - splx(s); if (error == 0) { if (ip6_mapped_addr_on || (inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) { /* should be non mapped addr */ inp->inp_vflag &= ~INP_IPV4; @@ -650,14 +714,11 @@ static int udp6_detach(struct socket *so) { struct inpcb *inp; - int s; inp = sotoinpcb(so); if (inp == 0) return EINVAL; - s = splnet(); in6_pcbdetach(inp); - splx(s); return 0; } @@ -665,7 +726,6 @@ static int udp6_disconnect(struct socket *so) { struct inpcb *inp; - int s; inp = sotoinpcb(so); if (inp == 0) @@ -681,10 +741,8 @@ udp6_disconnect(struct socket *so) if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) return ENOTCONN; - s = splnet(); in6_pcbdisconnect(inp); inp->in6p_laddr = in6addr_any; - splx(s); so->so_state &= ~SS_ISCONNECTED; /* XXX */ return 0; } @@ -749,5 +807,5 @@ struct pr_usrreqs udp6_usrreqs = { pru_connect2_notsupp, in6_control, udp6_detach, udp6_disconnect, pru_listen_notsupp, in6_mapped_peeraddr, pru_rcvd_notsupp, pru_rcvoob_notsupp, udp6_send, pru_sense_null, udp_shutdown, - in6_mapped_sockaddr, sosend, soreceive, sopoll + in6_mapped_sockaddr, sosend, soreceive, pru_sopoll_notsupp };