CVE-2017-8062: Improper Restriction of Operations within the Bounds of a Memory Buffer (CWE-119)
value: drivers/media/usb/dvb-usb/dw2102.c in the Linux kernel 4.9.x and 4.10.x before 4.10.4 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/dw2102.c
Commit date: 2017-03-06 09:36:47 -0300
Commit message: [media] dw2102: don't do DMA on stack

On Kernel 4.9, WARNINGs about doing DMA on stack are hit at
the dw2102 driver: one in su3000_power_ctrl() and the other in tt_s2_4600_frontend_attach().

Both were due to the use of buffers on the stack as parameters to
dvb_usb_generic_rw() and the resulting attempt to do DMA with them.

The device was non-functional as a result.

So, switch this driver over to use a buffer within the device state
structure, as has been done with other DVB-USB drivers.

Tested with TechnoTrend TT-connect S2-4600.

[mchehab@osg.samsung.com: fixed a warning at su3000_i2c_transfer() that
 state var were dereferenced before check 'd']
Signed-off-by: Jonathan McDowell <noodles@earth.li>
Cc: <stable@vger.kernel.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>

Diff: diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c
index 6ca502d834b4..4f42d57f81d9 100644
--- a/drivers/media/usb/dvb-usb/dw2102.c
+++ b/drivers/media/usb/dvb-usb/dw2102.c
@@ -66,10 +66,11 @@
 		"on firmware-problems."
 
 struct dw2102_state {
 	u8 initialized;
 	u8 last_lock;
+	u8 data[MAX_XFER_SIZE + 4];
 	struct i2c_client *i2c_client_demod;
 	struct i2c_client *i2c_client_tuner;
 
 	/* fe hook functions*/
 	int (*old_set_voltage)(struct dvb_frontend *f, enum fe_sec_voltage v);
@@ -659,66 +660,76 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 
 static int su3000_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 								int num)
 {
 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
-	u8 obuf[0x40], ibuf[0x40];
+	struct dw2102_state *state;
 
 	if (!d)
 		return -ENODEV;
+
+	state = d->priv;
+
 	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
 		return -EAGAIN;
+	if (mutex_lock_interruptible(&d->data_mutex) < 0) {
+		mutex_unlock(&d->i2c_mutex);
+		return -EAGAIN;
+	}
 
 	switch (num) {
 	case 1:
 		switch (msg[0].addr) {
 		case SU3000_STREAM_CTRL:
-			obuf[0] = msg[0].buf[0] + 0x36;
-			obuf[1] = 3;
-			obuf[2] = 0;
-			if (dvb_usb_generic_rw(d, obuf, 3, ibuf, 0, 0) < 0)
+			state->data[0] = msg[0].buf[0] + 0x36;
+			state->data[1] = 3;
+			state->data[2] = 0;
+			if (dvb_usb_generic_rw(d, state->data, 3,
+					state->data, 0, 0) < 0)
 				err("i2c transfer failed.");
 			break;
 		case DW2102_RC_QUERY:
-			obuf[0] = 0x10;
-			if (dvb_usb_generic_rw(d, obuf, 1, ibuf, 2, 0) < 0)
+			state->data[0] = 0x10;
+			if (dvb_usb_generic_rw(d, state->data, 1,
+					state->data, 2, 0) < 0)
 				err("i2c transfer failed.");
-			msg[0].buf[1] = ibuf[0];
-			msg[0].buf[0] = ibuf[1];
+			msg[0].buf[1] = state->data[0];
+			msg[0].buf[0] = state->data[1];
 			break;
 		default:
 			/* always i2c write*/
-			obuf[0] = 0x08;
-			obuf[1] = msg[0].addr;
-			obuf[2] = msg[0].len;
+			state->data[0] = 0x08;
+			state->data[1] = msg[0].addr;
+			state->data[2] = msg[0].len;
 
-			memcpy(&obuf[3], msg[0].buf, msg[0].len);
+			memcpy(&state->data[3], msg[0].buf, msg[0].len);
 
-			if (dvb_usb_generic_rw(d, obuf, msg[0].len + 3,
-						ibuf, 1, 0) < 0)
+			if (dvb_usb_generic_rw(d, state->data, msg[0].len + 3,
+						state->data, 1, 0) < 0)
 				err("i2c transfer failed.");
 
 		}
 		break;
 	case 2:
 		/* always i2c read */
-		obuf[0] = 0x09;
-		obuf[1] = msg[0].len;
-		obuf[2] = msg[1].len;
-		obuf[3] = msg[0].addr;
-		memcpy(&obuf[4], msg[0].buf, msg[0].len);
-
-		if (dvb_usb_generic_rw(d, obuf, msg[0].len + 4,
-					ibuf, msg[1].len + 1, 0) < 0)
+		state->data[0] = 0x09;
+		state->data[1] = msg[0].len;
+		state->data[2] = msg[1].len;
+		state->data[3] = msg[0].addr;
+		memcpy(&state->data[4], msg[0].buf, msg[0].len);
+
+		if (dvb_usb_generic_rw(d, state->data, msg[0].len + 4,
+					state->data, msg[1].len + 1, 0) < 0)
 			err("i2c transfer failed.");
 
-		memcpy(msg[1].buf, &ibuf[1], msg[1].len);
+		memcpy(msg[1].buf, &state->data[1], msg[1].len);
 		break;
 	default:
 		warn("more than 2 i2c messages at a time is not handled yet.");
 		break;
 	}
+	mutex_unlock(&d->data_mutex);
 	mutex_unlock(&d->i2c_mutex);
 	return num;
 }
 
 static u32 dw210x_i2c_func(struct i2c_adapter *adapter)
