diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2008-02-09 17:24:09 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2008-02-09 17:24:09 -0500 |
commit | fac84939609a683503947f41eb93e1917d026263 (patch) | |
tree | 8bf2df694a2300a277cf097ba778f9b4b28f2122 /arch | |
parent | b1d95f4e41d6a5969e3a847ceeae8379f30c84c3 (diff) |
x86: cpa, strict range check in try_preserve_large_page()
Right now, we check only the first 4k page for static required protections.
This does not take overlapping regions into account. So we might end up
setting the wrong permissions/protections for other parts of this large page.
This can be optimized further, but correctness is the important part.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/mm/pageattr.c | 17 |
1 files changed, 15 insertions, 2 deletions
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index e5d29a112d00..440210a2277d 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c | |||
@@ -253,10 +253,10 @@ static int | |||
253 | try_preserve_large_page(pte_t *kpte, unsigned long address, | 253 | try_preserve_large_page(pte_t *kpte, unsigned long address, |
254 | struct cpa_data *cpa) | 254 | struct cpa_data *cpa) |
255 | { | 255 | { |
256 | unsigned long nextpage_addr, numpages, pmask, psize, flags; | 256 | unsigned long nextpage_addr, numpages, pmask, psize, flags, addr; |
257 | pte_t new_pte, old_pte, *tmp; | 257 | pte_t new_pte, old_pte, *tmp; |
258 | pgprot_t old_prot, new_prot; | 258 | pgprot_t old_prot, new_prot; |
259 | int do_split = 1; | 259 | int i, do_split = 1; |
260 | unsigned int level; | 260 | unsigned int level; |
261 | 261 | ||
262 | spin_lock_irqsave(&pgd_lock, flags); | 262 | spin_lock_irqsave(&pgd_lock, flags); |
@@ -304,6 +304,19 @@ try_preserve_large_page(pte_t *kpte, unsigned long address, | |||
304 | new_prot = static_protections(new_prot, address); | 304 | new_prot = static_protections(new_prot, address); |
305 | 305 | ||
306 | /* | 306 | /* |
307 | * We need to check the full range, whether | ||
308 | * static_protection() requires a different pgprot for one of | ||
309 | * the pages in the range we try to preserve: | ||
310 | */ | ||
311 | addr = address + PAGE_SIZE; | ||
312 | for (i = 1; i < cpa->numpages; i++, addr += PAGE_SIZE) { | ||
313 | pgprot_t chk_prot = static_protections(new_prot, addr); | ||
314 | |||
315 | if (pgprot_val(chk_prot) != pgprot_val(new_prot)) | ||
316 | goto out_unlock; | ||
317 | } | ||
318 | |||
319 | /* | ||
307 | * If there are no changes, return. maxpages has been updated | 320 | * If there are no changes, return. maxpages has been updated |
308 | * above: | 321 | * above: |
309 | */ | 322 | */ |