2022-01-31 16:54:55 +00:00
// 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>
2022-12-22 18:12:51 +00:00
# define for_each_mte_vma(cprm, i, m) \
2022-01-31 16:54:55 +00:00
if ( system_supports_mte ( ) ) \
2022-12-22 18:12:51 +00:00
for ( i = 0 , m = cprm - > vma_meta ; \
i < cprm - > vma_count ; \
i + + , m = cprm - > vma_meta + i ) \
if ( m - > flags & VM_MTE )
2022-01-31 16:54:55 +00:00
2022-12-22 18:12:51 +00:00
static unsigned long mte_vma_tag_dump_size ( struct core_vma_metadata * m )
2022-01-31 16:54:55 +00:00
{
2022-12-22 18:12:51 +00:00
return ( m - > dump_size > > PAGE_SHIFT ) * MTE_PAGE_TAG_STORAGE ;
2022-01-31 16:54:55 +00:00
}
/* Derived from dump_user_range(); start/end must be page-aligned */
static int mte_dump_tag_range ( struct coredump_params * cprm ,
2022-12-22 18:12:51 +00:00
unsigned long start , unsigned long len )
2022-01-31 16:54:55 +00:00
{
2022-04-01 16:13:56 +01:00
int ret = 1 ;
2022-01-31 16:54:55 +00:00
unsigned long addr ;
2022-04-01 16:13:56 +01:00
void * tags = NULL ;
2022-01-31 16:54:55 +00:00
2022-12-22 18:12:51 +00:00
for ( addr = start ; addr < start + len ; addr + = PAGE_SIZE ) {
2022-01-31 16:54:55 +00:00
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 .
*/
2022-11-03 18:10:35 -07:00
if ( ! page_mte_tagged ( page ) ) {
2022-01-31 16:54:55 +00:00
put_page ( page ) ;
dump_skip ( cprm , MTE_PAGE_TAG_STORAGE ) ;
continue ;
}
2022-04-01 16:13:56 +01:00
if ( ! tags ) {
tags = mte_allocate_tag_storage ( ) ;
if ( ! tags ) {
put_page ( page ) ;
ret = 0 ;
break ;
}
}
2022-01-31 16:54:55 +00:00
mte_save_page_tags ( page_address ( page ) , tags ) ;
put_page ( page ) ;
2022-04-01 16:13:56 +01:00
if ( ! dump_emit ( cprm , tags , MTE_PAGE_TAG_STORAGE ) ) {
ret = 0 ;
break ;
}
2022-01-31 16:54:55 +00:00
}
2022-04-01 16:13:56 +01:00
if ( tags )
mte_free_tag_storage ( tags ) ;
return ret ;
2022-01-31 16:54:55 +00:00
}
2022-12-22 18:12:50 +00:00
Elf_Half elf_core_extra_phdrs ( struct coredump_params * cprm )
2022-01-31 16:54:55 +00:00
{
2022-12-22 18:12:51 +00:00
int i ;
struct core_vma_metadata * m ;
2022-01-31 16:54:55 +00:00
int vma_count = 0 ;
2022-12-22 18:12:51 +00:00
for_each_mte_vma ( cprm , i , m )
2022-01-31 16:54:55 +00:00
vma_count + + ;
return vma_count ;
}
int elf_core_write_extra_phdrs ( struct coredump_params * cprm , loff_t offset )
{
2022-12-22 18:12:51 +00:00
int i ;
struct core_vma_metadata * m ;
2022-01-31 16:54:55 +00:00
2022-12-22 18:12:51 +00:00
for_each_mte_vma ( cprm , i , m ) {
2022-01-31 16:54:55 +00:00
struct elf_phdr phdr ;
2022-04-25 16:18:33 +01:00
phdr . p_type = PT_AARCH64_MEMTAG_MTE ;
2022-01-31 16:54:55 +00:00
phdr . p_offset = offset ;
2022-12-22 18:12:51 +00:00
phdr . p_vaddr = m - > start ;
2022-01-31 16:54:55 +00:00
phdr . p_paddr = 0 ;
2022-12-22 18:12:51 +00:00
phdr . p_filesz = mte_vma_tag_dump_size ( m ) ;
phdr . p_memsz = m - > end - m - > start ;
2022-01-31 16:54:55 +00:00
offset + = phdr . p_filesz ;
phdr . p_flags = 0 ;
phdr . p_align = 0 ;
if ( ! dump_emit ( cprm , & phdr , sizeof ( phdr ) ) )
return 0 ;
}
return 1 ;
}
2022-12-22 18:12:50 +00:00
size_t elf_core_extra_data_size ( struct coredump_params * cprm )
2022-01-31 16:54:55 +00:00
{
2022-12-22 18:12:51 +00:00
int i ;
struct core_vma_metadata * m ;
2022-01-31 16:54:55 +00:00
size_t data_size = 0 ;
2022-12-22 18:12:51 +00:00
for_each_mte_vma ( cprm , i , m )
data_size + = mte_vma_tag_dump_size ( m ) ;
2022-01-31 16:54:55 +00:00
return data_size ;
}
int elf_core_write_extra_data ( struct coredump_params * cprm )
{
2022-12-22 18:12:51 +00:00
int i ;
struct core_vma_metadata * m ;
2022-01-31 16:54:55 +00:00
2022-12-22 18:12:51 +00:00
for_each_mte_vma ( cprm , i , m ) {
if ( ! mte_dump_tag_range ( cprm , m - > start , m - > dump_size ) )
2022-01-31 16:54:55 +00:00
return 0 ;
}
return 1 ;
}