Skip to content

Commit e084728

Browse files
chleroympe
authored andcommitted
powerpc/ptdump: Convert powerpc to GENERIC_PTDUMP
This patch converts powerpc to the generic PTDUMP implementation. Signed-off-by: Christophe Leroy <[email protected]> Signed-off-by: Michael Ellerman <[email protected]> Link: https://lore.kernel.org/r/03166d569526be70214fe9370a7bad219d2f41c8.1625762907.git.christophe.leroy@csgroup.eu
1 parent cf98d2b commit e084728

File tree

6 files changed

+47
-144
lines changed

6 files changed

+47
-144
lines changed

arch/powerpc/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ config PPC
123123
select ARCH_HAS_COPY_MC if PPC64
124124
select ARCH_HAS_DEBUG_VIRTUAL
125125
select ARCH_HAS_DEBUG_VM_PGTABLE
126+
select ARCH_HAS_DEBUG_WX if STRICT_KERNEL_RWX
126127
select ARCH_HAS_DEVMEM_IS_ALLOWED
127128
select ARCH_HAS_DMA_MAP_DIRECT if PPC_PSERIES
128129
select ARCH_HAS_ELF_RANDOMIZE
@@ -182,6 +183,7 @@ config PPC
182183
select GENERIC_IRQ_SHOW
183184
select GENERIC_IRQ_SHOW_LEVEL
184185
select GENERIC_PCI_IOMAP if PCI
186+
select GENERIC_PTDUMP
185187
select GENERIC_SMP_IDLE_THREAD
186188
select GENERIC_STRNCPY_FROM_USER
187189
select GENERIC_STRNLEN_USER

arch/powerpc/Kconfig.debug

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -365,36 +365,6 @@ config FAIL_IOMMU
365365

366366
If you are unsure, say N.
367367

368-
config PPC_PTDUMP
369-
bool "Export kernel pagetable layout to userspace via debugfs"
370-
depends on DEBUG_KERNEL && DEBUG_FS
371-
help
372-
This option exports the state of the kernel pagetables to a
373-
debugfs file. This is only useful for kernel developers who are
374-
working in architecture specific areas of the kernel - probably
375-
not a good idea to enable this feature in a production kernel.
376-
377-
If you are unsure, say N.
378-
379-
config PPC_DEBUG_WX
380-
bool "Warn on W+X mappings at boot"
381-
depends on PPC_PTDUMP && STRICT_KERNEL_RWX
382-
help
383-
Generate a warning if any W+X mappings are found at boot.
384-
385-
This is useful for discovering cases where the kernel is leaving
386-
W+X mappings after applying NX, as such mappings are a security risk.
387-
388-
Note that even if the check fails, your kernel is possibly
389-
still fine, as W+X mappings are not a security hole in
390-
themselves, what they do is that they make the exploitation
391-
of other unfixed kernel bugs easier.
392-
393-
There is no runtime or memory usage effect of this option
394-
once the kernel has booted up - it's a one time check.
395-
396-
If in doubt, say "Y".
397-
398368
config PPC_FAST_ENDIAN_SWITCH
399369
bool "Deprecated fast endian-switch syscall"
400370
depends on DEBUG_KERNEL && PPC_BOOK3S_64

arch/powerpc/mm/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,5 @@ obj-$(CONFIG_PPC_MM_SLICES) += slice.o
1818
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
1919
obj-$(CONFIG_NOT_COHERENT_CACHE) += dma-noncoherent.o
2020
obj-$(CONFIG_PPC_COPRO_BASE) += copro_fault.o
21-
obj-$(CONFIG_PPC_PTDUMP) += ptdump/
21+
obj-$(CONFIG_PTDUMP_CORE) += ptdump/
2222
obj-$(CONFIG_KASAN) += kasan/

arch/powerpc/mm/mmu_decl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ static inline void mmu_mark_rodata_ro(void) { }
180180
void __init mmu_mapin_immr(void);
181181
#endif
182182

183-
#ifdef CONFIG_PPC_DEBUG_WX
183+
#ifdef CONFIG_DEBUG_WX
184184
void ptdump_check_wx(void);
185185
#else
186186
static inline void ptdump_check_wx(void) { }

