Re: [PATCH 1/2] ipc/sem.c: Fix complex_count vs. simple op race

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sat, 25 Jun 2016 19:37:51 +0200, Manfred Spraul wrote:

> 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.
> 
> Full memory barrier are required to synchronize changes of
> complex_mode and the lock operations.
> 
> Fixes: 6d07b68ce16a ("ipc/sem.c: optimize sem_lock()")
> Reported-by: felixh@xxxxxxxxxxxxxxxxxxxxxxxx
> Signed-off-by: Manfred Spraul <manfred@xxxxxxxxxxxxxxxx>
> Cc: <stable@xxxxxxxxxxxxxxx>

<snip>

>  
> -		/* Then check that the global lock is free */
> -		if (!spin_is_locked(&sma->sem_perm.lock)) {
> -			/*
> -			 * We need a memory barrier with acquire semantics,
> -			 * otherwise we can race with another thread that does:
> -			 *	complex_count++;
> -			 *	spin_unlock(sem_perm.lock);
> -			 */
> -			smp_acquire__after_ctrl_dep();

This won't apply to -stable because smp_acquire__after_ctrl_dep() was only
recently added. I could merge this over 4.4.x by replacing it with the previous
definition ipc_smp_acquire__after_spin_is_unlocked() (just as you did in the
first version of the patch).

hth,
Holger

--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]