kasan: fix unaligned address is unhandled in kasan_remove_zero_shadow
Subsystems (3)
PATCH 1/1 kasan: fix unaligned address is unhandled in kasan_remove_zero_shadow
During testing kasan_populate_early_shadow and kasan_remove_zero_shadow, if the shadow start and end address in kasan_remove_zero_shadow() is not aligned to PMD_SIZE, the remain unaligned PTE won't be removed.
In the test case for kasan_remove_zero_shadow():
shadow_start: 0xffffffb802000000, shadow end: 0xffffffbfbe000000
3-level page table:
PUD_SIZE: 0x40000000 PMD_SIZE: 0x200000 PAGE_SIZE: 4K0xffffffbf80000000 ~ 0xffffffbfbdf80000 will not be removed because in kasan_remove_pud_table(), kasan_pmd_table(*pud) is true but the next address is 0xffffffbfbdf80000 which is not aligned to PUD_SIZE.
In the correct condition, this should fallback to the next level kasan_remove_pmd_table() but the condition flow always continue to skip the unaligned part.
Fix by correcting the condition when next and addr are neither aligned.
--- mm/kasan/init.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-)
mm/kasan/init.c +12 -8
@@ -372,9 +372,10 @@ static void kasan_remove_pmd_table(pmd_t *pmd, unsigned long addr,if (kasan_pte_table (*pmd)) {if (IS_ALIGNED (addr,PMD_SIZE ) && -IS_ALIGNED (next,PMD_SIZE )) +IS_ALIGNED (next,PMD_SIZE )) {pmd_clear (pmd); -continue ; +continue ; + } } pte =pte_offset_kernel (pmd, addr);kasan_remove_pte_table (pte, addr, next);
@@ -397,9 +398,10 @@ static void kasan_remove_pud_table(pud_t *pud, unsigned long addr,if (kasan_pmd_table (*pud)) {if (IS_ALIGNED (addr,PUD_SIZE ) && -IS_ALIGNED (next,PUD_SIZE )) +IS_ALIGNED (next,PUD_SIZE )) {pud_clear (pud); -continue ; +continue ; + } } pmd =pmd_offset (pud, addr); pmd_base =pmd_offset (pud,0 );
@@ -423,9 +425,10 @@ static void kasan_remove_p4d_table(p4d_t *p4d, unsigned long addr,if (kasan_pud_table (*p4d)) {if (IS_ALIGNED (addr,P4D_SIZE ) && -IS_ALIGNED (next,P4D_SIZE )) +IS_ALIGNED (next,P4D_SIZE )) {p4d_clear (p4d); -continue ; +continue ; + } } pud =pud_offset (p4d, addr);kasan_remove_pud_table (pud, addr, next);
@@ -456,9 +459,10 @@ void kasan_remove_zero_shadow(void *start, unsigned long size)if (kasan_p4d_table (*pgd)) {if (IS_ALIGNED (addr,PGDIR_SIZE ) && -IS_ALIGNED (next,PGDIR_SIZE )) +IS_ALIGNED (next,PGDIR_SIZE )) {pgd_clear (pgd); -continue ; +continue ; + } } p4d =p4d_offset (pgd, addr);
Signature · 1 line
2.25.1
Quoted 82 lines · Lecopzer Chen
During testing
kasan_populate_early_shadowandkasan_remove_zero_shadow, if the shadow start and end address inkasan_remove_zero_shadow()is not aligned toPMD_SIZE, the remain unaligned PTE won't be removed.In the test case for
kasan_remove_zero_shadow():shadow_start: 0xffffffb802000000, shadow end: 0xffffffbfbe000000 3-level page table: PUD_SIZE: 0x40000000 PMD_SIZE: 0x200000 PAGE_SIZE: 4K
0xffffffbf80000000~0xffffffbfbdf80000will not be removed because inkasan_remove_pud_table(),kasan_pmd_table(*pud)is true but the next address is0xffffffbfbdf80000which is not aligned toPUD_SIZE.In the correct condition, this should fallback to the next level
kasan_remove_pmd_table()but the condition flow always continue to skip the unaligned part.Fix by correcting the condition when next and addr are neither aligned.
Fixes 0207df4fa1a86 ("kernel/memremap, kasan: make ZONE_DEVICE with work with KASAN")Signed-off-by Lecopzer Chen <[email protected]>--- mm/kasan/init.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-)mm/kasan/init.c +12
-9@@ -372,9 +372,10 @@ static void kasan_remove_pmd_table(pmd_t *pmd, unsigned long addr,if (kasan_pte_table (*pmd)) {if (IS_ALIGNED (addr,PMD_SIZE ) && -IS_ALIGNED (next,PMD_SIZE )) +IS_ALIGNED (next,PMD_SIZE )) {pmd_clear (pmd); -continue ; +continue ; + } } pte =pte_offset_kernel (pmd, addr);kasan_remove_pte_table (pte, addr, next);@@ -397,9 +398,10 @@ static void kasan_remove_pud_table(pud_t *pud, unsigned long addr,if (kasan_pmd_table (*pud)) {if (IS_ALIGNED (addr,PUD_SIZE ) && -IS_ALIGNED (next,PUD_SIZE )) +IS_ALIGNED (next,PUD_SIZE )) {pud_clear (pud); -continue ; +continue ; + } } pmd =pmd_offset (pud, addr); pmd_base =pmd_offset (pud,0 );@@ -423,9 +425,10 @@ static void kasan_remove_p4d_table(p4d_t *p4d, unsigned long addr,if (kasan_pud_table (*p4d)) {if (IS_ALIGNED (addr,P4D_SIZE ) && -IS_ALIGNED (next,P4D_SIZE )) +IS_ALIGNED (next,P4D_SIZE )) {p4d_clear (p4d); -continue ; +continue ; + } } pud =pud_offset (p4d, addr);kasan_remove_pud_table (pud, addr, next);@@ -456,9 +459,10 @@ void kasan_remove_zero_shadow(void *start, unsigned long size)if (kasan_p4d_table (*pgd)) {if (IS_ALIGNED (addr,PGDIR_SIZE ) && -IS_ALIGNED (next,PGDIR_SIZE )) +IS_ALIGNED (next,PGDIR_SIZE )) {pgd_clear (pgd); -continue ; +continue ; + } } p4d =p4d_offset (pgd, addr); --
Quoted 1 line
2.25.1
Andrey, could you please take a look at this change?
Thanks!