Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86/mpx: Fix 32-bit address space calculation

I received a bug report that running 32-bit MPX binaries on
64-bit kernels was broken. I traced it down to this little code
snippet. We were switching our "number of bounds directory
entries" calculation correctly. But, we didn't switch the other
side of the calculation: the virtual space size.

This meant that we were calculating an absurd size for
bd_entry_virt_space() on 32-bit because we used the 64-bit
virt_space.

This was _also_ broken for 32-bit kernels running on 64-bit
hardware since boot_cpu_data.x86_virt_bits=48 even when running
in 32-bit mode.

Correct that and properly handle all 3 possible cases:

1. 32-bit binary on 64-bit kernel
2. 64-bit binary on 64-bit kernel
3. 32-bit binary on 32-bit kernel

This manifested in having bounds tables not properly unmapped.
It "leaked" memory but had no functional impact otherwise.

Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Cc: <stable@vger.kernel.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Dave Hansen <dave@sr71.net>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20151111181934.FA7FAC34@viggo.jf.intel.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>

authored by

Dave Hansen and committed by
Ingo Molnar
f3119b83 46561c39

+17 -5
+17 -5
arch/x86/mm/mpx.c
··· 723 723 */ 724 724 static inline unsigned long bd_entry_virt_space(struct mm_struct *mm) 725 725 { 726 - unsigned long long virt_space = (1ULL << boot_cpu_data.x86_virt_bits); 727 - if (is_64bit_mm(mm)) 728 - return virt_space / MPX_BD_NR_ENTRIES_64; 729 - else 730 - return virt_space / MPX_BD_NR_ENTRIES_32; 726 + unsigned long long virt_space; 727 + unsigned long long GB = (1ULL << 30); 728 + 729 + /* 730 + * This covers 32-bit emulation as well as 32-bit kernels 731 + * running on 64-bit harware. 732 + */ 733 + if (!is_64bit_mm(mm)) 734 + return (4ULL * GB) / MPX_BD_NR_ENTRIES_32; 735 + 736 + /* 737 + * 'x86_virt_bits' returns what the hardware is capable 738 + * of, and returns the full >32-bit adddress space when 739 + * running 32-bit kernels on 64-bit hardware. 740 + */ 741 + virt_space = (1ULL << boot_cpu_data.x86_virt_bits); 742 + return virt_space / MPX_BD_NR_ENTRIES_64; 731 743 } 732 744 733 745 /*