| From d082d48737c75d2b3cc1f972b8c8674c25131534 Mon Sep 17 00:00:00 2001 |
| From: Lee Jones <lee@kernel.org> |
| Date: Wed, 14 Jun 2023 17:38:54 +0100 |
| Subject: x86/mm: Avoid using set_pgd() outside of real PGD pages |
| |
| From: Lee Jones <lee@kernel.org> |
| |
| commit d082d48737c75d2b3cc1f972b8c8674c25131534 upstream. |
| |
| KPTI keeps around two PGDs: one for userspace and another for the |
| kernel. Among other things, set_pgd() contains infrastructure to |
| ensure that updates to the kernel PGD are reflected in the user PGD |
| as well. |
| |
| One side-effect of this is that set_pgd() expects to be passed whole |
| pages. Unfortunately, init_trampoline_kaslr() passes in a single entry: |
| 'trampoline_pgd_entry'. |
| |
| When KPTI is on, set_pgd() will update 'trampoline_pgd_entry' (an |
| 8-Byte globally stored [.bss] variable) and will then proceed to |
| replicate that value into the non-existent neighboring user page |
| (located +4k away), leading to the corruption of other global [.bss] |
| stored variables. |
| |
| Fix it by directly assigning 'trampoline_pgd_entry' and avoiding |
| set_pgd(). |
| |
| [ dhansen: tweak subject and changelog ] |
| |
| Fixes: 0925dda5962e ("x86/mm/KASLR: Use only one PUD entry for real mode trampoline") |
| Suggested-by: Dave Hansen <dave.hansen@linux.intel.com> |
| Signed-off-by: Lee Jones <lee@kernel.org> |
| Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> |
| Cc: <stable@vger.kernel.org> |
| Link: https://lore.kernel.org/all/20230614163859.924309-1-lee@kernel.org/g |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| arch/x86/mm/kaslr.c | 8 ++++---- |
| 1 file changed, 4 insertions(+), 4 deletions(-) |
| |
| --- a/arch/x86/mm/kaslr.c |
| +++ b/arch/x86/mm/kaslr.c |
| @@ -182,11 +182,11 @@ static void __meminit init_trampoline_pu |
| set_p4d(p4d_tramp, |
| __p4d(_KERNPG_TABLE | __pa(pud_page_tramp))); |
| |
| - set_pgd(&trampoline_pgd_entry, |
| - __pgd(_KERNPG_TABLE | __pa(p4d_page_tramp))); |
| + trampoline_pgd_entry = |
| + __pgd(_KERNPG_TABLE | __pa(p4d_page_tramp)); |
| } else { |
| - set_pgd(&trampoline_pgd_entry, |
| - __pgd(_KERNPG_TABLE | __pa(pud_page_tramp))); |
| + trampoline_pgd_entry = |
| + __pgd(_KERNPG_TABLE | __pa(pud_page_tramp)); |
| } |
| } |
| |