arm: mm: dump: don't skip final region
PATCH 1/1 arm: mm: dump: don't skip final region
If the final page table entry we walk is a valid mapping, the page table dumping code will not log the region this entry is part of, as the final note_page call in walk_pgd will trigger an early return. Luckily this isn't seen on contemporary systems as they typically don't have enough RAM to extend the linear mapping right to the end of the address space.
In note_page, we log a region when we reach its end (i.e. we hit an entry immediately afterwards which has different prot bits or is invalid). The final entry has no subsequent entry, so we will not log this immediately. We try to cater for this with a subsequent call to note_page in ptdump_show, but this returns early as 0 is less than USER_PGTABLES_CEILING, and hence we will skip a valid mapping if it spans to the final entry we note.
Luckily, the final note_page call has level == 0, while all prior calls have a non-zero level, so if we also check level we will both skip user entries and handle the final note_page call correctly. Due to the way addr is constructed in the walk_* functions, it can never be less than LOWEST_ADDR when walking the page tables, so it is not necessary to avoid dereferencing invalid table addresses. The existing checks for st->current_prot and st->marker[1].start_address are sufficient to ensure we will not print and/or dereference garbage when trying to log information.
This patch adds the aformentioned check for level, ensuring we log all regions in the kernel mappings, including those which span right to the end of the address space.
--- arch/arm/mm/dump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
I found this via inspection, rather than being hit by the problem described above, but it seemed worthwhile to fix this up (otherwise the final note_page call is pointless).
arch/arm/mm/dump.c +1 -1
@@ -220,7 +220,7 @@ static void note_page(struct pg_state *st, unsigned long addr, unsigned level, ustatic const char units[] ="KMGTPE" ;u64 prot = val & pg_level[level].mask; -if (addr <USER_PGTABLES_CEILING ) +if (level && addr <USER_PGTABLES_CEILING )return ;if (!st->level) {
Signature · 1 line
1.9.1
PATCH 1/1 arm: mm: dump: don't skip final region
Quoted 14 lines · Mark Rutland
If the final page table entry we walk is a valid mapping, the page table dumping code will not log the region this entry is part of, as the final
note_pagecall inwalk_pgdwill trigger an early return. Luckily this isn't seen on contemporary systems as they typically don't have enough RAM to extend the linear mapping right to the end of the address space.In
note_page, we log a region when we reach its end (i.e. we hit an entry immediately afterwards which has different prot bits or is invalid). The final entry has no subsequent entry, so we will not log this immediately. We try to cater for this with a subsequent call tonote_pageinptdump_show, but this returns early as 0 is less thanUSER_PGTABLES_CEILING, and hence we will skip a valid mapping if it spans to the final entry we note.
Quoted 9 lines
Luckily, the final
note_pagecall has level == 0, while all prior calls have a non-zero level, so if we also check level we will both skip user entries and handle the finalnote_pagecall correctly. Due to the way addr is constructed in the walk_* functions, it can never be less thanLOWEST_ADDRwhen walking the page tables, so it is not necessary to avoid dereferencing invalid table addresses. The existing checks forst->current_protand st->marker[1].start_address are sufficient to ensure we will not print and/or dereference garbage when trying to log information.
Do you mean USER_PGTABLES_CEILING instead of LOWEST_ADDR?
Quoted 5 lines
This patch adds the aformentioned check for level, ensuring we log all regions in the kernel mappings, including those which span right to the end of the address space.
One comment above, then:
Quoted 29 lines
Signed-off-by Mark Rutland <[email protected]>Cc Kees Cook <[email protected]>Cc Russell King <[email protected]>Cc Steve Capper <[email protected]>Cc Will Deacon <[email protected]>--- arch/arm/mm/dump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)I found this via inspection, rather than being hit by the problem described above, but it seemed worthwhile to fix this up (otherwise the final
note_pagecall is pointless).arch/arm/mm/dump.c +1
-2@@ -220,7 +220,7 @@ static void note_page(struct pg_state *st, unsigned long addr, unsigned level, ustatic const char units[] ="KMGTPE" ;u64 prot = val & pg_level[level].mask; -if (addr <USER_PGTABLES_CEILING ) +if (level && addr <USER_PGTABLES_CEILING )return ;if (!st->level) { --1.9.1
PATCH 1/1 arm: mm: dump: don't skip final region
Quoted 25 lines · Steve Capper
Quoted 14 lines · Mark Rutland
If the final page table entry we walk is a valid mapping, the page table dumping code will not log the region this entry is part of, as the final
note_pagecall inwalk_pgdwill trigger an early return. Luckily this isn't seen on contemporary systems as they typically don't have enough RAM to extend the linear mapping right to the end of the address space.In
note_page, we log a region when we reach its end (i.e. we hit an entry immediately afterwards which has different prot bits or is invalid). The final entry has no subsequent entry, so we will not log this immediately. We try to cater for this with a subsequent call tonote_pageinptdump_show, but this returns early as 0 is less thanUSER_PGTABLES_CEILING, and hence we will skip a valid mapping if it spans to the final entry we note.Quoted 9 lines
Luckily, the final
note_pagecall has level == 0, while all prior calls have a non-zero level, so if we also check level we will both skip user entries and handle the finalnote_pagecall correctly. Due to the way addr is constructed in the walk_* functions, it can never be less thanLOWEST_ADDRwhen walking the page tables, so it is not necessary to avoid dereferencing invalid table addresses. The existing checks forst->current_protand st->marker[1].start_address are sufficient to ensure we will not print and/or dereference garbage when trying to log information.
Quoted 1 line
Do you mean
USER_PGTABLES_CEILINGinstead ofLOWEST_ADDR?
Yes; sorry about that.
Looking at this again my commit message is bogus: we can construct an address below USER_PGTABLES_CEILING in walk_pmd in the case of LPAE, as USER_PGTABLES_CEILING isn't pgd_t aligned in that case.
As the swapper_pg_dir only contains kernel entries, the handling of USER_PGTABLES_CEILING is just an optimisation to skip some entries that we expect to be empty in the kernel page tables. We can handle them in note_page as we do for other *_none() entries and don't need to skip them early.
So I can entirely remove the check against USER_PGTABLES_CEILING in note_page. Would that make sense to you?
I also think we should remove pgdoff from walk_pgd. It's only non-zero for LPAE kernels, so currently if we corrupt the tables somehow and have entries below pgdoff we won't note them, making that case harder to spot.
Thanks,
Mark.
Quoted 39 lines
Quoted 5 lines
This patch adds the aformentioned check for level, ensuring we log all regions in the kernel mappings, including those which span right to the end of the address space.
One comment above, then:
Acked-by Steve Capper <[email protected]>Quoted 29 lines
Signed-off-by Mark Rutland <[email protected]>Cc Kees Cook <[email protected]>Cc Russell King <[email protected]>Cc Steve Capper <[email protected]>Cc Will Deacon <[email protected]>--- arch/arm/mm/dump.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)I found this via inspection, rather than being hit by the problem described above, but it seemed worthwhile to fix this up (otherwise the final
note_pagecall is pointless).arch/arm/mm/dump.c +1
-2@@ -220,7 +220,7 @@ static void note_page(struct pg_state *st, unsigned long addr, unsigned level, ustatic const char units[] ="KMGTPE" ;u64 prot = val & pg_level[level].mask; -if (addr <USER_PGTABLES_CEILING ) +if (level && addr <USER_PGTABLES_CEILING )return ;if (!st->level) { --1.9.1
PATCH 1/1 arm: mm: dump: don't skip final region
Quoted 34 lines · Mark Rutland
Quoted 25 lines · Steve Capper
Quoted 14 lines · Mark Rutland
If the final page table entry we walk is a valid mapping, the page table dumping code will not log the region this entry is part of, as the final
note_pagecall inwalk_pgdwill trigger an early return. Luckily this isn't seen on contemporary systems as they typically don't have enough RAM to extend the linear mapping right to the end of the address space.In
note_page, we log a region when we reach its end (i.e. we hit an entry immediately afterwards which has different prot bits or is invalid). The final entry has no subsequent entry, so we will not log this immediately. We try to cater for this with a subsequent call tonote_pageinptdump_show, but this returns early as 0 is less thanUSER_PGTABLES_CEILING, and hence we will skip a valid mapping if it spans to the final entry we note.Quoted 9 lines
Luckily, the final
note_pagecall has level == 0, while all prior calls have a non-zero level, so if we also check level we will both skip user entries and handle the finalnote_pagecall correctly. Due to the way addr is constructed in the walk_* functions, it can never be less thanLOWEST_ADDRwhen walking the page tables, so it is not necessary to avoid dereferencing invalid table addresses. The existing checks forst->current_protand st->marker[1].start_address are sufficient to ensure we will not print and/or dereference garbage when trying to log information.Quoted 1 line
Do you mean
USER_PGTABLES_CEILINGinstead ofLOWEST_ADDR?Yes; sorry about that.
Looking at this again my commit message is bogus: we can construct an address below
USER_PGTABLES_CEILINGinwalk_pmdin the case of LPAE, asUSER_PGTABLES_CEILINGisn'tpgd_taligned in that case.
Quoted 8 lines
As the
swapper_pg_dironly contains kernel entries, the handling ofUSER_PGTABLES_CEILINGis just an optimisation to skip some entries that we expect to be empty in the kernel page tables. We can handle them innote_pageas we do for other*_none()entries and don't need to skip them early.So I can entirely remove the check against
USER_PGTABLES_CEILINGinnote_page. Would that make sense to you?
After some head scratching....
Basically, the swapper_pg_dir will only contain kernel pgd entries. So at the beginning where one would normally user-space entries in a pgd table, there should be null entries that are skipped over. So yes, I agree, we should be able to remove the USER_PGTABLES_CEILING check.
Quoted 5 lines
I also think we should remove pgdoff from
walk_pgd. It's only non-zero for LPAE kernels, so currently if we corrupt the tables somehow and have entries below pgdoff we won't note them, making that case harder to spot.
I agree. Let's see what happens :-).
Quoted 4 lines
Thanks,
Mark.
Cheers,
Signature · 1 line
Steve
PATCH 1/1 arm: mm: dump: don't skip final region
Quoted 6 lines · Steve Capper
After some head scratching....
Basically, the
swapper_pg_dirwill only contain kernel pgd entries. So at the beginning where one would normally user-space entries in a pgd table, there should be null entries that are skipped over. So yes, I agree, we should be able to remove theUSER_PGTABLES_CEILINGcheck.
The check is there to avoid noting anything about the lower entries. There is the possibility for lower entries to contain something (the low vector mapping), though you're probably right that we should report those too.
Signature · 2 lines
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up according to speedtest.net.
PATCH 1/1 arm: mm: dump: don't skip final region
Quoted 8 lines · Russell King - ARM Linux
Quoted 6 lines · Steve Capper
After some head scratching....
Basically, the
swapper_pg_dirwill only contain kernel pgd entries. So at the beginning where one would normally user-space entries in a pgd table, there should be null entries that are skipped over. So yes, I agree, we should be able to remove theUSER_PGTABLES_CEILINGcheck.
Quoted 4 lines
The check is there to avoid noting anything about the lower entries. There is the possibility for lower entries to contain something (the low vector mapping), though you're probably right that we should report those too.
Ok. I'll send out a v2 which removes both uses of USER_PGTABLES_CEILING and repots all entries.
Thanks,
Mark.