| From foo@baz Fri Jan 4 19:32:29 CET 2019 |
| From: Eric Dumazet <edumazet@google.com> |
| Date: Wed, 2 Jan 2019 04:24:20 -0800 |
| Subject: net/hamradio/6pack: use mod_timer() to rearm timers |
| |
| From: Eric Dumazet <edumazet@google.com> |
| |
| [ Upstream commit 202700e30740c6568b5a6943662f3829566dd533 ] |
| |
| Using del_timer() + add_timer() is generally unsafe on SMP, |
| as noticed by syzbot. Use mod_timer() instead. |
| |
| kernel BUG at kernel/time/timer.c:1136! |
| invalid opcode: 0000 [#1] PREEMPT SMP KASAN |
| CPU: 1 PID: 1026 Comm: kworker/u4:4 Not tainted 4.20.0+ #2 |
| Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 |
| Workqueue: events_unbound flush_to_ldisc |
| RIP: 0010:add_timer kernel/time/timer.c:1136 [inline] |
| RIP: 0010:add_timer+0xa81/0x1470 kernel/time/timer.c:1134 |
| Code: 4d 89 7d 40 48 c7 85 70 fe ff ff 00 00 00 00 c7 85 7c fe ff ff ff ff ff ff 48 89 85 90 fe ff ff e9 e6 f7 ff ff e8 cf 42 12 00 <0f> 0b e8 c8 42 12 00 0f 0b e8 c1 42 12 00 4c 89 bd 60 fe ff ff e9 |
| RSP: 0018:ffff8880a7fdf5a8 EFLAGS: 00010293 |
| RAX: ffff8880a7846340 RBX: dffffc0000000000 RCX: 0000000000000000 |
| RDX: 0000000000000000 RSI: ffffffff816f3ee1 RDI: ffff88808a514ff8 |
| RBP: ffff8880a7fdf760 R08: 0000000000000007 R09: ffff8880a7846c58 |
| R10: ffff8880a7846340 R11: 0000000000000000 R12: ffff88808a514ff8 |
| R13: ffff88808a514ff8 R14: ffff88808a514dc0 R15: 0000000000000030 |
| FS: 0000000000000000(0000) GS:ffff8880ae700000(0000) knlGS:0000000000000000 |
| CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 |
| CR2: 000000000061c500 CR3: 00000000994d9000 CR4: 00000000001406e0 |
| DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 |
| DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 |
| Call Trace: |
| decode_prio_command drivers/net/hamradio/6pack.c:903 [inline] |
| sixpack_decode drivers/net/hamradio/6pack.c:971 [inline] |
| sixpack_receive_buf drivers/net/hamradio/6pack.c:457 [inline] |
| sixpack_receive_buf+0xf9c/0x1470 drivers/net/hamradio/6pack.c:434 |
| tty_ldisc_receive_buf+0x164/0x1c0 drivers/tty/tty_buffer.c:465 |
| tty_port_default_receive_buf+0x114/0x190 drivers/tty/tty_port.c:38 |
| receive_buf drivers/tty/tty_buffer.c:481 [inline] |
| flush_to_ldisc+0x3b2/0x590 drivers/tty/tty_buffer.c:533 |
| process_one_work+0xd0c/0x1ce0 kernel/workqueue.c:2153 |
| worker_thread+0x143/0x14a0 kernel/workqueue.c:2296 |
| kthread+0x357/0x430 kernel/kthread.c:246 |
| ret_from_fork+0x3a/0x50 arch/x86/entry/entry_64.S:352 |
| |
| Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") |
| Signed-off-by: Eric Dumazet <edumazet@google.com> |
| Reported-by: syzbot <syzkaller@googlegroups.com> |
| Cc: Andreas Koensgen <ajk@comnets.uni-bremen.de> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/net/hamradio/6pack.c | 16 ++++------------ |
| 1 file changed, 4 insertions(+), 12 deletions(-) |
| |
| --- a/drivers/net/hamradio/6pack.c |
| +++ b/drivers/net/hamradio/6pack.c |
| @@ -523,10 +523,7 @@ static void resync_tnc(struct timer_list |
| |
| |
| /* Start resync timer again -- the TNC might be still absent */ |
| - |
| - del_timer(&sp->resync_t); |
| - sp->resync_t.expires = jiffies + SIXP_RESYNC_TIMEOUT; |
| - add_timer(&sp->resync_t); |
| + mod_timer(&sp->resync_t, jiffies + SIXP_RESYNC_TIMEOUT); |
| } |
| |
| static inline int tnc_init(struct sixpack *sp) |
| @@ -537,9 +534,7 @@ static inline int tnc_init(struct sixpac |
| |
| sp->tty->ops->write(sp->tty, &inbyte, 1); |
| |
| - del_timer(&sp->resync_t); |
| - sp->resync_t.expires = jiffies + SIXP_RESYNC_TIMEOUT; |
| - add_timer(&sp->resync_t); |
| + mod_timer(&sp->resync_t, jiffies + SIXP_RESYNC_TIMEOUT); |
| |
| return 0; |
| } |
| @@ -897,11 +892,8 @@ static void decode_prio_command(struct s |
| /* if the state byte has been received, the TNC is present, |
| so the resync timer can be reset. */ |
| |
| - if (sp->tnc_state == TNC_IN_SYNC) { |
| - del_timer(&sp->resync_t); |
| - sp->resync_t.expires = jiffies + SIXP_INIT_RESYNC_TIMEOUT; |
| - add_timer(&sp->resync_t); |
| - } |
| + if (sp->tnc_state == TNC_IN_SYNC) |
| + mod_timer(&sp->resync_t, jiffies + SIXP_INIT_RESYNC_TIMEOUT); |
| |
| sp->status1 = cmd & SIXP_PRIO_DATA_MASK; |
| } |