ptdump.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include <linux/pagewalk.h>
  3. #include <linux/debugfs.h>
  4. #include <linux/ptdump.h>
  5. #include <linux/kasan.h>
  6. #include "internal.h"
  7. #if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)
  8. /*
  9. * This is an optimization for KASAN=y case. Since all kasan page tables
  10. * eventually point to the kasan_early_shadow_page we could call note_page()
  11. * right away without walking through lower level page tables. This saves
  12. * us dozens of seconds (minutes for 5-level config) while checking for
  13. * W+X mapping or reading kernel_page_tables debugfs file.
  14. */
  15. static inline int note_kasan_page_table(struct mm_walk *walk,
  16. unsigned long addr)
  17. {
  18. struct ptdump_state *st = walk->private;
  19. st->note_page_pte(st, addr, kasan_early_shadow_pte[0]);
  20. walk->action = ACTION_CONTINUE;
  21. return 0;
  22. }
  23. #endif
  24. static int ptdump_pgd_entry(pgd_t *pgd, unsigned long addr,
  25. unsigned long next, struct mm_walk *walk)
  26. {
  27. struct ptdump_state *st = walk->private;
  28. pgd_t val = pgdp_get(pgd);
  29. #if CONFIG_PGTABLE_LEVELS > 4 && \
  30. (defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS))
  31. if (pgd_page(val) == virt_to_page(lm_alias(kasan_early_shadow_p4d)))
  32. return note_kasan_page_table(walk, addr);
  33. #endif
  34. if (st->effective_prot_pgd)
  35. st->effective_prot_pgd(st, val);
  36. if (pgd_leaf(val)) {
  37. st->note_page_pgd(st, addr, val);
  38. walk->action = ACTION_CONTINUE;
  39. }
  40. return 0;
  41. }
  42. static int ptdump_p4d_entry(p4d_t *p4d, unsigned long addr,
  43. unsigned long next, struct mm_walk *walk)
  44. {
  45. struct ptdump_state *st = walk->private;
  46. p4d_t val = p4dp_get(p4d);
  47. #if CONFIG_PGTABLE_LEVELS > 3 && \
  48. (defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS))
  49. if (p4d_page(val) == virt_to_page(lm_alias(kasan_early_shadow_pud)))
  50. return note_kasan_page_table(walk, addr);
  51. #endif
  52. if (st->effective_prot_p4d)
  53. st->effective_prot_p4d(st, val);
  54. if (p4d_leaf(val)) {
  55. st->note_page_p4d(st, addr, val);
  56. walk->action = ACTION_CONTINUE;
  57. }
  58. return 0;
  59. }
  60. static int ptdump_pud_entry(pud_t *pud, unsigned long addr,
  61. unsigned long next, struct mm_walk *walk)
  62. {
  63. struct ptdump_state *st = walk->private;
  64. pud_t val = pudp_get(pud);
  65. #if CONFIG_PGTABLE_LEVELS > 2 && \
  66. (defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS))
  67. if (pud_page(val) == virt_to_page(lm_alias(kasan_early_shadow_pmd)))
  68. return note_kasan_page_table(walk, addr);
  69. #endif
  70. if (st->effective_prot_pud)
  71. st->effective_prot_pud(st, val);
  72. if (pud_leaf(val)) {
  73. st->note_page_pud(st, addr, val);
  74. walk->action = ACTION_CONTINUE;
  75. }
  76. return 0;
  77. }
  78. static int ptdump_pmd_entry(pmd_t *pmd, unsigned long addr,
  79. unsigned long next, struct mm_walk *walk)
  80. {
  81. struct ptdump_state *st = walk->private;
  82. pmd_t val = pmdp_get(pmd);
  83. #if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)
  84. if (pmd_page(val) == virt_to_page(lm_alias(kasan_early_shadow_pte)))
  85. return note_kasan_page_table(walk, addr);
  86. #endif
  87. if (st->effective_prot_pmd)
  88. st->effective_prot_pmd(st, val);
  89. if (pmd_leaf(val)) {
  90. st->note_page_pmd(st, addr, val);
  91. walk->action = ACTION_CONTINUE;
  92. }
  93. return 0;
  94. }
  95. static int ptdump_pte_entry(pte_t *pte, unsigned long addr,
  96. unsigned long next, struct mm_walk *walk)
  97. {
  98. struct ptdump_state *st = walk->private;
  99. pte_t val = ptep_get(pte);
  100. if (st->effective_prot_pte)
  101. st->effective_prot_pte(st, val);
  102. st->note_page_pte(st, addr, val);
  103. return 0;
  104. }
  105. static int ptdump_hole(unsigned long addr, unsigned long next,
  106. int depth, struct mm_walk *walk)
  107. {
  108. struct ptdump_state *st = walk->private;
  109. pte_t pte_zero = {0};
  110. pmd_t pmd_zero = {0};
  111. pud_t pud_zero = {0};
  112. p4d_t p4d_zero = {0};
  113. pgd_t pgd_zero = {0};
  114. switch (depth) {
  115. case 4:
  116. st->note_page_pte(st, addr, pte_zero);
  117. break;
  118. case 3:
  119. st->note_page_pmd(st, addr, pmd_zero);
  120. break;
  121. case 2:
  122. st->note_page_pud(st, addr, pud_zero);
  123. break;
  124. case 1:
  125. st->note_page_p4d(st, addr, p4d_zero);
  126. break;
  127. case 0:
  128. st->note_page_pgd(st, addr, pgd_zero);
  129. break;
  130. default:
  131. break;
  132. }
  133. return 0;
  134. }
  135. static const struct mm_walk_ops ptdump_ops = {
  136. .pgd_entry = ptdump_pgd_entry,
  137. .p4d_entry = ptdump_p4d_entry,
  138. .pud_entry = ptdump_pud_entry,
  139. .pmd_entry = ptdump_pmd_entry,
  140. .pte_entry = ptdump_pte_entry,
  141. .pte_hole = ptdump_hole,
  142. };
  143. void ptdump_walk_pgd(struct ptdump_state *st, struct mm_struct *mm, pgd_t *pgd)
  144. {
  145. const struct ptdump_range *range = st->range;
  146. get_online_mems();
  147. mmap_write_lock(mm);
  148. while (range->start != range->end) {
  149. walk_page_range_debug(mm, range->start, range->end,
  150. &ptdump_ops, pgd, st);
  151. range++;
  152. }
  153. mmap_write_unlock(mm);
  154. put_online_mems();
  155. /* Flush out the last page */
  156. st->note_page_flush(st);
  157. }
  158. static int check_wx_show(struct seq_file *m, void *v)
  159. {
  160. if (ptdump_check_wx())
  161. seq_puts(m, "SUCCESS\n");
  162. else
  163. seq_puts(m, "FAILED\n");
  164. return 0;
  165. }
  166. DEFINE_SHOW_ATTRIBUTE(check_wx);
  167. static int ptdump_debugfs_init(void)
  168. {
  169. debugfs_create_file("check_wx_pages", 0400, NULL, NULL, &check_wx_fops);
  170. return 0;
  171. }
  172. device_initcall(ptdump_debugfs_init);