0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/debugfs.h>
0013 #include <linux/errno.h>
0014 #include <linux/fs.h>
0015 #include <linux/io.h>
0016 #include <linux/init.h>
0017 #include <linux/mm.h>
0018 #include <linux/ptdump.h>
0019 #include <linux/sched.h>
0020 #include <linux/seq_file.h>
0021
0022 #include <asm/fixmap.h>
0023 #include <asm/kasan.h>
0024 #include <asm/memory.h>
0025 #include <asm/pgtable-hwdef.h>
0026 #include <asm/ptdump.h>
0027
0028
0029 enum address_markers_idx {
0030 PAGE_OFFSET_NR = 0,
0031 PAGE_END_NR,
0032 #if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)
0033 KASAN_START_NR,
0034 #endif
0035 };
0036
0037 static struct addr_marker address_markers[] = {
0038 { PAGE_OFFSET, "Linear Mapping start" },
0039 { 0 , "Linear Mapping end" },
0040 #if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)
0041 { 0 , "Kasan shadow start" },
0042 { KASAN_SHADOW_END, "Kasan shadow end" },
0043 #endif
0044 { MODULES_VADDR, "Modules start" },
0045 { MODULES_END, "Modules end" },
0046 { VMALLOC_START, "vmalloc() area" },
0047 { VMALLOC_END, "vmalloc() end" },
0048 { FIXADDR_START, "Fixmap start" },
0049 { FIXADDR_TOP, "Fixmap end" },
0050 { PCI_IO_START, "PCI I/O start" },
0051 { PCI_IO_END, "PCI I/O end" },
0052 { VMEMMAP_START, "vmemmap start" },
0053 { VMEMMAP_START + VMEMMAP_SIZE, "vmemmap end" },
0054 { -1, NULL },
0055 };
0056
0057 #define pt_dump_seq_printf(m, fmt, args...) \
0058 ({ \
0059 if (m) \
0060 seq_printf(m, fmt, ##args); \
0061 })
0062
0063 #define pt_dump_seq_puts(m, fmt) \
0064 ({ \
0065 if (m) \
0066 seq_printf(m, fmt); \
0067 })
0068
0069
0070
0071
0072
0073
0074
0075 struct pg_state {
0076 struct ptdump_state ptdump;
0077 struct seq_file *seq;
0078 const struct addr_marker *marker;
0079 unsigned long start_address;
0080 int level;
0081 u64 current_prot;
0082 bool check_wx;
0083 unsigned long wx_pages;
0084 unsigned long uxn_pages;
0085 };
0086
0087 struct prot_bits {
0088 u64 mask;
0089 u64 val;
0090 const char *set;
0091 const char *clear;
0092 };
0093
0094 static const struct prot_bits pte_bits[] = {
0095 {
0096 .mask = PTE_VALID,
0097 .val = PTE_VALID,
0098 .set = " ",
0099 .clear = "F",
0100 }, {
0101 .mask = PTE_USER,
0102 .val = PTE_USER,
0103 .set = "USR",
0104 .clear = " ",
0105 }, {
0106 .mask = PTE_RDONLY,
0107 .val = PTE_RDONLY,
0108 .set = "ro",
0109 .clear = "RW",
0110 }, {
0111 .mask = PTE_PXN,
0112 .val = PTE_PXN,
0113 .set = "NX",
0114 .clear = "x ",
0115 }, {
0116 .mask = PTE_SHARED,
0117 .val = PTE_SHARED,
0118 .set = "SHD",
0119 .clear = " ",
0120 }, {
0121 .mask = PTE_AF,
0122 .val = PTE_AF,
0123 .set = "AF",
0124 .clear = " ",
0125 }, {
0126 .mask = PTE_NG,
0127 .val = PTE_NG,
0128 .set = "NG",
0129 .clear = " ",
0130 }, {
0131 .mask = PTE_CONT,
0132 .val = PTE_CONT,
0133 .set = "CON",
0134 .clear = " ",
0135 }, {
0136 .mask = PTE_TABLE_BIT,
0137 .val = PTE_TABLE_BIT,
0138 .set = " ",
0139 .clear = "BLK",
0140 }, {
0141 .mask = PTE_UXN,
0142 .val = PTE_UXN,
0143 .set = "UXN",
0144 .clear = " ",
0145 }, {
0146 .mask = PTE_GP,
0147 .val = PTE_GP,
0148 .set = "GP",
0149 .clear = " ",
0150 }, {
0151 .mask = PTE_ATTRINDX_MASK,
0152 .val = PTE_ATTRINDX(MT_DEVICE_nGnRnE),
0153 .set = "DEVICE/nGnRnE",
0154 }, {
0155 .mask = PTE_ATTRINDX_MASK,
0156 .val = PTE_ATTRINDX(MT_DEVICE_nGnRE),
0157 .set = "DEVICE/nGnRE",
0158 }, {
0159 .mask = PTE_ATTRINDX_MASK,
0160 .val = PTE_ATTRINDX(MT_NORMAL_NC),
0161 .set = "MEM/NORMAL-NC",
0162 }, {
0163 .mask = PTE_ATTRINDX_MASK,
0164 .val = PTE_ATTRINDX(MT_NORMAL),
0165 .set = "MEM/NORMAL",
0166 }, {
0167 .mask = PTE_ATTRINDX_MASK,
0168 .val = PTE_ATTRINDX(MT_NORMAL_TAGGED),
0169 .set = "MEM/NORMAL-TAGGED",
0170 }
0171 };
0172
0173 struct pg_level {
0174 const struct prot_bits *bits;
0175 const char *name;
0176 size_t num;
0177 u64 mask;
0178 };
0179
0180 static struct pg_level pg_level[] = {
0181 {
0182 .name = "PGD",
0183 .bits = pte_bits,
0184 .num = ARRAY_SIZE(pte_bits),
0185 }, {
0186 .name = "P4D",
0187 .bits = pte_bits,
0188 .num = ARRAY_SIZE(pte_bits),
0189 }, {
0190 .name = (CONFIG_PGTABLE_LEVELS > 3) ? "PUD" : "PGD",
0191 .bits = pte_bits,
0192 .num = ARRAY_SIZE(pte_bits),
0193 }, {
0194 .name = (CONFIG_PGTABLE_LEVELS > 2) ? "PMD" : "PGD",
0195 .bits = pte_bits,
0196 .num = ARRAY_SIZE(pte_bits),
0197 }, {
0198 .name = "PTE",
0199 .bits = pte_bits,
0200 .num = ARRAY_SIZE(pte_bits),
0201 },
0202 };
0203
0204 static void dump_prot(struct pg_state *st, const struct prot_bits *bits,
0205 size_t num)
0206 {
0207 unsigned i;
0208
0209 for (i = 0; i < num; i++, bits++) {
0210 const char *s;
0211
0212 if ((st->current_prot & bits->mask) == bits->val)
0213 s = bits->set;
0214 else
0215 s = bits->clear;
0216
0217 if (s)
0218 pt_dump_seq_printf(st->seq, " %s", s);
0219 }
0220 }
0221
0222 static void note_prot_uxn(struct pg_state *st, unsigned long addr)
0223 {
0224 if (!st->check_wx)
0225 return;
0226
0227 if ((st->current_prot & PTE_UXN) == PTE_UXN)
0228 return;
0229
0230 WARN_ONCE(1, "arm64/mm: Found non-UXN mapping at address %p/%pS\n",
0231 (void *)st->start_address, (void *)st->start_address);
0232
0233 st->uxn_pages += (addr - st->start_address) / PAGE_SIZE;
0234 }
0235
0236 static void note_prot_wx(struct pg_state *st, unsigned long addr)
0237 {
0238 if (!st->check_wx)
0239 return;
0240 if ((st->current_prot & PTE_RDONLY) == PTE_RDONLY)
0241 return;
0242 if ((st->current_prot & PTE_PXN) == PTE_PXN)
0243 return;
0244
0245 WARN_ONCE(1, "arm64/mm: Found insecure W+X mapping at address %p/%pS\n",
0246 (void *)st->start_address, (void *)st->start_address);
0247
0248 st->wx_pages += (addr - st->start_address) / PAGE_SIZE;
0249 }
0250
0251 static void note_page(struct ptdump_state *pt_st, unsigned long addr, int level,
0252 u64 val)
0253 {
0254 struct pg_state *st = container_of(pt_st, struct pg_state, ptdump);
0255 static const char units[] = "KMGTPE";
0256 u64 prot = 0;
0257
0258 if (level >= 0)
0259 prot = val & pg_level[level].mask;
0260
0261 if (st->level == -1) {
0262 st->level = level;
0263 st->current_prot = prot;
0264 st->start_address = addr;
0265 pt_dump_seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
0266 } else if (prot != st->current_prot || level != st->level ||
0267 addr >= st->marker[1].start_address) {
0268 const char *unit = units;
0269 unsigned long delta;
0270
0271 if (st->current_prot) {
0272 note_prot_uxn(st, addr);
0273 note_prot_wx(st, addr);
0274 }
0275
0276 pt_dump_seq_printf(st->seq, "0x%016lx-0x%016lx ",
0277 st->start_address, addr);
0278
0279 delta = (addr - st->start_address) >> 10;
0280 while (!(delta & 1023) && unit[1]) {
0281 delta >>= 10;
0282 unit++;
0283 }
0284 pt_dump_seq_printf(st->seq, "%9lu%c %s", delta, *unit,
0285 pg_level[st->level].name);
0286 if (st->current_prot && pg_level[st->level].bits)
0287 dump_prot(st, pg_level[st->level].bits,
0288 pg_level[st->level].num);
0289 pt_dump_seq_puts(st->seq, "\n");
0290
0291 if (addr >= st->marker[1].start_address) {
0292 st->marker++;
0293 pt_dump_seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
0294 }
0295
0296 st->start_address = addr;
0297 st->current_prot = prot;
0298 st->level = level;
0299 }
0300
0301 if (addr >= st->marker[1].start_address) {
0302 st->marker++;
0303 pt_dump_seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
0304 }
0305
0306 }
0307
0308 void ptdump_walk(struct seq_file *s, struct ptdump_info *info)
0309 {
0310 unsigned long end = ~0UL;
0311 struct pg_state st;
0312
0313 if (info->base_addr < TASK_SIZE_64)
0314 end = TASK_SIZE_64;
0315
0316 st = (struct pg_state){
0317 .seq = s,
0318 .marker = info->markers,
0319 .level = -1,
0320 .ptdump = {
0321 .note_page = note_page,
0322 .range = (struct ptdump_range[]){
0323 {info->base_addr, end},
0324 {0, 0}
0325 }
0326 }
0327 };
0328
0329 ptdump_walk_pgd(&st.ptdump, info->mm, NULL);
0330 }
0331
0332 static void __init ptdump_initialize(void)
0333 {
0334 unsigned i, j;
0335
0336 for (i = 0; i < ARRAY_SIZE(pg_level); i++)
0337 if (pg_level[i].bits)
0338 for (j = 0; j < pg_level[i].num; j++)
0339 pg_level[i].mask |= pg_level[i].bits[j].mask;
0340 }
0341
0342 static struct ptdump_info kernel_ptdump_info = {
0343 .mm = &init_mm,
0344 .markers = address_markers,
0345 .base_addr = PAGE_OFFSET,
0346 };
0347
0348 void ptdump_check_wx(void)
0349 {
0350 struct pg_state st = {
0351 .seq = NULL,
0352 .marker = (struct addr_marker[]) {
0353 { 0, NULL},
0354 { -1, NULL},
0355 },
0356 .level = -1,
0357 .check_wx = true,
0358 .ptdump = {
0359 .note_page = note_page,
0360 .range = (struct ptdump_range[]) {
0361 {PAGE_OFFSET, ~0UL},
0362 {0, 0}
0363 }
0364 }
0365 };
0366
0367 ptdump_walk_pgd(&st.ptdump, &init_mm, NULL);
0368
0369 if (st.wx_pages || st.uxn_pages)
0370 pr_warn("Checked W+X mappings: FAILED, %lu W+X pages found, %lu non-UXN pages found\n",
0371 st.wx_pages, st.uxn_pages);
0372 else
0373 pr_info("Checked W+X mappings: passed, no W+X pages found\n");
0374 }
0375
0376 static int __init ptdump_init(void)
0377 {
0378 address_markers[PAGE_END_NR].start_address = PAGE_END;
0379 #if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS)
0380 address_markers[KASAN_START_NR].start_address = KASAN_SHADOW_START;
0381 #endif
0382 ptdump_initialize();
0383 ptdump_debugfs_register(&kernel_ptdump_info, "kernel_page_tables");
0384 return 0;
0385 }
0386 device_initcall(ptdump_init);