Skip to content

Commit 07a66d7

Browse files
author
Ingo Molnar
committed
x86: use the right protections for split-up pagetables
Steven Rostedt found a bug in where in his modified kernel ftrace was unable to modify the kernel text, due to the PMD itself having been marked read-only as well in split_large_page(). The fix, suggested by Linus, is to not try to 'clone' the reference protection of a huge-page, but to use the standard (and permissive) page protection bits of KERNPG_TABLE. The 'cloning' makes sense for the ptes but it's a confused and incorrect concept at the page table level - because the pagetable entry is a set of all ptes and hence cannot 'clone' any single protection attribute - the ptes can be any mixture of protections. With the permissive KERNPG_TABLE, even if the pte protections get changed after this point (due to ftrace doing code-patching or other similar activities like kprobes), the resulting combined protections will still be correct and the pte's restrictive (or permissive) protections will control it. Also update the comment. This bug was there for a long time but has not caused visible problems before as it needs a rather large read-only area to trigger. Steve possibly hacked his kernel with some really large arrays or so. Anyway, the bug is definitely worth fixing. [ Huang Ying also experienced problems in this area when writing the EFI code, but the real bug in split_large_page() was not realized back then. ] Reported-by: Steven Rostedt <rostedt@goodmis.org> Reported-by: Huang Ying <ying.huang@intel.com> Acked-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
1 parent 48ffc70 commit 07a66d7

File tree

1 file changed

+5
-10
lines changed

1 file changed

+5
-10
lines changed

arch/x86/mm/pageattr.c

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -508,18 +508,13 @@ static int split_large_page(pte_t *kpte, unsigned long address)
508508
#endif
509509

510510
/*
511-
* Install the new, split up pagetable. Important details here:
511+
* Install the new, split up pagetable.
512512
*
513-
* On Intel the NX bit of all levels must be cleared to make a
514-
* page executable. See section 4.13.2 of Intel 64 and IA-32
515-
* Architectures Software Developer's Manual).
516-
*
517-
* Mark the entry present. The current mapping might be
518-
* set to not present, which we preserved above.
513+
* We use the standard kernel pagetable protections for the new
514+
* pagetable protections, the actual ptes set above control the
515+
* primary protection behavior:
519516
*/
520-
ref_prot = pte_pgprot(pte_mkexec(pte_clrhuge(*kpte)));
521-
pgprot_val(ref_prot) |= _PAGE_PRESENT;
522-
__set_pmd_pte(kpte, address, mk_pte(base, ref_prot));
517+
__set_pmd_pte(kpte, address, mk_pte(base, __pgprot(_KERNPG_TABLE)));
523518
base = NULL;
524519

525520
out_unlock:

0 commit comments

Comments
 (0)