linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC RESEND] binfmt_elf: preserve original ELF e_flags in core dumps
@ 2025-08-06 16:18 Svetlana Parfenova
  2025-08-06 18:57 ` Kees Cook
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Svetlana Parfenova @ 2025-08-06 16:18 UTC (permalink / raw)
  To: linux-fsdevel, linux-mm, linux-kernel
  Cc: viro, brauner, jack, kees, akpm, david, lorenzo.stoakes,
	Liam.Howlett, vbabka, rppt, surenb, mhocko, svetlana.parfenova

Preserve the original ELF e_flags from the executable in the core dump
header instead of relying on compile-time defaults (ELF_CORE_EFLAGS or
value from the regset view). This ensures that ABI-specific flags in
the dump file match the actual binary being executed.

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()). Use this saved value to populate the e_flags in
the core dump ELF header.

Add a new Kconfig option, CONFIG_CORE_DUMP_USE_PROCESS_EFLAGS, to guard
this behavior. Although motivated by a RISC-V use case, the mechanism is
generic and can be applied to all architectures.

This change is needed to resolve a debugging issue encountered when
analyzing core dumps with GDB for RISC-V systems. GDB inspects the
e_flags field to determine whether optional register sets such as the
floating-point unit are supported. Without correct flags, GDB may warn
and ignore valid register data:

    warning: Unexpected size of section '.reg2/213' in core file.

As a result, floating-point registers are not accessible in the debugger,
even though they were dumped. Preserving the original e_flags enables
GDB and other tools to properly interpret the dump contents.

Signed-off-by: Svetlana Parfenova <svetlana.parfenova@syntacore.com>
---
 fs/Kconfig.binfmt        |  9 +++++++++
 fs/binfmt_elf.c          | 26 ++++++++++++++++++++------
 include/linux/mm_types.h |  5 +++++
 3 files changed, 34 insertions(+), 6 deletions(-)

diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt
index bd2f530e5740..45bed2041542 100644
--- a/fs/Kconfig.binfmt
+++ b/fs/Kconfig.binfmt
@@ -184,4 +184,13 @@ config EXEC_KUNIT_TEST
 	  This builds the exec KUnit tests, which tests boundary conditions
 	  of various aspects of the exec internals.
 
+config CORE_DUMP_USE_PROCESS_EFLAGS
+	bool "Preserve ELF e_flags from executable in core dumps"
+	depends on BINFMT_ELF && ELF_CORE && RISCV
+	default n
+	help
+	  Save the ELF e_flags from the process executable at load time
+	  and use it in the core dump header. This ensures the dump reflects
+	  the original binary ABI.
+
 endmenu
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index caeddccaa1fe..e5e06e11f9fc 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -1290,6 +1290,11 @@ static int load_elf_binary(struct linux_binprm *bprm)
 	mm->end_data = end_data;
 	mm->start_stack = bprm->p;
 
+#ifdef CONFIG_CORE_DUMP_USE_PROCESS_EFLAGS
+	/* stash e_flags for use in core dumps */
+	mm->saved_e_flags = elf_ex->e_flags;
+#endif
+
 	/**
 	 * DOC: "brk" handling
 	 *
@@ -1804,6 +1809,8 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
 	struct elf_thread_core_info *t;
 	struct elf_prpsinfo *psinfo;
 	struct core_thread *ct;
+	u16 machine;
+	u32 flags;
 
 	psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL);
 	if (!psinfo)
@@ -1831,17 +1838,24 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
 		return 0;
 	}
 
-	/*
-	 * Initialize the ELF file header.
-	 */
-	fill_elf_header(elf, phdrs,
-			view->e_machine, view->e_flags);
+	machine = view->e_machine;
+	flags = view->e_flags;
 #else
 	view = NULL;
 	info->thread_notes = 2;
-	fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS);
+	machine = ELF_ARCH;
+	flags = ELF_CORE_EFLAGS;
 #endif
 
+#ifdef CONFIG_CORE_DUMP_USE_PROCESS_EFLAGS
+	flags = dump_task->mm->saved_e_flags;
+#endif
+
+	/*
+	 * Initialize the ELF file header.
+	 */
+	fill_elf_header(elf, phdrs, machine, flags);
+
 	/*
 	 * Allocate a structure for each thread.
 	 */
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index d6b91e8a66d6..39921b32e4f5 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -1098,6 +1098,11 @@ struct mm_struct {
 
 		unsigned long saved_auxv[AT_VECTOR_SIZE]; /* for /proc/PID/auxv */
 
+#ifdef CONFIG_CORE_DUMP_USE_PROCESS_EFLAGS
+		/* the ABI-related flags from the ELF header. Used for core dump */
+		unsigned long saved_e_flags;
+#endif
+
 		struct percpu_counter rss_stat[NR_MM_COUNTERS];
 
 		struct linux_binfmt *binfmt;
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [RFC RESEND] binfmt_elf: preserve original ELF e_flags in core dumps
  2025-08-06 16:18 [RFC RESEND] binfmt_elf: preserve original ELF e_flags in core dumps Svetlana Parfenova
@ 2025-08-06 18:57 ` Kees Cook
  2025-08-07 13:13   ` Svetlana Parfenova
  2025-08-11  9:53 ` [RFC RESEND v2] binfmt_elf: preserve original ELF e_flags for " Svetlana Parfenova
  2025-09-01 13:53 ` [RFC RESEND v3] " Svetlana Parfenova
  2 siblings, 1 reply; 10+ messages in thread
From: Kees Cook @ 2025-08-06 18:57 UTC (permalink / raw)
  To: Svetlana Parfenova
  Cc: linux-fsdevel, linux-mm, linux-kernel, viro, brauner, jack, akpm,
	david, lorenzo.stoakes, Liam.Howlett, vbabka, rppt, surenb,
	mhocko

On Wed, Aug 06, 2025 at 10:18:14PM +0600, Svetlana Parfenova wrote:
> Preserve the original ELF e_flags from the executable in the core dump
> header instead of relying on compile-time defaults (ELF_CORE_EFLAGS or
> value from the regset view). This ensures that ABI-specific flags in
> the dump file match the actual binary being executed.
> 
> 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()). Use this saved value to populate the e_flags in
> the core dump ELF header.
> 
> Add a new Kconfig option, CONFIG_CORE_DUMP_USE_PROCESS_EFLAGS, to guard
> this behavior. Although motivated by a RISC-V use case, the mechanism is
> generic and can be applied to all architectures.

In the general case, is e_flags mismatched? i.e. why hide this behind a
Kconfig? Put another way, if I enabled this Kconfig and dumped core from
some regular x86_64 process, will e_flags be different?

> This change is needed to resolve a debugging issue encountered when
> analyzing core dumps with GDB for RISC-V systems. GDB inspects the
> e_flags field to determine whether optional register sets such as the
> floating-point unit are supported. Without correct flags, GDB may warn
> and ignore valid register data:
> 
>     warning: Unexpected size of section '.reg2/213' in core file.
> 
> As a result, floating-point registers are not accessible in the debugger,
> even though they were dumped. Preserving the original e_flags enables
> GDB and other tools to properly interpret the dump contents.
> 
> Signed-off-by: Svetlana Parfenova <svetlana.parfenova@syntacore.com>
> ---
>  fs/Kconfig.binfmt        |  9 +++++++++
>  fs/binfmt_elf.c          | 26 ++++++++++++++++++++------
>  include/linux/mm_types.h |  5 +++++
>  3 files changed, 34 insertions(+), 6 deletions(-)
> 
> diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt
> index bd2f530e5740..45bed2041542 100644
> --- a/fs/Kconfig.binfmt
> +++ b/fs/Kconfig.binfmt
> @@ -184,4 +184,13 @@ config EXEC_KUNIT_TEST
>  	  This builds the exec KUnit tests, which tests boundary conditions
>  	  of various aspects of the exec internals.
>  
> +config CORE_DUMP_USE_PROCESS_EFLAGS
> +	bool "Preserve ELF e_flags from executable in core dumps"
> +	depends on BINFMT_ELF && ELF_CORE && RISCV
> +	default n
> +	help
> +	  Save the ELF e_flags from the process executable at load time
> +	  and use it in the core dump header. This ensures the dump reflects
> +	  the original binary ABI.
> +
>  endmenu
> diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
> index caeddccaa1fe..e5e06e11f9fc 100644
> --- a/fs/binfmt_elf.c
> +++ b/fs/binfmt_elf.c
> @@ -1290,6 +1290,11 @@ static int load_elf_binary(struct linux_binprm *bprm)
>  	mm->end_data = end_data;
>  	mm->start_stack = bprm->p;
>  
> +#ifdef CONFIG_CORE_DUMP_USE_PROCESS_EFLAGS
> +	/* stash e_flags for use in core dumps */
> +	mm->saved_e_flags = elf_ex->e_flags;
> +#endif

Is this structure actually lost during ELF load? I thought we preserved
some more of the ELF headers during load...

> +
>  	/**
>  	 * DOC: "brk" handling
>  	 *
> @@ -1804,6 +1809,8 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
>  	struct elf_thread_core_info *t;
>  	struct elf_prpsinfo *psinfo;
>  	struct core_thread *ct;
> +	u16 machine;
> +	u32 flags;
>  
>  	psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL);
>  	if (!psinfo)
> @@ -1831,17 +1838,24 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
>  		return 0;
>  	}
>  
> -	/*
> -	 * Initialize the ELF file header.
> -	 */
> -	fill_elf_header(elf, phdrs,
> -			view->e_machine, view->e_flags);
> +	machine = view->e_machine;
> +	flags = view->e_flags;
>  #else
>  	view = NULL;
>  	info->thread_notes = 2;
> -	fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS);
> +	machine = ELF_ARCH;
> +	flags = ELF_CORE_EFLAGS;
>  #endif
>  
> +#ifdef CONFIG_CORE_DUMP_USE_PROCESS_EFLAGS
> +	flags = dump_task->mm->saved_e_flags;
> +#endif

This appears to clobber the value from view->e_flags. Is that right? It
feels like this change should only be needed in the default
ELF_CORE_EFLAGS case. How is view->e_flags normally set?

> +
> +	/*
> +	 * Initialize the ELF file header.
> +	 */
> +	fill_elf_header(elf, phdrs, machine, flags);
> +
>  	/*
>  	 * Allocate a structure for each thread.
>  	 */
> diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
> index d6b91e8a66d6..39921b32e4f5 100644
> --- a/include/linux/mm_types.h
> +++ b/include/linux/mm_types.h
> @@ -1098,6 +1098,11 @@ struct mm_struct {
>  
>  		unsigned long saved_auxv[AT_VECTOR_SIZE]; /* for /proc/PID/auxv */
>  
> +#ifdef CONFIG_CORE_DUMP_USE_PROCESS_EFLAGS
> +		/* the ABI-related flags from the ELF header. Used for core dump */
> +		unsigned long saved_e_flags;
> +#endif
> +
>  		struct percpu_counter rss_stat[NR_MM_COUNTERS];
>  
>  		struct linux_binfmt *binfmt;
> -- 
> 2.50.1
> 

-Kees

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC RESEND] binfmt_elf: preserve original ELF e_flags in core dumps
  2025-08-06 18:57 ` Kees Cook
