All of lore.kernel.org
 help / color / mirror / Atom feed
* ipc: BUG: sem_unlock unlocks non-locked lock
@ 2016-12-16  9:33 Dmitry Vyukov
  2016-12-18 16:28 ` Davidlohr Bueso
  0 siblings, 1 reply; 8+ messages in thread
From: Dmitry Vyukov @ 2016-12-16  9:33 UTC (permalink / raw)
  To: Andrew Morton, Davidlohr Bueso, Ingo Molnar, manfred,
	Peter Zijlstra, fabf, kernel, LKML
  Cc: syzkaller

Hello,

The following program causes BUG: bad unlock balance detected!

https://gist.githubusercontent.com/dvyukov/d0e5efefe4d7d6daed829f5c3ca26a40/raw/08d0a261fe3c987bed04fbf267e08ba04bd533ea/gistfile1.txt

On commit 5cc60aeedf315a7513f92e98314e86d515b986d1 (Dec 14).

[ BUG: bad unlock balance detected! ]
4.9.0+ #89 Not tainted
-------------------------------------
a.out/6330 is trying to release lock (&(&new->lock)->rlock) at:
[<ffffffff8316d150>] spin_unlock include/linux/spinlock.h:347 [inline]
[<ffffffff8316d150>] ipc_unlock_object ipc/util.h:175 [inline]
[<ffffffff8316d150>] sem_unlock ipc/sem.c:404 [inline]
[<ffffffff8316d150>] SYSC_semtimedop+0x22f0/0x4410 ipc/sem.c:2004
but there are no more locks to release!

other info that might help us debug this:
2 locks held by a.out/6330:
 #0:  (rcu_read_lock){......}, at: [<ffffffff8316c9c2>]
SYSC_semtimedop+0x1b62/0x4410 ipc/sem.c:1968
 #1:  (&(&sma->sem_base[i].lock)->rlock){+.+...}, at:
[<ffffffff8316d1e4>] spin_lock include/linux/spinlock.h:302 [inline]
 #1:  (&(&sma->sem_base[i].lock)->rlock){+.+...}, at:
[<ffffffff8316d1e4>] sem_lock ipc/sem.c:362 [inline]
 #1:  (&(&sma->sem_base[i].lock)->rlock){+.+...}, at:
[<ffffffff8316d1e4>] SYSC_semtimedop+0x2384/0x4410 ipc/sem.c:1980

stack backtrace:
CPU: 1 PID: 6330 Comm: a.out Not tainted 4.9.0+ #89
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
Call Trace:
 __dump_stack lib/dump_stack.c:15 [inline]
 dump_stack+0x2ee/0x3ef lib/dump_stack.c:51
 print_unlock_imbalance_bug+0x12f/0x140 kernel/locking/lockdep.c:3391
 __lock_release kernel/locking/lockdep.c:3533 [inline]
 lock_release+0xa21/0xf00 kernel/locking/lockdep.c:3772
 __raw_spin_unlock include/linux/spinlock_api_smp.h:152 [inline]
 _raw_spin_unlock+0x1f/0x40 kernel/locking/spinlock.c:183
 spin_unlock include/linux/spinlock.h:347 [inline]
 ipc_unlock_object ipc/util.h:175 [inline]
 sem_unlock ipc/sem.c:404 [inline]
 SYSC_semtimedop+0x22f0/0x4410 ipc/sem.c:2004
 SyS_semtimedop ipc/sem.c:1755 [inline]
 SYSC_semop ipc/sem.c:2015 [inline]
 SyS_semop+0x2b/0x40 ipc/sem.c:2012
 entry_SYSCALL_64_fastpath+0x23/0xc6
RIP: 0033:0x44dc19
RSP: 002b:00007fa18086ec88 EFLAGS: 00000206 ORIG_RAX: 0000000000000041
RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 000000000044dc19
RDX: 0000000000000001 RSI: 0000000020002ff0 RDI: 0000000000008001
RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000206 R12: 0000000000000000
R13: 0000000000000000 R14: 00007fa18086f9c0 R15: 00007fa18086f700

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: ipc: BUG: sem_unlock unlocks non-locked lock
  2016-12-16  9:33 ipc: BUG: sem_unlock unlocks non-locked lock Dmitry Vyukov
@ 2016-12-18 16:28 ` Davidlohr Bueso
  2016-12-18 16:29   ` Davidlohr Bueso
  0 siblings, 1 reply; 8+ messages in thread
From: Davidlohr Bueso @ 2016-12-18 16:28 UTC (permalink / raw)
  To: Dmitry Vyukov
  Cc: Andrew Morton, Ingo Molnar, manfred, Peter Zijlstra, fabf, kernel,
	LKML, syzkaller

On Fri, 16 Dec 2016, Dmitry Vyukov wrote:

>[ BUG: bad unlock balance detected! ]
>4.9.0+ #89 Not tainted

Thanks for the report, I can reproduce the issue as of (which I obviously
should have tested with lockdep):

370b262c896 (ipc/sem: avoid idr tree lookup for interrupted semop)

I need to think more about it this evening, but I believe the issue to be
the potentially bogus locknum in the unlock path, as we are calling sem_lock
without updating the variable. I'll send a patch after more testing. This
fixes it for me:

diff --git a/ipc/sem.c b/ipc/sem.c
index e08b94851922..fba6139e7208 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -1977,7 +1977,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
 		}
 
 		rcu_read_lock();
-		sem_lock(sma, sops, nsops);
+	        sem_lock(sma, sops, nsops);
 
 		if (!ipc_valid_object(&sma->sem_perm))
 			goto out_unlock_free;

Thanks,
Davidlohr

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: ipc: BUG: sem_unlock unlocks non-locked lock
  2016-12-18 16:28 ` Davidlohr Bueso
