diff mbox

endless loop in futex code since commit 00b73d8d1b71

Message ID 20170502131148.xyob4eswy7ayxwok@aurel32.net (mailing list archive)
State New, archived
Headers show

Commit Message

Aurelien Jarno May 2, 2017, 1:11 p.m. UTC
On 2017-05-02 12:25, Aurelien Jarno wrote:
> Hi,
> 
> Commit 00b73d8d1b71 ("sh: add working futex atomic ops on userspace
> addresses for smp") introduce a loop over the atomic code used in
> futex_atomic_op_inuser. On a SH7751R based machine (actually QEMU
> emulated), therefore using the futex-irq.h code, this causes a deadlock:
> 
>     [   40.092000] NMI watchdog: BUG: soft lockup - CPU#0 stuck for 23s! [rsyslogd:401]
>     [   40.092000] Modules linked in:
>     [   40.092000]
>     [   40.092000] CPU: 0 PID: 401 Comm: rsyslogd Not tainted 4.8.5 #18
>     [   40.092000] task: 8fed96c0 task.stack: 8ec56000
>     [   40.092000] PC is at arch_local_save_flags+0x0/0x8
>     [   40.092000] PR is at do_futex+0x5d6/0x8d4
>     [   40.092000] PC  : 8c0128c8 SP  : 8ec57ec0 SR  : 40008001 TEA : 295b3cc0
>     [   40.092000] R0  : 00000000 R1  : 80000000 R2  : 00000001 R3  : 8c0128c8
>     [   40.092000] R4  : 00000000 R5  : 8c0128d0 R6  : 00a3bbb9 R7  : 00000001
>     [   40.092000] R8  : ffffffff R9  : 00000000 R10 : 00000000 R11 : 00000000
>     [   40.092000] R12 : 00473878 R13 : 00000000 R14 : 8ec57ec0
>     [   40.092000] MACH: 00000000 MACL: 47ae147b GBR : 295784d0 PR  : 8c0819ae
>     [   40.092000]
>     [   40.092000] Call trace:
>     [   40.092000]  [<8c07c654>] clockevents_program_event+0x88/0x1b4
>     [   40.092000]  [<8c06fa94>] hrtimer_interrupt+0xa0/0x1a0
>     [   40.092000]  [<8c07d348>] tick_program_event+0x0/0x90
>     [   40.092000]  [<8c04dbfc>] pick_next_task_fair+0x190/0x1f0
>     [   40.092000]  [<8c081d24>] SyS_futex+0x78/0x154
>     [   40.092000]  [<8c52c864>] handle_tlbmiss+0x90/0x140
>     [   40.092000]  [<8c018242>] syscall_call+0x18/0x1e
>     [   40.092000]  [<8c081cac>] SyS_futex+0x0/0x154
>     [   40.092000]
>     [   40.092000] Code:
>     [   40.092000]   8c0128c2:  .word 0x8c63
>     [   40.092000]   8c0128c4:  add       #76, r1
>     [   40.092000]   8c0128c6:  .word 0x8c5e
>     [   40.092000] ->8c0128c8:  stc       sr, r0
>     [   40.092000]   8c0128ca:  and       #-16, r0
>     [   40.092000]   8c0128cc:  rts
>     [   40.092000]   8c0128ce:  nop
>     [   40.092000]   8c0128d0:  mov.w     8c0128f0 <arch_local_irq_restore+0x20/0x24>, r1  ! 000000f0 <0xf0>
>     [   40.092000]   8c0128d2:  cmp/eq    r1, r4
>     [   40.092000]
> 
> The deadlock happens in the FUTEX_OP_SET case, with oparg = 0 and
> *uaddr = 1. In that case oldval = 0, so newval is not written to *uaddr
> and prev get set to 1. It means that the while condition prev != oldval
> is always true, leading to an endless loop.
> 
> The previous code didn't have this while loop. It looks like something
> is wrong somewhere in the new code. Any idea?

I guess that the problem doesn't happen on an SMP system as the other
CPU has a chance to modify this value. The following patch fixes the
issue:

From: Aurelien Jarno <aurelien@aurel32.net>
Date: Tue, 2 May 2017 13:00:12 +0000
Subject: [PATCH] sh: fix futex FUTEX_OP_SET op on userspace addresses

Commit 00b73d8d1b71 ("sh: add working futex atomic ops on userspace
addresses for smp") changed the futex_atomic_op_inuser function to
use a loop. In case of the FUTEX_OP_SET op with a userspace address
containing a value different of 0, this loop is an endless loop.

Fix that by loading the value of oldval from the userspace before doing
the cmpxchg op, also for the FUTEX_OP_SET case.

Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
---
 arch/sh/include/asm/futex.h | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

Comments

dalias@libc.org May 2, 2017, 4:23 p.m. UTC | #1
On Tue, May 02, 2017 at 03:11:48PM +0200, Aurelien Jarno wrote:
> On 2017-05-02 12:25, Aurelien Jarno wrote:
> > Hi,
> > 
> > Commit 00b73d8d1b71 ("sh: add working futex atomic ops on userspace
> > addresses for smp") introduce a loop over the atomic code used in
> > futex_atomic_op_inuser. On a SH7751R based machine (actually QEMU
> > emulated), therefore using the futex-irq.h code, this causes a deadlock:
> > 
> >     [   40.092000] NMI watchdog: BUG: soft lockup - CPU#0 stuck for 23s! [rsyslogd:401]
> >     [   40.092000] Modules linked in:
> >     [   40.092000]
> >     [   40.092000] CPU: 0 PID: 401 Comm: rsyslogd Not tainted 4.8.5 #18
> >     [   40.092000] task: 8fed96c0 task.stack: 8ec56000
> >     [   40.092000] PC is at arch_local_save_flags+0x0/0x8
> >     [   40.092000] PR is at do_futex+0x5d6/0x8d4
> >     [   40.092000] PC  : 8c0128c8 SP  : 8ec57ec0 SR  : 40008001 TEA : 295b3cc0
> >     [   40.092000] R0  : 00000000 R1  : 80000000 R2  : 00000001 R3  : 8c0128c8
> >     [   40.092000] R4  : 00000000 R5  : 8c0128d0 R6  : 00a3bbb9 R7  : 00000001
> >     [   40.092000] R8  : ffffffff R9  : 00000000 R10 : 00000000 R11 : 00000000
> >     [   40.092000] R12 : 00473878 R13 : 00000000 R14 : 8ec57ec0
> >     [   40.092000] MACH: 00000000 MACL: 47ae147b GBR : 295784d0 PR  : 8c0819ae
> >     [   40.092000]
> >     [   40.092000] Call trace:
> >     [   40.092000]  [<8c07c654>] clockevents_program_event+0x88/0x1b4
> >     [   40.092000]  [<8c06fa94>] hrtimer_interrupt+0xa0/0x1a0
> >     [   40.092000]  [<8c07d348>] tick_program_event+0x0/0x90
> >     [   40.092000]  [<8c04dbfc>] pick_next_task_fair+0x190/0x1f0
> >     [   40.092000]  [<8c081d24>] SyS_futex+0x78/0x154
> >     [   40.092000]  [<8c52c864>] handle_tlbmiss+0x90/0x140
> >     [   40.092000]  [<8c018242>] syscall_call+0x18/0x1e
> >     [   40.092000]  [<8c081cac>] SyS_futex+0x0/0x154
> >     [   40.092000]
> >     [   40.092000] Code:
> >     [   40.092000]   8c0128c2:  .word 0x8c63
> >     [   40.092000]   8c0128c4:  add       #76, r1
> >     [   40.092000]   8c0128c6:  .word 0x8c5e
> >     [   40.092000] ->8c0128c8:  stc       sr, r0
> >     [   40.092000]   8c0128ca:  and       #-16, r0
> >     [   40.092000]   8c0128cc:  rts
> >     [   40.092000]   8c0128ce:  nop
> >     [   40.092000]   8c0128d0:  mov.w     8c0128f0 <arch_local_irq_restore+0x20/0x24>, r1  ! 000000f0 <0xf0>
> >     [   40.092000]   8c0128d2:  cmp/eq    r1, r4
> >     [   40.092000]
> > 
> > The deadlock happens in the FUTEX_OP_SET case, with oparg = 0 and
> > *uaddr = 1. In that case oldval = 0, so newval is not written to *uaddr
> > and prev get set to 1. It means that the while condition prev != oldval
> > is always true, leading to an endless loop.
> > 
> > The previous code didn't have this while loop. It looks like something
> > is wrong somewhere in the new code. Any idea?
> 
> I guess that the problem doesn't happen on an SMP system as the other
> CPU has a chance to modify this value. The following patch fixes the
> issue:
> 
> From: Aurelien Jarno <aurelien@aurel32.net>
> Date: Tue, 2 May 2017 13:00:12 +0000
> Subject: [PATCH] sh: fix futex FUTEX_OP_SET op on userspace addresses
> 
> Commit 00b73d8d1b71 ("sh: add working futex atomic ops on userspace
> addresses for smp") changed the futex_atomic_op_inuser function to
> use a loop. In case of the FUTEX_OP_SET op with a userspace address
> containing a value different of 0, this loop is an endless loop.
> 
> Fix that by loading the value of oldval from the userspace before doing
> the cmpxchg op, also for the FUTEX_OP_SET case.
> 
> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
> ---
>  arch/sh/include/asm/futex.h | 5 +----
>  1 file changed, 1 insertion(+), 4 deletions(-)
> 
> diff --git a/arch/sh/include/asm/futex.h b/arch/sh/include/asm/futex.h
> index d0078747d308..8e26e0ddc872 100644
> --- a/arch/sh/include/asm/futex.h
> +++ b/arch/sh/include/asm/futex.h
> @@ -45,10 +45,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
>  	pagefault_disable();
>  
>  	do {
> -		if (op == FUTEX_OP_SET)
> -			ret = oldval = 0;
> -		else
> -			ret = get_user(oldval, uaddr);
> +		ret = get_user(oldval, uaddr);
>  
>  		if (ret) break;
>  

This looks correct. Looks like I just missed the "optimization" of
skipping the load of the old value in the FUTEX_OP_SET case.

Rich
--
To unsubscribe from this list: send the line "unsubscribe linux-sh" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Aurelien Jarno May 15, 2017, 12:40 p.m. UTC | #2
On 2017-05-02 12:23, Rich Felker wrote:
> On Tue, May 02, 2017 at 03:11:48PM +0200, Aurelien Jarno wrote:
> > On 2017-05-02 12:25, Aurelien Jarno wrote:
> > > Hi,
> > > 
> > > Commit 00b73d8d1b71 ("sh: add working futex atomic ops on userspace
> > > addresses for smp") introduce a loop over the atomic code used in
> > > futex_atomic_op_inuser. On a SH7751R based machine (actually QEMU
> > > emulated), therefore using the futex-irq.h code, this causes a deadlock:
> > > 
> > >     [   40.092000] NMI watchdog: BUG: soft lockup - CPU#0 stuck for 23s! [rsyslogd:401]
> > >     [   40.092000] Modules linked in:
> > >     [   40.092000]
> > >     [   40.092000] CPU: 0 PID: 401 Comm: rsyslogd Not tainted 4.8.5 #18
> > >     [   40.092000] task: 8fed96c0 task.stack: 8ec56000
> > >     [   40.092000] PC is at arch_local_save_flags+0x0/0x8
> > >     [   40.092000] PR is at do_futex+0x5d6/0x8d4
> > >     [   40.092000] PC  : 8c0128c8 SP  : 8ec57ec0 SR  : 40008001 TEA : 295b3cc0
> > >     [   40.092000] R0  : 00000000 R1  : 80000000 R2  : 00000001 R3  : 8c0128c8
> > >     [   40.092000] R4  : 00000000 R5  : 8c0128d0 R6  : 00a3bbb9 R7  : 00000001
> > >     [   40.092000] R8  : ffffffff R9  : 00000000 R10 : 00000000 R11 : 00000000
> > >     [   40.092000] R12 : 00473878 R13 : 00000000 R14 : 8ec57ec0
> > >     [   40.092000] MACH: 00000000 MACL: 47ae147b GBR : 295784d0 PR  : 8c0819ae
> > >     [   40.092000]
> > >     [   40.092000] Call trace:
> > >     [   40.092000]  [<8c07c654>] clockevents_program_event+0x88/0x1b4
> > >     [   40.092000]  [<8c06fa94>] hrtimer_interrupt+0xa0/0x1a0
> > >     [   40.092000]  [<8c07d348>] tick_program_event+0x0/0x90
> > >     [   40.092000]  [<8c04dbfc>] pick_next_task_fair+0x190/0x1f0
> > >     [   40.092000]  [<8c081d24>] SyS_futex+0x78/0x154
> > >     [   40.092000]  [<8c52c864>] handle_tlbmiss+0x90/0x140
> > >     [   40.092000]  [<8c018242>] syscall_call+0x18/0x1e
> > >     [   40.092000]  [<8c081cac>] SyS_futex+0x0/0x154
> > >     [   40.092000]
> > >     [   40.092000] Code:
> > >     [   40.092000]   8c0128c2:  .word 0x8c63
> > >     [   40.092000]   8c0128c4:  add       #76, r1
> > >     [   40.092000]   8c0128c6:  .word 0x8c5e
> > >     [   40.092000] ->8c0128c8:  stc       sr, r0
> > >     [   40.092000]   8c0128ca:  and       #-16, r0
> > >     [   40.092000]   8c0128cc:  rts
> > >     [   40.092000]   8c0128ce:  nop
> > >     [   40.092000]   8c0128d0:  mov.w     8c0128f0 <arch_local_irq_restore+0x20/0x24>, r1  ! 000000f0 <0xf0>
> > >     [   40.092000]   8c0128d2:  cmp/eq    r1, r4
> > >     [   40.092000]
> > > 
> > > The deadlock happens in the FUTEX_OP_SET case, with oparg = 0 and
> > > *uaddr = 1. In that case oldval = 0, so newval is not written to *uaddr
> > > and prev get set to 1. It means that the while condition prev != oldval
> > > is always true, leading to an endless loop.
> > > 
> > > The previous code didn't have this while loop. It looks like something
> > > is wrong somewhere in the new code. Any idea?
> > 
> > I guess that the problem doesn't happen on an SMP system as the other
> > CPU has a chance to modify this value. The following patch fixes the
> > issue:
> > 
> > From: Aurelien Jarno <aurelien@aurel32.net>
> > Date: Tue, 2 May 2017 13:00:12 +0000
> > Subject: [PATCH] sh: fix futex FUTEX_OP_SET op on userspace addresses
> > 
> > Commit 00b73d8d1b71 ("sh: add working futex atomic ops on userspace
> > addresses for smp") changed the futex_atomic_op_inuser function to
> > use a loop. In case of the FUTEX_OP_SET op with a userspace address
> > containing a value different of 0, this loop is an endless loop.
> > 
> > Fix that by loading the value of oldval from the userspace before doing
> > the cmpxchg op, also for the FUTEX_OP_SET case.
> > 
> > Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
> > ---
> >  arch/sh/include/asm/futex.h | 5 +----
> >  1 file changed, 1 insertion(+), 4 deletions(-)
> > 
> > diff --git a/arch/sh/include/asm/futex.h b/arch/sh/include/asm/futex.h
> > index d0078747d308..8e26e0ddc872 100644
> > --- a/arch/sh/include/asm/futex.h
> > +++ b/arch/sh/include/asm/futex.h
> > @@ -45,10 +45,7 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
> >  	pagefault_disable();
> >  
> >  	do {
> > -		if (op == FUTEX_OP_SET)
> > -			ret = oldval = 0;
> > -		else
> > -			ret = get_user(oldval, uaddr);
> > +		ret = get_user(oldval, uaddr);
> >  
> >  		if (ret) break;
> >  
> 
> This looks correct. Looks like I just missed the "optimization" of
> skipping the load of the old value in the FUTEX_OP_SET case.

Thanks for your answer. What would be the way to get this patch into
Linus' tree. Should i submit it more formally?

Regards,
Aurelien
diff mbox

Patch

diff --git a/arch/sh/include/asm/futex.h b/arch/sh/include/asm/futex.h
index d0078747d308..8e26e0ddc872 100644
--- a/arch/sh/include/asm/futex.h
+++ b/arch/sh/include/asm/futex.h
@@ -45,10 +45,7 @@  static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
 	pagefault_disable();
 
 	do {
-		if (op == FUTEX_OP_SET)
-			ret = oldval = 0;
-		else
-			ret = get_user(oldval, uaddr);
+		ret = get_user(oldval, uaddr);
 
 		if (ret) break;