^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (c) 2014, The Linux Foundation. All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Debug helper to dump the current kernel pagetables of the system
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * so that we can see what the various memory ranges are set to.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Derived from x86 and arm implementation:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * (C) Copyright 2008 Intel Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Author: Arjan van de Ven <arjan@linux.intel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/debugfs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/ptdump.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/seq_file.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <asm/fixmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <asm/kasan.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <asm/memory.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <asm/pgtable-hwdef.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <asm/ptdump.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) enum address_markers_idx {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) PAGE_OFFSET_NR = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) PAGE_END_NR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) KASAN_START_NR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) static struct addr_marker address_markers[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) { PAGE_OFFSET, "Linear Mapping start" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) { 0 /* PAGE_END */, "Linear Mapping end" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) { 0 /* KASAN_SHADOW_START */, "Kasan shadow start" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) { KASAN_SHADOW_END, "Kasan shadow end" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) { BPF_JIT_REGION_START, "BPF start" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) { BPF_JIT_REGION_END, "BPF end" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) { MODULES_VADDR, "Modules start" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) { MODULES_END, "Modules end" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) { VMALLOC_START, "vmalloc() area" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) { VMALLOC_END, "vmalloc() end" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) { FIXADDR_START, "Fixmap start" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) { FIXADDR_TOP, "Fixmap end" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) { PCI_IO_START, "PCI I/O start" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) { PCI_IO_END, "PCI I/O end" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #ifdef CONFIG_SPARSEMEM_VMEMMAP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) { VMEMMAP_START, "vmemmap start" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) { VMEMMAP_START + VMEMMAP_SIZE, "vmemmap end" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) { -1, NULL },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define pt_dump_seq_printf(m, fmt, args...) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) ({ \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) if (m) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) seq_printf(m, fmt, ##args); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) })
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #define pt_dump_seq_puts(m, fmt) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) ({ \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) if (m) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) seq_printf(m, fmt); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) })
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * The page dumper groups page table entries of the same type into a single
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * description. It uses pg_state to track the range information while
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * iterating over the pte entries. When the continuity is broken it then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * dumps out a description of the range.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) struct pg_state {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) struct ptdump_state ptdump;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) struct seq_file *seq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) const struct addr_marker *marker;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) unsigned long start_address;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) int level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) u64 current_prot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) bool check_wx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) unsigned long wx_pages;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) unsigned long uxn_pages;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) struct prot_bits {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) u64 mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) u64 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) const char *set;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) const char *clear;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) static const struct prot_bits pte_bits[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) .mask = PTE_VALID,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) .val = PTE_VALID,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) .set = " ",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) .clear = "F",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) .mask = PTE_USER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) .val = PTE_USER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) .set = "USR",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) .clear = " ",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) .mask = PTE_RDONLY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) .val = PTE_RDONLY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) .set = "ro",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) .clear = "RW",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) .mask = PTE_PXN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) .val = PTE_PXN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) .set = "NX",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) .clear = "x ",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) .mask = PTE_SHARED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) .val = PTE_SHARED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) .set = "SHD",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) .clear = " ",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) .mask = PTE_AF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) .val = PTE_AF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) .set = "AF",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) .clear = " ",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) .mask = PTE_NG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) .val = PTE_NG,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) .set = "NG",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) .clear = " ",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) .mask = PTE_CONT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) .val = PTE_CONT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) .set = "CON",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) .clear = " ",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) .mask = PTE_TABLE_BIT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) .val = PTE_TABLE_BIT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) .set = " ",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) .clear = "BLK",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) .mask = PTE_UXN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) .val = PTE_UXN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) .set = "UXN",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) .clear = " ",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) .mask = PTE_GP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) .val = PTE_GP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) .set = "GP",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) .clear = " ",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) .mask = PTE_ATTRINDX_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) .val = PTE_ATTRINDX(MT_DEVICE_nGnRnE),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) .set = "DEVICE/nGnRnE",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) .mask = PTE_ATTRINDX_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) .val = PTE_ATTRINDX(MT_DEVICE_nGnRE),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) .set = "DEVICE/nGnRE",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) .mask = PTE_ATTRINDX_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) .val = PTE_ATTRINDX(MT_DEVICE_GRE),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) .set = "DEVICE/GRE",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) .mask = PTE_ATTRINDX_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) .val = PTE_ATTRINDX(MT_NORMAL_NC),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) .set = "MEM/NORMAL-NC",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) .mask = PTE_ATTRINDX_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) .val = PTE_ATTRINDX(MT_NORMAL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) .set = "MEM/NORMAL",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) .mask = PTE_ATTRINDX_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) .val = PTE_ATTRINDX(MT_NORMAL_TAGGED),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) .set = "MEM/NORMAL-TAGGED",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) struct pg_level {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) const struct prot_bits *bits;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) const char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) size_t num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) u64 mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) static struct pg_level pg_level[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) { /* pgd */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) .name = "PGD",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) .bits = pte_bits,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) .num = ARRAY_SIZE(pte_bits),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) }, { /* p4d */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) .name = "P4D",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) .bits = pte_bits,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) .num = ARRAY_SIZE(pte_bits),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) }, { /* pud */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) .name = (CONFIG_PGTABLE_LEVELS > 3) ? "PUD" : "PGD",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) .bits = pte_bits,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) .num = ARRAY_SIZE(pte_bits),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) }, { /* pmd */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) .name = (CONFIG_PGTABLE_LEVELS > 2) ? "PMD" : "PGD",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) .bits = pte_bits,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) .num = ARRAY_SIZE(pte_bits),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) }, { /* pte */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) .name = "PTE",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) .bits = pte_bits,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) .num = ARRAY_SIZE(pte_bits),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) static void dump_prot(struct pg_state *st, const struct prot_bits *bits,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) size_t num)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) unsigned i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) for (i = 0; i < num; i++, bits++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) const char *s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) if ((st->current_prot & bits->mask) == bits->val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) s = bits->set;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) s = bits->clear;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) if (s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) pt_dump_seq_printf(st->seq, " %s", s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) static void note_prot_uxn(struct pg_state *st, unsigned long addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) if (!st->check_wx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) if ((st->current_prot & PTE_UXN) == PTE_UXN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) WARN_ONCE(1, "arm64/mm: Found non-UXN mapping at address %p/%pS\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) (void *)st->start_address, (void *)st->start_address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) st->uxn_pages += (addr - st->start_address) / PAGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) static void note_prot_wx(struct pg_state *st, unsigned long addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) if (!st->check_wx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) if ((st->current_prot & PTE_RDONLY) == PTE_RDONLY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) if ((st->current_prot & PTE_PXN) == PTE_PXN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) WARN_ONCE(1, "arm64/mm: Found insecure W+X mapping at address %p/%pS\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) (void *)st->start_address, (void *)st->start_address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) st->wx_pages += (addr - st->start_address) / PAGE_SIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) static void note_page(struct ptdump_state *pt_st, unsigned long addr, int level,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) u64 val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) struct pg_state *st = container_of(pt_st, struct pg_state, ptdump);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) static const char units[] = "KMGTPE";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) u64 prot = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) if (level >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) prot = val & pg_level[level].mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) if (st->level == -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) st->level = level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) st->current_prot = prot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) st->start_address = addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) pt_dump_seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) } else if (prot != st->current_prot || level != st->level ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) addr >= st->marker[1].start_address) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) const char *unit = units;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) unsigned long delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) if (st->current_prot) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) note_prot_uxn(st, addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) note_prot_wx(st, addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) pt_dump_seq_printf(st->seq, "0x%016lx-0x%016lx ",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) st->start_address, addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) delta = (addr - st->start_address) >> 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) while (!(delta & 1023) && unit[1]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) delta >>= 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) unit++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) pt_dump_seq_printf(st->seq, "%9lu%c %s", delta, *unit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) pg_level[st->level].name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) if (st->current_prot && pg_level[st->level].bits)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) dump_prot(st, pg_level[st->level].bits,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) pg_level[st->level].num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) pt_dump_seq_puts(st->seq, "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) if (addr >= st->marker[1].start_address) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) st->marker++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) pt_dump_seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) st->start_address = addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) st->current_prot = prot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) st->level = level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) if (addr >= st->marker[1].start_address) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) st->marker++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) pt_dump_seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) void ptdump_walk(struct seq_file *s, struct ptdump_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) unsigned long end = ~0UL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) struct pg_state st;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) if (info->base_addr < TASK_SIZE_64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) end = TASK_SIZE_64;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) st = (struct pg_state){
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) .seq = s,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) .marker = info->markers,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) .ptdump = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) .note_page = note_page,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) .range = (struct ptdump_range[]){
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) {info->base_addr, end},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) {0, 0}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) ptdump_walk_pgd(&st.ptdump, info->mm, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) static void ptdump_initialize(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) unsigned i, j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) for (i = 0; i < ARRAY_SIZE(pg_level); i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) if (pg_level[i].bits)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) for (j = 0; j < pg_level[i].num; j++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) pg_level[i].mask |= pg_level[i].bits[j].mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) static struct ptdump_info kernel_ptdump_info = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) .mm = &init_mm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) .markers = address_markers,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) .base_addr = PAGE_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) void ptdump_check_wx(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) struct pg_state st = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) .seq = NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) .marker = (struct addr_marker[]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) { 0, NULL},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) { -1, NULL},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) .level = -1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) .check_wx = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) .ptdump = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) .note_page = note_page,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) .range = (struct ptdump_range[]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) {PAGE_OFFSET, ~0UL},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) {0, 0}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) ptdump_walk_pgd(&st.ptdump, &init_mm, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) if (st.wx_pages || st.uxn_pages)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) pr_warn("Checked W+X mappings: FAILED, %lu W+X pages found, %lu non-UXN pages found\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) st.wx_pages, st.uxn_pages);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) pr_info("Checked W+X mappings: passed, no W+X pages found\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) static int ptdump_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) address_markers[PAGE_END_NR].start_address = PAGE_END;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) #if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) address_markers[KASAN_START_NR].start_address = KASAN_SHADOW_START;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) ptdump_initialize();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) ptdump_debugfs_register(&kernel_ptdump_info, "kernel_page_tables");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) device_initcall(ptdump_init);