@ 2016-12-18 16:29   ` Davidlohr Bueso
  2016-12-18 18:32     ` Manfred Spraul
  0 siblings, 1 reply; 8+ messages in thread
From: Davidlohr Bueso @ 2016-12-18 16:29 UTC (permalink / raw)
  To: Dmitry Vyukov
  Cc: Andrew Morton, Ingo Molnar, manfred, Peter Zijlstra, fabf, kernel,
	LKML, syzkaller

On Sun, 18 Dec 2016, Bueso wrote:

>On Fri, 16 Dec 2016, Dmitry Vyukov wrote:
>
>>[ BUG: bad unlock balance detected! ]
>>4.9.0+ #89 Not tainted
>
>Thanks for the report, I can reproduce the issue as of (which I obviously
>should have tested with lockdep):
>
>370b262c896 (ipc/sem: avoid idr tree lookup for interrupted semop)
>
>I need to think more about it this evening, but I believe the issue to be
>the potentially bogus locknum in the unlock path, as we are calling sem_lock
>without updating the variable. I'll send a patch after more testing. This
>fixes it for me:
>
>diff --git a/ipc/sem.c b/ipc/sem.c
>index e08b94851922..fba6139e7208 100644
>--- a/ipc/sem.c
>+++ b/ipc/sem.c
>@@ -1977,7 +1977,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
>		}
>
>		rcu_read_lock();
>-		sem_lock(sma, sops, nsops);
>+	        sem_lock(sma, sops, nsops);

*sigh*, that would be:
	         locknum = sem_lock(sma, sops, nsops);

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: ipc: BUG: sem_unlock unlocks non-locked lock
  2016-12-18 16:29   ` Davidlohr Bueso
@ 2016-12-18 18:32     ` Manfred Spraul
  2016-12-18 18:38       ` [PATCH] ipc/sem.c: fix semop()/semop() locking failure Manfred Spraul
  2016-12-20  6:34       ` [PATCH v2] ipc/sem.c: fix incorrect sem_lock pairing Manfred Spraul
  0 siblings, 2 replies; 8+ messages in thread
From: Manfred Spraul @ 2016-12-18 18:32 UTC (permalink / raw)
  To: Davidlohr Bueso, Dmitry Vyukov
  Cc: Andrew Morton, Ingo Molnar, Peter Zijlstra, fabf, kernel, LKML,
	syzkaller

