summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Andrzej Siewior <bigeasy@linutronix.de>2015-02-18 14:07:21 +0100
committerSteven Rostedt <rostedt@goodmis.org>2016-11-16 14:23:09 -0500
commitcb2d569753b98a04191e17c5436920216fd0c8a2 (patch)
tree02fa4ed511a176075061dbd81fb2a4bbbbf85ac1
parenteb1003195451b8602b1164d1249352a0de0c4512 (diff)
downloadlinux-rt-cb2d569753b98a04191e17c5436920216fd0c8a2.tar.gz
arm/futex: disable preemption during futex_atomic_cmpxchg_inatomic()
The ARM UP implementation of futex_atomic_cmpxchg_inatomic() assumes that pagefault_disable() inherits a preempt disabled section. This assumtion is true for mainline but -RT reverts this and allows preemption in pagefault disabled regions. The code sequence of futex_atomic_cmpxchg_inatomic(): | x = *futex; | if (x == oldval) | *futex = newval; The problem occurs if the code is preempted after reading the futex value or after comparing it with x. While preempted, the futex owner has to be scheduled which then releases the lock (in userland because it has no waiter yet). Once the code is back on the CPU, it overwrites the futex value with with the old PID and the waiter bit set. The workaround is to explicit disable code preemption to avoid the described race window. Debugged-by: Thomas Gleixner <tglx@linutronix.de> Cc: stable-rt@vger.kernel.org Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--arch/arm/include/asm/futex.h4
1 files changed, 4 insertions, 0 deletions
diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h
index 7be54690aeec..3d1ae210c4b5 100644
--- a/arch/arm/include/asm/futex.h
+++ b/arch/arm/include/asm/futex.h
@@ -94,6 +94,8 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;
+ preempt_disable_rt();
+
__asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n"
"1: " TUSER(ldr) " %1, [%4]\n"
" teq %1, %2\n"
@@ -105,6 +107,8 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
: "cc", "memory");
*uval = val;
+
+ preempt_enable_rt();
return ret;
}