@ 2025-08-07 13:13   ` Svetlana Parfenova
  2025-08-07 21:14     ` Kees Cook
  0 siblings, 1 reply; 10+ messages in thread
From: Svetlana Parfenova @ 2025-08-07 13:13 UTC (permalink / raw)
  To: Kees Cook
  Cc: linux-fsdevel, linux-mm, linux-kernel, viro, brauner, jack, akpm,
	david, lorenzo.stoakes, Liam.Howlett, vbabka, rppt, surenb,
	mhocko

On 07/08/2025 00.57, Kees Cook wrote:
> On Wed, Aug 06, 2025 at 10:18:14PM +0600, Svetlana Parfenova wrote:
>> Preserve the original ELF e_flags from the executable in the core dump
>> header instead of relying on compile-time defaults (ELF_CORE_EFLAGS or
>> value from the regset view). This ensures that ABI-specific flags in
>> the dump file match the actual binary being executed.
>>
>> 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()). Use this saved value to populate the e_flags in
>> the core dump ELF header.
>>
>> Add a new Kconfig option, CONFIG_CORE_DUMP_USE_PROCESS_EFLAGS, to guard
>> this behavior. Although motivated by a RISC-V use case, the mechanism is
>> generic and can be applied to all architectures.
> 
> In the general case, is e_flags mismatched? i.e. why hide this behind a
> Kconfig? Put another way, if I enabled this Kconfig and dumped core from
> some regular x86_64 process, will e_flags be different?
> 

The Kconfig option is currently restricted to the RISC-V architecture 
because it's not clear to me whether other architectures need actual 
e_flags value from ELF header. If this option is disabled, the core dump 
will always use a compile time value for e_flags, regardless of which 
method is selected: ELF_CORE_EFLAGS or CORE_DUMP_USE_REGSET. And this 
constant does not necessarily reflect the actual e_flags of the running 
process (at least on RISC-V), which can vary depending on how the binary 
was compiled. Thus, I made a third method to obtain e_flags that 
reflects the real value. And it is gated behind a Kconfig option, as not 
all users may need it.