On 12/18/2016 05:29 PM, Davidlohr Bueso wrote:
> On Sun, 18 Dec 2016, Bueso wrote:
>
>> On Fri, 16 Dec 2016, Dmitry Vyukov wrote:
>>
>>> [ BUG: bad unlock balance detected! ]
>>> 4.9.0+ #89 Not tainted
>>
>> Thanks for the report, I can reproduce the issue as of (which I 
>> obviously
>> should have tested with lockdep):
>>
>> 370b262c896 (ipc/sem: avoid idr tree lookup for interrupted semop)
>>
>> I need to think more about it this evening, but I believe the issue 
>> to be
>> the potentially bogus locknum in the unlock path, as we are calling 
>> sem_lock
>> without updating the variable. I'll send a patch after more testing. 
>> This
>> fixes it for me:
>>
>> diff --git a/ipc/sem.c b/ipc/sem.c
>> index e08b94851922..fba6139e7208 100644
>> --- a/ipc/sem.c
>> +++ b/ipc/sem.c
>> @@ -1977,7 +1977,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct 
>> sembuf __user *, tsops,
>>         }
>>
>>         rcu_read_lock();
>> -        sem_lock(sma, sops, nsops);
>> +            sem_lock(sma, sops, nsops);
>
> *sigh*, that would be:
>              locknum = sem_lock(sma, sops, nsops);

Yes, I can confirm that this fixes the issue.

Reproducing is simple:

- task A: single semop semop(), sleeps
- task B: multi semop semop(), sleeps
- task A woken up by signal/timeout

I'll send a patch.

--

     Manfred

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH] ipc/sem.c: fix semop()/semop() locking failure
  2016-12-18 18:32     ` Manfred Spraul
@ 2016-12-18 18:38       ` Manfred Spraul
  2016-12-19  3:45         ` Davidlohr Bueso
  2016-12-20  6:34       ` [PATCH v2] ipc/sem.c: fix incorrect sem_lock pairing Manfred Spraul
  1 sibling, 1 reply; 8+ messages in thread
From: Manfred Spraul @ 2016-12-18 18:38 UTC (permalink / raw)
  To: LKML, Andrew Morton, Davidlohr Bueso
  Cc: 1vier1, dvyukov, mingo, peterz, fabf, kernel, syzkaller,
	Manfred Spraul

Based on the syzcaller test case from dvyukov:
https://gist.githubusercontent.com/dvyukov/d0e5efefe4d7d6daed829f5c3ca26a40/raw/08d0a261fe3c987bed04fbf267e08ba04bd533ea/gistfile1.txt

The slow (i.e.: failure to acquire) syscall exit from semtimedop()
incorrectly assumed that the the same lock is acquired as it was
at the initial syscall entry.

This is wrong:
- thread A: single semop semop(), sleeps
- thread B: multi semop semop(), sleeps
- thread A: woken up by signal/timeout

With this sequence, the initial sem_lock() call locks the
per-semaphore spinlock, the call at the syscall return locks
the global spinlock.

The fix is trivial: Use the return value from sem_lock.

Reported-by: dvyukov@google.com
Signed-off-by: Manfred Spraul <manfred@colorfullife.com>
Fixes: 370b262c896e ("ipc/sem: avoid idr tree lookup for interrupted semop")
Cc: dave@stgolabs.net
---
 ipc/sem.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ipc/sem.c b/ipc/sem.c
index e08b948..3ec5742 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -1977,7 +1977,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
 		}
 
 		rcu_read_lock();