@@ -842,21 +853,27 @@ static int su3000_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 }
 
 static int su3000_power_ctrl(struct dvb_usb_device *d, int i)
 {
 	struct dw2102_state *state = (struct dw2102_state *)d->priv;
-	u8 obuf[] = {0xde, 0};
+	int ret = 0;
 
 	info("%s: %d, initialized %d", __func__, i, state->initialized);
 
 	if (i && !state->initialized) {
+		mutex_lock(&d->data_mutex);
+
+		state->data[0] = 0xde;
+		state->data[1] = 0;
+
 		state->initialized = 1;
 		/* reset board */
-		return dvb_usb_generic_rw(d, obuf, 2, NULL, 0, 0);
+		ret = dvb_usb_generic_rw(d, state->data, 2, NULL, 0, 0);
+		mutex_unlock(&d->data_mutex);
 	}
 
-	return 0;
+	return ret;
 }
 
 static int su3000_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
 {
 	int i;
@@ -1307,128 +1324,151 @@ static int prof_7500_frontend_attach(struct dvb_usb_adapter *d)
 	info("Attached STV0900+STB6100A!");
 
 	return 0;
 }
 
-static int su3000_frontend_attach(struct dvb_usb_adapter *d)
+static int su3000_frontend_attach(struct dvb_usb_adapter *adap)
 {
-	u8 obuf[3] = { 0xe, 0x80, 0 };
-	u8 ibuf[] = { 0 };
+	struct dvb_usb_device *d = adap->dev;
+	struct dw2102_state *state = d->priv;
+
+	mutex_lock(&d->data_mutex);
+
+	state->data[0] = 0xe;
+	state->data[1] = 0x80;
+	state->data[2] = 0;
 
-	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
+	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
 		err("command 0x0e transfer failed.");
 
-	obuf[0] = 0xe;
-	obuf[1] = 0x02;
-	obuf[2] = 1;
+	state->data[0] = 0xe;
+	state->data[1] = 0x02;
+	state->data[2] = 1;
 
-	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
+	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
 		err("command 0x0e transfer failed.");
 	msleep(300);
 
-	obuf[0] = 0xe;
-	obuf[1] = 0x83;
-	obuf[2] = 0;
+	state->data[0] = 0xe;
+	state->data[1] = 0x83;
+	state->data[2] = 0;
 
-	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
+	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
 		err("command 0x0e transfer failed.");
 
-	obuf[0] = 0xe;
-	obuf[1] = 0x83;
-	obuf[2] = 1;
+	state->data[0] = 0xe;
+	state->data[1] = 0x83;
+	state->data[2] = 1;
 
-	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
+	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
 		err("command 0x0e transfer failed.");
 
-	obuf[0] = 0x51;
+	state->data[0] = 0x51;
 
-	if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0)
+	if (dvb_usb_generic_rw(d, state->data, 1, state->data, 1, 0) < 0)
 		err("command 0x51 transfer failed.");
 
