Vulnerability: The dispatch_discard_io function in drivers/block/xen-blkback/blkback.c in the Xen blkback implementation in the Linux kernel before 3.10.5 allows guest OS users to cause a denial of service (data loss) via filesystem write operations on a read-only disk that supports the (1) BLKIF_OP_DISCARD (aka discard or TRIM) or (2) SCSI UNMAP feature.
Vulnerability ID: CVE-2013-2140
CWE: CWE-20
Severity score: 4.9
Project: https://github.com/torvalds/linux
Published: 2013-09-25
File: drivers/block/xen-blkback/blkback.c
Commit message: xen/blkback: Check device permissions before allowing OP_DISCARD

We need to make sure that the device is not RO or that
the request is not past the number of sectors we want to
issue the DISCARD operation for.

This fixes CVE-2013-2140.

Cc: stable@vger.kernel.org
Acked-by: Jan Beulich <JBeulich@suse.com>
Acked-by: Ian Campbell <Ian.Campbell@citrix.com>
[v1: Made it pr_warn instead of pr_debug]
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Commit author: Konrad Rzeszutek Wilk

Vulnerable version (before fix):
 static int dispatch_discard_io(struct xen_blkif *blkif, 	int status = BLKIF_RSP_OKAY; 	struct block_device *bdev = blkif->vbd.bdev; 	unsigned long secure;  	blkif->st_ds_req++;  	xen_blkif_get(blkif); static int dispatch_discard_io(struct xen_blkif *blkif, 	err = blkdev_issue_discard(bdev, req->u.discard.sector_number, 				   req->u.discard.nr_sectors, 				   GFP_KERNEL, secure);  	if (err == -EOPNOTSUPP) { 		pr_debug(DRV_PFX "discard op failed, not supported\n"); 		status = BLKIF_RSP_EOPNOTSUPP;

Fixed version (after fix):
 static int dispatch_discard_io(struct xen_blkif *blkif, 	int status = BLKIF_RSP_OKAY; 	struct block_device *bdev = blkif->vbd.bdev; 	unsigned long secure; 	struct phys_req preq;  	preq.sector_number = req->u.discard.sector_number; 	preq.nr_sects      = req->u.discard.nr_sectors;  	err = xen_vbd_translate(&preq, blkif, WRITE); 	if (err) { 		pr_warn(DRV_PFX "access denied: DISCARD [%llu->%llu] on dev=%04x\n", 			preq.sector_number, 			preq.sector_number + preq.nr_sects, blkif->vbd.pdevice); 		goto fail_response; 	} 	blkif->st_ds_req++;  	xen_blkif_get(blkif); static int dispatch_discard_io(struct xen_blkif *blkif, 	err = blkdev_issue_discard(bdev, req->u.discard.sector_number, 				   req->u.discard.nr_sectors, 				   GFP_KERNEL, secure); fail_response: 	if (err == -EOPNOTSUPP) { 		pr_debug(DRV_PFX "discard op failed, not supported\n"); 		status = BLKIF_RSP_EOPNOTSUPP;

Patch:
patch: @@ -876,7 +876,18 @@ static int dispatch_discard_io(struct xen_blkif *blkif,
 	int status = BLKIF_RSP_OKAY;
 	struct block_device *bdev = blkif->vbd.bdev;
 	unsigned long secure;
+	struct phys_req preq;
+
+	preq.sector_number = req->u.discard.sector_number;
+	preq.nr_sects      = req->u.discard.nr_sectors;
 
+	err = xen_vbd_translate(&preq, blkif, WRITE);
+	if (err) {
+		pr_warn(DRV_PFX "access denied: DISCARD [%llu->%llu] on dev=%04x\n",
+			preq.sector_number,
+			preq.sector_number + preq.nr_sects, blkif->vbd.pdevice);
+		goto fail_response;
+	}
 	blkif->st_ds_req++;
 
 	xen_blkif_get(blkif);
@@ -887,7 +898,7 @@ static int dispatch_discard_io(struct xen_blkif *blkif,
 	err = blkdev_issue_discard(bdev, req->u.discard.sector_number,
 				   req->u.discard.nr_sectors,
 				   GFP_KERNEL, secure);
-
+fail_response:
 	if (err == -EOPNOTSUPP) {
 		pr_debug(DRV_PFX "discard op failed, not supported\n");
 		status = BLKIF_RSP_EOPNOTSUPP;
path: drivers/block/xen-blkback/blkback.c