-		sem_lock(sma, sops, nsops);
+		locknum = sem_lock(sma, sops, nsops);
 
 		if (!ipc_valid_object(&sma->sem_perm))
 			goto out_unlock_free;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH] ipc/sem.c: fix semop()/semop() locking failure
  2016-12-18 18:38       ` [PATCH] ipc/sem.c: fix semop()/semop() locking failure Manfred Spraul
@ 2016-12-19  3:45         ` Davidlohr Bueso
  2017-01-07  4:45           ` Mike Galbraith
  0 siblings, 1 reply; 8+ messages in thread
From: Davidlohr Bueso @ 2016-12-19  3:45 UTC (permalink / raw)
  To: Manfred Spraul
  Cc: LKML, Andrew Morton, 1vier1, dvyukov, mingo, peterz, fabf, kernel,
	syzkaller

Nit: the title is a bit unclear. How about:

ipc/sem.: fix semop() locking imbalance

Otherwise, Ack.

Thanks,
Davidlohr

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v2] ipc/sem.c: fix incorrect sem_lock pairing
  2016-12-18 18:32     ` Manfred Spraul
  2016-12-18 18:38       ` [PATCH] ipc/sem.c: fix semop()/semop() locking failure Manfred Spraul
@ 2016-12-20  6:34       ` Manfred Spraul
  1 sibling, 0 replies; 8+ messages in thread
From: Manfred Spraul @ 2016-12-20  6:34 UTC (permalink / raw)
  To: LKML, Andrew Morton, Davidlohr Bueso
  Cc: 1vier1, dvyukov, mingo, peterz, fabf, kernel, syzkaller,
	Manfred Spraul

Based on the syzcaller test case from dvyukov:
https://gist.githubusercontent.com/dvyukov/d0e5efefe4d7d6daed829f5c3ca26a40/raw/08d0a261fe3c987bed04fbf267e08ba04bd533ea/gistfile1.txt

The slow (i.e.: failure to acquire) syscall exit from semtimedop()
incorrectly assumed that the the same lock is acquired as it was
at the initial syscall entry.

This is wrong:
- thread A: single semop semop(), sleeps
- thread B: multi semop semop(), sleeps
- thread A: woken up by signal/timeout

With this sequence, the initial sem_lock() call locks the
per-semaphore spinlock, and it is unlocked with sem_unlock().
The call at the syscall return locks the global spinlock.
Because locknum is not updated, the following sem_unlock() call
unlocks the per-semaphore spinlock, which is actually not locked.

The fix is trivial: Use the return value from sem_lock.

Reported-by: dvyukov@google.com
Signed-off-by: Manfred Spraul <manfred@colorfullife.com>
Fixes: 370b262c896e ("ipc/sem: avoid idr tree lookup for interrupted semop")
Cc: dave@stgolabs.net

---

Patch V2:
- subject line updated
- documentation slightly updated

 ipc/sem.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ipc/sem.c b/ipc/sem.c
index e08b948..3ec5742 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -1977,7 +1977,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
 		}
 
 		rcu_read_lock();
-		sem_lock(sma, sops, nsops);
+		locknum = sem_lock(sma, sops, nsops);
 
 		if (!ipc_valid_object(&sma->sem_perm))
 			goto out_unlock_free;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH] ipc/sem.c: fix semop()/semop() locking failure
  2016-12-19  3:45         ` Davidlohr Bueso
@ 2017-01-07  4:45           ` Mike Galbraith
  0 siblings, 0 replies; 8+ messages in thread
From: Mike Galbraith @ 2017-01-07  4:45 UTC (permalink / raw)
  To: Davidlohr Bueso, Manfred Spraul
  Cc: LKML, Andrew Morton, 1vier1, dvyukov, mingo, peterz, fabf, kernel,
	syzkaller

On Sun, 2016-12-18 at 19:45 -0800, Davidlohr Bueso wrote:
> Nit: the title is a bit unclear. How about:
> 
> ipc/sem.: fix semop() locking imbalance
> 
> Otherwise, Ack.

(notices patchlet _not_ flying upstream... s/failure/imbalance?)

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2017-01-07  4:45 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-12-16  9:33 ipc: BUG: sem_unlock unlocks non-locked lock Dmitry Vyukov
2016-12-18 16:28 ` Davidlohr Bueso
2016-12-18 16:29   ` Davidlohr Bueso
2016-12-18 18:32     ` Manfred Spraul
2016-12-18 18:38       ` [PATCH] ipc/sem.c: fix semop()/semop() locking failure Manfred Spraul
2016-12-19  3:45         ` Davidlohr Bueso
2017-01-07  4:45           ` Mike Galbraith
2016-12-20  6:34       ` [PATCH v2] ipc/sem.c: fix incorrect sem_lock pairing Manfred Spraul

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.