[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen stable-4.6] xen: Port the array_index_nospec() infrastructure from Linux
commit 03ba2724ae575fa60132d2bcb19802890bfd3d8c Author: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> AuthorDate: Mon Jul 30 14:17:11 2018 +0200 Commit: Jan Beulich <jbeulich@xxxxxxxx> CommitDate: Mon Jul 30 14:17:11 2018 +0200 xen: Port the array_index_nospec() infrastructure from Linux This is as the infrastructure appeared in Linux 4.17, adapted slightly for Xen. Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> Signed-off-by: Julien Grall <julien.grall@xxxxxxx> Acked-by: Jan Beulich <jbeulich@xxxxxxxx> master commit: 2ddfae51d8b1d7b8cd33a4f6ad4d16d27cb869ae master date: 2018-07-06 16:49:57 +0100 --- xen/include/asm-arm/arm32/system.h | 18 ++++++++++ xen/include/asm-arm/arm64/system.h | 22 ++++++++++++ xen/include/asm-x86/system.h | 24 +++++++++++++ xen/include/xen/compiler.h | 3 ++ xen/include/xen/nospec.h | 70 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 137 insertions(+) diff --git a/xen/include/asm-arm/arm32/system.h b/xen/include/asm-arm/arm32/system.h index c617b40438..ab57abfbc5 100644 --- a/xen/include/asm-arm/arm32/system.h +++ b/xen/include/asm-arm/arm32/system.h @@ -48,6 +48,24 @@ static inline int local_fiq_is_enabled(void) return !(flags & PSR_FIQ_MASK); } +#define CSDB ".inst 0xe320f014" + +static inline unsigned long array_index_mask_nospec(unsigned long idx, + unsigned long sz) +{ + unsigned long mask; + + asm volatile( "cmp %1, %2\n" + "sbc %0, %1, %1\n" + CSDB + : "=r" (mask) + : "r" (idx), "Ir" (sz) + : "cc" ); + + return mask; +} +#define array_index_mask_nospec array_index_mask_nospec + #endif /* * Local variables: diff --git a/xen/include/asm-arm/arm64/system.h b/xen/include/asm-arm/arm64/system.h index 2e2ee212a1..2e36573ac6 100644 --- a/xen/include/asm-arm/arm64/system.h +++ b/xen/include/asm-arm/arm64/system.h @@ -58,6 +58,28 @@ static inline int local_fiq_is_enabled(void) return !(flags & PSR_FIQ_MASK); } +#define csdb() asm volatile ( "hint #20" : : : "memory" ) + +/* + * Generate a mask for array_index__nospec() that is ~0UL when 0 <= idx < sz + * and 0 otherwise. + */ +static inline unsigned long array_index_mask_nospec(unsigned long idx, + unsigned long sz) +{ + unsigned long mask; + + asm volatile ( "cmp %1, %2\n" + "sbc %0, xzr, xzr\n" + : "=r" (mask) + : "r" (idx), "Ir" (sz) + : "cc" ); + csdb(); + + return mask; +} +#define array_index_mask_nospec array_index_mask_nospec + #endif /* * Local variables: diff --git a/xen/include/asm-x86/system.h b/xen/include/asm-x86/system.h index 9fb70f5704..b53cf5d0ab 100644 --- a/xen/include/asm-x86/system.h +++ b/xen/include/asm-x86/system.h @@ -185,6 +185,30 @@ static always_inline unsigned long __xadd( #define set_mb(var, value) do { xchg(&var, value); } while (0) #define set_wmb(var, value) do { var = value; wmb(); } while (0) +/** + * array_index_mask_nospec() - generate a mask that is ~0UL when the + * bounds check succeeds and 0 otherwise + * @index: array element index + * @size: number of elements in array + * + * Returns: + * 0 - (index < size) + */ +static inline unsigned long array_index_mask_nospec(unsigned long index, + unsigned long size) +{ + unsigned long mask; + + asm volatile ( "cmp %[size], %[index]; sbb %[mask], %[mask];" + : [mask] "=r" (mask) + : [size] "g" (size), [index] "r" (index) ); + + return mask; +} + +/* Override default implementation in nospec.h. */ +#define array_index_mask_nospec array_index_mask_nospec + #define local_irq_disable() asm volatile ( "cli" : : : "memory" ) #define local_irq_enable() asm volatile ( "sti" : : : "memory" ) diff --git a/xen/include/xen/compiler.h b/xen/include/xen/compiler.h index e6a32cef90..c226264c5a 100644 --- a/xen/include/xen/compiler.h +++ b/xen/include/xen/compiler.h @@ -79,6 +79,9 @@ #pragma GCC visibility push(hidden) #endif +/* Make the optimizer believe the variable can be manipulated arbitrarily. */ +#define OPTIMIZER_HIDE_VAR(var) __asm__ ( "" : "+g" (var) ) + /* This macro obfuscates arithmetic on a variable address so that gcc shouldn't recognize the original var, and make assumptions about it */ /* diff --git a/xen/include/xen/nospec.h b/xen/include/xen/nospec.h new file mode 100644 index 0000000000..48793996e8 --- /dev/null +++ b/xen/include/xen/nospec.h @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright(c) 2018 Linus Torvalds. All rights reserved. */ +/* Copyright(c) 2018 Alexei Starovoitov. All rights reserved. */ +/* Copyright(c) 2018 Intel Corporation. All rights reserved. */ +/* Copyright(c) 2018 Citrix Systems R&D Ltd. All rights reserved. */ + +#ifndef XEN_NOSPEC_H +#define XEN_NOSPEC_H + +#include <asm/system.h> + +/** + * array_index_mask_nospec() - generate a ~0 mask when index < size, 0 otherwise + * @index: array element index + * @size: number of elements in array + * + * When @index is out of bounds (@index >= @size), the sign bit will be + * set. Extend the sign bit to all bits and invert, giving a result of + * zero for an out of bounds index, or ~0 if within bounds [0, @size). + */ +#ifndef array_index_mask_nospec +static inline unsigned long array_index_mask_nospec(unsigned long index, + unsigned long size) +{ + /* + * Always calculate and emit the mask even if the compiler + * thinks the mask is not needed. The compiler does not take + * into account the value of @index under speculation. + */ + OPTIMIZER_HIDE_VAR(index); + return ~(long)(index | (size - 1UL - index)) >> (BITS_PER_LONG - 1); +} +#endif + +/* + * array_index_nospec - sanitize an array index after a bounds check + * + * For a code sequence like: + * + * if (index < size) { + * index = array_index_nospec(index, size); + * val = array[index]; + * } + * + * ...if the CPU speculates past the bounds check then + * array_index_nospec() will clamp the index within the range of [0, + * size). + */ +#define array_index_nospec(index, size) \ +({ \ + typeof(index) _i = (index); \ + typeof(size) _s = (size); \ + unsigned long _mask = array_index_mask_nospec(_i, _s); \ + \ + BUILD_BUG_ON(sizeof(_i) > sizeof(long)); \ + BUILD_BUG_ON(sizeof(_s) > sizeof(long)); \ + \ + (typeof(_i)) (_i & _mask); \ +}) + +#endif /* XEN_NOSPEC_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ -- generated by git-patchbot for /home/xen/git/xen.git#stable-4.6 _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |