]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From: Ingo Molnar <mingo@elte.hu> |
2 | References: bnc#439348 | |
3 | Subject: x86: use the right protections for split-up pagetables | |
4 | Patch-mainline: yes | |
5 | Git: 07a66d7c53a538e1a9759954a82bb6c07365eff9 | |
6 | ||
7 | Steven Rostedt found a bug in where in his modified kernel | |
8 | ftrace was unable to modify the kernel text, due to the PMD | |
9 | itself having been marked read-only as well in | |
10 | split_large_page(). | |
11 | ||
12 | The fix, suggested by Linus, is to not try to 'clone' the | |
13 | reference protection of a huge-page, but to use the standard | |
14 | (and permissive) page protection bits of KERNPG_TABLE. | |
15 | ||
16 | The 'cloning' makes sense for the ptes but it's a confused and | |
17 | incorrect concept at the page table level - because the | |
18 | pagetable entry is a set of all ptes and hence cannot | |
19 | 'clone' any single protection attribute - the ptes can be any | |
20 | mixture of protections. | |
21 | ||
22 | With the permissive KERNPG_TABLE, even if the pte protections | |
23 | get changed after this point (due to ftrace doing code-patching | |
24 | or other similar activities like kprobes), the resulting combined | |
25 | protections will still be correct and the pte's restrictive | |
26 | (or permissive) protections will control it. | |
27 | ||
28 | Also update the comment. | |
29 | ||
30 | This bug was there for a long time but has not caused visible | |
31 | problems before as it needs a rather large read-only area to | |
32 | trigger. Steve possibly hacked his kernel with some really | |
33 | large arrays or so. Anyway, the bug is definitely worth fixing. | |
34 | ||
35 | [ Huang Ying also experienced problems in this area when writing | |
36 | the EFI code, but the real bug in split_large_page() was not | |
37 | realized back then. ] | |
38 | ||
39 | Reported-by: Steven Rostedt <rostedt@goodmis.org> | |
40 | Reported-by: Huang Ying <ying.huang@intel.com> | |
41 | Acked-by: Linus Torvalds <torvalds@linux-foundation.org> | |
42 | Signed-off-by: Ingo Molnar <mingo@elte.hu> | |
43 | ||
44 | Acked-by: Nick Piggin <npiggin@suse.de> | |
45 | ||
46 | --- | |
47 | arch/x86/mm/pageattr.c | 15 +++++---------- | |
48 | 1 file changed, 5 insertions(+), 10 deletions(-) | |
49 | ||
50 | --- a/arch/x86/mm/pageattr.c | |
51 | +++ b/arch/x86/mm/pageattr.c | |
52 | @@ -557,18 +557,13 @@ static int split_large_page(pte_t *kpte, | |
53 | #endif | |
54 | ||
55 | /* | |
56 | - * Install the new, split up pagetable. Important details here: | |
57 | + * Install the new, split up pagetable. | |
58 | * | |
59 | - * On Intel the NX bit of all levels must be cleared to make a | |
60 | - * page executable. See section 4.13.2 of Intel 64 and IA-32 | |
61 | - * Architectures Software Developer's Manual). | |
62 | - * | |
63 | - * Mark the entry present. The current mapping might be | |
64 | - * set to not present, which we preserved above. | |
65 | + * We use the standard kernel pagetable protections for the new | |
66 | + * pagetable protections, the actual ptes set above control the | |
67 | + * primary protection behavior: | |
68 | */ | |
69 | - ref_prot = pte_pgprot(pte_mkexec(pte_clrhuge(*kpte))); | |
70 | - pgprot_val(ref_prot) |= _PAGE_PRESENT; | |
71 | - __set_pmd_pte(kpte, address, mk_pte(base, ref_prot)); | |
72 | + __set_pmd_pte(kpte, address, mk_pte(base, __pgprot(_KERNPG_TABLE))); | |
73 | ||
74 | /* | |
75 | * Intel Atom errata AAH41 workaround. |