1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2019 SiFive 4 */ 5 6 #include <linux/efi.h> 7 #include <linux/init.h> 8 #include <linux/debugfs.h> 9 #include <linux/seq_file.h> 10 #include <linux/ptdump.h> 11 12 #include <asm/ptdump.h> 13 #include <linux/pgtable.h> 14 #include <asm/kasan.h> 15 16 #define pt_dump_seq_printf(m, fmt, args...) \ 17 ({ \ 18 if (m) \ 19 seq_printf(m, fmt, ##args); \ 20 }) 21 22 #define pt_dump_seq_puts(m, fmt) \ 23 ({ \ 24 if (m) \ 25 seq_printf(m, fmt); \ 26 }) 27 28 /* 29 * The page dumper groups page table entries of the same type into a single 30 * description. It uses pg_state to track the range information while 31 * iterating over the pte entries. When the continuity is broken it then 32 * dumps out a description of the range. 33 */ 34 struct pg_state { 35 struct ptdump_state ptdump; 36 struct seq_file *seq; 37 const struct addr_marker *marker; 38 unsigned long start_address; 39 unsigned long start_pa; 40 unsigned long last_pa; 41 int level; 42 u64 current_prot; 43 bool check_wx; 44 unsigned long wx_pages; 45 }; 46 47 /* Address marker */ 48 struct addr_marker { 49 unsigned long start_address; 50 const char *name; 51 }; 52 53 /* Private information for debugfs */ 54 struct ptd_mm_info { 55 struct mm_struct *mm; 56 const struct addr_marker *markers; 57 unsigned long base_addr; 58 unsigned long end; 59 }; 60 61 static struct addr_marker address_markers[] = { 62 #ifdef CONFIG_KASAN 63 {KASAN_SHADOW_START, "Kasan shadow start"}, 64 {KASAN_SHADOW_END, "Kasan shadow end"}, 65 #endif 66 {FIXADDR_START, "Fixmap start"}, 67 {FIXADDR_TOP, "Fixmap end"}, 68 {PCI_IO_START, "PCI I/O start"}, 69 {PCI_IO_END, "PCI I/O end"}, 70 #ifdef CONFIG_SPARSEMEM_VMEMMAP 71 {VMEMMAP_START, "vmemmap start"}, 72 {VMEMMAP_END, "vmemmap end"}, 73 #endif 74 {VMALLOC_START, "vmalloc() area"}, 75 {VMALLOC_END, "vmalloc() end"}, 76 {PAGE_OFFSET, "Linear mapping"}, 77 {-1, NULL}, 78 }; 79 80 static struct ptd_mm_info kernel_ptd_info = { 81 .mm = &init_mm, 82 .markers = address_markers, 83 .base_addr = KERN_VIRT_START, 84 .end = ULONG_MAX, 85 }; 86 87 #ifdef CONFIG_EFI 88 static struct addr_marker efi_addr_markers[] = { 89 { 0, "UEFI runtime start" }, 90 { SZ_1G, "UEFI runtime end" }, 91 { -1, NULL } 92 }; 93 94 static struct ptd_mm_info efi_ptd_info = { 95 .mm = &efi_mm, 96 .markers = efi_addr_markers, 97 .base_addr = 0, 98 .end = SZ_2G, 99 }; 100 #endif 101 102 /* Page Table Entry */ 103 struct prot_bits { 104 u64 mask; 105 u64 val; 106 const char *set; 107 const char *clear; 108 }; 109 110 static const struct prot_bits pte_bits[] = { 111 { 112 .mask = _PAGE_SOFT, 113 .val = _PAGE_SOFT, 114 .set = "RSW", 115 .clear = " ", 116 }, { 117 .mask = _PAGE_DIRTY, 118 .val = _PAGE_DIRTY, 119 .set = "D", 120 .clear = ".", 121 }, { 122 .mask = _PAGE_ACCESSED, 123 .val = _PAGE_ACCESSED, 124 .set = "A", 125 .clear = ".", 126 }, { 127 .mask = _PAGE_GLOBAL, 128 .val = _PAGE_GLOBAL, 129 .set = "G", 130 .clear = ".", 131 }, { 132 .mask = _PAGE_USER, 133 .val = _PAGE_USER, 134 .set = "U", 135 .clear = ".", 136 }, { 137 .mask = _PAGE_EXEC, 138 .val = _PAGE_EXEC, 139 .set = "X", 140 .clear = ".", 141 }, { 142 .mask = _PAGE_WRITE, 143 .val = _PAGE_WRITE, 144 .set = "W", 145 .clear = ".", 146 }, { 147 .mask = _PAGE_READ, 148 .val = _PAGE_READ, 149 .set = "R", 150 .clear = ".", 151 }, { 152 .mask = _PAGE_PRESENT, 153 .val = _PAGE_PRESENT, 154 .set = "V", 155 .clear = ".", 156 } 157 }; 158 159 /* Page Level */ 160 struct pg_level { 161 const char *name; 162 u64 mask; 163 }; 164 165 static struct pg_level pg_level[] = { 166 { /* pgd */ 167 .name = "PGD", 168 }, { /* p4d */ 169 .name = (CONFIG_PGTABLE_LEVELS > 4) ? "P4D" : "PGD", 170 }, { /* pud */ 171 .name = (CONFIG_PGTABLE_LEVELS > 3) ? "PUD" : "PGD", 172 }, { /* pmd */ 173 .name = (CONFIG_PGTABLE_LEVELS > 2) ? "PMD" : "PGD", 174 }, { /* pte */ 175 .name = "PTE", 176 }, 177 }; 178 179 static void dump_prot(struct pg_state *st) 180 { 181 unsigned int i; 182 183 for (i = 0; i < ARRAY_SIZE(pte_bits); i++) { 184 const char *s; 185 186 if ((st->current_prot & pte_bits[i].mask) == pte_bits[i].val) 187 s = pte_bits[i].set; 188 else 189 s = pte_bits[i].clear; 190 191 if (s) 192 pt_dump_seq_printf(st->seq, " %s", s); 193 } 194 } 195 196 #ifdef CONFIG_64BIT 197 #define ADDR_FORMAT "0x%016lx" 198 #else 199 #define ADDR_FORMAT "0x%08lx" 200 #endif 201 static void dump_addr(struct pg_state *st, unsigned long addr) 202 { 203 static const char units[] = "KMGTPE"; 204 const char *unit = units; 205 unsigned long delta; 206 207 pt_dump_seq_printf(st->seq, ADDR_FORMAT "-" ADDR_FORMAT " ", 208 st->start_address, addr); 209 210 pt_dump_seq_printf(st->seq, " " ADDR_FORMAT " ", st->start_pa); 211 delta = (addr - st->start_address) >> 10; 212 213 while (!(delta & 1023) && unit[1]) { 214 delta >>= 10; 215 unit++; 216 } 217 218 pt_dump_seq_printf(st->seq, "%9lu%c %s", delta, *unit, 219 pg_level[st->level].name); 220 } 221 222 static void note_prot_wx(struct pg_state *st, unsigned long addr) 223 { 224 if (!st->check_wx) 225 return; 226 227 if ((st->current_prot & (_PAGE_WRITE | _PAGE_EXEC)) != 228 (_PAGE_WRITE | _PAGE_EXEC)) 229 return; 230 231 WARN_ONCE(1, "riscv/mm: Found insecure W+X mapping at address %p/%pS\n", 232 (void *)st->start_address, (void *)st->start_address); 233 234 st->wx_pages += (addr - st->start_address) / PAGE_SIZE; 235 } 236 237 static void note_page(struct ptdump_state *pt_st, unsigned long addr, 238 int level, u64 val) 239 { 240 struct pg_state *st = container_of(pt_st, struct pg_state, ptdump); 241 u64 pa = PFN_PHYS(pte_pfn(__pte(val))); 242 u64 prot = 0; 243 244 if (level >= 0) 245 prot = val & pg_level[level].mask; 246 247 if (st->level == -1) { 248 st->level = level; 249 st->current_prot = prot; 250 st->start_address = addr; 251 st->start_pa = pa; 252 st->last_pa = pa; 253 pt_dump_seq_printf(st->seq, "---[ %s ]---\n", st->marker->name); 254 } else if (prot != st->current_prot || 255 level != st->level || addr >= st->marker[1].start_address) { 256 if (st->current_prot) { 257 note_prot_wx(st, addr); 258 dump_addr(st, addr); 259 dump_prot(st); 260 pt_dump_seq_puts(st->seq, "\n"); 261 } 262 263 while (addr >= st->marker[1].start_address) { 264 st->marker++; 265 pt_dump_seq_printf(st->seq, "---[ %s ]---\n", 266 st->marker->name); 267 } 268 269 st->start_address = addr; 270 st->start_pa = pa; 271 st->last_pa = pa; 272 st->current_prot = prot; 273 st->level = level; 274 } else { 275 st->last_pa = pa; 276 } 277 } 278 279 static void ptdump_walk(struct seq_file *s, struct ptd_mm_info *pinfo) 280 { 281 struct pg_state st = { 282 .seq = s, 283 .marker = pinfo->markers, 284 .level = -1, 285 .ptdump = { 286 .note_page = note_page, 287 .range = (struct ptdump_range[]) { 288 {pinfo->base_addr, pinfo->end}, 289 {0, 0} 290 } 291 } 292 }; 293 294 ptdump_walk_pgd(&st.ptdump, pinfo->mm, NULL); 295 } 296 297 void ptdump_check_wx(void) 298 { 299 struct pg_state st = { 300 .seq = NULL, 301 .marker = (struct addr_marker[]) { 302 {0, NULL}, 303 {-1, NULL}, 304 }, 305 .level = -1, 306 .check_wx = true, 307 .ptdump = { 308 .note_page = note_page, 309 .range = (struct ptdump_range[]) { 310 {KERN_VIRT_START, ULONG_MAX}, 311 {0, 0} 312 } 313 } 314 }; 315 316 ptdump_walk_pgd(&st.ptdump, &init_mm, NULL); 317 318 if (st.wx_pages) 319 pr_warn("Checked W+X mappings: failed, %lu W+X pages found\n", 320 st.wx_pages); 321 else 322 pr_info("Checked W+X mappings: passed, no W+X pages found\n"); 323 } 324 325 static int ptdump_show(struct seq_file *m, void *v) 326 { 327 ptdump_walk(m, m->private); 328 329 return 0; 330 } 331 332 DEFINE_SHOW_ATTRIBUTE(ptdump); 333 334 static int ptdump_init(void) 335 { 336 unsigned int i, j; 337 338 for (i = 0; i < ARRAY_SIZE(pg_level); i++) 339 for (j = 0; j < ARRAY_SIZE(pte_bits); j++) 340 pg_level[i].mask |= pte_bits[j].mask; 341 342 debugfs_create_file("kernel_page_tables", 0400, NULL, &kernel_ptd_info, 343 &ptdump_fops); 344 #ifdef CONFIG_EFI 345 if (efi_enabled(EFI_RUNTIME_SERVICES)) 346 debugfs_create_file("efi_page_tables", 0400, NULL, &efi_ptd_info, 347 &ptdump_fops); 348 #endif 349 350 return 0; 351 } 352 353 device_initcall(ptdump_init); 354