mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-14 12:37:32 +00:00
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>
This commit is contained in:
parent
b1d95f4e41
commit
fac8493960
1 changed files with 15 additions and 2 deletions
|
@ -253,10 +253,10 @@ static int
|
||||||
try_preserve_large_page(pte_t *kpte, unsigned long address,
|
try_preserve_large_page(pte_t *kpte, unsigned long address,
|
||||||
struct cpa_data *cpa)
|
struct cpa_data *cpa)
|
||||||
{
|
{
|
||||||
unsigned long nextpage_addr, numpages, pmask, psize, flags;
|
unsigned long nextpage_addr, numpages, pmask, psize, flags, addr;
|
||||||
pte_t new_pte, old_pte, *tmp;
|
pte_t new_pte, old_pte, *tmp;
|
||||||
pgprot_t old_prot, new_prot;
|
pgprot_t old_prot, new_prot;
|
||||||
int do_split = 1;
|
int i, do_split = 1;
|
||||||
unsigned int level;
|
unsigned int level;
|
||||||
|
|
||||||
spin_lock_irqsave(&pgd_lock, flags);
|
spin_lock_irqsave(&pgd_lock, flags);
|
||||||
|
@ -303,6 +303,19 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
|
||||||
pgprot_val(new_prot) |= pgprot_val(cpa->mask_set);
|
pgprot_val(new_prot) |= pgprot_val(cpa->mask_set);
|
||||||
new_prot = static_protections(new_prot, address);
|
new_prot = static_protections(new_prot, address);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to check the full range, whether
|
||||||
|
* static_protection() requires a different pgprot for one of
|
||||||
|
* the pages in the range we try to preserve:
|
||||||
|
*/
|
||||||
|
addr = address + PAGE_SIZE;
|
||||||
|
for (i = 1; i < cpa->numpages; i++, addr += PAGE_SIZE) {
|
||||||
|
pgprot_t chk_prot = static_protections(new_prot, addr);
|
||||||
|
|
||||||
|
if (pgprot_val(chk_prot) != pgprot_val(new_prot))
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there are no changes, return. maxpages has been updated
|
* If there are no changes, return. maxpages has been updated
|
||||||
* above:
|
* above:
|
||||||
|
|
Loading…
Reference in a new issue