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

Configure Feed

Select the types of activity you want to include in your feed.

xen/scsifront: harden driver against malicious backend

Instead of relying on a well behaved PV scsi backend verify all meta
data received from the backend and avoid multiple reads of the same
data from the shared ring page.

In case any illegal data from the backend is detected switch the
PV device to a new "error" state and deactivate it for further use.

Use the "lateeoi" variant for the event channel in order to avoid
event storms blocking the guest.

Signed-off-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Link: https://lore.kernel.org/r/20220428075323.12853-5-jgross@suse.com
Signed-off-by: Juergen Gross <jgross@suse.com>

+77 -29
+77 -29
drivers/scsi/xen-scsifront.c
··· 83 83 uint16_t rqid; 84 84 uint16_t ref_rqid; 85 85 86 + bool inflight; 87 + 86 88 unsigned int nr_grants; /* number of grants in gref[] */ 87 89 struct scsiif_request_segment *sg; /* scatter/gather elements */ 88 90 struct scsiif_request_segment seg[VSCSIIF_SG_TABLESIZE]; ··· 106 104 struct xenbus_device *dev; 107 105 108 106 struct Scsi_Host *host; 109 - int host_active; 107 + enum { 108 + STATE_INACTIVE, 109 + STATE_ACTIVE, 110 + STATE_ERROR 111 + } host_active; 110 112 111 113 unsigned int evtchn; 112 114 unsigned int irq; ··· 223 217 for (i = 0; i < (shadow->nr_segments & ~VSCSIIF_SG_GRANT); i++) 224 218 ring_req->seg[i] = shadow->seg[i]; 225 219 220 + shadow->inflight = true; 221 + 226 222 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(ring, notify); 227 223 if (notify) 228 224 notify_remote_via_irq(info->irq); 229 225 230 226 return 0; 227 + } 228 + 229 + static void scsifront_set_error(struct vscsifrnt_info *info, const char *msg) 230 + { 231 + shost_printk(KERN_ERR, info->host, KBUILD_MODNAME "%s\n" 232 + "Disabling device for further use\n", msg); 233 + info->host_active = STATE_ERROR; 231 234 } 232 235 233 236 static void scsifront_gnttab_done(struct vscsifrnt_info *info, ··· 249 234 250 235 for (i = 0; i < shadow->nr_grants; i++) { 251 236 if (unlikely(!gnttab_try_end_foreign_access(shadow->gref[i]))) { 252 - shost_printk(KERN_ALERT, info->host, KBUILD_MODNAME 253 - "grant still in use by backend\n"); 254 - BUG(); 237 + scsifront_set_error(info, "grant still in use by backend"); 238 + return; 255 239 } 256 240 } 257 241 ··· 322 308 BUG_ON(sc == NULL); 323 309 324 310 scsifront_gnttab_done(info, shadow); 311 + if (info->host_active == STATE_ERROR) 312 + return; 325 313 scsifront_put_rqid(info, id); 326 314 327 315 set_host_byte(sc, scsifront_host_byte(ring_rsp->rslt)); ··· 364 348 scsifront_wake_up(info); 365 349 return; 366 350 default: 367 - shost_printk(KERN_ERR, info->host, KBUILD_MODNAME 368 - "bad reset state %d, possibly leaking %u\n", 369 - shadow->rslt_reset, id); 351 + scsifront_set_error(info, "bad reset state"); 370 352 break; 371 353 } 372 354 spin_unlock_irqrestore(&info->shadow_lock, flags); ··· 375 361 static void scsifront_do_response(struct vscsifrnt_info *info, 376 362 struct vscsiif_response *ring_rsp) 377 363 { 378 - if (WARN(ring_rsp->rqid >= VSCSIIF_MAX_REQS || 379 - test_bit(ring_rsp->rqid, info->shadow_free_bitmap), 380 - "illegal rqid %u returned by backend!\n", ring_rsp->rqid)) 381 - return; 364 + struct vscsifrnt_shadow *shadow; 382 365 383 - if (info->shadow[ring_rsp->rqid]->act == VSCSIIF_ACT_SCSI_CDB) 366 + if (ring_rsp->rqid >= VSCSIIF_MAX_REQS || 367 + !info->shadow[ring_rsp->rqid]->inflight) { 368 + scsifront_set_error(info, "illegal rqid returned by backend!"); 369 + return; 370 + } 371 + shadow = info->shadow[ring_rsp->rqid]; 372 + shadow->inflight = false; 373 + 374 + if (shadow->act == VSCSIIF_ACT_SCSI_CDB) 384 375 scsifront_cdb_cmd_done(info, ring_rsp); 385 376 else 386 377 scsifront_sync_cmd_done(info, ring_rsp); 387 378 } 388 379 389 - static int scsifront_ring_drain(struct vscsifrnt_info *info) 380 + static int scsifront_ring_drain(struct vscsifrnt_info *info, 381 + unsigned int *eoiflag) 390 382 { 391 - struct vscsiif_response *ring_rsp; 383 + struct vscsiif_response ring_rsp; 392 384 RING_IDX i, rp; 393 385 int more_to_do = 0; 394 386 395 - rp = info->ring.sring->rsp_prod; 396 - rmb(); /* ordering required respective to dom0 */ 387 + rp = READ_ONCE(info->ring.sring->rsp_prod); 388 + virt_rmb(); /* ordering required respective to backend */ 389 + if (RING_RESPONSE_PROD_OVERFLOW(&info->ring, rp)) { 390 + scsifront_set_error(info, "illegal number of responses"); 391 + return 0; 392 + } 397 393 for (i = info->ring.rsp_cons; i != rp; i++) { 398 - ring_rsp = RING_GET_RESPONSE(&info->ring, i); 399 - scsifront_do_response(info, ring_rsp); 394 + RING_COPY_RESPONSE(&info->ring, i, &ring_rsp); 395 + scsifront_do_response(info, &ring_rsp); 396 + if (info->host_active == STATE_ERROR) 397 + return 0; 398 + *eoiflag &= ~XEN_EOI_FLAG_SPURIOUS; 400 399 } 401 400 402 401 info->ring.rsp_cons = i; ··· 422 395 return more_to_do; 423 396 } 424 397 425 - static int scsifront_cmd_done(struct vscsifrnt_info *info) 398 + static int scsifront_cmd_done(struct vscsifrnt_info *info, 399 + unsigned int *eoiflag) 426 400 { 427 401 int more_to_do; 428 402 unsigned long flags; 429 403 430 404 spin_lock_irqsave(info->host->host_lock, flags); 431 405 432 - more_to_do = scsifront_ring_drain(info); 406 + more_to_do = scsifront_ring_drain(info, eoiflag); 433 407 434 408 info->wait_ring_available = 0; 435 409 ··· 444 416 static irqreturn_t scsifront_irq_fn(int irq, void *dev_id) 445 417 { 446 418 struct vscsifrnt_info *info = dev_id; 419 + unsigned int eoiflag = XEN_EOI_FLAG_SPURIOUS; 447 420 448 - while (scsifront_cmd_done(info)) 421 + if (info->host_active == STATE_ERROR) { 422 + xen_irq_lateeoi(irq, XEN_EOI_FLAG_SPURIOUS); 423 + return IRQ_HANDLED; 424 + } 425 + 426 + while (scsifront_cmd_done(info, &eoiflag)) 449 427 /* Yield point for this unbounded loop. */ 450 428 cond_resched(); 429 + 430 + xen_irq_lateeoi(irq, eoiflag); 451 431 452 432 return IRQ_HANDLED; 453 433 } 454 434 455 435 static void scsifront_finish_all(struct vscsifrnt_info *info) 456 436 { 457 - unsigned i; 437 + unsigned int i, dummy; 458 438 struct vscsiif_response resp; 459 439 460 - scsifront_ring_drain(info); 440 + scsifront_ring_drain(info, &dummy); 461 441 462 442 for (i = 0; i < VSCSIIF_MAX_REQS; i++) { 463 443 if (test_bit(i, info->shadow_free_bitmap)) ··· 622 586 unsigned long flags; 623 587 int err; 624 588 589 + if (info->host_active == STATE_ERROR) 590 + return SCSI_MLQUEUE_HOST_BUSY; 591 + 625 592 sc->result = 0; 626 593 627 594 shadow->sc = sc; ··· 676 637 struct vscsifrnt_info *info = shost_priv(host); 677 638 struct vscsifrnt_shadow *shadow, *s = scsi_cmd_priv(sc); 678 639 int err = 0; 640 + 641 + if (info->host_active == STATE_ERROR) 642 + return FAILED; 679 643 680 644 shadow = kzalloc(sizeof(*shadow), GFP_NOIO); 681 645 if (!shadow) ··· 750 708 { 751 709 struct vscsifrnt_info *info = shost_priv(sdev->host); 752 710 int err; 711 + 712 + if (info->host_active == STATE_ERROR) 713 + return -EIO; 753 714 754 715 if (info && current == info->curr) { 755 716 err = xenbus_printf(XBT_NIL, info->dev->nodename, ··· 829 784 goto free_gnttab; 830 785 } 831 786 832 - err = bind_evtchn_to_irq(info->evtchn); 787 + err = bind_evtchn_to_irq_lateeoi(info->evtchn); 833 788 if (err <= 0) { 834 789 xenbus_dev_fatal(dev, err, "bind_evtchn_to_irq"); 835 790 goto free_gnttab; ··· 959 914 goto free_sring; 960 915 } 961 916 info->host = host; 962 - info->host_active = 1; 917 + info->host_active = STATE_ACTIVE; 963 918 964 919 xenbus_switch_state(dev, XenbusStateInitialised); 965 920 ··· 1027 982 pr_debug("%s: %s removed\n", __func__, dev->nodename); 1028 983 1029 984 mutex_lock(&scsifront_mutex); 1030 - if (info->host_active) { 985 + if (info->host_active != STATE_INACTIVE) { 1031 986 /* Scsi_host not yet removed */ 1032 987 scsi_remove_host(info->host); 1033 - info->host_active = 0; 988 + info->host_active = STATE_INACTIVE; 1034 989 } 1035 990 mutex_unlock(&scsifront_mutex); 1036 991 ··· 1054 1009 */ 1055 1010 1056 1011 mutex_lock(&scsifront_mutex); 1057 - if (info->host_active) { 1012 + if (info->host_active != STATE_INACTIVE) { 1058 1013 scsi_remove_host(host); 1059 - info->host_active = 0; 1014 + info->host_active = STATE_INACTIVE; 1060 1015 } 1061 1016 mutex_unlock(&scsifront_mutex); 1062 1017 ··· 1073 1028 unsigned int device_state; 1074 1029 unsigned int hst, chn, tgt, lun; 1075 1030 struct scsi_device *sdev; 1031 + 1032 + if (info->host_active == STATE_ERROR) 1033 + return; 1076 1034 1077 1035 dir = xenbus_directory(XBT_NIL, dev->otherend, "vscsi-devs", &dir_n); 1078 1036 if (IS_ERR(dir))