[PATCH v3 1/2] x86/fpu: Fix memory leak with dynamic fpstate and exec()

From: Guixiong Wei

Date: Mon Oct 26 2026 - 23:46:10 EST


Using an XFD-controlled xfeature can allocate a larger fpstate. On
exec(), fpstate_reset() replaces fpu->fpstate with the embedded buffer
without freeing the dynamic allocation. Once the pointer is overwritten,
the allocation cannot be freed on task exit.

Free dynamic state at the start of fpstate_reset(). In fpu_clone(),
clear the pointer copied from the parent before resetting the child's
state, so the parent's allocation is not freed.

Fixes: 500afbf645a0 ("x86/fpu/xstate: Add fpstate_realloc()/free()")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Guixiong Wei <weiguixiong@xxxxxxxxxxxxx>
---
arch/x86/kernel/fpu/core.c | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c
index d1aeecd57f5ed..dbe6696fdf8cf 100644
--- a/arch/x86/kernel/fpu/core.c
+++ b/arch/x86/kernel/fpu/core.c
@@ -594,6 +594,9 @@ static void __fpstate_reset(struct fpstate *fpstate)

void fpstate_reset(struct fpu *fpu)
{
+ /* Free dynamic fpstate (if any) before resetting pointer: */
+ fpstate_free(fpu);
+
/* Set the fpstate pointer to the default fpstate */
fpu->fpstate = &fpu->__fpstate;
__fpstate_reset(fpu->fpstate);
@@ -670,6 +673,8 @@ int fpu_clone(struct task_struct *dst, u64 clone_flags, bool minimal,
/* The new task's FPU state cannot be valid in the hardware. */
dst_fpu->last_cpu = -1;

+ /* Break the link to the other FPU's fpstate: */
+ dst_fpu->fpstate = NULL;
fpstate_reset(dst_fpu);

if (!cpu_feature_enabled(X86_FEATURE_FPU))
--
2.55.0