>> This change is needed to resolve a debugging issue encountered when
>> analyzing core dumps with GDB for RISC-V systems. GDB inspects the
>> e_flags field to determine whether optional register sets such as the
>> floating-point unit are supported. Without correct flags, GDB may warn
>> and ignore valid register data:
>>
>>      warning: Unexpected size of section '.reg2/213' in core file.
>>
>> As a result, floating-point registers are not accessible in the debugger,
>> even though they were dumped. Preserving the original e_flags enables
>> GDB and other tools to properly interpret the dump contents.
>>
>> Signed-off-by: Svetlana Parfenova <svetlana.parfenova@syntacore.com>
>> ---
>>   fs/Kconfig.binfmt        |  9 +++++++++
>>   fs/binfmt_elf.c          | 26 ++++++++++++++++++++------
>>   include/linux/mm_types.h |  5 +++++
>>   3 files changed, 34 insertions(+), 6 deletions(-)
>>
>> diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt
>> index bd2f530e5740..45bed2041542 100644
>> --- a/fs/Kconfig.binfmt
>> +++ b/fs/Kconfig.binfmt
>> @@ -184,4 +184,13 @@ config EXEC_KUNIT_TEST
>>   	  This builds the exec KUnit tests, which tests boundary conditions
>>   	  of various aspects of the exec internals.
>>   
>> +config CORE_DUMP_USE_PROCESS_EFLAGS
>> +	bool "Preserve ELF e_flags from executable in core dumps"
>> +	depends on BINFMT_ELF && ELF_CORE && RISCV
>> +	default n
>> +	help
>> +	  Save the ELF e_flags from the process executable at load time
>> +	  and use it in the core dump header. This ensures the dump reflects
>> +	  the original binary ABI.
>> +
>>   endmenu
>> diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
>> index caeddccaa1fe..e5e06e11f9fc 100644
>> --- a/fs/binfmt_elf.c
>> +++ b/fs/binfmt_elf.c
>> @@ -1290,6 +1290,11 @@ static int load_elf_binary(struct linux_binprm *bprm)
>>   	mm->end_data = end_data;
>>   	mm->start_stack = bprm->p;
>>   
>> +#ifdef CONFIG_CORE_DUMP_USE_PROCESS_EFLAGS
>> +	/* stash e_flags for use in core dumps */
>> +	mm->saved_e_flags = elf_ex->e_flags;
>> +#endif
> 
> Is this structure actually lost during ELF load? I thought we preserved
> some more of the ELF headers during load...
> 

As far as I can tell, the ELF header itself is not preserved beyond 
loading. If there's a mechanism I'm missing that saves it, please let me 
know.

>> +
>>   	/**
>>   	 * DOC: "brk" handling
>>   	 *
>> @@ -1804,6 +1809,8 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
>>   	struct elf_thread_core_info *t;
>>   	struct elf_prpsinfo *psinfo;
>>   	struct core_thread *ct;
>> +	u16 machine;
>> +	u32 flags;
>>   
>>   	psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL);
>>   	if (!psinfo)
>> @@ -1831,17 +1838,24 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
>>   		return 0;
>>   	}
>>   
>> -	/*
>> -	 * Initialize the ELF file header.
>> -	 */
>> -	fill_elf_header(elf, phdrs,
>> -			view->e_machine, view->e_flags);
>> +	machine = view->e_machine;
>> +	flags = view->e_flags;
>>   #else
>>   	view = NULL;
>>   	info->thread_notes = 2;
>> -	fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS);
>> +	machine = ELF_ARCH;
>> +	flags = ELF_CORE_EFLAGS;
>>   #endif
>>   
>> +#ifdef CONFIG_CORE_DUMP_USE_PROCESS_EFLAGS
>> +	flags = dump_task->mm->saved_e_flags;
>> +#endif
> 
> This appears to clobber the value from view->e_flags. Is that right? It
> feels like this change should only be needed in the default
> ELF_CORE_EFLAGS case. How is view->e_flags normally set?
> 

view->e_flags is set at compile time, and view is pointing to const 
struct. The override of e_flags is intentional in both cases 
(ELF_CORE_EFLAGS and CORE_DUMP_USE_REGSET) to allow access to the 
process actual e_flags, regardless of the selected method.

>> +
>> +	/*
>> +	 * Initialize the ELF file header.
>> +	 */
>> +	fill_elf_header(elf, phdrs, machine, flags);
>> +
>>   	/*
>>   	 * Allocate a structure for each thread.
>>   	 */
>> diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
>> index d6b91e8a66d6..39921b32e4f5 100644
>> --- a/include/linux/mm_types.h
>> +++ b/include/linux/mm_types.h
>> @@ -1098,6 +1098,11 @@ struct mm_struct {
>>   
>>   		unsigned long saved_auxv[AT_VECTOR_SIZE]; /* for /proc/PID/auxv */
>>   
>> +#ifdef CONFIG_CORE_DUMP_USE_PROCESS_EFLAGS
>> +		/* the ABI-related flags from the ELF header. Used for core dump */
>> +		unsigned long saved_e_flags;
>> +#endif
>> +
>>   		struct percpu_counter rss_stat[NR_MM_COUNTERS];
>>   
>>   		struct linux_binfmt *binfmt;
>> -- 
>> 2.50.1
>>
> 
> -Kees
> 


-- 
Best regards,
Svetlana Parfenova

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC RESEND] binfmt_elf: preserve original ELF e_flags in core dumps
  2025-08-07 13:13   ` Svetlana Parfenova
@ 2025-08-07 21:14     ` Kees Cook
  2025-08-08 15:54       ` Svetlana Parfenova
  0 siblings, 1 reply; 10+ messages in thread
From: Kees Cook @ 2025-08-07 21:14 UTC (permalink / raw)
  To: Svetlana Parfenova
  Cc: linux-fsdevel, linux-mm, linux-kernel, viro, brauner, jack, akpm,
	david, lorenzo.stoakes, Liam.Howlett, vbabka, rppt, surenb,
	mhocko

On Thu, Aug 07, 2025 at 07:13:50PM +0600, Svetlana Parfenova wrote:
> On 07/08/2025 00.57, Kees Cook wrote:
> > On Wed, Aug 06, 2025 at 10:18:14PM +0600, Svetlana Parfenova wrote:
> > > Preserve the original ELF e_flags from the executable in the core dump
> > > header instead of relying on compile-time defaults (ELF_CORE_EFLAGS or
> > > value from the regset view). This ensures that ABI-specific flags in
> > > the dump file match the actual binary being executed.
> > > 
> > > 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()). Use this saved value to populate the e_flags in
> > > the core dump ELF header.
> > > 
> > > Add a new Kconfig option, CONFIG_CORE_DUMP_USE_PROCESS_EFLAGS, to guard
> > > this behavior. Although motivated by a RISC-V use case, the mechanism is
> > > generic and can be applied to all architectures.
> > 
> > In the general case, is e_flags mismatched? i.e. why hide this behind a
> > Kconfig? Put another way, if I enabled this Kconfig and dumped core from
> > some regular x86_64 process, will e_flags be different?
> > 
> 
> The Kconfig option is currently restricted to the RISC-V architecture
> because it's not clear to me whether other architectures need actual e_flags
> value from ELF header. If this option is disabled, the core dump will always
> use a compile time value for e_flags, regardless of which method is
> selected: ELF_CORE_EFLAGS or CORE_DUMP_USE_REGSET. And this constant does
> not necessarily reflect the actual e_flags of the running process (at least
> on RISC-V), which can vary depending on how the binary was compiled. Thus, I
> made a third method to obtain e_flags that reflects the real value. And it
> is gated behind a Kconfig option, as not all users may need it.

Can you check if the ELF e_flags and the hard-coded e_flags actually
differ on other architectures? I'd rather avoid using the Kconfig so we
can have a common execution path for all architectures.

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC RESEND] binfmt_elf: preserve original ELF e_flags in core dumps
  2025-08-07 21:14     ` Kees Cook
