linux/ipc
Manfred Spraul accb9f16ad ipc/sem.c: fix complex_count vs. simple op race
commit 5864a2fd30 upstream.

Commit 6d07b68ce1 ("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 6d07b68ce1 ("ipc/sem.c: optimize sem_lock()") (3.10?)

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

The patch is safe for backporting, i.e. it makes no assumptions
about memory barriers in spin_unlock_wait().

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: 6d07b68ce1 ("ipc/sem.c: optimize sem_lock()")
Link: http://lkml.kernel.org/r/1469123695-5661-1-git-send-email-manfred@colorfullife.com
Reported-by: <felixh@informatik.uni-bremen.de>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Davidlohr Bueso <dave@stgolabs.net>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: <1vier1@web.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
[bwh: Backported to 3.16:
 - We missed out on some earlier memory barrier changes
 - Use set_mb instead of smp_store_mb]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
History 2017-02-23 03:54:12 +00:00
..
compat.c ipc, kernel: use Linux headers 2014-06-06 16:08:14 -07:00
compat_mq.c ipc, kernel: use Linux headers 2014-06-06 16:08:14 -07:00
ipc_sysctl.c ipc: always handle a new value of auto_msgmni 2014-11-27 11:22:09 +00:00
ipcns_notifier.c ipc: do not use a negative value to re-enable msgmni automatic recomputing 2008-07-25 10:53:42 -07:00
Makefile Add generic sys_ipc wrapper 2010-03-12 15:52:32 -08:00
mq_sysctl.c ipc: convert use of typedef ctl_table to struct ctl_table 2014-06-06 16:08:16 -07:00
mqueue.c ipc: modify message queue accounting to not take kernel data structures into account 2015-08-27 12:08:15 +01:00
msg.c ipc: remove use of seq_printf return value 2017-02-23 03:54:11 +00:00
msgutil.c ipc, msg: fix message length check for negative values 2013-11-13 12:09:36 +09:00
namespace.c ipc: drop ipc_lock_by_ptr 2013-09-11 15:59:44 -07:00
sem.c ipc/sem.c: fix complex_count vs. simple op race 2017-02-23 03:54:12 +00:00
shm.c ipc: remove use of seq_printf return value 2017-02-23 03:54:11 +00:00
syscall.c get rid of union semop in sys_semctl(2) arguments 2013-03-05 15:14:16 -05:00
util.c ipc: remove use of seq_printf return value 2017-02-23 03:54:11 +00:00
util.h ipc, kernel: clear whitespace 2014-06-06 16:08:14 -07:00