@@ -154,10 +154,24 @@ static inline int pgd_large(pgd_t pgd) { return 0; }
/* PUD - Level3 access */
/* PMD - Level 2 access */
-#define pte_to_pgoff(pte) ((pte_val((pte)) & PHYSICAL_PAGE_MASK) >> PAGE_SHIFT)
-#define pgoff_to_pte(off) ((pte_t) { .pte = ((off) << PAGE_SHIFT) | \
- _PAGE_FILE })
-#define PTE_FILE_MAX_BITS __PHYSICAL_MASK_SHIFT
+#define pte_to_pgoff(pte) ((~pte_val((pte)) & PHYSICAL_PAGE_MASK) >> PAGE_SHIFT)
+#define pgoff_to_pte(off) ((pte_t) { .pte = \
+ ((~(off) & (PHYSICAL_PAGE_MASK >> PAGE_SHIFT)) \
+ << PAGE_SHIFT) | _PAGE_FILE })
+/*
+ * Set the highest allowed nonlinear pgoff to 1 bit less than
+ * x86_phys_bits to guarantee the inversion of the highest bit
+ * in the pgoff_to_pte conversion. The lowest x86_phys_bits is
+ * 36 so x86 implementations with 36 bits will find themselves
+ * unable to keep using remap_file_pages() with file offsets
+ * above 128TiB (calculated as 1<<(36-1+PAGE_SHIFT)). More
+ * recent CPUs will retain much higher max file offset limits.
+ */
+#ifdef PTE_FILE_MAX_BITS
+#error "Huh? PTE_FILE_MAX_BITS shouldn't be defined here"
+#endif
+#define L1TF_PTE_FILE_MAX_BITS min(__PHYSICAL_MASK_SHIFT, \
+ boot_cpu_data.x86_phys_bits - 1)
/* PTE - Level 1 access. */
@@ -153,10 +153,16 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
return err;
/* Can we represent this offset inside this architecture's pte's? */
+#ifdef L1TF_PTE_FILE_MAX_BITS
+ if (L1TF_PTE_FILE_MAX_BITS < BITS_PER_LONG &&
+ (pgoff + (size >> PAGE_SHIFT) >= (1UL << L1TF_PTE_FILE_MAX_BITS)))
+ return err;
+#else
#if PTE_FILE_MAX_BITS < BITS_PER_LONG
if (pgoff + (size >> PAGE_SHIFT) >= (1UL << PTE_FILE_MAX_BITS))
return err;
#endif
+#endif /* L1TF_PTE_FILE_MAX_BITS */
/* We need down_write() to change vma->vm_flags. */
down_read(&mm->mmap_sem);
The 3.13 kernel still uses non-emulated code for the remap_file_pages syscall which makes use of macros to convert between page offsets and PTEs. These macros need to invert the offset for L1TF protection. Without this, the page table entries of a remapped and swapped out file page look like this: [28865.660359] virtual user addr: 00007fe49ea9b000 [28865.660360] page: ffffeddf927aa6c0 [28865.660361] pgd: ffff8802605267f8 (8000000260229067) | USR RW NX | pgd [28865.660365] pud: ffff880260229c90 (000000025f9d1067) | USR RW PAT x | pud 1G [28865.660368] pmd: ffff88025f9d17a8 (00000002602d8067) | USR RW x | pmd 2M [28865.660371] pte: ffff8802602d84d8 (00000000001f4040) | ro x | pte 4K ^^^^^^ non-inverted offset With this commit, they look like: [ 2564.508511] virtual user addr: 00007f728c787000 [ 2564.508514] page: ffffedddca31e1c0 [ 2564.508518] pgd: ffff8802603207f0 (800000026036b067) | USR RW NX | pgd [ 2564.508531] pud: ffff88026036be50 (0000000260ee6067) | USR RW x | pud 1G [ 2564.508543] pmd: ffff880260ee6318 (0000000260360067) | USR RW x | pmd 2M [ 2564.508554] pte: ffff880260360c38 (00003fffffe0b040) | ro x | pte 4K ^^^^^^ inverted offset Also make sure that the number of bits for the maximum offset for a remap is limited to 1 bit less than the number of actual physical bits so that the highest bit can be inverted by the conversion macros. CVE-2018-3620 CVE-2018-3646 Signed-off-by: Juerg Haefliger <juergh@canonical.com> --- arch/x86/include/asm/pgtable_64.h | 22 ++++++++++++++++++---- mm/fremap.c | 6 ++++++ 2 files changed, 24 insertions(+), 4 deletions(-)