Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <linux/set_memory.h>
0003 #include <linux/ptdump.h>
0004 #include <linux/seq_file.h>
0005 #include <linux/debugfs.h>
0006 #include <linux/mm.h>
0007 #include <linux/kfence.h>
0008 #include <linux/kasan.h>
0009 #include <asm/ptdump.h>
0010 #include <asm/kasan.h>
0011 #include <asm/nospec-branch.h>
0012 #include <asm/sections.h>
0013 
0014 static unsigned long max_addr;
0015 
0016 struct addr_marker {
0017     unsigned long start_address;
0018     const char *name;
0019 };
0020 
0021 enum address_markers_idx {
0022     IDENTITY_BEFORE_NR = 0,
0023     IDENTITY_BEFORE_END_NR,
0024     KERNEL_START_NR,
0025     KERNEL_END_NR,
0026 #ifdef CONFIG_KFENCE
0027     KFENCE_START_NR,
0028     KFENCE_END_NR,
0029 #endif
0030     IDENTITY_AFTER_NR,
0031     IDENTITY_AFTER_END_NR,
0032 #ifdef CONFIG_KASAN
0033     KASAN_SHADOW_START_NR,
0034     KASAN_SHADOW_END_NR,
0035 #endif
0036     VMEMMAP_NR,
0037     VMEMMAP_END_NR,
0038     VMALLOC_NR,
0039     VMALLOC_END_NR,
0040     MODULES_NR,
0041     MODULES_END_NR,
0042 };
0043 
0044 static struct addr_marker address_markers[] = {
0045     [IDENTITY_BEFORE_NR]    = {0, "Identity Mapping Start"},
0046     [IDENTITY_BEFORE_END_NR] = {(unsigned long)_stext, "Identity Mapping End"},
0047     [KERNEL_START_NR]   = {(unsigned long)_stext, "Kernel Image Start"},
0048     [KERNEL_END_NR]     = {(unsigned long)_end, "Kernel Image End"},
0049 #ifdef CONFIG_KFENCE
0050     [KFENCE_START_NR]   = {0, "KFence Pool Start"},
0051     [KFENCE_END_NR]     = {0, "KFence Pool End"},
0052 #endif
0053     [IDENTITY_AFTER_NR] = {(unsigned long)_end, "Identity Mapping Start"},
0054     [IDENTITY_AFTER_END_NR] = {0, "Identity Mapping End"},
0055 #ifdef CONFIG_KASAN
0056     [KASAN_SHADOW_START_NR] = {KASAN_SHADOW_START, "Kasan Shadow Start"},
0057     [KASAN_SHADOW_END_NR]   = {KASAN_SHADOW_END, "Kasan Shadow End"},
0058 #endif
0059     [VMEMMAP_NR]        = {0, "vmemmap Area Start"},
0060     [VMEMMAP_END_NR]    = {0, "vmemmap Area End"},
0061     [VMALLOC_NR]        = {0, "vmalloc Area Start"},
0062     [VMALLOC_END_NR]    = {0, "vmalloc Area End"},
0063     [MODULES_NR]        = {0, "Modules Area Start"},
0064     [MODULES_END_NR]    = {0, "Modules Area End"},
0065     { -1, NULL }
0066 };
0067 
0068 struct pg_state {
0069     struct ptdump_state ptdump;
0070     struct seq_file *seq;
0071     int level;
0072     unsigned int current_prot;
0073     bool check_wx;
0074     unsigned long wx_pages;
0075     unsigned long start_address;
0076     const struct addr_marker *marker;
0077 };
0078 
0079 #define pt_dump_seq_printf(m, fmt, args...) \
0080 ({                      \
0081     struct seq_file *__m = (m);     \
0082                         \
0083     if (__m)                \
0084         seq_printf(__m, fmt, ##args);   \
0085 })
0086 
0087 #define pt_dump_seq_puts(m, fmt)        \
0088 ({                      \
0089     struct seq_file *__m = (m);     \
0090                         \
0091     if (__m)                \
0092         seq_printf(__m, fmt);       \
0093 })
0094 
0095 static void print_prot(struct seq_file *m, unsigned int pr, int level)
0096 {
0097     static const char * const level_name[] =
0098         { "ASCE", "PGD", "PUD", "PMD", "PTE" };
0099 
0100     pt_dump_seq_printf(m, "%s ", level_name[level]);
0101     if (pr & _PAGE_INVALID) {
0102         pt_dump_seq_printf(m, "I\n");
0103         return;
0104     }
0105     pt_dump_seq_puts(m, (pr & _PAGE_PROTECT) ? "RO " : "RW ");
0106     pt_dump_seq_puts(m, (pr & _PAGE_NOEXEC) ? "NX\n" : "X\n");
0107 }
0108 
0109 static void note_prot_wx(struct pg_state *st, unsigned long addr)
0110 {
0111 #ifdef CONFIG_DEBUG_WX
0112     if (!st->check_wx)
0113         return;
0114     if (st->current_prot & _PAGE_INVALID)
0115         return;
0116     if (st->current_prot & _PAGE_PROTECT)
0117         return;
0118     if (st->current_prot & _PAGE_NOEXEC)
0119         return;
0120     /*
0121      * The first lowcore page is W+X if spectre mitigations are using
0122      * trampolines or the BEAR enhancements facility is not installed,
0123      * in which case we have two lpswe instructions in lowcore that need
0124      * to be executable.
0125      */
0126     if (addr == PAGE_SIZE && (nospec_uses_trampoline() || !static_key_enabled(&cpu_has_bear)))
0127         return;
0128     WARN_ONCE(1, "s390/mm: Found insecure W+X mapping at address %pS\n",
0129           (void *)st->start_address);
0130     st->wx_pages += (addr - st->start_address) / PAGE_SIZE;
0131 #endif /* CONFIG_DEBUG_WX */
0132 }
0133 
0134 static void note_page(struct ptdump_state *pt_st, unsigned long addr, int level, u64 val)
0135 {
0136     int width = sizeof(unsigned long) * 2;
0137     static const char units[] = "KMGTPE";
0138     const char *unit = units;
0139     unsigned long delta;
0140     struct pg_state *st;
0141     struct seq_file *m;
0142     unsigned int prot;
0143 
0144     st = container_of(pt_st, struct pg_state, ptdump);
0145     m = st->seq;
0146     prot = val & (_PAGE_PROTECT | _PAGE_NOEXEC);
0147     if (level == 4 && (val & _PAGE_INVALID))
0148         prot = _PAGE_INVALID;
0149     /* For pmd_none() & friends val gets passed as zero. */
0150     if (level != 4 && !val)
0151         prot = _PAGE_INVALID;
0152     /* Final flush from generic code. */
0153     if (level == -1)
0154         addr = max_addr;
0155     if (st->level == -1) {
0156         pt_dump_seq_printf(m, "---[ %s ]---\n", st->marker->name);
0157         st->start_address = addr;
0158         st->current_prot = prot;
0159         st->level = level;
0160     } else if (prot != st->current_prot || level != st->level ||
0161            addr >= st->marker[1].start_address) {
0162         note_prot_wx(st, addr);
0163         pt_dump_seq_printf(m, "0x%0*lx-0x%0*lx ",
0164                    width, st->start_address,
0165                    width, addr);
0166         delta = (addr - st->start_address) >> 10;
0167         while (!(delta & 0x3ff) && unit[1]) {
0168             delta >>= 10;
0169             unit++;
0170         }
0171         pt_dump_seq_printf(m, "%9lu%c ", delta, *unit);
0172         print_prot(m, st->current_prot, st->level);
0173         while (addr >= st->marker[1].start_address) {
0174             st->marker++;
0175             pt_dump_seq_printf(m, "---[ %s ]---\n", st->marker->name);
0176         }
0177         st->start_address = addr;
0178         st->current_prot = prot;
0179         st->level = level;
0180     }
0181 }
0182 
0183 #ifdef CONFIG_DEBUG_WX
0184 void ptdump_check_wx(void)
0185 {
0186     struct pg_state st = {
0187         .ptdump = {
0188             .note_page = note_page,
0189             .range = (struct ptdump_range[]) {
0190                 {.start = 0, .end = max_addr},
0191                 {.start = 0, .end = 0},
0192             }
0193         },
0194         .seq = NULL,
0195         .level = -1,
0196         .current_prot = 0,
0197         .check_wx = true,
0198         .wx_pages = 0,
0199         .start_address = 0,
0200         .marker = (struct addr_marker[]) {
0201             { .start_address =  0, .name = NULL},
0202             { .start_address = -1, .name = NULL},
0203         },
0204     };
0205 
0206     if (!MACHINE_HAS_NX)
0207         return;
0208     ptdump_walk_pgd(&st.ptdump, &init_mm, NULL);
0209     if (st.wx_pages)
0210         pr_warn("Checked W+X mappings: FAILED, %lu W+X pages found\n", st.wx_pages);
0211     else
0212         pr_info("Checked W+X mappings: passed, no %sW+X pages found\n",
0213             (nospec_uses_trampoline() || !static_key_enabled(&cpu_has_bear)) ?
0214             "unexpected " : "");
0215 }
0216 #endif /* CONFIG_DEBUG_WX */
0217 
0218 #ifdef CONFIG_PTDUMP_DEBUGFS
0219 static int ptdump_show(struct seq_file *m, void *v)
0220 {
0221     struct pg_state st = {
0222         .ptdump = {
0223             .note_page = note_page,
0224             .range = (struct ptdump_range[]) {
0225                 {.start = 0, .end = max_addr},
0226                 {.start = 0, .end = 0},
0227             }
0228         },
0229         .seq = m,
0230         .level = -1,
0231         .current_prot = 0,
0232         .check_wx = false,
0233         .wx_pages = 0,
0234         .start_address = 0,
0235         .marker = address_markers,
0236     };
0237 
0238     get_online_mems();
0239     mutex_lock(&cpa_mutex);
0240     ptdump_walk_pgd(&st.ptdump, &init_mm, NULL);
0241     mutex_unlock(&cpa_mutex);
0242     put_online_mems();
0243     return 0;
0244 }
0245 DEFINE_SHOW_ATTRIBUTE(ptdump);
0246 #endif /* CONFIG_PTDUMP_DEBUGFS */
0247 
0248 /*
0249  * Heapsort from lib/sort.c is not a stable sorting algorithm, do a simple
0250  * insertion sort to preserve the original order of markers with the same
0251  * start address.
0252  */
0253 static void sort_address_markers(void)
0254 {
0255     struct addr_marker tmp;
0256     int i, j;
0257 
0258     for (i = 1; i < ARRAY_SIZE(address_markers) - 1; i++) {
0259         tmp = address_markers[i];
0260         for (j = i - 1; j >= 0 && address_markers[j].start_address > tmp.start_address; j--)
0261             address_markers[j + 1] = address_markers[j];
0262         address_markers[j + 1] = tmp;
0263     }
0264 }
0265 
0266 static int pt_dump_init(void)
0267 {
0268 #ifdef CONFIG_KFENCE
0269     unsigned long kfence_start = (unsigned long)__kfence_pool;
0270 #endif
0271     /*
0272      * Figure out the maximum virtual address being accessible with the
0273      * kernel ASCE. We need this to keep the page table walker functions
0274      * from accessing non-existent entries.
0275      */
0276     max_addr = (S390_lowcore.kernel_asce & _REGION_ENTRY_TYPE_MASK) >> 2;
0277     max_addr = 1UL << (max_addr * 11 + 31);
0278     address_markers[IDENTITY_AFTER_END_NR].start_address = ident_map_size;
0279     address_markers[MODULES_NR].start_address = MODULES_VADDR;
0280     address_markers[MODULES_END_NR].start_address = MODULES_END;
0281     address_markers[VMEMMAP_NR].start_address = (unsigned long) vmemmap;
0282     address_markers[VMEMMAP_END_NR].start_address = (unsigned long)vmemmap + vmemmap_size;
0283     address_markers[VMALLOC_NR].start_address = VMALLOC_START;
0284     address_markers[VMALLOC_END_NR].start_address = VMALLOC_END;
0285 #ifdef CONFIG_KFENCE
0286     address_markers[KFENCE_START_NR].start_address = kfence_start;
0287     address_markers[KFENCE_END_NR].start_address = kfence_start + KFENCE_POOL_SIZE;
0288 #endif
0289     sort_address_markers();
0290 #ifdef CONFIG_PTDUMP_DEBUGFS
0291     debugfs_create_file("kernel_page_tables", 0400, NULL, NULL, &ptdump_fops);
0292 #endif /* CONFIG_PTDUMP_DEBUGFS */
0293     return 0;
0294 }
0295 device_initcall(pt_dump_init);