Message ID | 20190728125311.10369-1-colin.king@canonical.com |
---|---|
State | New |
Headers | show |
Series | [SRU,BIONIC] mm/vmalloc: Sync unmappings in __purge_vmap_area_lazy() | expand |
Sorry, actually DISCO and for DISCO HWE kernel. Apology for confusion. Colin On 28/07/2019 13:53, Colin King wrote: > From: Colin Ian King <colin.king@canonical.com> > > BugLink: https://bugs.launchpad.net/bugs/1838115 > > On x86-32 with PTI enabled, parts of the kernel page-tables are not shared > between processes. This can cause mappings in the vmalloc/ioremap area to > persist in some page-tables after the region is unmapped and released. > > When the region is re-used the processes with the old mappings do not fault > in the new mappings but still access the old ones. > > This causes undefined behavior, in reality often data corruption, kernel > oopses and panics and even spontaneous reboots. > > Fix this problem by activly syncing unmaps in the vmalloc/ioremap area to > all page-tables in the system before the regions can be re-used. > > References: https://bugzilla.suse.com/show_bug.cgi?id=1118689 > Fixes: 5d72b4fba40ef ('x86, mm: support huge I/O mapping capability I/F') > Signed-off-by: Joerg Roedel <jroedel@suse.de> > Signed-off-by: Thomas Gleixner <tglx@linutronix.de> > Reviewed-by: Dave Hansen <dave.hansen@linux.intel.com> > Link: https://lkml.kernel.org/r/20190719184652.11391-4-joro@8bytes.org > (backported from commit 3f8fd02b1bf1d7ba964485a56f2f4b53ae88c167) > Signed-off-by: Colin Ian King <colin.king@canonical.com> > --- > arch/x86/mm/fault.c | 13 +++++-------- > 1 file changed, 5 insertions(+), 8 deletions(-) > > diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c > index 9d5c75f02295..eb246b3df03d 100644 > --- a/arch/x86/mm/fault.c > +++ b/arch/x86/mm/fault.c > @@ -193,11 +193,12 @@ static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address) > > pmd = pmd_offset(pud, address); > pmd_k = pmd_offset(pud_k, address); > - if (!pmd_present(*pmd_k)) > - return NULL; > > - if (!pmd_present(*pmd)) > + if (pmd_present(*pmd) != pmd_present(*pmd_k)) > set_pmd(pmd, *pmd_k); > + > + if (!pmd_present(*pmd_k)) > + return NULL; > else > BUG_ON(pmd_page(*pmd) != pmd_page(*pmd_k)); > > @@ -219,17 +220,13 @@ void vmalloc_sync_all(void) > spin_lock(&pgd_lock); > list_for_each_entry(page, &pgd_list, lru) { > spinlock_t *pgt_lock; > - pmd_t *ret; > > /* the pgt_lock only for Xen */ > pgt_lock = &pgd_page_get_mm(page)->page_table_lock; > > spin_lock(pgt_lock); > - ret = vmalloc_sync_one(page_address(page), address); > + vmalloc_sync_one(page_address(page), address); > spin_unlock(pgt_lock); > - > - if (!ret) > - break; > } > spin_unlock(&pgd_lock); > } >
I bodged this up, V2 coming soon. On 28/07/2019 13:54, Colin Ian King wrote: > Sorry, actually DISCO and for DISCO HWE kernel. Apology for confusion. > > Colin > > On 28/07/2019 13:53, Colin King wrote: >> From: Colin Ian King <colin.king@canonical.com> >> >> BugLink: https://bugs.launchpad.net/bugs/1838115 >> >> On x86-32 with PTI enabled, parts of the kernel page-tables are not shared >> between processes. This can cause mappings in the vmalloc/ioremap area to >> persist in some page-tables after the region is unmapped and released. >> >> When the region is re-used the processes with the old mappings do not fault >> in the new mappings but still access the old ones. >> >> This causes undefined behavior, in reality often data corruption, kernel >> oopses and panics and even spontaneous reboots. >> >> Fix this problem by activly syncing unmaps in the vmalloc/ioremap area to >> all page-tables in the system before the regions can be re-used. >> >> References: https://bugzilla.suse.com/show_bug.cgi?id=1118689 >> Fixes: 5d72b4fba40ef ('x86, mm: support huge I/O mapping capability I/F') >> Signed-off-by: Joerg Roedel <jroedel@suse.de> >> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> >> Reviewed-by: Dave Hansen <dave.hansen@linux.intel.com> >> Link: https://lkml.kernel.org/r/20190719184652.11391-4-joro@8bytes.org >> (backported from commit 3f8fd02b1bf1d7ba964485a56f2f4b53ae88c167) >> Signed-off-by: Colin Ian King <colin.king@canonical.com> >> --- >> arch/x86/mm/fault.c | 13 +++++-------- >> 1 file changed, 5 insertions(+), 8 deletions(-) >> >> diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c >> index 9d5c75f02295..eb246b3df03d 100644 >> --- a/arch/x86/mm/fault.c >> +++ b/arch/x86/mm/fault.c >> @@ -193,11 +193,12 @@ static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address) >> >> pmd = pmd_offset(pud, address); >> pmd_k = pmd_offset(pud_k, address); >> - if (!pmd_present(*pmd_k)) >> - return NULL; >> >> - if (!pmd_present(*pmd)) >> + if (pmd_present(*pmd) != pmd_present(*pmd_k)) >> set_pmd(pmd, *pmd_k); >> + >> + if (!pmd_present(*pmd_k)) >> + return NULL; >> else >> BUG_ON(pmd_page(*pmd) != pmd_page(*pmd_k)); >> >> @@ -219,17 +220,13 @@ void vmalloc_sync_all(void) >> spin_lock(&pgd_lock); >> list_for_each_entry(page, &pgd_list, lru) { >> spinlock_t *pgt_lock; >> - pmd_t *ret; >> >> /* the pgt_lock only for Xen */ >> pgt_lock = &pgd_page_get_mm(page)->page_table_lock; >> >> spin_lock(pgt_lock); >> - ret = vmalloc_sync_one(page_address(page), address); >> + vmalloc_sync_one(page_address(page), address); >> spin_unlock(pgt_lock); >> - >> - if (!ret) >> - break; >> } >> spin_unlock(&pgd_lock); >> } >> > >
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 9d5c75f02295..eb246b3df03d 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -193,11 +193,12 @@ static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address) pmd = pmd_offset(pud, address); pmd_k = pmd_offset(pud_k, address); - if (!pmd_present(*pmd_k)) - return NULL; - if (!pmd_present(*pmd)) + if (pmd_present(*pmd) != pmd_present(*pmd_k)) set_pmd(pmd, *pmd_k); + + if (!pmd_present(*pmd_k)) + return NULL; else BUG_ON(pmd_page(*pmd) != pmd_page(*pmd_k)); @@ -219,17 +220,13 @@ void vmalloc_sync_all(void) spin_lock(&pgd_lock); list_for_each_entry(page, &pgd_list, lru) { spinlock_t *pgt_lock; - pmd_t *ret; /* the pgt_lock only for Xen */ pgt_lock = &pgd_page_get_mm(page)->page_table_lock; spin_lock(pgt_lock); - ret = vmalloc_sync_one(page_address(page), address); + vmalloc_sync_one(page_address(page), address); spin_unlock(pgt_lock); - - if (!ret) - break; } spin_unlock(&pgd_lock); }