arch/powerpc/mm/ptdump/Makefile

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,10 @@ obj-y += ptdump.o
55
obj-$(CONFIG_4xx) += shared.o
66
obj-$(CONFIG_PPC_8xx) += 8xx.o
77
obj-$(CONFIG_PPC_BOOK3E_MMU) += shared.o
8-
obj-$(CONFIG_PPC_BOOK3S_32) += shared.o bats.o segment_regs.o
9-
obj-$(CONFIG_PPC_BOOK3S_64) += book3s64.o hashpagetable.o
8+
obj-$(CONFIG_PPC_BOOK3S_32) += shared.o
9+
obj-$(CONFIG_PPC_BOOK3S_64) += book3s64.o
10+
11+
ifdef CONFIG_PTDUMP_DEBUGFS
12+
obj-$(CONFIG_PPC_BOOK3S_32) += bats.o segment_regs.o
13+
obj-$(CONFIG_PPC_BOOK3S_64) += hashpagetable.o
14+
endif

arch/powerpc/mm/ptdump/ptdump.c

Lines changed: 36 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <linux/io.h>
1717
#include <linux/mm.h>
1818
#include <linux/highmem.h>
19+
#include <linux/ptdump.h>
1920
#include <linux/sched.h>
2021
#include <linux/seq_file.h>
2122
#include <asm/fixmap.h>
@@ -54,6 +55,7 @@
5455
*
5556
*/
5657
struct pg_state {
58+
struct ptdump_state ptdump;
5759
struct seq_file *seq;
5860
const struct addr_marker *marker;
5961
unsigned long start_address;
@@ -102,6 +104,11 @@ static struct addr_marker address_markers[] = {
102104
{ -1, NULL },
103105
};
104106

107+
static struct ptdump_range ptdump_range[] __ro_after_init = {
108+
{TASK_SIZE_MAX, ~0UL},
109+
{0, 0}
110+
};
111+
105112
#define pt_dump_seq_printf(m, fmt, args...) \
106113
({ \
107114
if (m) \
@@ -204,10 +211,10 @@ static void note_page_update_state(struct pg_state *st, unsigned long addr, int
204211
}
205212
}
206213

207-
static void note_page(struct pg_state *st, unsigned long addr,
208-
int level, u64 val, unsigned long page_size)
214+
static void note_page(struct ptdump_state *pt_st, unsigned long addr, int level, u64 val)
209215
{
210216
u64 flag = level >= 0 ? val & pg_level[level].mask : 0;
217+
struct pg_state *st = container_of(pt_st, struct pg_state, ptdump);
211218

212219
/* At first no level is set */
213220
if (st->level == -1) {
@@ -245,94 +252,6 @@ static void note_page(struct pg_state *st, unsigned long addr,
245252
}
246253
}
247254

248-
static void walk_pte(struct pg_state *st, pmd_t *pmd, unsigned long start)
249-
{
250-
pte_t *pte = pte_offset_kernel(pmd, 0);
251-
unsigned long addr;
252-
unsigned int i;
253-
254-
for (i = 0; i < PTRS_PER_PTE; i++, pte++) {
255-
addr = start + i * PAGE_SIZE;
256-
note_page(st, addr, 4, pte_val(*pte), PAGE_SIZE);
257-
258-
}
259-
}
260-
261-
static void walk_hugepd(struct pg_state *st, hugepd_t *phpd, unsigned long start,
262-
int pdshift, int level)
263-
{
264-
#ifdef CONFIG_ARCH_HAS_HUGEPD
265-
unsigned int i;
266-
int shift = hugepd_shift(*phpd);
267-
int ptrs_per_hpd = pdshift - shift > 0 ? 1 << (pdshift - shift) : 1;
268-
269-
if (start & ((1 << shift) - 1))
270-
return;
271-
272-
for (i = 0; i < ptrs_per_hpd; i++) {
273-
unsigned long addr = start + (i << shift);
274-
pte_t *pte = hugepte_offset(*phpd, addr, pdshift);
275-
276-
note_page(st, addr, level + 1, pte_val(*pte), 1 << shift);
277-
}
278-
#endif
279-
}
280-
281-
static void walk_pmd(struct pg_state *st, pud_t *pud, unsigned long start)
282-
{
283-
pmd_t *pmd = pmd_offset(pud, 0);
284-
unsigned long addr;
285-
unsigned int i;
286-
287-
for (i = 0; i < PTRS_PER_PMD; i++, pmd++) {
288-
addr = start + i * PMD_SIZE;
289-
if (!pmd_none(*pmd) && !pmd_is_leaf(*pmd))
290-
/* pmd exists */
291-
walk_pte(st, pmd, addr);
292-
else
293-
note_page(st, addr, 3, pmd_val(*pmd), PMD_SIZE);
294-
}
295-
}
296-
297-
static void walk_pud(struct pg_state *st, p4d_t *p4d, unsigned long start)
298-
{
299-
pud_t *pud = pud_offset(p4d, 0);
300-
unsigned long addr;
301-
unsigned int i;
302-
303-
for (i = 0; i < PTRS_PER_PUD; i++, pud++) {
304-
addr = start + i * PUD_SIZE;
305-
if (!pud_none(*pud) && !pud_is_leaf(*pud))
306-
/* pud exists */
307-
walk_pmd(st, pud, addr);
308-
else
309-
note_page(st, addr, 2, pud_val(*pud), PUD_SIZE);
310-
}
311-
}
312-
313-
static void walk_pagetables(struct pg_state *st)
314-
{
315-
unsigned int i;
316-
unsigned long addr = st->start_address & PGDIR_MASK;
317-
pgd_t *pgd = pgd_offset_k(addr);
318-
319-
/*
320-
* Traverse the linux pagetable structure and dump pages that are in
321-
* the hash pagetable.
322-
*/
323-
for (i = pgd_index(addr); i < PTRS_PER_PGD; i++, pgd++, addr += PGDIR_SIZE) {
324-
p4d_t *p4d = p4d_offset(pgd, 0);
325-
326-
if (p4d_none(*p4d) || p4d_is_leaf(*p4d))
327-
note_page(st, addr, 1, p4d_val(*p4d), PGDIR_SIZE);
328-
else if (is_hugepd(__hugepd(p4d_val(*p4d))))
329-
walk_hugepd(st, (hugepd_t *)p4d, addr, PGDIR_SHIFT, 1);
330-
else
331-
/* p4d exists */
332-
walk_pud(st, p4d, addr);
333-
}
334-
}
335-
336255
static void populate_markers(void)
337256
{
338257
int i = 0;
@@ -383,17 +302,14 @@ static int ptdump_show(struct seq_file *m, void *v)
383302
.seq = m,
384303
.marker = address_markers,
385304
.level = -1,
386-
.start_address = IS_ENABLED(CONFIG_PPC64) ? PAGE_OFFSET : TASK_SIZE,
305+
.ptdump = {
306+
.note_page = note_page,
307+
.range = ptdump_range,
308+
}
387309
};
388310

389-
#ifdef CONFIG_PPC64
390-
if (!radix_enabled())
391-
st.start_address = KERN_VIRT_START;
392-
#endif
393-
394311
/* Traverse kernel page tables */
395-
walk_pagetables(&st);
396-
note_page(&st, 0, -1, 0, 0);
312+
ptdump_walk_pgd(&st.ptdump, &init_mm, NULL);
397313
return 0;
398314
}
399315

@@ -409,23 +325,24 @@ static void build_pgtable_complete_mask(void)
409325
pg_level[i].mask |= pg_level[i].flag[j].mask;
410326
}
411327

412-
#ifdef CONFIG_PPC_DEBUG_WX
328+
#ifdef CONFIG_DEBUG_WX
413329
void ptdump_check_wx(void)
414330
{
415331
struct pg_state st = {
416332
.seq = NULL,
417-
.marker = address_markers,
333+
.marker = (struct addr_marker[]) {
334+
{ 0, NULL},
335+
{ -1, NULL},
336+
},
418337
.level = -1,
419338
.check_wx = true,
420-
.start_address = IS_ENABLED(CONFIG_PPC64) ? PAGE_OFFSET : TASK_SIZE,
339+
.ptdump = {
340+
.note_page = note_page,
341+
.range = ptdump_range,
342+
}
421343
};
422344

423-
#ifdef CONFIG_PPC64
424-
if (!radix_enabled())
425-
st.start_address = KERN_VIRT_START;
426-
#endif
427-
428-
walk_pagetables(&st);
345+
ptdump_walk_pgd(&st.ptdump, &init_mm, NULL);
429346

430347
if (st.wx_pages)
431348
pr_warn("Checked W+X mappings: FAILED, %lu W+X pages found\n",
@@ -435,12 +352,21 @@ void ptdump_check_wx(void)
435352
}
436353
#endif
437354

438-
static int ptdump_init(void)
355+
static int __init ptdump_init(void)
439356
{
357+
#ifdef CONFIG_PPC64
358+
if (!radix_enabled())
359+
ptdump_range[0].start = KERN_VIRT_START;
360+
else
361+
ptdump_range[0].start = PAGE_OFFSET;
362+
#endif
363+
440364
populate_markers();
441365
build_pgtable_complete_mask();
442-
debugfs_create_file("kernel_page_tables", 0400, NULL, NULL,
443-
&ptdump_fops);
366+
367+
if (IS_ENABLED(CONFIG_PTDUMP_DEBUGFS))
368+
debugfs_create_file("kernel_page_tables", 0400, NULL, NULL, &ptdump_fops);
369+
444370
return 0;
445371
}
446372
device_initcall(ptdump_init);

0 commit comments

Comments
 (0)