| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 |
- // SPDX-License-Identifier: GPL-2.0-only
- #include <linux/coredump.h>
- #include <linux/elfcore.h>
- #include <linux/kernel.h>
- #include <linux/mm.h>
- #include <asm/cpufeature.h>
- #include <asm/mte.h>
- #define for_each_mte_vma(cprm, i, m) \
- if (system_supports_mte()) \
- for (i = 0, m = cprm->vma_meta; \
- i < cprm->vma_count; \
- i++, m = cprm->vma_meta + i) \
- if (m->flags & VM_MTE)
- static unsigned long mte_vma_tag_dump_size(struct core_vma_metadata *m)
- {
- return (m->dump_size >> PAGE_SHIFT) * MTE_PAGE_TAG_STORAGE;
- }
- /* Derived from dump_user_range(); start/end must be page-aligned */
- static int mte_dump_tag_range(struct coredump_params *cprm,
- unsigned long start, unsigned long len)
- {
- int ret = 1;
- unsigned long addr;
- void *tags = NULL;
- for (addr = start; addr < start + len; addr += PAGE_SIZE) {
- struct page *page = get_dump_page(addr);
- /*
- * get_dump_page() returns NULL when encountering an empty
- * page table entry that would otherwise have been filled with
- * the zero page. Skip the equivalent tag dump which would
- * have been all zeros.
- */
- if (!page) {
- dump_skip(cprm, MTE_PAGE_TAG_STORAGE);
- continue;
- }
- /*
- * Pages mapped in user space as !pte_access_permitted() (e.g.
- * PROT_EXEC only) may not have the PG_mte_tagged flag set.
- */
- if (!page_mte_tagged(page)) {
- put_page(page);
- dump_skip(cprm, MTE_PAGE_TAG_STORAGE);
- continue;
- }
- if (!tags) {
- tags = mte_allocate_tag_storage();
- if (!tags) {
- put_page(page);
- ret = 0;
- break;
- }
- }
- mte_save_page_tags(page_address(page), tags);
- put_page(page);
- if (!dump_emit(cprm, tags, MTE_PAGE_TAG_STORAGE)) {
- ret = 0;
- break;
- }
- }
- if (tags)
- mte_free_tag_storage(tags);
- return ret;
- }
- Elf_Half elf_core_extra_phdrs(struct coredump_params *cprm)
- {
- int i;
- struct core_vma_metadata *m;
- int vma_count = 0;
- for_each_mte_vma(cprm, i, m)
- vma_count++;
- return vma_count;
- }
- int elf_core_write_extra_phdrs(struct coredump_params *cprm, loff_t offset)
- {
- int i;
- struct core_vma_metadata *m;
- for_each_mte_vma(cprm, i, m) {
- struct elf_phdr phdr;
- phdr.p_type = PT_AARCH64_MEMTAG_MTE;
- phdr.p_offset = offset;
- phdr.p_vaddr = m->start;
- phdr.p_paddr = 0;
- phdr.p_filesz = mte_vma_tag_dump_size(m);
- phdr.p_memsz = m->end - m->start;
- offset += phdr.p_filesz;
- phdr.p_flags = 0;
- phdr.p_align = 0;
- if (!dump_emit(cprm, &phdr, sizeof(phdr)))
- return 0;
- }
- return 1;
- }
- size_t elf_core_extra_data_size(struct coredump_params *cprm)
- {
- int i;
- struct core_vma_metadata *m;
- size_t data_size = 0;
- for_each_mte_vma(cprm, i, m)
- data_size += mte_vma_tag_dump_size(m);
- return data_size;
- }
- int elf_core_write_extra_data(struct coredump_params *cprm)
- {
- int i;
- struct core_vma_metadata *m;
- for_each_mte_vma(cprm, i, m) {
- if (!mte_dump_tag_range(cprm, m->start, m->dump_size))
- return 0;
- }
- return 1;
- }
|