Skip to content

Commit b5521fe

Browse files
committed
Merge tag 'xsa396-5.17-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip
Pull xen fixes from Juergen Gross: "Several Linux PV device frontends are using the grant table interfaces for removing access rights of the backends in ways being subject to race conditions, resulting in potential data leaks, data corruption by malicious backends, and denial of service triggered by malicious backends: - blkfront, netfront, scsifront and the gntalloc driver are testing whether a grant reference is still in use. If this is not the case, they assume that a following removal of the granted access will always succeed, which is not true in case the backend has mapped the granted page between those two operations. As a result the backend can keep access to the memory page of the guest no matter how the page will be used after the frontend I/O has finished. The xenbus driver has a similar problem, as it doesn't check the success of removing the granted access of a shared ring buffer. - blkfront, netfront, scsifront, usbfront, dmabuf, xenbus, 9p, kbdfront, and pvcalls are using a functionality to delay freeing a grant reference until it is no longer in use, but the freeing of the related data page is not synchronized with dropping the granted access. As a result the backend can keep access to the memory page even after it has been freed and then re-used for a different purpose. - netfront will fail a BUG_ON() assertion if it fails to revoke access in the rx path. This will result in a Denial of Service (DoS) situation of the guest which can be triggered by the backend" * tag 'xsa396-5.17-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip: xen/netfront: react properly to failing gnttab_end_foreign_access_ref() xen/gnttab: fix gnttab_end_foreign_access() without page specified xen/pvcalls: use alloc/free_pages_exact() xen/9p: use alloc/free_pages_exact() xen/usb: don't use gnttab_end_foreign_access() in xenhcd_gnttab_done() xen: remove gnttab_query_foreign_access() xen/gntalloc: don't use gnttab_query_foreign_access() xen/scsifront: don't use gnttab_query_foreign_access() for mapped status xen/netfront: don't use gnttab_query_foreign_access() for mapped status xen/blkfront: don't use gnttab_query_foreign_access() for mapped status xen/grant-table: add gnttab_try_end_foreign_access() xen/xenbus: don't let xenbus_grant_ring() remove grants in error case
2 parents 3bf7edc + 66e3531 commit b5521fe

File tree

10 files changed

+173
-134
lines changed

10 files changed

+173
-134
lines changed

drivers/block/xen-blkfront.c

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1288,7 +1288,8 @@ static void blkif_free_ring(struct blkfront_ring_info *rinfo)
12881288
rinfo->ring_ref[i] = GRANT_INVALID_REF;
12891289
}
12901290
}
1291-
free_pages((unsigned long)rinfo->ring.sring, get_order(info->nr_ring_pages * XEN_PAGE_SIZE));
1291+
free_pages_exact(rinfo->ring.sring,
1292+
info->nr_ring_pages * XEN_PAGE_SIZE);
12921293
rinfo->ring.sring = NULL;
12931294

12941295
if (rinfo->irq)
@@ -1372,9 +1373,15 @@ static int blkif_get_final_status(enum blk_req_status s1,
13721373
return BLKIF_RSP_OKAY;
13731374
}
13741375

