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
This commit is contained in:
parent
1775215f88
commit
c2a8fd6f05
@ -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, int *enq_cnt,
|
||||
*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, int *enq_cnt,
|
||||
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 @@ ktls_encrypt(struct mbuf *top)
|
||||
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,
|
||||
|
@ -1655,6 +1655,8 @@ m_uiotombuf_nomap(struct uio *uio, int how, int len, int maxseg, int flags)
|
||||
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.
|
||||
@ -1667,11 +1669,24 @@ m_uiotombuf_nomap(struct uio *uio, int how, int len, int maxseg, int flags)
|
||||
if (maxseg == 0)
|
||||
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)
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user