Vulnerability: Array index error in the tcm_vhost_make_tpg function in drivers/vhost/scsi.c in the Linux kernel before 4.0 might allow guest OS users to cause a denial of service (memory corruption) or possibly have unspecified other impact via a crafted VHOST_SCSI_SET_ENDPOINT ioctl call.  NOTE: the affected function was renamed to vhost_scsi_make_tpg before the vulnerability was announced.
Vulnerability ID: CVE-2015-4036
CWE: CWE-119
Severity score: 10
Project: https://github.com/torvalds/linux
Published: 2015-08-31
File: drivers/vhost/scsi.c
Commit message: vhost/scsi: potential memory corruption

This code in vhost_scsi_make_tpg() is confusing because we limit "tpgt"
to UINT_MAX but the data type of "tpg->tport_tpgt" and that is a u16.

I looked at the context and it turns out that in
vhost_scsi_set_endpoint(), "tpg->tport_tpgt" is used as an offset into
the vs_tpg[] array which has VHOST_SCSI_MAX_TARGET (256) elements so
anything higher than 255 then it is invalid.  I have made that the limit
now.

In vhost_scsi_send_evt() we mask away values higher than 255, but now
that the limit has changed, we don't need the mask.

Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Commit author: Dan Carpenter

Vulnerable version (before fix):
 vhost_scsi_send_evt(struct vhost_scsi *vs, 		 * lun[4-7] need to be zero according to virtio-scsi spec. 		 */ 		evt->event.lun[0] = 0x01; 		evt->event.lun[1] = tpg->tport_tpgt & 0xFF; 		if (lun->unpacked_lun >= 256) 			evt->event.lun[2] = lun->unpacked_lun >> 8 | 0x40 ; 		evt->event.lun[3] = lun->unpacked_lun & 0xFF; vhost_scsi_make_tpg(struct se_wwn *wwn, 			struct vhost_scsi_tport, tport_wwn);  	struct vhost_scsi_tpg *tpg; 	unsigned long tpgt; 	int ret;  	if (strstr(name, "tpgt_") != name) 		return ERR_PTR(-EINVAL); 	if (kstrtoul(name + 5, 10, &tpgt) || tpgt > UINT_MAX) 		return ERR_PTR(-EINVAL);  	tpg = kzalloc(sizeof(struct vhost_scsi_tpg), GFP_KERNEL);

Fixed version (after fix):
 vhost_scsi_send_evt(struct vhost_scsi *vs, 		 * lun[4-7] need to be zero according to virtio-scsi spec. 		 */ 		evt->event.lun[0] = 0x01; 		evt->event.lun[1] = tpg->tport_tpgt; 		if (lun->unpacked_lun >= 256) 			evt->event.lun[2] = lun->unpacked_lun >> 8 | 0x40 ; 		evt->event.lun[3] = lun->unpacked_lun & 0xFF; vhost_scsi_make_tpg(struct se_wwn *wwn, 			struct vhost_scsi_tport, tport_wwn);  	struct vhost_scsi_tpg *tpg; 	u16 tpgt; 	int ret;  	if (strstr(name, "tpgt_") != name) 		return ERR_PTR(-EINVAL); 	if (kstrtou16(name + 5, 10, &tpgt) || tpgt >= VHOST_SCSI_MAX_TARGET) 		return ERR_PTR(-EINVAL);  	tpg = kzalloc(sizeof(struct vhost_scsi_tpg), GFP_KERNEL);

Patch:
patch: @@ -1249,7 +1249,7 @@ vhost_scsi_send_evt(struct vhost_scsi *vs,
 		 * lun[4-7] need to be zero according to virtio-scsi spec.
 		 */
 		evt->event.lun[0] = 0x01;
-		evt->event.lun[1] = tpg->tport_tpgt & 0xFF;
+		evt->event.lun[1] = tpg->tport_tpgt;
 		if (lun->unpacked_lun >= 256)
 			evt->event.lun[2] = lun->unpacked_lun >> 8 | 0x40 ;
 		evt->event.lun[3] = lun->unpacked_lun & 0xFF;
@@ -2120,12 +2120,12 @@ vhost_scsi_make_tpg(struct se_wwn *wwn,
 			struct vhost_scsi_tport, tport_wwn);
 
 	struct vhost_scsi_tpg *tpg;
-	unsigned long tpgt;
+	u16 tpgt;
 	int ret;
 
 	if (strstr(name, "tpgt_") != name)
 		return ERR_PTR(-EINVAL);
-	if (kstrtoul(name + 5, 10, &tpgt) || tpgt > UINT_MAX)
+	if (kstrtou16(name + 5, 10, &tpgt) || tpgt >= VHOST_SCSI_MAX_TARGET)
 		return ERR_PTR(-EINVAL);
 
 	tpg = kzalloc(sizeof(struct vhost_scsi_tpg), GFP_KERNEL);
path: drivers/vhost/scsi.c