Blame view

mm/ptdump.c 3.79 KB
30d621f67   Steven Price   mm: add generic p...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  // SPDX-License-Identifier: GPL-2.0
  
  #include <linux/pagewalk.h>
  #include <linux/ptdump.h>
  #include <linux/kasan.h>
  
  #ifdef CONFIG_KASAN
  /*
   * This is an optimization for KASAN=y case. Since all kasan page tables
   * eventually point to the kasan_early_shadow_page we could call note_page()
   * right away without walking through lower level page tables. This saves
   * us dozens of seconds (minutes for 5-level config) while checking for
   * W+X mapping or reading kernel_page_tables debugfs file.
   */
  static inline int note_kasan_page_table(struct mm_walk *walk,
  					unsigned long addr)
  {
  	struct ptdump_state *st = walk->private;
f8f0d0b6f   Steven Price   mm: ptdump: reduc...
19
  	st->note_page(st, addr, 4, pte_val(kasan_early_shadow_pte[0]));
30d621f67   Steven Price   mm: add generic p...
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
  
  	walk->action = ACTION_CONTINUE;
  
  	return 0;
  }
  #endif
  
  static int ptdump_pgd_entry(pgd_t *pgd, unsigned long addr,
  			    unsigned long next, struct mm_walk *walk)
  {
  	struct ptdump_state *st = walk->private;
  	pgd_t val = READ_ONCE(*pgd);
  
  #if CONFIG_PGTABLE_LEVELS > 4 && defined(CONFIG_KASAN)
  	if (pgd_page(val) == virt_to_page(lm_alias(kasan_early_shadow_p4d)))
  		return note_kasan_page_table(walk, addr);
  #endif
1494e0c38   Steven Price   x86: mm: ptdump: ...
37
38
  	if (st->effective_prot)
  		st->effective_prot(st, 0, pgd_val(val));
30d621f67   Steven Price   mm: add generic p...
39
  	if (pgd_leaf(val))
f8f0d0b6f   Steven Price   mm: ptdump: reduc...
40
  		st->note_page(st, addr, 0, pgd_val(val));
30d621f67   Steven Price   mm: add generic p...
41
42
43
44
45
46
47
48
49
50
51
52
53
54
  
  	return 0;
  }
  
  static int ptdump_p4d_entry(p4d_t *p4d, unsigned long addr,
  			    unsigned long next, struct mm_walk *walk)
  {
  	struct ptdump_state *st = walk->private;
  	p4d_t val = READ_ONCE(*p4d);
  
  #if CONFIG_PGTABLE_LEVELS > 3 && defined(CONFIG_KASAN)
  	if (p4d_page(val) == virt_to_page(lm_alias(kasan_early_shadow_pud)))
  		return note_kasan_page_table(walk, addr);
  #endif
1494e0c38   Steven Price   x86: mm: ptdump: ...
55
56
  	if (st->effective_prot)
  		st->effective_prot(st, 1, p4d_val(val));
30d621f67   Steven Price   mm: add generic p...
57
  	if (p4d_leaf(val))
f8f0d0b6f   Steven Price   mm: ptdump: reduc...
58
  		st->note_page(st, addr, 1, p4d_val(val));
30d621f67   Steven Price   mm: add generic p...
59
60
61
62
63
64
65
66
67
68
69
70
71
72
  
  	return 0;
  }
  
  static int ptdump_pud_entry(pud_t *pud, unsigned long addr,
  			    unsigned long next, struct mm_walk *walk)
  {
  	struct ptdump_state *st = walk->private;
  	pud_t val = READ_ONCE(*pud);
  
  #if CONFIG_PGTABLE_LEVELS > 2 && defined(CONFIG_KASAN)
  	if (pud_page(val) == virt_to_page(lm_alias(kasan_early_shadow_pmd)))
  		return note_kasan_page_table(walk, addr);
  #endif
1494e0c38   Steven Price   x86: mm: ptdump: ...
73
74
  	if (st->effective_prot)
  		st->effective_prot(st, 2, pud_val(val));
30d621f67   Steven Price   mm: add generic p...
75
  	if (pud_leaf(val))
f8f0d0b6f   Steven Price   mm: ptdump: reduc...
76
  		st->note_page(st, addr, 2, pud_val(val));
30d621f67   Steven Price   mm: add generic p...
77
78
79
80
81
82
83
84
85
86
87
88
89
90
  
  	return 0;
  }
  
  static int ptdump_pmd_entry(pmd_t *pmd, unsigned long addr,
  			    unsigned long next, struct mm_walk *walk)
  {
  	struct ptdump_state *st = walk->private;
  	pmd_t val = READ_ONCE(*pmd);
  
  #if defined(CONFIG_KASAN)
  	if (pmd_page(val) == virt_to_page(lm_alias(kasan_early_shadow_pte)))
  		return note_kasan_page_table(walk, addr);
  #endif
1494e0c38   Steven Price   x86: mm: ptdump: ...
91
92
  	if (st->effective_prot)
  		st->effective_prot(st, 3, pmd_val(val));
30d621f67   Steven Price   mm: add generic p...
93
  	if (pmd_leaf(val))
f8f0d0b6f   Steven Price   mm: ptdump: reduc...
94
  		st->note_page(st, addr, 3, pmd_val(val));
30d621f67   Steven Price   mm: add generic p...
95
96
97
98
99
100
101
102
  
  	return 0;
  }
  
  static int ptdump_pte_entry(pte_t *pte, unsigned long addr,
  			    unsigned long next, struct mm_walk *walk)
  {
  	struct ptdump_state *st = walk->private;
1494e0c38   Steven Price   x86: mm: ptdump: ...
103
104
105
106
  	pte_t val = READ_ONCE(*pte);
  
  	if (st->effective_prot)
  		st->effective_prot(st, 4, pte_val(val));
30d621f67   Steven Price   mm: add generic p...
107

1494e0c38   Steven Price   x86: mm: ptdump: ...
108
  	st->note_page(st, addr, 4, pte_val(val));
30d621f67   Steven Price   mm: add generic p...
109
110
111
112
113
114
115
116
  
  	return 0;
  }
  
  static int ptdump_hole(unsigned long addr, unsigned long next,
  		       int depth, struct mm_walk *walk)
  {
  	struct ptdump_state *st = walk->private;
f8f0d0b6f   Steven Price   mm: ptdump: reduc...
117
  	st->note_page(st, addr, depth, 0);
30d621f67   Steven Price   mm: add generic p...
118
119
120
121
122
123
124
125
126
127
128
129
  
  	return 0;
  }
  
  static const struct mm_walk_ops ptdump_ops = {
  	.pgd_entry	= ptdump_pgd_entry,
  	.p4d_entry	= ptdump_p4d_entry,
  	.pud_entry	= ptdump_pud_entry,
  	.pmd_entry	= ptdump_pmd_entry,
  	.pte_entry	= ptdump_pte_entry,
  	.pte_hole	= ptdump_hole,
  };
e47690d75   Steven Price   x86: mm: avoid al...
130
  void ptdump_walk_pgd(struct ptdump_state *st, struct mm_struct *mm, pgd_t *pgd)
30d621f67   Steven Price   mm: add generic p...
131
132
  {
  	const struct ptdump_range *range = st->range;
d8ed45c5d   Michel Lespinasse   mmap locking API:...
133
  	mmap_read_lock(mm);
30d621f67   Steven Price   mm: add generic p...
134
135
  	while (range->start != range->end) {
  		walk_page_range_novma(mm, range->start, range->end,
e47690d75   Steven Price   x86: mm: avoid al...
136
  				      &ptdump_ops, pgd, st);
30d621f67   Steven Price   mm: add generic p...
137
138
  		range++;
  	}
d8ed45c5d   Michel Lespinasse   mmap locking API:...
139
  	mmap_read_unlock(mm);
30d621f67   Steven Price   mm: add generic p...
140
141
  
  	/* Flush out the last page */
f8f0d0b6f   Steven Price   mm: ptdump: reduc...
142
  	st->note_page(st, 0, -1, 0);
30d621f67   Steven Price   mm: add generic p...
143
  }