]> git.karo-electronics.de Git - karo-tx-linux.git/commit
ipc/sem.c: Fix complex_count vs. simple op race
authorManfred Spraul <manfred@colorfullife.com>
Tue, 9 Feb 2016 23:14:00 +0000 (10:14 +1100)
committerStephen Rothwell <sfr@canb.auug.org.au>
Tue, 9 Feb 2016 23:14:00 +0000 (10:14 +1100)
commitc762a2319ae87c9257d94010981f84f20cb95fba
tree6bbb37be0dc170b09bfefba4204203293e786267
parent6b5ec2e7f659ce164528d1420db6df868cffb6e9
ipc/sem.c: Fix complex_count vs. simple op race

Commit 6d07b68ce16a ("ipc/sem.c: optimize sem_lock()") introduced a race:

sem_lock has a fast path that allows parallel simple operations.
There are two reasons why a simple operation cannot run in parallel:

- a non-simple operations is ongoing (sma->sem_perm.lock held)
- a complex operation is sleeping (sma->complex_count != 0)

As both facts are stored independently, a thread can bypass the current
checks by sleeping in the right positions.  See below for more details (or
kernel bugzilla 105651).

The patch fixes that by creating one variable (complex_mode) that tracks
both reasons why parallel operations are not possible.

The patch also updates stale documentation regarding the locking.

With regards to stable kernels:
The patch is required for all kernels that include the commit 6d07b68ce16a
("ipc/sem.c: optimize sem_lock()") (3.10?)

The alternative is to revert the patch that introduced the race.

Background:
Here is the race of the current implementation:

Thread A: (simple op)
- does the first "sma->complex_count == 0" test

Thread B: (complex op)
- does sem_lock(): This includes an array scan. But the scan can't
  find Thread A, because Thread A does not own sem->lock yet.
- the thread does the operation, increases complex_count,
  drops sem_lock, sleeps

Thread A:
- spin_lock(&sem->lock), spin_is_locked(sma->sem_perm.lock)
- sleeps before the complex_count test

Thread C: (complex op)
- does sem_lock (no array scan, complex_count==1)
- wakes up Thread B.
- decrements complex_count

Thread A:
- does the complex_count test

Bug:
Now both thread A and thread C operate on the same array, without
any synchronization.

Fixes: 6d07b68ce16a ("ipc/sem.c: optimize sem_lock()")
Signed-off-by: Manfred Spraul <manfred@colorfullife.com>
Reported-by: <felixh@informatik.uni-bremen.de>
Cc: Davidlohr Bueso <dave@stgolabs.net>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
include/linux/sem.h
ipc/sem.c