Skip to content

Commit 4e528eb

Browse files
mrutland-armgregkh
authored andcommitted
arm64: ensure extension of smp_store_release value
commit 994870bead4ab19087a79492400a5478e2906196 upstream. When an inline assembly operand's type is narrower than the register it is allocated to, the least significant bits of the register (up to the operand type's width) are valid, and any other bits are permitted to contain any arbitrary value. This aligns with the AAPCS64 parameter passing rules. Our __smp_store_release() implementation does not account for this, and implicitly assumes that operands have been zero-extended to the width of the type being stored to. Thus, we may store unknown values to memory when the value type is narrower than the pointer type (e.g. when storing a char to a long). This patch fixes the issue by casting the value operand to the same width as the pointer operand in all cases, which ensures that the value is zero-extended as we expect. We use the same union trickery as __smp_load_acquire and {READ,WRITE}_ONCE() to avoid GCC complaining that pointers are potentially cast to narrower width integers in unreachable paths. A whitespace issue at the top of __smp_store_release() is also corrected. No changes are necessary for __smp_load_acquire(). Load instructions implicitly clear any upper bits of the register, and the compiler will only consider the least significant bits of the register as valid regardless. Fixes: 47933ad ("arch: Introduce smp_load_acquire(), smp_store_release()") Fixes: 878a84d ("arm64: add missing data types in smp_load_acquire/smp_store_release") Cc: <stable@vger.kernel.org> # 3.14.x- Acked-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Mark Rutland <mark.rutland@arm.com> Cc: Matthias Kaehlcke <mka@chromium.org> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 01ce16f commit 4e528eb

1 file changed

Lines changed: 14 additions & 4 deletions

File tree

arch/arm64/include/asm/barrier.h

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,23 +41,33 @@
4141

4242
#define smp_store_release(p, v) \
4343
do { \
44+
union { typeof(*p) __val; char __c[1]; } __u = \
45+
{ .__val = (__force typeof(*p)) (v) }; \
4446
compiletime_assert_atomic_type(*p); \
4547
switch (sizeof(*p)) { \
4648
case 1: \
4749
asm volatile ("stlrb %w1, %0" \
48-
: "=Q" (*p) : "r" (v) : "memory"); \
50+
: "=Q" (*p) \
51+
: "r" (*(__u8 *)__u.__c) \
52+
: "memory"); \
4953
break; \
5054
case 2: \
5155
asm volatile ("stlrh %w1, %0" \
52-
: "=Q" (*p) : "r" (v) : "memory"); \
56+
: "=Q" (*p) \
57+
: "r" (*(__u16 *)__u.__c) \
58+
: "memory"); \
5359
break; \
5460
case 4: \
5561
asm volatile ("stlr %w1, %0" \
56-
: "=Q" (*p) : "r" (v) : "memory"); \
62+
: "=Q" (*p) \
63+
: "r" (*(__u32 *)__u.__c) \
64+
: "memory"); \
5765
break; \
5866
case 8: \
5967
asm volatile ("stlr %1, %0" \
60-
: "=Q" (*p) : "r" (v) : "memory"); \
68+
: "=Q" (*p) \
69+
: "r" (*(__u64 *)__u.__c) \
70+
: "memory"); \
6171
break; \
6272
} \
6373
} while (0)

0 commit comments

Comments
 (0)