X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/143cc14e17b26a90f1f4060725df7ea635161581..91447636331957f3d9b5ca5b508f07c526b0074d:/bsd/netinet6/esp_input.c diff --git a/bsd/netinet6/esp_input.c b/bsd/netinet6/esp_input.c index 549b37d41..4b080c6b4 100644 --- a/bsd/netinet6/esp_input.c +++ b/bsd/netinet6/esp_input.c @@ -48,8 +48,8 @@ #include #include -#include #include +#include #include #include @@ -89,8 +89,14 @@ #include +#include +#define DBG_LAYER_BEG NETDBG_CODE(DBG_NETIPSEC, 1) +#define DBG_LAYER_END NETDBG_CODE(DBG_NETIPSEC, 3) +#define DBG_FNC_ESPIN NETDBG_CODE(DBG_NETIPSEC, (6 << 8)) +#define DBG_FNC_DECRYPT NETDBG_CODE(DBG_NETIPSEC, (7 << 8)) #define IPLEN_FLIPPED +extern lck_mtx_t *sadb_mutex; #if INET extern struct protosw inetsw[]; @@ -116,6 +122,9 @@ esp4_input(m, off) size_t esplen; int s; + lck_mtx_lock(sadb_mutex); + + KERNEL_DEBUG(DBG_FNC_ESPIN | DBG_FUNC_START, 0,0,0,0,0); /* sanity check for alignment. */ if (off % 4 != 0 || m->m_pkthdr.len % 4 != 0) { ipseclog((LOG_ERR, "IPv4 ESP input: packet alignment problem " @@ -308,14 +317,17 @@ noreplaycheck: */ if (!algo->decrypt) panic("internal error: no decrypt function"); + KERNEL_DEBUG(DBG_FNC_DECRYPT | DBG_FUNC_START, 0,0,0,0,0); if ((*algo->decrypt)(m, off, sav, algo, ivlen)) { /* m is already freed */ m = NULL; ipseclog((LOG_ERR, "decrypt fail in IPv4 ESP input: %s\n", ipsec_logsastr(sav))); ipsecstat.in_inval++; + KERNEL_DEBUG(DBG_FNC_DECRYPT | DBG_FUNC_END, 1,0,0,0,0); goto bad; } + KERNEL_DEBUG(DBG_FNC_DECRYPT | DBG_FUNC_END, 2,0,0,0,0); ipsecstat.in_esphist[sav->alg_enc]++; m->m_flags |= M_DECRYPTED; @@ -378,32 +390,21 @@ noreplaycheck: goto bad; } -#if 0 /* XXX should call ipfw rather than ipsec_in_reject, shouldn't it ? */ - /* drop it if it does not match the default policy */ - if (ipsec4_in_reject(m, NULL)) { - ipsecstat.in_polvio++; - goto bad; - } -#endif - key_sa_recordxfer(sav, m); if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0 || ipsec_addhist(m, IPPROTO_IPV4, 0) != 0) { ipsecstat.in_nomem++; goto bad; } + + /* Clear the csum flags, they can't be valid for the inner headers */ + m->m_pkthdr.csum_flags = 0; - s = splimp(); - if (IF_QFULL(&ipintrq)) { - ipsecstat.in_inval++; - splx(s); - goto bad; - } - IF_ENQUEUE(&ipintrq, m); - m = NULL; - schednetisr(NETISR_IP); /*can be skipped but to make sure*/ - splx(s); + lck_mtx_unlock(sadb_mutex); + proto_input(PF_INET, m); + lck_mtx_lock(sadb_mutex); nxt = IPPROTO_DONE; + KERNEL_DEBUG(DBG_FNC_ESPIN | DBG_FUNC_END, 2,0,0,0,0); } else { /* * strip off ESP header and IV. @@ -433,6 +434,17 @@ noreplaycheck: ipsecstat.in_nomem++; goto bad; } + + /* + * Set the csum valid flag, if we authenticated the + * packet, the payload shouldn't be corrupt unless + * it was corrupted before being signed on the other + * side. + */ + if (nxt == IPPROTO_TCP || nxt == IPPROTO_UDP) { + m->m_pkthdr.csum_flags = CSUM_DATA_VALID | CSUM_PSEUDO_HDR; + m->m_pkthdr.csum_data = 0xFFFF; + } if (nxt != IPPROTO_DONE) { if ((ip_protox[nxt]->pr_flags & PR_LASTHDR) != 0 && @@ -440,7 +452,10 @@ noreplaycheck: ipsecstat.in_polvio++; goto bad; } - (*ip_protox[nxt]->pr_input)(m, off); + KERNEL_DEBUG(DBG_FNC_ESPIN | DBG_FUNC_END, 3,0,0,0,0); + lck_mtx_unlock(sadb_mutex); + ip_proto_dispatch_in(m, off, nxt, 0); + lck_mtx_lock(sadb_mutex); } else m_freem(m); m = NULL; @@ -452,6 +467,7 @@ noreplaycheck: key_freesav(sav); } ipsecstat.in_success++; + lck_mtx_unlock(sadb_mutex); return; bad: @@ -460,17 +476,19 @@ bad: printf("DP esp4_input call free SA:%p\n", sav)); key_freesav(sav); } + lck_mtx_unlock(sadb_mutex); if (m) m_freem(m); + KERNEL_DEBUG(DBG_FNC_ESPIN | DBG_FUNC_END, 4,0,0,0,0); return; } #endif /* INET */ #if INET6 int -esp6_input(mp, offp, proto) +esp6_input(mp, offp) struct mbuf **mp; - int *offp, proto; + int *offp; { struct mbuf *m = *mp; int off = *offp; @@ -486,6 +504,8 @@ esp6_input(mp, offp, proto) size_t esplen; int s; + lck_mtx_lock(sadb_mutex); + /* sanity check for alignment. */ if (off % 4 != 0 || m->m_pkthdr.len % 4 != 0) { ipseclog((LOG_ERR, "IPv6 ESP input: packet alignment problem " @@ -495,12 +515,13 @@ esp6_input(mp, offp, proto) } #ifndef PULLDOWN_TEST - IP6_EXTHDR_CHECK(m, off, ESPMAXLEN, IPPROTO_DONE); + IP6_EXTHDR_CHECK(m, off, ESPMAXLEN, {lck_mtx_unlock(sadb_mutex); return IPPROTO_DONE;}); esp = (struct esp *)(mtod(m, caddr_t) + off); #else IP6_EXTHDR_GET(esp, struct esp *, m, off, ESPMAXLEN); if (esp == NULL) { ipsec6stat.in_inval++; + lck_mtx_unlock(sadb_mutex); return IPPROTO_DONE; } #endif @@ -654,7 +675,7 @@ noreplaycheck: } #ifndef PULLDOWN_TEST - IP6_EXTHDR_CHECK(m, off, esplen + ivlen, IPPROTO_DONE); /*XXX*/ + IP6_EXTHDR_CHECK(m, off, esplen + ivlen, return IPPROTO_DONE); /*XXX*/ #else IP6_EXTHDR_GET(esp, struct esp *, m, off, esplen + ivlen); if (esp == NULL) { @@ -752,31 +773,15 @@ noreplaycheck: goto bad; } -#if 0 /* XXX should call ipfw rather than ipsec_in_reject, shouldn't it ? */ - /* drop it if it does not match the default policy */ - if (ipsec6_in_reject(m, NULL)) { - ipsec6stat.in_polvio++; - goto bad; - } -#endif - key_sa_recordxfer(sav, m); if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0 || ipsec_addhist(m, IPPROTO_IPV6, 0) != 0) { ipsec6stat.in_nomem++; goto bad; } - - s = splimp(); - if (IF_QFULL(&ip6intrq)) { - ipsec6stat.in_inval++; - splx(s); - goto bad; - } - IF_ENQUEUE(&ip6intrq, m); - m = NULL; - schednetisr(NETISR_IPV6); /*can be skipped but to make sure*/ - splx(s); + lck_mtx_unlock(sadb_mutex); + proto_input(PF_INET6, m); + lck_mtx_lock(sadb_mutex); nxt = IPPROTO_DONE; } else { /* @@ -814,9 +819,9 @@ noreplaycheck: goto bad; } m_adj(n, stripsiz); - m_cat(m, n); /* m_cat does not update m_pkthdr.len */ m->m_pkthdr.len += n->m_pkthdr.len; + m_cat(m, n); } #ifndef PULLDOWN_TEST @@ -855,10 +860,10 @@ noreplaycheck: m_freem(m); } else { m_copydata(m, 0, maxlen, mtod(n, caddr_t)); - m_adj(m, maxlen); n->m_len = maxlen; n->m_pkthdr.len = m->m_pkthdr.len; n->m_next = m; + m_adj(m, maxlen); m->m_flags &= ~M_PKTHDR; } m = n; @@ -884,6 +889,7 @@ noreplaycheck: key_freesav(sav); } ipsec6stat.in_success++; + lck_mtx_unlock(sadb_mutex); return nxt; bad: @@ -892,6 +898,7 @@ bad: printf("DP esp6_input call free SA:%p\n", sav)); key_freesav(sav); } + lck_mtx_unlock(sadb_mutex); if (m) m_freem(m); return IPPROTO_DONE; @@ -910,7 +917,7 @@ esp6_ctlinput(cmd, sa, d) struct ip6_hdr *ip6; struct mbuf *m; int off; - struct sockaddr_in6 sa6_src, sa6_dst; + struct sockaddr_in6 *sa6_src, *sa6_dst; if (sa->sa_family != AF_INET6 || sa->sa_len != sizeof(struct sockaddr_in6)) @@ -974,16 +981,20 @@ esp6_ctlinput(cmd, sa, d) * Check to see if we have a valid SA corresponding to * the address in the ICMP message payload. */ + sa6_src = ip6cp->ip6c_src; + sa6_dst = (struct sockaddr_in6 *)sa; + lck_mtx_lock(sadb_mutex); sav = key_allocsa(AF_INET6, - (caddr_t)&sa6_src.sin6_addr, - (caddr_t)&sa6_dst, IPPROTO_ESP, - espp->esp_spi); + (caddr_t)&sa6_src->sin6_addr, + (caddr_t)&sa6_dst->sin6_addr, + IPPROTO_ESP, espp->esp_spi); if (sav) { if (sav->state == SADB_SASTATE_MATURE || sav->state == SADB_SASTATE_DYING) valid++; key_freesav(sav); } + lck_mtx_unlock(sadb_mutex); /* XXX Further validation? */