@ 2025-08-08 15:54       ` Svetlana Parfenova
  2025-08-08 21:54         ` Kees Cook
  0 siblings, 1 reply; 10+ messages in thread
From: Svetlana Parfenova @ 2025-08-08 15:54 UTC (permalink / raw)
  To: Kees Cook
  Cc: linux-fsdevel, linux-mm, linux-kernel, viro, brauner, jack, akpm,
	david, lorenzo.stoakes, Liam.Howlett, vbabka, rppt, surenb,
	mhocko

On 08/08/2025 03.14, Kees Cook wrote:
> On Thu, Aug 07, 2025 at 07:13:50PM +0600, Svetlana Parfenova wrote:
>> On 07/08/2025 00.57, Kees Cook wrote:
>>> On Wed, Aug 06, 2025 at 10:18:14PM +0600, Svetlana Parfenova
>>> wrote:
>>>> Preserve the original ELF e_flags from the executable in the
>>>> core dump header instead of relying on compile-time defaults
>>>> (ELF_CORE_EFLAGS or value from the regset view). This ensures
>>>> that ABI-specific flags in the dump file match the actual
>>>> binary being executed.
>>>> 
>>>> 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()). Use this
>>>> saved value to populate the e_flags in the core dump ELF
>>>> header.
>>>> 
>>>> Add a new Kconfig option, CONFIG_CORE_DUMP_USE_PROCESS_EFLAGS,
>>>> to guard this behavior. Although motivated by a RISC-V use
>>>> case, the mechanism is generic and can be applied to all
>>>> architectures.
>>> 
>>> In the general case, is e_flags mismatched? i.e. why hide this
>>> behind a Kconfig? Put another way, if I enabled this Kconfig and
>>> dumped core from some regular x86_64 process, will e_flags be
>>> different?
>>> 
>> 
>> The Kconfig option is currently restricted to the RISC-V
>> architecture because it's not clear to me whether other
>> architectures need actual e_flags value from ELF header. If this
>> option is disabled, the core dump will always use a compile time
>> value for e_flags, regardless of which method is selected:
>> ELF_CORE_EFLAGS or CORE_DUMP_USE_REGSET. And this constant does 
>> not necessarily reflect the actual e_flags of the running process
>> (at least on RISC-V), which can vary depending on how the binary
>> was compiled. Thus, I made a third method to obtain e_flags that
>> reflects the real value. And it is gated behind a Kconfig option,
>> as not all users may need it.
> 
> Can you check if the ELF e_flags and the hard-coded e_flags actually 
> differ on other architectures? I'd rather avoid using the Kconfig so
> we can have a common execution path for all architectures.
> 

I checked various architectures, and most don’t use e_flags in core
dumps - just zero value. For x86 this is valid since it doesn’t define
values for e_flags. However, architectures like ARM do have meaningful
e_flags, yet still they are set to zero in core dumps. I guess the real
question isn't about core dump correctness, but whether tools like GDB
actually rely on e_flags to provide debug information. Seems like most
architectures either don’t use it or can operate without it. RISC-V
looks like black sheep here ... GDB relies on e_flags to determine the
ABI and interpret the core dump correctly.

What if I rework my patch the following way:
- remove Kconfig option;
- add function/macro that would override e_flags with value taken from
process, but it would only be applied if architecture specifies that.

Would that be a better approach?

-- 
Best regards,
Svetlana Parfenova

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC RESEND] binfmt_elf: preserve original ELF e_flags in core dumps
  2025-08-08 15:54       ` Svetlana Parfenova
@ 2025-08-08 21:54         ` Kees Cook
  0 siblings, 0 replies; 10+ messages in thread
From: Kees Cook @ 2025-08-08 21:54 UTC (permalink / raw)
  To: Svetlana Parfenova
  Cc: linux-fsdevel, linux-mm, linux-kernel, viro, brauner, jack, akpm,
	david, lorenzo.stoakes, Liam.Howlett, vbabka, rppt, surenb,
	mhocko



