|
Ivan T. Ivanov |
60a154 |
From: Will Deacon <will.deacon@arm.com>
|
|
Ivan T. Ivanov |
60a154 |
Date: Mon, 8 Apr 2019 12:45:09 +0100
|
|
Ivan T. Ivanov |
60a154 |
Subject: arm64: futex: Fix FUTEX_WAKE_OP atomic ops with non-zero result value
|
|
Ivan T. Ivanov |
60a154 |
Git-commit: 045afc24124d80c6998d9c770844c67912083506
|
|
Ivan T. Ivanov |
60a154 |
Patch-mainline: v5.1-rc5
|
|
Ivan T. Ivanov |
60a154 |
References: git-fixes
|
|
Ivan T. Ivanov |
60a154 |
|
|
Ivan T. Ivanov |
60a154 |
Rather embarrassingly, our futex() FUTEX_WAKE_OP implementation doesn't
|
|
Ivan T. Ivanov |
60a154 |
explicitly set the return value on the non-faulting path and instead
|
|
Ivan T. Ivanov |
60a154 |
leaves it holding the result of the underlying atomic operation. This
|
|
Ivan T. Ivanov |
60a154 |
means that any FUTEX_WAKE_OP atomic operation which computes a non-zero
|
|
Ivan T. Ivanov |
60a154 |
value will be reported as having failed. Regrettably, I wrote the buggy
|
|
Ivan T. Ivanov |
60a154 |
code back in 2011 and it was upstreamed as part of the initial arm64
|
|
Ivan T. Ivanov |
60a154 |
support in 2012.
|
|
Ivan T. Ivanov |
60a154 |
|
|
Ivan T. Ivanov |
60a154 |
The reasons we appear to get away with this are:
|
|
Ivan T. Ivanov |
60a154 |
|
|
Ivan T. Ivanov |
60a154 |
1. FUTEX_WAKE_OP is rarely used and therefore doesn't appear to get
|
|
Ivan T. Ivanov |
60a154 |
exercised by futex() test applications
|
|
Ivan T. Ivanov |
60a154 |
|
|
Ivan T. Ivanov |
60a154 |
2. If the result of the atomic operation is zero, the system call
|
|
Ivan T. Ivanov |
60a154 |
behaves correctly
|
|
Ivan T. Ivanov |
60a154 |
|
|
Ivan T. Ivanov |
60a154 |
3. Prior to version 2.25, the only operation used by GLIBC set the
|
|
Ivan T. Ivanov |
60a154 |
futex to zero, and therefore worked as expected. From 2.25 onwards,
|
|
Ivan T. Ivanov |
60a154 |
FUTEX_WAKE_OP is not used by GLIBC at all.
|
|
Ivan T. Ivanov |
60a154 |
|
|
Ivan T. Ivanov |
60a154 |
Fix the implementation by ensuring that the return value is either 0
|
|
Ivan T. Ivanov |
60a154 |
to indicate that the atomic operation completed successfully, or -EFAULT
|
|
Ivan T. Ivanov |
60a154 |
if we encountered a fault when accessing the user mapping.
|
|
Ivan T. Ivanov |
60a154 |
|
|
Ivan T. Ivanov |
60a154 |
Cc: <stable@kernel.org>
|
|
Ivan T. Ivanov |
60a154 |
Fixes: 6170a97460db ("arm64: Atomic operations")
|
|
Ivan T. Ivanov |
60a154 |
Signed-off-by: Will Deacon <will.deacon@arm.com>
|
|
Ivan T. Ivanov |
60a154 |
Acked-by: Ivan T. Ivanov <iivanov@suse.de>
|
|
Ivan T. Ivanov |
60a154 |
---
|
|
Ivan T. Ivanov |
60a154 |
arch/arm64/include/asm/futex.h | 16 ++++++++--------
|
|
Ivan T. Ivanov |
60a154 |
1 file changed, 8 insertions(+), 8 deletions(-)
|
|
Ivan T. Ivanov |
60a154 |
|
|
Ivan T. Ivanov |
60a154 |
--- a/arch/arm64/include/asm/futex.h
|
|
Ivan T. Ivanov |
60a154 |
+++ b/arch/arm64/include/asm/futex.h
|
|
Ivan T. Ivanov |
60a154 |
@@ -30,8 +30,8 @@ do { \
|
|
Ivan T. Ivanov |
60a154 |
" prfm pstl1strm, %2\n" \
|
|
Ivan T. Ivanov |
60a154 |
"1: ldxr %w1, %2\n" \
|
|
Ivan T. Ivanov |
60a154 |
insn "\n" \
|
|
Ivan T. Ivanov |
60a154 |
-"2: stlxr %w3, %w0, %2\n" \
|
|
Ivan T. Ivanov |
60a154 |
-" cbnz %w3, 1b\n" \
|
|
Ivan T. Ivanov |
60a154 |
+"2: stlxr %w0, %w3, %2\n" \
|
|
Ivan T. Ivanov |
60a154 |
+" cbnz %w0, 1b\n" \
|
|
Ivan T. Ivanov |
60a154 |
" dmb ish\n" \
|
|
Ivan T. Ivanov |
60a154 |
"3:\n" \
|
|
Ivan T. Ivanov |
60a154 |
" .pushsection .fixup,\"ax\"\n" \
|
|
Ivan T. Ivanov |
60a154 |
@@ -50,30 +50,30 @@ do { \
|
|
Ivan T. Ivanov |
60a154 |
static inline int
|
|
Ivan T. Ivanov |
60a154 |
arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *_uaddr)
|
|
Ivan T. Ivanov |
60a154 |
{
|
|
Ivan T. Ivanov |
60a154 |
- int oldval = 0, ret, tmp;
|
|
Ivan T. Ivanov |
60a154 |
+ int oldval, ret, tmp;
|
|
Ivan T. Ivanov |
60a154 |
u32 __user *uaddr = __uaccess_mask_ptr(_uaddr);
|
|
Ivan T. Ivanov |
60a154 |
|
|
Ivan T. Ivanov |
60a154 |
pagefault_disable();
|
|
Ivan T. Ivanov |
60a154 |
|
|
Ivan T. Ivanov |
60a154 |
switch (op) {
|
|
Ivan T. Ivanov |
60a154 |
case FUTEX_OP_SET:
|
|
Ivan T. Ivanov |
60a154 |
- __futex_atomic_op("mov %w0, %w4",
|
|
Ivan T. Ivanov |
60a154 |
+ __futex_atomic_op("mov %w3, %w4",
|
|
Ivan T. Ivanov |
60a154 |
ret, oldval, uaddr, tmp, oparg);
|
|
Ivan T. Ivanov |
60a154 |
break;
|
|
Ivan T. Ivanov |
60a154 |
case FUTEX_OP_ADD:
|
|
Ivan T. Ivanov |
60a154 |
- __futex_atomic_op("add %w0, %w1, %w4",
|
|
Ivan T. Ivanov |
60a154 |
+ __futex_atomic_op("add %w3, %w1, %w4",
|
|
Ivan T. Ivanov |
60a154 |
ret, oldval, uaddr, tmp, oparg);
|
|
Ivan T. Ivanov |
60a154 |
break;
|
|
Ivan T. Ivanov |
60a154 |
case FUTEX_OP_OR:
|
|
Ivan T. Ivanov |
60a154 |
- __futex_atomic_op("orr %w0, %w1, %w4",
|
|
Ivan T. Ivanov |
60a154 |
+ __futex_atomic_op("orr %w3, %w1, %w4",
|
|
Ivan T. Ivanov |
60a154 |
ret, oldval, uaddr, tmp, oparg);
|
|
Ivan T. Ivanov |
60a154 |
break;
|
|
Ivan T. Ivanov |
60a154 |
case FUTEX_OP_ANDN:
|
|
Ivan T. Ivanov |
60a154 |
- __futex_atomic_op("and %w0, %w1, %w4",
|
|
Ivan T. Ivanov |
60a154 |
+ __futex_atomic_op("and %w3, %w1, %w4",
|
|
Ivan T. Ivanov |
60a154 |
ret, oldval, uaddr, tmp, ~oparg);
|
|
Ivan T. Ivanov |
60a154 |
break;
|
|
Ivan T. Ivanov |
60a154 |
case FUTEX_OP_XOR:
|
|
Ivan T. Ivanov |
60a154 |
- __futex_atomic_op("eor %w0, %w1, %w4",
|
|
Ivan T. Ivanov |
60a154 |
+ __futex_atomic_op("eor %w3, %w1, %w4",
|
|
Ivan T. Ivanov |
60a154 |
ret, oldval, uaddr, tmp, oparg);
|
|
Ivan T. Ivanov |
60a154 |
break;
|
|
Ivan T. Ivanov |
60a154 |
default:
|