-
Notifications
You must be signed in to change notification settings - Fork 907
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix use after free issue in mbuf free #565
Conversation
Hi there, I could be wrong but from the code inside the
From the above code snippet, it seems to me that the relation between the buffers is:
I could be wrong though. Let's double check it. Pavel. |
This is related to #556 |
It's chained segment by segment, isn't it?
|
I think, the data of the segments is chained. |
That's exactly the case we encounter. When bsd stack intput this packet chain, it finds that the part pointed by bsd_mbuf1 is already recevied by previous packet, so it sets bsd_mbufs1->m_len = 0; and before it puts later segments into receive buffer, it invokes sbcompress() to free those segments with m_len = 0. That is to say, bsd wants to free the first segment, instead of the whole chain. But orginal implementation would the whole chain; as a result dpdk_mbuf2 and dpdk_mbuf3 are freed and reused while they are still in receive buffer.
|
BTW, this bug can be expoited for DOS attack; and what's worse, it could be reused to deliver more serious attack. |
As far as I understand the proposed fix, it's going to free only the first segment of the DPDK mbuf and then the next segments won't be freed because they haven't been attached to the BSD segments. The BSD segments only point to their data. |
Yep.
Make sense. I'll try your suggestion, and do some local test to make sure those dpdk mbufs are not leaked. Thanks! |
Two kinds of mbuf are used in f-stack: freebsd mbuf and dpdk mbuf. freebsd mbufs are metadata used in freebsd stack, and their data pointers (m_data) point to dpdk mbuf's data (buf_addr). And they have their own chain, like this: bsd_mbuf1 -> bsd_mbuf2 -> bsd_mbuf3 \ \ \ dpdk_mbuf1 -> dpdk_mbuf2 -> dpdk_mbuf3 Considering the map relationship, - m_freem() is corresponding to rte_pktmbuf_free(), is to free the whole chain of mbufs. - m_free() is corresponding to rte_pktmbuf_free_seg(), is to free the specified mbuf segment. The current implementation in f-stack uses rte_pktmbuf_free() for m_free(). This leads to mbufs, which are still in use, be freed unexpectedly. For example, if the bsd_mbuf1 is trimed into zero length, bsd will invoke m_free() to free the specified segment, however, the whole mbuf chain is freed by calling rte_pktmbuf_free(). #0 rte_pktmbuf_free (m=0x22006fb480) F-Stack#1 in ff_dpdk_pktmbuf_free (m=0x22006fb480) F-Stack#2 in ff_mbuf_ext_free (m=0x7ffff7f82800, arg1=0x22006fb480, arg2=0x0) F-Stack#3 in mb_free_ext (m=0x7ffff7f82800) F-Stack#4 in m_free (m=0x7ffff7f82800) F-Stack#5 in sbcompress (sb=, m=0x7ffff7f82800, n=) F-Stack#6 in sbappendstream_locked (sb=, m=0x7ffff7f82800, flags=0) The fix is straightforward. Use the correct API for segment free. Reported-by: Yong-Hao Zou <yonghaoz1994@gmail.com> Signed-off-by: Jianfeng Tan <henry.tjf@antgroup.com>
@freak82 Changed as you suggested, and I wrote a simple test to make sure that every segment is freed (unfortunately, I did not find a way to share the test case). |
Can @jfb8856606 confirm this? |
Two kinds of mbuf are used in f-stack: freebsd mbuf and dpdk mbuf.
freebsd mbufs are metadata used in freebsd stack, and their data
pointers (m_data) point to dpdk mbuf's data (buf_addr). And they have
their own chain, like this:
Considering the map relationship,
chain of mbufs.
specified mbuf segment.
The current implementation in f-stack uses rte_pktmbuf_free() for
m_free(). This leads to mbufs, which are still in use, be freed
unexpectedly. For example, if the bsd_mbuf1 is trimed into zero length,
bsd will invoke m_free() to free the specified segment, however, the
whole mbuf chain is freed by calling rte_pktmbuf_free().
#0 rte_pktmbuf_free (m=0x22006fb480)
#1 in ff_dpdk_pktmbuf_free (m=0x22006fb480)
#2 in ff_mbuf_ext_free (m=0x7ffff7f82800, arg1=0x22006fb480, arg2=0x0)
#3 in mb_free_ext (m=0x7ffff7f82800)
#4 in m_free (m=0x7ffff7f82800)
#5 in sbcompress (sb=, m=0x7ffff7f82800, n=)
#6 in sbappendstream_locked (sb=, m=0x7ffff7f82800, flags=0)
The fix is straightforward. Use the correct API for segment free.
Reported-by: Yong-Hao Zou yonghaoz1994@gmail.com
Signed-off-by: Jianfeng Tan henry.tjf@antgroup.com