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>

+15 -2
+15 -2
arch/x86/mm/pageattr.c
··· 253 try_preserve_large_page(pte_t *kpte, unsigned long address, 254 struct cpa_data *cpa) 255 { 256 - unsigned long nextpage_addr, numpages, pmask, psize, flags; 257 pte_t new_pte, old_pte, *tmp; 258 pgprot_t old_prot, new_prot; 259 - int do_split = 1; 260 unsigned int level; 261 262 spin_lock_irqsave(&pgd_lock, flags); ··· 302 pgprot_val(new_prot) &= ~pgprot_val(cpa->mask_clr); 303 pgprot_val(new_prot) |= pgprot_val(cpa->mask_set); 304 new_prot = static_protections(new_prot, address); 305 306 /* 307 * If there are no changes, return. maxpages has been updated
··· 253 try_preserve_large_page(pte_t *kpte, unsigned long address, 254 struct cpa_data *cpa) 255 { 256 + unsigned long nextpage_addr, numpages, pmask, psize, flags, addr; 257 pte_t new_pte, old_pte, *tmp; 258 pgprot_t old_prot, new_prot; 259 + int i, do_split = 1; 260 unsigned int level; 261 262 spin_lock_irqsave(&pgd_lock, flags); ··· 302 pgprot_val(new_prot) &= ~pgprot_val(cpa->mask_clr); 303 pgprot_val(new_prot) |= pgprot_val(cpa->mask_set); 304 new_prot = static_protections(new_prot, address); 305 + 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 /* 320 * If there are no changes, return. maxpages has been updated