Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
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 /* Derived from dump_user_range(); start/end must be page-aligned */
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          * get_dump_page() returns NULL when encountering an empty
0037          * page table entry that would otherwise have been filled with
0038          * the zero page. Skip the equivalent tag dump which would
0039          * have been all zeros.
0040          */
0041         if (!page) {
0042             dump_skip(cprm, MTE_PAGE_TAG_STORAGE);
0043             continue;
0044         }
0045 
0046         /*
0047          * Pages mapped in user space as !pte_access_permitted() (e.g.
0048          * PROT_EXEC only) may not have the PG_mte_tagged flag set.
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 }