On August 8, 2025 8:54:30 AM PDT, Svetlana Parfenova <svetlana.parfenova@syntacore.com> wrote:
>On 08/08/2025 03.14, Kees Cook wrote:
>> On Thu, Aug 07, 2025 at 07:13:50PM +0600, Svetlana Parfenova wrote:
>>> On 07/08/2025 00.57, Kees Cook wrote:
>>>> On Wed, Aug 06, 2025 at 10:18:14PM +0600, Svetlana Parfenova
>>>> wrote:
>>>>> Preserve the original ELF e_flags from the executable in the
>>>>> core dump header instead of relying on compile-time defaults
>>>>> (ELF_CORE_EFLAGS or value from the regset view). This ensures
>>>>> that ABI-specific flags in the dump file match the actual
>>>>> binary being executed.
>>>>> 
>>>>> 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()). Use this
>>>>> saved value to populate the e_flags in the core dump ELF
>>>>> header.
>>>>> 
>>>>> Add a new Kconfig option, CONFIG_CORE_DUMP_USE_PROCESS_EFLAGS,
>>>>> to guard this behavior. Although motivated by a RISC-V use
>>>>> case, the mechanism is generic and can be applied to all
>>>>> architectures.
>>>> 
>>>> In the general case, is e_flags mismatched? i.e. why hide this
>>>> behind a Kconfig? Put another way, if I enabled this Kconfig and
>>>> dumped core from some regular x86_64 process, will e_flags be
>>>> different?
>>>> 
>>> 
>>> The Kconfig option is currently restricted to the RISC-V
>>> architecture because it's not clear to me whether other
>>> architectures need actual e_flags value from ELF header. If this
>>> option is disabled, the core dump will always use a compile time
>>> value for e_flags, regardless of which method is selected:
>>> ELF_CORE_EFLAGS or CORE_DUMP_USE_REGSET. And this constant does not necessarily reflect the actual e_flags of the running process
>>> (at least on RISC-V), which can vary depending on how the binary
>>> was compiled. Thus, I made a third method to obtain e_flags that
>>> reflects the real value. And it is gated behind a Kconfig option,
>>> as not all users may need it.
>> 
>> Can you check if the ELF e_flags and the hard-coded e_flags actually differ on other architectures? I'd rather avoid using the Kconfig so
>> we can have a common execution path for all architectures.
>> 
>
>I checked various architectures, and most don’t use e_flags in core
>dumps - just zero value. For x86 this is valid since it doesn’t define
>values for e_flags. However, architectures like ARM do have meaningful
>e_flags, yet still they are set to zero in core dumps. I guess the real
>question isn't about core dump correctness, but whether tools like GDB
>actually rely on e_flags to provide debug information. Seems like most
>architectures either don’t use it or can operate without it. RISC-V
>looks like black sheep here ... GDB relies on e_flags to determine the
>ABI and interpret the core dump correctly.
>
>What if I rework my patch the following way:
>- remove Kconfig option;
>- add function/macro that would override e_flags with value taken from
>process, but it would only be applied if architecture specifies that.
>
>Would that be a better approach?

Yeah! Let's see what that looks like. :)


-- 
Kees Cook

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [RFC RESEND v2] binfmt_elf: preserve original ELF e_flags for core dumps
  2025-08-06 16:18 [RFC RESEND] binfmt_elf: preserve original ELF e_flags in core dumps Svetlana Parfenova
  2025-08-06 18:57 ` Kees Cook
@ 2025-08-11  9:53 ` Svetlana Parfenova
  2025-08-25 17:17   ` Kees Cook
  2025-09-01 13:53 ` [RFC RESEND v3] " Svetlana Parfenova
  2 siblings, 1 reply; 10+ messages in thread
From: Svetlana Parfenova @ 2025-08-11  9:53 UTC (permalink / raw)
  To: linux-fsdevel, linux-mm, linux-kernel
  Cc: viro, brauner, jack, kees, akpm, david, lorenzo.stoakes,
	Liam.Howlett, vbabka, rppt, surenb, mhocko, svetlana.parfenova

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()). A new macro ELF_CORE_USE_PROCESS_EFLAGS allows
architectures to enable this behavior - currently just RISC-V.

Signed-off-by: Svetlana Parfenova <svetlana.parfenova@syntacore.com>
---
Changes in v2:
 - Remove usage of Kconfig option.
 - Add an architecture-optional macro to set process e_flags. Enabled
   by defining ELF_CORE_USE_PROCESS_EFLAGS. Defaults to no-op if not
   used.

 arch/riscv/include/asm/elf.h |  1 +
 fs/binfmt_elf.c              | 34 ++++++++++++++++++++++++++++------
 include/linux/mm_types.h     |  3 +++
 3 files changed, 32 insertions(+), 6 deletions(-)

diff --git a/arch/riscv/include/asm/elf.h b/arch/riscv/include/asm/elf.h
index c7aea7886d22..5d9f0ac851ee 100644
--- a/arch/riscv/include/asm/elf.h
+++ b/arch/riscv/include/asm/elf.h
@@ -20,6 +20,7 @@
  * These are used to set parameters in the core dumps.
  */
 #define ELF_ARCH	EM_RISCV
+#define ELF_CORE_USE_PROCESS_EFLAGS
 
 #ifndef ELF_CLASS
 #ifdef CONFIG_64BIT
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index caeddccaa1fe..e52b1e077218 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -66,6 +66,14 @@
 #define elf_check_fdpic(ex) false
 #endif
 
+#ifdef ELF_CORE_USE_PROCESS_EFLAGS
+#define elf_coredump_get_process_eflags(dump_task, e_flags) \
+	(*(e_flags) = (dump_task)->mm->saved_e_flags)
+#else
+#define elf_coredump_get_process_eflags(dump_task, e_flags) \
+	do { (void)(dump_task); (void)(e_flags); } while (0)
+#endif
+
 static int load_elf_binary(struct linux_binprm *bprm);
 
 /*
@@ -1290,6 +1298,9 @@ static int load_elf_binary(struct linux_binprm *bprm)
 	mm->end_data = end_data;
 	mm->start_stack = bprm->p;
 
+	/* stash e_flags for use in core dumps */
+	mm->saved_e_flags = elf_ex->e_flags;
+
 	/**
 	 * DOC: "brk" handling
 	 *
@@ -1804,6 +1815,8 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
 	struct elf_thread_core_info *t;
 	struct elf_prpsinfo *psinfo;
 	struct core_thread *ct;
+	u16 machine;
+	u32 flags;
 
 	psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL);
 	if (!psinfo)
@@ -1831,17 +1844,26 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
 		return 0;
 	}
 
-	/*
-	 * Initialize the ELF file header.
-	 */
-	fill_elf_header(elf, phdrs,
-			view->e_machine, view->e_flags);
+	machine = view->e_machine;
+	flags = view->e_flags;
 #else
 	view = NULL;
 	info->thread_notes = 2;
-	fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS);
+	machine = ELF_ARCH;
+	flags = ELF_CORE_EFLAGS;
 #endif
 
