Author: jhb Date: Tue Oct 13 17:30:34 2020 New Revision: 366674 URL: https://svnweb.freebsd.org/changeset/base/366674
Log: Permit sending empty fragments for TLS 1.0. Due to a weakness in the TLS 1.0 protocol, OpenSSL will periodically send empty TLS records ("empty fragments"). These TLS records have no payload (and thus a page count of zero). m_uiotombuf_nomap() was returning NULL instead of an empty mbuf, and a few places needed to be updated to treat an empty TLS record as having a page count of "1" as 0 means "no work to do" (e.g. nothing to encrypt, or nothing to mark ready via sbready()). Reviewed by: gallatin Sponsored by: Netflix Differential Revision: https://reviews.freebsd.org/D26729 Modified: head/sys/kern/uipc_ktls.c head/sys/kern/uipc_mbuf.c head/sys/kern/uipc_sockbuf.c Modified: head/sys/kern/uipc_ktls.c ============================================================================== --- head/sys/kern/uipc_ktls.c Tue Oct 13 17:27:37 2020 (r366673) +++ head/sys/kern/uipc_ktls.c Tue Oct 13 17:30:34 2020 (r366674) @@ -1384,7 +1384,9 @@ ktls_seq(struct sockbuf *sb, struct mbuf *m) * The enq_count argument on return is set to the number of pages of * payload data for this entire chain that need to be encrypted via SW * encryption. The returned value should be passed to ktls_enqueue - * when scheduling encryption of this chain of mbufs. + * when scheduling encryption of this chain of mbufs. To handle the + * special case of empty fragments for TLS 1.0 sessions, an empty + * fragment counts as one page. */ void ktls_frame(struct mbuf *top, struct ktls_session *tls, int *enq_cnt, @@ -1400,12 +1402,16 @@ ktls_frame(struct mbuf *top, struct ktls_session *tls, *enq_cnt = 0; for (m = top; m != NULL; m = m->m_next) { /* - * All mbufs in the chain should be non-empty TLS - * records whose payload does not exceed the maximum - * frame length. + * All mbufs in the chain should be TLS records whose + * payload does not exceed the maximum frame length. + * + * Empty TLS records are permitted when using CBC. */ - KASSERT(m->m_len <= maxlen && m->m_len > 0, + KASSERT(m->m_len <= maxlen && + (tls->params.cipher_algorithm == CRYPTO_AES_CBC ? + m->m_len >= 0 : m->m_len > 0), ("ktls_frame: m %p len %d\n", m, m->m_len)); + /* * TLS frames require unmapped mbufs to store session * info. @@ -1496,7 +1502,11 @@ ktls_frame(struct mbuf *top, struct ktls_session *tls, if (tls->mode == TCP_TLS_MODE_SW) { m->m_flags |= M_NOTREADY; m->m_epg_nrdy = m->m_epg_npgs; - *enq_cnt += m->m_epg_npgs; + if (__predict_false(tls_len == 0)) { + /* TLS 1.0 empty fragment. */ + *enq_cnt += 1; + } else + *enq_cnt += m->m_epg_npgs; } } } @@ -1961,7 +1971,11 @@ retry_page: dst_iov[i].iov_len = len; } - npages += i; + if (__predict_false(m->m_epg_npgs == 0)) { + /* TLS 1.0 empty fragment. */ + npages++; + } else + npages += i; error = (*tls->sw_encrypt)(tls, (const struct tls_record_layer *)m->m_epg_hdr, Modified: head/sys/kern/uipc_mbuf.c ============================================================================== --- head/sys/kern/uipc_mbuf.c Tue Oct 13 17:27:37 2020 (r366673) +++ head/sys/kern/uipc_mbuf.c Tue Oct 13 17:30:34 2020 (r366674) @@ -1655,6 +1655,8 @@ m_uiotombuf_nomap(struct uio *uio, int how, int len, i int pflags = malloc2vm_flags(how) | VM_ALLOC_NOOBJ | VM_ALLOC_NODUMP | VM_ALLOC_WIRED; + MPASS((flags & M_PKTHDR) == 0); + /* * len can be zero or an arbitrary large value bound by * the total data supplied by the uio. @@ -1668,10 +1670,23 @@ m_uiotombuf_nomap(struct uio *uio, int how, int len, i maxseg = MBUF_PEXT_MAX_PGS * PAGE_SIZE; /* + * If total is zero, return an empty mbuf. This can occur + * for TLS 1.0 connections which send empty fragments as + * a countermeasure against the known-IV weakness in CBC + * ciphersuites. + */ + if (__predict_false(total == 0)) { + mb = mb_alloc_ext_pgs(how, mb_free_mext_pgs); + if (mb == NULL) + return (NULL); + mb->m_epg_flags = EPG_FLAG_ANON; + return (mb); + } + + /* * Allocate the pages */ m = NULL; - MPASS((flags & M_PKTHDR) == 0); while (total > 0) { mb = mb_alloc_ext_pgs(how, mb_free_mext_pgs); if (mb == NULL) Modified: head/sys/kern/uipc_sockbuf.c ============================================================================== --- head/sys/kern/uipc_sockbuf.c Tue Oct 13 17:27:37 2020 (r366673) +++ head/sys/kern/uipc_sockbuf.c Tue Oct 13 17:30:34 2020 (r366674) @@ -212,7 +212,7 @@ sbready(struct sockbuf *sb, struct mbuf *m0, int count while (count > 0) { KASSERT(m->m_flags & M_NOTREADY, ("%s: m %p !M_NOTREADY", __func__, m)); - if ((m->m_flags & M_EXTPG) != 0) { + if ((m->m_flags & M_EXTPG) != 0 && m->m_epg_npgs != 0) { if (count < m->m_epg_nrdy) { m->m_epg_nrdy -= count; count = 0; _______________________________________________ svn-src-all@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"