aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mm
diff options
context:
space:
mode:
authorMark Rutland <mark.rutland@arm.com>2014-12-17 11:57:38 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2015-01-07 15:33:33 -0500
commitcca547e9aa3a6d561fe65e75a4bb2c18d80c541a (patch)
treeabe9fe828d06386be6df66bc1eefe31d9d5771d7 /arch/arm/mm
parent841ee230253f2ceb647f89a218e6e0575d961435 (diff)
ARM: 8249/1: mm: dump: don't skip regions
Currently the arm page table dumping code starts dumping page tables from USER_PGTABLES_CEILING. This is unnecessary for skipping any entries related to userspace as the swapper_pg_dir does not contain such entries, and results in a couple of unfortuante side effects. Firstly, any kernel mappings which might exist below USER_PGTABLES_CEILING will not be accounted in the dump output. This masks any entries erroneously created below this address. Secondly, if the final page table entry walked is part of 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 when 0 < USER_PGTABLES_CEILING. 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. Due to the way addr is constructed in the walk_* functions, it can never be less than USER_PGTABLES_CEILING 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 removes both problematic uses of USER_PGTABLES_CEILING from the arm page table dumping code, preventing both of these issues. We will now report any low mappings, and the final note_page call will not return early, ensuring all regions are logged. Signed-off-by: Mark Rutland <mark.rutland@arm.com> Cc: Steve Capper <steve.capper@linaro.org> Cc: Kees Cook <keescook@chromium.org> Cc: Will Deacon <will.deacon@arm.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/mm')
-rw-r--r--arch/arm/mm/dump.c9
1 files changed, 2 insertions, 7 deletions
diff --git a/arch/arm/mm/dump.c b/arch/arm/mm/dump.c
index 59424937e52b..9fe8e241335c 100644
--- a/arch/arm/mm/dump.c
+++ b/arch/arm/mm/dump.c
@@ -220,9 +220,6 @@ static void note_page(struct pg_state *st, unsigned long addr, unsigned level, u
220 static const char units[] = "KMGTPE"; 220 static const char units[] = "KMGTPE";
221 u64 prot = val & pg_level[level].mask; 221 u64 prot = val & pg_level[level].mask;
222 222
223 if (addr < USER_PGTABLES_CEILING)
224 return;
225
226 if (!st->level) { 223 if (!st->level) {
227 st->level = level; 224 st->level = level;
228 st->current_prot = prot; 225 st->current_prot = prot;
@@ -308,15 +305,13 @@ static void walk_pgd(struct seq_file *m)
308 pgd_t *pgd = swapper_pg_dir; 305 pgd_t *pgd = swapper_pg_dir;
309 struct pg_state st; 306 struct pg_state st;
310 unsigned long addr; 307 unsigned long addr;
311 unsigned i, pgdoff = USER_PGTABLES_CEILING / PGDIR_SIZE; 308 unsigned i;
312 309
313 memset(&st, 0, sizeof(st)); 310 memset(&st, 0, sizeof(st));
314 st.seq = m; 311 st.seq = m;
315 st.marker = address_markers; 312 st.marker = address_markers;
316 313
317 pgd += pgdoff; 314 for (i = 0; i < PTRS_PER_PGD; i++, pgd++) {
318
319 for (i = pgdoff; i < PTRS_PER_PGD; i++, pgd++) {
320 addr = i * PGDIR_SIZE; 315 addr = i * PGDIR_SIZE;
321 if (!pgd_none(*pgd)) { 316 if (!pgd_none(*pgd)) {
322 walk_pud(&st, pgd, addr); 317 walk_pud(&st, pgd, addr);