Vulnerability: The sr_do_ioctl function in drivers/scsi/sr_ioctl.c in the Linux kernel through 4.16.12 allows local users to cause a denial of service (stack-based buffer overflow) or possibly have unspecified other impact because sense buffers have different sizes at the CDROM layer and the SCSI layer, as demonstrated by a CDROMREADMODE2 ioctl call.
Vulnerability ID: CVE-2018-11506
CWE: CWE-787
Severity score: 10
Project: https://github.com/torvalds/linux
Published: 2018-05-28
File: drivers/scsi/sr_ioctl.c
Commit message: sr: pass down correctly sized SCSI sense buffer

We're casting the CDROM layer request_sense to the SCSI sense
buffer, but the former is 64 bytes and the latter is 96 bytes.
As we generally allocate these on the stack, we end up blowing
up the stack.

Fix this by wrapping the scsi_execute() call with a properly
sized sense buffer, and copying back the bits for the CDROM
layer.

Cc: stable@vger.kernel.org
Reported-by: Piotr Gabriel Kosinski <pg.kosinski@gmail.com>
Reported-by: Daniel Shapira <daniel@twistlock.com>
Tested-by: Kees Cook <keescook@chromium.org>
Fixes: 82ed4db499b8 ("block: split scsi_request out of struct request")
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Commit author: Jens Axboe

Vulnerable version (before fix):
 int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc) 	struct scsi_device *SDev; 	struct scsi_sense_hdr sshdr; 	int result, err = 0, retries = 0;  	SDev = cd->device;        retry: 	if (!scsi_block_when_processing_errors(SDev)) { 		err = -ENODEV; 		goto out; 	}  	result = scsi_execute(SDev, cgc->cmd, cgc->data_direction, 			      cgc->buffer, cgc->buflen, 			      (unsigned char *)cgc->sense, &sshdr, 			      cgc->timeout, IOCTL_RETRIES, 0, 0, NULL);  	/* Minimal error checking.  Ignore cases we know about, and report the rest. */ 	if (driver_byte(result) != 0) { 		switch (sshdr.sense_key) {

Fixed version (after fix):
 int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc) 	struct scsi_device *SDev; 	struct scsi_sense_hdr sshdr; 	int result, err = 0, retries = 0; 	unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE], *senseptr = NULL;  	SDev = cd->device;  	if (cgc->sense) 		senseptr = sense_buffer;        retry: 	if (!scsi_block_when_processing_errors(SDev)) { 		err = -ENODEV; 		goto out; 	}  	result = scsi_execute(SDev, cgc->cmd, cgc->data_direction, 			      cgc->buffer, cgc->buflen, senseptr, &sshdr, 			      cgc->timeout, IOCTL_RETRIES, 0, 0, NULL);  	if (cgc->sense) 		memcpy(cgc->sense, sense_buffer, sizeof(*cgc->sense));  	/* Minimal error checking.  Ignore cases we know about, and report the rest. */ 	if (driver_byte(result) != 0) { 		switch (sshdr.sense_key) {

Patch:
patch: @@ -188,20 +188,26 @@ int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc)
 	struct scsi_device *SDev;
 	struct scsi_sense_hdr sshdr;
 	int result, err = 0, retries = 0;
+	unsigned char sense_buffer[SCSI_SENSE_BUFFERSIZE], *senseptr = NULL;
 
 	SDev = cd->device;
 
+	if (cgc->sense)
+		senseptr = sense_buffer;
+
       retry:
 	if (!scsi_block_when_processing_errors(SDev)) {
 		err = -ENODEV;
 		goto out;
 	}
 
 	result = scsi_execute(SDev, cgc->cmd, cgc->data_direction,
-			      cgc->buffer, cgc->buflen,
-			      (unsigned char *)cgc->sense, &sshdr,
+			      cgc->buffer, cgc->buflen, senseptr, &sshdr,
 			      cgc->timeout, IOCTL_RETRIES, 0, 0, NULL);
 
+	if (cgc->sense)
+		memcpy(cgc->sense, sense_buffer, sizeof(*cgc->sense));
+
 	/* Minimal error checking.  Ignore cases we know about, and report the rest. */
 	if (driver_byte(result) != 0) {
 		switch (sshdr.sense_key) {
path: drivers/scsi/sr_ioctl.c