From nobody Mon Sep 28 21:52:48 2026 Received: from mail-oo1-f69.google.com (mail-oo1-f69.google.com [209.85.161.69]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 561C92FDC28 for ; Mon, 17 Aug 2026 04:20:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.161.69 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786940459; cv=none; b=sYn7Cj+s+eZmRJWladO0USC7AMGkx5a0ZmQRITCLDCo1haJDHcjCLmIeU9LQXZ0dklyMYrf7h/9y4afTIqaayI0mb7dsCAUfXdOTCaZNehqlmtKfTB2cmisWOy+LmKOlYfgVmXjQ7wqoZ1fCPG/9Xz2tHGUTkofWs4zk+l05pTs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786940459; c=relaxed/simple; bh=OsoKEk7GX9Uo57cVgZPnavKrdTxXv/aAd4HR3J1jAa4=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=Xd3xBqUCJHbrS1gq4P6svSWD5jNE91AC5j+yGmdtH3vPasiYv0BAQCtUrAaN5c4tm9IvaZ+gJ1LFzLHd2nahlWHlkL2q79Rd7ffj+IWPb9tNbrtDBcQGjhvn08DMibHrvQ2sHK90lsUdfHoyot20VHQK7n0TndlwRSgJMVqEk8U= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--avagin.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=A9YUvqAx; arc=none smtp.client-ip=209.85.161.69 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--avagin.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="A9YUvqAx" Received: by mail-oo1-f69.google.com with SMTP id 006d021491bc7-6acaccb8b0cso170797eaf.0 for ; Sun, 16 Aug 2026 21:20:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1786940457; x=1787545257; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=NxGFNIIttK/Di7j6noyFdeWJnIK8feIGyqagdVJjeuU=; b=A9YUvqAxLHTeSKCqr98dFQSlXrAlyA2vhqAiPIZ0CHJJCWK2Lx6vBsP7lR6hCihWJI +gIASybpqh8y78xG6SmyGDdhywDjNDPoPc0nlRftVTxNgR+K1HQ1IZqexNIDsqyiRVq3 8p2Wdrcdt4dnfHrQsLwBnc8izdzSOlFW4Y83adaK9mMkrH/UKvD1W5oMtPXX9eiovb0L bAEZNLTmRmUMnpcmsxtblVxGPyJPR4TsyXfjwR+bzAto/N+KAQA4Kvhw3GNp5bMZtu3j fRONIcLnby1v75DQL8kc/MSUiZ7IIdSz9s29K0i+Ha9LJvmHLZ6jZNjPEBBo5NtGs9Yl J3xQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786940457; x=1787545257; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=NxGFNIIttK/Di7j6noyFdeWJnIK8feIGyqagdVJjeuU=; b=Kk17zc9jVlPRfVQ7LFZje4snOfD2qxvU/IS1dJ+zTJ/QFRyPVK+USFki/BaBPU5gXL NA0l/P8UPgsgpgiH2J2hFK0pztjJ30SlS+baInHY9RWq1X6cct/cxB7RhwNho7B+2Mbw gA6edQesw1Ggx21CFCnGKEvvJUce/mN5NiZ7ue3B69HlcYbeqmIKrCfBiTb/Xrr0qnph 7lfTzn824iYt/FEe57CDvI4WX4HxiV1+iaXCWic/OzoBlu1LYrOoggBaCKD7Eo4cdl8X 94IO0WSYwxb53dXUnZL5zbszHFdkdIdWT9uhc6NFl1S0VvdH0z7yo0J8RztbEAWc2pq0 4NZw== X-Gm-Message-State: AOJu0YzPfNQtnFI4iKIaeusc0yJeOV87J3DDS6A7IzMwocF6JPN2g+o5 CNp+7cvebQU9YQ6Hiw8QOXAhmJhe+dIxW09QUC7E+KKHw8WNKoXjy/BvuLI/goV69popGdlthbs VgPpN5g== X-Received: from iobbe8.prod.google.com ([2002:a05:6602:3788:b0:9a7:f0cb:c0ae]) (user=avagin job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6820:180c:b0:6a3:97a0:b224 with SMTP id 006d021491bc7-6b0d690c2b7mr20284657eaf.33.1786940456936; Sun, 16 Aug 2026 21:20:56 -0700 (PDT) Date: Mon, 17 Aug 2026 04:20:41 +0000 In-Reply-To: <20260817042048.1579415-1-avagin@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260817042048.1579415-1-avagin@google.com> X-Mailer: git-send-email 2.55.0.691.gc56d675ccc-goog Message-ID: <20260817042048.1579415-2-avagin@google.com> Subject: [PATCH 1/8] x86/fpu: Document signal frame portability From: Andrei Vagin To: Thomas Gleixner , Ingo Molnar , Borislav Petkov , "Chang S. Bae" Cc: linux-kernel@vger.kernel.org, criu@lists.linux.dev, Dave Hansen , x86@kernel.org, Andrei Vagin , Alexander Mikhalitsyn , "H. Peter Anvin" Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The x86 signal frame is designed to be self-describing, with the 'xstate_size' field in the software-reserved bytes indicating the actual size of the context. This design is required for portability, allowing a signal frame created on a system with a specific set of xstate features to be restored on a machine with a different (larger) set of features. Document this contract in the uapi headers and Documentation/. This requirement is critical for checkpoint/restore tools like CRIU, which should be able to migrate processes across machines with heterogeneous FPU capabilities. Note that portability is constrained by the architectural XSAVE layout (component offsets and sizes); the destination machine must share matching component layouts for all features present in the frame. While layouts are consistent across CPUs from the same vendor for active features, differences can occur across vendors or if the XSAVE space of a deprecated feature (e.g. MPX) is repurposed for a newer feature (e.g. APX). Reviewed-by: Alexander Mikhalitsyn Signed-off-by: Andrei Vagin --- Documentation/arch/x86/xstate.rst | 16 ++++++++++++++++ arch/x86/include/uapi/asm/sigcontext.h | 17 +++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/Documentation/arch/x86/xstate.rst b/Documentation/arch/x86/xst= ate.rst index cec05ac464c1..0b4d541ab6f8 100644 --- a/Documentation/arch/x86/xstate.rst +++ b/Documentation/arch/x86/xstate.rst @@ -172,3 +172,19 @@ are extended to control the guest permission: =20 Note that some VMMs may have already established a set of supported state components. These options are not presumed to support any particular VMM. + +Signal Frame Portability +------------------------ + +The signal frame is designed to be self-describing and portable. This is +especially important for checkpoint/restore tools like CRIU, which may res= tore +a process on a different host than where it was checkpointed. A signal fra= me +created on a machine with fewer CPU features can be successfully restored = on a +machine with more CPU features. + +Note that signal frame portability is constrained by the architectural XSA= VE +layout. Restoration is supported only if the destination host supports all +features present in the frame and uses matching component offsets and size= s for +them. While layout compatibility is generally maintained across CPUs from = the +same vendor, differences can occur across vendors or if the XSAVE space of= a +deprecated feature (e.g. MPX) is repurposed for a newer feature (e.g. APX). diff --git a/arch/x86/include/uapi/asm/sigcontext.h b/arch/x86/include/uapi= /asm/sigcontext.h index d0d9b331d3a1..c01f55f1fc12 100644 --- a/arch/x86/include/uapi/asm/sigcontext.h +++ b/arch/x86/include/uapi/asm/sigcontext.h @@ -34,6 +34,23 @@ * fpstate+extended_size-FP_XSTATE_MAGIC2_SIZE address) is set to * FP_XSTATE_MAGIC2 so that you can sanity check your size calculations.) * + * The xstate_size field indicates the actual size of the xstate context + * (including the 512-byte FXSAVE area and the 64-byte XSAVE header + * struct _header). This size is used in conjunction with the pointer to + * the xstate context to locate FP_XSTATE_MAGIC2. Note that in 32-bit sign= al + * frames (including 32-bit compat tasks on 64-bit kernels), the fpstate + * pointer points to a legacy 112-byte FPU environment (struct _fpstate_32) + * that precedes the xstate context, so the xstate context starts at + * fpstate + 112. This makes the signal frame self-describing and portable: + * a signal frame created on a machine with a certain set of xstate featur= es + * can be restored on a machine with a different (larger) set of features, + * as long as the destination supports all features present in the frame + * and shares matching XSAVE component offsets and sizes for those feature= s. + * Note that portability is constrained by the architectural XSAVE layout + * and is not guaranteed across different vendors or if space from + * deprecated features (e.g. MPX) is repurposed for newer features + * (e.g. APX). + * * This extended area typically grows with newer CPUs that have larger and * larger XSAVE areas. */ --=20 2.55.0.691.gc56d675ccc-goog From nobody Mon Sep 28 21:52:48 2026 Received: from mail-ot1-f72.google.com (mail-ot1-f72.google.com [209.85.210.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3ACB131195B for ; Mon, 17 Aug 2026 04:20:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786940460; cv=none; b=EPLWpzn6ZUsA3IX8N3jopT75CUonlhc08HehNoBED/rapb+ZOV4XZEmTwckluR06wa8mW3KMzwpHRd3xzQ1Tc9KmkhE72sJcQYhDBIkd8peUVNWwN2AE1uYkjMUsHDJDFilo99x/lkWGPUD47fg3e3rtMISvXsw/1FzD4QjFrkI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786940460; c=relaxed/simple; bh=IE7mt7/BFp0bgQ1LI68ONe5Jnz6OuMyNQlLoL4RhNQo=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=BUHZ7ZwdcKkErvgIrAkY7uby4b1Rgx3ax2A2uupnE18Z60Yikep+FNDwtzNaWwKFZQRg+B6ePIHJ1Mtfw2YdKJy/KCuuyFEZ82VtriCmELwxjF3kT+9Ks4GcPLTe0M9vczemZjrPaHSq1nJdLYyOGnSidRgg9idsJNHhu09UpW4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--avagin.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=Xhjb/ao1; arc=none smtp.client-ip=209.85.210.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--avagin.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="Xhjb/ao1" Received: by mail-ot1-f72.google.com with SMTP id 46e09a7af769-7e9f6a49e69so4485295a34.0 for ; Sun, 16 Aug 2026 21:20:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1786940458; x=1787545258; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=IorWRCySNO6ENC7qC+rtcq4PMoQOHo3F/0XthkTN28c=; b=Xhjb/ao17oOxjwfpW2Ym9xW6Sz/ShMXvy6d3f4In++/9zjK4+4SicU1lUWKpkr+2yx R2ey36TY/j0N3qGnx4myy0dijX39IHBcgKRlv8i0a1eTV7+yVPUi24/Z2mcqc1sqnmLa qtN3KzUu9i8xs6qLeXCZoFrWNFgCGgcAa8EzegkwGfHjaenZZzrVBLYOwNna9rQ2tloD bqaGlqSnNla6QYa1wYj2sigBKfZgk42L+H4Dm/XVcivS7KTSAu8DlCsKFbYAG8L1eX7k UF+hSDbA8mcdP4fZbVRVyBXgbeLoK59I0/Rh5Y/TTX9ozwce14+1Amh6wOQNQsie1YfA 7OSA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786940458; x=1787545258; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=IorWRCySNO6ENC7qC+rtcq4PMoQOHo3F/0XthkTN28c=; b=JbMfdQRRXXWiBGnXwGZigusU4e4BFr/TVRWWSWQHUDx6qyaXVux/XP7V7C4+nFaM9w AVtuQUxQWaNDl2q+hTr2ms0X7catzmb1vJpM+hxONMdC2RDVcFvytJFJ0/U3qaAVpGIG ypaiXna2H6dgGh8V97RW591cwqVZjfpcbgpn2FZi6eZYOdKjTPfvwW93oYYQrmHozhZv 0+zYg/gc/LkEFeuLVB7T40oyeC+iXH6dYGa7G6Ngc7a4mNYRl8xXKA0lSHaVS/WXSUBj 3uVS2qCAp79IFnWbVlPxLCHmHzNLD9tTgBapmiGsRJWQi9NJTiryqlUqG6fzvLZadC1D ILUg== X-Gm-Message-State: AOJu0YwfbD0dJvJSO9ECeV+29ngaYHmPhqLXbPdUFYI48Apt/hZI9bOA ILDYVP8tnO8iS1rIAHSJcm7QkKU7R6zl8vjluGQxPVmjUMQDbCE7FsHJhs92FaNjVjlPTaCckfI vX3cBVQ== X-Received: from ilpa3.prod.google.com ([2002:a92:c703:0:b0:509:637c:4c67]) (user=avagin job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6820:169e:b0:6aa:d13c:a709 with SMTP id 006d021491bc7-6b0d690f719mr19197580eaf.31.1786940457950; Sun, 16 Aug 2026 21:20:57 -0700 (PDT) Date: Mon, 17 Aug 2026 04:20:42 +0000 In-Reply-To: <20260817042048.1579415-1-avagin@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260817042048.1579415-1-avagin@google.com> X-Mailer: git-send-email 2.55.0.691.gc56d675ccc-goog Message-ID: <20260817042048.1579415-3-avagin@google.com> Subject: [PATCH 2/8] x86/fpu: Clean up and rename variables in signal frame handling From: Andrei Vagin To: Thomas Gleixner , Ingo Molnar , Borislav Petkov , "Chang S. Bae" Cc: linux-kernel@vger.kernel.org, criu@lists.linux.dev, Dave Hansen , x86@kernel.org, Andrei Vagin , Alexander Mikhalitsyn , "H. Peter Anvin" , Ingo Molnar Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Clean up signal frame handling code by renaming several variables for clarity and consistency, and moving masking logic closer to its usage. - Rename 'fxbuf' to 'buf_fx' in check_xstate_in_sigframe() for consistency. - Rename label 'setfx' to 'err_setfx' in check_xstate_in_sigframe() to indicate it is an error path. - In __restore_fpregs_from_user(), rename 'ufeatures' to 'task_xfeatures' and 'xrestore' to 'xrestore_mask'. - Move the masking logic 'xrestore_mask &=3D task_xfeatures' from restore_fpregs_from_user() into __restore_fpregs_from_user(). - Rename 'xrestore' to 'xrestore_mask' in restore_fpregs_from_user() to match the name in __restore_fpregs_from_user() and __fpu_restore_sig(). - In __fpu_restore_sig(), rename 'buf' to 'buf_f' to distinguish it from 'buf_fx', and 'user_xfeatures' to 'xrestore_mask'. No functional changes. Suggested-by: Ingo Molnar Reviewed-by: Alexander Mikhalitsyn Signed-off-by: Andrei Vagin --- arch/x86/kernel/fpu/signal.c | 40 ++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c index 20b638c507ca..42c3d78bd849 100644 --- a/arch/x86/kernel/fpu/signal.c +++ b/arch/x86/kernel/fpu/signal.c @@ -24,15 +24,15 @@ * Check for the presence of extended state information in the * user fpstate pointer in the sigcontext. */ -static inline bool check_xstate_in_sigframe(struct fxregs_state __user *fx= buf, +static inline bool check_xstate_in_sigframe(struct fxregs_state __user *bu= f_fx, struct _fpx_sw_bytes *fx_sw) { int min_xstate_size =3D sizeof(struct fxregs_state) + sizeof(struct xstate_header); - void __user *fpstate =3D fxbuf; + void __user *fpstate =3D buf_fx; unsigned int magic2; =20 - if (__copy_from_user(fx_sw, &fxbuf->sw_reserved[0], sizeof(*fx_sw))) + if (__copy_from_user(fx_sw, &buf_fx->sw_reserved[0], sizeof(*fx_sw))) return false; =20 /* Check for the first magic field and other error scenarios. */ @@ -40,7 +40,7 @@ static inline bool check_xstate_in_sigframe(struct fxregs= _state __user *fxbuf, fx_sw->xstate_size < min_xstate_size || fx_sw->xstate_size > x86_task_fpu(current)->fpstate->user_size || fx_sw->xstate_size > fx_sw->extended_size) - goto setfx; + goto err_setfx; =20 /* * Check for the presence of second magic word at the end of memory @@ -53,7 +53,7 @@ static inline bool check_xstate_in_sigframe(struct fxregs= _state __user *fxbuf, =20 if (likely(magic2 =3D=3D FP_XSTATE_MAGIC2)) return true; -setfx: +err_setfx: trace_x86_fpu_xstate_check_failed(x86_task_fpu(current)); =20 /* Set the parameters for fx only state */ @@ -240,15 +240,17 @@ bool copy_fpstate_to_sigframe(void __user *buf, void = __user *buf_fx, int size, u return true; } =20 -static int __restore_fpregs_from_user(void __user *buf, u64 ufeatures, - u64 xrestore, bool fx_only) +static int __restore_fpregs_from_user(void __user *buf, u64 task_xfeatures, + u64 xrestore_mask, bool fx_only) { if (use_xsave()) { - u64 init_bv =3D ufeatures & ~xrestore; + u64 init_bv =3D task_xfeatures & ~xrestore_mask; int ret; =20 + /* Restore enabled features only. */ + xrestore_mask &=3D task_xfeatures; if (likely(!fx_only)) - ret =3D xrstor_from_user_sigframe(buf, xrestore); + ret =3D xrstor_from_user_sigframe(buf, xrestore_mask); else ret =3D fxrstor_from_user_sigframe(buf); =20 @@ -266,20 +268,18 @@ static int __restore_fpregs_from_user(void __user *bu= f, u64 ufeatures, * Attempt to restore the FPU registers directly from user memory. * Pagefaults are handled and any errors returned are fatal. */ -static bool restore_fpregs_from_user(void __user *buf, u64 xrestore, bool = fx_only) +static bool restore_fpregs_from_user(void __user *buf, u64 xrestore_mask, = bool fx_only) { struct fpu *fpu =3D x86_task_fpu(current); int ret; =20 - /* Restore enabled features only. */ - xrestore &=3D fpu->fpstate->user_xfeatures; retry: fpregs_lock(); /* Ensure that XFD is up to date */ xfd_update_state(fpu->fpstate); pagefault_disable(); ret =3D __restore_fpregs_from_user(buf, fpu->fpstate->user_xfeatures, - xrestore, fx_only); + xrestore_mask, fx_only); pagefault_enable(); =20 if (unlikely(ret)) { @@ -324,7 +324,7 @@ static bool restore_fpregs_from_user(void __user *buf, = u64 xrestore, bool fx_onl return true; } =20 -static bool __fpu_restore_sig(void __user *buf, void __user *buf_fx, +static bool __fpu_restore_sig(void __user *buf_f, void __user *buf_fx, bool ia32_fxstate) { struct task_struct *tsk =3D current; @@ -332,7 +332,7 @@ static bool __fpu_restore_sig(void __user *buf, void __= user *buf_fx, struct user_i387_ia32_struct env; bool success, fx_only =3D false; union fpregs_state *fpregs; - u64 user_xfeatures =3D 0; + u64 xrestore_mask =3D 0; =20 if (use_xsave()) { struct _fpx_sw_bytes fx_sw_user; @@ -341,14 +341,14 @@ static bool __fpu_restore_sig(void __user *buf, void = __user *buf_fx, return false; =20 fx_only =3D !fx_sw_user.magic1; - user_xfeatures =3D fx_sw_user.xfeatures; + xrestore_mask =3D fx_sw_user.xfeatures; } else { - user_xfeatures =3D XFEATURE_MASK_FPSSE; + xrestore_mask =3D XFEATURE_MASK_FPSSE; } =20 if (likely(!ia32_fxstate)) { /* Restore the FPU registers directly from user memory. */ - return restore_fpregs_from_user(buf_fx, user_xfeatures, fx_only); + return restore_fpregs_from_user(buf_fx, xrestore_mask, fx_only); } =20 /* @@ -356,7 +356,7 @@ static bool __fpu_restore_sig(void __user *buf, void __= user *buf_fx, * to be ignored for histerical raisins. The legacy state is folded * in once the larger state has been copied. */ - if (__copy_from_user(&env, buf, sizeof(env))) + if (__copy_from_user(&env, buf_f, sizeof(env))) return false; =20 /* @@ -420,7 +420,7 @@ static bool __fpu_restore_sig(void __user *buf, void __= user *buf_fx, * * Preserve supervisor states! */ - u64 mask =3D user_xfeatures | xfeatures_mask_supervisor(); + u64 mask =3D xrestore_mask | xfeatures_mask_supervisor(); =20 fpregs->xsave.header.xfeatures &=3D mask; success =3D !os_xrstor_safe(fpu->fpstate, --=20 2.55.0.691.gc56d675ccc-goog From nobody Mon Sep 28 21:52:48 2026 Received: from mail-ot1-f71.google.com (mail-ot1-f71.google.com [209.85.210.71]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7E92131715F for ; Mon, 17 Aug 2026 04:21:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.71 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786940462; cv=none; b=fOilSBhF24E5GdcURn4fsrMW7QKi8XPPF79bjrU4WHmfQOOmEPojRSB4+uwoz8bbo6uB9eDHNvDFBuap7WKgNiKSP9Hhh68SI58zswUvlyh7W0iQnuwagpLFKQbDMoQZZeHFwXmBbDpH6FmbfIuE/Wt5P0bogX6W/M86gqfVstc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786940462; c=relaxed/simple; bh=Fj6O5O0OVGQEOAg5m3ZLYJrkJ3m5QZuJ2i4wisOSKW4=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=CJVBDDSLIzYduBPqRUyXEugYrsfrtYlzGw2dUS8OUXZGg/sMBUpRgP4XG+xNNR/8Ye8DJ4nnGCSY2I6p5YI9c2kch+CF1C6MEMRUT75BK7PeI0UgyPRT3ova4McEonJ74697W9HAapcahzwkhwnNL5enp7eShMkvcnjUssVdijc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--avagin.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=uaVhoYqv; arc=none smtp.client-ip=209.85.210.71 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--avagin.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="uaVhoYqv" Received: by mail-ot1-f71.google.com with SMTP id 46e09a7af769-7e9f6f0240eso3859435a34.3 for ; Sun, 16 Aug 2026 21:21:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1786940459; x=1787545259; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=sTjo6aZvyLBA/rbDobhpOJiS9o4YY4gm2eDitpUg4DA=; b=uaVhoYqvd9ddvX0lqMeWA+ucTJkN5FMXqG7hYkp6tyB5po5TcIXprvs8FeBXBs+xXn 9hj51DYrCWnq0rZDx0wFsFZC1NkKZNR7wNWddOaq0pM97HvW9/2eLTOM3ROJNmixe6C/ b96fM7XKZdeRA71RSkNK8I2ivCn0ANFLMQV2nNHePiubZEaFllzZGurnfnh2yoWar+9n HFYZfqO+lil4yRSzr8L4JFvPM+G/12IXpKBdHSG2JocLKarGPI3SrNdmroUbma83jsND +1nRsWzS4v1hE3fwUxFd8/HoJV+j0B7szjYkjGCRkXqn5ZIYp5NT6JsB+gL+dMvzwT3d 2IGA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786940459; x=1787545259; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=sTjo6aZvyLBA/rbDobhpOJiS9o4YY4gm2eDitpUg4DA=; b=cQ6PzH7smxcF9SDBJR/yxnhlSxEsPux2irLPWvtleoEPkuQGrMlLiZU+GN1csFO2zn aEdOSwN4oFlvnVcyPpUmKA4C63nFJQ+05XTh/zhllfW8HhfdjlNptdz5HantzUo4XD7g vFE7dIy8+MadxatZrHwSVAxBHc4yUg3iL+rt4oqKWMi7pxG++8HoKVXh9zSAeyjLbuO8 /7KfqnTkqrnJMTfwKhdJRucnG/xYTLLG6j5tM8P5hych6knYU3BGAmM87bLjWGA234Rl dkdGOoiQxeXCtpoX69EX7YclHtspUkCdE6S9IKkXosoJQGc1mQ2NJv4IQyzTMkY+nrxl JHgA== X-Gm-Message-State: AOJu0YzN8unLPoHF/Q5M9JiMNdD7G8iYU+8P4ANr9fRMKuq/e0i9OWxj rOZKazl02z+7bTTDWj2GYmJ7MOJMsnZX6XGpEI7GvjClhg1c3xOSPO4i7okYyeh2Cv0zh02UZhx NFPz4lA== X-Received: from ilkj13.prod.google.com ([2002:a05:6e02:eed:b0:509:30bc:8271]) (user=avagin job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6820:c93:b0:6b1:64f:cd88 with SMTP id 006d021491bc7-6b106501ebcmr7175117eaf.6.1786940458922; Sun, 16 Aug 2026 21:20:58 -0700 (PDT) Date: Mon, 17 Aug 2026 04:20:43 +0000 In-Reply-To: <20260817042048.1579415-1-avagin@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260817042048.1579415-1-avagin@google.com> X-Mailer: git-send-email 2.55.0.691.gc56d675ccc-goog Message-ID: <20260817042048.1579415-4-avagin@google.com> Subject: [PATCH 3/8] x86/fpu: Split __fpu_restore_sig to extract compat path From: Andrei Vagin To: Thomas Gleixner , Ingo Molnar , Borislav Petkov , "Chang S. Bae" Cc: linux-kernel@vger.kernel.org, criu@lists.linux.dev, Dave Hansen , x86@kernel.org, Andrei Vagin , Alexander Mikhalitsyn , "H. Peter Anvin" Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Split __fpu_restore_sig to move the restore part for the legacy/compat FPU state (when buf_f is present) to a separate helper function. The legacy 32-bit FP frame duplicates the FP state portion of the FX/XSAVE frame. For backward compatibility, the legacy FP frame is treated as the source of truth, and its state is folded into the FX/XSAVE state before restoring the registers. Reviewed-by: Alexander Mikhalitsyn Signed-off-by: Andrei Vagin --- arch/x86/kernel/fpu/signal.c | 50 +++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c index 42c3d78bd849..6a14b528ac7f 100644 --- a/arch/x86/kernel/fpu/signal.c +++ b/arch/x86/kernel/fpu/signal.c @@ -264,6 +264,9 @@ static int __restore_fpregs_from_user(void __user *buf,= u64 task_xfeatures, } } =20 +static bool restore_fpregs_from_user_compat(void __user *buf_f, void __use= r *buf_fx, + u64 xrestore_mask, bool fx_only); + /* * Attempt to restore the FPU registers directly from user memory. * Pagefaults are handled and any errors returned are fatal. @@ -324,14 +327,9 @@ static bool restore_fpregs_from_user(void __user *buf,= u64 xrestore_mask, bool f return true; } =20 -static bool __fpu_restore_sig(void __user *buf_f, void __user *buf_fx, - bool ia32_fxstate) +static bool __fpu_restore_sig(void __user *buf_f, void __user *buf_fx) { - struct task_struct *tsk =3D current; - struct fpu *fpu =3D x86_task_fpu(tsk); - struct user_i387_ia32_struct env; - bool success, fx_only =3D false; - union fpregs_state *fpregs; + bool fx_only =3D false; u64 xrestore_mask =3D 0; =20 if (use_xsave()) { @@ -346,11 +344,33 @@ static bool __fpu_restore_sig(void __user *buf_f, voi= d __user *buf_fx, xrestore_mask =3D XFEATURE_MASK_FPSSE; } =20 - if (likely(!ia32_fxstate)) { + if (likely(!buf_f)) { /* Restore the FPU registers directly from user memory. */ return restore_fpregs_from_user(buf_fx, xrestore_mask, fx_only); } =20 + return restore_fpregs_from_user_compat(buf_f, buf_fx, xrestore_mask, fx_o= nly); +} + +#if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION) +/* + * Restore FPU state from a signal frame when a legacy 32-bit FP frame + * (buf_f) is present. + * + * The legacy FP frame duplicates the FP state portion of the FX/XSAVE + * frame (buf_fx). For backward compatibility, the legacy FP frame is + * treated as the source of truth, and its state is folded into the + * FX/XSAVE state before restoring the registers. + */ +static bool restore_fpregs_from_user_compat(void __user *buf_f, void __use= r *buf_fx, + u64 xrestore_mask, bool fx_only) +{ + struct task_struct *tsk =3D current; + struct fpu *fpu =3D x86_task_fpu(tsk); + struct user_i387_ia32_struct env; + union fpregs_state *fpregs; + bool success; + /* * Copy the legacy state because the FP portion of the FX frame has * to be ignored for histerical raisins. The legacy state is folded @@ -435,6 +455,13 @@ static bool __fpu_restore_sig(void __user *buf_f, void= __user *buf_fx, fpregs_unlock(); return success; } +#else +static bool restore_fpregs_from_user_compat(void __user *buf_f, void __use= r *buf_fx, + u64 xrestore_mask, bool fx_only) +{ + return false; +} +#endif =20 static inline unsigned int xstate_sigframe_size(struct fpstate *fpstate) { @@ -449,8 +476,7 @@ static inline unsigned int xstate_sigframe_size(struct = fpstate *fpstate) bool fpu__restore_sig(void __user *buf, int ia32_frame) { struct fpu *fpu =3D x86_task_fpu(current); - void __user *buf_fx =3D buf; - bool ia32_fxstate =3D false; + void __user *buf_fx =3D buf, *buf_f =3D NULL; bool success =3D false; unsigned int size; =20 @@ -471,7 +497,7 @@ bool fpu__restore_sig(void __user *buf, int ia32_frame) if (ia32_frame && use_fxsr()) { buf_fx =3D buf + sizeof(struct fregs_state); size +=3D sizeof(struct fregs_state); - ia32_fxstate =3D true; + buf_f =3D buf; } =20 if (!access_ok(buf, size)) @@ -482,7 +508,7 @@ bool fpu__restore_sig(void __user *buf, int ia32_frame) sizeof(struct user_i387_ia32_struct), NULL, buf); } else { - success =3D __fpu_restore_sig(buf, buf_fx, ia32_fxstate); + success =3D __fpu_restore_sig(buf_f, buf_fx); } =20 out: --=20 2.55.0.691.gc56d675ccc-goog From nobody Mon Sep 28 21:52:48 2026 Received: from mail-ot1-f69.google.com (mail-ot1-f69.google.com [209.85.210.69]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6B1093112B2 for ; Mon, 17 Aug 2026 04:21:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.69 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786940465; cv=none; b=NP4psGwaun+NkWNLFqxd95x0PjCNdZST0doxBriNDvOsxahJ3u96ffPUTqEFrKMq+YGAYfkJhNtEYafhng82xOePFpRSNSGf9UD+Rn/TvIj5qOsfMrthT4eemJ+nzKJAaD6WIoORbfPqURw+Gp4YUA0mOD5zk18zCeNuTNp1Vo0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786940465; c=relaxed/simple; bh=svYz+QsX7dtpedtqHqww6ZTpPVUveypQSsJmW25Hjvg=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=Q+A1z5eRhw9GrusbdGII1Ti69jlGaEMhfA+tY/Xs+AIP7hf2YBsQjEY6ZSZnh8ThmYQqfGSsrJwACeDdE5n9NISwscenM96sPEjTDsk+W3oaPssPVmF/NB0LciUW1UcZ+dw+RK87Kjxk201CHbyTB+Vi73BcC2ug9LPsGTp0J2M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--avagin.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=QUXAB4Aj; arc=none smtp.client-ip=209.85.210.69 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--avagin.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="QUXAB4Aj" Received: by mail-ot1-f69.google.com with SMTP id 46e09a7af769-7e9dc0f5900so6974838a34.0 for ; Sun, 16 Aug 2026 21:21:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1786940460; x=1787545260; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=CoyS/Te2F5yF1AVsXNnrALUu84hJAgdlObRwg/dPksI=; b=QUXAB4AjdHHXhpbMAU6kfyHqtswrJ40bwjSnjKtXfAWwDTYOmafX3gRhA4hGVd9LTU daHX00Fx7aTGiRN4T8LcrED3PYyEwj77PzxAn/t36xA75RGT7VfyrLRU7fuC5Q5vZyGO mw82S/PsAKxcYwTJCtXUwLR0CT3aU0LfA4FDxMShONQ1s7LDz/rK2mBkMw357VKSvaiK 6/tUF/VU4S/utw/pb7dh0oVjkp8S82ooL6Sh+0LUW/q9WcFrZ9Kk848+ZLn018eXyZ+7 kREL+6MI5wIOvVIc9dJRVBxrg6MTLe6YGycVTE51sWcMhAidqdkCSg27T6FoMwVIu5Yl T6oA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786940460; x=1787545260; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=CoyS/Te2F5yF1AVsXNnrALUu84hJAgdlObRwg/dPksI=; b=MYUWbV/sJOT4QK/Pbk3P43kde8d0VQG9+e96rXRaJXNYaRknRhKEHWFRMIpC5vAl44 bYWVT7er31j05ySuo+dKjzTZH1LpGy3mmghxQw7nXbvgRhplNz35h1zTHOq2EO9ljRez I3klXo7RBx/+U1PyV9yEf4UrOjBe7nqKX3pKRbxhNoU5y7pCXqrmiOQbyZCAJL7llgRh XOrvB8taOt0RL7SrWBBuYVX6gR3Nbq4//arQA5ZXaXtziUVLV05eY5ppNxfnW7++Be8f K9Wpj1U5/TM2aH0F7ycGbP5r+P5dF4MNMPFPpa9WtuuP/yGZ+QBzYOLcRouIQ0ko63Aw uNwQ== X-Gm-Message-State: AOJu0YyauGkgjfnhq4c6ntR9pGPS/DsVQ212CZ9kbvIq9OAIKbZBnabv QDuZW5dLf3uOcU26CArVB0ztFPUoSyYNNBx1Wcqfn4LGbmRsjV1jkhhUBlm9GF5/kiSabfckIu4 iOlwRJg== X-Received: from ilbeo25-n2.prod.google.com ([2002:a05:6e02:2919:20b0:509:545b:77b5]) (user=avagin job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6820:2d03:b0:6a9:fa7f:faaf with SMTP id 006d021491bc7-6b0c5a8f072mr17604962eaf.5.1786940460025; Sun, 16 Aug 2026 21:21:00 -0700 (PDT) Date: Mon, 17 Aug 2026 04:20:44 +0000 In-Reply-To: <20260817042048.1579415-1-avagin@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260817042048.1579415-1-avagin@google.com> X-Mailer: git-send-email 2.55.0.691.gc56d675ccc-goog Message-ID: <20260817042048.1579415-5-avagin@google.com> Subject: [PATCH 4/8] x86/fpu: Document reasoning of FX-only fallback From: Andrei Vagin To: Thomas Gleixner , Ingo Molnar , Borislav Petkov , "Chang S. Bae" Cc: linux-kernel@vger.kernel.org, criu@lists.linux.dev, Dave Hansen , x86@kernel.org, Andrei Vagin , Alexander Mikhalitsyn , "H. Peter Anvin" Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add a comment to check_xstate_in_sigframe() to explain reasoning behind falling back to the FX-only state when signal frame metadata is inconsistent. The fallback is intended to preserve backward compatibility with legacy user-space processes that are not aware of XSAVE states and might only fill or copy just the legacy FP state. This fallback is dangerous as it can trigger silent corruptions of user-space state by resetting extended registers if the process was using them but the frame metadata was malformed. Reviewed-by: Alexander Mikhalitsyn Signed-off-by: Andrei Vagin --- arch/x86/kernel/fpu/signal.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c index 6a14b528ac7f..85021c5ea649 100644 --- a/arch/x86/kernel/fpu/signal.c +++ b/arch/x86/kernel/fpu/signal.c @@ -54,6 +54,14 @@ static inline bool check_xstate_in_sigframe(struct fxreg= s_state __user *buf_fx, if (likely(magic2 =3D=3D FP_XSTATE_MAGIC2)) return true; err_setfx: + /* + * The fallback to FX-only state is used to preserve backward + * compatibility with user-space processes that are not aware of xsave + * states. + * + * In all other cases, returning false (to trigger SIGSEGV) is + * preferred to avoid silent user-space state corruption. + */ trace_x86_fpu_xstate_check_failed(x86_task_fpu(current)); =20 /* Set the parameters for fx only state */ --=20 2.55.0.691.gc56d675ccc-goog From nobody Mon Sep 28 21:52:48 2026 Received: from mail-oa1-f72.google.com (mail-oa1-f72.google.com [209.85.160.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 71094318EC9 for ; Mon, 17 Aug 2026 04:21:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.160.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786940467; cv=none; b=kLi/Jc0C3rd2lE+Ww6yNoEF6S1HzkMIwRz9m1mXge+lSAzAbCI75MytdwnGnqvw7RENiXDutP4tcr+YWgHQ36FAkVs1pVkT+mQxsthY7P9suB2IAMBdzcElq6y2MbK/dGUCOkO0d4A3TXnYOrnnwQA/Ea+y+XLGRP80b87YPaPA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786940467; c=relaxed/simple; bh=EGVW2FWzSjrTgOoN/kUC29vh76R2kVadPH9iJz0yEoQ=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=K/u/auT3jbIXNEXBjPne0Z0s6rdG0R0sFMGI8d6J2BZJ36+hP6lLGoPPDTOiGLhOntHzwe0aJ0z2yAp3lx7SjTiUvfpPGPmMeP81yQGbET67vRtMkqyKoM13smd0EhDJpdQjaXvwOjDVFoLqhZBI5Czs20X9gYd7rgHD8yZXG90= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--avagin.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=F0GSRsjZ; arc=none smtp.client-ip=209.85.160.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--avagin.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="F0GSRsjZ" Received: by mail-oa1-f72.google.com with SMTP id 586e51a60fabf-44d0960fb5bso2190833fac.2 for ; Sun, 16 Aug 2026 21:21:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1786940461; x=1787545261; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=8qIEfcQtgJN4KzTA+lksjAtNa1kCGrCX85DLYtTOqKQ=; b=F0GSRsjZ4E1Sgx0XqtnbXHrxSEVv71SimocJsQ9zFw/tfGwlWqVeqMPNM49YJB2WcB HwqonzqCenEzPnbKc2RRAcnOhIAbMD8MJ5s2eauc4uBTys+5RanhkGyg7ZhaeEngkGOR 0kTzVpoRIk2eCGNfXUMMOEzwu4sMfeVF5gMIAAyAgU8uoGkF7C49JZIF5Ut7vUOeepUK Op8kavddZiogdpJIqpBqNTrwWgQE9cAGpbuXSatXijMUYjbM4ebQqmtIiVErYM0GzQCS kCyuIUhPUaItb4jl63/DGKV80NK/zlXOA5TGuiP04FiutJZdTmqKqD/Iq+p3WIt9Tt/G zQcw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786940461; x=1787545261; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=8qIEfcQtgJN4KzTA+lksjAtNa1kCGrCX85DLYtTOqKQ=; b=Ja//dItg/7FnpPJkmOWpJn10LEs5vQk+Fl19G5KVfTW64R6ZLucEunlwHRKPj1Rvur qonRpWO1HKAePFwIqk/RlWZXgT524FINc5iXF+NY6liSV9m9BuwU2Y1h12ot2mqvk2jQ FjHbhTLZ/+msImqXXHs0iT65o5IVAFPKQ01BHYV1w4VGsUrbrd6F3cnxPf1Mpw/d10UN TrvKftp5U7tJ2P2lorj8WpnSLajI+0/5DUca3nzEnvcFV2flRcSZrhldo6exnXMdCaos H4Qd1+NQDpM7RTt76JM73ZOGEIgp+zO8VXDehSg7T7kmsTgYgjNsch8PDwQY/jkwgEHj +Krg== X-Gm-Message-State: AOJu0Ywp9E+Z9bmrLFdD7SqnIwogcATKJyj/DQxzh02iae6B4c1jZnqa zQya7HaSM7WXKRxbHAZQCThOmcthS50A6KEotHlSfc8pFRE10IlT5F/OW7FLBjPb0LRxB8zlYac L1C8gNQ== X-Received: from oapb36.prod.google.com ([2002:a05:6870:3924:b0:45e:d413:4b3d]) (user=avagin job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6871:341d:b0:456:772f:682d with SMTP id 586e51a60fabf-45e92467466mr19745620fac.19.1786940461018; Sun, 16 Aug 2026 21:21:01 -0700 (PDT) Date: Mon, 17 Aug 2026 04:20:45 +0000 In-Reply-To: <20260817042048.1579415-1-avagin@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260817042048.1579415-1-avagin@google.com> X-Mailer: git-send-email 2.55.0.691.gc56d675ccc-goog Message-ID: <20260817042048.1579415-6-avagin@google.com> Subject: [PATCH 5/8] selftests/x86: Add a test for signal frame FPU portability From: Andrei Vagin To: Thomas Gleixner , Ingo Molnar , Borislav Petkov , "Chang S. Bae" Cc: linux-kernel@vger.kernel.org, criu@lists.linux.dev, Dave Hansen , x86@kernel.org, Andrei Vagin , Alexander Mikhalitsyn , "H. Peter Anvin" Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add a new selftest tools/testing/selftests/x86/sigframe_fpu_portability.c that verifies that the kernel correctly restores the xstate context even if the frame size has been manually reduced, as long as the FP_XSTATE_MAGIC2 marker is correctly placed at the end of the specified xstate_size. This test simulates a scenario where a signal frame is created on a system with fewer xstate features and restored on a system with more features. Reviewed-by: Alexander Mikhalitsyn Signed-off-by: Andrei Vagin --- tools/testing/selftests/x86/Makefile | 5 +- .../selftests/x86/sigframe_fpu_portability.c | 162 ++++++++++++++++++ tools/testing/selftests/x86/xstate.c | 5 - tools/testing/selftests/x86/xstate.h | 12 ++ 4 files changed, 178 insertions(+), 6 deletions(-) create mode 100644 tools/testing/selftests/x86/sigframe_fpu_portability.c diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests= /x86/Makefile index 434065215d12..72071deda978 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile @@ -19,7 +19,8 @@ TARGETS_C_32BIT_ONLY :=3D entry_from_vm86 test_syscall_vd= so unwind_vdso \ test_FCMOV test_FCOMI test_FISTTP \ vdso_restorer TARGETS_C_64BIT_ONLY :=3D fsgsbase sysret_rip syscall_numbering \ - corrupt_xstate_header amx lam test_shadow_stack avx apx + corrupt_xstate_header amx lam test_shadow_stack avx apx \ + sigframe_fpu_portability # Some selftests require 32bit support enabled also on 64bit systems TARGETS_C_32BIT_NEEDED :=3D ldt_gdt ptrace_syscall =20 @@ -138,3 +139,5 @@ $(OUTPUT)/avx_64: CFLAGS +=3D -mno-avx -mno-avx512f $(OUTPUT)/amx_64: EXTRA_FILES +=3D xstate.c $(OUTPUT)/avx_64: EXTRA_FILES +=3D xstate.c $(OUTPUT)/apx_64: EXTRA_FILES +=3D xstate.c + +$(OUTPUT)/sigframe_fpu_portability_64: CFLAGS +=3D -mno-avx -mno-avx512f diff --git a/tools/testing/selftests/x86/sigframe_fpu_portability.c b/tools= /testing/selftests/x86/sigframe_fpu_portability.c new file mode 100644 index 000000000000..169548892f92 --- /dev/null +++ b/tools/testing/selftests/x86/sigframe_fpu_portability.c @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: GPL-2.0-only +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "helpers.h" +#include "xstate.h" + +/* + * This test verifies the FPU portability of the signal frame. + * It verifies that the kernel correctly restores the xstate context even + * if the frame size has been manually reduced (shrunk), as long as the + * FP_XSTATE_MAGIC2 marker is correctly placed. + */ + +#define SIGFRAME_XSTATE_HDR_OFFSET 512 + +#define XSTATE_SSE_ONLY_SIZE (SIGFRAME_XSTATE_HDR_OFFSET + XSAVE_HDR_SIZE) +#define XFEATURE_MASK_FPSSE ((1 << XFEATURE_FP) | (1 << XFEATURE_SSE)) + +static uint32_t ymm_offset; +static uint32_t xstate_size_ymm; + +/* + * Avoid using printf() in signal handlers as it is not + * async-signal-safe. + */ +#define SIGNAL_BUF_LEN 1024 +static char sig_err_buf[SIGNAL_BUF_LEN]; + +static void sig_print(const char *msg) +{ + int left =3D SIGNAL_BUF_LEN - strlen(sig_err_buf) - 1; + + strncat(sig_err_buf, msg, left); +} + +static void check_avx_support(void) +{ + struct xstate_info xstate; + unsigned long features; + long rc; + + /* + * Check if the kernel supports AVX (XFEATURE_YMM). + * This also confirms that the OS has enabled XSAVE. + */ + rc =3D syscall(SYS_arch_prctl, ARCH_GET_XCOMP_SUPP, &features); + if (rc !=3D 0) + ksft_exit_skip("ARCH_GET_XCOMP_SUPP not supported\n"); + + if (!(features & (1 << XFEATURE_YMM))) + ksft_exit_skip("AVX not supported by kernel/hardware\n"); + + xstate =3D get_xstate_info(XFEATURE_YMM); + if (!xstate.size) + ksft_exit_skip("AVX not supported by hardware\n"); + + ymm_offset =3D xstate.xbuf_offset; + xstate_size_ymm =3D xstate.xbuf_offset + xstate.size; +} + +#define TEST_YMMH_VAL (0x5656565656565656UL) + +__attribute__((target("avx"))) +static void read_ymm0(uint64_t *v) +{ + asm volatile ("vmovdqu %%ymm0, %0" : "=3Dm" (*(char (*)[32])v)); +} + +__attribute__((target("avx"))) +static void write_ymm0(uint64_t *v) +{ + asm volatile ("vmovdqu %0, %%ymm0" : : "m" (*(char (*)[32])v)); +} + +static void handle_shrunk_xstate_size(int sig, siginfo_t *si, void *ucp) +{ + ucontext_t *uc =3D ucp; + void *fp =3D uc->uc_mcontext.fpregs; + struct _fpx_sw_bytes *sw =3D get_fpx_sw_bytes(fp); + struct xsave_buffer *xbuf; + uint64_t xfeatures, *ymmh_p; + + if (sw->magic1 !=3D FP_XSTATE_MAGIC1) { + sig_print("magic1 is not valid\n"); + return; + } + + xbuf =3D (struct xsave_buffer *)fp; + + /* Shrink the frame to just YMM size */ + sw->xstate_size =3D xstate_size_ymm; + + xfeatures =3D get_xstatebv(xbuf); + xfeatures &=3D XFEATURE_MASK_FPSSE | (1 << XFEATURE_YMM); + set_xstatebv(xbuf, xfeatures); + /* Also update sw->xfeatures as the kernel relies on it */ + set_fpx_sw_bytes_features(fp, xfeatures); + + *(uint32_t *)(fp + sw->xstate_size) =3D FP_XSTATE_MAGIC2; + + ymmh_p =3D (uint64_t *)(fp + ymm_offset); + ymmh_p[0] =3D TEST_YMMH_VAL; + ymmh_p[1] =3D TEST_YMMH_VAL+1; + + /* clear everything after MAGIC2. */ + if (sw->xstate_size + 4 < sw->extended_size) + memset(fp + sw->xstate_size + 4, 0, sw->extended_size - sw->xstate_size = - 4); +} + +static void test_shrunk_xstate_size(void) +{ + uint64_t v[4] =3D {0, 0, 0, 0}; + + sig_err_buf[0] =3D 0; + sethandler(SIGUSR1, handle_shrunk_xstate_size, 0); + + v[0] =3D 0x1111111111111111ULL; + v[1] =3D 0x2222222222222222ULL; + v[2] =3D 0x3333333333333333ULL; + v[3] =3D 0x4444444444444444ULL; + write_ymm0(v); + + raise(SIGUSR1); + v[0] =3D v[1] =3D v[2] =3D v[3] =3D 0; + read_ymm0(v); + + if (sig_err_buf[0]) + ksft_test_result_fail("%s\n", sig_err_buf); + else if (v[2] =3D=3D TEST_YMMH_VAL && v[3] =3D=3D (TEST_YMMH_VAL + 1)) + ksft_test_result_pass("YMM state restored correctly from shrunk frame\n"= ); + else + ksft_test_result_fail( + "Got upper bits: 0x%lx 0x%lx (expected %lx %lx)\n", + v[2], v[3], TEST_YMMH_VAL, TEST_YMMH_VAL + 1); + + clearhandler(SIGUSR1); +} + + +int main(void) +{ + ksft_print_header(); + ksft_set_plan(1); + + check_avx_support(); + + test_shrunk_xstate_size(); + ksft_finished(); + return 0; +} diff --git a/tools/testing/selftests/x86/xstate.c b/tools/testing/selftests= /x86/xstate.c index 97fe4bd8bc77..40062b28c001 100644 --- a/tools/testing/selftests/x86/xstate.c +++ b/tools/testing/selftests/x86/xstate.c @@ -42,11 +42,6 @@ static inline uint64_t xgetbv(uint32_t index) return eax + ((uint64_t)edx << 32); } =20 -static inline uint64_t get_xstatebv(struct xsave_buffer *xbuf) -{ - return *(uint64_t *)(&xbuf->header); -} - static struct xstate_info xstate; =20 struct futex_info { diff --git a/tools/testing/selftests/x86/xstate.h b/tools/testing/selftests= /x86/xstate.h index 6ee816e7625a..c531667b66ad 100644 --- a/tools/testing/selftests/x86/xstate.h +++ b/tools/testing/selftests/x86/xstate.h @@ -3,6 +3,8 @@ #define __SELFTESTS_X86_XSTATE_H =20 #include +#include +#include =20 #include "kselftest.h" =20 @@ -160,6 +162,11 @@ static inline void set_xstatebv(struct xsave_buffer *x= buf, uint64_t bv) *(uint64_t *)(&xbuf->header) =3D bv; } =20 +static inline uint64_t get_xstatebv(struct xsave_buffer *xbuf) +{ + return *(uint64_t *)(&xbuf->header); +} + /* See 'struct _fpx_sw_bytes' at sigcontext.h */ #define SW_BYTES_OFFSET 464 /* N.B. The struct's field name varies so read from the offset. */ @@ -175,6 +182,11 @@ static inline uint64_t get_fpx_sw_bytes_features(void = *buffer) return *(uint64_t *)(buffer + SW_BYTES_BV_OFFSET); } =20 +static inline void set_fpx_sw_bytes_features(void *buffer, uint64_t featur= es) +{ + *(uint64_t *)(buffer + SW_BYTES_BV_OFFSET) =3D features; +} + static inline void set_rand_data(struct xstate_info *xstate, struct xsave_= buffer *xbuf) { int *ptr =3D (int *)&xbuf->bytes[xstate->xbuf_offset]; --=20 2.55.0.691.gc56d675ccc-goog From nobody Mon Sep 28 21:52:48 2026 Received: from mail-oo1-f69.google.com (mail-oo1-f69.google.com [209.85.161.69]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6BEC85474E for ; Mon, 17 Aug 2026 04:21:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.161.69 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786940466; cv=none; b=uebUaIkwojP6XXR5xxXkEAz9EfHx6/jxx324hVlpJCDd+ZOmE8MWrTC8qyB6+C/tXvx4out+cE79XtOFMywOjgCnLE3flC2n4JOMolcgDScDgefqu8d5pBdPP19RGBGgNWOSvpbl0bAzrKFmyDeECakjlmff9Xl6tyrbdMGHE7s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786940466; c=relaxed/simple; bh=OHRR405LoruzjVQ7I+gV2w9ZETAswaFWPTaGunXzhfQ=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=XCaHlOrQrhnerCkyGO4ZQHl6XgBFJ7gZSxnS/YcnKaxBd0GZUVywYmnpQLFHpeaHoJG4pbjHM1lOMjfZaftZ/Hhh8bV1CSH6l8VDDE2yjyBIKW4enCPV+4EyUANf4Yg11XI//pAs/hsfHSXi0TrUIahHcpTE3gMFu+c2QgGpV1E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--avagin.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=insoOdzq; arc=none smtp.client-ip=209.85.161.69 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--avagin.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="insoOdzq" Received: by mail-oo1-f69.google.com with SMTP id 006d021491bc7-6a3da2369aaso1962331eaf.1 for ; Sun, 16 Aug 2026 21:21:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1786940462; x=1787545262; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=akqPyoKu72swjeR5uaSFSTBEl/QkWuBKcd50F31FwJY=; b=insoOdzq5v1h4ICmckwZnsDC098zzN3DyUuB0OcrCdZ6KNAYVgLV8hwNVRTnXYi0PV plh8ZsYR/fI9wenimjKhXpH7raUB46dGiOqBld8VrBJLQvDuXg7Xb4f3kzmlvP8g8yt0 JwWscLgBn2BqSkTB8j2qJyXsceBba49JdlHJrQ6kqcCntH3LHY0UrW2b6lTWT4tOE3Op X69KPcU5CSveJgrwqO4F8r94Ho7Rk5gGUDFq4OOq/3QPJNjg9p/itDPGEjw9P+AepRG4 Rfy7m1yqq23gqvtUf4wd6B3GWNKzf22P5ltqWYpTG1Y1jV1Gs4tx1Y6NwZd3kWHeiEwj Bn/Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786940462; x=1787545262; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=akqPyoKu72swjeR5uaSFSTBEl/QkWuBKcd50F31FwJY=; b=Velfc6Ju+Z/vuQyxT9nMahL0Caa8p80ctkwrKdIyMJ1gEdRUefMLNyGfiNIa7dtzr9 z8I6DsCtfwQSsUG1eUXi+bNOHVOY83tAPoYIaAFa38M7nxPz+QH7eb0+qZaN3PLrVigp /KPjoOitQErn8gh7CqLa0iTvVafdw/2XCoOcQcrOPEjiotS5BDy/5mXfZJesm8nFVZ7q YRNpH4+JWewBpZOTa6x4bccJIOCAIthUpRu/Gt9hLXbZixThT1ddMrLCf4BfKvvPJnDS z8xrlkWtANNeKHFCl3xPbuqg+D39EhZaFv7uUF/hiR8lvhXwhZteMzBPyc5pHzdux0pI IJFQ== X-Gm-Message-State: AOJu0YwdswSfUPXgSA99lmeha8sQjyNzRYdy41vGsRpfZqMJBlL4/aPq brh4hQbOvsQSrbiE8O1DPtbO/9Qn9OiCER/9uUrXxVfajRhqaQm82qYJ/UXP/HZY8f6lT4ZXvsi DKf62PQ== X-Received: from jabjx3.prod.google.com ([2002:a05:6638:a283:b0:5e9:17a8:a8c9]) (user=avagin job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6820:f02f:b0:6ac:b3b1:a5a2 with SMTP id 006d021491bc7-6b0d5db38f0mr18372936eaf.0.1786940462110; Sun, 16 Aug 2026 21:21:02 -0700 (PDT) Date: Mon, 17 Aug 2026 04:20:46 +0000 In-Reply-To: <20260817042048.1579415-1-avagin@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260817042048.1579415-1-avagin@google.com> X-Mailer: git-send-email 2.55.0.691.gc56d675ccc-goog Message-ID: <20260817042048.1579415-7-avagin@google.com> Subject: [PATCH 6/8] x86/fpu: Fix potential underflow in xstate_calculate_size() From: Andrei Vagin To: Thomas Gleixner , Ingo Molnar , Borislav Petkov , "Chang S. Bae" Cc: linux-kernel@vger.kernel.org, criu@lists.linux.dev, Dave Hansen , x86@kernel.org, Andrei Vagin , Alexander Mikhalitsyn , "H. Peter Anvin" Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" xstate_calculate_size() calculates the size required for a given set of xfeatures. It determines the topmost feature by finding the most significant bit in xfeatures using fls64(xfeatures) - 1. If xfeatures is 0, fls64(0) returns 0, and topmost becomes -1. Previously, topmost was unsigned int, so -1 underflowed to UINT_MAX. This caused the subsequent check `topmost <=3D XFEATURE_SSE` to fail, and the code proceeded to access xstate arrays using topmost (UINT_MAX) as an index, leading to an out-of-bounds access. Fix this by checking if xfeatures only contains legacy features (FP/SSE) or is empty (xfeatures <=3D XFEATURE_MASK_FPSSE) before calculating topmost. Fixes: d6d6d50f1e80 ("x86/fpu/xstate: Consolidate size calculations") Reviewed-by: Alexander Mikhalitsyn Signed-off-by: Andrei Vagin --- arch/x86/kernel/fpu/xstate.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index a7b6524a9dea..ed39d7051d0d 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c @@ -589,12 +589,13 @@ static bool __init check_xstate_against_struct(int nr) =20 static unsigned int xstate_calculate_size(u64 xfeatures, bool compacted) { - unsigned int topmost =3D fls64(xfeatures) - 1; - unsigned int offset, i; + unsigned int topmost, offset, i; =20 - if (topmost <=3D XFEATURE_SSE) + if (xfeatures <=3D XFEATURE_MASK_FPSSE) return sizeof(struct xregs_state); =20 + topmost =3D fls64(xfeatures) - 1; + if (compacted) { offset =3D xfeature_get_offset(xfeatures, topmost); } else { --=20 2.55.0.691.gc56d675ccc-goog From nobody Mon Sep 28 21:52:48 2026 Received: from mail-oo1-f71.google.com (mail-oo1-f71.google.com [209.85.161.71]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 60FEA31716B for ; Mon, 17 Aug 2026 04:21:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.161.71 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786940474; cv=none; b=ilzajIdalotTS69AUyic23ZQUE8rtmfNnvg5S3eV89cRTAEahQK19L7UgIbAw9quDh43t9uYK21Smfol0Fd9YNf+qd1jeshoHiB/RWYNCQ3WJJympToid7P71ZcMyqdQfhm0QqXD78YBS1lN+UJ8AoDxN0IQDJrIrSWy1aqSrwg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786940474; c=relaxed/simple; bh=/S3Ozt5U6D8GZmtRXmXpLrKP6xBvYXtBazq5LRSVX5Q=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=F6GUYChOgVNMYIELthty680h3Z8Uzq78QeQ45Gv6hlMuF/2mqlGAx/+ee1w7V5HknEDlJ+Vj8uW3GTDvu/8wc6z6uLLgSZ7fGveiB3BB4+RhQ+hTvyzyY+BRarERnYhtH0nSYTPtjHCf2bFG7jUAMuzou0SwjFMFZQvux0IJPAI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--avagin.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=R/A0h+LP; arc=none smtp.client-ip=209.85.161.71 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--avagin.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="R/A0h+LP" Received: by mail-oo1-f71.google.com with SMTP id 006d021491bc7-6a3da2369aaso1962348eaf.1 for ; Sun, 16 Aug 2026 21:21:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1786940463; x=1787545263; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=iDLrJ1Ge+3vjceZ0Kl5T/TuvEl2B8CvC5RmISz7HKIc=; b=R/A0h+LPm7qzku/9kyShhrKaXycD2zGp8SYXzm29wew50bb51OidXjqOjpws1Ad/jC S474Auz0mySw2PgbrpI/uDQacBc+SC9FCPFWMHRlsLkzhCv5TM0euDPi96p0ZGrW9HQD d/xPyHIzsb87XZu43fc1EX+NSJgk1egK/v8zEn7PCSIB8FgQivYjFhMBp4EfzVQDs9iO 2A29pQEWD1QAMhgfe/MaxV2kpfAONkdoHUgssyp6/PYpgWR7eT+LcFvdRrmpqyzwlXSY Dovz3wqW9bWoo75zkREXX+rmcZ3E5zTGnZqZXbSS+wNyVwUkOD2qRhvRueXM2PXK/BzA kOEA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786940463; x=1787545263; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=iDLrJ1Ge+3vjceZ0Kl5T/TuvEl2B8CvC5RmISz7HKIc=; b=KOY9j9IhLIrzr+FQzMUnvAzukl90E0WxHmnUhqGyC4ROCDsBqiWWrGn1G9cB3zCdNv vNoAgT8IUNaamgrqVhmJ8p7ZT7yY+NlZFKf1EBkvQ6tMDEmFVzBNeV0PFmTruoRnjqaz qmWr4z7KsqTGn+FWfB1W8GWpt+mrPFwbYqX5X8etnBcedAKE5g0PLZ3LtFCPDjg3RDgk WKc9B/3DqDRZ6AcFI1ggIY1hREWZ4U+4IlX/pXqCiwIlIKgM77nrwTlzgaNsjhITv/Ak Iy3exTqdoU1i1YSiq8mdjUV49bpO/bG0wyQ87EJh9mo2eaXDsoeVJo00wl3lCbxPZcBs MG+A== X-Gm-Message-State: AOJu0YwFuR4rTUJ9tOeU2zm+HaA4RxIR0xvbaqLhIRXb3s8ce4Aoz1KZ XmXxrwnbRjZuYTZo6o/UeWzkcif0qOmMk+aDN+yGQCX53DjDchhrs7OxunPR62qvhHj/dvvbweo fCwkpaA== X-Received: from ilbdx25-n1.prod.google.com ([2002:a05:6e02:4219:10b0:509:60ca:f9a4]) (user=avagin job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6820:201b:b0:6b0:589e:42f4 with SMTP id 006d021491bc7-6b0d6245e3bmr19339142eaf.20.1786940463163; Sun, 16 Aug 2026 21:21:03 -0700 (PDT) Date: Mon, 17 Aug 2026 04:20:47 +0000 In-Reply-To: <20260817042048.1579415-1-avagin@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260817042048.1579415-1-avagin@google.com> X-Mailer: git-send-email 2.55.0.691.gc56d675ccc-goog Message-ID: <20260817042048.1579415-8-avagin@google.com> Subject: [PATCH 7/8] x86/fpu: Pre-fault only required size of xstate buffer From: Andrei Vagin To: Thomas Gleixner , Ingo Molnar , Borislav Petkov , "Chang S. Bae" Cc: linux-kernel@vger.kernel.org, criu@lists.linux.dev, Dave Hansen , x86@kernel.org, Andrei Vagin , Alexander Mikhalitsyn , "H. Peter Anvin" Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The kernel previously used the default task FPU state size (user_size) to fault in the user buffer when restoring FPU registers from a signal frame. This can lead to attempting to fault in memory past the end of the actual frame if the frame was smaller than the default size. Introduce consistency checks to calculate the actual required size for the features enabled in the xfeatures mask, ensure that the provided xstate_size is sufficient, and shrink it to the actual required size. Use this validated size to fault in the user buffer. Keep the strict check that the provided xstate_size does not exceed the default user_size for now. Reviewed-by: Alexander Mikhalitsyn Signed-off-by: Andrei Vagin --- arch/x86/kernel/fpu/signal.c | 40 ++++++++++++++++++++++++++++-------- arch/x86/kernel/fpu/xstate.c | 2 +- arch/x86/kernel/fpu/xstate.h | 2 ++ 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c index 85021c5ea649..1e7cc114c186 100644 --- a/arch/x86/kernel/fpu/signal.c +++ b/arch/x86/kernel/fpu/signal.c @@ -29,7 +29,8 @@ static inline bool check_xstate_in_sigframe(struct fxregs= _state __user *buf_fx, { int min_xstate_size =3D sizeof(struct fxregs_state) + sizeof(struct xstate_header); - void __user *fpstate =3D buf_fx; + struct fpstate *fpstate =3D x86_task_fpu(current)->fpstate; + void __user *buf =3D buf_fx; unsigned int magic2; =20 if (__copy_from_user(fx_sw, &buf_fx->sw_reserved[0], sizeof(*fx_sw))) @@ -38,8 +39,9 @@ static inline bool check_xstate_in_sigframe(struct fxregs= _state __user *buf_fx, /* Check for the first magic field and other error scenarios. */ if (fx_sw->magic1 !=3D FP_XSTATE_MAGIC1 || fx_sw->xstate_size < min_xstate_size || - fx_sw->xstate_size > x86_task_fpu(current)->fpstate->user_size || - fx_sw->xstate_size > fx_sw->extended_size) + fx_sw->xstate_size > fpstate->user_size || + fx_sw->xstate_size > fx_sw->extended_size || + fx_sw->extended_size - fx_sw->xstate_size < FP_XSTATE_MAGIC2_SIZE) goto err_setfx; =20 /* @@ -48,11 +50,27 @@ static inline bool check_xstate_in_sigframe(struct fxre= gs_state __user *buf_fx, * fpstate layout with out copying the extended state information * in the memory layout. */ - if (__get_user(magic2, (__u32 __user *)(fpstate + fx_sw->xstate_size))) + if (__get_user(magic2, (__u32 __user *)(buf + fx_sw->xstate_size))) return false; + if (unlikely(magic2 !=3D FP_XSTATE_MAGIC2)) + goto err_setfx; =20 - if (likely(magic2 =3D=3D FP_XSTATE_MAGIC2)) - return true; + if (fx_sw->xstate_size !=3D fpstate->user_size || + fx_sw->xfeatures !=3D fpstate->user_xfeatures) { + unsigned int xsize; + u64 xfeatures; + + /* Calculate size of enabled features only. */ + xfeatures =3D fx_sw->xfeatures & fpstate->user_xfeatures; + + xsize =3D xstate_calculate_size(xfeatures, false); + if (fx_sw->xstate_size < xsize) + return false; + + fx_sw->xstate_size =3D xsize; + } + + return true; err_setfx: /* * The fallback to FX-only state is used to preserve backward @@ -279,7 +297,8 @@ static bool restore_fpregs_from_user_compat(void __user= *buf_f, void __user *buf * Attempt to restore the FPU registers directly from user memory. * Pagefaults are handled and any errors returned are fatal. */ -static bool restore_fpregs_from_user(void __user *buf, u64 xrestore_mask, = bool fx_only) +static bool restore_fpregs_from_user(void __user *buf, u64 xrestore_mask, + bool fx_only, size_t xstate_size) { struct fpu *fpu =3D x86_task_fpu(current); int ret; @@ -313,7 +332,7 @@ static bool restore_fpregs_from_user(void __user *buf, = u64 xrestore_mask, bool f if (ret !=3D X86_TRAP_PF) return false; =20 - if (!fault_in_readable(buf, fpu->fpstate->user_size)) + if (!fault_in_readable(buf, xstate_size)) goto retry; return false; } @@ -339,6 +358,7 @@ static bool __fpu_restore_sig(void __user *buf_f, void = __user *buf_fx) { bool fx_only =3D false; u64 xrestore_mask =3D 0; + size_t xstate_size; =20 if (use_xsave()) { struct _fpx_sw_bytes fx_sw_user; @@ -348,13 +368,15 @@ static bool __fpu_restore_sig(void __user *buf_f, voi= d __user *buf_fx) =20 fx_only =3D !fx_sw_user.magic1; xrestore_mask =3D fx_sw_user.xfeatures; + xstate_size =3D fx_sw_user.xstate_size; } else { xrestore_mask =3D XFEATURE_MASK_FPSSE; + xstate_size =3D sizeof(struct fxregs_state); } =20 if (likely(!buf_f)) { /* Restore the FPU registers directly from user memory. */ - return restore_fpregs_from_user(buf_fx, xrestore_mask, fx_only); + return restore_fpregs_from_user(buf_fx, xrestore_mask, fx_only, xstate_s= ize); } =20 return restore_fpregs_from_user_compat(buf_f, buf_fx, xrestore_mask, fx_o= nly); diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index ed39d7051d0d..b7d0d78d2081 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c @@ -587,7 +587,7 @@ static bool __init check_xstate_against_struct(int nr) return true; } =20 -static unsigned int xstate_calculate_size(u64 xfeatures, bool compacted) +unsigned int xstate_calculate_size(u64 xfeatures, bool compacted) { unsigned int topmost, offset, i; =20 diff --git a/arch/x86/kernel/fpu/xstate.h b/arch/x86/kernel/fpu/xstate.h index 38a2862f09d3..c73cf2444de6 100644 --- a/arch/x86/kernel/fpu/xstate.h +++ b/arch/x86/kernel/fpu/xstate.h @@ -55,6 +55,8 @@ extern int copy_sigframe_from_user_to_xstate(struct task_= struct *tsk, const void extern void fpu__init_cpu_xstate(void); extern void fpu__init_system_xstate(unsigned int legacy_size); =20 +extern unsigned int xstate_calculate_size(u64 xfeatures, bool compacted); + extern void __user *get_xsave_addr_user(struct xregs_state __user *xsave, = int xfeature_nr); =20 static inline u64 xfeatures_mask_supervisor(void) --=20 2.55.0.691.gc56d675ccc-goog From nobody Mon Sep 28 21:52:48 2026 Received: from mail-oo1-f70.google.com (mail-oo1-f70.google.com [209.85.161.70]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 637772FDC28 for ; Mon, 17 Aug 2026 04:21:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.161.70 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786940467; cv=none; b=FGbRzVDuzplN5TXN3iiB+kc+a66jqPSxo204eKbsggdcGHeCkTLiqti0rrDTDTU3R1YB4iqiIXF3y7W3/tP5l/7Qmc6JjCpDgqhz265RJUVLcCxXnzAnmdzuG8y1QeqRAQ5UgUTgH2ORVX7gvCbD0fJNTkNKh2U3CyDQAM/1Qvk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786940467; c=relaxed/simple; bh=ua6URTtpR5hNOIdWlAMkKlywe5eRMh+7ftq1EDn7Vvc=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=V1d65IDRaBG7kZrgt2Iz/4w2N8jyZ1WdOXYXyx5M5KowVM8Z6rwO/ZdCV0wcNW1AmwK6x1HRICqd7mRjSipzTxlkrXBAmsYE+jfXV+JylmPKoTMs7rbRqxV7rjEzbkDJPfC4h3itP626MePnaiKHPqgMlTCFjfYV8eWN+TxzFqg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--avagin.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=Aa+WH6SW; arc=none smtp.client-ip=209.85.161.70 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--avagin.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="Aa+WH6SW" Received: by mail-oo1-f70.google.com with SMTP id 006d021491bc7-6ab4aec4a14so3003599eaf.2 for ; Sun, 16 Aug 2026 21:21:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1786940464; x=1787545264; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=fGTueokr9JHsHAyyUBEdstVedHWswEXJTEA+EvRHyTg=; b=Aa+WH6SWECpQ+AEerlcZs8IwR55KFmMwnGZuZxDO+Ky8Kb9xyKmKSHvSJty7Ct4XQt GPYN98UjDMI6YD8O9eW7rsjiEW0zp+kmbwlq6WvK0oB/LcP/QO0RyjSkHbfvIiIVLUvE BKFRTD7NHDS4ih7AtwfmmmoYMBJf6ZjfM7mTkkiWdJHyk2wJ/b8RmcwmoRIOPi+iLdXI 6v8qqJGg3maMhmE7zcfuVvrnCebqcGUq5LGlsG+tuF+vs+VVLqZ0VUMiaWHOc+opuslm T4699x/9LY8NyODyxxIJ28cOkZ9gycJpjh0fToVytg6h5ql32UhMm06dp3MijNd3l2po xfVg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786940464; x=1787545264; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=fGTueokr9JHsHAyyUBEdstVedHWswEXJTEA+EvRHyTg=; b=WNXQarpHNhL+uIYgF7fUQ+sY+e3rk+WsSQfI8c/70JYoSfNZn4baIHDVv8oCWn0zLf 5Dt+t66xwBt2B6cgI0mwk2/ykXYRvaW5hzNE+9SPEFdYGwjODSc42f3h1N73Sh0jsjO2 aaF5lhaQ2CWGq3S1ErQRp8lT+TgMHBVh+/2AL1aOjQdzPUOWBZEv8fB8GZIsXyCWh/mC ekSq4jebbyC8gL/Vp89uEEUlEp3QpCHAalfUZ4Iw2UwHlIt1YZOJB4IMa5fxXCfm3rXS SDdpbLbSxSPTubPtbHyB+aJGzRp3EdKHVKAjgA1hx6/rdy/WzRIrZDta69/uQr6oGDuG ANsQ== X-Gm-Message-State: AOJu0YyNWcKXE7mQv7czLERHXzqUuEs+C8UFYNOkuqIWhO7g1lQ8fPIT Z4I/Egweh+Aoev75sR0rpm9XIaYPNuLOyokPOUVcpvmZyNh0kFcFAl9GcdB6N2pOx4pAan2seZN YKOnEcg== X-Received: from ilbej10-n1.prod.google.com ([2002:a05:6e02:4e0a:10b0:508:1635:6e4c]) (user=avagin job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6820:1627:b0:6b0:5bd1:4722 with SMTP id 006d021491bc7-6b0d6176dedmr18012014eaf.13.1786940464182; Sun, 16 Aug 2026 21:21:04 -0700 (PDT) Date: Mon, 17 Aug 2026 04:20:48 +0000 In-Reply-To: <20260817042048.1579415-1-avagin@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260817042048.1579415-1-avagin@google.com> X-Mailer: git-send-email 2.55.0.691.gc56d675ccc-goog Message-ID: <20260817042048.1579415-9-avagin@google.com> Subject: [PATCH 8/8] selftests/x86: Add a sigframe insufficient xstate_size test From: Andrei Vagin To: Thomas Gleixner , Ingo Molnar , Borislav Petkov , "Chang S. Bae" Cc: linux-kernel@vger.kernel.org, criu@lists.linux.dev, Dave Hansen , x86@kernel.org, Andrei Vagin , Alexander Mikhalitsyn , "H. Peter Anvin" Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Extend sigframe_fpu_portability to include an insufficient xstate_size check (test_insufficient_xstate_size). Verify that the kernel correctly rejects signal frames where the xstate_size is too small for the enabled features in the xfeatures mask. Reviewed-by: Alexander Mikhalitsyn Signed-off-by: Andrei Vagin --- .../selftests/x86/sigframe_fpu_portability.c | 79 +++++++++++++++++-- 1 file changed, 73 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/x86/sigframe_fpu_portability.c b/tools= /testing/selftests/x86/sigframe_fpu_portability.c index 169548892f92..59d5c6049892 100644 --- a/tools/testing/selftests/x86/sigframe_fpu_portability.c +++ b/tools/testing/selftests/x86/sigframe_fpu_portability.c @@ -12,19 +12,24 @@ #include #include #include +#include =20 #include "helpers.h" #include "xstate.h" =20 /* - * This test verifies the FPU portability of the signal frame. - * It verifies that the kernel correctly restores the xstate context even - * if the frame size has been manually reduced (shrunk), as long as the - * FP_XSTATE_MAGIC2 marker is correctly placed. + * This test verifies the FPU portability and consistency of the signal fr= ame. + * + * - test_shrunk_xstate_size: + * Verifies that the kernel restores state from a frame with xstate_size + * shrunk to only include active features. + * + * - test_insufficient_xstate_size: + * Verifies that the kernel rejects a frame if xstate_size is too small = for + * the features enabled in xfeatures. */ =20 #define SIGFRAME_XSTATE_HDR_OFFSET 512 - #define XSTATE_SSE_ONLY_SIZE (SIGFRAME_XSTATE_HDR_OFFSET + XSAVE_HDR_SIZE) #define XFEATURE_MASK_FPSSE ((1 << XFEATURE_FP) | (1 << XFEATURE_SSE)) =20 @@ -148,15 +153,77 @@ static void test_shrunk_xstate_size(void) clearhandler(SIGUSR1); } =20 +static sigjmp_buf segv_jmpbuf; + +static void handle_segv(int sig, siginfo_t *si, void *ucp) +{ + siglongjmp(segv_jmpbuf, 1); +} + +static void handle_insufficient_xstate_size(int sig, siginfo_t *si, void *= ucp) +{ + ucontext_t *uc =3D ucp; + void *fp =3D uc->uc_mcontext.fpregs; + struct _fpx_sw_bytes *sw; + + if (!fp) { + sig_print("fpregs is NULL\n"); + return; + } + + sw =3D get_fpx_sw_bytes(fp); + if (sw->magic1 !=3D FP_XSTATE_MAGIC1) { + sig_print("magic1 is not valid\n"); + return; + } + + /* The origin frame contains an AVX state. */ + sw->xstate_size =3D XSTATE_SSE_ONLY_SIZE; + + *(uint32_t *)(fp + sw->xstate_size) =3D FP_XSTATE_MAGIC2; +} + +static void test_insufficient_xstate_size(void) +{ + uint64_t v[4] =3D {0, 0, 0, 0}; + + sig_err_buf[0] =3D 0; + sethandler(SIGUSR1, handle_insufficient_xstate_size, 0); + sethandler(SIGSEGV, handle_segv, 0); + + v[0] =3D 0x1111111111111111ULL; + v[1] =3D 0x2222222222222222ULL; + v[2] =3D 0x3333333333333333ULL; + v[3] =3D 0x4444444444444444ULL; + write_ymm0(v); + + if (sigsetjmp(segv_jmpbuf, 1) =3D=3D 0) { + raise(SIGUSR1); + sig_print("Inconsistent size was NOT rejected\n"); + } + + clearhandler(SIGUSR1); + clearhandler(SIGSEGV); + + if (sig_err_buf[0]) + ksft_test_result_fail("%s\n", sig_err_buf); + else + ksft_test_result_pass("Inconsistent size correctly rejected\n"); + + clearhandler(SIGUSR1); + clearhandler(SIGSEGV); +} =20 int main(void) { ksft_print_header(); - ksft_set_plan(1); + ksft_set_plan(2); =20 check_avx_support(); =20 test_shrunk_xstate_size(); + test_insufficient_xstate_size(); + ksft_finished(); return 0; } --=20 2.55.0.691.gc56d675ccc-goog