blob: e6fd0cdef9ad68131d32a57bd63a40dec827cf97 [file] [log] [blame]
Arjan van de Ven926e5392008-04-17 17:40:45 +02001/*
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 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; version 2
12 * of the License.
13 */
14
H. Peter Anvinfe770bf02008-04-17 17:40:45 +020015#include <linux/debugfs.h>
Andrey Ryabinin04b67022017-07-24 18:25:58 +030016#include <linux/kasan.h>
H. Peter Anvinfe770bf02008-04-17 17:40:45 +020017#include <linux/mm.h>
Paul Gortmaker84e629b2016-07-13 20:18:54 -040018#include <linux/init.h>
Andrey Ryabinin146fbb762017-02-10 12:54:05 +030019#include <linux/sched.h>
Arjan van de Ven926e5392008-04-17 17:40:45 +020020#include <linux/seq_file.h>
Joerg Roedeld6ef1f12018-04-17 15:27:16 +020021#include <linux/highmem.h>
Arjan van de Ven926e5392008-04-17 17:40:45 +020022
23#include <asm/pgtable.h>
24
25/*
26 * The dumper groups pagetable entries of the same type into one, and for
27 * that it needs to keep some state when walking, and flush this state
28 * when a "break" in the continuity is found.
29 */
30struct pg_state {
31 int level;
32 pgprot_t current_prot;
Jan Beulich672c0ae2018-02-23 01:27:37 -070033 pgprotval_t effective_prot;
Arjan van de Ven926e5392008-04-17 17:40:45 +020034 unsigned long start_address;
35 unsigned long current_address;
H. Peter Anvinfe770bf02008-04-17 17:40:45 +020036 const struct addr_marker *marker;
H. Peter Anvin3891a042014-04-29 16:46:09 -070037 unsigned long lines;
Borislav Petkovef6bea62014-01-18 12:48:14 +010038 bool to_dmesg;
Stephen Smalleye1a58322015-10-05 12:55:20 -040039 bool check_wx;
40 unsigned long wx_pages;
H. Peter Anvinfe770bf02008-04-17 17:40:45 +020041};
42
43struct addr_marker {
44 unsigned long start_address;
45 const char *name;
H. Peter Anvin3891a042014-04-29 16:46:09 -070046 unsigned long max_lines;
H. Peter Anvinfe770bf02008-04-17 17:40:45 +020047};
48
Thomas Gleixner146122e2017-12-20 18:07:42 +010049/* Address space markers hints */
50
51#ifdef CONFIG_X86_64
52
Andres Salomon92851e22010-07-20 15:19:46 -070053enum address_markers_idx {
54 USER_SPACE_NR = 0,
Andres Salomon92851e22010-07-20 15:19:46 -070055 KERNEL_SPACE_NR,
56 LOW_KERNEL_NR,
Andy Lutomirskif55f0502017-12-12 07:56:45 -080057#if defined(CONFIG_MODIFY_LDT_SYSCALL) && defined(CONFIG_X86_5LEVEL)
58 LDT_NR,
59#endif
Andres Salomon92851e22010-07-20 15:19:46 -070060 VMALLOC_START_NR,
61 VMEMMAP_START_NR,
Andrey Ryabinin025205f2017-02-14 13:08:39 +030062#ifdef CONFIG_KASAN
63 KASAN_SHADOW_START_NR,
64 KASAN_SHADOW_END_NR,
65#endif
Thomas Gleixnerf2078902018-01-04 13:01:40 +010066 CPU_ENTRY_AREA_NR,
Andy Lutomirskif55f0502017-12-12 07:56:45 -080067#if defined(CONFIG_MODIFY_LDT_SYSCALL) && !defined(CONFIG_X86_5LEVEL)
68 LDT_NR,
69#endif
Thomas Gleixner146122e2017-12-20 18:07:42 +010070#ifdef CONFIG_X86_ESPFIX64
H. Peter Anvin3891a042014-04-29 16:46:09 -070071 ESPFIX_START_NR,
Thomas Gleixner146122e2017-12-20 18:07:42 +010072#endif
73#ifdef CONFIG_EFI
74 EFI_END_NR,
75#endif
Andres Salomon92851e22010-07-20 15:19:46 -070076 HIGH_KERNEL_NR,
77 MODULES_VADDR_NR,
78 MODULES_END_NR,
Thomas Gleixner146122e2017-12-20 18:07:42 +010079 FIXADDR_START_NR,
80 END_OF_SPACE_NR,
81};
82
83static struct addr_marker address_markers[] = {
84 [USER_SPACE_NR] = { 0, "User Space" },
85 [KERNEL_SPACE_NR] = { (1UL << 63), "Kernel Space" },
86 [LOW_KERNEL_NR] = { 0UL, "Low Kernel Mapping" },
87 [VMALLOC_START_NR] = { 0UL, "vmalloc() Area" },
88 [VMEMMAP_START_NR] = { 0UL, "Vmemmap" },
89#ifdef CONFIG_KASAN
Kirill A. Shutemov09e61a72018-02-14 14:16:55 +030090 /*
91 * These fields get initialized with the (dynamic)
92 * KASAN_SHADOW_{START,END} values in pt_dump_init().
93 */
94 [KASAN_SHADOW_START_NR] = { 0UL, "KASAN shadow" },
95 [KASAN_SHADOW_END_NR] = { 0UL, "KASAN shadow end" },
Thomas Gleixner146122e2017-12-20 18:07:42 +010096#endif
Andy Lutomirskif55f0502017-12-12 07:56:45 -080097#ifdef CONFIG_MODIFY_LDT_SYSCALL
Kirill A. Shutemov5c7919b2018-02-14 14:16:52 +030098 [LDT_NR] = { 0UL, "LDT remap" },
Andy Lutomirskif55f0502017-12-12 07:56:45 -080099#endif
Thomas Gleixner92a0f812017-12-20 18:51:31 +0100100 [CPU_ENTRY_AREA_NR] = { CPU_ENTRY_AREA_BASE,"CPU entry Area" },
Thomas Gleixner146122e2017-12-20 18:07:42 +0100101#ifdef CONFIG_X86_ESPFIX64
102 [ESPFIX_START_NR] = { ESPFIX_BASE_ADDR, "ESPfix Area", 16 },
103#endif
104#ifdef CONFIG_EFI
105 [EFI_END_NR] = { EFI_VA_END, "EFI Runtime Services" },
106#endif
107 [HIGH_KERNEL_NR] = { __START_KERNEL_map, "High Kernel Mapping" },
108 [MODULES_VADDR_NR] = { MODULES_VADDR, "Modules" },
109 [MODULES_END_NR] = { MODULES_END, "End Modules" },
110 [FIXADDR_START_NR] = { FIXADDR_START, "Fixmap Area" },
111 [END_OF_SPACE_NR] = { -1, NULL }
112};
113
Joerg Roedel4e8537e2018-07-18 11:41:08 +0200114#define INIT_PGD ((pgd_t *) &init_top_pgt)
115
Thomas Gleixner146122e2017-12-20 18:07:42 +0100116#else /* CONFIG_X86_64 */
117
118enum address_markers_idx {
119 USER_SPACE_NR = 0,
Andres Salomon92851e22010-07-20 15:19:46 -0700120 KERNEL_SPACE_NR,
121 VMALLOC_START_NR,
122 VMALLOC_END_NR,
Thomas Gleixner146122e2017-12-20 18:07:42 +0100123#ifdef CONFIG_HIGHMEM
Andres Salomon92851e22010-07-20 15:19:46 -0700124 PKMAP_BASE_NR,
Andres Salomon92851e22010-07-20 15:19:46 -0700125#endif
Thomas Gleixner92a0f812017-12-20 18:51:31 +0100126 CPU_ENTRY_AREA_NR,
Thomas Gleixner146122e2017-12-20 18:07:42 +0100127 FIXADDR_START_NR,
128 END_OF_SPACE_NR,
Andres Salomon92851e22010-07-20 15:19:46 -0700129};
130
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200131static struct addr_marker address_markers[] = {
Thomas Gleixner146122e2017-12-20 18:07:42 +0100132 [USER_SPACE_NR] = { 0, "User Space" },
133 [KERNEL_SPACE_NR] = { PAGE_OFFSET, "Kernel Mapping" },
134 [VMALLOC_START_NR] = { 0UL, "vmalloc() Area" },
135 [VMALLOC_END_NR] = { 0UL, "vmalloc() End" },
136#ifdef CONFIG_HIGHMEM
137 [PKMAP_BASE_NR] = { 0UL, "Persistent kmap() Area" },
Andrey Ryabinin025205f2017-02-14 13:08:39 +0300138#endif
Thomas Gleixner92a0f812017-12-20 18:51:31 +0100139 [CPU_ENTRY_AREA_NR] = { 0UL, "CPU entry area" },
Thomas Gleixner146122e2017-12-20 18:07:42 +0100140 [FIXADDR_START_NR] = { 0UL, "Fixmap area" },
141 [END_OF_SPACE_NR] = { -1, NULL }
Arjan van de Ven926e5392008-04-17 17:40:45 +0200142};
143
Joerg Roedel4e8537e2018-07-18 11:41:08 +0200144#define INIT_PGD (swapper_pg_dir)
145
Thomas Gleixner146122e2017-12-20 18:07:42 +0100146#endif /* !CONFIG_X86_64 */
147
Arjan van de Ven926e5392008-04-17 17:40:45 +0200148/* Multipliers for offsets within the PTEs */
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200149#define PTE_LEVEL_MULT (PAGE_SIZE)
150#define PMD_LEVEL_MULT (PTRS_PER_PTE * PTE_LEVEL_MULT)
151#define PUD_LEVEL_MULT (PTRS_PER_PMD * PMD_LEVEL_MULT)
Kirill A. Shutemovfdd3d8c2017-03-28 13:48:06 +0300152#define P4D_LEVEL_MULT (PTRS_PER_PUD * PUD_LEVEL_MULT)
Juergen Gross84bbabc2017-04-12 16:36:34 +0200153#define PGD_LEVEL_MULT (PTRS_PER_P4D * P4D_LEVEL_MULT)
Arjan van de Ven926e5392008-04-17 17:40:45 +0200154
Borislav Petkovef6bea62014-01-18 12:48:14 +0100155#define pt_dump_seq_printf(m, to_dmesg, fmt, args...) \
156({ \
157 if (to_dmesg) \
158 printk(KERN_INFO fmt, ##args); \
159 else \
160 if (m) \
161 seq_printf(m, fmt, ##args); \
162})
163
164#define pt_dump_cont_printf(m, to_dmesg, fmt, args...) \
165({ \
166 if (to_dmesg) \
167 printk(KERN_CONT fmt, ##args); \
168 else \
169 if (m) \
170 seq_printf(m, fmt, ##args); \
171})
172
Arjan van de Ven926e5392008-04-17 17:40:45 +0200173/*
174 * Print a readable form of a pgprot_t to the seq_file
175 */
Borislav Petkovef6bea62014-01-18 12:48:14 +0100176static void printk_prot(struct seq_file *m, pgprot_t prot, int level, bool dmsg)
Arjan van de Ven926e5392008-04-17 17:40:45 +0200177{
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200178 pgprotval_t pr = pgprot_val(prot);
179 static const char * const level_name[] =
Kirill A. Shutemov45dcd202017-07-17 01:59:48 +0300180 { "cr3", "pgd", "p4d", "pud", "pmd", "pte" };
Arjan van de Ven926e5392008-04-17 17:40:45 +0200181
Thomas Gleixnerc0534492017-12-16 01:14:39 +0100182 if (!(pr & _PAGE_PRESENT)) {
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200183 /* Not present */
Juergen Grossf439c429c32014-11-03 14:02:01 +0100184 pt_dump_cont_printf(m, dmsg, " ");
Arjan van de Ven926e5392008-04-17 17:40:45 +0200185 } else {
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200186 if (pr & _PAGE_USER)
Borislav Petkovef6bea62014-01-18 12:48:14 +0100187 pt_dump_cont_printf(m, dmsg, "USR ");
Arjan van de Ven926e5392008-04-17 17:40:45 +0200188 else
Borislav Petkovef6bea62014-01-18 12:48:14 +0100189 pt_dump_cont_printf(m, dmsg, " ");
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200190 if (pr & _PAGE_RW)
Borislav Petkovef6bea62014-01-18 12:48:14 +0100191 pt_dump_cont_printf(m, dmsg, "RW ");
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200192 else
Borislav Petkovef6bea62014-01-18 12:48:14 +0100193 pt_dump_cont_printf(m, dmsg, "ro ");
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200194 if (pr & _PAGE_PWT)
Borislav Petkovef6bea62014-01-18 12:48:14 +0100195 pt_dump_cont_printf(m, dmsg, "PWT ");
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200196 else
Borislav Petkovef6bea62014-01-18 12:48:14 +0100197 pt_dump_cont_printf(m, dmsg, " ");
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200198 if (pr & _PAGE_PCD)
Borislav Petkovef6bea62014-01-18 12:48:14 +0100199 pt_dump_cont_printf(m, dmsg, "PCD ");
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200200 else
Borislav Petkovef6bea62014-01-18 12:48:14 +0100201 pt_dump_cont_printf(m, dmsg, " ");
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200202
Juergen Grossf439c429c32014-11-03 14:02:01 +0100203 /* Bit 7 has a different meaning on level 3 vs 4 */
Kirill A. Shutemov45dcd202017-07-17 01:59:48 +0300204 if (level <= 4 && pr & _PAGE_PSE)
Juergen Grossf439c429c32014-11-03 14:02:01 +0100205 pt_dump_cont_printf(m, dmsg, "PSE ");
206 else
207 pt_dump_cont_printf(m, dmsg, " ");
Kirill A. Shutemov45dcd202017-07-17 01:59:48 +0300208 if ((level == 5 && pr & _PAGE_PAT) ||
209 ((level == 4 || level == 3) && pr & _PAGE_PAT_LARGE))
Toshi Kanida25e622015-09-17 12:24:19 -0600210 pt_dump_cont_printf(m, dmsg, "PAT ");
Juergen Grossf439c429c32014-11-03 14:02:01 +0100211 else
212 pt_dump_cont_printf(m, dmsg, " ");
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200213 if (pr & _PAGE_GLOBAL)
Borislav Petkovef6bea62014-01-18 12:48:14 +0100214 pt_dump_cont_printf(m, dmsg, "GLB ");
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200215 else
Borislav Petkovef6bea62014-01-18 12:48:14 +0100216 pt_dump_cont_printf(m, dmsg, " ");
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200217 if (pr & _PAGE_NX)
Borislav Petkovef6bea62014-01-18 12:48:14 +0100218 pt_dump_cont_printf(m, dmsg, "NX ");
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200219 else
Borislav Petkovef6bea62014-01-18 12:48:14 +0100220 pt_dump_cont_printf(m, dmsg, "x ");
Arjan van de Ven926e5392008-04-17 17:40:45 +0200221 }
Borislav Petkovef6bea62014-01-18 12:48:14 +0100222 pt_dump_cont_printf(m, dmsg, "%s\n", level_name[level]);
Arjan van de Ven926e5392008-04-17 17:40:45 +0200223}
224
225/*
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200226 * On 64 bits, sign-extend the 48 bit address to 64 bit
Arjan van de Ven926e5392008-04-17 17:40:45 +0200227 */
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200228static unsigned long normalize_addr(unsigned long u)
Arjan van de Ven926e5392008-04-17 17:40:45 +0200229{
Kirill A. Shutemov3a366f72017-07-17 01:59:47 +0300230 int shift;
231 if (!IS_ENABLED(CONFIG_X86_64))
232 return u;
233
234 shift = 64 - (__VIRTUAL_MASK_SHIFT + 1);
235 return (signed long)(u << shift) >> shift;
Arjan van de Ven926e5392008-04-17 17:40:45 +0200236}
237
238/*
239 * This function gets called on a break in a continuous series
240 * of PTE entries; the next one is different so we need to
241 * print what we collected so far.
242 */
243static void note_page(struct seq_file *m, struct pg_state *st,
Jan Beulich672c0ae2018-02-23 01:27:37 -0700244 pgprot_t new_prot, pgprotval_t new_eff, int level)
Arjan van de Ven926e5392008-04-17 17:40:45 +0200245{
Jan Beulich672c0ae2018-02-23 01:27:37 -0700246 pgprotval_t prot, cur, eff;
H. Peter Anvin3891a042014-04-29 16:46:09 -0700247 static const char units[] = "BKMGTPE";
Arjan van de Ven926e5392008-04-17 17:40:45 +0200248
249 /*
250 * If we have a "break" in the series, we need to flush the state that
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200251 * we have now. "break" is either changing perms, levels or
252 * address space marker.
Arjan van de Ven926e5392008-04-17 17:40:45 +0200253 */
Toshi Kanida25e622015-09-17 12:24:19 -0600254 prot = pgprot_val(new_prot);
255 cur = pgprot_val(st->current_prot);
Jan Beulich672c0ae2018-02-23 01:27:37 -0700256 eff = st->effective_prot;
Arjan van de Ven926e5392008-04-17 17:40:45 +0200257
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200258 if (!st->level) {
259 /* First entry */
260 st->current_prot = new_prot;
Jan Beulich672c0ae2018-02-23 01:27:37 -0700261 st->effective_prot = new_eff;
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200262 st->level = level;
263 st->marker = address_markers;
H. Peter Anvin3891a042014-04-29 16:46:09 -0700264 st->lines = 0;
Borislav Petkovef6bea62014-01-18 12:48:14 +0100265 pt_dump_seq_printf(m, st->to_dmesg, "---[ %s ]---\n",
266 st->marker->name);
Jan Beulich672c0ae2018-02-23 01:27:37 -0700267 } else if (prot != cur || new_eff != eff || level != st->level ||
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200268 st->current_address >= st->marker[1].start_address) {
269 const char *unit = units;
Arjan van de Ven926e5392008-04-17 17:40:45 +0200270 unsigned long delta;
Yinghai Lu6424fb32009-04-13 23:51:46 -0700271 int width = sizeof(unsigned long) * 2;
Stephen Smalleye1a58322015-10-05 12:55:20 -0400272
Jan Beulich672c0ae2018-02-23 01:27:37 -0700273 if (st->check_wx && (eff & _PAGE_RW) && !(eff & _PAGE_NX)) {
Stephen Smalleye1a58322015-10-05 12:55:20 -0400274 WARN_ONCE(1,
275 "x86/mm: Found insecure W+X mapping at address %p/%pS\n",
276 (void *)st->start_address,
277 (void *)st->start_address);
278 st->wx_pages += (st->current_address -
279 st->start_address) / PAGE_SIZE;
280 }
Arjan van de Ven926e5392008-04-17 17:40:45 +0200281
282 /*
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200283 * Now print the actual finished series
284 */
H. Peter Anvin3891a042014-04-29 16:46:09 -0700285 if (!st->marker->max_lines ||
286 st->lines < st->marker->max_lines) {
287 pt_dump_seq_printf(m, st->to_dmesg,
288 "0x%0*lx-0x%0*lx ",
289 width, st->start_address,
290 width, st->current_address);
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200291
H. Peter Anvin3891a042014-04-29 16:46:09 -0700292 delta = st->current_address - st->start_address;
293 while (!(delta & 1023) && unit[1]) {
294 delta >>= 10;
295 unit++;
296 }
297 pt_dump_cont_printf(m, st->to_dmesg, "%9lu%c ",
298 delta, *unit);
299 printk_prot(m, st->current_prot, st->level,
300 st->to_dmesg);
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200301 }
H. Peter Anvin3891a042014-04-29 16:46:09 -0700302 st->lines++;
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200303
304 /*
Arjan van de Ven926e5392008-04-17 17:40:45 +0200305 * We print markers for special areas of address space,
306 * such as the start of vmalloc space etc.
307 * This helps in the interpretation.
308 */
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200309 if (st->current_address >= st->marker[1].start_address) {
H. Peter Anvin3891a042014-04-29 16:46:09 -0700310 if (st->marker->max_lines &&
311 st->lines > st->marker->max_lines) {
312 unsigned long nskip =
313 st->lines - st->marker->max_lines;
314 pt_dump_seq_printf(m, st->to_dmesg,
315 "... %lu entr%s skipped ... \n",
316 nskip,
317 nskip == 1 ? "y" : "ies");
318 }
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200319 st->marker++;
H. Peter Anvin3891a042014-04-29 16:46:09 -0700320 st->lines = 0;
Borislav Petkovef6bea62014-01-18 12:48:14 +0100321 pt_dump_seq_printf(m, st->to_dmesg, "---[ %s ]---\n",
322 st->marker->name);
Arjan van de Ven926e5392008-04-17 17:40:45 +0200323 }
324
Arjan van de Ven926e5392008-04-17 17:40:45 +0200325 st->start_address = st->current_address;
326 st->current_prot = new_prot;
Jan Beulich672c0ae2018-02-23 01:27:37 -0700327 st->effective_prot = new_eff;
Arjan van de Ven926e5392008-04-17 17:40:45 +0200328 st->level = level;
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200329 }
Arjan van de Ven926e5392008-04-17 17:40:45 +0200330}
331
Jan Beulich672c0ae2018-02-23 01:27:37 -0700332static inline pgprotval_t effective_prot(pgprotval_t prot1, pgprotval_t prot2)
333{
334 return (prot1 & prot2 & (_PAGE_USER | _PAGE_RW)) |
335 ((prot1 | prot2) & _PAGE_NX);
336}
337
338static void walk_pte_level(struct seq_file *m, struct pg_state *st, pmd_t addr,
339 pgprotval_t eff_in, unsigned long P)
Arjan van de Ven926e5392008-04-17 17:40:45 +0200340{
341 int i;
Joerg Roedeld6ef1f12018-04-17 15:27:16 +0200342 pte_t *pte;
Jan Beulich672c0ae2018-02-23 01:27:37 -0700343 pgprotval_t prot, eff;
Arjan van de Ven926e5392008-04-17 17:40:45 +0200344
Arjan van de Ven926e5392008-04-17 17:40:45 +0200345 for (i = 0; i < PTRS_PER_PTE; i++) {
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200346 st->current_address = normalize_addr(P + i * PTE_LEVEL_MULT);
Joerg Roedeld6ef1f12018-04-17 15:27:16 +0200347 pte = pte_offset_map(&addr, st->current_address);
348 prot = pte_flags(*pte);
349 eff = effective_prot(eff_in, prot);
Jan Beulich672c0ae2018-02-23 01:27:37 -0700350 note_page(m, st, __pgprot(prot), eff, 5);
Joerg Roedeld6ef1f12018-04-17 15:27:16 +0200351 pte_unmap(pte);
Arjan van de Ven926e5392008-04-17 17:40:45 +0200352 }
353}
Andrey Ryabinin04b67022017-07-24 18:25:58 +0300354#ifdef CONFIG_KASAN
355
356/*
357 * This is an optimization for KASAN=y case. Since all kasan page tables
358 * eventually point to the kasan_zero_page we could call note_page()
359 * right away without walking through lower level page tables. This saves
360 * us dozens of seconds (minutes for 5-level config) while checking for
361 * W+X mapping or reading kernel_page_tables debugfs file.
362 */
363static inline bool kasan_page_table(struct seq_file *m, struct pg_state *st,
364 void *pt)
365{
366 if (__pa(pt) == __pa(kasan_zero_pmd) ||
Kirill A. Shutemoved7588d2018-05-18 13:35:24 +0300367 (pgtable_l5_enabled() && __pa(pt) == __pa(kasan_zero_p4d)) ||
Andrey Ryabinin04b67022017-07-24 18:25:58 +0300368 __pa(pt) == __pa(kasan_zero_pud)) {
369 pgprotval_t prot = pte_flags(kasan_zero_pte[0]);
Jan Beulich672c0ae2018-02-23 01:27:37 -0700370 note_page(m, st, __pgprot(prot), 0, 5);
Andrey Ryabinin04b67022017-07-24 18:25:58 +0300371 return true;
372 }
373 return false;
374}
375#else
376static inline bool kasan_page_table(struct seq_file *m, struct pg_state *st,
377 void *pt)
378{
379 return false;
380}
381#endif
Arjan van de Ven926e5392008-04-17 17:40:45 +0200382
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200383#if PTRS_PER_PMD > 1
Arjan van de Ven926e5392008-04-17 17:40:45 +0200384
Jan Beulich672c0ae2018-02-23 01:27:37 -0700385static void walk_pmd_level(struct seq_file *m, struct pg_state *st, pud_t addr,
386 pgprotval_t eff_in, unsigned long P)
Arjan van de Ven926e5392008-04-17 17:40:45 +0200387{
388 int i;
Andrey Ryabinin04b67022017-07-24 18:25:58 +0300389 pmd_t *start, *pmd_start;
Jan Beulich672c0ae2018-02-23 01:27:37 -0700390 pgprotval_t prot, eff;
Arjan van de Ven926e5392008-04-17 17:40:45 +0200391
Andrey Ryabinin04b67022017-07-24 18:25:58 +0300392 pmd_start = start = (pmd_t *)pud_page_vaddr(addr);
Arjan van de Ven926e5392008-04-17 17:40:45 +0200393 for (i = 0; i < PTRS_PER_PMD; i++) {
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200394 st->current_address = normalize_addr(P + i * PMD_LEVEL_MULT);
Arjan van de Ven926e5392008-04-17 17:40:45 +0200395 if (!pmd_none(*start)) {
Jan Beulich672c0ae2018-02-23 01:27:37 -0700396 prot = pmd_flags(*start);
397 eff = effective_prot(eff_in, prot);
Toshi Kanida25e622015-09-17 12:24:19 -0600398 if (pmd_large(*start) || !pmd_present(*start)) {
Jan Beulich672c0ae2018-02-23 01:27:37 -0700399 note_page(m, st, __pgprot(prot), eff, 4);
Andrey Ryabinin04b67022017-07-24 18:25:58 +0300400 } else if (!kasan_page_table(m, st, pmd_start)) {
Jan Beulich672c0ae2018-02-23 01:27:37 -0700401 walk_pte_level(m, st, *start, eff,
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200402 P + i * PMD_LEVEL_MULT);
Toshi Kanida25e622015-09-17 12:24:19 -0600403 }
Arjan van de Ven926e5392008-04-17 17:40:45 +0200404 } else
Jan Beulich672c0ae2018-02-23 01:27:37 -0700405 note_page(m, st, __pgprot(0), 0, 4);
Arjan van de Ven926e5392008-04-17 17:40:45 +0200406 start++;
407 }
408}
409
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200410#else
Jan Beulich672c0ae2018-02-23 01:27:37 -0700411#define walk_pmd_level(m,s,a,e,p) walk_pte_level(m,s,__pmd(pud_val(a)),e,p)
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200412#define pud_large(a) pmd_large(__pmd(pud_val(a)))
413#define pud_none(a) pmd_none(__pmd(pud_val(a)))
414#endif
Arjan van de Ven926e5392008-04-17 17:40:45 +0200415
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200416#if PTRS_PER_PUD > 1
417
Jan Beulich672c0ae2018-02-23 01:27:37 -0700418static void walk_pud_level(struct seq_file *m, struct pg_state *st, p4d_t addr,
419 pgprotval_t eff_in, unsigned long P)
Arjan van de Ven926e5392008-04-17 17:40:45 +0200420{
421 int i;
Andrey Ryabinin04b67022017-07-24 18:25:58 +0300422 pud_t *start, *pud_start;
Jan Beulich672c0ae2018-02-23 01:27:37 -0700423 pgprotval_t prot, eff;
Andrey Ryabinin243b72a2017-02-14 13:08:38 +0300424 pud_t *prev_pud = NULL;
Arjan van de Ven926e5392008-04-17 17:40:45 +0200425
Andrey Ryabinin04b67022017-07-24 18:25:58 +0300426 pud_start = start = (pud_t *)p4d_page_vaddr(addr);
Arjan van de Ven926e5392008-04-17 17:40:45 +0200427
428 for (i = 0; i < PTRS_PER_PUD; i++) {
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200429 st->current_address = normalize_addr(P + i * PUD_LEVEL_MULT);
Andrey Ryabinin04b67022017-07-24 18:25:58 +0300430 if (!pud_none(*start)) {
Jan Beulich672c0ae2018-02-23 01:27:37 -0700431 prot = pud_flags(*start);
432 eff = effective_prot(eff_in, prot);
Toshi Kanida25e622015-09-17 12:24:19 -0600433 if (pud_large(*start) || !pud_present(*start)) {
Jan Beulich672c0ae2018-02-23 01:27:37 -0700434 note_page(m, st, __pgprot(prot), eff, 3);
Andrey Ryabinin04b67022017-07-24 18:25:58 +0300435 } else if (!kasan_page_table(m, st, pud_start)) {
Jan Beulich672c0ae2018-02-23 01:27:37 -0700436 walk_pmd_level(m, st, *start, eff,
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200437 P + i * PUD_LEVEL_MULT);
Toshi Kanida25e622015-09-17 12:24:19 -0600438 }
Arjan van de Ven926e5392008-04-17 17:40:45 +0200439 } else
Jan Beulich672c0ae2018-02-23 01:27:37 -0700440 note_page(m, st, __pgprot(0), 0, 3);
Arjan van de Ven926e5392008-04-17 17:40:45 +0200441
Andrey Ryabinin243b72a2017-02-14 13:08:38 +0300442 prev_pud = start;
Arjan van de Ven926e5392008-04-17 17:40:45 +0200443 start++;
444 }
445}
446
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200447#else
Jan Beulich672c0ae2018-02-23 01:27:37 -0700448#define walk_pud_level(m,s,a,e,p) walk_pmd_level(m,s,__pud(p4d_val(a)),e,p)
Kirill A. Shutemovfdd3d8c2017-03-28 13:48:06 +0300449#define p4d_large(a) pud_large(__pud(p4d_val(a)))
450#define p4d_none(a) pud_none(__pud(p4d_val(a)))
451#endif
452
Jan Beulich672c0ae2018-02-23 01:27:37 -0700453static void walk_p4d_level(struct seq_file *m, struct pg_state *st, pgd_t addr,
454 pgprotval_t eff_in, unsigned long P)
Kirill A. Shutemovfdd3d8c2017-03-28 13:48:06 +0300455{
456 int i;
Andrey Ryabinin04b67022017-07-24 18:25:58 +0300457 p4d_t *start, *p4d_start;
Jan Beulich672c0ae2018-02-23 01:27:37 -0700458 pgprotval_t prot, eff;
Kirill A. Shutemovfdd3d8c2017-03-28 13:48:06 +0300459
Kirill A. Shutemovc65e7742018-02-14 14:16:53 +0300460 if (PTRS_PER_P4D == 1)
Jan Beulich672c0ae2018-02-23 01:27:37 -0700461 return walk_pud_level(m, st, __p4d(pgd_val(addr)), eff_in, P);
Kirill A. Shutemovc65e7742018-02-14 14:16:53 +0300462
Andrey Ryabinin04b67022017-07-24 18:25:58 +0300463 p4d_start = start = (p4d_t *)pgd_page_vaddr(addr);
Kirill A. Shutemovfdd3d8c2017-03-28 13:48:06 +0300464
465 for (i = 0; i < PTRS_PER_P4D; i++) {
466 st->current_address = normalize_addr(P + i * P4D_LEVEL_MULT);
467 if (!p4d_none(*start)) {
Jan Beulich672c0ae2018-02-23 01:27:37 -0700468 prot = p4d_flags(*start);
469 eff = effective_prot(eff_in, prot);
Kirill A. Shutemovfdd3d8c2017-03-28 13:48:06 +0300470 if (p4d_large(*start) || !p4d_present(*start)) {
Jan Beulich672c0ae2018-02-23 01:27:37 -0700471 note_page(m, st, __pgprot(prot), eff, 2);
Andrey Ryabinin04b67022017-07-24 18:25:58 +0300472 } else if (!kasan_page_table(m, st, p4d_start)) {
Jan Beulich672c0ae2018-02-23 01:27:37 -0700473 walk_pud_level(m, st, *start, eff,
Kirill A. Shutemovfdd3d8c2017-03-28 13:48:06 +0300474 P + i * P4D_LEVEL_MULT);
475 }
476 } else
Jan Beulich672c0ae2018-02-23 01:27:37 -0700477 note_page(m, st, __pgprot(0), 0, 2);
Kirill A. Shutemovfdd3d8c2017-03-28 13:48:06 +0300478
479 start++;
480 }
481}
482
Kirill A. Shutemoved7588d2018-05-18 13:35:24 +0300483#define pgd_large(a) (pgtable_l5_enabled() ? pgd_large(a) : p4d_large(__p4d(pgd_val(a))))
484#define pgd_none(a) (pgtable_l5_enabled() ? pgd_none(a) : p4d_none(__p4d(pgd_val(a))))
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200485
Boris Ostrovskyf4e342c2015-11-05 13:56:35 -0500486static inline bool is_hypervisor_range(int idx)
487{
Borislav Petkovb1768622016-02-18 21:00:41 +0100488#ifdef CONFIG_X86_64
Boris Ostrovskyf4e342c2015-11-05 13:56:35 -0500489 /*
490 * ffff800000000000 - ffff87ffffffffff is reserved for
491 * the hypervisor.
492 */
Borislav Petkovb1768622016-02-18 21:00:41 +0100493 return (idx >= pgd_index(__PAGE_OFFSET) - 16) &&
494 (idx < pgd_index(__PAGE_OFFSET));
Boris Ostrovskyf4e342c2015-11-05 13:56:35 -0500495#else
Borislav Petkovb1768622016-02-18 21:00:41 +0100496 return false;
Boris Ostrovskyf4e342c2015-11-05 13:56:35 -0500497#endif
Borislav Petkovb1768622016-02-18 21:00:41 +0100498}
Boris Ostrovskyf4e342c2015-11-05 13:56:35 -0500499
Stephen Smalleye1a58322015-10-05 12:55:20 -0400500static void ptdump_walk_pgd_level_core(struct seq_file *m, pgd_t *pgd,
Thomas Gleixnerb4bf4f92017-12-04 15:08:05 +0100501 bool checkwx, bool dmesg)
Arjan van de Ven926e5392008-04-17 17:40:45 +0200502{
Joerg Roedel4e8537e2018-07-18 11:41:08 +0200503 pgd_t *start = INIT_PGD;
Jan Beulich672c0ae2018-02-23 01:27:37 -0700504 pgprotval_t prot, eff;
Arjan van de Ven926e5392008-04-17 17:40:45 +0200505 int i;
Borislav Petkovef6bea62014-01-18 12:48:14 +0100506 struct pg_state st = {};
Arjan van de Ven926e5392008-04-17 17:40:45 +0200507
Borislav Petkovef6bea62014-01-18 12:48:14 +0100508 if (pgd) {
509 start = pgd;
Thomas Gleixnerb4bf4f92017-12-04 15:08:05 +0100510 st.to_dmesg = dmesg;
Borislav Petkovef6bea62014-01-18 12:48:14 +0100511 }
Arjan van de Ven926e5392008-04-17 17:40:45 +0200512
Stephen Smalleye1a58322015-10-05 12:55:20 -0400513 st.check_wx = checkwx;
514 if (checkwx)
515 st.wx_pages = 0;
516
Arjan van de Ven926e5392008-04-17 17:40:45 +0200517 for (i = 0; i < PTRS_PER_PGD; i++) {
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200518 st.current_address = normalize_addr(i * PGD_LEVEL_MULT);
Boris Ostrovskyf4e342c2015-11-05 13:56:35 -0500519 if (!pgd_none(*start) && !is_hypervisor_range(i)) {
Jan Beulich672c0ae2018-02-23 01:27:37 -0700520 prot = pgd_flags(*start);
521#ifdef CONFIG_X86_PAE
522 eff = _PAGE_USER | _PAGE_RW;
523#else
524 eff = prot;
525#endif
Toshi Kanida25e622015-09-17 12:24:19 -0600526 if (pgd_large(*start) || !pgd_present(*start)) {
Jan Beulich672c0ae2018-02-23 01:27:37 -0700527 note_page(m, &st, __pgprot(prot), eff, 1);
Toshi Kanida25e622015-09-17 12:24:19 -0600528 } else {
Jan Beulich672c0ae2018-02-23 01:27:37 -0700529 walk_p4d_level(m, &st, *start, eff,
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200530 i * PGD_LEVEL_MULT);
Toshi Kanida25e622015-09-17 12:24:19 -0600531 }
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200532 } else
Jan Beulich672c0ae2018-02-23 01:27:37 -0700533 note_page(m, &st, __pgprot(0), 0, 1);
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200534
Andrey Ryabinin146fbb762017-02-10 12:54:05 +0300535 cond_resched();
Arjan van de Ven926e5392008-04-17 17:40:45 +0200536 start++;
537 }
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200538
539 /* Flush out the last page */
540 st.current_address = normalize_addr(PTRS_PER_PGD*PGD_LEVEL_MULT);
Jan Beulich672c0ae2018-02-23 01:27:37 -0700541 note_page(m, &st, __pgprot(0), 0, 0);
Stephen Smalleye1a58322015-10-05 12:55:20 -0400542 if (!checkwx)
543 return;
544 if (st.wx_pages)
545 pr_info("x86/mm: Checked W+X mappings: FAILED, %lu W+X pages found.\n",
546 st.wx_pages);
547 else
548 pr_info("x86/mm: Checked W+X mappings: passed, no W+X pages found.\n");
Arjan van de Ven926e5392008-04-17 17:40:45 +0200549}
550
Stephen Smalleye1a58322015-10-05 12:55:20 -0400551void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd)
552{
Thomas Gleixnerb4bf4f92017-12-04 15:08:05 +0100553 ptdump_walk_pgd_level_core(m, pgd, false, true);
Stephen Smalleye1a58322015-10-05 12:55:20 -0400554}
Thomas Gleixnerb4bf4f92017-12-04 15:08:05 +0100555
Thomas Gleixnera4b51ef2017-12-04 15:08:06 +0100556void ptdump_walk_pgd_level_debugfs(struct seq_file *m, pgd_t *pgd, bool user)
Thomas Gleixnerb4bf4f92017-12-04 15:08:05 +0100557{
Thomas Gleixnera4b51ef2017-12-04 15:08:06 +0100558#ifdef CONFIG_PAGE_TABLE_ISOLATION
559 if (user && static_cpu_has(X86_FEATURE_PTI))
560 pgd = kernel_to_user_pgdp(pgd);
561#endif
Thomas Gleixnerb4bf4f92017-12-04 15:08:05 +0100562 ptdump_walk_pgd_level_core(m, pgd, false, false);
563}
564EXPORT_SYMBOL_GPL(ptdump_walk_pgd_level_debugfs);
565
566static void ptdump_walk_user_pgd_level_checkwx(void)
567{
568#ifdef CONFIG_PAGE_TABLE_ISOLATION
Joerg Roedel4e8537e2018-07-18 11:41:08 +0200569 pgd_t *pgd = INIT_PGD;
Thomas Gleixnerb4bf4f92017-12-04 15:08:05 +0100570
571 if (!static_cpu_has(X86_FEATURE_PTI))
572 return;
573
574 pr_info("x86/mm: Checking user space page tables\n");
575 pgd = kernel_to_user_pgdp(pgd);
576 ptdump_walk_pgd_level_core(NULL, pgd, true, false);
577#endif
578}
Stephen Smalleye1a58322015-10-05 12:55:20 -0400579
580void ptdump_walk_pgd_level_checkwx(void)
581{
Thomas Gleixnerb4bf4f92017-12-04 15:08:05 +0100582 ptdump_walk_pgd_level_core(NULL, NULL, true, false);
583 ptdump_walk_user_pgd_level_checkwx();
Stephen Smalleye1a58322015-10-05 12:55:20 -0400584}
585
Kees Cook8609d1b2015-11-19 17:07:55 -0800586static int __init pt_dump_init(void)
Arjan van de Ven926e5392008-04-17 17:40:45 +0200587{
Thomas Garnier0483e1f2016-06-21 17:47:02 -0700588 /*
589 * Various markers are not compile-time constants, so assign them
590 * here.
591 */
592#ifdef CONFIG_X86_64
593 address_markers[LOW_KERNEL_NR].start_address = PAGE_OFFSET;
594 address_markers[VMALLOC_START_NR].start_address = VMALLOC_START;
595 address_markers[VMEMMAP_START_NR].start_address = VMEMMAP_START;
Kirill A. Shutemov5c7919b2018-02-14 14:16:52 +0300596#ifdef CONFIG_MODIFY_LDT_SYSCALL
597 address_markers[LDT_NR].start_address = LDT_BASE_ADDR;
598#endif
Kirill A. Shutemov09e61a72018-02-14 14:16:55 +0300599#ifdef CONFIG_KASAN
600 address_markers[KASAN_SHADOW_START_NR].start_address = KASAN_SHADOW_START;
601 address_markers[KASAN_SHADOW_END_NR].start_address = KASAN_SHADOW_END;
602#endif
Thomas Garnier0483e1f2016-06-21 17:47:02 -0700603#endif
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200604#ifdef CONFIG_X86_32
Andres Salomon92851e22010-07-20 15:19:46 -0700605 address_markers[VMALLOC_START_NR].start_address = VMALLOC_START;
606 address_markers[VMALLOC_END_NR].start_address = VMALLOC_END;
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200607# ifdef CONFIG_HIGHMEM
Andres Salomon92851e22010-07-20 15:19:46 -0700608 address_markers[PKMAP_BASE_NR].start_address = PKMAP_BASE;
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200609# endif
Andres Salomon92851e22010-07-20 15:19:46 -0700610 address_markers[FIXADDR_START_NR].start_address = FIXADDR_START;
Thomas Gleixner92a0f812017-12-20 18:51:31 +0100611 address_markers[CPU_ENTRY_AREA_NR].start_address = CPU_ENTRY_AREA_BASE;
H. Peter Anvinfe770bf02008-04-17 17:40:45 +0200612#endif
Arjan van de Ven926e5392008-04-17 17:40:45 +0200613 return 0;
614}
Arjan van de Ven926e5392008-04-17 17:40:45 +0200615__initcall(pt_dump_init);