| From a8893cfbe73fda6d9eceb84d651818ef14df8e8a Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Wed, 22 Jan 2025 18:02:44 +0000 |
| Subject: net: rose: fix timer races against user threads |
| |
| From: Eric Dumazet <edumazet@google.com> |
| |
| [ Upstream commit 5de7665e0a0746b5ad7943554b34db8f8614a196 ] |
| |
| Rose timers only acquire the socket spinlock, without |
| checking if the socket is owned by one user thread. |
| |
| Add a check and rearm the timers if needed. |
| |
| BUG: KASAN: slab-use-after-free in rose_timer_expiry+0x31d/0x360 net/rose/rose_timer.c:174 |
| Read of size 2 at addr ffff88802f09b82a by task swapper/0/0 |
| |
| CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Not tainted 6.13.0-rc5-syzkaller-00172-gd1bf27c4e176 #0 |
| Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 09/13/2024 |
| Call Trace: |
| <IRQ> |
| __dump_stack lib/dump_stack.c:94 [inline] |
| dump_stack_lvl+0x241/0x360 lib/dump_stack.c:120 |
| print_address_description mm/kasan/report.c:378 [inline] |
| print_report+0x169/0x550 mm/kasan/report.c:489 |
| kasan_report+0x143/0x180 mm/kasan/report.c:602 |
| rose_timer_expiry+0x31d/0x360 net/rose/rose_timer.c:174 |
| call_timer_fn+0x187/0x650 kernel/time/timer.c:1793 |
| expire_timers kernel/time/timer.c:1844 [inline] |
| __run_timers kernel/time/timer.c:2418 [inline] |
| __run_timer_base+0x66a/0x8e0 kernel/time/timer.c:2430 |
| run_timer_base kernel/time/timer.c:2439 [inline] |
| run_timer_softirq+0xb7/0x170 kernel/time/timer.c:2449 |
| handle_softirqs+0x2d4/0x9b0 kernel/softirq.c:561 |
| __do_softirq kernel/softirq.c:595 [inline] |
| invoke_softirq kernel/softirq.c:435 [inline] |
| __irq_exit_rcu+0xf7/0x220 kernel/softirq.c:662 |
| irq_exit_rcu+0x9/0x30 kernel/softirq.c:678 |
| instr_sysvec_apic_timer_interrupt arch/x86/kernel/apic/apic.c:1049 [inline] |
| sysvec_apic_timer_interrupt+0xa6/0xc0 arch/x86/kernel/apic/apic.c:1049 |
| </IRQ> |
| |
| Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") |
| Reported-by: syzbot <syzkaller@googlegroups.com> |
| Signed-off-by: Eric Dumazet <edumazet@google.com> |
| Link: https://patch.msgid.link/20250122180244.1861468-1-edumazet@google.com |
| Signed-off-by: Jakub Kicinski <kuba@kernel.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| net/rose/rose_timer.c | 15 +++++++++++++++ |
| 1 file changed, 15 insertions(+) |
| |
| diff --git a/net/rose/rose_timer.c b/net/rose/rose_timer.c |
| index f06ddbed3fed6..1525773e94aa1 100644 |
| --- a/net/rose/rose_timer.c |
| +++ b/net/rose/rose_timer.c |
| @@ -122,6 +122,10 @@ static void rose_heartbeat_expiry(struct timer_list *t) |
| struct rose_sock *rose = rose_sk(sk); |
| |
| bh_lock_sock(sk); |
| + if (sock_owned_by_user(sk)) { |
| + sk_reset_timer(sk, &sk->sk_timer, jiffies + HZ/20); |
| + goto out; |
| + } |
| switch (rose->state) { |
| case ROSE_STATE_0: |
| /* Magic here: If we listen() and a new link dies before it |
| @@ -152,6 +156,7 @@ static void rose_heartbeat_expiry(struct timer_list *t) |
| } |
| |
| rose_start_heartbeat(sk); |
| +out: |
| bh_unlock_sock(sk); |
| sock_put(sk); |
| } |
| @@ -162,6 +167,10 @@ static void rose_timer_expiry(struct timer_list *t) |
| struct sock *sk = &rose->sock; |
| |
| bh_lock_sock(sk); |
| + if (sock_owned_by_user(sk)) { |
| + sk_reset_timer(sk, &rose->timer, jiffies + HZ/20); |
| + goto out; |
| + } |
| switch (rose->state) { |
| case ROSE_STATE_1: /* T1 */ |
| case ROSE_STATE_4: /* T2 */ |
| @@ -182,6 +191,7 @@ static void rose_timer_expiry(struct timer_list *t) |
| } |
| break; |
| } |
| +out: |
| bh_unlock_sock(sk); |
| sock_put(sk); |
| } |
| @@ -192,6 +202,10 @@ static void rose_idletimer_expiry(struct timer_list *t) |
| struct sock *sk = &rose->sock; |
| |
| bh_lock_sock(sk); |
| + if (sock_owned_by_user(sk)) { |
| + sk_reset_timer(sk, &rose->idletimer, jiffies + HZ/20); |
| + goto out; |
| + } |
| rose_clear_queues(sk); |
| |
| rose_write_internal(sk, ROSE_CLEAR_REQUEST); |
| @@ -207,6 +221,7 @@ static void rose_idletimer_expiry(struct timer_list *t) |
| sk->sk_state_change(sk); |
| sock_set_flag(sk, SOCK_DEAD); |
| } |
| +out: |
| bh_unlock_sock(sk); |
| sock_put(sk); |
| } |
| -- |
| 2.39.5 |
| |