dump_pagetables.c (da25e628c4c231a281b1c1de3168a36ab9bfe473) | dump_pagetables.c (e1a58320a38dfa72be48a0f1a3a92273663ba6db) |
---|---|
1/* 2 * Debug helper to dump the current kernel pagetables of the system 3 * so that we can see what the various memory ranges are set to. 4 * 5 * (C) Copyright 2008 Intel Corporation 6 * 7 * Author: Arjan van de Ven <arjan@linux.intel.com> 8 * --- 18 unchanged lines hidden (view full) --- 27struct pg_state { 28 int level; 29 pgprot_t current_prot; 30 unsigned long start_address; 31 unsigned long current_address; 32 const struct addr_marker *marker; 33 unsigned long lines; 34 bool to_dmesg; | 1/* 2 * Debug helper to dump the current kernel pagetables of the system 3 * so that we can see what the various memory ranges are set to. 4 * 5 * (C) Copyright 2008 Intel Corporation 6 * 7 * Author: Arjan van de Ven <arjan@linux.intel.com> 8 * --- 18 unchanged lines hidden (view full) --- 27struct pg_state { 28 int level; 29 pgprot_t current_prot; 30 unsigned long start_address; 31 unsigned long current_address; 32 const struct addr_marker *marker; 33 unsigned long lines; 34 bool to_dmesg; |
35 bool check_wx; 36 unsigned long wx_pages; |
|
35}; 36 37struct addr_marker { 38 unsigned long start_address; 39 const char *name; 40 unsigned long max_lines; 41}; 42 --- 166 unchanged lines hidden (view full) --- 209 st->lines = 0; 210 pt_dump_seq_printf(m, st->to_dmesg, "---[ %s ]---\n", 211 st->marker->name); 212 } else if (prot != cur || level != st->level || 213 st->current_address >= st->marker[1].start_address) { 214 const char *unit = units; 215 unsigned long delta; 216 int width = sizeof(unsigned long) * 2; | 37}; 38 39struct addr_marker { 40 unsigned long start_address; 41 const char *name; 42 unsigned long max_lines; 43}; 44 --- 166 unchanged lines hidden (view full) --- 211 st->lines = 0; 212 pt_dump_seq_printf(m, st->to_dmesg, "---[ %s ]---\n", 213 st->marker->name); 214 } else if (prot != cur || level != st->level || 215 st->current_address >= st->marker[1].start_address) { 216 const char *unit = units; 217 unsigned long delta; 218 int width = sizeof(unsigned long) * 2; |
219 pgprotval_t pr = pgprot_val(st->current_prot); |
|
217 | 220 |
221 if (st->check_wx && (pr & _PAGE_RW) && !(pr & _PAGE_NX)) { 222 WARN_ONCE(1, 223 "x86/mm: Found insecure W+X mapping at address %p/%pS\n", 224 (void *)st->start_address, 225 (void *)st->start_address); 226 st->wx_pages += (st->current_address - 227 st->start_address) / PAGE_SIZE; 228 } 229 |
|
218 /* 219 * Now print the actual finished series 220 */ 221 if (!st->marker->max_lines || 222 st->lines < st->marker->max_lines) { 223 pt_dump_seq_printf(m, st->to_dmesg, 224 "0x%0*lx-0x%0*lx ", 225 width, st->start_address, --- 115 unchanged lines hidden (view full) --- 341} 342 343#else 344#define walk_pud_level(m,s,a,p) walk_pmd_level(m,s,__pud(pgd_val(a)),p) 345#define pgd_large(a) pud_large(__pud(pgd_val(a))) 346#define pgd_none(a) pud_none(__pud(pgd_val(a))) 347#endif 348 | 230 /* 231 * Now print the actual finished series 232 */ 233 if (!st->marker->max_lines || 234 st->lines < st->marker->max_lines) { 235 pt_dump_seq_printf(m, st->to_dmesg, 236 "0x%0*lx-0x%0*lx ", 237 width, st->start_address, --- 115 unchanged lines hidden (view full) --- 353} 354 355#else 356#define walk_pud_level(m,s,a,p) walk_pmd_level(m,s,__pud(pgd_val(a)),p) 357#define pgd_large(a) pud_large(__pud(pgd_val(a))) 358#define pgd_none(a) pud_none(__pud(pgd_val(a))) 359#endif 360 |
349void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd) | 361static void ptdump_walk_pgd_level_core(struct seq_file *m, pgd_t *pgd, 362 bool checkwx) |
350{ 351#ifdef CONFIG_X86_64 352 pgd_t *start = (pgd_t *) &init_level4_pgt; 353#else 354 pgd_t *start = swapper_pg_dir; 355#endif 356 pgprotval_t prot; 357 int i; 358 struct pg_state st = {}; 359 360 if (pgd) { 361 start = pgd; 362 st.to_dmesg = true; 363 } 364 | 363{ 364#ifdef CONFIG_X86_64 365 pgd_t *start = (pgd_t *) &init_level4_pgt; 366#else 367 pgd_t *start = swapper_pg_dir; 368#endif 369 pgprotval_t prot; 370 int i; 371 struct pg_state st = {}; 372 373 if (pgd) { 374 start = pgd; 375 st.to_dmesg = true; 376 } 377 |
378 st.check_wx = checkwx; 379 if (checkwx) 380 st.wx_pages = 0; 381 |
|
365 for (i = 0; i < PTRS_PER_PGD; i++) { 366 st.current_address = normalize_addr(i * PGD_LEVEL_MULT); 367 if (!pgd_none(*start)) { 368 if (pgd_large(*start) || !pgd_present(*start)) { 369 prot = pgd_flags(*start); 370 note_page(m, &st, __pgprot(prot), 1); 371 } else { 372 walk_pud_level(m, &st, *start, 373 i * PGD_LEVEL_MULT); 374 } 375 } else 376 note_page(m, &st, __pgprot(0), 1); 377 378 start++; 379 } 380 381 /* Flush out the last page */ 382 st.current_address = normalize_addr(PTRS_PER_PGD*PGD_LEVEL_MULT); 383 note_page(m, &st, __pgprot(0), 0); | 382 for (i = 0; i < PTRS_PER_PGD; i++) { 383 st.current_address = normalize_addr(i * PGD_LEVEL_MULT); 384 if (!pgd_none(*start)) { 385 if (pgd_large(*start) || !pgd_present(*start)) { 386 prot = pgd_flags(*start); 387 note_page(m, &st, __pgprot(prot), 1); 388 } else { 389 walk_pud_level(m, &st, *start, 390 i * PGD_LEVEL_MULT); 391 } 392 } else 393 note_page(m, &st, __pgprot(0), 1); 394 395 start++; 396 } 397 398 /* Flush out the last page */ 399 st.current_address = normalize_addr(PTRS_PER_PGD*PGD_LEVEL_MULT); 400 note_page(m, &st, __pgprot(0), 0); |
401 if (!checkwx) 402 return; 403 if (st.wx_pages) 404 pr_info("x86/mm: Checked W+X mappings: FAILED, %lu W+X pages found.\n", 405 st.wx_pages); 406 else 407 pr_info("x86/mm: Checked W+X mappings: passed, no W+X pages found.\n"); |
|
384} 385 | 408} 409 |
410void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd) 411{ 412 ptdump_walk_pgd_level_core(m, pgd, false); 413} 414 415void ptdump_walk_pgd_level_checkwx(void) 416{ 417 ptdump_walk_pgd_level_core(NULL, NULL, true); 418} 419 420#ifdef CONFIG_X86_PTDUMP |
|
386static int ptdump_show(struct seq_file *m, void *v) 387{ 388 ptdump_walk_pgd_level(m, NULL); 389 return 0; 390} 391 392static int ptdump_open(struct inode *inode, struct file *filp) 393{ 394 return single_open(filp, ptdump_show, NULL); 395} 396 397static const struct file_operations ptdump_fops = { 398 .open = ptdump_open, 399 .read = seq_read, 400 .llseek = seq_lseek, 401 .release = single_release, 402}; | 421static int ptdump_show(struct seq_file *m, void *v) 422{ 423 ptdump_walk_pgd_level(m, NULL); 424 return 0; 425} 426 427static int ptdump_open(struct inode *inode, struct file *filp) 428{ 429 return single_open(filp, ptdump_show, NULL); 430} 431 432static const struct file_operations ptdump_fops = { 433 .open = ptdump_open, 434 .read = seq_read, 435 .llseek = seq_lseek, 436 .release = single_release, 437}; |
438#endif |
|
403 404static int pt_dump_init(void) 405{ | 439 440static int pt_dump_init(void) 441{ |
442#ifdef CONFIG_X86_PTDUMP |
|
406 struct dentry *pe; | 443 struct dentry *pe; |
444#endif |
|
407 408#ifdef CONFIG_X86_32 409 /* Not a compile-time constant on x86-32 */ 410 address_markers[VMALLOC_START_NR].start_address = VMALLOC_START; 411 address_markers[VMALLOC_END_NR].start_address = VMALLOC_END; 412# ifdef CONFIG_HIGHMEM 413 address_markers[PKMAP_BASE_NR].start_address = PKMAP_BASE; 414# endif 415 address_markers[FIXADDR_START_NR].start_address = FIXADDR_START; 416#endif 417 | 445 446#ifdef CONFIG_X86_32 447 /* Not a compile-time constant on x86-32 */ 448 address_markers[VMALLOC_START_NR].start_address = VMALLOC_START; 449 address_markers[VMALLOC_END_NR].start_address = VMALLOC_END; 450# ifdef CONFIG_HIGHMEM 451 address_markers[PKMAP_BASE_NR].start_address = PKMAP_BASE; 452# endif 453 address_markers[FIXADDR_START_NR].start_address = FIXADDR_START; 454#endif 455 |
456#ifdef CONFIG_X86_PTDUMP |
|
418 pe = debugfs_create_file("kernel_page_tables", 0600, NULL, NULL, 419 &ptdump_fops); 420 if (!pe) 421 return -ENOMEM; | 457 pe = debugfs_create_file("kernel_page_tables", 0600, NULL, NULL, 458 &ptdump_fops); 459 if (!pe) 460 return -ENOMEM; |
461#endif |
|
422 423 return 0; 424} 425 426__initcall(pt_dump_init); 427MODULE_LICENSE("GPL"); 428MODULE_AUTHOR("Arjan van de Ven <arjan@linux.intel.com>"); 429MODULE_DESCRIPTION("Kernel debugging helper that dumps pagetables"); | 462 463 return 0; 464} 465 466__initcall(pt_dump_init); 467MODULE_LICENSE("GPL"); 468MODULE_AUTHOR("Arjan van de Ven <arjan@linux.intel.com>"); 469MODULE_DESCRIPTION("Kernel debugging helper that dumps pagetables"); |