1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include <linux/debugfs.h>
16#include <linux/kasan.h>
17#include <linux/mm.h>
18#include <linux/init.h>
19#include <linux/sched.h>
20#include <linux/seq_file.h>
21#include <linux/highmem.h>
22
23#include <asm/pgtable.h>
24
25
26
27
28
29
30struct pg_state {
31 int level;
32 pgprot_t current_prot;
33 pgprotval_t effective_prot;
34 unsigned long start_address;
35 unsigned long current_address;
36 const struct addr_marker *marker;
37 unsigned long lines;
38 bool to_dmesg;
39 bool check_wx;
40 unsigned long wx_pages;
41};
42
43struct addr_marker {
44 unsigned long start_address;
45 const char *name;
46 unsigned long max_lines;
47};
48
49
50
51#ifdef CONFIG_X86_64
52
53enum address_markers_idx {
54 USER_SPACE_NR = 0,
55 KERNEL_SPACE_NR,
56#ifdef CONFIG_MODIFY_LDT_SYSCALL
57 LDT_NR,
58#endif
59 LOW_KERNEL_NR,
60 VMALLOC_START_NR,
61 VMEMMAP_START_NR,
62#ifdef CONFIG_KASAN
63 KASAN_SHADOW_START_NR,
64 KASAN_SHADOW_END_NR,
65#endif
66 CPU_ENTRY_AREA_NR,
67#ifdef CONFIG_X86_ESPFIX64
68 ESPFIX_START_NR,
69#endif
70#ifdef CONFIG_EFI
71 EFI_END_NR,
72#endif
73 HIGH_KERNEL_NR,
74 MODULES_VADDR_NR,
75 MODULES_END_NR,
76 FIXADDR_START_NR,
77 END_OF_SPACE_NR,
78};
79
80static struct addr_marker address_markers[] = {
81 [USER_SPACE_NR] = { 0, "User Space" },
82 [KERNEL_SPACE_NR] = { (1UL << 63), "Kernel Space" },
83 [LOW_KERNEL_NR] = { 0UL, "Low Kernel Mapping" },
84 [VMALLOC_START_NR] = { 0UL, "vmalloc() Area" },
85 [VMEMMAP_START_NR] = { 0UL, "Vmemmap" },
86#ifdef CONFIG_KASAN
87
88
89
90
91 [KASAN_SHADOW_START_NR] = { 0UL, "KASAN shadow" },
92 [KASAN_SHADOW_END_NR] = { 0UL, "KASAN shadow end" },
93#endif
94#ifdef CONFIG_MODIFY_LDT_SYSCALL
95 [LDT_NR] = { 0UL, "LDT remap" },
96#endif
97 [CPU_ENTRY_AREA_NR] = { CPU_ENTRY_AREA_BASE,"CPU entry Area" },
98#ifdef CONFIG_X86_ESPFIX64
99 [ESPFIX_START_NR] = { ESPFIX_BASE_ADDR, "ESPfix Area", 16 },
100#endif
101#ifdef CONFIG_EFI
102 [EFI_END_NR] = { EFI_VA_END, "EFI Runtime Services" },
103#endif
104 [HIGH_KERNEL_NR] = { __START_KERNEL_map, "High Kernel Mapping" },
105 [MODULES_VADDR_NR] = { MODULES_VADDR, "Modules" },
106 [MODULES_END_NR] = { MODULES_END, "End Modules" },
107 [FIXADDR_START_NR] = { FIXADDR_START, "Fixmap Area" },
108 [END_OF_SPACE_NR] = { -1, NULL }
109};
110
111#else
112
113enum address_markers_idx {
114 USER_SPACE_NR = 0,
115 KERNEL_SPACE_NR,
116 VMALLOC_START_NR,
117 VMALLOC_END_NR,
118#ifdef CONFIG_HIGHMEM
119 PKMAP_BASE_NR,
120#endif
121#ifdef CONFIG_MODIFY_LDT_SYSCALL
122 LDT_NR,
123#endif
124 CPU_ENTRY_AREA_NR,
125 FIXADDR_START_NR,
126 END_OF_SPACE_NR,
127};
128
129static struct addr_marker address_markers[] = {
130 [USER_SPACE_NR] = { 0, "User Space" },
131 [KERNEL_SPACE_NR] = { PAGE_OFFSET, "Kernel Mapping" },
132 [VMALLOC_START_NR] = { 0UL, "vmalloc() Area" },
133 [VMALLOC_END_NR] = { 0UL, "vmalloc() End" },
134#ifdef CONFIG_HIGHMEM
135 [PKMAP_BASE_NR] = { 0UL, "Persistent kmap() Area" },
136#endif
137#ifdef CONFIG_MODIFY_LDT_SYSCALL
138 [LDT_NR] = { 0UL, "LDT remap" },
139#endif
140 [CPU_ENTRY_AREA_NR] = { 0UL, "CPU entry area" },
141 [FIXADDR_START_NR] = { 0UL, "Fixmap area" },
142 [END_OF_SPACE_NR] = { -1, NULL }
143};
144
145#endif
146
147
148#define PTE_LEVEL_MULT (PAGE_SIZE)
149#define PMD_LEVEL_MULT (PTRS_PER_PTE * PTE_LEVEL_MULT)
150#define PUD_LEVEL_MULT (PTRS_PER_PMD * PMD_LEVEL_MULT)
151#define P4D_LEVEL_MULT (PTRS_PER_PUD * PUD_LEVEL_MULT)
152#define PGD_LEVEL_MULT (PTRS_PER_P4D * P4D_LEVEL_MULT)
153
154#define pt_dump_seq_printf(m, to_dmesg, fmt, args...) \
155({ \
156 if (to_dmesg) \
157 printk(KERN_INFO fmt, ##args); \
158 else \
159 if (m) \
160 seq_printf(m, fmt, ##args); \
161})
162
163#define pt_dump_cont_printf(m, to_dmesg, fmt, args...) \
164({ \
165 if (to_dmesg) \
166 printk(KERN_CONT fmt, ##args); \
167 else \
168 if (m) \
169 seq_printf(m, fmt, ##args); \
170})
171
172
173
174
175static void printk_prot(struct seq_file *m, pgprot_t prot, int level, bool dmsg)
176{
177 pgprotval_t pr = pgprot_val(prot);
178 static const char * const level_name[] =
179 { "cr3", "pgd", "p4d", "pud", "pmd", "pte" };
180
181 if (!(pr & _PAGE_PRESENT)) {
182
183 pt_dump_cont_printf(m, dmsg, " ");
184 } else {
185 if (pr & _PAGE_USER)
186 pt_dump_cont_printf(m, dmsg, "USR ");
187 else
188 pt_dump_cont_printf(m, dmsg, " ");
189 if (pr & _PAGE_RW)
190 pt_dump_cont_printf(m, dmsg, "RW ");
191 else
192 pt_dump_cont_printf(m, dmsg, "ro ");
193 if (pr & _PAGE_PWT)
194 pt_dump_cont_printf(m, dmsg, "PWT ");
195 else
196 pt_dump_cont_printf(m, dmsg, " ");
197 if (pr & _PAGE_PCD)
198 pt_dump_cont_printf(m, dmsg, "PCD ");
199 else
200 pt_dump_cont_printf(m, dmsg, " ");
201
202
203 if (level <= 4 && pr & _PAGE_PSE)
204 pt_dump_cont_printf(m, dmsg, "PSE ");
205 else
206 pt_dump_cont_printf(m, dmsg, " ");
207 if ((level == 5 && pr & _PAGE_PAT) ||
208 ((level == 4 || level == 3) && pr & _PAGE_PAT_LARGE))
209 pt_dump_cont_printf(m, dmsg, "PAT ");
210 else
211 pt_dump_cont_printf(m, dmsg, " ");
212 if (pr & _PAGE_GLOBAL)
213 pt_dump_cont_printf(m, dmsg, "GLB ");
214 else
215 pt_dump_cont_printf(m, dmsg, " ");
216 if (pr & _PAGE_NX)
217 pt_dump_cont_printf(m, dmsg, "NX ");
218 else
219 pt_dump_cont_printf(m, dmsg, "x ");
220 }
221 pt_dump_cont_printf(m, dmsg, "%s\n", level_name[level]);
222}
223
224
225
226
227static unsigned long normalize_addr(unsigned long u)
228{
229 int shift;
230 if (!IS_ENABLED(CONFIG_X86_64))
231 return u;
232
233 shift = 64 - (__VIRTUAL_MASK_SHIFT + 1);
234 return (signed long)(u << shift) >> shift;
235}
236
237
238
239
240
241
242static void note_page(struct seq_file *m, struct pg_state *st,
243 pgprot_t new_prot, pgprotval_t new_eff, int level)
244{
245 pgprotval_t prot, cur, eff;
246 static const char units[] = "BKMGTPE";
247
248
249
250
251
252
253 prot = pgprot_val(new_prot);
254 cur = pgprot_val(st->current_prot);
255 eff = st->effective_prot;
256
257 if (!st->level) {
258
259 st->current_prot = new_prot;
260 st->effective_prot = new_eff;
261 st->level = level;
262 st->marker = address_markers;
263 st->lines = 0;
264 pt_dump_seq_printf(m, st->to_dmesg, "---[ %s ]---\n",
265 st->marker->name);
266 } else if (prot != cur || new_eff != eff || level != st->level ||
267 st->current_address >= st->marker[1].start_address) {
268 const char *unit = units;
269 unsigned long delta;
270 int width = sizeof(unsigned long) * 2;
271
272 if (st->check_wx && (eff & _PAGE_RW) && !(eff & _PAGE_NX)) {
273 WARN_ONCE(1,
274 "x86/mm: Found insecure W+X mapping at address %p/%pS\n",
275 (void *)st->start_address,
276 (void *)st->start_address);
277 st->wx_pages += (st->current_address -
278 st->start_address) / PAGE_SIZE;
279 }
280
281
282
283
284 if (!st->marker->max_lines ||
285 st->lines < st->marker->max_lines) {
286 pt_dump_seq_printf(m, st->to_dmesg,
287 "0x%0*lx-0x%0*lx ",
288 width, st->start_address,
289 width, st->current_address);
290
291 delta = st->current_address - st->start_address;
292 while (!(delta & 1023) && unit[1]) {
293 delta >>= 10;
294 unit++;
295 }
296 pt_dump_cont_printf(m, st->to_dmesg, "%9lu%c ",
297 delta, *unit);
298 printk_prot(m, st->current_prot, st->level,
299 st->to_dmesg);
300 }
301 st->lines++;
302
303
304
305
306
307
308 if (st->current_address >= st->marker[1].start_address) {
309 if (st->marker->max_lines &&
310 st->lines > st->marker->max_lines) {
311 unsigned long nskip =
312 st->lines - st->marker->max_lines;
313 pt_dump_seq_printf(m, st->to_dmesg,
314 "... %lu entr%s skipped ... \n",
315 nskip,
316 nskip == 1 ? "y" : "ies");
317 }
318 st->marker++;
319 st->lines = 0;
320 pt_dump_seq_printf(m, st->to_dmesg, "---[ %s ]---\n",
321 st->marker->name);
322 }
323
324 st->start_address = st->current_address;
325 st->current_prot = new_prot;
326 st->effective_prot = new_eff;
327 st->level = level;
328 }
329}
330
331static inline pgprotval_t effective_prot(pgprotval_t prot1, pgprotval_t prot2)
332{
333 return (prot1 & prot2 & (_PAGE_USER | _PAGE_RW)) |
334 ((prot1 | prot2) & _PAGE_NX);
335}
336
337static void walk_pte_level(struct seq_file *m, struct pg_state *st, pmd_t addr,
338 pgprotval_t eff_in, unsigned long P)
339{
340 int i;
341 pte_t *pte;
342 pgprotval_t prot, eff;
343
344 for (i = 0; i < PTRS_PER_PTE; i++) {
345 st->current_address = normalize_addr(P + i * PTE_LEVEL_MULT);
346 pte = pte_offset_map(&addr, st->current_address);
347 prot = pte_flags(*pte);
348 eff = effective_prot(eff_in, prot);
349 note_page(m, st, __pgprot(prot), eff, 5);
350 pte_unmap(pte);
351 }
352}
353#ifdef CONFIG_KASAN
354
355
356
357
358
359
360
361
362static inline bool kasan_page_table(struct seq_file *m, struct pg_state *st,
363 void *pt)
364{
365 if (__pa(pt) == __pa(kasan_early_shadow_pmd) ||
366 (pgtable_l5_enabled() &&
367 __pa(pt) == __pa(kasan_early_shadow_p4d)) ||
368 __pa(pt) == __pa(kasan_early_shadow_pud)) {
369 pgprotval_t prot = pte_flags(kasan_early_shadow_pte[0]);
370 note_page(m, st, __pgprot(prot), 0, 5);
371 return true;
372 }
373 return false;
374}
375#else
376static inline bool kasan_page_table(struct seq_file *m, struct pg_state *st,
377 void *pt)
378{
379 return false;
380}
381#endif
382
383#if PTRS_PER_PMD > 1
384
385static void walk_pmd_level(struct seq_file *m, struct pg_state *st, pud_t addr,
386 pgprotval_t eff_in, unsigned long P)
387{
388 int i;
389 pmd_t *start, *pmd_start;
390 pgprotval_t prot, eff;
391
392 pmd_start = start = (pmd_t *)pud_page_vaddr(addr);
393 for (i = 0; i < PTRS_PER_PMD; i++) {
394 st->current_address = normalize_addr(P + i * PMD_LEVEL_MULT);
395 if (!pmd_none(*start)) {
396 prot = pmd_flags(*start);
397 eff = effective_prot(eff_in, prot);
398 if (pmd_large(*start) || !pmd_present(*start)) {
399 note_page(m, st, __pgprot(prot), eff, 4);
400 } else if (!kasan_page_table(m, st, pmd_start)) {
401 walk_pte_level(m, st, *start, eff,
402 P + i * PMD_LEVEL_MULT);
403 }
404 } else
405 note_page(m, st, __pgprot(0), 0, 4);
406 start++;
407 }
408}
409
410#else
411#define walk_pmd_level(m,s,a,e,p) walk_pte_level(m,s,__pmd(pud_val(a)),e,p)
412#define pud_large(a) pmd_large(__pmd(pud_val(a)))
413#define pud_none(a) pmd_none(__pmd(pud_val(a)))
414#endif
415
416#if PTRS_PER_PUD > 1
417
418static void walk_pud_level(struct seq_file *m, struct pg_state *st, p4d_t addr,
419 pgprotval_t eff_in, unsigned long P)
420{
421 int i;
422 pud_t *start, *pud_start;
423 pgprotval_t prot, eff;
424 pud_t *prev_pud = NULL;
425
426 pud_start = start = (pud_t *)p4d_page_vaddr(addr);
427
428 for (i = 0; i < PTRS_PER_PUD; i++) {
429 st->current_address = normalize_addr(P + i * PUD_LEVEL_MULT);
430 if (!pud_none(*start)) {
431 prot = pud_flags(*start);
432 eff = effective_prot(eff_in, prot);
433 if (pud_large(*start) || !pud_present(*start)) {
434 note_page(m, st, __pgprot(prot), eff, 3);
435 } else if (!kasan_page_table(m, st, pud_start)) {
436 walk_pmd_level(m, st, *start, eff,
437 P + i * PUD_LEVEL_MULT);
438 }
439 } else
440 note_page(m, st, __pgprot(0), 0, 3);
441
442 prev_pud = start;
443 start++;
444 }
445}
446
447#else
448#define walk_pud_level(m,s,a,e,p) walk_pmd_level(m,s,__pud(p4d_val(a)),e,p)
449#define p4d_large(a) pud_large(__pud(p4d_val(a)))
450#define p4d_none(a) pud_none(__pud(p4d_val(a)))
451#endif
452
453static void walk_p4d_level(struct seq_file *m, struct pg_state *st, pgd_t addr,
454 pgprotval_t eff_in, unsigned long P)
455{
456 int i;
457 p4d_t *start, *p4d_start;
458 pgprotval_t prot, eff;
459
460 if (PTRS_PER_P4D == 1)
461 return walk_pud_level(m, st, __p4d(pgd_val(addr)), eff_in, P);
462
463 p4d_start = start = (p4d_t *)pgd_page_vaddr(addr);
464
465 for (i = 0; i < PTRS_PER_P4D; i++) {
466 st->current_address = normalize_addr(P + i * P4D_LEVEL_MULT);
467 if (!p4d_none(*start)) {
468 prot = p4d_flags(*start);
469 eff = effective_prot(eff_in, prot);
470 if (p4d_large(*start) || !p4d_present(*start)) {
471 note_page(m, st, __pgprot(prot), eff, 2);
472 } else if (!kasan_page_table(m, st, p4d_start)) {
473 walk_pud_level(m, st, *start, eff,
474 P + i * P4D_LEVEL_MULT);
475 }
476 } else
477 note_page(m, st, __pgprot(0), 0, 2);
478
479 start++;
480 }
481}
482
483#define pgd_large(a) (pgtable_l5_enabled() ? pgd_large(a) : p4d_large(__p4d(pgd_val(a))))
484#define pgd_none(a) (pgtable_l5_enabled() ? pgd_none(a) : p4d_none(__p4d(pgd_val(a))))
485
486static inline bool is_hypervisor_range(int idx)
487{
488#ifdef CONFIG_X86_64
489
490
491
492
493 return (idx >= pgd_index(GUARD_HOLE_BASE_ADDR)) &&
494 (idx < pgd_index(GUARD_HOLE_END_ADDR));
495#else
496 return false;
497#endif
498}
499
500static void ptdump_walk_pgd_level_core(struct seq_file *m, pgd_t *pgd,
501 bool checkwx, bool dmesg)
502{
503#ifdef CONFIG_X86_64
504 pgd_t *start = (pgd_t *) &init_top_pgt;
505#else
506 pgd_t *start = swapper_pg_dir;
507#endif
508 pgprotval_t prot, eff;
509 int i;
510 struct pg_state st = {};
511
512 if (pgd) {
513 start = pgd;
514 st.to_dmesg = dmesg;
515 }
516
517 st.check_wx = checkwx;
518 if (checkwx)
519 st.wx_pages = 0;
520
521 for (i = 0; i < PTRS_PER_PGD; i++) {
522 st.current_address = normalize_addr(i * PGD_LEVEL_MULT);
523 if (!pgd_none(*start) && !is_hypervisor_range(i)) {
524 prot = pgd_flags(*start);
525#ifdef CONFIG_X86_PAE
526 eff = _PAGE_USER | _PAGE_RW;
527#else
528 eff = prot;
529#endif
530 if (pgd_large(*start) || !pgd_present(*start)) {
531 note_page(m, &st, __pgprot(prot), eff, 1);
532 } else {
533 walk_p4d_level(m, &st, *start, eff,
534 i * PGD_LEVEL_MULT);
535 }
536 } else
537 note_page(m, &st, __pgprot(0), 0, 1);
538
539 cond_resched();
540 start++;
541 }
542
543
544 st.current_address = normalize_addr(PTRS_PER_PGD*PGD_LEVEL_MULT);
545 note_page(m, &st, __pgprot(0), 0, 0);
546 if (!checkwx)
547 return;
548 if (st.wx_pages)
549 pr_info("x86/mm: Checked W+X mappings: FAILED, %lu W+X pages found.\n",
550 st.wx_pages);
551 else
552 pr_info("x86/mm: Checked W+X mappings: passed, no W+X pages found.\n");
553}
554
555void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd)
556{
557 ptdump_walk_pgd_level_core(m, pgd, false, true);
558}
559
560void ptdump_walk_pgd_level_debugfs(struct seq_file *m, pgd_t *pgd, bool user)
561{
562#ifdef CONFIG_PAGE_TABLE_ISOLATION
563 if (user && static_cpu_has(X86_FEATURE_PTI))
564 pgd = kernel_to_user_pgdp(pgd);
565#endif
566 ptdump_walk_pgd_level_core(m, pgd, false, false);
567}
568EXPORT_SYMBOL_GPL(ptdump_walk_pgd_level_debugfs);
569
570static void ptdump_walk_user_pgd_level_checkwx(void)
571{
572#ifdef CONFIG_PAGE_TABLE_ISOLATION
573 pgd_t *pgd = (pgd_t *) &init_top_pgt;
574
575 if (!static_cpu_has(X86_FEATURE_PTI))
576 return;
577
578 pr_info("x86/mm: Checking user space page tables\n");
579 pgd = kernel_to_user_pgdp(pgd);
580 ptdump_walk_pgd_level_core(NULL, pgd, true, false);
581#endif
582}
583
584void ptdump_walk_pgd_level_checkwx(void)
585{
586 ptdump_walk_pgd_level_core(NULL, NULL, true, false);
587 ptdump_walk_user_pgd_level_checkwx();
588}
589
590static int __init pt_dump_init(void)
591{
592
593
594
595
596#ifdef CONFIG_X86_64
597 address_markers[LOW_KERNEL_NR].start_address = PAGE_OFFSET;
598 address_markers[VMALLOC_START_NR].start_address = VMALLOC_START;
599 address_markers[VMEMMAP_START_NR].start_address = VMEMMAP_START;
600#ifdef CONFIG_MODIFY_LDT_SYSCALL
601 address_markers[LDT_NR].start_address = LDT_BASE_ADDR;
602#endif
603#ifdef CONFIG_KASAN
604 address_markers[KASAN_SHADOW_START_NR].start_address = KASAN_SHADOW_START;
605 address_markers[KASAN_SHADOW_END_NR].start_address = KASAN_SHADOW_END;
606#endif
607#endif
608#ifdef CONFIG_X86_32
609 address_markers[VMALLOC_START_NR].start_address = VMALLOC_START;
610 address_markers[VMALLOC_END_NR].start_address = VMALLOC_END;
611# ifdef CONFIG_HIGHMEM
612 address_markers[PKMAP_BASE_NR].start_address = PKMAP_BASE;
613# endif
614 address_markers[FIXADDR_START_NR].start_address = FIXADDR_START;
615 address_markers[CPU_ENTRY_AREA_NR].start_address = CPU_ENTRY_AREA_BASE;
616# ifdef CONFIG_MODIFY_LDT_SYSCALL
617 address_markers[LDT_NR].start_address = LDT_BASE_ADDR;
618# endif
619#endif
620 return 0;
621}
622__initcall(pt_dump_init);
623