This source file includes following definitions.
- dump_flag_info
- dump_addr
- note_prot_wx
- note_page
- walk_pte
- walk_pmd
- walk_pud
- walk_pagetables
- populate_markers
- ptdump_show
- ptdump_open
- build_pgtable_complete_mask
- ptdump_check_wx
- ptdump_init
1
2
3
4
5
6
7
8
9
10
11
12
13 #include <linux/debugfs.h>
14 #include <linux/fs.h>
15 #include <linux/hugetlb.h>
16 #include <linux/io.h>
17 #include <linux/mm.h>
18 #include <linux/highmem.h>
19 #include <linux/sched.h>
20 #include <linux/seq_file.h>
21 #include <asm/fixmap.h>
22 #include <asm/pgtable.h>
23 #include <linux/const.h>
24 #include <asm/page.h>
25 #include <asm/pgalloc.h>
26
27 #include "ptdump.h"
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 struct pg_state {
56 struct seq_file *seq;
57 const struct addr_marker *marker;
58 unsigned long start_address;
59 unsigned long start_pa;
60 unsigned long last_pa;
61 unsigned long page_size;
62 unsigned int level;
63 u64 current_flags;
64 bool check_wx;
65 unsigned long wx_pages;
66 };
67
68 struct addr_marker {
69 unsigned long start_address;
70 const char *name;
71 };
72
73 static struct addr_marker address_markers[] = {
74 { 0, "Start of kernel VM" },
75 { 0, "vmalloc() Area" },
76 { 0, "vmalloc() End" },
77 #ifdef CONFIG_PPC64
78 { 0, "isa I/O start" },
79 { 0, "isa I/O end" },
80 { 0, "phb I/O start" },
81 { 0, "phb I/O end" },
82 { 0, "I/O remap start" },
83 { 0, "I/O remap end" },
84 { 0, "vmemmap start" },
85 #else
86 { 0, "Early I/O remap start" },
87 { 0, "Early I/O remap end" },
88 #ifdef CONFIG_HIGHMEM
89 { 0, "Highmem PTEs start" },
90 { 0, "Highmem PTEs end" },
91 #endif
92 { 0, "Fixmap start" },
93 { 0, "Fixmap end" },
94 #endif
95 #ifdef CONFIG_KASAN
96 { 0, "kasan shadow mem start" },
97 { 0, "kasan shadow mem end" },
98 #endif
99 { -1, NULL },
100 };
101
102 #define pt_dump_seq_printf(m, fmt, args...) \
103 ({ \
104 if (m) \
105 seq_printf(m, fmt, ##args); \
106 })
107
108 #define pt_dump_seq_putc(m, c) \
109 ({ \
110 if (m) \
111 seq_putc(m, c); \
112 })
113
114 static void dump_flag_info(struct pg_state *st, const struct flag_info
115 *flag, u64 pte, int num)
116 {
117 unsigned int i;
118
119 for (i = 0; i < num; i++, flag++) {
120 const char *s = NULL;
121 u64 val;
122
123
124 if (flag->mask == 0)
125 continue;
126
127 if (flag->is_val) {
128 val = pte & flag->val;
129 if (flag->shift)
130 val = val >> flag->shift;
131 pt_dump_seq_printf(st->seq, " %s:%llx", flag->set, val);
132 } else {
133 if ((pte & flag->mask) == flag->val)
134 s = flag->set;
135 else
136 s = flag->clear;
137 if (s)
138 pt_dump_seq_printf(st->seq, " %s", s);
139 }
140 st->current_flags &= ~flag->mask;
141 }
142 if (st->current_flags != 0)
143 pt_dump_seq_printf(st->seq, " unknown flags:%llx", st->current_flags);
144 }
145
146 static void dump_addr(struct pg_state *st, unsigned long addr)
147 {
148 static const char units[] = "KMGTPE";
149 const char *unit = units;
150 unsigned long delta;
151
152 #ifdef CONFIG_PPC64
153 #define REG "0x%016lx"
154 #else
155 #define REG "0x%08lx"
156 #endif
157
158 pt_dump_seq_printf(st->seq, REG "-" REG " ", st->start_address, addr - 1);
159 if (st->start_pa == st->last_pa && st->start_address + st->page_size != addr) {
160 pt_dump_seq_printf(st->seq, "[" REG "]", st->start_pa);
161 delta = st->page_size >> 10;
162 } else {
163 pt_dump_seq_printf(st->seq, " " REG " ", st->start_pa);
164 delta = (addr - st->start_address) >> 10;
165 }
166
167 while (!(delta & 1023) && unit[1]) {
168 delta >>= 10;
169 unit++;
170 }
171 pt_dump_seq_printf(st->seq, "%9lu%c", delta, *unit);
172
173 }
174
175 static void note_prot_wx(struct pg_state *st, unsigned long addr)
176 {
177 pte_t pte = __pte(st->current_flags);
178
179 if (!IS_ENABLED(CONFIG_PPC_DEBUG_WX) || !st->check_wx)
180 return;
181
182 if (!pte_write(pte) || !pte_exec(pte))
183 return;
184
185 WARN_ONCE(1, "powerpc/mm: Found insecure W+X mapping at address %p/%pS\n",
186 (void *)st->start_address, (void *)st->start_address);
187
188 st->wx_pages += (addr - st->start_address) / PAGE_SIZE;
189 }
190
191 static void note_page(struct pg_state *st, unsigned long addr,
192 unsigned int level, u64 val, unsigned long page_size)
193 {
194 u64 flag = val & pg_level[level].mask;
195 u64 pa = val & PTE_RPN_MASK;
196
197
198 if (!st->level) {
199 st->level = level;
200 st->current_flags = flag;
201 st->start_address = addr;
202 st->start_pa = pa;
203 st->last_pa = pa;
204 st->page_size = page_size;
205 pt_dump_seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
206
207
208
209
210
211
212
213
214 } else if (flag != st->current_flags || level != st->level ||
215 addr >= st->marker[1].start_address ||
216 (pa != st->last_pa + st->page_size &&
217 (pa != st->start_pa || st->start_pa != st->last_pa))) {
218
219
220 if (st->current_flags) {
221 note_prot_wx(st, addr);
222 dump_addr(st, addr);
223
224
225 if (pg_level[st->level].flag)
226 dump_flag_info(st, pg_level[st->level].flag,
227 st->current_flags,
228 pg_level[st->level].num);
229
230 pt_dump_seq_putc(st->seq, '\n');
231 }
232
233
234
235
236
237 while (addr >= st->marker[1].start_address) {
238 st->marker++;
239 pt_dump_seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
240 }
241 st->start_address = addr;
242 st->start_pa = pa;
243 st->last_pa = pa;
244 st->page_size = page_size;
245 st->current_flags = flag;
246 st->level = level;
247 } else {
248 st->last_pa = pa;
249 }
250 }
251
252 static void walk_pte(struct pg_state *st, pmd_t *pmd, unsigned long start)
253 {
254 pte_t *pte = pte_offset_kernel(pmd, 0);
255 unsigned long addr;
256 unsigned int i;
257
258 for (i = 0; i < PTRS_PER_PTE; i++, pte++) {
259 addr = start + i * PAGE_SIZE;
260 note_page(st, addr, 4, pte_val(*pte), PAGE_SIZE);
261
262 }
263 }
264
265 static void walk_pmd(struct pg_state *st, pud_t *pud, unsigned long start)
266 {
267 pmd_t *pmd = pmd_offset(pud, 0);
268 unsigned long addr;
269 unsigned int i;
270
271 for (i = 0; i < PTRS_PER_PMD; i++, pmd++) {
272 addr = start + i * PMD_SIZE;
273 if (!pmd_none(*pmd) && !pmd_is_leaf(*pmd))
274
275 walk_pte(st, pmd, addr);
276 else
277 note_page(st, addr, 3, pmd_val(*pmd), PMD_SIZE);
278 }
279 }
280
281 static void walk_pud(struct pg_state *st, pgd_t *pgd, unsigned long start)
282 {
283 pud_t *pud = pud_offset(pgd, 0);
284 unsigned long addr;
285 unsigned int i;
286
287 for (i = 0; i < PTRS_PER_PUD; i++, pud++) {
288 addr = start + i * PUD_SIZE;
289 if (!pud_none(*pud) && !pud_is_leaf(*pud))
290
291 walk_pmd(st, pud, addr);
292 else
293 note_page(st, addr, 2, pud_val(*pud), PUD_SIZE);
294 }
295 }
296
297 static void walk_pagetables(struct pg_state *st)
298 {
299 unsigned int i;
300 unsigned long addr = st->start_address & PGDIR_MASK;
301 pgd_t *pgd = pgd_offset_k(addr);
302
303
304
305
306
307 for (i = pgd_index(addr); i < PTRS_PER_PGD; i++, pgd++, addr += PGDIR_SIZE) {
308 if (!pgd_none(*pgd) && !pgd_is_leaf(*pgd))
309
310 walk_pud(st, pgd, addr);
311 else
312 note_page(st, addr, 1, pgd_val(*pgd), PGDIR_SIZE);
313 }
314 }
315
316 static void populate_markers(void)
317 {
318 int i = 0;
319
320 address_markers[i++].start_address = PAGE_OFFSET;
321 address_markers[i++].start_address = VMALLOC_START;
322 address_markers[i++].start_address = VMALLOC_END;
323 #ifdef CONFIG_PPC64
324 address_markers[i++].start_address = ISA_IO_BASE;
325 address_markers[i++].start_address = ISA_IO_END;
326 address_markers[i++].start_address = PHB_IO_BASE;
327 address_markers[i++].start_address = PHB_IO_END;
328 address_markers[i++].start_address = IOREMAP_BASE;
329 address_markers[i++].start_address = IOREMAP_END;
330
331 #ifdef CONFIG_PPC_BOOK3S_64
332 address_markers[i++].start_address = H_VMEMMAP_START;
333 #else
334 address_markers[i++].start_address = VMEMMAP_BASE;
335 #endif
336 #else
337 address_markers[i++].start_address = ioremap_bot;
338 address_markers[i++].start_address = IOREMAP_TOP;
339 #ifdef CONFIG_HIGHMEM
340 address_markers[i++].start_address = PKMAP_BASE;
341 address_markers[i++].start_address = PKMAP_ADDR(LAST_PKMAP);
342 #endif
343 address_markers[i++].start_address = FIXADDR_START;
344 address_markers[i++].start_address = FIXADDR_TOP;
345 #ifdef CONFIG_KASAN
346 address_markers[i++].start_address = KASAN_SHADOW_START;
347 address_markers[i++].start_address = KASAN_SHADOW_END;
348 #endif
349 #endif
350 }
351
352 static int ptdump_show(struct seq_file *m, void *v)
353 {
354 struct pg_state st = {
355 .seq = m,
356 .marker = address_markers,
357 .start_address = PAGE_OFFSET,
358 };
359
360 #ifdef CONFIG_PPC64
361 if (!radix_enabled())
362 st.start_address = KERN_VIRT_START;
363 #endif
364
365
366 walk_pagetables(&st);
367 note_page(&st, 0, 0, 0, 0);
368 return 0;
369 }
370
371
372 static int ptdump_open(struct inode *inode, struct file *file)
373 {
374 return single_open(file, ptdump_show, NULL);
375 }
376
377 static const struct file_operations ptdump_fops = {
378 .open = ptdump_open,
379 .read = seq_read,
380 .llseek = seq_lseek,
381 .release = single_release,
382 };
383
384 static void build_pgtable_complete_mask(void)
385 {
386 unsigned int i, j;
387
388 for (i = 0; i < ARRAY_SIZE(pg_level); i++)
389 if (pg_level[i].flag)
390 for (j = 0; j < pg_level[i].num; j++)
391 pg_level[i].mask |= pg_level[i].flag[j].mask;
392 }
393
394 #ifdef CONFIG_PPC_DEBUG_WX
395 void ptdump_check_wx(void)
396 {
397 struct pg_state st = {
398 .seq = NULL,
399 .marker = address_markers,
400 .check_wx = true,
401 .start_address = PAGE_OFFSET,
402 };
403
404 #ifdef CONFIG_PPC64
405 if (!radix_enabled())
406 st.start_address = KERN_VIRT_START;
407 #endif
408
409 walk_pagetables(&st);
410
411 if (st.wx_pages)
412 pr_warn("Checked W+X mappings: FAILED, %lu W+X pages found\n",
413 st.wx_pages);
414 else
415 pr_info("Checked W+X mappings: passed, no W+X pages found\n");
416 }
417 #endif
418
419 static int ptdump_init(void)
420 {
421 struct dentry *debugfs_file;
422
423 populate_markers();
424 build_pgtable_complete_mask();
425 debugfs_file = debugfs_create_file("kernel_page_tables", 0400, NULL,
426 NULL, &ptdump_fops);
427 return debugfs_file ? 0 : -ENOMEM;
428 }
429 device_initcall(ptdump_init);