drivers/media/usb/dvb-usb/dvb-usb-i2c.c | 5 +++++ 1 file changed, 5 insertions(+)
The syzbot fuzzer reported a WARNING related to the dib0700 dvb-usb
driver:
usb 1-1: BOGUS control dir, pipe 80000f80 doesn't match bRequestType c0
WARNING: CPU: 1 PID: 5901 at drivers/usb/core/urb.c:413 usb_submit_urb+0x11d9/0x18c0 drivers/usb/core/urb.c:411
...
Call Trace:
<TASK>
usb_start_wait_urb+0x113/0x520 drivers/usb/core/message.c:59
usb_internal_control_msg drivers/usb/core/message.c:103 [inline]
usb_control_msg+0x2b1/0x4c0 drivers/usb/core/message.c:154
dib0700_ctrl_rd drivers/media/usb/dvb-usb/dib0700_core.c:95 [inline]
dib0700_i2c_xfer_legacy drivers/media/usb/dvb-usb/dib0700_core.c:315 [inline]
dib0700_i2c_xfer+0xc53/0x1060 drivers/media/usb/dvb-usb/dib0700_core.c:361
__i2c_transfer+0x866/0x2220
i2c_transfer+0x271/0x3b0 drivers/i2c/i2c-core-base.c:2315
i2cdev_ioctl_rdwr+0x452/0x710 drivers/i2c/i2c-dev.c:306
i2cdev_ioctl+0x759/0x9f0 drivers/i2c/i2c-dev.c:467
vfs_ioctl fs/ioctl.c:51 [inline]
Evidently the fuzzer submitted an I2C transfer containing a length-0
read message. The dib0700 driver translated this more or less
literally into a length-0 USB read request. But the USB protocol does
not allow reads to have length 0; all length-0 transfers are
considered to be writes. Hence the WARNING above.
Fix the problem by adding the I2C_AQ_NO_ZERO_LEN_READ adapter quirk
flag to all the USB I2C adapter devices managed by dvb-usb-i2c.c,
following Wolfram Sang's suggestion. This tells the I2C core not to
allow length-0 read messages.
Reported-by: syzbot+c38e5e60d0041a99dbf5@syzkaller.appspotmail.com
Tested-by: syzbot+c38e5e60d0041a99dbf5@syzkaller.appspotmail.com
Suggested-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Link: https://lore.kernel.org/linux-usb/67e1a1f5.050a0220.a7ebc.0029.GAE@google.com/
---
Resend to the media maintainer.
v2: Move the static definition of the i2c_usb_quirks structure outside
the dvb_usb_i2c_init() function.
drivers/media/usb/dvb-usb/dvb-usb-i2c.c | 5 +++++
1 file changed, 5 insertions(+)
Index: usb-devel/drivers/media/usb/dvb-usb/dvb-usb-i2c.c
===================================================================
--- usb-devel.orig/drivers/media/usb/dvb-usb/dvb-usb-i2c.c
+++ usb-devel/drivers/media/usb/dvb-usb/dvb-usb-i2c.c
@@ -8,6 +8,10 @@
*/
#include "dvb-usb-common.h"
+static const struct i2c_adapter_quirks i2c_usb_quirks = {
+ .flags = I2C_AQ_NO_ZERO_LEN_READ,
+};
+
int dvb_usb_i2c_init(struct dvb_usb_device *d)
{
int ret = 0;
@@ -24,6 +28,7 @@ int dvb_usb_i2c_init(struct dvb_usb_devi
strscpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name));
d->i2c_adap.algo = d->props.i2c_algo;
d->i2c_adap.algo_data = NULL;
+ d->i2c_adap.quirks = &i2c_usb_quirks;
d->i2c_adap.dev.parent = &d->udev->dev;
i2c_set_adapdata(&d->i2c_adap, d);
Alan, > Fix the problem by adding the I2C_AQ_NO_ZERO_LEN_READ adapter quirk > flag to all the USB I2C adapter devices managed by dvb-usb-i2c.c, > following Wolfram Sang's suggestion. This tells the I2C core not to > allow length-0 read messages. Thank you again for fixing this issue. There are some USB-I2C bridges in drivers/i2c/busses which also do not prevent zero len reads. Would it make sense to put a protection into the I2C core? Can we reliably detect that an adapter sits on a USB (maybe via the parent device), so that we can then check if I2C_AQ_NO_ZERO_LEN_READ is set, and take action if not? Appreciating your input, Wolfram
On Fri, Mar 28, 2025 at 04:45:10PM +0100, Wolfram Sang wrote: > Alan, > > > Fix the problem by adding the I2C_AQ_NO_ZERO_LEN_READ adapter quirk > > flag to all the USB I2C adapter devices managed by dvb-usb-i2c.c, > > following Wolfram Sang's suggestion. This tells the I2C core not to > > allow length-0 read messages. > > Thank you again for fixing this issue. There are some USB-I2C bridges in > drivers/i2c/busses which also do not prevent zero len reads. Would it > make sense to put a protection into the I2C core? Can we reliably detect > that an adapter sits on a USB (maybe via the parent device), so that we > can then check if I2C_AQ_NO_ZERO_LEN_READ is set, and take action if > not? This really should be handled by someone who knows how those bridges work. In the case of dib0700, it was clear from the source code that the driver uses USB Control transfers to tell the hardware about I2C messages. I don't know if other bridges work in the same way. In theory a bridge could use USB Bulk transfers instead; they aren't subject to this restriction on length-0 reads. Or a bridge could use a Control read transfer but include extra header material along with the actual data, so that a length-0 message wouldn't end up generating a length-0 read. So the short answer is that you would need to find someone who really understands what's going on here -- which I don't. Sorry. Alan Stern
> In the case of dib0700, it was clear from the source code that the > driver uses USB Control transfers to tell the hardware about I2C > messages. I don't know if other bridges work in the same way. In > theory a bridge could use USB Bulk transfers instead; they aren't > subject to this restriction on length-0 reads. Or a bridge could use a > Control read transfer but include extra header material along with the > actual data, so that a length-0 message wouldn't end up generating a > length-0 read. Fully understood, thanks for your explanation. > So the short answer is that you would need to find someone who really > understands what's going on here -- which I don't. Sorry. No worries. There are only 5 drivers or so, I will manually check if they use a control_read and have no own header. Doesn't sound hard.
On Sat, Mar 29, 2025 at 07:05:49AM +0100, Wolfram Sang wrote: > > > In the case of dib0700, it was clear from the source code that the > > driver uses USB Control transfers to tell the hardware about I2C > > messages. I don't know if other bridges work in the same way. In > > theory a bridge could use USB Bulk transfers instead; they aren't > > subject to this restriction on length-0 reads. Or a bridge could use a > > Control read transfer but include extra header material along with the > > actual data, so that a length-0 message wouldn't end up generating a > > length-0 read. > > Fully understood, thanks for your explanation. > > > So the short answer is that you would need to find someone who really > > understands what's going on here -- which I don't. Sorry. > > No worries. There are only 5 drivers or so, I will manually check if > they use a control_read and have no own header. Doesn't sound hard. Good... Feel free to ask me if you have any questions or need any other help. Alan Stern
© 2016 - 2025 Red Hat, Inc.