Commit 68fe2426 authored by Linus Torvalds's avatar Linus Torvalds Committed by Stefan Bader

x86/speculation/l1tf: Protect swap entries against L1TF

With L1 terminal fault the CPU speculates into unmapped PTEs, and resulting
side effects allow to read the memory the PTE is pointing too, if its
values are still in the L1 cache.

For swapped out pages Linux uses unmapped PTEs and stores a swap entry into
them.

To protect against L1TF it must be ensured that the swap entry is not
pointing to valid memory, which requires setting higher bits (between bit
36 and bit 45) that are inside the CPUs physical address space, but outside
any real memory.

To do this invert the offset to make sure the higher bits are always set,
as long as the swap file is not too big.

Note there is no workaround for 32bit !PAE, or on systems which have more
than MAX_PA/2 worth of memory. The later case is very unlikely to happen on
real systems.

[AK: updated description and minor tweaks by. Split out from the original
     patch ]
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: default avatarAndi Kleen <ak@linux.intel.com>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Tested-by: default avatarAndi Kleen <ak@linux.intel.com>
Reviewed-by: default avatarJosh Poimboeuf <jpoimboe@redhat.com>
Acked-by: default avatarMichal Hocko <mhocko@suse.com>
Acked-by: default avatarVlastimil Babka <vbabka@suse.cz>
Acked-by: default avatarDave Hansen <dave.hansen@intel.com>

CVE-2018-3620
CVE-2018-3646

[smb: context adjustments around commentary]
Signed-off-by: default avatarStefan Bader <stefan.bader@canonical.com>
parent 0f4bae8b
...@@ -163,7 +163,7 @@ static inline int pgd_large(pgd_t pgd) { return 0; } ...@@ -163,7 +163,7 @@ static inline int pgd_large(pgd_t pgd) { return 0; }
#define pte_offset_map(dir, address) pte_offset_kernel((dir), (address)) #define pte_offset_map(dir, address) pte_offset_kernel((dir), (address))
#define pte_unmap(pte) ((void)(pte))/* NOP */ #define pte_unmap(pte) ((void)(pte))/* NOP */
/* Encode and de-code a swap entry */ /* Encode and de-code a swap entry. */
#define SWP_TYPE_BITS 5 #define SWP_TYPE_BITS 5
#define SWP_OFFSET_FIRST_BIT (_PAGE_BIT_PROTNONE + 1) #define SWP_OFFSET_FIRST_BIT (_PAGE_BIT_PROTNONE + 1)
/* We always extract/encode the offset by shifting it all the way up, /* We always extract/encode the offset by shifting it all the way up,
...@@ -177,13 +177,15 @@ static inline int pgd_large(pgd_t pgd) { return 0; } ...@@ -177,13 +177,15 @@ static inline int pgd_large(pgd_t pgd) { return 0; }
#define __swp_type(x) ((x).val >> (64 - SWP_TYPE_BITS)) #define __swp_type(x) ((x).val >> (64 - SWP_TYPE_BITS))
/* Shift up (to get rid of type), then down to get value */ /* Shift up (to get rid of type), then down to get value */
#define __swp_offset(x) ((x).val << SWP_TYPE_BITS >> SWP_OFFSET_SHIFT) #define __swp_offset(x) (~(x).val << SWP_TYPE_BITS >> SWP_OFFSET_SHIFT)
/* /*
* Shift the offset up "too far" by TYPE bits, then down again * Shift the offset up "too far" by TYPE bits, then down again.
* The offset is inverted by a binary not operation to make the high
* physical bits set.
*/ */
#define __swp_entry(type, offset) ((swp_entry_t) { \ #define __swp_entry(type, offset) ((swp_entry_t) { \
((unsigned long)(offset) << SWP_OFFSET_SHIFT >> SWP_TYPE_BITS) \ (~(unsigned long)(offset) << SWP_OFFSET_SHIFT >> SWP_TYPE_BITS) \
| ((unsigned long)(type) << (64-SWP_TYPE_BITS)) }) | ((unsigned long)(type) << (64-SWP_TYPE_BITS)) })
#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val((pte)) }) #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val((pte)) })
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment