0001
0002
0003 #include <linux/coredump.h>
0004 #include <linux/elfcore.h>
0005 #include <linux/kernel.h>
0006 #include <linux/mm.h>
0007
0008 #include <asm/cpufeature.h>
0009 #include <asm/mte.h>
0010
0011 #define for_each_mte_vma(tsk, vma) \
0012 if (system_supports_mte()) \
0013 for (vma = tsk->mm->mmap; vma; vma = vma->vm_next) \
0014 if (vma->vm_flags & VM_MTE)
0015
0016 static unsigned long mte_vma_tag_dump_size(struct vm_area_struct *vma)
0017 {
0018 if (vma->vm_flags & VM_DONTDUMP)
0019 return 0;
0020
0021 return vma_pages(vma) * MTE_PAGE_TAG_STORAGE;
0022 }
0023
0024
0025 static int mte_dump_tag_range(struct coredump_params *cprm,
0026 unsigned long start, unsigned long end)
0027 {
0028 int ret = 1;
0029 unsigned long addr;
0030 void *tags = NULL;
0031
0032 for (addr = start; addr < end; addr += PAGE_SIZE) {
0033 struct page *page = get_dump_page(addr);
0034
0035
0036
0037
0038
0039
0040
0041 if (!page) {
0042 dump_skip(cprm, MTE_PAGE_TAG_STORAGE);
0043 continue;
0044 }
0045
0046
0047
0048
0049
0050 if (!test_bit(PG_mte_tagged, &page->flags)) {
0051 put_page(page);
0052 dump_skip(cprm, MTE_PAGE_TAG_STORAGE);
0053 continue;
0054 }
0055
0056 if (!tags) {
0057 tags = mte_allocate_tag_storage();
0058 if (!tags) {
0059 put_page(page);
0060 ret = 0;
0061 break;
0062 }
0063 }
0064
0065 mte_save_page_tags(page_address(page), tags);
0066 put_page(page);
0067 if (!dump_emit(cprm, tags, MTE_PAGE_TAG_STORAGE)) {
0068 mte_free_tag_storage(tags);
0069 ret = 0;
0070 break;
0071 }
0072 }
0073
0074 if (tags)
0075 mte_free_tag_storage(tags);
0076
0077 return ret;
0078 }
0079
0080 Elf_Half elf_core_extra_phdrs(void)
0081 {
0082 struct vm_area_struct *vma;
0083 int vma_count = 0;
0084
0085 for_each_mte_vma(current, vma)
0086 vma_count++;
0087
0088 return vma_count;
0089 }
0090
0091 int elf_core_write_extra_phdrs(struct coredump_params *cprm, loff_t offset)
0092 {
0093 struct vm_area_struct *vma;
0094
0095 for_each_mte_vma(current, vma) {
0096 struct elf_phdr phdr;
0097
0098 phdr.p_type = PT_AARCH64_MEMTAG_MTE;
0099 phdr.p_offset = offset;
0100 phdr.p_vaddr = vma->vm_start;
0101 phdr.p_paddr = 0;
0102 phdr.p_filesz = mte_vma_tag_dump_size(vma);
0103 phdr.p_memsz = vma->vm_end - vma->vm_start;
0104 offset += phdr.p_filesz;
0105 phdr.p_flags = 0;
0106 phdr.p_align = 0;
0107
0108 if (!dump_emit(cprm, &phdr, sizeof(phdr)))
0109 return 0;
0110 }
0111
0112 return 1;
0113 }
0114
0115 size_t elf_core_extra_data_size(void)
0116 {
0117 struct vm_area_struct *vma;
0118 size_t data_size = 0;
0119
0120 for_each_mte_vma(current, vma)
0121 data_size += mte_vma_tag_dump_size(vma);
0122
0123 return data_size;
0124 }
0125
0126 int elf_core_write_extra_data(struct coredump_params *cprm)
0127 {
0128 struct vm_area_struct *vma;
0129
0130 for_each_mte_vma(current, vma) {
0131 if (vma->vm_flags & VM_DONTDUMP)
0132 continue;
0133
0134 if (!mte_dump_tag_range(cprm, vma->vm_start, vma->vm_end))
0135 return 0;
0136 }
0137
0138 return 1;
0139 }