+	/*
+	 * Override ELF e_flags with value taken from process,
+	 * if arch wants to.
+	 */
+	elf_coredump_get_process_eflags(dump_task, &flags);
+
+	/*
+	 * Initialize the ELF file header.
+	 */
+	fill_elf_header(elf, phdrs, machine, flags);
+
 	/*
 	 * Allocate a structure for each thread.
 	 */
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index d6b91e8a66d6..e46f554f8d91 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -1098,6 +1098,9 @@ struct mm_struct {
 
 		unsigned long saved_auxv[AT_VECTOR_SIZE]; /* for /proc/PID/auxv */
 
+		/* the ABI-related flags from the ELF header. Used for core dump */
+		unsigned long saved_e_flags;
+
 		struct percpu_counter rss_stat[NR_MM_COUNTERS];
 
 		struct linux_binfmt *binfmt;
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [RFC RESEND v2] binfmt_elf: preserve original ELF e_flags for core dumps
  2025-08-11  9:53 ` [RFC RESEND v2] binfmt_elf: preserve original ELF e_flags for " Svetlana Parfenova
@ 2025-08-25 17:17   ` Kees Cook
  2025-09-01 13:58     ` Svetlana Parfenova
  0 siblings, 1 reply; 10+ messages in thread
From: Kees Cook @ 2025-08-25 17:17 UTC (permalink / raw)
  To: Svetlana Parfenova
  Cc: linux-fsdevel, linux-mm, linux-kernel, viro, brauner, jack, akpm,
	david, lorenzo.stoakes, Liam.Howlett, vbabka, rppt, surenb,
	mhocko

On Mon, Aug 11, 2025 at 03:53:28PM +0600, Svetlana Parfenova wrote:
> 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()). A new macro ELF_CORE_USE_PROCESS_EFLAGS allows
> architectures to enable this behavior - currently just RISC-V.
> 
> Signed-off-by: Svetlana Parfenova <svetlana.parfenova@syntacore.com>
> ---
> Changes in v2:
>  - Remove usage of Kconfig option.
>  - Add an architecture-optional macro to set process e_flags. Enabled
>    by defining ELF_CORE_USE_PROCESS_EFLAGS. Defaults to no-op if not
>    used.
> 
>  arch/riscv/include/asm/elf.h |  1 +
>  fs/binfmt_elf.c              | 34 ++++++++++++++++++++++++++++------
>  include/linux/mm_types.h     |  3 +++
>  3 files changed, 32 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/riscv/include/asm/elf.h b/arch/riscv/include/asm/elf.h
> index c7aea7886d22..5d9f0ac851ee 100644
> --- a/arch/riscv/include/asm/elf.h
> +++ b/arch/riscv/include/asm/elf.h
> @@ -20,6 +20,7 @@
>   * These are used to set parameters in the core dumps.
>   */
>  #define ELF_ARCH	EM_RISCV
> +#define ELF_CORE_USE_PROCESS_EFLAGS

Let's move this to the per-arch Kconfig instead, that way we can use it
in other places. Maybe call in CONFIG_ARCH_HAS_ELF_CORE_EFLAGS?

>  
>  #ifndef ELF_CLASS
>  #ifdef CONFIG_64BIT
> diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
> index caeddccaa1fe..e52b1e077218 100644
> --- a/fs/binfmt_elf.c
> +++ b/fs/binfmt_elf.c
> @@ -66,6 +66,14 @@
>  #define elf_check_fdpic(ex) false
>  #endif
>  
> +#ifdef ELF_CORE_USE_PROCESS_EFLAGS
> +#define elf_coredump_get_process_eflags(dump_task, e_flags) \
> +	(*(e_flags) = (dump_task)->mm->saved_e_flags)
> +#else
> +#define elf_coredump_get_process_eflags(dump_task, e_flags) \
> +	do { (void)(dump_task); (void)(e_flags); } while (0)
> +#endif

Let's make specific set/get helpers here, instead.

static inline
u32 coredump_get_mm_eflags(struct mm_struct *mm, u32 flags)
{
#ifdef CONFIG_ARCH_HAS_ELF_CORE_EFLAGS
	flags = mm->saved_e_flags;
#else
	return flags;
}

static inline
void coredump_set_mm_eflags(struct mm_struct *mm, u32 flags)
{
#ifdef CONFIG_ARCH_HAS_ELF_CORE_EFLAGS
	mm->saved_e_flags = flags;
#endif
}


> +
>  static int load_elf_binary(struct linux_binprm *bprm);
>  
>  /*
> @@ -1290,6 +1298,9 @@ static int load_elf_binary(struct linux_binprm *bprm)
>  	mm->end_data = end_data;
>  	mm->start_stack = bprm->p;
>  
> +	/* stash e_flags for use in core dumps */
> +	mm->saved_e_flags = elf_ex->e_flags;

Then this is:

	coredump_set_mm_eflags(mm, elf_ex->e_flags);

> +
>  	/**
>  	 * DOC: "brk" handling
>  	 *
> @@ -1804,6 +1815,8 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
>  	struct elf_thread_core_info *t;
>  	struct elf_prpsinfo *psinfo;
>  	struct core_thread *ct;
> +	u16 machine;
> +	u32 flags;
>  
>  	psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL);
>  	if (!psinfo)
> @@ -1831,17 +1844,26 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
>  		return 0;
>  	}
>  
> -	/*
> -	 * Initialize the ELF file header.
> -	 */
> -	fill_elf_header(elf, phdrs,
> -			view->e_machine, view->e_flags);
> +	machine = view->e_machine;
> +	flags = view->e_flags;
>  #else
>  	view = NULL;
>  	info->thread_notes = 2;
> -	fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS);
> +	machine = ELF_ARCH;
> +	flags = ELF_CORE_EFLAGS;
>  #endif
>  
> +	/*
> +	 * Override ELF e_flags with value taken from process,
> +	 * if arch wants to.
> +	 */
> +	elf_coredump_get_process_eflags(dump_task, &flags);

And this is:

	flags = coredump_get_mm_eflags(dump_task->mm, flags);

> +
> +	/*
> +	 * Initialize the ELF file header.
> +	 */
> +	fill_elf_header(elf, phdrs, machine, flags);
> +
>  	/*
>  	 * Allocate a structure for each thread.
>  	 */
> diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
> index d6b91e8a66d6..e46f554f8d91 100644
> --- a/include/linux/mm_types.h
> +++ b/include/linux/mm_types.h
> @@ -1098,6 +1098,9 @@ struct mm_struct {
>  
>  		unsigned long saved_auxv[AT_VECTOR_SIZE]; /* for /proc/PID/auxv */
>  

And then add:

#ifdef CONFIG_ARCH_HAS_ELF_CORE_EFLAGS

> +		/* the ABI-related flags from the ELF header. Used for core dump */
> +		unsigned long saved_e_flags;

#endif

around this part

> +
>  		struct percpu_counter rss_stat[NR_MM_COUNTERS];
>  
>  		struct linux_binfmt *binfmt;
> -- 
> 2.50.1
> 

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [RFC RESEND v3] binfmt_elf: preserve original ELF e_flags for core dumps
  2025-08-06 16:18 [RFC RESEND] binfmt_elf: preserve original ELF e_flags in core dumps Svetlana Parfenova
  2025-08-06 18:57 ` Kees Cook
  2025-08-11  9:53 ` [RFC RESEND v2] binfmt_elf: preserve original ELF e_flags for " Svetlana Parfenova
@ 2025-09-01 13:53 ` Svetlana Parfenova
  2 siblings, 0 replies; 10+ messages in thread
From: Svetlana Parfenova @ 2025-09-01 13:53 UTC (permalink / raw)
  To: linux-fsdevel, linux-mm, linux-kernel, linux-riscv
  Cc: paul.walmsley, palmer, aou, alex, viro, brauner, jack, kees, akpm,
	david, lorenzo.stoakes, Liam.Howlett, vbabka, rppt, surenb,
	mhocko, svetlana.parfenova

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>
---
Changes in v3:
 - Introduce CONFIG_ARCH_HAS_ELF_CORE_EFLAGS Kconfig option instead of
   arch-specific ELF_CORE_USE_PROCESS_EFLAGS define.
 - Add helper functions to set/get e_flags in mm_struct.
 - Wrap saved_e_flags field of mm_struct with
   #ifdef CONFIG_ARCH_HAS_ELF_CORE_EFLAGS.

Changes in v2:
 - Remove usage of Kconfig option.
 - Add an architecture-optional macro to set process e_flags. Enabled
   by defining ELF_CORE_USE_PROCESS_EFLAGS. Defaults to no-op if not
   used.

 arch/riscv/Kconfig       |  1 +
 fs/Kconfig.binfmt        |  9 +++++++++
 fs/binfmt_elf.c          | 40 ++++++++++++++++++++++++++++++++++------
 include/linux/mm_types.h |  5 +++++
 4 files changed, 49 insertions(+), 6 deletions(-)

diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index a4b233a0659e..1bef00208bdd 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -224,6 +224,7 @@ config RISCV
 	select VDSO_GETRANDOM if HAVE_GENERIC_VDSO
 	select USER_STACKTRACE_SUPPORT
 	select ZONE_DMA32 if 64BIT
+	select ARCH_HAS_ELF_CORE_EFLAGS
 
 config RUSTC_SUPPORTS_RISCV
 	def_bool y
diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt
index bd2f530e5740..1949e25c7741 100644
--- a/fs/Kconfig.binfmt
+++ b/fs/Kconfig.binfmt
@@ -184,4 +184,13 @@ config EXEC_KUNIT_TEST
 	  This builds the exec KUnit tests, which tests boundary conditions
 	  of various aspects of the exec internals.
 
+config ARCH_HAS_ELF_CORE_EFLAGS
+	bool
+	depends on BINFMT_ELF && ELF_CORE
+	default n
+	help
+	  Select this option if the architecture makes use of the e_flags
+	  field in the ELF header to store ABI or other architecture-specific
+	  information that should be preserved in core dumps.
+
 endmenu
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 4aacf9c9cc2d..e4653bb99946 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -103,6 +103,21 @@ static struct linux_binfmt elf_format = {
 
 #define BAD_ADDR(x) (unlikely((unsigned long)(x) >= TASK_SIZE))
 
+static inline void elf_coredump_set_mm_eflags(struct mm_struct *mm, u32 flags)
+{
+#ifdef CONFIG_ARCH_HAS_ELF_CORE_EFLAGS
+	mm->saved_e_flags = flags;
+#endif
+}
+
+static inline u32 elf_coredump_get_mm_eflags(struct mm_struct *mm, u32 flags)
+{
+#ifdef CONFIG_ARCH_HAS_ELF_CORE_EFLAGS
+	flags = mm->saved_e_flags;
+#endif
+	return flags;
+}
+
 /*
  * We need to explicitly zero any trailing portion of the page that follows
  * 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)
 	mm->end_data = end_data;
 	mm->start_stack = bprm->p;
 
+	elf_coredump_set_mm_eflags(mm, elf_ex->e_flags);
+
 	/**
 	 * DOC: "brk" handling
 	 *
@@ -1804,6 +1821,8 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
 	struct elf_thread_core_info *t;
 	struct elf_prpsinfo *psinfo;
 	struct core_thread *ct;
+	u16 machine;
+	u32 flags;
 
 	psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL);
 	if (!psinfo)
@@ -1831,17 +1850,26 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
 		return 0;
 	}
 
-	/*
-	 * Initialize the ELF file header.
-	 */
-	fill_elf_header(elf, phdrs,
-			view->e_machine, view->e_flags);
+	machine = view->e_machine;
+	flags = view->e_flags;
 #else
 	view = NULL;
 	info->thread_notes = 2;
-	fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS);
+	machine = ELF_ARCH;
+	flags = ELF_CORE_EFLAGS;
 #endif
 
+	/*
+	 * Override ELF e_flags with value taken from process,
+	 * if arch needs that.
+	 */
+	flags = elf_coredump_get_mm_eflags(dump_task->mm, flags);
+
+	/*
+	 * Initialize the ELF file header.
+	 */
+	fill_elf_header(elf, phdrs, machine, flags);
+
 	/*
 	 * Allocate a structure for each thread.
 	 */
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 08bc2442db93..04a2857f12f2 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -1102,6 +1102,11 @@ struct mm_struct {
 
 		unsigned long saved_auxv[AT_VECTOR_SIZE]; /* for /proc/PID/auxv */
 
+#ifdef CONFIG_ARCH_HAS_ELF_CORE_EFLAGS
+		/* the ABI-related flags from the ELF header. Used for core dump */
+		unsigned long saved_e_flags;
+#endif
+
 		struct percpu_counter rss_stat[NR_MM_COUNTERS];
 
 		struct linux_binfmt *binfmt;
-- 
2.51.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [RFC RESEND v2] binfmt_elf: preserve original ELF e_flags for core dumps
  2025-08-25 17:17   ` Kees Cook
@ 2025-09-01 13:58     ` Svetlana Parfenova
  0 siblings, 0 replies; 10+ messages in thread
From: Svetlana Parfenova @ 2025-09-01 13:58 UTC (permalink / raw)
  To: Kees Cook
  Cc: linux-fsdevel, linux-mm, linux-kernel, viro, brauner, jack, akpm,
	david, lorenzo.stoakes, Liam.Howlett, vbabka, rppt, surenb,
	mhocko

On 26/08/2025 00.17, Kees Cook wrote:
> On Mon, Aug 11, 2025 at 03:53:28PM +0600, Svetlana Parfenova wrote:
>> 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()). A new macro ELF_CORE_USE_PROCESS_EFLAGS allows
>> architectures to enable this behavior - currently just RISC-V.
>>
>> Signed-off-by: Svetlana Parfenova <svetlana.parfenova@syntacore.com>
>> ---
>> Changes in v2:
>>   - Remove usage of Kconfig option.
>>   - Add an architecture-optional macro to set process e_flags. Enabled
>>     by defining ELF_CORE_USE_PROCESS_EFLAGS. Defaults to no-op if not
>>     used.
>>
>>   arch/riscv/include/asm/elf.h |  1 +
>>   fs/binfmt_elf.c              | 34 ++++++++++++++++++++++++++++------
>>   include/linux/mm_types.h     |  3 +++
>>   3 files changed, 32 insertions(+), 6 deletions(-)
>>
>> diff --git a/arch/riscv/include/asm/elf.h b/arch/riscv/include/asm/elf.h
>> index c7aea7886d22..5d9f0ac851ee 100644
>> --- a/arch/riscv/include/asm/elf.h
>> +++ b/arch/riscv/include/asm/elf.h
>> @@ -20,6 +20,7 @@
>>    * These are used to set parameters in the core dumps.
>>    */
>>   #define ELF_ARCH	EM_RISCV
>> +#define ELF_CORE_USE_PROCESS_EFLAGS
> 
> Let's move this to the per-arch Kconfig instead, that way we can use it
> in other places. Maybe call in CONFIG_ARCH_HAS_ELF_CORE_EFLAGS?
> 
>>   
>>   #ifndef ELF_CLASS
>>   #ifdef CONFIG_64BIT
>> diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
>> index caeddccaa1fe..e52b1e077218 100644
>> --- a/fs/binfmt_elf.c
>> +++ b/fs/binfmt_elf.c
>> @@ -66,6 +66,14 @@
>>   #define elf_check_fdpic(ex) false
>>   #endif
>>   
>> +#ifdef ELF_CORE_USE_PROCESS_EFLAGS
>> +#define elf_coredump_get_process_eflags(dump_task, e_flags) \
>> +	(*(e_flags) = (dump_task)->mm->saved_e_flags)
>> +#else
>> +#define elf_coredump_get_process_eflags(dump_task, e_flags) \
>> +	do { (void)(dump_task); (void)(e_flags); } while (0)
>> +#endif
> 
> Let's make specific set/get helpers here, instead.
> 
> static inline
> u32 coredump_get_mm_eflags(struct mm_struct *mm, u32 flags)
> {
> #ifdef CONFIG_ARCH_HAS_ELF_CORE_EFLAGS
> 	flags = mm->saved_e_flags;
> #else
> 	return flags;
> }
> 
> static inline
> void coredump_set_mm_eflags(struct mm_struct *mm, u32 flags)
> {
> #ifdef CONFIG_ARCH_HAS_ELF_CORE_EFLAGS
> 	mm->saved_e_flags = flags;
> #endif
> }
> 
> 
>> +
>>   static int load_elf_binary(struct linux_binprm *bprm);
>>   
>>   /*
>> @@ -1290,6 +1298,9 @@ static int load_elf_binary(struct linux_binprm *bprm)
>>   	mm->end_data = end_data;
>>   	mm->start_stack = bprm->p;
>>   
>> +	/* stash e_flags for use in core dumps */
>> +	mm->saved_e_flags = elf_ex->e_flags;
> 
> Then this is:
> 
> 	coredump_set_mm_eflags(mm, elf_ex->e_flags);
> 
>> +
>>   	/**
>>   	 * DOC: "brk" handling
>>   	 *
>> @@ -1804,6 +1815,8 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
>>   	struct elf_thread_core_info *t;
>>   	struct elf_prpsinfo *psinfo;
>>   	struct core_thread *ct;
>> +	u16 machine;
>> +	u32 flags;
>>   
>>   	psinfo = kmalloc(sizeof(*psinfo), GFP_KERNEL);
>>   	if (!psinfo)
>> @@ -1831,17 +1844,26 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
>>   		return 0;
>>   	}
>>   
>> -	/*
>> -	 * Initialize the ELF file header.
>> -	 */
>> -	fill_elf_header(elf, phdrs,
>> -			view->e_machine, view->e_flags);
>> +	machine = view->e_machine;
>> +	flags = view->e_flags;
>>   #else
>>   	view = NULL;
>>   	info->thread_notes = 2;
>> -	fill_elf_header(elf, phdrs, ELF_ARCH, ELF_CORE_EFLAGS);
>> +	machine = ELF_ARCH;
>> +	flags = ELF_CORE_EFLAGS;
>>   #endif
>>   
>> +	/*
>> +	 * Override ELF e_flags with value taken from process,
>> +	 * if arch wants to.
>> +	 */
>> +	elf_coredump_get_process_eflags(dump_task, &flags);
> 
> And this is:
> 
> 	flags = coredump_get_mm_eflags(dump_task->mm, flags);
> 
>> +
>> +	/*
>> +	 * Initialize the ELF file header.
>> +	 */
>> +	fill_elf_header(elf, phdrs, machine, flags);
>> +
>>   	/*
>>   	 * Allocate a structure for each thread.
>>   	 */
>> diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
>> index d6b91e8a66d6..e46f554f8d91 100644
>> --- a/include/linux/mm_types.h
>> +++ b/include/linux/mm_types.h
>> @@ -1098,6 +1098,9 @@ struct mm_struct {
>>   
>>   		unsigned long saved_auxv[AT_VECTOR_SIZE]; /* for /proc/PID/auxv */
>>   
> 
> And then add:
> 
> #ifdef CONFIG_ARCH_HAS_ELF_CORE_EFLAGS
> 
>> +		/* the ABI-related flags from the ELF header. Used for core dump */
>> +		unsigned long saved_e_flags;
> 
> #endif
> 
> around this part
> 
>> +
>>   		struct percpu_counter rss_stat[NR_MM_COUNTERS];
>>   
>>   		struct linux_binfmt *binfmt;
>> -- 
>> 2.50.1
>>
> 

Thank you for review! I have addressed your comments in v3 of the patch.

-- 
Best regards,
Svetlana Parfenova

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2025-09-01 14:01 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-06 16:18 [RFC RESEND] binfmt_elf: preserve original ELF e_flags in core dumps Svetlana Parfenova
2025-08-06 18:57 ` Kees Cook
2025-08-07 13:13   ` Svetlana Parfenova
2025-08-07 21:14     ` Kees Cook
2025-08-08 15:54       ` Svetlana Parfenova
2025-08-08 21:54         ` Kees Cook
2025-08-11  9:53 ` [RFC RESEND v2] binfmt_elf: preserve original ELF e_flags for " Svetlana Parfenova
2025-08-25 17:17   ` Kees Cook
2025-09-01 13:58     ` Svetlana Parfenova
2025-09-01 13:53 ` [RFC RESEND v3] " Svetlana Parfenova

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).