Index: head/sys/kern/uipc_ktls.c =================================================================== --- head/sys/kern/uipc_ktls.c +++ head/sys/kern/uipc_ktls.c @@ -1384,7 +1384,9 @@ * 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 @@ *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 @@ 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 @@ 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, Index: head/sys/kern/uipc_mbuf.c =================================================================== --- head/sys/kern/uipc_mbuf.c +++ head/sys/kern/uipc_mbuf.c @@ -1655,6 +1655,8 @@ 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 @@ 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) Index: head/sys/kern/uipc_sockbuf.c =================================================================== --- head/sys/kern/uipc_sockbuf.c +++ head/sys/kern/uipc_sockbuf.c @@ -212,7 +212,7 @@ 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;