1 // SPDX-License-Identifier: GPL-2.0-only 2 3 #include <linux/coredump.h> 4 #include <linux/elfcore.h> 5 #include <linux/kernel.h> 6 #include <linux/mm.h> 7 8 #include <asm/cpufeature.h> 9 #include <asm/mte.h> 10 11 #define for_each_mte_vma(cprm, i, m) \ 12 if (system_supports_mte()) \ 13 for (i = 0, m = cprm->vma_meta; \ 14 i < cprm->vma_count; \ 15 i++, m = cprm->vma_meta + i) \ 16 if (m->flags & VM_MTE) 17 18 static unsigned long mte_vma_tag_dump_size(struct core_vma_metadata *m) 19 { 20 return (m->dump_size >> PAGE_SHIFT) * MTE_PAGE_TAG_STORAGE; 21 } 22 23 /* Derived from dump_user_range(); start/end must be page-aligned */ 24 static int mte_dump_tag_range(struct coredump_params *cprm, 25 unsigned long start, unsigned long len) 26 { 27 int ret = 1; 28 unsigned long addr; 29 void *tags = NULL; 30 31 for (addr = start; addr < start + len; addr += PAGE_SIZE) { 32 struct page *page = get_dump_page(addr); 33 34 /* 35 * get_dump_page() returns NULL when encountering an empty 36 * page table entry that would otherwise have been filled with 37 * the zero page. Skip the equivalent tag dump which would 38 * have been all zeros. 39 */ 40 if (!page) { 41 dump_skip(cprm, MTE_PAGE_TAG_STORAGE); 42 continue; 43 } 44 45 /* 46 * Pages mapped in user space as !pte_access_permitted() (e.g. 47 * PROT_EXEC only) may not have the PG_mte_tagged flag set. 48 */ 49 if (!page_mte_tagged(page)) { 50 put_page(page); 51 dump_skip(cprm, MTE_PAGE_TAG_STORAGE); 52 continue; 53 } 54 55 if (!tags) { 56 tags = mte_allocate_tag_storage(); 57 if (!tags) { 58 put_page(page); 59 ret = 0; 60 break; 61 } 62 } 63 64 mte_save_page_tags(page_address(page), tags); 65 put_page(page); 66 if (!dump_emit(cprm, tags, MTE_PAGE_TAG_STORAGE)) { 67 ret = 0; 68 break; 69 } 70 } 71 72 if (tags) 73 mte_free_tag_storage(tags); 74 75 return ret; 76 } 77 78 Elf_Half elf_core_extra_phdrs(struct coredump_params *cprm) 79 { 80 int i; 81 struct core_vma_metadata *m; 82 int vma_count = 0; 83 84 for_each_mte_vma(cprm, i, m) 85 vma_count++; 86 87 return vma_count; 88 } 89 90 int elf_core_write_extra_phdrs(struct coredump_params *cprm, loff_t offset) 91 { 92 int i; 93 struct core_vma_metadata *m; 94 95 for_each_mte_vma(cprm, i, m) { 96 struct elf_phdr phdr; 97 98 phdr.p_type = PT_AARCH64_MEMTAG_MTE; 99 phdr.p_offset = offset; 100 phdr.p_vaddr = m->start; 101 phdr.p_paddr = 0; 102 phdr.p_filesz = mte_vma_tag_dump_size(m); 103 phdr.p_memsz = m->end - m->start; 104 offset += phdr.p_filesz; 105 phdr.p_flags = 0; 106 phdr.p_align = 0; 107 108 if (!dump_emit(cprm, &phdr, sizeof(phdr))) 109 return 0; 110 } 111 112 return 1; 113 } 114 115 size_t elf_core_extra_data_size(struct coredump_params *cprm) 116 { 117 int i; 118 struct core_vma_metadata *m; 119 size_t data_size = 0; 120 121 for_each_mte_vma(cprm, i, m) 122 data_size += mte_vma_tag_dump_size(m); 123 124 return data_size; 125 } 126 127 int elf_core_write_extra_data(struct coredump_params *cprm) 128 { 129 int i; 130 struct core_vma_metadata *m; 131 132 for_each_mte_vma(cprm, i, m) { 133 if (!mte_dump_tag_range(cprm, m->start, m->dump_size)) 134 return 0; 135 } 136 137 return 1; 138 } 139
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.