From: Ross Lagerwall ross.lagerwall@citrix.com
stable inclusion from stable-v4.19.290 commit 11e6919ae028b5de1fc48007354ea07069561b31 category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/I7RQ63 CVE: CVE-2023-34319
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
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
Conflicts: drivers/net/xen-netback/netback.c
Signed-off-by: Zhengchao Shao shaozhengchao@huawei.com --- drivers/net/xen-netback/netback.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 649049df922f..103f2c09d785 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -384,7 +384,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;
@@ -439,8 +439,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, @@ -453,12 +453,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]; @@ -469,6 +469,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;