On 21-07-31 00:44:11, Pavel Skripkin wrote: > Syzbot reported uninit value pegasus_probe(). The problem was in missing > error handling. > > get_interrupt_interval() internally calls read_eprom_word() which can > fail in some cases. For example: failed to receive usb control message. > These cases should be handled to prevent uninit value bug, since > read_eprom_word() will not initialize passed stack variable in case of > internal failure. Well, this is most definitelly a bug. ACK! Petko > Fail log: > > BUG: KMSAN: uninit-value in get_interrupt_interval drivers/net/usb/pegasus.c:746 [inline] > BUG: KMSAN: uninit-value in pegasus_probe+0x10e7/0x4080 drivers/net/usb/pegasus.c:1152 > CPU: 1 PID: 825 Comm: kworker/1:1 Not tainted 5.12.0-rc6-syzkaller #0 > ... > Workqueue: usb_hub_wq hub_event > Call Trace: > __dump_stack lib/dump_stack.c:79 [inline] > dump_stack+0x24c/0x2e0 lib/dump_stack.c:120 > kmsan_report+0xfb/0x1e0 mm/kmsan/kmsan_report.c:118 > __msan_warning+0x5c/0xa0 mm/kmsan/kmsan_instr.c:197 > get_interrupt_interval drivers/net/usb/pegasus.c:746 [inline] > pegasus_probe+0x10e7/0x4080 drivers/net/usb/pegasus.c:1152 > .... > > Local variable ----data.i@pegasus_probe created at: > get_interrupt_interval drivers/net/usb/pegasus.c:1151 [inline] > pegasus_probe+0xe57/0x4080 drivers/net/usb/pegasus.c:1152 > get_interrupt_interval drivers/net/usb/pegasus.c:1151 [inline] > pegasus_probe+0xe57/0x4080 drivers/net/usb/pegasus.c:1152 > > Reported-and-tested-by: syzbot+02c9f70f3afae308464a@xxxxxxxxxxxxxxxxxxxxxxxxx > Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") > Signed-off-by: Pavel Skripkin <paskripkin@xxxxxxxxx> > --- > drivers/net/usb/pegasus.c | 14 +++++++++++--- > 1 file changed, 11 insertions(+), 3 deletions(-) > > diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c > index 9a907182569c..bc2dbf86496b 100644 > --- a/drivers/net/usb/pegasus.c > +++ b/drivers/net/usb/pegasus.c > @@ -735,12 +735,16 @@ static inline void disable_net_traffic(pegasus_t *pegasus) > set_registers(pegasus, EthCtrl0, sizeof(tmp), &tmp); > } > > -static inline void get_interrupt_interval(pegasus_t *pegasus) > +static inline int get_interrupt_interval(pegasus_t *pegasus) > { > u16 data; > u8 interval; > + int ret; > + > + ret = read_eprom_word(pegasus, 4, &data); > + if (ret < 0) > + return ret; > > - read_eprom_word(pegasus, 4, &data); > interval = data >> 8; > if (pegasus->usb->speed != USB_SPEED_HIGH) { > if (interval < 0x80) { > @@ -755,6 +759,8 @@ static inline void get_interrupt_interval(pegasus_t *pegasus) > } > } > pegasus->intr_interval = interval; > + > + return 0; > } > > static void set_carrier(struct net_device *net) > @@ -1149,7 +1155,9 @@ static int pegasus_probe(struct usb_interface *intf, > | NETIF_MSG_PROBE | NETIF_MSG_LINK); > > pegasus->features = usb_dev_id[dev_index].private; > - get_interrupt_interval(pegasus); > + res = get_interrupt_interval(pegasus); > + if (res) > + goto out2; > if (reset_mac(pegasus)) { > dev_err(&intf->dev, "can't reset MAC\n"); > res = -EIO; > -- > 2.32.0 > >