CVE-2017-8061: Improper Restriction of Operations within the Bounds of a Memory Buffer (CWE-119)
value: drivers/media/usb/dvb-usb/dvb-usb-firmware.c in the Linux kernel 4.9.x and 4.10.x before 4.10.7 interacts incorrectly with the CONFIG_VMAP_STACK option, which allows local users to cause a denial of service (system crash or memory corruption) or possibly have unspecified other impact by leveraging use of more than one virtual page for a DMA scatterlist.
CWE description: The product performs operations on a memory buffer, but it reads from or writes to a memory location outside the buffer's intended boundary. This may result in read or write operations on unexpected memory locations that could be linked to other variables, data structures, or internal program data.
CVSS v3 base score: 7.8
Published: 2017-04-23T05:59Z
Repository: https://github.com/torvalds/linux
Language: C
Files changed: drivers/media/usb/dvb-usb/dvb-usb-firmware.c
Commit date: 2017-03-08 22:43:02 -0300
Commit message: [media] dvb-usb-firmware: don't do DMA on stack

The buffer allocation for the firmware data was changed in
commit 43fab9793c1f ("[media] dvb-usb: don't use stack for firmware load")
but the same applies for the reset value.

Fixes: 43fab9793c1f ("[media] dvb-usb: don't use stack for firmware load")
Cc: stable@vger.kernel.org
Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>

Diff: diff --git a/drivers/media/usb/dvb-usb/dvb-usb-firmware.c b/drivers/media/usb/dvb-usb/dvb-usb-firmware.c
index ab9866024ec7..04033efe7ad5 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb-firmware.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-firmware.c
@@ -34,20 +34,22 @@ static int usb_cypress_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 le
 }
 
 int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type)
 {
 	struct hexline *hx;
-	u8 reset;
-	int ret,pos=0;
+	u8 *buf;
+	int ret, pos = 0;
+	u16 cpu_cs_register = cypress[type].cpu_cs_register;
 
-	hx = kmalloc(sizeof(*hx), GFP_KERNEL);
-	if (!hx)
+	buf = kmalloc(sizeof(*hx), GFP_KERNEL);
+	if (!buf)
 		return -ENOMEM;
+	hx = (struct hexline *)buf;
 
 	/* stop the CPU */
-	reset = 1;
-	if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1)
+	buf[0] = 1;
+	if (usb_cypress_writemem(udev, cpu_cs_register, buf, 1) != 1)
 		err("could not stop the USB controller CPU.");
 
 	while ((ret = dvb_usb_get_hexline(fw, hx, &pos)) > 0) {
 		deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n", hx->addr, hx->len, hx->chk);
 		ret = usb_cypress_writemem(udev, hx->addr, hx->data, hx->len);
@@ -59,25 +61,25 @@ int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw
 			break;
 		}
 	}
 	if (ret < 0) {
 		err("firmware download failed at %d with %d",pos,ret);
-		kfree(hx);
+		kfree(buf);
 		return ret;
 	}
 
 	if (ret == 0) {
 		/* restart the CPU */
-		reset = 0;
-		if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1) != 1) {
+		buf[0] = 0;
+		if (usb_cypress_writemem(udev, cpu_cs_register, buf, 1) != 1) {
 			err("could not restart the USB controller CPU.");
 			ret = -EINVAL;
 		}
 	} else
 		ret = -EIO;
 
-	kfree(hx);
+	kfree(buf);
 
 	return ret;
 }
 EXPORT_SYMBOL(usb_cypress_load_firmware);
 

Vulnerable code: 	u8 reset;
	int ret,pos=0;
	hx = kmalloc(sizeof(*hx), GFP_KERNEL);
	if (!hx)
	reset = 1;
	if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1)
		kfree(hx);
		reset = 0;
		if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1) != 1) {
	kfree(hx);
Fixed code: 	u8 *buf;
	int ret, pos = 0;
	u16 cpu_cs_register = cypress[type].cpu_cs_register;
	buf = kmalloc(sizeof(*hx), GFP_KERNEL);
	if (!buf)
	hx = (struct hexline *)buf;
	buf[0] = 1;
	if (usb_cypress_writemem(udev, cpu_cs_register, buf, 1) != 1)
		kfree(buf);
		buf[0] = 0;
		if (usb_cypress_writemem(udev, cpu_cs_register, buf, 1) != 1) {
	kfree(buf);