diff options
author | Eric Joyner <erj@FreeBSD.org> | 2019-03-19 17:49:03 +0000 |
---|---|---|
committer | Eric Joyner <erj@FreeBSD.org> | 2019-03-19 17:49:03 +0000 |
commit | 3e8d1bae5f49aab7132bd3f4be24867f18d5b103 (patch) | |
tree | 9d988efb8bb53a70bc2b452c174349f4960fb722 /sys/net/iflib.c | |
parent | 938b7a44d9a71a0fe8e408ec37508f3065edc83e (diff) | |
download | src-3e8d1bae5f49aab7132bd3f4be24867f18d5b103.tar.gz src-3e8d1bae5f49aab7132bd3f4be24867f18d5b103.zip |
iflib: prevent possible infinite loop in iflib_encap
From Jake:
iflib_encap calls bus_dmamap_load_mbuf_sg. Upon it returning EFBIG, an
m_collapse and an m_defrag are attempted to shrink the mbuf cluster to
fit within the DMA segment limitations.
However, if we call m_defrag, and then bus_dmamap_load_mbuf_sg returns
EFBIG on the now defragmented mbuf, we will continuously re-call
bus_dmamap_load_mbuf_sg over and over.
This happens because m_head isn't NULL, and remap is >1, so we don't try
to m_collapse or m_defrag again. The only way we exit the loop is if
m_head is NULL. However, m_head can't be modified by the call to
bus_dmamap_load_mbuf_sg, because we don't pass it as a double pointer.
I believe this will be an incredibly rare occurrence, because it is
unlikely that bus_dmamap_load_mbuf_sg will actually fail on the second
defragment with an EFBIG error. However, it still seems like
a possibility that we should account for.
Fix the exit check to ensure that if remap is >1, we will also exit,
even if m_head is not NULL.
Submitted by: Jacob Keller <jacob.e.keller@intel.com>
Reviewed by: shurd@, gallatin@
MFC after: 1 week
Sponsored by: Intel Corporation
Differential Revision: https://reviews.freebsd.org/D19468
Notes
Notes:
svn path=/head/; revision=345303
Diffstat (limited to 'sys/net/iflib.c')
-rw-r--r-- | sys/net/iflib.c | 9 |
1 files changed, 7 insertions, 2 deletions
diff --git a/sys/net/iflib.c b/sys/net/iflib.c index b803c4b3ca1f..694dd9b632fb 100644 --- a/sys/net/iflib.c +++ b/sys/net/iflib.c @@ -3276,9 +3276,14 @@ defrag: txq->ift_mbuf_defrag++; m_head = m_defrag(*m_headp, M_NOWAIT); } - remap++; - if (__predict_false(m_head == NULL)) + /* + * remap should never be >1 unless bus_dmamap_load_mbuf_sg + * failed to map an mbuf that was run through m_defrag + */ + MPASS(remap <= 1); + if (__predict_false(m_head == NULL || remap > 1)) goto defrag_failed; + remap++; *m_headp = m_head; goto retry; break; |