Skip to content

Commit

Permalink
netdev-dpdk: Fix incorrect shinfo initialization.
Browse files Browse the repository at this point in the history
shinfo is used to store reference counter and free callback
of an external buffer, but it is stored in mbuf if the mbuf
has tailroom for it.

This is wrong because the mbuf (and its data) can be freed
before the external buffer, for example:

  pkt2 = rte_pktmbuf_alloc(mp);
  rte_pktmbuf_attach(pkt2, pkt);
  rte_pktmbuf_free(pkt);

After this, pkt is freed, but it still contains shinfo, which
is referenced by pkt2.

This sequence of operations is possible inside DPDK e.g., while
performing TSO operations for 'net_tap' PMD.

Fix this by always storing shinfo at the tail of external buffer.

Fixes: 29cf9c1 ("userspace: Add TCP Segmentation Offload support")
Co-authored-by: Olivier Matz <[email protected]>
Signed-off-by: Olivier Matz <[email protected]>
Signed-off-by: Yi Yang <[email protected]>
Acked-by: Flavio Leitner <[email protected]>
Signed-off-by: Ilya Maximets <[email protected]>
  • Loading branch information
2 people authored and igsilya committed Feb 1, 2021
1 parent 75e1e6f commit c17f32a
Showing 1 changed file with 10 additions and 20 deletions.
30 changes: 10 additions & 20 deletions lib/netdev-dpdk.c
Original file line number Diff line number Diff line change
Expand Up @@ -2683,12 +2683,8 @@ dpdk_pktmbuf_attach_extbuf(struct rte_mbuf *pkt, uint32_t data_len)
uint16_t buf_len;
void *buf;

if (rte_pktmbuf_tailroom(pkt) >= sizeof *shinfo) {
shinfo = rte_pktmbuf_mtod(pkt, struct rte_mbuf_ext_shared_info *);
} else {
total_len += sizeof *shinfo + sizeof(uintptr_t);
total_len = RTE_ALIGN_CEIL(total_len, sizeof(uintptr_t));
}
total_len += sizeof *shinfo + sizeof(uintptr_t);
total_len = RTE_ALIGN_CEIL(total_len, sizeof(uintptr_t));

if (OVS_UNLIKELY(total_len > UINT16_MAX)) {
VLOG_ERR("Can't copy packet: too big %u", total_len);
Expand All @@ -2703,20 +2699,14 @@ dpdk_pktmbuf_attach_extbuf(struct rte_mbuf *pkt, uint32_t data_len)
}

/* Initialize shinfo. */
if (shinfo) {
shinfo->free_cb = netdev_dpdk_extbuf_free;
shinfo->fcb_opaque = buf;
rte_mbuf_ext_refcnt_set(shinfo, 1);
} else {
shinfo = rte_pktmbuf_ext_shinfo_init_helper(buf, &buf_len,
netdev_dpdk_extbuf_free,
buf);
if (OVS_UNLIKELY(shinfo == NULL)) {
rte_free(buf);
VLOG_ERR("Failed to initialize shared info for mbuf while "
"attempting to attach an external buffer.");
return NULL;
}
shinfo = rte_pktmbuf_ext_shinfo_init_helper(buf, &buf_len,
netdev_dpdk_extbuf_free,
buf);
if (OVS_UNLIKELY(shinfo == NULL)) {
rte_free(buf);
VLOG_ERR("Failed to initialize shared info for mbuf while "
"attempting to attach an external buffer.");
return NULL;
}

rte_pktmbuf_attach_extbuf(pkt, buf, rte_malloc_virt2iova(buf), buf_len,
Expand Down

0 comments on commit c17f32a

Please sign in to comment.