syzbot reports a WARNING issue as below:
usb 1-1: BOGUS control dir, pipe 80000280 doesn't match bRequestType c0 WARNING: CPU: 0 PID: 5833 at drivers/usb/core/urb.c:413 usb_submit_urb+0x1112/0x1870 drivers/usb/core/urb.c:411 Modules linked in: CPU: 0 UID: 0 PID: 5833 Comm: syz-executor411 Not tainted 6.15.0-syzkaller #0 PREEMPT(full) Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 05/07/2025 Call Trace: <TASK> usb_start_wait_urb+0x114/0x4c0 drivers/usb/core/message.c:59 usb_internal_control_msg drivers/usb/core/message.c:103 [inline] usb_control_msg+0x232/0x3e0 drivers/usb/core/message.c:154 dtv5100_i2c_msg+0x250/0x330 drivers/media/usb/dvb-usb/dtv5100.c:60 dtv5100_i2c_xfer+0x1a4/0x3c0 drivers/media/usb/dvb-usb/dtv5100.c:86 __i2c_transfer+0x871/0x2170 drivers/i2c/i2c-core-base.c:-1 i2c_transfer+0x25b/0x3a0 drivers/i2c/i2c-core-base.c:2315 i2c_transfer_buffer_flags+0x105/0x190 drivers/i2c/i2c-core-base.c:2343 i2c_master_send include/linux/i2c.h:109 [inline] i2cdev_write+0x112/0x1b0 drivers/i2c/i2c-dev.c:183 do_loop_readv_writev include/linux/uio.h:-1 [inline] vfs_writev+0x4a5/0x9a0 fs/read_write.c:1057 do_writev+0x14d/0x2d0 fs/read_write.c:1101 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xf6/0x210 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f </TASK>
The issue occurs due to insufficient validation of data passed to the USB API. In the current implementation, the dtv5100 driver expects two I2C non-zero length messages for a combined write/read request. However, when only a single message is provided, the driver incorrectly processes message of size 1, passing a read data size of zero to the dtv5100_i2c_msg function.
When usb_control_msg() is called with a PIPEOUT type and a read length of zero, a mismatch error occurs between the operation type and the expected transfer direction in function usb_submit_urb. This is the trigger for warning.
Replace usb_control_msg() with usb_control_msg_recv() and usb_control_msg_send() to rely on the USB API for proper validation and prevent inconsistencies in the future.
Reported-by: syzbot+0335df380edd9bd3ff70@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=0335df380edd9bd3ff70 Fixes: 60688d5e6e6e ("V4L/DVB (8735): dtv5100: replace dummy frontend by zl10353") Cc: stable@vger.kernel.org Signed-off-by: Nalivayko Sergey Sergey.Nalivayko@kaspersky.com --- v2: Expand problem description.
drivers/media/usb/dvb-usb/dtv5100.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-)
diff --git a/drivers/media/usb/dvb-usb/dtv5100.c b/drivers/media/usb/dvb-usb/dtv5100.c index 3d85c6f7f6ec..05860f5d5053 100644 --- a/drivers/media/usb/dvb-usb/dtv5100.c +++ b/drivers/media/usb/dvb-usb/dtv5100.c @@ -26,40 +26,37 @@ static int dtv5100_i2c_msg(struct dvb_usb_device *d, u8 addr, u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen) { struct dtv5100_state *st = d->priv; - unsigned int pipe; u8 request; u8 type; u16 value; u16 index;
+ index = (addr << 8) + wbuf[0]; + + memcpy(st->data, rbuf, rlen); + msleep(1); /* avoid I2C errors */ + switch (wlen) { case 1: /* write { reg }, read { value } */ - pipe = usb_rcvctrlpipe(d->udev, 0); request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_READ : DTV5100_TUNER_READ); type = USB_TYPE_VENDOR | USB_DIR_IN; value = 0; - break; + return usb_control_msg_recv(d->udev, 0, request, type, value, index, + st->data, rlen, DTV5100_USB_TIMEOUT, GFP_KERNEL); case 2: /* write { reg, value } */ - pipe = usb_sndctrlpipe(d->udev, 0); request = (addr == DTV5100_DEMOD_ADDR ? DTV5100_DEMOD_WRITE : DTV5100_TUNER_WRITE); type = USB_TYPE_VENDOR | USB_DIR_OUT; value = wbuf[1]; - break; + return usb_control_msg_send(d->udev, 0, request, type, value, index, + st->data, rlen, DTV5100_USB_TIMEOUT, GFP_KERNEL); default: warn("wlen = %x, aborting.", wlen); return -EINVAL; } - index = (addr << 8) + wbuf[0]; - - memcpy(st->data, rbuf, rlen); - msleep(1); /* avoid I2C errors */ - return usb_control_msg(d->udev, pipe, request, - type, value, index, st->data, rlen, - DTV5100_USB_TIMEOUT); }
/* I2C */
linux-stable-mirror@lists.linaro.org