Skip to content

Commit 96219af

Browse files
jgross1gregkh
authored andcommitted
xen/blkfront: don't use gnttab_query_foreign_access() for mapped status
Commit abf1fd5 upstream. It isn't enough to check whether a grant is still being in use by calling gnttab_query_foreign_access(), as a mapping could be realized by the other side just after having called that function. In case the call was done in preparation of revoking a grant it is better to do so via gnttab_end_foreign_access_ref() and check the success of that operation instead. For the ring allocation use alloc_pages_exact() in order to avoid high order pages in case of a multi-page ring. If a grant wasn't unmapped by the backend without persistent grants being used, set the device state to "error". This is CVE-2022-23036 / part of XSA-396. Reported-by: Demi Marie Obenour <demi@invisiblethingslab.com> Signed-off-by: Juergen Gross <jgross@suse.com> Reviewed-by: Roger Pau Monné <roger.pau@citrix.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 3d81e85 commit 96219af

1 file changed

Lines changed: 37 additions & 26 deletions

File tree

drivers/block/xen-blkfront.c

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1352,7 +1352,8 @@ static void blkif_free_ring(struct blkfront_ring_info *rinfo)
13521352
rinfo->ring_ref[i] = GRANT_INVALID_REF;
13531353
}
13541354
}
1355-
free_pages((unsigned long)rinfo->ring.sring, get_order(info->nr_ring_pages * XEN_PAGE_SIZE));
1355+
free_pages_exact(rinfo->ring.sring,
1356+
info->nr_ring_pages * XEN_PAGE_SIZE);
13561357
rinfo->ring.sring = NULL;
13571358

13581359
if (rinfo->irq)
@@ -1436,9 +1437,15 @@ static int blkif_get_final_status(enum blk_req_status s1,
14361437
return BLKIF_RSP_OKAY;
14371438
}
14381439

