| From 9df9516940a61d29aedf4d91b483ca6597e7d480 Mon Sep 17 00:00:00 2001 |
| From: Vlastimil Babka <vbabka@suse.cz> |
| Date: Mon, 20 Aug 2018 11:58:35 +0200 |
| Subject: x86/speculation/l1tf: Fix overflow in l1tf_pfn_limit() on 32bit |
| |
| From: Vlastimil Babka <vbabka@suse.cz> |
| |
| commit 9df9516940a61d29aedf4d91b483ca6597e7d480 upstream. |
| |
| On 32bit PAE kernels on 64bit hardware with enough physical bits, |
| l1tf_pfn_limit() will overflow unsigned long. This in turn affects |
| max_swapfile_size() and can lead to swapon returning -EINVAL. This has been |
| observed in a 32bit guest with 42 bits physical address size, where |
| max_swapfile_size() overflows exactly to 1 << 32, thus zero, and produces |
| the following warning to dmesg: |
| |
| [ 6.396845] Truncating oversized swap area, only using 0k out of 2047996k |
| |
| Fix this by using unsigned long long instead. |
| |
| Fixes: 17dbca119312 ("x86/speculation/l1tf: Add sysfs reporting for l1tf") |
| Fixes: 377eeaa8e11f ("x86/speculation/l1tf: Limit swap file size to MAX_PA/2") |
| Reported-by: Dominique Leuenberger <dimstar@suse.de> |
| Reported-by: Adrian Schroeter <adrian@suse.de> |
| Signed-off-by: Vlastimil Babka <vbabka@suse.cz> |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| Acked-by: Andi Kleen <ak@linux.intel.com> |
| Acked-by: Michal Hocko <mhocko@suse.com> |
| Cc: "H . Peter Anvin" <hpa@zytor.com> |
| Cc: Linus Torvalds <torvalds@linux-foundation.org> |
| Cc: Dave Hansen <dave.hansen@intel.com> |
| Cc: Michal Hocko <mhocko@kernel.org> |
| Cc: stable@vger.kernel.org |
| Link: https://lkml.kernel.org/r/20180820095835.5298-1-vbabka@suse.cz |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/x86/include/asm/processor.h | 4 ++-- |
| arch/x86/mm/init.c | 4 ++-- |
| 2 files changed, 4 insertions(+), 4 deletions(-) |
| |
| --- a/arch/x86/include/asm/processor.h |
| +++ b/arch/x86/include/asm/processor.h |
| @@ -180,9 +180,9 @@ extern const struct seq_operations cpuin |
| |
| extern void cpu_detect(struct cpuinfo_x86 *c); |
| |
| -static inline unsigned long l1tf_pfn_limit(void) |
| +static inline unsigned long long l1tf_pfn_limit(void) |
| { |
| - return BIT(boot_cpu_data.x86_phys_bits - 1 - PAGE_SHIFT) - 1; |
| + return BIT_ULL(boot_cpu_data.x86_phys_bits - 1 - PAGE_SHIFT) - 1; |
| } |
| |
| extern void early_cpu_init(void); |
| --- a/arch/x86/mm/init.c |
| +++ b/arch/x86/mm/init.c |
| @@ -892,7 +892,7 @@ unsigned long max_swapfile_size(void) |
| |
| if (boot_cpu_has_bug(X86_BUG_L1TF)) { |
| /* Limit the swap file size to MAX_PA/2 for L1TF workaround */ |
| - unsigned long l1tf_limit = l1tf_pfn_limit() + 1; |
| + unsigned long long l1tf_limit = l1tf_pfn_limit() + 1; |
| /* |
| * We encode swap offsets also with 3 bits below those for pfn |
| * which makes the usable limit higher. |
| @@ -900,7 +900,7 @@ unsigned long max_swapfile_size(void) |
| #if CONFIG_PGTABLE_LEVELS > 2 |
| l1tf_limit <<= PAGE_SHIFT - SWP_OFFSET_FIRST_BIT; |
| #endif |
| - pages = min_t(unsigned long, l1tf_limit, pages); |
| + pages = min_t(unsigned long long, l1tf_limit, pages); |
| } |
| return pages; |
| } |