-	d->fe_adap[0].fe = dvb_attach(ds3000_attach, &su3000_ds3000_config,
-					&d->dev->i2c_adap);
-	if (d->fe_adap[0].fe == NULL)
+	mutex_unlock(&d->data_mutex);
+
+	adap->fe_adap[0].fe = dvb_attach(ds3000_attach, &su3000_ds3000_config,
+					&d->i2c_adap);
+	if (adap->fe_adap[0].fe == NULL)
 		return -EIO;
 
-	if (dvb_attach(ts2020_attach, d->fe_adap[0].fe,
+	if (dvb_attach(ts2020_attach, adap->fe_adap[0].fe,
 				&dw2104_ts2020_config,
-				&d->dev->i2c_adap)) {
+				&d->i2c_adap)) {
 		info("Attached DS3000/TS2020!");
 		return 0;
 	}
 
 	info("Failed to attach DS3000/TS2020!");
 	return -EIO;
 }
 
-static int t220_frontend_attach(struct dvb_usb_adapter *d)
+static int t220_frontend_attach(struct dvb_usb_adapter *adap)
 {
-	u8 obuf[3] = { 0xe, 0x87, 0 };
-	u8 ibuf[] = { 0 };
+	struct dvb_usb_device *d = adap->dev;
+	struct dw2102_state *state = d->priv;
+
+	mutex_lock(&d->data_mutex);
 
-	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
+	state->data[0] = 0xe;
+	state->data[1] = 0x87;
+	state->data[2] = 0x0;
+
+	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
 		err("command 0x0e transfer failed.");
 
-	obuf[0] = 0xe;
-	obuf[1] = 0x86;
-	obuf[2] = 1;
+	state->data[0] = 0xe;
+	state->data[1] = 0x86;
+	state->data[2] = 1;
 
-	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
+	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
 		err("command 0x0e transfer failed.");
 
-	obuf[0] = 0xe;
-	obuf[1] = 0x80;
-	obuf[2] = 0;
+	state->data[0] = 0xe;
+	state->data[1] = 0x80;
+	state->data[2] = 0;
 
-	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
+	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
 		err("command 0x0e transfer failed.");
 
 	msleep(50);
 
-	obuf[0] = 0xe;
-	obuf[1] = 0x80;
-	obuf[2] = 1;
+	state->data[0] = 0xe;
+	state->data[1] = 0x80;
+	state->data[2] = 1;
 
-	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
+	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
 		err("command 0x0e transfer failed.");
 
-	obuf[0] = 0x51;
+	state->data[0] = 0x51;
 
-	if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0)
+	if (dvb_usb_generic_rw(d, state->data, 1, state->data, 1, 0) < 0)
 		err("command 0x51 transfer failed.");
 
