semop() may sleep waiting for a semaphore. Upon waking up, it checks to
see if the set's sequence number has changed, indicating that the set
was removed. The sequence number is not wide enough to prevent a false
negative due to wraparound, in which case the subsequent access of
semakptr->u.__sem_base[sopptr->sem_num] may be out of bounds. This
race can be leveraged into privilege escalation.
I think the proper fix would be to add a wider sequence number to struct
semid_kernel. However, this would change the layout and so break
applications which define _WANT_SYSVSEM_INTERNALS.
Instead, simply re-validate the set size upon waking up. Move MAC and
permission checks into the loop as well. This still permits false
negatives, but I don't see how we can do better without changing the
ABI.
While here, use semvalid() instead of open-coding its implementation,
convert a couple of flags to be bool, and use a better variable name to
store required permissions.
Reported by: Reo Shiseki
Reported by: Andrew Griffiths