page_table_check.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (c) 2021, Google LLC.
  4. * Pasha Tatashin <pasha.tatashin@soleen.com>
  5. */
  6. #include <linux/kstrtox.h>
  7. #include <linux/mm.h>
  8. #include <linux/page_table_check.h>
  9. #include <linux/swap.h>
  10. #include <linux/leafops.h>
  11. #undef pr_fmt
  12. #define pr_fmt(fmt) "page_table_check: " fmt
  13. struct page_table_check {
  14. atomic_t anon_map_count;
  15. atomic_t file_map_count;
  16. };
  17. static bool __page_table_check_enabled __initdata =
  18. IS_ENABLED(CONFIG_PAGE_TABLE_CHECK_ENFORCED);
  19. DEFINE_STATIC_KEY_TRUE(page_table_check_disabled);
  20. EXPORT_SYMBOL(page_table_check_disabled);
  21. static int __init early_page_table_check_param(char *buf)
  22. {
  23. return kstrtobool(buf, &__page_table_check_enabled);
  24. }
  25. early_param("page_table_check", early_page_table_check_param);
  26. static bool __init need_page_table_check(void)
  27. {
  28. return __page_table_check_enabled;
  29. }
  30. static void __init init_page_table_check(void)
  31. {
  32. if (!__page_table_check_enabled)
  33. return;
  34. static_branch_disable(&page_table_check_disabled);
  35. }
  36. struct page_ext_operations page_table_check_ops = {
  37. .size = sizeof(struct page_table_check),
  38. .need = need_page_table_check,
  39. .init = init_page_table_check,
  40. .need_shared_flags = false,
  41. };
  42. static struct page_table_check *get_page_table_check(struct page_ext *page_ext)
  43. {
  44. BUG_ON(!page_ext);
  45. return page_ext_data(page_ext, &page_table_check_ops);
  46. }
  47. /*
  48. * An entry is removed from the page table, decrement the counters for that page
  49. * verify that it is of correct type and counters do not become negative.
  50. */
  51. static void page_table_check_clear(unsigned long pfn, unsigned long pgcnt)
  52. {
  53. struct page_ext_iter iter;
  54. struct page_ext *page_ext;
  55. struct page *page;
  56. bool anon;
  57. if (!pfn_valid(pfn))
  58. return;
  59. page = pfn_to_page(pfn);
  60. BUG_ON(PageSlab(page));
  61. anon = PageAnon(page);
  62. rcu_read_lock();
  63. for_each_page_ext(page, pgcnt, page_ext, iter) {
  64. struct page_table_check *ptc = get_page_table_check(page_ext);
  65. if (anon) {
  66. BUG_ON(atomic_read(&ptc->file_map_count));
  67. BUG_ON(atomic_dec_return(&ptc->anon_map_count) < 0);
  68. } else {
  69. BUG_ON(atomic_read(&ptc->anon_map_count));
  70. BUG_ON(atomic_dec_return(&ptc->file_map_count) < 0);
  71. }
  72. }
  73. rcu_read_unlock();
  74. }
  75. /*
  76. * A new entry is added to the page table, increment the counters for that page
  77. * verify that it is of correct type and is not being mapped with a different
  78. * type to a different process.
  79. */
  80. static void page_table_check_set(unsigned long pfn, unsigned long pgcnt,
  81. bool rw)
  82. {
  83. struct page_ext_iter iter;
  84. struct page_ext *page_ext;
  85. struct page *page;
  86. bool anon;
  87. if (!pfn_valid(pfn))
  88. return;
  89. page = pfn_to_page(pfn);
  90. BUG_ON(PageSlab(page));
  91. anon = PageAnon(page);
  92. rcu_read_lock();
  93. for_each_page_ext(page, pgcnt, page_ext, iter) {
  94. struct page_table_check *ptc = get_page_table_check(page_ext);
  95. if (anon) {
  96. BUG_ON(atomic_read(&ptc->file_map_count));
  97. BUG_ON(atomic_inc_return(&ptc->anon_map_count) > 1 && rw);
  98. } else {
  99. BUG_ON(atomic_read(&ptc->anon_map_count));
  100. BUG_ON(atomic_inc_return(&ptc->file_map_count) < 0);
  101. }
  102. }
  103. rcu_read_unlock();
  104. }
  105. /*
  106. * page is on free list, or is being allocated, verify that counters are zeroes
  107. * crash if they are not.
  108. */
  109. void __page_table_check_zero(struct page *page, unsigned int order)
  110. {
  111. struct page_ext_iter iter;
  112. struct page_ext *page_ext;
  113. BUG_ON(PageSlab(page));
  114. rcu_read_lock();
  115. for_each_page_ext(page, 1 << order, page_ext, iter) {
  116. struct page_table_check *ptc = get_page_table_check(page_ext);
  117. BUG_ON(atomic_read(&ptc->anon_map_count));
  118. BUG_ON(atomic_read(&ptc->file_map_count));
  119. }
  120. rcu_read_unlock();
  121. }
  122. void __page_table_check_pte_clear(struct mm_struct *mm, unsigned long addr,
  123. pte_t pte)
  124. {
  125. if (&init_mm == mm)
  126. return;
  127. if (pte_user_accessible_page(pte, addr)) {
  128. page_table_check_clear(pte_pfn(pte), PAGE_SIZE >> PAGE_SHIFT);
  129. }
  130. }
  131. EXPORT_SYMBOL(__page_table_check_pte_clear);
  132. void __page_table_check_pmd_clear(struct mm_struct *mm, unsigned long addr,
  133. pmd_t pmd)
  134. {
  135. if (&init_mm == mm)
  136. return;
  137. if (pmd_user_accessible_page(pmd, addr)) {
  138. page_table_check_clear(pmd_pfn(pmd), PMD_SIZE >> PAGE_SHIFT);
  139. }
  140. }
  141. EXPORT_SYMBOL(__page_table_check_pmd_clear);
  142. void __page_table_check_pud_clear(struct mm_struct *mm, unsigned long addr,
  143. pud_t pud)
  144. {
  145. if (&init_mm == mm)
  146. return;
  147. if (pud_user_accessible_page(pud, addr)) {
  148. page_table_check_clear(pud_pfn(pud), PUD_SIZE >> PAGE_SHIFT);
  149. }
  150. }
  151. EXPORT_SYMBOL(__page_table_check_pud_clear);
  152. /* Whether the swap entry cached writable information */
  153. static inline bool softleaf_cached_writable(softleaf_t entry)
  154. {
  155. return softleaf_is_device_private_write(entry) ||
  156. softleaf_is_migration_write(entry);
  157. }
  158. static void page_table_check_pte_flags(pte_t pte)
  159. {
  160. if (pte_present(pte)) {
  161. WARN_ON_ONCE(pte_uffd_wp(pte) && pte_write(pte));
  162. } else if (pte_swp_uffd_wp(pte)) {
  163. const softleaf_t entry = softleaf_from_pte(pte);
  164. WARN_ON_ONCE(softleaf_cached_writable(entry));
  165. }
  166. }
  167. void __page_table_check_ptes_set(struct mm_struct *mm, unsigned long addr,
  168. pte_t *ptep, pte_t pte, unsigned int nr)
  169. {
  170. unsigned int i;
  171. if (&init_mm == mm)
  172. return;
  173. page_table_check_pte_flags(pte);
  174. for (i = 0; i < nr; i++)
  175. __page_table_check_pte_clear(mm, addr + PAGE_SIZE * i, ptep_get(ptep + i));
  176. if (pte_user_accessible_page(pte, addr))
  177. page_table_check_set(pte_pfn(pte), nr, pte_write(pte));
  178. }
  179. EXPORT_SYMBOL(__page_table_check_ptes_set);
  180. static inline void page_table_check_pmd_flags(pmd_t pmd)
  181. {
  182. if (pmd_present(pmd)) {
  183. if (pmd_uffd_wp(pmd))
  184. WARN_ON_ONCE(pmd_write(pmd));
  185. } else if (pmd_swp_uffd_wp(pmd)) {
  186. const softleaf_t entry = softleaf_from_pmd(pmd);
  187. WARN_ON_ONCE(softleaf_cached_writable(entry));
  188. }
  189. }
  190. void __page_table_check_pmds_set(struct mm_struct *mm, unsigned long addr,
  191. pmd_t *pmdp, pmd_t pmd, unsigned int nr)
  192. {
  193. unsigned long stride = PMD_SIZE >> PAGE_SHIFT;
  194. unsigned int i;
  195. if (&init_mm == mm)
  196. return;
  197. page_table_check_pmd_flags(pmd);
  198. for (i = 0; i < nr; i++)
  199. __page_table_check_pmd_clear(mm, addr + PMD_SIZE * i, *(pmdp + i));
  200. if (pmd_user_accessible_page(pmd, addr))
  201. page_table_check_set(pmd_pfn(pmd), stride * nr, pmd_write(pmd));
  202. }
  203. EXPORT_SYMBOL(__page_table_check_pmds_set);
  204. void __page_table_check_puds_set(struct mm_struct *mm, unsigned long addr,
  205. pud_t *pudp, pud_t pud, unsigned int nr)
  206. {
  207. unsigned long stride = PUD_SIZE >> PAGE_SHIFT;
  208. unsigned int i;
  209. if (&init_mm == mm)
  210. return;
  211. for (i = 0; i < nr; i++)
  212. __page_table_check_pud_clear(mm, addr + PUD_SIZE * i, *(pudp + i));
  213. if (pud_user_accessible_page(pud, addr))
  214. page_table_check_set(pud_pfn(pud), stride * nr, pud_write(pud));
  215. }
  216. EXPORT_SYMBOL(__page_table_check_puds_set);
  217. void __page_table_check_pte_clear_range(struct mm_struct *mm,
  218. unsigned long addr,
  219. pmd_t pmd)
  220. {
  221. if (&init_mm == mm)
  222. return;
  223. if (!pmd_bad(pmd) && !pmd_leaf(pmd)) {
  224. pte_t *ptep = pte_offset_map(&pmd, addr);
  225. unsigned long i;
  226. if (WARN_ON(!ptep))
  227. return;
  228. for (i = 0; i < PTRS_PER_PTE; i++) {
  229. __page_table_check_pte_clear(mm, addr, ptep_get(ptep));
  230. addr += PAGE_SIZE;
  231. ptep++;
  232. }
  233. pte_unmap(ptep - PTRS_PER_PTE);
  234. }
  235. }