xen/netback: Fix buffer overrun triggered by unusual packet
commit 534fc31d09b706a16d83533e16b5dc855caf7576 upstream. It is possible that a guest can send a packet that contains a head + 18 slots and yet has a len <= XEN_NETBACK_TX_COPY_LEN. This causes nr_slots to underflow in xenvif_get_requests() which then causes the subsequent loop's termination condition to be wrong, causing a buffer overrun of queue->tx_map_ops. Rework the code to account for the extra frag_overflow slots. This is CVE-2023-34319 / XSA-432. Fixes: ad7f402ae4f4 ("xen/netback: Ensure protocol headers don't fall in the non-linear area") Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com> Reviewed-by: Paul Durrant <paul@xen.org> Reviewed-by: Wei Liu <wei.liu@kernel.org> Signed-off-by: Juergen Gross <jgross@suse.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
8457fb5740
commit
f9167a2d6b
@ -396,7 +396,7 @@ static void xenvif_get_requests(struct xenvif_queue *queue,
|
||||
struct gnttab_map_grant_ref *gop = queue->tx_map_ops + *map_ops;
|
||||
struct xen_netif_tx_request *txp = first;
|
||||
|
||||
nr_slots = shinfo->nr_frags + 1;
|
||||
nr_slots = shinfo->nr_frags + frag_overflow + 1;
|
||||
|
||||
copy_count(skb) = 0;
|
||||
XENVIF_TX_CB(skb)->split_mask = 0;
|
||||
@ -462,8 +462,8 @@ static void xenvif_get_requests(struct xenvif_queue *queue,
|
||||
}
|
||||
}
|
||||
|
||||
for (shinfo->nr_frags = 0; shinfo->nr_frags < nr_slots;
|
||||
shinfo->nr_frags++, gop++) {
|
||||
for (shinfo->nr_frags = 0; nr_slots > 0 && shinfo->nr_frags < MAX_SKB_FRAGS;
|
||||
shinfo->nr_frags++, gop++, nr_slots--) {
|
||||
index = pending_index(queue->pending_cons++);
|
||||
pending_idx = queue->pending_ring[index];
|
||||
xenvif_tx_create_map_op(queue, pending_idx, txp,
|
||||
@ -476,12 +476,12 @@ static void xenvif_get_requests(struct xenvif_queue *queue,
|
||||
txp++;
|
||||
}
|
||||
|
||||
if (frag_overflow) {
|
||||
if (nr_slots > 0) {
|
||||
|
||||
shinfo = skb_shinfo(nskb);
|
||||
frags = shinfo->frags;
|
||||
|
||||
for (shinfo->nr_frags = 0; shinfo->nr_frags < frag_overflow;
|
||||
for (shinfo->nr_frags = 0; shinfo->nr_frags < nr_slots;
|
||||
shinfo->nr_frags++, txp++, gop++) {
|
||||
index = pending_index(queue->pending_cons++);
|
||||
pending_idx = queue->pending_ring[index];
|
||||
@ -492,6 +492,11 @@ static void xenvif_get_requests(struct xenvif_queue *queue,
|
||||
}
|
||||
|
||||
skb_shinfo(skb)->frag_list = nskb;
|
||||
} else if (nskb) {
|
||||
/* A frag_list skb was allocated but it is no longer needed
|
||||
* because enough slots were converted to copy ops above.
|
||||
*/
|
||||
kfree_skb(nskb);
|
||||
}
|
||||
|
||||
(*copy_ops) = cop - queue->tx_copy_ops;
|
||||
|
Loading…
Reference in New Issue
Block a user