1439-
static bool blkif_completion(unsigned long *id,
1440-
struct blkfront_ring_info *rinfo,
1441-
struct blkif_response *bret)
1440+
/*
1441+
* Return values:
1442+
* 1 response processed.
1443+
* 0 missing further responses.
1444+
* -1 error while processing.
1445+
*/
1446+
static int blkif_completion(unsigned long *id,
1447+
struct blkfront_ring_info *rinfo,
1448+
struct blkif_response *bret)
14421449
{
14431450
int i = 0;
14441451
struct scatterlist *sg;
@@ -1461,7 +1468,7 @@ static bool blkif_completion(unsigned long *id,
14611468

14621469
/* Wait the second response if not yet here. */
14631470
if (s2->status < REQ_DONE)
1464-
return false;
1471+
return 0;
14651472

14661473
bret->status = blkif_get_final_status(s->status,
14671474
s2->status);
@@ -1512,42 +1519,43 @@ static bool blkif_completion(unsigned long *id,
15121519
}
15131520
/* Add the persistent grant into the list of free grants */
15141521
for (i = 0; i < num_grant; i++) {
1515-
if (gnttab_query_foreign_access(s->grants_used[i]->gref)) {
1522+
if (!gnttab_try_end_foreign_access(s->grants_used[i]->gref)) {
15161523
/*
15171524
* If the grant is still mapped by the backend (the
15181525
* backend has chosen to make this grant persistent)
15191526
* we add it at the head of the list, so it will be
15201527
* reused first.
15211528
*/
1522-
if (!info->feature_persistent)
1523-
pr_alert_ratelimited("backed has not unmapped grant: %u\n",
1524-
s->grants_used[i]->gref);
1529+
if (!info->feature_persistent) {
1530+
pr_alert("backed has not unmapped grant: %u\n",
1531+
s->grants_used[i]->gref);
1532+
return -1;
1533+
}
15251534
list_add(&s->grants_used[i]->node, &rinfo->grants);
15261535
rinfo->persistent_gnts_c++;
15271536
} else {
15281537
/*
1529-
* If the grant is not mapped by the backend we end the
1530-
* foreign access and add it to the tail of the list,
1531-
* so it will not be picked again unless we run out of
1532-
* persistent grants.
1538+
* If the grant is not mapped by the backend we add it
1539+
* to the tail of the list, so it will not be picked
1540+
* again unless we run out of persistent grants.
15331541
*/
1534-
gnttab_end_foreign_access(s->grants_used[i]->gref, 0, 0UL);
15351542
s->grants_used[i]->gref = GRANT_INVALID_REF;
15361543
list_add_tail(&s->grants_used[i]->node, &rinfo->grants);
15371544
}
15381545
}
15391546
if (s->req.operation == BLKIF_OP_INDIRECT) {
15401547
for (i = 0; i < INDIRECT_GREFS(num_grant); i++) {
1541-
if (gnttab_query_foreign_access(s->indirect_grants[i]->gref)) {
1542-
if (!info->feature_persistent)
1543-
pr_alert_ratelimited("backed has not unmapped grant: %u\n",
1544-
s->indirect_grants[i]->gref);
1548+
if (!gnttab_try_end_foreign_access(s->indirect_grants[i]->gref)) {
1549+
if (!info->feature_persistent) {
1550+
pr_alert("backed has not unmapped grant: %u\n",
1551+
s->indirect_grants[i]->gref);
1552+
return -1;
1553+
}
15451554
list_add(&s->indirect_grants[i]->node, &rinfo->grants);
15461555
rinfo->persistent_gnts_c++;
15471556
} else {
15481557
struct page *indirect_page;
15491558

1550-
gnttab_end_foreign_access(s->indirect_grants[i]->gref, 0, 0UL);
15511559
/*
15521560
* Add the used indirect page back to the list of
15531561
* available pages for indirect grefs.
@@ -1562,7 +1570,7 @@ static bool blkif_completion(unsigned long *id,
15621570
}
15631571
}
15641572

1565-
return true;
1573+
return 1;
15661574
}
15671575

15681576
static irqreturn_t blkif_interrupt(int irq, void *dev_id)
@@ -1628,12 +1636,17 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
16281636
}
16291637

16301638
if (bret.operation != BLKIF_OP_DISCARD) {
1639+
int ret;
1640+
16311641
/*
16321642
* We may need to wait for an extra response if the
16331643
* I/O request is split in 2
16341644
*/
1635-
if (!blkif_completion(&id, rinfo, &bret))
1645+
ret = blkif_completion(&id, rinfo, &bret);
1646+
if (!ret)
16361647
continue;
1648+
if (unlikely(ret < 0))
1649+
goto err;
16371650
}
16381651

16391652
if (add_id_to_freelist(rinfo, id)) {
@@ -1740,8 +1753,7 @@ static int setup_blkring(struct xenbus_device *dev,
17401753
for (i = 0; i < info->nr_ring_pages; i++)
17411754
rinfo->ring_ref[i] = GRANT_INVALID_REF;
17421755

1743-
sring = (struct blkif_sring *)__get_free_pages(GFP_NOIO | __GFP_HIGH,
1744-
get_order(ring_size));
1756+
sring = alloc_pages_exact(ring_size, GFP_NOIO);
17451757
if (!sring) {
17461758
xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
17471759
return -ENOMEM;
@@ -1751,7 +1763,7 @@ static int setup_blkring(struct xenbus_device *dev,
17511763

17521764
err = xenbus_grant_ring(dev, rinfo->ring.sring, info->nr_ring_pages, gref);
17531765
if (err < 0) {
1754-
free_pages((unsigned long)sring, get_order(ring_size));
1766+
free_pages_exact(sring, ring_size);
17551767
rinfo->ring.sring = NULL;
17561768
goto fail;
17571769
}
@@ -2729,11 +2741,10 @@ static void purge_persistent_grants(struct blkfront_info *info)
27292741
list_for_each_entry_safe(gnt_list_entry, tmp, &rinfo->grants,
27302742
node) {
27312743
if (gnt_list_entry->gref == GRANT_INVALID_REF ||
2732-
gnttab_query_foreign_access(gnt_list_entry->gref))
2744+
!gnttab_try_end_foreign_access(gnt_list_entry->gref))
27332745
continue;
27342746

27352747
list_del(&gnt_list_entry->node);
2736-
gnttab_end_foreign_access(gnt_list_entry->gref, 0, 0UL);
27372748
rinfo->persistent_gnts_c--;
27382749
gnt_list_entry->gref = GRANT_INVALID_REF;
27392750
list_add_tail(&gnt_list_entry->node, &rinfo->grants);

0 commit comments

Comments
 (0)