1 // SPDX-License-Identifier: GPL-2.0-only
3 #include <linux/coredump.h>
4 #include <linux/elfcore.h>
5 #include <linux/kernel.h>
8 #include <asm/cpufeature.h>
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)
18 static unsigned long mte_vma_tag_dump_size(struct core_vma_metadata *m)
20 return (m->dump_size >> PAGE_SHIFT) * MTE_PAGE_TAG_STORAGE;
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)
31 for (addr = start; addr < start + len; addr += PAGE_SIZE) {
32 struct page *page = get_dump_page(addr);
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.
41 dump_skip(cprm, MTE_PAGE_TAG_STORAGE);
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.
49 if (!page_mte_tagged(page)) {
51 dump_skip(cprm, MTE_PAGE_TAG_STORAGE);
56 tags = mte_allocate_tag_storage();
64 mte_save_page_tags(page_address(page), tags);
66 if (!dump_emit(cprm, tags, MTE_PAGE_TAG_STORAGE)) {
73 mte_free_tag_storage(tags);
78 Elf_Half elf_core_extra_phdrs(struct coredump_params *cprm)
81 struct core_vma_metadata *m;
84 for_each_mte_vma(cprm, i, m)
90 int elf_core_write_extra_phdrs(struct coredump_params *cprm, loff_t offset)
93 struct core_vma_metadata *m;
95 for_each_mte_vma(cprm, i, m) {
98 phdr.p_type = PT_AARCH64_MEMTAG_MTE;
99 phdr.p_offset = offset;
100 phdr.p_vaddr = m->start;
102 phdr.p_filesz = mte_vma_tag_dump_size(m);
103 phdr.p_memsz = m->end - m->start;
104 offset += phdr.p_filesz;
108 if (!dump_emit(cprm, &phdr, sizeof(phdr)))
115 size_t elf_core_extra_data_size(struct coredump_params *cprm)
118 struct core_vma_metadata *m;
119 size_t data_size = 0;
121 for_each_mte_vma(cprm, i, m)
122 data_size += mte_vma_tag_dump_size(m);
127 int elf_core_write_extra_data(struct coredump_params *cprm)
130 struct core_vma_metadata *m;
132 for_each_mte_vma(cprm, i, m) {
133 if (!mte_dump_tag_range(cprm, m->start, m->dump_size))