net: pegasus: fix uninit-value in get_interrupt_interval
[ Upstream commitaf35fc3735] 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. 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@syzkaller.appspotmail.com Fixes:1da177e4c3("Linux-2.6.12-rc2") Signed-off-by: Pavel Skripkin <paskripkin@gmail.com> Link: https://lore.kernel.org/r/20210804143005.439-1-paskripkin@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
c66d273b70
commit
f12b6b6bc1
@@ -736,12 +736,16 @@ static inline void disable_net_traffic(pegasus_t *pegasus)
|
|||||||
set_registers(pegasus, EthCtrl0, sizeof(tmp), &tmp);
|
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;
|
u16 data;
|
||||||
u8 interval;
|
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;
|
interval = data >> 8;
|
||||||
if (pegasus->usb->speed != USB_SPEED_HIGH) {
|
if (pegasus->usb->speed != USB_SPEED_HIGH) {
|
||||||
if (interval < 0x80) {
|
if (interval < 0x80) {
|
||||||
@@ -756,6 +760,8 @@ static inline void get_interrupt_interval(pegasus_t *pegasus)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
pegasus->intr_interval = interval;
|
pegasus->intr_interval = interval;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_carrier(struct net_device *net)
|
static void set_carrier(struct net_device *net)
|
||||||
@@ -1150,7 +1156,9 @@ static int pegasus_probe(struct usb_interface *intf,
|
|||||||
| NETIF_MSG_PROBE | NETIF_MSG_LINK);
|
| NETIF_MSG_PROBE | NETIF_MSG_LINK);
|
||||||
|
|
||||||
pegasus->features = usb_dev_id[dev_index].private;
|
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)) {
|
if (reset_mac(pegasus)) {
|
||||||
dev_err(&intf->dev, "can't reset MAC\n");
|
dev_err(&intf->dev, "can't reset MAC\n");
|
||||||
res = -EIO;
|
res = -EIO;
|
||||||
|
|||||||
Reference in New Issue
Block a user