Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
  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 */
 34struct 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 */
 48struct addr_marker {
 49	unsigned long start_address;
 50	const char *name;
 51};
 52
 53/* Private information for debugfs */
 54struct 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
 61enum address_markers_idx {
 62#ifdef CONFIG_KASAN
 63	KASAN_SHADOW_START_NR,
 64	KASAN_SHADOW_END_NR,
 65#endif
 66	FIXMAP_START_NR,
 67	FIXMAP_END_NR,
 68	PCI_IO_START_NR,
 69	PCI_IO_END_NR,
 70#ifdef CONFIG_SPARSEMEM_VMEMMAP
 71	VMEMMAP_START_NR,
 72	VMEMMAP_END_NR,
 73#endif
 74	VMALLOC_START_NR,
 75	VMALLOC_END_NR,
 76	PAGE_OFFSET_NR,
 77#ifdef CONFIG_64BIT
 78	MODULES_MAPPING_NR,
 79	KERNEL_MAPPING_NR,
 80#endif
 81	END_OF_SPACE_NR
 82};
 83
 84static struct addr_marker address_markers[] = {
 85#ifdef CONFIG_KASAN
 86	{0, "Kasan shadow start"},
 87	{0, "Kasan shadow end"},
 88#endif
 89	{0, "Fixmap start"},
 90	{0, "Fixmap end"},
 91	{0, "PCI I/O start"},
 92	{0, "PCI I/O end"},
 93#ifdef CONFIG_SPARSEMEM_VMEMMAP
 94	{0, "vmemmap start"},
 95	{0, "vmemmap end"},
 96#endif
 97	{0, "vmalloc() area"},
 98	{0, "vmalloc() end"},
 99	{0, "Linear mapping"},
100#ifdef CONFIG_64BIT
101	{0, "Modules/BPF mapping"},
102	{0, "Kernel mapping"},
103#endif
104	{-1, NULL},
105};
106
107static struct ptd_mm_info kernel_ptd_info = {
108	.mm		= &init_mm,
109	.markers	= address_markers,
110	.base_addr	= 0,
111	.end		= ULONG_MAX,
112};
113
114#ifdef CONFIG_EFI
115static struct addr_marker efi_addr_markers[] = {
116		{ 0,		"UEFI runtime start" },
117		{ SZ_1G,	"UEFI runtime end" },
118		{ -1,		NULL }
119};
120
121static struct ptd_mm_info efi_ptd_info = {
122	.mm		= &efi_mm,
123	.markers	= efi_addr_markers,
124	.base_addr	= 0,
125	.end		= SZ_2G,
126};
127#endif
128
129/* Page Table Entry */
130struct prot_bits {
131	u64 mask;
132	u64 val;
133	const char *set;
134	const char *clear;
135};
136
137static const struct prot_bits pte_bits[] = {
138	{
139		.mask = _PAGE_SOFT,
140		.val = _PAGE_SOFT,
141		.set = "RSW",
142		.clear = "   ",
143	}, {
144		.mask = _PAGE_DIRTY,
145		.val = _PAGE_DIRTY,
146		.set = "D",
147		.clear = ".",
148	}, {
149		.mask = _PAGE_ACCESSED,
150		.val = _PAGE_ACCESSED,
151		.set = "A",
152		.clear = ".",
153	}, {
154		.mask = _PAGE_GLOBAL,
155		.val = _PAGE_GLOBAL,
156		.set = "G",
157		.clear = ".",
158	}, {
159		.mask = _PAGE_USER,
160		.val = _PAGE_USER,
161		.set = "U",
162		.clear = ".",
163	}, {
164		.mask = _PAGE_EXEC,
165		.val = _PAGE_EXEC,
166		.set = "X",
167		.clear = ".",
168	}, {
169		.mask = _PAGE_WRITE,
170		.val = _PAGE_WRITE,
171		.set = "W",
172		.clear = ".",
173	}, {
174		.mask = _PAGE_READ,
175		.val = _PAGE_READ,
176		.set = "R",
177		.clear = ".",
178	}, {
179		.mask = _PAGE_PRESENT,
180		.val = _PAGE_PRESENT,
181		.set = "V",
182		.clear = ".",
183	}
184};
185
186/* Page Level */
187struct pg_level {
188	const char *name;
189	u64 mask;
190};
191
192static struct pg_level pg_level[] = {
193	{ /* pgd */
194		.name = "PGD",
195	}, { /* p4d */
196		.name = (CONFIG_PGTABLE_LEVELS > 4) ? "P4D" : "PGD",
197	}, { /* pud */
198		.name = (CONFIG_PGTABLE_LEVELS > 3) ? "PUD" : "PGD",
199	}, { /* pmd */
200		.name = (CONFIG_PGTABLE_LEVELS > 2) ? "PMD" : "PGD",
201	}, { /* pte */
202		.name = "PTE",
203	},
204};
205
206static void dump_prot(struct pg_state *st)
207{
208	unsigned int i;
209
210	for (i = 0; i < ARRAY_SIZE(pte_bits); i++) {
211		const char *s;
212
213		if ((st->current_prot & pte_bits[i].mask) == pte_bits[i].val)
214			s = pte_bits[i].set;
215		else
216			s = pte_bits[i].clear;
217
218		if (s)
219			pt_dump_seq_printf(st->seq, " %s", s);
220	}
221}
222
223#ifdef CONFIG_64BIT
224#define ADDR_FORMAT	"0x%016lx"
225#else
226#define ADDR_FORMAT	"0x%08lx"
227#endif
228static void dump_addr(struct pg_state *st, unsigned long addr)
229{
230	static const char units[] = "KMGTPE";
231	const char *unit = units;
232	unsigned long delta;
233
234	pt_dump_seq_printf(st->seq, ADDR_FORMAT "-" ADDR_FORMAT "   ",
235			   st->start_address, addr);
236
237	pt_dump_seq_printf(st->seq, " " ADDR_FORMAT " ", st->start_pa);
238	delta = (addr - st->start_address) >> 10;
239
240	while (!(delta & 1023) && unit[1]) {
241		delta >>= 10;
242		unit++;
243	}
244
245	pt_dump_seq_printf(st->seq, "%9lu%c %s", delta, *unit,
246			   pg_level[st->level].name);
247}
248
249static void note_prot_wx(struct pg_state *st, unsigned long addr)
250{
251	if (!st->check_wx)
252		return;
253
254	if ((st->current_prot & (_PAGE_WRITE | _PAGE_EXEC)) !=
255	    (_PAGE_WRITE | _PAGE_EXEC))
256		return;
257
258	WARN_ONCE(1, "riscv/mm: Found insecure W+X mapping at address %p/%pS\n",
259		  (void *)st->start_address, (void *)st->start_address);
260
261	st->wx_pages += (addr - st->start_address) / PAGE_SIZE;
262}
263
264static void note_page(struct ptdump_state *pt_st, unsigned long addr,
265		      int level, u64 val)
266{
267	struct pg_state *st = container_of(pt_st, struct pg_state, ptdump);
268	u64 pa = PFN_PHYS(pte_pfn(__pte(val)));
269	u64 prot = 0;
270
271	if (level >= 0)
272		prot = val & pg_level[level].mask;
273
274	if (st->level == -1) {
275		st->level = level;
276		st->current_prot = prot;
277		st->start_address = addr;
278		st->start_pa = pa;
279		st->last_pa = pa;
280		pt_dump_seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
281	} else if (prot != st->current_prot ||
282		   level != st->level || addr >= st->marker[1].start_address) {
283		if (st->current_prot) {
284			note_prot_wx(st, addr);
285			dump_addr(st, addr);
286			dump_prot(st);
287			pt_dump_seq_puts(st->seq, "\n");
288		}
289
290		while (addr >= st->marker[1].start_address) {
291			st->marker++;
292			pt_dump_seq_printf(st->seq, "---[ %s ]---\n",
293					   st->marker->name);
294		}
295
296		st->start_address = addr;
297		st->start_pa = pa;
298		st->last_pa = pa;
299		st->current_prot = prot;
300		st->level = level;
301	} else {
302		st->last_pa = pa;
303	}
304}
305
306static void ptdump_walk(struct seq_file *s, struct ptd_mm_info *pinfo)
307{
308	struct pg_state st = {
309		.seq = s,
310		.marker = pinfo->markers,
311		.level = -1,
312		.ptdump = {
313			.note_page = note_page,
314			.range = (struct ptdump_range[]) {
315				{pinfo->base_addr, pinfo->end},
316				{0, 0}
317			}
318		}
319	};
320
321	ptdump_walk_pgd(&st.ptdump, pinfo->mm, NULL);
322}
323
324void ptdump_check_wx(void)
325{
326	struct pg_state st = {
327		.seq = NULL,
328		.marker = (struct addr_marker[]) {
329			{0, NULL},
330			{-1, NULL},
331		},
332		.level = -1,
333		.check_wx = true,
334		.ptdump = {
335			.note_page = note_page,
336			.range = (struct ptdump_range[]) {
337				{KERN_VIRT_START, ULONG_MAX},
338				{0, 0}
339			}
340		}
341	};
342
343	ptdump_walk_pgd(&st.ptdump, &init_mm, NULL);
344
345	if (st.wx_pages)
346		pr_warn("Checked W+X mappings: failed, %lu W+X pages found\n",
347			st.wx_pages);
348	else
349		pr_info("Checked W+X mappings: passed, no W+X pages found\n");
350}
351
352static int ptdump_show(struct seq_file *m, void *v)
353{
354	ptdump_walk(m, m->private);
355
356	return 0;
357}
358
359DEFINE_SHOW_ATTRIBUTE(ptdump);
360
361static int __init ptdump_init(void)
362{
363	unsigned int i, j;
364
365#ifdef CONFIG_KASAN
366	address_markers[KASAN_SHADOW_START_NR].start_address = KASAN_SHADOW_START;
367	address_markers[KASAN_SHADOW_END_NR].start_address = KASAN_SHADOW_END;
368#endif
369	address_markers[FIXMAP_START_NR].start_address = FIXADDR_START;
370	address_markers[FIXMAP_END_NR].start_address = FIXADDR_TOP;
371	address_markers[PCI_IO_START_NR].start_address = PCI_IO_START;
372	address_markers[PCI_IO_END_NR].start_address = PCI_IO_END;
373#ifdef CONFIG_SPARSEMEM_VMEMMAP
374	address_markers[VMEMMAP_START_NR].start_address = VMEMMAP_START;
375	address_markers[VMEMMAP_END_NR].start_address = VMEMMAP_END;
376#endif
377	address_markers[VMALLOC_START_NR].start_address = VMALLOC_START;
378	address_markers[VMALLOC_END_NR].start_address = VMALLOC_END;
379	address_markers[PAGE_OFFSET_NR].start_address = PAGE_OFFSET;
380#ifdef CONFIG_64BIT
381	address_markers[MODULES_MAPPING_NR].start_address = MODULES_VADDR;
382	address_markers[KERNEL_MAPPING_NR].start_address = kernel_map.virt_addr;
383#endif
384
385	kernel_ptd_info.base_addr = KERN_VIRT_START;
386
387	for (i = 0; i < ARRAY_SIZE(pg_level); i++)
388		for (j = 0; j < ARRAY_SIZE(pte_bits); j++)
389			pg_level[i].mask |= pte_bits[j].mask;
390
391	debugfs_create_file("kernel_page_tables", 0400, NULL, &kernel_ptd_info,
392			    &ptdump_fops);
393#ifdef CONFIG_EFI
394	if (efi_enabled(EFI_RUNTIME_SERVICES))
395		debugfs_create_file("efi_page_tables", 0400, NULL, &efi_ptd_info,
396				    &ptdump_fops);
397#endif
398
399	return 0;
400}
401
402device_initcall(ptdump_init);