Skip to content

Commit 8c94db0

Browse files
psi-sckees
authored andcommitted
binfmt_elf: preserve original ELF e_flags for core dumps
Some architectures, such as RISC-V, use the ELF e_flags field to encode ABI-specific information (e.g., ISA extensions, fpu support). Debuggers like GDB rely on these flags in core dumps to correctly interpret optional register sets. If the flags are missing or incorrect, GDB may warn and ignore valid data, for example: warning: Unexpected size of section '.reg2/213' in core file. This can prevent access to fpu or other architecture-specific registers even when they were dumped. Save the e_flags field during ELF binary loading (in load_elf_binary()) into the mm_struct, and later retrieve it during core dump generation (in fill_note_info()). Kconfig option CONFIG_ARCH_HAS_ELF_CORE_EFLAGS is introduced for architectures that require this behaviour. Signed-off-by: Svetlana Parfenova <svetlana.parfenova@syntacore.com> Link: https://lore.kernel.org/r/20250901135350.619485-1-svetlana.parfenova@syntacore.com Signed-off-by: Kees Cook <kees@kernel.org>
1 parent a728ce8 commit 8c94db0

4 files changed

Lines changed: 49 additions & 6 deletions

File tree

arch/riscv/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ config RISCV
2828
select ARCH_HAS_DEBUG_VIRTUAL if MMU
2929
select ARCH_HAS_DEBUG_VM_PGTABLE
3030
select ARCH_HAS_DEBUG_WX
31+
select ARCH_HAS_ELF_CORE_EFLAGS
3132
select ARCH_HAS_FAST_MULTIPLIER
3233
select ARCH_HAS_FORTIFY_SOURCE
3334
select ARCH_HAS_GCOV_PROFILE_ALL

fs/Kconfig.binfmt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,4 +184,13 @@ config EXEC_KUNIT_TEST
184184
This builds the exec KUnit tests, which tests boundary conditions
185185
of various aspects of the exec internals.
186186

187+
config ARCH_HAS_ELF_CORE_EFLAGS
188+
bool
189+
depends on BINFMT_ELF && ELF_CORE
190+
default n
191+
help
192+
Select this option if the architecture makes use of the e_flags
193+
field in the ELF header to store ABI or other architecture-specific
194+
information that should be preserved in core dumps.
195+
187196
endmenu

fs/binfmt_elf.c

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,21 @@ static struct linux_binfmt elf_format = {
103103

104104
#define BAD_ADDR(x) (unlikely((unsigned long)(x) >= TASK_SIZE))
105105

106+
static inline void elf_coredump_set_mm_eflags(struct mm_struct *mm, u32 flags)
107+
{
108+
#ifdef CONFIG_ARCH_HAS_ELF_CORE_EFLAGS
109+
mm->saved_e_flags = flags;
110+
#endif
111+
}
112+
113+
static inline u32 elf_coredump_get_mm_eflags(struct mm_struct *mm, u32 flags)
114+
{
115+
#ifdef CONFIG_ARCH_HAS_ELF_CORE_EFLAGS
116+
flags = mm->saved_e_flags;
117+
#endif
118+
return flags;
119+
}
120+
106121
/*
107122
* We need to explicitly zero any trailing portion of the page that follows
108123
* p_filesz when it ends before the page ends (e.g. bss), otherwise this
@@ -1290,6 +1305,8 @@ static int load_elf_binary(struct linux_binprm *bprm)
12901305
mm->end_data = end_data;
12911306
mm->start_stack = bprm->p;
12921307

1308+
elf_coredump_set_mm_eflags(mm, elf_ex->e_flags);
1309+
12931310
/**
12941311
* DOC: "brk" handling
12951312
*
@@ -1804,6 +1821,8 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
18041821
struct elf_thread_core_info *t;
18051822
struct elf_prpsinfo *psinfo;
18061823
struct core_thread *ct;
1824+
u16 machine;
1825+
u32 flags;
18071826

18081827
psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL);
18091828
if (!psinfo)
@@ -1831,17 +1850,26 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
18311850
return 0;
18321851
}
18331852

1834-
/*
1835-
* Initialize the ELF file header.
1836-
*/
1837-
fill_elf_header(elf, phdrs,
1838-
view->e_machine, view->e_flags);
1853+
machine = view->e_machine;
1854+
flags = view->e_flags;
18391855
#else
18401856
view = NULL;
18411857
info->thread_notes = 2;
1842-
fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS);
1858+
machine = ELF_ARCH;
1859+
flags = ELF_CORE_EFLAGS;
18431860
#endif
18441861

1862+
/*
1863+
* Override ELF e_flags with value taken from process,
1864+
* if arch needs that.
1865+
*/
1866+
flags = elf_coredump_get_mm_eflags(dump_task->mm, flags);
1867+
1868+
/*
1869+
* Initialize the ELF file header.
1870+
*/
1871+
fill_elf_header(elf, phdrs, machine, flags);
1872+
18451873
/*
18461874
* Allocate a structure for each thread.
18471875
*/

include/linux/mm_types.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,6 +1102,11 @@ struct mm_struct {
11021102

11031103
unsigned long saved_auxv[AT_VECTOR_SIZE]; /* for /proc/PID/auxv */
11041104

1105+
#ifdef CONFIG_ARCH_HAS_ELF_CORE_EFLAGS
1106+
/* the ABI-related flags from the ELF header. Used for core dump */
1107+
unsigned long saved_e_flags;
1108+
#endif
1109+
11051110
struct percpu_counter rss_stat[NR_MM_COUNTERS];
11061111

11071112
struct linux_binfmt *binfmt;

0 commit comments

Comments
 (0)