Skip to content

Commit abf1fd5

Browse files
committed
xen/blkfront: don't use gnttab_query_foreign_access() for mapped status
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 <[email protected]> Signed-off-by: Juergen Gross <[email protected]> Reviewed-by: Roger Pau Monné <[email protected]> --- V2: - use gnttab_try_end_foreign_access() V4: - use alloc_pages_exact() and free_pages_exact() - set state to error if backend didn't unmap (Roger Pau Monné)
1 parent 6b1775f commit abf1fd5

File tree

1 file changed

+37
-26
lines changed

1 file changed

+37
-26
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);

0 commit comments

Comments
 (0)