-	d->fe_adap[0].fe = dvb_attach(cxd2820r_attach, &cxd2820r_config,
-					&d->dev->i2c_adap, NULL);
-	if (d->fe_adap[0].fe != NULL) {
-		if (dvb_attach(tda18271_attach, d->fe_adap[0].fe, 0x60,
-					&d->dev->i2c_adap, &tda18271_config)) {
+	mutex_unlock(&d->data_mutex);
+
+	adap->fe_adap[0].fe = dvb_attach(cxd2820r_attach, &cxd2820r_config,
+					&d->i2c_adap, NULL);
+	if (adap->fe_adap[0].fe != NULL) {
+		if (dvb_attach(tda18271_attach, adap->fe_adap[0].fe, 0x60,
+					&d->i2c_adap, &tda18271_config)) {
 			info("Attached TDA18271HD/CXD2820R!");
 			return 0;
 		}
 	}
 
 	info("Failed to attach TDA18271HD/CXD2820R!");
 	return -EIO;
 }
 
-static int m88rs2000_frontend_attach(struct dvb_usb_adapter *d)
+static int m88rs2000_frontend_attach(struct dvb_usb_adapter *adap)
 {
-	u8 obuf[] = { 0x51 };
-	u8 ibuf[] = { 0 };
+	struct dvb_usb_device *d = adap->dev;
+	struct dw2102_state *state = d->priv;
+
+	mutex_lock(&d->data_mutex);
 
-	if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0)
+	state->data[0] = 0x51;
+
+	if (dvb_usb_generic_rw(d, state->data, 1, state->data, 1, 0) < 0)
 		err("command 0x51 transfer failed.");
 
-	d->fe_adap[0].fe = dvb_attach(m88rs2000_attach, &s421_m88rs2000_config,
-					&d->dev->i2c_adap);
+	mutex_unlock(&d->data_mutex);
 
-	if (d->fe_adap[0].fe == NULL)
+	adap->fe_adap[0].fe = dvb_attach(m88rs2000_attach,
+					&s421_m88rs2000_config,
+					&d->i2c_adap);
+
+	if (adap->fe_adap[0].fe == NULL)
 		return -EIO;
 
-	if (dvb_attach(ts2020_attach, d->fe_adap[0].fe,
+	if (dvb_attach(ts2020_attach, adap->fe_adap[0].fe,
 				&dw2104_ts2020_config,
-				&d->dev->i2c_adap)) {
+				&d->i2c_adap)) {
 		info("Attached RS2000/TS2020!");
 		return 0;
 	}
 
 	info("Failed to attach RS2000/TS2020!");
@@ -1437,48 +1477,54 @@ static int m88rs2000_frontend_attach(struct dvb_usb_adapter *d)
 
 static int tt_s2_4600_frontend_attach(struct dvb_usb_adapter *adap)
 {
 	struct dvb_usb_device *d = adap->dev;
 	struct dw2102_state *state = d->priv;
-	u8 obuf[3] = { 0xe, 0x80, 0 };
-	u8 ibuf[] = { 0 };
 	struct i2c_adapter *i2c_adapter;
 	struct i2c_client *client;
 	struct i2c_board_info board_info;
 	struct m88ds3103_platform_data m88ds3103_pdata = {};
 	struct ts2020_config ts2020_config = {};
 
-	if (dvb_usb_generic_rw(d, obuf, 3, ibuf, 1, 0) < 0)
+	mutex_lock(&d->data_mutex);
+
+	state->data[0] = 0xe;
+	state->data[1] = 0x80;
+	state->data[2] = 0x0;
+
+	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
 		err("command 0x0e transfer failed.");
 
-	obuf[0] = 0xe;
-	obuf[1] = 0x02;
-	obuf[2] = 1;
+	state->data[0] = 0xe;
+	state->data[1] = 0x02;
+	state->data[2] = 1;
 
-	if (dvb_usb_generic_rw(d, obuf, 3, ibuf, 1, 0) < 0)
+	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
 		err("command 0x0e transfer failed.");
 	msleep(300);
 
-	obuf[0] = 0xe;
-	obuf[1] = 0x83;
-	obuf[2] = 0;
+	state->data[0] = 0xe;
+	state->data[1] = 0x83;
+	state->data[2] = 0;
 
-	if (dvb_usb_generic_rw(d, obuf, 3, ibuf, 1, 0) < 0)
+	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
 		err("command 0x0e transfer failed.");
 
-	obuf[0] = 0xe;
-	obuf[1] = 0x83;
-	obuf[2] = 1;
+	state->data[0] = 0xe;
+	state->data[1] = 0x83;
+	state->data[2] = 1;
 
-	if (dvb_usb_generic_rw(d, obuf, 3, ibuf, 1, 0) < 0)
+	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
 		err("command 0x0e transfer failed.");
 
-	obuf[0] = 0x51;
+	state->data[0] = 0x51;
 
-	if (dvb_usb_generic_rw(d, obuf, 1, ibuf, 1, 0) < 0)
+	if (dvb_usb_generic_rw(d, state->data, 1, state->data, 1, 0) < 0)
 		err("command 0x51 transfer failed.");
 
+	mutex_unlock(&d->data_mutex);
+
 	/* attach demod */
 	m88ds3103_pdata.clk = 27000000;
 	m88ds3103_pdata.i2c_wr_max = 33;
 	m88ds3103_pdata.ts_mode = M88DS3103_TS_CI;
 	m88ds3103_pdata.ts_clk = 16000;

Vulnerable code: 	u8 obuf[0x40], ibuf[0x40];
			obuf[0] = msg[0].buf[0] + 0x36;
			obuf[1] = 3;
			obuf[2] = 0;
			if (dvb_usb_generic_rw(d, obuf, 3, ibuf, 0, 0) < 0)
			obuf[0] = 0x10;
			if (dvb_usb_generic_rw(d, obuf, 1, ibuf, 2, 0) < 0)
			msg[0].buf[1] = ibuf[0];
			msg[0].buf[0] = ibuf[1];
			obuf[0] = 0x08;
			obuf[1] = msg[0].addr;
			obuf[2] = msg[0].len;
			memcpy(&obuf[3], msg[0].buf, msg[0].len);
			if (dvb_usb_generic_rw(d, obuf, msg[0].len + 3,
						ibuf, 1, 0) < 0)
		obuf[0] = 0x09;
		obuf[1] = msg[0].len;
		obuf[2] = msg[1].len;
		obuf[3] = msg[0].addr;
		memcpy(&obuf[4], msg[0].buf, msg[0].len);

		if (dvb_usb_generic_rw(d, obuf, msg[0].len + 4,
					ibuf, msg[1].len + 1, 0) < 0)
		memcpy(msg[1].buf, &ibuf[1], msg[1].len);
	u8 obuf[] = {0xde, 0};
		return dvb_usb_generic_rw(d, obuf, 2, NULL, 0, 0);
	return 0;
static int su3000_frontend_attach(struct dvb_usb_adapter *d)
	u8 obuf[3] = { 0xe, 0x80, 0 };
	u8 ibuf[] = { 0 };
	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
	obuf[0] = 0xe;
	obuf[1] = 0x02;
	obuf[2] = 1;
	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
	obuf[0] = 0xe;
	obuf[1] = 0x83;
	obuf[2] = 0;
	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
	obuf[0] = 0xe;
	obuf[1] = 0x83;
	obuf[2] = 1;
	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
	obuf[0] = 0x51;
	if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0)
	d->fe_adap[0].fe = dvb_attach(ds3000_attach, &su3000_ds3000_config,
					&d->dev->i2c_adap);
	if (d->fe_adap[0].fe == NULL)
	if (dvb_attach(ts2020_attach, d->fe_adap[0].fe,
				&d->dev->i2c_adap)) {
static int t220_frontend_attach(struct dvb_usb_adapter *d)
	u8 obuf[3] = { 0xe, 0x87, 0 };
	u8 ibuf[] = { 0 };
	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
	obuf[0] = 0xe;
	obuf[1] = 0x86;
	obuf[2] = 1;
	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
	obuf[0] = 0xe;
	obuf[1] = 0x80;
	obuf[2] = 0;
	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
	obuf[0] = 0xe;
	obuf[1] = 0x80;
	obuf[2] = 1;
	if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
	obuf[0] = 0x51;
	if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0)
	d->fe_adap[0].fe = dvb_attach(cxd2820r_attach, &cxd2820r_config,
					&d->dev->i2c_adap, NULL);
	if (d->fe_adap[0].fe != NULL) {
		if (dvb_attach(tda18271_attach, d->fe_adap[0].fe, 0x60,
					&d->dev->i2c_adap, &tda18271_config)) {
static int m88rs2000_frontend_attach(struct dvb_usb_adapter *d)
	u8 obuf[] = { 0x51 };
	u8 ibuf[] = { 0 };
	if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0)
	d->fe_adap[0].fe = dvb_attach(m88rs2000_attach, &s421_m88rs2000_config,
					&d->dev->i2c_adap);
	if (d->fe_adap[0].fe == NULL)
	if (dvb_attach(ts2020_attach, d->fe_adap[0].fe,
				&d->dev->i2c_adap)) {
	u8 obuf[3] = { 0xe, 0x80, 0 };
	u8 ibuf[] = { 0 };
	if (dvb_usb_generic_rw(d, obuf, 3, ibuf, 1, 0) < 0)
	obuf[0] = 0xe;
	obuf[1] = 0x02;
	obuf[2] = 1;
	if (dvb_usb_generic_rw(d, obuf, 3, ibuf, 1, 0) < 0)
	obuf[0] = 0xe;
	obuf[1] = 0x83;
	obuf[2] = 0;
	if (dvb_usb_generic_rw(d, obuf, 3, ibuf, 1, 0) < 0)
	obuf[0] = 0xe;
	obuf[1] = 0x83;
	obuf[2] = 1;
	if (dvb_usb_generic_rw(d, obuf, 3, ibuf, 1, 0) < 0)
	obuf[0] = 0x51;
	if (dvb_usb_generic_rw(d, obuf, 1, ibuf, 1, 0) < 0)
Fixed code: 	u8 data[MAX_XFER_SIZE + 4];
	struct dw2102_state *state;

	state = d->priv;

	if (mutex_lock_interruptible(&d->data_mutex) < 0) {
		mutex_unlock(&d->i2c_mutex);
		return -EAGAIN;
	}
			state->data[0] = msg[0].buf[0] + 0x36;
			state->data[1] = 3;
			state->data[2] = 0;
			if (dvb_usb_generic_rw(d, state->data, 3,
					state->data, 0, 0) < 0)
			state->data[0] = 0x10;
			if (dvb_usb_generic_rw(d, state->data, 1,
					state->data, 2, 0) < 0)
			msg[0].buf[1] = state->data[0];
			msg[0].buf[0] = state->data[1];
			state->data[0] = 0x08;
			state->data[1] = msg[0].addr;
			state->data[2] = msg[0].len;
			memcpy(&state->data[3], msg[0].buf, msg[0].len);
			if (dvb_usb_generic_rw(d, state->data, msg[0].len + 3,
						state->data, 1, 0) < 0)
		state->data[0] = 0x09;
		state->data[1] = msg[0].len;
		state->data[2] = msg[1].len;
		state->data[3] = msg[0].addr;
		memcpy(&state->data[4], msg[0].buf, msg[0].len);

		if (dvb_usb_generic_rw(d, state->data, msg[0].len + 4,
					state->data, msg[1].len + 1, 0) < 0)
		memcpy(msg[1].buf, &state->data[1], msg[1].len);
	mutex_unlock(&d->data_mutex);
	int ret = 0;
		mutex_lock(&d->data_mutex);

		state->data[0] = 0xde;
		state->data[1] = 0;

		ret = dvb_usb_generic_rw(d, state->data, 2, NULL, 0, 0);
		mutex_unlock(&d->data_mutex);
	return ret;
static int su3000_frontend_attach(struct dvb_usb_adapter *adap)
	struct dvb_usb_device *d = adap->dev;
	struct dw2102_state *state = d->priv;

	mutex_lock(&d->data_mutex);

	state->data[0] = 0xe;
	state->data[1] = 0x80;
	state->data[2] = 0;
	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
	state->data[0] = 0xe;
	state->data[1] = 0x02;
	state->data[2] = 1;
	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
	state->data[0] = 0xe;
	state->data[1] = 0x83;
	state->data[2] = 0;
	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
	state->data[0] = 0xe;
	state->data[1] = 0x83;
	state->data[2] = 1;
	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
	state->data[0] = 0x51;
	if (dvb_usb_generic_rw(d, state->data, 1, state->data, 1, 0) < 0)
	mutex_unlock(&d->data_mutex);

	adap->fe_adap[0].fe = dvb_attach(ds3000_attach, &su3000_ds3000_config,
					&d->i2c_adap);
	if (adap->fe_adap[0].fe == NULL)
	if (dvb_attach(ts2020_attach, adap->fe_adap[0].fe,
				&d->i2c_adap)) {
static int t220_frontend_attach(struct dvb_usb_adapter *adap)
	struct dvb_usb_device *d = adap->dev;
	struct dw2102_state *state = d->priv;

	mutex_lock(&d->data_mutex);
	state->data[0] = 0xe;
	state->data[1] = 0x87;
	state->data[2] = 0x0;

	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
	state->data[0] = 0xe;
	state->data[1] = 0x86;
	state->data[2] = 1;
	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
	state->data[0] = 0xe;
	state->data[1] = 0x80;
	state->data[2] = 0;
	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
	state->data[0] = 0xe;
	state->data[1] = 0x80;
	state->data[2] = 1;
	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
	state->data[0] = 0x51;
	if (dvb_usb_generic_rw(d, state->data, 1, state->data, 1, 0) < 0)
	mutex_unlock(&d->data_mutex);

	adap->fe_adap[0].fe = dvb_attach(cxd2820r_attach, &cxd2820r_config,
					&d->i2c_adap, NULL);
	if (adap->fe_adap[0].fe != NULL) {
		if (dvb_attach(tda18271_attach, adap->fe_adap[0].fe, 0x60,
					&d->i2c_adap, &tda18271_config)) {
static int m88rs2000_frontend_attach(struct dvb_usb_adapter *adap)
	struct dvb_usb_device *d = adap->dev;
	struct dw2102_state *state = d->priv;

	mutex_lock(&d->data_mutex);
	state->data[0] = 0x51;

	if (dvb_usb_generic_rw(d, state->data, 1, state->data, 1, 0) < 0)
	mutex_unlock(&d->data_mutex);
	adap->fe_adap[0].fe = dvb_attach(m88rs2000_attach,
					&s421_m88rs2000_config,
					&d->i2c_adap);

	if (adap->fe_adap[0].fe == NULL)
	if (dvb_attach(ts2020_attach, adap->fe_adap[0].fe,
				&d->i2c_adap)) {
	mutex_lock(&d->data_mutex);

	state->data[0] = 0xe;
	state->data[1] = 0x80;
	state->data[2] = 0x0;

	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
	state->data[0] = 0xe;
	state->data[1] = 0x02;
	state->data[2] = 1;
	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
	state->data[0] = 0xe;
	state->data[1] = 0x83;
	state->data[2] = 0;
	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
	state->data[0] = 0xe;
	state->data[1] = 0x83;
	state->data[2] = 1;
	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
	state->data[0] = 0x51;
	if (dvb_usb_generic_rw(d, state->data, 1, state->data, 1, 0) < 0)
	mutex_unlock(&d->data_mutex);