Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

xen/blkfront: force data bouncing when backend is untrusted

Split the current bounce buffering logic used with persistent grants
into it's own option, and allow enabling it independently of
persistent grants. This allows to reuse the same code paths to
perform the bounce buffering required to avoid leaking contiguous data
in shared pages not part of the request fragments.

Reporting whether the backend is to be trusted can be done using a
module parameter, or from the xenstore frontend path as set by the
toolstack when adding the device.

This is CVE-2022-33742, part of XSA-403.

Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
Signed-off-by: Juergen Gross <jgross@suse.com>

authored by

Roger Pau Monne and committed by
Juergen Gross
2400617d 4491001c

+34 -15
+34 -15
drivers/block/xen-blkfront.c
··· 152 152 module_param_named(max_ring_page_order, xen_blkif_max_ring_order, int, 0444); 153 153 MODULE_PARM_DESC(max_ring_page_order, "Maximum order of pages to be used for the shared ring"); 154 154 155 + static bool __read_mostly xen_blkif_trusted = true; 156 + module_param_named(trusted, xen_blkif_trusted, bool, 0644); 157 + MODULE_PARM_DESC(trusted, "Is the backend trusted"); 158 + 155 159 #define BLK_RING_SIZE(info) \ 156 160 __CONST_RING_SIZE(blkif, XEN_PAGE_SIZE * (info)->nr_ring_pages) 157 161 ··· 214 210 unsigned int feature_discard:1; 215 211 unsigned int feature_secdiscard:1; 216 212 unsigned int feature_persistent:1; 213 + unsigned int bounce:1; 217 214 unsigned int discard_granularity; 218 215 unsigned int discard_alignment; 219 216 /* Number of 4KB segments handled */ ··· 315 310 if (!gnt_list_entry) 316 311 goto out_of_memory; 317 312 318 - if (info->feature_persistent) { 313 + if (info->bounce) { 319 314 granted_page = alloc_page(GFP_NOIO | __GFP_ZERO); 320 315 if (!granted_page) { 321 316 kfree(gnt_list_entry); ··· 335 330 list_for_each_entry_safe(gnt_list_entry, n, 336 331 &rinfo->grants, node) { 337 332 list_del(&gnt_list_entry->node); 338 - if (info->feature_persistent) 333 + if (info->bounce) 339 334 __free_page(gnt_list_entry->page); 340 335 kfree(gnt_list_entry); 341 336 i--; ··· 381 376 /* Assign a gref to this page */ 382 377 gnt_list_entry->gref = gnttab_claim_grant_reference(gref_head); 383 378 BUG_ON(gnt_list_entry->gref == -ENOSPC); 384 - if (info->feature_persistent) 379 + if (info->bounce) 385 380 grant_foreign_access(gnt_list_entry, info); 386 381 else { 387 382 /* Grant access to the GFN passed by the caller */ ··· 405 400 /* Assign a gref to this page */ 406 401 gnt_list_entry->gref = gnttab_claim_grant_reference(gref_head); 407 402 BUG_ON(gnt_list_entry->gref == -ENOSPC); 408 - if (!info->feature_persistent) { 403 + if (!info->bounce) { 409 404 struct page *indirect_page; 410 405 411 406 /* Fetch a pre-allocated page to use for indirect grefs */ ··· 708 703 .grant_idx = 0, 709 704 .segments = NULL, 710 705 .rinfo = rinfo, 711 - .need_copy = rq_data_dir(req) && info->feature_persistent, 706 + .need_copy = rq_data_dir(req) && info->bounce, 712 707 }; 713 708 714 709 /* ··· 986 981 { 987 982 blk_queue_write_cache(info->rq, info->feature_flush ? true : false, 988 983 info->feature_fua ? true : false); 989 - pr_info("blkfront: %s: %s %s %s %s %s\n", 984 + pr_info("blkfront: %s: %s %s %s %s %s %s %s\n", 990 985 info->gd->disk_name, flush_info(info), 991 986 "persistent grants:", info->feature_persistent ? 992 987 "enabled;" : "disabled;", "indirect descriptors:", 993 - info->max_indirect_segments ? "enabled;" : "disabled;"); 988 + info->max_indirect_segments ? "enabled;" : "disabled;", 989 + "bounce buffer:", info->bounce ? "enabled" : "disabled;"); 994 990 } 995 991 996 992 static int xen_translate_vdev(int vdevice, int *minor, unsigned int *offset) ··· 1213 1207 if (!list_empty(&rinfo->indirect_pages)) { 1214 1208 struct page *indirect_page, *n; 1215 1209 1216 - BUG_ON(info->feature_persistent); 1210 + BUG_ON(info->bounce); 1217 1211 list_for_each_entry_safe(indirect_page, n, &rinfo->indirect_pages, lru) { 1218 1212 list_del(&indirect_page->lru); 1219 1213 __free_page(indirect_page); ··· 1230 1224 NULL); 1231 1225 rinfo->persistent_gnts_c--; 1232 1226 } 1233 - if (info->feature_persistent) 1227 + if (info->bounce) 1234 1228 __free_page(persistent_gnt->page); 1235 1229 kfree(persistent_gnt); 1236 1230 } ··· 1251 1245 for (j = 0; j < segs; j++) { 1252 1246 persistent_gnt = rinfo->shadow[i].grants_used[j]; 1253 1247 gnttab_end_foreign_access(persistent_gnt->gref, NULL); 1254 - if (info->feature_persistent) 1248 + if (info->bounce) 1255 1249 __free_page(persistent_gnt->page); 1256 1250 kfree(persistent_gnt); 1257 1251 } ··· 1434 1428 data.s = s; 1435 1429 num_sg = s->num_sg; 1436 1430 1437 - if (bret->operation == BLKIF_OP_READ && info->feature_persistent) { 1431 + if (bret->operation == BLKIF_OP_READ && info->bounce) { 1438 1432 for_each_sg(s->sg, sg, num_sg, i) { 1439 1433 BUG_ON(sg->offset + sg->length > PAGE_SIZE); 1440 1434 ··· 1493 1487 * Add the used indirect page back to the list of 1494 1488 * available pages for indirect grefs. 1495 1489 */ 1496 - if (!info->feature_persistent) { 1490 + if (!info->bounce) { 1497 1491 indirect_page = s->indirect_grants[i]->page; 1498 1492 list_add(&indirect_page->lru, &rinfo->indirect_pages); 1499 1493 } ··· 1769 1763 1770 1764 if (!info) 1771 1765 return -ENODEV; 1766 + 1767 + /* Check if backend is trusted. */ 1768 + info->bounce = !xen_blkif_trusted || 1769 + !xenbus_read_unsigned(dev->nodename, "trusted", 1); 1772 1770 1773 1771 max_page_order = xenbus_read_unsigned(info->xbdev->otherend, 1774 1772 "max-ring-page-order", 0); ··· 2183 2173 if (err) 2184 2174 goto out_of_memory; 2185 2175 2186 - if (!info->feature_persistent && info->max_indirect_segments) { 2176 + if (!info->bounce && info->max_indirect_segments) { 2187 2177 /* 2188 - * We are using indirect descriptors but not persistent 2189 - * grants, we need to allocate a set of pages that can be 2178 + * We are using indirect descriptors but don't have a bounce 2179 + * buffer, we need to allocate a set of pages that can be 2190 2180 * used for mapping indirect grefs 2191 2181 */ 2192 2182 int num = INDIRECT_GREFS(grants) * BLK_RING_SIZE(info); ··· 2287 2277 info->feature_persistent = 2288 2278 !!xenbus_read_unsigned(info->xbdev->otherend, 2289 2279 "feature-persistent", 0); 2280 + if (info->feature_persistent) 2281 + info->bounce = true; 2290 2282 2291 2283 indirect_segments = xenbus_read_unsigned(info->xbdev->otherend, 2292 2284 "feature-max-indirect-segments", 0); ··· 2559 2547 { 2560 2548 struct blkfront_info *info; 2561 2549 bool need_schedule_work = false; 2550 + 2551 + /* 2552 + * Note that when using bounce buffers but not persistent grants 2553 + * there's no need to run blkfront_delay_work because grants are 2554 + * revoked in blkif_completion or else an error is reported and the 2555 + * connection is closed. 2556 + */ 2562 2557 2563 2558 mutex_lock(&blkfront_mutex); 2564 2559