1375-
static bool blkif_completion(unsigned long *id,
1376-
struct blkfront_ring_info *rinfo,
1377-
struct blkif_response *bret)
1376+
/*
1377+
* Return values:
1378+
* 1 response processed.
1379+
* 0 missing further responses.
1380+
* -1 error while processing.
1381+
*/
1382+
static int blkif_completion(unsigned long *id,
1383+
struct blkfront_ring_info *rinfo,
1384+
struct blkif_response *bret)
13781385
{
13791386
int i = 0;
13801387
struct scatterlist *sg;
@@ -1397,7 +1404,7 @@ static bool blkif_completion(unsigned long *id,
13971404

13981405
/* Wait the second response if not yet here. */
13991406
if (s2->status < REQ_DONE)
1400-
return false;
1407+
return 0;
14011408

14021409
bret->status = blkif_get_final_status(s->status,
14031410
s2->status);
@@ -1448,42 +1455,43 @@ static bool blkif_completion(unsigned long *id,
14481455
}
14491456
/* Add the persistent grant into the list of free grants */
14501457
for (i = 0; i < num_grant; i++) {
1451-
if (gnttab_query_foreign_access(s->grants_used[i]->gref)) {
1458+
if (!gnttab_try_end_foreign_access(s->grants_used[i]->gref)) {
14521459
/*
14531460
* If the grant is still mapped by the backend (the
14541461
* backend has chosen to make this grant persistent)
14551462
* we add it at the head of the list, so it will be
14561463
* reused first.
14571464
*/
1458-
if (!info->feature_persistent)
1459-
pr_alert_ratelimited("backed has not unmapped grant: %u\n",
1460-
s->grants_used[i]->gref);
1465+
if (!info->feature_persistent) {
1466+
pr_alert("backed has not unmapped grant: %u\n",
1467+
s->grants_used[i]->gref);
1468+
return -1;
1469+
}
14611470
list_add(&s->grants_used[i]->node, &rinfo->grants);
14621471
rinfo->persistent_gnts_c++;
14631472
} else {
14641473
/*
1465-
* If the grant is not mapped by the backend we end the
1466-
* foreign access and add it to the tail of the list,
1467-
* so it will not be picked again unless we run out of
1468-
* persistent grants.
1474+
* If the grant is not mapped by the backend we add it
1475+
* to the tail of the list, so it will not be picked
1476+
* again unless we run out of persistent grants.
14691477
*/
1470-
gnttab_end_foreign_access(s->grants_used[i]->gref, 0, 0UL);
14711478
s->grants_used[i]->gref = GRANT_INVALID_REF;
14721479
list_add_tail(&s->grants_used[i]->node, &rinfo->grants);
14731480
}
14741481
}
14751482
if (s->req.operation == BLKIF_OP_INDIRECT) {
14761483
for (i = 0; i < INDIRECT_GREFS(num_grant); i++) {
1477-
if (gnttab_query_foreign_access(s->indirect_grants[i]->gref)) {
1478-
if (!info->feature_persistent)
1479-
pr_alert_ratelimited("backed has not unmapped grant: %u\n",
1480-
s->indirect_grants[i]->gref);
1484+
if (!gnttab_try_end_foreign_access(s->indirect_grants[i]->gref)) {
1485+
if (!info->feature_persistent) {
1486+
pr_alert("backed has not unmapped grant: %u\n",
1487+
s->indirect_grants[i]->gref);
1488+
return -1;
1489+
}
14811490
list_add(&s->indirect_grants[i]->node, &rinfo->grants);
14821491
rinfo->persistent_gnts_c++;
14831492
} else {
14841493
struct page *indirect_page;
14851494

1486-
gnttab_end_foreign_access(s->indirect_grants[i]->gref, 0, 0UL);
14871495
/*
14881496
* Add the used indirect page back to the list of
14891497
* available pages for indirect grefs.
@@ -1498,7 +1506,7 @@ static bool blkif_completion(unsigned long *id,
14981506
}
14991507
}
15001508

1501-
return true;
1509+
return 1;
15021510
}
15031511

15041512
static irqreturn_t blkif_interrupt(int irq, void *dev_id)
@@ -1564,12 +1572,17 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
15641572
}
15651573

15661574
if (bret.operation != BLKIF_OP_DISCARD) {
1575+
int ret;
1576+
15671577
/*
15681578
* We may need to wait for an extra response if the
15691579
* I/O request is split in 2
15701580
*/
1571-
if (!blkif_completion(&id, rinfo, &bret))
1581+
ret = blkif_completion(&id, rinfo, &bret);
1582+
if (!ret)
15721583
continue;
1584+
if (unlikely(ret < 0))
1585+
goto err;
15731586
}
15741587

15751588
if (add_id_to_freelist(rinfo, id)) {
@@ -1676,8 +1689,7 @@ static int setup_blkring(struct xenbus_device *dev,
16761689
for (i = 0; i < info->nr_ring_pages; i++)
16771690
rinfo->ring_ref[i] = GRANT_INVALID_REF;
16781691

1679-
sring = (struct blkif_sring *)__get_free_pages(GFP_NOIO | __GFP_HIGH,
1680-
get_order(ring_size));
1692+
sring = alloc_pages_exact(ring_size, GFP_NOIO);
16811693
if (!sring) {
16821694
xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
16831695
return -ENOMEM;
@@ -1687,7 +1699,7 @@ static int setup_blkring(struct xenbus_device *dev,
16871699

16881700
err = xenbus_grant_ring(dev, rinfo->ring.sring, info->nr_ring_pages, gref);
16891701
if (err < 0) {
1690-
free_pages((unsigned long)sring, get_order(ring_size));
1702+
free_pages_exact(sring, ring_size);
16911703
rinfo->ring.sring = NULL;
16921704
goto fail;
16931705
}
@@ -2532,11 +2544,10 @@ static void purge_persistent_grants(struct blkfront_info *info)
25322544
list_for_each_entry_safe(gnt_list_entry, tmp, &rinfo->grants,
25332545
node) {
25342546
if (gnt_list_entry->gref == GRANT_INVALID_REF ||
2535-
gnttab_query_foreign_access(gnt_list_entry->gref))
2547+
!gnttab_try_end_foreign_access(gnt_list_entry->gref))
25362548
continue;
25372549

25382550
list_del(&gnt_list_entry->node);
2539-
gnttab_end_foreign_access(gnt_list_entry->gref, 0, 0UL);
25402551
rinfo->persistent_gnts_c--;
25412552
gnt_list_entry->gref = GRANT_INVALID_REF;
25422553
list_add_tail(&gnt_list_entry->node, &rinfo->grants);

drivers/net/xen-netfront.c

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -424,14 +424,12 @@ static bool xennet_tx_buf_gc(struct netfront_queue *queue)
424424
queue->tx_link[id] = TX_LINK_NONE;
425425
skb = queue->tx_skbs[id];
426426
queue->tx_skbs[id] = NULL;
427-
if (unlikely(gnttab_query_foreign_access(
428-
queue->grant_tx_ref[id]) != 0)) {
427+
if (unlikely(!gnttab_end_foreign_access_ref(
428+
queue->grant_tx_ref[id], GNTMAP_readonly))) {
429429
dev_alert(dev,
430430
"Grant still in use by backend domain\n");
431431
goto err;
432432
}
433-
gnttab_end_foreign_access_ref(
434-
queue->grant_tx_ref[id], GNTMAP_readonly);
435433
gnttab_release_grant_reference(
436434
&queue->gref_tx_head, queue->grant_tx_ref[id]);
437435
queue->grant_tx_ref[id] = GRANT_INVALID_REF;
@@ -990,7 +988,6 @@ static int xennet_get_responses(struct netfront_queue *queue,
990988
struct device *dev = &queue->info->netdev->dev;
991989
struct bpf_prog *xdp_prog;
992990
struct xdp_buff xdp;
993-
unsigned long ret;
994991
int slots = 1;
995992
int err = 0;
996993
u32 verdict;
@@ -1032,8 +1029,13 @@ static int xennet_get_responses(struct netfront_queue *queue,
10321029
goto next;
10331030
}
10341031

1035-
ret = gnttab_end_foreign_access_ref(ref, 0);
1036-
BUG_ON(!ret);
1032+
if (!gnttab_end_foreign_access_ref(ref, 0)) {
1033+
dev_alert(dev,
1034+
"Grant still in use by backend domain\n");
1035+
queue->info->broken = true;
1036+
dev_alert(dev, "Disabled for further use\n");
1037+
return -EINVAL;
1038+
}
10371039

10381040
gnttab_release_grant_reference(&queue->gref_rx_head, ref);
10391041

@@ -1254,6 +1256,10 @@ static int xennet_poll(struct napi_struct *napi, int budget)
12541256
&need_xdp_flush);
12551257

12561258
if (unlikely(err)) {
1259+
if (queue->info->broken) {
1260+
spin_unlock(&queue->rx_lock);
1261+
return 0;
1262+
}
12571263
err:
12581264
while ((skb = __skb_dequeue(&tmpq)))
12591265
__skb_queue_tail(&errq, skb);
@@ -1918,7 +1924,7 @@ static int setup_netfront(struct xenbus_device *dev,
19181924
struct netfront_queue *queue, unsigned int feature_split_evtchn)
19191925
{
19201926
struct xen_netif_tx_sring *txs;
1921-
struct xen_netif_rx_sring *rxs;
1927+
struct xen_netif_rx_sring *rxs = NULL;
19221928
grant_ref_t gref;
19231929
int err;
19241930

@@ -1938,21 +1944,21 @@ static int setup_netfront(struct xenbus_device *dev,
19381944

19391945
err = xenbus_grant_ring(dev, txs, 1, &gref);
19401946
if (err < 0)
1941-
goto grant_tx_ring_fail;
1947+
goto fail;
19421948
queue->tx_ring_ref = gref;
19431949

19441950
rxs = (struct xen_netif_rx_sring *)get_zeroed_page(GFP_NOIO | __GFP_HIGH);
19451951
if (!rxs) {
19461952
err = -ENOMEM;
19471953
xenbus_dev_fatal(dev, err, "allocating rx ring page");
1948-
goto alloc_rx_ring_fail;
1954+
goto fail;
19491955
}
19501956
SHARED_RING_INIT(rxs);
19511957
FRONT_RING_INIT(&queue->rx, rxs, XEN_PAGE_SIZE);
19521958

19531959
err = xenbus_grant_ring(dev, rxs, 1, &gref);
19541960
if (err < 0)
1955-
goto grant_rx_ring_fail;
1961+
goto fail;
19561962
queue->rx_ring_ref = gref;
19571963

19581964
if (feature_split_evtchn)
@@ -1965,22 +1971,28 @@ static int setup_netfront(struct xenbus_device *dev,
19651971
err = setup_netfront_single(queue);
19661972

19671973
if (err)
1968-
goto alloc_evtchn_fail;
1974+
goto fail;
19691975

19701976
return 0;
19711977

19721978
/* If we fail to setup netfront, it is safe to just revoke access to
19731979
* granted pages because backend is not accessing it at this point.
19741980
*/
1975-
alloc_evtchn_fail:
1976-
gnttab_end_foreign_access_ref(queue->rx_ring_ref, 0);
1977-
grant_rx_ring_fail:
1978-
free_page((unsigned long)rxs);
1979-
alloc_rx_ring_fail:
1980-
gnttab_end_foreign_access_ref(queue->tx_ring_ref, 0);
1981-
grant_tx_ring_fail:
1982-
free_page((unsigned long)txs);
1983-
fail:
1981+
fail:
1982+
if (queue->rx_ring_ref != GRANT_INVALID_REF) {
1983+
gnttab_end_foreign_access(queue->rx_ring_ref, 0,
1984+
(unsigned long)rxs);
1985+
queue->rx_ring_ref = GRANT_INVALID_REF;
1986+
} else {
1987+
free_page((unsigned long)rxs);
1988+
}
1989+
if (queue->tx_ring_ref != GRANT_INVALID_REF) {
1990+
gnttab_end_foreign_access(queue->tx_ring_ref, 0,
1991+
(unsigned long)txs);
1992+
queue->tx_ring_ref = GRANT_INVALID_REF;
1993+
} else {
1994+
free_page((unsigned long)txs);
1995+
}
19841996
return err;
19851997
}
19861998

drivers/scsi/xen-scsifront.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -233,12 +233,11 @@ static void scsifront_gnttab_done(struct vscsifrnt_info *info,
233233
return;
234234

235235
for (i = 0; i < shadow->nr_grants; i++) {
236-
if (unlikely(gnttab_query_foreign_access(shadow->gref[i]))) {
236+
if (unlikely(!gnttab_try_end_foreign_access(shadow->gref[i]))) {
237237
shost_printk(KERN_ALERT, info->host, KBUILD_MODNAME
238238
"grant still in use by backend\n");
239239
BUG();
240240
}
241-
gnttab_end_foreign_access(shadow->gref[i], 0, 0UL);
242241
}
243242

244243
kfree(shadow->sg);

drivers/usb/host/xen-hcd.c

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -716,8 +716,9 @@ static int xenhcd_map_urb_for_request(struct xenhcd_info *info, struct urb *urb,
716716
return 0;
717717
}
718718

719-
static void xenhcd_gnttab_done(struct usb_shadow *shadow)
719+
static void xenhcd_gnttab_done(struct xenhcd_info *info, unsigned int id)
720720
{
721+
struct usb_shadow *shadow = info->shadow + id;
721722
int nr_segs = 0;
722723
int i;
723724

@@ -726,8 +727,10 @@ static void xenhcd_gnttab_done(struct usb_shadow *shadow)
726727
if (xenusb_pipeisoc(shadow->req.pipe))
727728
nr_segs += shadow->req.u.isoc.nr_frame_desc_segs;
728729

729-
for (i = 0; i < nr_segs; i++)
730-
gnttab_end_foreign_access(shadow->req.seg[i].gref, 0, 0UL);
730+
for (i = 0; i < nr_segs; i++) {
731+
if (!gnttab_try_end_foreign_access(shadow->req.seg[i].gref))
732+
xenhcd_set_error(info, "backend didn't release grant");
733+
}
731734

732735
shadow->req.nr_buffer_segs = 0;
733736
shadow->req.u.isoc.nr_frame_desc_segs = 0;
@@ -841,7 +844,9 @@ static void xenhcd_cancel_all_enqueued_urbs(struct xenhcd_info *info)
841844
list_for_each_entry_safe(urbp, tmp, &info->in_progress_list, list) {
842845
req_id = urbp->req_id;
843846
if (!urbp->unlinked) {
844-
xenhcd_gnttab_done(&info->shadow[req_id]);
847+
xenhcd_gnttab_done(info, req_id);
848+
if (info->error)
849+
return;
845850
if (urbp->urb->status == -EINPROGRESS)
846851
/* not dequeued */
847852
xenhcd_giveback_urb(info, urbp->urb,
@@ -942,8 +947,7 @@ static int xenhcd_urb_request_done(struct xenhcd_info *info)
942947
rp = info->urb_ring.sring->rsp_prod;
943948
if (RING_RESPONSE_PROD_OVERFLOW(&info->urb_ring, rp)) {
944949
xenhcd_set_error(info, "Illegal index on urb-ring");
945-
spin_unlock_irqrestore(&info->lock, flags);
946-
return 0;
950+
goto err;
947951
}
948952
rmb(); /* ensure we see queued responses up to "rp" */
949953

@@ -952,11 +956,13 @@ static int xenhcd_urb_request_done(struct xenhcd_info *info)
952956
id = res.id;
953957
if (id >= XENUSB_URB_RING_SIZE) {
954958
xenhcd_set_error(info, "Illegal data on urb-ring");
955-
continue;
959+
goto err;
956960
}
957961

958962
if (likely(xenusb_pipesubmit(info->shadow[id].req.pipe))) {
959-
xenhcd_gnttab_done(&info->shadow[id]);
963+
xenhcd_gnttab_done(info, id);
964+
if (info->error)
965+
goto err;
960966
urb = info->shadow[id].urb;
961967
if (likely(urb)) {
962968
urb->actual_length = res.actual_length;
@@ -978,6 +984,10 @@ static int xenhcd_urb_request_done(struct xenhcd_info *info)
978984
spin_unlock_irqrestore(&info->lock, flags);
979985

980986
return more_to_do;
987+
988+
err:
989+
spin_unlock_irqrestore(&info->lock, flags);
990+
return 0;
981991
}
982992

983993
static int xenhcd_conn_notify(struct xenhcd_info *info)

0 commit comments

Comments
 (0)