From nobody Mon May 25 06:40:25 2026 Received: from mail-108-mta185.mxroute.com (mail-108-mta185.mxroute.com [136.175.108.185]) (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 80191298CB2 for ; Sun, 17 May 2026 18:35:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=136.175.108.185 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779042948; cv=none; b=sUdLRTkaek2HFNk5GNHJu6HKo7dIBLcdKb98yis2nybFJxHAUvivb5LhwLjqwq7KZifEc1N2q4hZq+6vVFRvyFJrj5S4wXSwZerGyHevppxDIuOZ6vKgOJ1mafWiERTmnRFZOplha01453CM6k31rfJU8A04THmMkry6NRLU1K8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779042948; c=relaxed/simple; bh=/j8aHXrfZYMx5ZkyWVQrUIv7sxmv3gJCEOG1gnjvaMA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=gwrjiC7Avn+lXzVAb3I/ZASJHJziKZbbEwf27wxBp5HdhzsqKE7fvC0TSpwLf3+WsgHlxNI2nyX4G7MQiHkrazJB1cKlzbDzOxzGjXjHJh8dPlqAB/cPQoB/U6VxTSef+lkD07r/JeKUYYPyaNO4b5dx2zAELPb1oJ7mnb3IKLU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=wii.dev; spf=pass smtp.mailfrom=wii.dev; dkim=fail (0-bit key) header.d=wii.dev header.i=@wii.dev header.b=dziNSDjz reason="key not found in DNS"; arc=none smtp.client-ip=136.175.108.185 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=wii.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=wii.dev Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=wii.dev header.i=@wii.dev header.b="dziNSDjz" Received: from filter006.mxroute.com ([136.175.111.3] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta185.mxroute.com (ZoneMTA) with ESMTPSA id 19e37344fe000067f7.00c for (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Sun, 17 May 2026 18:30:35 +0000 X-Zone-Loop: 8febbf026b519c077fa43a3531212f4a97aab561b63a DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=wii.dev; s=x; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=hISvt7Q9/uti1qoO6ln4lOuHlFanj3DiUngmVUOuBcY=; b=dziNSDjz41/AdrBj/yE9flyiUO yykFzAxBi8uCE3S4cnoVxWsc3vwNVe2SzgS23wpIbOfdX+6LOua2MfGLMiTePOninSyM9aT6YtFHE eOGwiE2e4AYsTMdLpHCPr+JDJv7RLnd+Cc5EakY7ImtMFeFZNNMQckObAK3ljfnwhW0DVfF41TR2I raP4xpRb7+Do3443fHWpLcRnoOuep29VacKD3sxiUjKwt1KQSehVojkcg3buUH7C7kUQJ8zBsufz7 +xbRCMmo7X4HeXK7iuSxtHtHtyZ4R97k936L//Tq+lSulFSlP0rUP1M69lb+dJgxT7mO9NmIQW3YD nFwhGRdg==; From: Richard Patel To: x86@kernel.org Cc: Rick Edgecombe , Yu-cheng Yu , Dave Hansen , Thomas Gleixner , Ingo Molnar , Borislav Petkov , "H. Peter Anvin" , Andy Lutomirski , Kees Cook , Peter Zijlstra , Shuah Khan , linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 1/7] x86: add userspace IBT config option Date: Sun, 17 May 2026 13:30:18 -0500 Message-ID: <20260517183024.16292-2-ripatel@wii.dev> In-Reply-To: <20260517183024.16292-1-ripatel@wii.dev> References: <20260517183024.16292-1-ripatel@wii.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Authenticated-Id: ripatel@wii.dev Content-Type: text/plain; charset="utf-8" Adds a X86_USER_IBT Kconfig option and "nouseribt" command-line option. Default disabled for now. These prepare for userspace support for IBT (forward-edge control flow integrity protection). User IBT works even if kernel IBT is disabled. However, ibt=3Doff also disables user IBT. Signed-off-by: Richard Patel --- arch/x86/Kconfig | 17 +++++++++++++++++ arch/x86/include/asm/cpufeatures.h | 1 + arch/x86/kernel/cet.c | 3 ++- arch/x86/kernel/cpu/common.c | 14 ++++++++++++-- tools/arch/x86/include/asm/cpufeatures.h | 1 + 5 files changed, 33 insertions(+), 3 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index f3f7cb01d69d..12cc944b63c7 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1901,6 +1901,23 @@ config X86_USER_SHADOW_STACK =20 If unsure, say N. =20 +config X86_USER_IBT + bool "X86 userspace indirect branch tracking" + depends on X86_64 + select X86_CET + help + Support Indirect Branch Tracking protection for userspace + applications. IBT is a hardware-supported coarse-grained + forward-edge Control Flow Integrity protection feature. + It enforces that all indirect calls must land on an ENDBR + instruction. Applications must be enabled to use it, and old + userspace does not get protection "for free". Enables the + PR_CFI_BRANCH_LANDING_PADS prctl CFI option. + + CPUs supporting IBT were first released in 2021. + + If unsure, say N. + config INTEL_TDX_HOST bool "Intel Trust Domain Extensions (TDX) host support" depends on CPU_SUP_INTEL diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpuf= eatures.h index 1d506e5d6f46..1825cbf864c0 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -516,6 +516,7 @@ * and purposes if CLEAR_CPU_BUF_VM is set). */ #define X86_FEATURE_X2AVIC_EXT (21*32+20) /* AMD SVM x2AVIC support for 4= k vCPUs */ +#define X86_FEATURE_USER_IBT (21*32+21) /* Indirect Branch Tracking for u= ser mode applications */ =20 /* * BUG word(s) diff --git a/arch/x86/kernel/cet.c b/arch/x86/kernel/cet.c index 99444409c026..3ccf47e82da1 100644 --- a/arch/x86/kernel/cet.c +++ b/arch/x86/kernel/cet.c @@ -149,7 +149,8 @@ __setup("ibt=3D", ibt_setup); DEFINE_IDTENTRY_ERRORCODE(exc_control_protection) { if (user_mode(regs)) { - if (cpu_feature_enabled(X86_FEATURE_USER_SHSTK)) + if (cpu_feature_enabled(X86_FEATURE_USER_SHSTK) || + cpu_feature_enabled(X86_FEATURE_USER_IBT)) do_user_cp_fault(regs, error_code); else do_unexpected_cp(regs, error_code); diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index a4268c47f2bc..2839edd92331 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -634,7 +634,7 @@ __noendbr void ibt_restore(u64 save) =20 static __always_inline void setup_cet(struct cpuinfo_x86 *c) { - bool user_shstk, kernel_ibt; + bool user_shstk, kernel_ibt, user_ibt; =20 if (!IS_ENABLED(CONFIG_X86_CET)) return; @@ -642,13 +642,19 @@ static __always_inline void setup_cet(struct cpuinfo_= x86 *c) kernel_ibt =3D HAS_KERNEL_IBT && cpu_feature_enabled(X86_FEATURE_IBT); user_shstk =3D cpu_feature_enabled(X86_FEATURE_SHSTK) && IS_ENABLED(CONFIG_X86_USER_SHADOW_STACK); + /* User IBT only needs hardware IBT, not kernel-enabled IBT. */ + user_ibt =3D cpu_has(c, X86_FEATURE_IBT) && + IS_ENABLED(CONFIG_X86_USER_IBT); =20 - if (!kernel_ibt && !user_shstk) + if (!kernel_ibt && !user_shstk && !user_ibt) return; =20 if (user_shstk) set_cpu_cap(c, X86_FEATURE_USER_SHSTK); =20 + if (user_ibt) + set_cpu_cap(c, X86_FEATURE_USER_IBT); + if (kernel_ibt) wrmsrq(MSR_IA32_S_CET, CET_ENDBR_EN); else @@ -666,6 +672,7 @@ static __always_inline void setup_cet(struct cpuinfo_x8= 6 *c) __noendbr void cet_disable(void) { if (!(cpu_feature_enabled(X86_FEATURE_IBT) || + cpu_feature_enabled(X86_FEATURE_USER_IBT) || cpu_feature_enabled(X86_FEATURE_SHSTK))) return; =20 @@ -1760,6 +1767,9 @@ static void __init cpu_parse_early_param(void) if (cmdline_find_option_bool(boot_command_line, "nousershstk")) setup_clear_cpu_cap(X86_FEATURE_USER_SHSTK); =20 + if (cmdline_find_option_bool(boot_command_line, "nouseribt")) + setup_clear_cpu_cap(X86_FEATURE_USER_IBT); + /* Minimize the gap between FRED is available and available but disabled.= */ arglen =3D cmdline_find_option(boot_command_line, "fred", arg, sizeof(arg= )); if (arglen =3D=3D 3 && !strncmp(arg, "off", 3)) diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/incl= ude/asm/cpufeatures.h index 86d17b195e79..1cf22d27c7a1 100644 --- a/tools/arch/x86/include/asm/cpufeatures.h +++ b/tools/arch/x86/include/asm/cpufeatures.h @@ -515,6 +515,7 @@ * and purposes if CLEAR_CPU_BUF_VM is set). */ #define X86_FEATURE_X2AVIC_EXT (21*32+20) /* AMD SVM x2AVIC support for 4= k vCPUs */ +#define X86_FEATURE_USER_IBT (21*32+21) /* Indirect Branch Tracking for u= ser mode applications */ =20 /* * BUG word(s) --=20 2.47.3 From nobody Mon May 25 06:40:25 2026 Received: from mail-108-mta212.mxroute.com (mail-108-mta212.mxroute.com [136.175.108.212]) (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 682153CC7EC for ; Sun, 17 May 2026 18:35:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=136.175.108.212 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779042953; cv=none; b=TPVm7Z1NA30FzL7wblI1B+Wj+kInbKsrx9V47KU6bRNgRjLaO43Xj+ufJrH5XFazzhHt3ezQ0OPKZmvITz5jG4m29Muxrs6HjmS0fotfr4M+NmPZT391f+lu5/G3+NOTwS+sfR9LF1tItGTaex0M+BDd+bFG4eNhQfHXioVC56Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779042953; c=relaxed/simple; bh=b5WOFM52SN13MEtWftN752/9cLw0JVPazUMHSdNkRmc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=aQxXNSUafqYZ3TR4upSfcpMM8lhC4DInUWNr5Dl/YvJoul67ibc0cboNHHoFibjDFsqkNxDs2lJu26Qv0ctblmUL1bwtUMTc8nhcR0wlR0osB83vJLwhnQZk+fKYWUB5Wxj//MWfuybHIanrmmr+ALL1D8yMUXPSPNdzQBWmsr0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=wii.dev; spf=pass smtp.mailfrom=wii.dev; dkim=fail (0-bit key) header.d=wii.dev header.i=@wii.dev header.b=PSmxD8ew reason="key not found in DNS"; arc=none smtp.client-ip=136.175.108.212 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=wii.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=wii.dev Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=wii.dev header.i=@wii.dev header.b="PSmxD8ew" Received: from filter006.mxroute.com ([136.175.111.3] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta212.mxroute.com (ZoneMTA) with ESMTPSA id 19e37345e5700067f7.00c for (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Sun, 17 May 2026 18:30:39 +0000 X-Zone-Loop: 0b627e20035001d6e17b51e04eb6774005beddd173ca DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=wii.dev; s=x; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=ZjosEJpA1eXZ50hc7mf1XeR3qMEd5tWpuh367jDJpcc=; b=PSmxD8ewiMCz1ScvdSfi8f+EQL IAL5//DWcIuhw6ps49JXXZmkio18k9x/TlqE5cDkdwfqQ5Rg6H94NFbXbwY8RiJZiCgVWRUPveHvS tcFX3f15NCgga++KnOAitugfqKC0vp7FTfXojnAgcAhse5rahnO8iGud8swYUK+e0/7t3m2Z1T318 iQUHBkJWShIRKOfEur8rUkl9W+xrKFh9pr2WrW1hEPQoJ5re1EoP7nIRMXJNl0u2W31GLD1aDhkCD RKts/3W+DwxMhthcsCeo2o6QJJzOpbHRoXp85zakTJm2vyXsjXz1noEr1geYYKy4C0ORtu311knvs RGIbL8zQ==; From: Richard Patel To: x86@kernel.org Cc: Rick Edgecombe , Yu-cheng Yu , Dave Hansen , Thomas Gleixner , Ingo Molnar , Borislav Petkov , "H. Peter Anvin" , Andy Lutomirski , Kees Cook , Peter Zijlstra , Shuah Khan , linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 2/7] x86: shstk: don't clobber IBT bits in U_CET MSR Date: Sun, 17 May 2026 13:30:19 -0500 Message-ID: <20260517183024.16292-3-ripatel@wii.dev> In-Reply-To: <20260517183024.16292-1-ripatel@wii.dev> References: <20260517183024.16292-1-ripatel@wii.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Authenticated-Id: ripatel@wii.dev Content-Type: text/plain; charset="utf-8" Updates usermode shadow stack code to not set IBT-related bits in the U_CET MSR. Signed-off-by: Richard Patel --- arch/x86/kernel/shstk.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/shstk.c b/arch/x86/kernel/shstk.c index 0ca64900192f..ff4106dcfec4 100644 --- a/arch/x86/kernel/shstk.c +++ b/arch/x86/kernel/shstk.c @@ -150,6 +150,7 @@ static int shstk_setup(void) { struct thread_shstk *shstk =3D ¤t->thread.shstk; unsigned long addr, size; + u64 msrval; =20 /* Already enabled */ if (features_enabled(ARCH_SHSTK_SHSTK)) @@ -166,7 +167,10 @@ static int shstk_setup(void) =20 fpregs_lock_and_load(); wrmsrq(MSR_IA32_PL3_SSP, addr + size); - wrmsrq(MSR_IA32_U_CET, CET_SHSTK_EN); + rdmsrq(MSR_IA32_U_CET, msrval); + msrval &=3D ~CET_WRSS_EN; + msrval |=3D CET_SHSTK_EN; + wrmsrq(MSR_IA32_U_CET, msrval); fpregs_unlock(); =20 shstk->base =3D addr; @@ -520,6 +524,8 @@ static int wrss_control(bool enable) =20 static int shstk_disable(void) { + u64 msrval; + if (!cpu_feature_enabled(X86_FEATURE_USER_SHSTK)) return -EOPNOTSUPP; =20 @@ -528,8 +534,10 @@ static int shstk_disable(void) return 0; =20 fpregs_lock_and_load(); + rdmsrq(MSR_IA32_U_CET, msrval); /* Disable WRSS too when disabling shadow stack */ - wrmsrq(MSR_IA32_U_CET, 0); + msrval &=3D ~(CET_SHSTK_EN | CET_WRSS_EN); + wrmsrq(MSR_IA32_U_CET, msrval); wrmsrq(MSR_IA32_PL3_SSP, 0); fpregs_unlock(); =20 --=20 2.47.3 From nobody Mon May 25 06:40:25 2026 Received: from mail-108-mta158.mxroute.com (mail-108-mta158.mxroute.com [136.175.108.158]) (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 728813CC9F3 for ; Sun, 17 May 2026 18:35:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=136.175.108.158 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779042953; cv=none; b=mqERYIdclT9XAMKvP6gwZbU0TWH+cxepGw3dt47nbrEU/94yy5+iO653eJzk29iYFCs4D40pAWECNck07YeTXv4wEl3pztcwLGgfaUS0gtFbVx5e6bulmTx6mZJ6jkXQlXIC7bPSTdL2Tmx0aK1EbPSde4CyURYVkaEIXcUjNwY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779042953; c=relaxed/simple; bh=xeReBSOSsVkWQnbyMV8OsE+FLzgdoiGUrh7bN9xLWM4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=k/sAz3fGN5neFww1hWGISVSkbUl+rDazXRgoW2XUJN15LRQjl4E/Q8EkykkIukOxVfGwsTfpRc+nbRt+wtBvU0xnd0sWL3Mo6xSXG7qoymrH4Ix+C5jPynzeMzJ7At2VPjL3IrWSBeYEoSZTGzp3Nw4WZ66Gjsmh9YXUJ1wbeQk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=wii.dev; spf=pass smtp.mailfrom=wii.dev; dkim=fail (0-bit key) header.d=wii.dev header.i=@wii.dev header.b=vveJHAAR reason="key not found in DNS"; arc=none smtp.client-ip=136.175.108.158 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=wii.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=wii.dev Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=wii.dev header.i=@wii.dev header.b="vveJHAAR" Received: from filter006.mxroute.com ([136.175.111.3] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta158.mxroute.com (ZoneMTA) with ESMTPSA id 19e37346a3500067f7.00c for (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Sun, 17 May 2026 18:30:42 +0000 X-Zone-Loop: e258924fe3418e48bd540841317b93839d7e8f7bf55d DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=wii.dev; s=x; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=oi/FD+FVH2L6lffeDf4O/BKtqSjIgXeeFp6Po4P/CGI=; b=vveJHAARWyqcrfRODc0xyevwml TnfGyHeQ8NdmN8GLEoZEqsyDEKGD05QkRcgFd+ZJHP+4PNB+50tWcfGsd7JnQippJXtkKqfspeSHN GxvKugF/3fdTXBNtUxeTRtsRd7gvCXVl+FdmJOgGmWg+maIMQqbgniq559VfGiZUc9WFUGzwB4p7b x8/akAedXmp8RBkKFREA7deqyibshtDr94eY4ZAfct2jjcsiSxbT7p+ZgDiPJhZwBEZBq9GpDeSRl B1N38yO5C6DDiDfePCOkKKObPFEdhF5kORn6n9LhttCUGIcT720XTWAZ6+wRoCiSa0BrXlpSqZfcD +XjF2MNg==; From: Richard Patel To: x86@kernel.org Cc: Rick Edgecombe , Yu-cheng Yu , Dave Hansen , Thomas Gleixner , Ingo Molnar , Borislav Petkov , "H. Peter Anvin" , Andy Lutomirski , Kees Cook , Peter Zijlstra , Shuah Khan , linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 3/7] x86: signal handler support for IBT Date: Sun, 17 May 2026 13:30:20 -0500 Message-ID: <20260517183024.16292-4-ripatel@wii.dev> In-Reply-To: <20260517183024.16292-1-ripatel@wii.dev> References: <20260517183024.16292-1-ripatel@wii.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Authenticated-Id: ripatel@wii.dev Content-Type: text/plain; charset="utf-8" Addresses an edge case in usermode IBT with signal handlers. When entering and exiting signals, the WAIT_FOR_ENDBR CPU state must be restored. WAIT_FOR_ENDBR is a flag that raises a CET violation if the next instruction is not endbr64. If a thread enters a signal handler immediately after executing an indirect jump (before reaching an endbr64), the WAIT_FOR_ENDBR would otherwise mistakenly cause a CET violation on the signal handler's first instruction. Worse, an attacker could circumvent IBT by triggering a signal before a vulnerable jump, call rt_sigreturn in that signal, and then return to the original indirect jump target without endbr64 checking. Unless FRED is enabled, the WAIT_FOR_ENDBR flag is backed up from the U_CET MSR. Due to XSAVE, this MSR might be stale in kernel-mode. A gap in 32-bit signal handling is resolved in a follow-up commit. Based-on-patch-by: Yu-cheng Yu Link: https://lore.kernel.org/lkml/20210820182245.1188-4-yu-cheng.yu@intel.= com/ Signed-off-by: Richard Patel --- arch/x86/include/asm/ibt.h | 14 +++++ arch/x86/include/asm/processor.h | 5 ++ arch/x86/include/uapi/asm/ucontext.h | 5 ++ arch/x86/kernel/Makefile | 1 + arch/x86/kernel/ibt.c | 88 ++++++++++++++++++++++++++++ arch/x86/kernel/signal_64.c | 6 ++ 6 files changed, 119 insertions(+) create mode 100644 arch/x86/kernel/ibt.c diff --git a/arch/x86/include/asm/ibt.h b/arch/x86/include/asm/ibt.h index 5e45d6424722..3fe464bf83e7 100644 --- a/arch/x86/include/asm/ibt.h +++ b/arch/x86/include/asm/ibt.h @@ -114,4 +114,18 @@ static inline void ibt_restore(u64 save) { } =20 #define ENDBR_INSN_SIZE (4*HAS_KERNEL_IBT) =20 +#ifndef __ASSEMBLER__ + +struct pt_regs; + +#ifdef CONFIG_X86_USER_IBT +bool user_ibt_pop_wait_endbr(struct pt_regs *regs); +void user_ibt_restore_wait_endbr(struct pt_regs *regs, bool wait_endbr); +#else +static inline bool user_ibt_pop_wait_endbr(struct pt_regs *regs) { return = false; } +static inline void user_ibt_restore_wait_endbr(struct pt_regs *regs, bool = wait_endbr) {} +#endif /* CONFIG_X86_USER_IBT */ + +#endif /* __ASSEMBLER__ */ + #endif /* _ASM_X86_IBT_H */ diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/proces= sor.h index 10b5355b323e..6ce8f7b6607c 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -504,6 +504,11 @@ struct thread_struct { =20 unsigned int iopl_warn:1; =20 +#ifdef CONFIG_X86_USER_IBT + unsigned int ibt:1; + unsigned int ibt_locked:1; +#endif + /* * Protection Keys Register for Userspace. Loaded immediately on * context switch. Store it in thread_struct to avoid a lookup in diff --git a/arch/x86/include/uapi/asm/ucontext.h b/arch/x86/include/uapi/a= sm/ucontext.h index 5657b7a49f03..0271f5e8aa14 100644 --- a/arch/x86/include/uapi/asm/ucontext.h +++ b/arch/x86/include/uapi/asm/ucontext.h @@ -51,6 +51,11 @@ #define UC_STRICT_RESTORE_SS 0x4 #endif =20 +/* + * Indicates IBT status WAIT_FOR_ENDBR. + */ +#define UC_WAIT_ENDBR 0x8 + #include =20 #endif /* _ASM_X86_UCONTEXT_H */ diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 47a32f583930..05c87f014552 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -169,6 +169,7 @@ obj-$(CONFIG_CALL_THUNKS) +=3D callthunks.o obj-$(CONFIG_X86_CET) +=3D cet.o =20 obj-$(CONFIG_X86_USER_SHADOW_STACK) +=3D shstk.o +obj-$(CONFIG_X86_USER_IBT) +=3D ibt.o =20 ### # 64 bit specific files diff --git a/arch/x86/kernel/ibt.c b/arch/x86/kernel/ibt.c new file mode 100644 index 000000000000..596b0629106d --- /dev/null +++ b/arch/x86/kernel/ibt.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include + +static bool user_ibt_enabled(struct task_struct *task) +{ + return task->thread.ibt; +} + +bool user_ibt_pop_wait_endbr(struct pt_regs *regs) +{ + struct fpu *fpu =3D x86_task_fpu(current); + u64 msrval =3D 0; + + if (!user_ibt_enabled(current)) + return 0; + +#ifdef CONFIG_X86_FRED + if (cpu_feature_enabled(X86_FEATURE_FRED)) { + msrval =3D regs->fred_cs.wfe; + regs->fred_cs.wfe =3D 0; + return !!msrval; + } +#endif + + fpregs_lock(); + + if (!test_thread_flag(TIF_NEED_FPU_LOAD)) { + if (!rdmsrq_safe(MSR_IA32_U_CET, &msrval)) + wrmsrq(MSR_IA32_U_CET, msrval & ~CET_WAIT_ENDBR); + } else { + struct cet_user_state *cet; + + /* + * If TIF_NEED_FPU_LOAD and get_xsave_addr() returns zero, + * XFEATURE_CET_USER is in init state (cet is not active). + * Return zero status. + */ + cet =3D get_xsave_addr(&fpu->fpstate->regs.xsave, + XFEATURE_CET_USER); + if (cet) { + msrval =3D cet->user_cet; + cet->user_cet =3D msrval & ~CET_WAIT_ENDBR; + } + } + + fpregs_unlock(); + + return !!(msrval & CET_WAIT_ENDBR); +} + +void +user_ibt_restore_wait_endbr(struct pt_regs *regs, bool wait_endbr) +{ + struct fpu *fpu =3D x86_task_fpu(current); + u64 msrval =3D 0; + + if (!user_ibt_enabled(current)) + return; + +#ifdef CONFIG_X86_FRED + if (cpu_feature_enabled(X86_FEATURE_FRED)) { + regs->fred_cs.wfe =3D wait_endbr; + return; + } +#endif + + if (!wait_endbr) + return; + + fpregs_lock(); + + if (!test_thread_flag(TIF_NEED_FPU_LOAD)) { + if (!rdmsrq_safe(MSR_IA32_U_CET, &msrval)) + wrmsrq(MSR_IA32_U_CET, msrval | CET_WAIT_ENDBR); + } else { + struct cet_user_state *cet; + + cet =3D get_xsave_addr(&fpu->fpstate->regs.xsave, + XFEATURE_CET_USER); + if (cet) + cet->user_cet |=3D CET_WAIT_ENDBR; + } + + fpregs_unlock(); +} diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c index d483b585c6c6..9f1861540d27 100644 --- a/arch/x86/kernel/signal_64.c +++ b/arch/x86/kernel/signal_64.c @@ -14,6 +14,7 @@ =20 #include #include +#include #include =20 #include @@ -92,6 +93,8 @@ static bool restore_sigcontext(struct pt_regs *regs, if (unlikely(!(uc_flags & UC_STRICT_RESTORE_SS) && user_64bit_mode(regs))) force_valid_ss(regs); =20 + user_ibt_restore_wait_endbr(regs, uc_flags & UC_WAIT_ENDBR); + return fpu__restore_sig((void __user *)sc.fpstate, 0); } =20 @@ -158,6 +161,9 @@ static unsigned long frame_uc_flags(struct pt_regs *reg= s) if (likely(user_64bit_mode(regs))) flags |=3D UC_STRICT_RESTORE_SS; =20 + if (user_ibt_pop_wait_endbr(regs)) + flags |=3D UC_WAIT_ENDBR; + return flags; } =20 --=20 2.47.3 From nobody Mon May 25 06:40:25 2026 Received: from mail-108-mta149.mxroute.com (mail-108-mta149.mxroute.com [136.175.108.149]) (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 7D0693CD8A3 for ; Sun, 17 May 2026 18:35:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=136.175.108.149 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779042953; cv=none; b=GWsptUe/w0/kg0TkEOf7GoVnLWD6/tEKXH5dL+NldV6BnJhfOBmFG39r1PuRn1lXgsHkCvO8V6qve6nhr/etxm5aqP1r0SNlgRrAVW4WPXUAWcVau0ze8su8E7iDB1MP10VOlYLViMZM4nwYhXQdunfclDoQZkC4WZsHqJZJVjM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779042953; c=relaxed/simple; bh=6BYRV3L5PLKVoAAO31KqAH45okWzIVfiavyBzR9/wR4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=fPm8+v7maHvkLYnG7i59R3X9J7AwhfjdcEv33JzRCgSuClXlkf6imGhnj6cAZgcZ+IbyirfSmEBCVgb8/SsttBVj8oouMUe/LGyDwArX2agr5lACzCDmoPzNCC3YvpdIFID5ftuxIVjCsSvSfNQjagH4Yba6YLJt8aP9b/D0+Cc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=wii.dev; spf=pass smtp.mailfrom=wii.dev; dkim=fail (0-bit key) header.d=wii.dev header.i=@wii.dev header.b=VNMZXllS reason="key not found in DNS"; arc=none smtp.client-ip=136.175.108.149 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=wii.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=wii.dev Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=wii.dev header.i=@wii.dev header.b="VNMZXllS" Received: from filter006.mxroute.com ([136.175.111.3] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta149.mxroute.com (ZoneMTA) with ESMTPSA id 19e37346c3e00067f7.00c for (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Sun, 17 May 2026 18:30:43 +0000 X-Zone-Loop: 2ddeb096aaf9cf653dd390ce1d4658fe70dab8824a6d DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=wii.dev; s=x; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=3tHMER9SaYBsMWHifDDjYrpCxUmD2yWxiNZjkSjvogU=; b=VNMZXllS0Qt70Zgpk00r/oPCez 11jO33K/ki/vWsGmX7rFvAP8A4tgVlpjol2rBAanP9Of2aYOh0oa1IKH3qUgwLHJA1XjBrRJ8xZ6e Bpnp5mnTxcxrN1W8PvvBpjrVvoHrBijtzhkPwndcfsZh4z9Zz9DaURGHMWdnSOsatiIIcq51H9A6J w211yxCylt4q8fKxN9QlVrZUbLPkpDtydXpH4oALs821n/8YNCYHbZjiUUsoNnwImcbrS3ctPFksw Q+OyrkFOZdPWZLR/KXwI/+8PlcqbhY3m78XKR2GiCUY6MO87/0GSrFXpRlz88rs0CIbM2u2TY9mVt cbVWYf+w==; From: Richard Patel To: x86@kernel.org Cc: Rick Edgecombe , Yu-cheng Yu , Dave Hansen , Thomas Gleixner , Ingo Molnar , Borislav Petkov , "H. Peter Anvin" , Andy Lutomirski , Kees Cook , Peter Zijlstra , Shuah Khan , linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 4/7] x86: ban 32-bit sigreturn when user IBT enabled Date: Sun, 17 May 2026 13:30:21 -0500 Message-ID: <20260517183024.16292-5-ripatel@wii.dev> In-Reply-To: <20260517183024.16292-1-ripatel@wii.dev> References: <20260517183024.16292-1-ripatel@wii.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Authenticated-Id: ripatel@wii.dev Content-Type: text/plain; charset="utf-8" IBT enforces that indirect branch targets land on an endbr instruction. The CPU enforces this by setting the 'WAIT_FOR_ENDBR' bit after executing an indirect branch/jump. The only relevant edge case with user IBT is signal handling: When entering/leaving a signal handler, the WAIT_FOR_ENDBR bit must be backed up/restored. IBT is not implemented for 32-bit and cannot be enabled using a 32-bit syscall. However, a 64-bit thread could far jump into 32-bit. Therefore, 32-bit sigreturn must be banned until IBT supports that environment. Signed-off-by: Richard Patel Based-on-patch-by: Yu-cheng Yu Link: https://lwn.net/ml/linux-kernel/20210830182221.3535-5-yu-cheng.yu@int= el.com/ --- arch/x86/kernel/signal_32.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal_32.c index e55cf19e68fe..7cb76d794366 100644 --- a/arch/x86/kernel/signal_32.c +++ b/arch/x86/kernel/signal_32.c @@ -143,6 +143,11 @@ static bool ia32_restore_sigcontext(struct pt_regs *re= gs, regs->ds =3D fixup_rpl(sc.ds); #endif =20 +#ifdef CONFIG_X86_USER_IBT + if (current->thread.ibt) + return false; +#endif + return fpu__restore_sig(compat_ptr(sc.fpstate), 1); } =20 --=20 2.47.3 From nobody Mon May 25 06:40:25 2026 Received: from mail-108-mta249.mxroute.com (mail-108-mta249.mxroute.com [136.175.108.249]) (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 A60703C09E0 for ; Sun, 17 May 2026 18:35:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=136.175.108.249 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779042960; cv=none; b=eUV6OWWrt89l8FYpu3/kl8S1j66ucQc5Cc/R5TLMgGuOkw/ERQG0blE5+stELdxdndksIthyWVOV5Q4TVJFAULwyNcujxW8JQ4hzYe1UWzW02WZHfWBZ0XPlX6f3tQL6Y8QiqlCmG7awYqWzobp2PUAbuH1fs8Ticw7ZMN1O0lc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779042960; c=relaxed/simple; bh=nzkSeffIK+gjPwyOs7CPx0rKZ0wFtGra/6Hr/w1xvVQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=q6FXVwUwsjAX+iBx9+aFbWVUTKLvyOPeVacjASrTAA9JKd+osU1sOuOJAW5oQfbecT1zmzV47w8UNlOSkRaiJeu6YX75Ppo+jhsdN+JroW0a0J9aoR4rX1BaVqWG7mHRwm1rsQvuI82m2U9p5wOe1DWpEJYz06We7RPOsphWFxk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=wii.dev; spf=pass smtp.mailfrom=wii.dev; dkim=fail (0-bit key) header.d=wii.dev header.i=@wii.dev header.b=Id64VS9Q reason="key not found in DNS"; arc=none smtp.client-ip=136.175.108.249 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=wii.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=wii.dev Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=wii.dev header.i=@wii.dev header.b="Id64VS9Q" Received: from filter006.mxroute.com ([136.175.111.3] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta249.mxroute.com (ZoneMTA) with ESMTPSA id 19e37347b6100067f7.00c for (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Sun, 17 May 2026 18:30:46 +0000 X-Zone-Loop: d42bdabd33c2bcc63ff1bf2533d698dc7f27255c279d DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=wii.dev; s=x; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=rOYOSG9vWxa4zChVZ2uDWaCD4UCDHihRbzaFMlB+lKE=; b=Id64VS9Qd8ejJVKC/9/9mJrMnT ZCcDNhRLr7ch74kS4/j8ebw398JWGxET0ZdK/WTB7g1nrEVIMiCJ6CtqwugdxWsvdPXIz3QvfIFqR fyzkLA0KRgxRE1fAW8Z48jDScivfWCVkWyeor+VWUAwUIrdIuuIwLSwKqRhJWHTXnN+Ma9bTOMLhv E64CWMN8Y5/4SE+FHmfVDogeljuaQVhZv9KZ74vFbc/UwwottmB9GWfhlU11JRoIlL7E9T7xwS+to bNYANXnf9rJTaLnOj1bOHrTNmaWeU4K351QQT7TRjkMGFuh5/o2B6mC5fqiBKC6uWOpDclFtM+LcJ j6sVuXSg==; From: Richard Patel To: x86@kernel.org Cc: Rick Edgecombe , Yu-cheng Yu , Dave Hansen , Thomas Gleixner , Ingo Molnar , Borislav Petkov , "H. Peter Anvin" , Andy Lutomirski , Kees Cook , Peter Zijlstra , Shuah Khan , linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 5/7] x86: expose user IBT via PR_CFI_BRANCH_LANDING_PADS Date: Sun, 17 May 2026 13:30:22 -0500 Message-ID: <20260517183024.16292-6-ripatel@wii.dev> In-Reply-To: <20260517183024.16292-1-ripatel@wii.dev> References: <20260517183024.16292-1-ripatel@wii.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Authenticated-Id: ripatel@wii.dev Content-Type: text/plain; charset="utf-8" Allows userspace applications to enable IBT (forward-edge control flow integrity protection) using the portable PR_CFI prctl API. The name 'branch landing pads' is RISC-V specific, but the mechanism is nearly identical in x86. This setting enables the following MSR_IA32_U_CET bits: - CET_ENDBR_EN (enforce endbr as indirect branch target) - CET_NOTRACK_EN (jump modifier to opt-out of IBT checking) Kernel-mode IBT (as part of CFI) bans notrack. A future prctl flag could be introduced to ban notrack in usermode too. Signed-off-by: Richard Patel --- arch/x86/include/asm/ibt.h | 2 + arch/x86/kernel/ibt.c | 87 ++++++++++++++++++++++++++++++++++++ arch/x86/kernel/process_64.c | 2 + 3 files changed, 91 insertions(+) diff --git a/arch/x86/include/asm/ibt.h b/arch/x86/include/asm/ibt.h index 3fe464bf83e7..a67c9ceaaf9e 100644 --- a/arch/x86/include/asm/ibt.h +++ b/arch/x86/include/asm/ibt.h @@ -121,9 +121,11 @@ struct pt_regs; #ifdef CONFIG_X86_USER_IBT bool user_ibt_pop_wait_endbr(struct pt_regs *regs); void user_ibt_restore_wait_endbr(struct pt_regs *regs, bool wait_endbr); +void reset_thread_ibt(void); #else static inline bool user_ibt_pop_wait_endbr(struct pt_regs *regs) { return = false; } static inline void user_ibt_restore_wait_endbr(struct pt_regs *regs, bool = wait_endbr) {} +static inline void reset_thread_ibt(void) {} #endif /* CONFIG_X86_USER_IBT */ =20 #endif /* __ASSEMBLER__ */ diff --git a/arch/x86/kernel/ibt.c b/arch/x86/kernel/ibt.c index 596b0629106d..343e6fd5dab0 100644 --- a/arch/x86/kernel/ibt.c +++ b/arch/x86/kernel/ibt.c @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 =20 #include +#include +#include #include #include =20 @@ -9,6 +11,85 @@ static bool user_ibt_enabled(struct task_struct *task) return task->thread.ibt; } =20 +static bool user_ibt_locked(struct task_struct *task) +{ + return task->thread.ibt_locked; +} + +static void user_ibt_set_lock(struct task_struct *task, bool lock) +{ + task->thread.ibt_locked =3D lock; +} + +static void user_ibt_set_enable(bool enable) +{ + u64 msrval; + + /* Already enabled */ + if (user_ibt_enabled(current) =3D=3D enable) + return; + + current->thread.ibt =3D !!enable; + + fpregs_lock_and_load(); + rdmsrq(MSR_IA32_U_CET, msrval); + if (enable) + msrval |=3D CET_ENDBR_EN | CET_NO_TRACK_EN; + else + msrval &=3D ~(CET_ENDBR_EN | CET_NO_TRACK_EN); + msrval &=3D ~CET_WAIT_ENDBR; + wrmsrq(MSR_IA32_U_CET, msrval); + fpregs_unlock(); +} + +int arch_prctl_get_branch_landing_pad_state(struct task_struct *t, + unsigned long __user *state) +{ + unsigned long status =3D 0; + + if (!cpu_feature_enabled(X86_FEATURE_USER_IBT) || in_ia32_syscall()) + return -EINVAL; + + status =3D (user_ibt_enabled(t) ? PR_CFI_ENABLE : PR_CFI_DISABLE); + status |=3D (user_ibt_locked(t) ? PR_CFI_LOCK : 0); + + return copy_to_user(state, &status, sizeof(status)) ? -EFAULT : 0; +} + +int arch_prctl_set_branch_landing_pad_state(struct task_struct *t, unsigne= d long state) +{ + if (!cpu_feature_enabled(X86_FEATURE_USER_IBT) || in_ia32_syscall()) + return -EINVAL; + + if (t !=3D current) + return -EINVAL; + + if (user_ibt_locked(t)) + return -EINVAL; + + if (!(state & (PR_CFI_ENABLE | PR_CFI_DISABLE))) + return -EINVAL; + + if (state & PR_CFI_ENABLE && state & PR_CFI_DISABLE) + return -EINVAL; + + user_ibt_set_enable(!!(state & PR_CFI_ENABLE)); + + return 0; +} + +int arch_prctl_lock_branch_landing_pad_state(struct task_struct *task) +{ + if (!cpu_feature_enabled(X86_FEATURE_USER_IBT) || + !user_ibt_enabled(task) || + in_ia32_syscall()) + return -EINVAL; + + user_ibt_set_lock(task, true); + + return 0; +} + bool user_ibt_pop_wait_endbr(struct pt_regs *regs) { struct fpu *fpu =3D x86_task_fpu(current); @@ -86,3 +167,9 @@ user_ibt_restore_wait_endbr(struct pt_regs *regs, bool w= ait_endbr) =20 fpregs_unlock(); } + +void reset_thread_ibt(void) +{ + current->thread.ibt =3D false; + current->thread.ibt_locked =3D false; +} diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index b85e715ebb30..4b727cc7bccb 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -59,6 +59,7 @@ #include #include #include +#include #ifdef CONFIG_IA32_EMULATION /* Not included via unistd.h */ #include @@ -540,6 +541,7 @@ start_thread_common(struct pt_regs *regs, unsigned long= new_ip, } =20 reset_thread_features(); + reset_thread_ibt(); =20 loadsegment(fs, 0); loadsegment(es, _ds); --=20 2.47.3 From nobody Mon May 25 06:40:25 2026 Received: from mail-108-mta170.mxroute.com (mail-108-mta170.mxroute.com [136.175.108.170]) (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 828603C76AD for ; Sun, 17 May 2026 18:36:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=136.175.108.170 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779042964; cv=none; b=abq0RRbj3q4HmiRqAyT3BGSSMRtrEDTUhYgYsFHvAJKL0e7jAJrTEGOIZnEfAR3lJuPtYMnPVXNvZUS/BsB25BI/M6JOvOTumba4lEVFiIJDiU131NLZKkLzkbDVj8nC40GwSFhEyfG9CxnjV70M0U6ZXW4SxZxT5ce+G82jn14= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779042964; c=relaxed/simple; bh=U881s5n9/+Yxk0Tltn7Rw415Nvtzme8MYOKwt5z08hY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=kXBV4xg6tGUzAYoovJkIJ/wEEUp/RNxhXwWk7dWl1HaeeGVx4MmXe2Lchi6z2zDtX9ZpGKKrJkiLg9x0+h2WloLE8d1c6FVl+hwu/qI+mARXbLslnquza0eQAEy9ZHW32ipK8i3dwovtT6dSH930MwMNAicuf/i0AuRWdCovqfI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=wii.dev; spf=pass smtp.mailfrom=wii.dev; dkim=fail (0-bit key) header.d=wii.dev header.i=@wii.dev header.b=o1TMQByz reason="key not found in DNS"; arc=none smtp.client-ip=136.175.108.170 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=wii.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=wii.dev Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=wii.dev header.i=@wii.dev header.b="o1TMQByz" Received: from filter006.mxroute.com ([136.175.111.3] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta170.mxroute.com (ZoneMTA) with ESMTPSA id 19e373480e300067f7.00c for (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Sun, 17 May 2026 18:30:48 +0000 X-Zone-Loop: d86d76c5116b5524580b8cd2eaf4e971231c27b238f9 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=wii.dev; s=x; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=6AX3Kzk5v2aPc0+AOTs3qurotM7xs8HKDdOmhlGXq5E=; b=o1TMQByzpkn/0HW++VAR9B88n3 Q0QyB2b8MhsRpQ01mQH8wR8pze1pnLo1a77d0I8SkTTvwPavXTib2JP4i/W3oQADzUiX18/WK7ulM Lfk6qbmsMFG7D6/f1DuHbBb7Y2wLPRhL8B7Lcl0aoe3XLs21lUZ8KIGEZawQdFQ62ILtqhdKiLOg6 AbKgbqYF/nThoII66DqkK2ibmR82McGSrAHZutcfQuP7KTk4qJXLVZZWNMGSLkU2KdEZ4Km1545q8 lwrCRRD/7DD6kfrWJ47kHA1OPdIDibYjdP46GT+IyiQzy2OC73/kwXmlSvp7aKBL7bqDi3g19M28F BunCROYw==; From: Richard Patel To: x86@kernel.org Cc: Rick Edgecombe , Yu-cheng Yu , Dave Hansen , Thomas Gleixner , Ingo Molnar , Borislav Petkov , "H. Peter Anvin" , Andy Lutomirski , Kees Cook , Peter Zijlstra , Shuah Khan , linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 6/7] x86/entry/vdso: build with IBT support Date: Sun, 17 May 2026 13:30:23 -0500 Message-ID: <20260517183024.16292-7-ripatel@wii.dev> In-Reply-To: <20260517183024.16292-1-ripatel@wii.dev> References: <20260517183024.16292-1-ripatel@wii.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Authenticated-Id: ripatel@wii.dev Content-Type: text/plain; charset="utf-8" VDSO should expose ENDBR instructions now that usermode IBT is available. Signed-off-by: Richard Patel --- arch/x86/entry/vdso/common/Makefile.include | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/x86/entry/vdso/common/Makefile.include b/arch/x86/entry/v= dso/common/Makefile.include index 687b3d89b40d..a0dc69b7a330 100644 --- a/arch/x86/entry/vdso/common/Makefile.include +++ b/arch/x86/entry/vdso/common/Makefile.include @@ -46,8 +46,7 @@ flags-y +=3D -fasynchronous-unwind-tables # Reset cf protections enabled by compiler default flags-y +=3D $(call cc-option, -fcf-protection=3Dnone) flags-$(X86_USER_SHADOW_STACK) +=3D $(call cc-option, -fcf-protection=3Dre= turn) -# When user space IBT is supported, enable this. -# flags-$(CONFIG_USER_IBT) +=3D $(call cc-option, -fcf-protection=3Dbranch) +flags-$(CONFIG_X86_USER_IBT) +=3D $(call cc-option, -fcf-protection=3Dbran= ch) =20 flags-$(CONFIG_MITIGATION_RETPOLINE) +=3D $(RETPOLINE_VDSO_CFLAGS) =20 --=20 2.47.3 From nobody Mon May 25 06:40:25 2026 Received: from mail-108-mta248.mxroute.com (mail-108-mta248.mxroute.com [136.175.108.248]) (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 9C1B53C9EEC for ; Sun, 17 May 2026 18:36:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=136.175.108.248 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779042963; cv=none; b=QFwzPUlCd0EUMFNkiNuN5eIFV2uXOpCC7NyH+7mn9bxCIwyhWCmCGPQvdXhVUUSGghsqYqnY1zzYj6hiGY2EWr4QMyChvIbP8iRa8a8ko7Oe3VqJfXZaMZQB3VptBUU3JTIQMyhikoSubCJixfqseCrDMcO76fU/Nu6RZ6ct83Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779042963; c=relaxed/simple; bh=qe8/roO65A2VoZ78Z1QRgHVD8L+p2JrGkAE7QP5GbbQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=lFN/XALAYcK/MTznOG/DM33J0YH+vklVqm6FQb+86X71PS/fnRG6bsqIccc1A8QQLXGi+6jSnd4hBIxPGujTf0VCTjXkoZXmEjvYKgyblWcLwBMNJ8bmgxthAmgH+Gh7c/Dj83Xmp2M4Je8P9859B8/Yt2zUS3Pna5EaVPLd7oM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=wii.dev; spf=pass smtp.mailfrom=wii.dev; dkim=fail (0-bit key) header.d=wii.dev header.i=@wii.dev header.b=deq7JJoH reason="key not found in DNS"; arc=none smtp.client-ip=136.175.108.248 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=wii.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=wii.dev Authentication-Results: smtp.subspace.kernel.org; dkim=fail reason="key not found in DNS" (0-bit key) header.d=wii.dev header.i=@wii.dev header.b="deq7JJoH" Received: from filter006.mxroute.com ([136.175.111.3] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta248.mxroute.com (ZoneMTA) with ESMTPSA id 19e3734892800067f7.00c for (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Sun, 17 May 2026 18:30:50 +0000 X-Zone-Loop: 036fe070e812731548767391645265521e08c4de1ac7 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=wii.dev; s=x; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=O3MajR2UHTB7tELzpgwInX/+mjytSwXsndvBgFS7uhw=; b=deq7JJoHk5ZITIV0eUqmpRtNFO UhvqKUzSPnyAmhskyyLPSMndgQZIwuBWs1NGXQIC+XYL8LFBQszNh8Mt8DVRDX6XNGXJ9IOsaZrdy OefiRgVXmYyyL4K4FVbkz/TlMqVjm6vnFV6oc6//ZG48k1O7/Acbu9fFHpC8Xg93wWVhbGvsG6icn sstg99O/jTO2COyqe9RY/lODgrsE/68Y1vgwVSskNX/I12pJk8bXoZ5J5zv4tpjDl+QWSziGV0t2U oMxXwfpivipCygX/SlB91uT0p8GNoMvAvfQYL/nCK9pBJ60JTsf3LuVpAlDsHuiNbCzNYuTXHJAce dZ78ZS9A==; From: Richard Patel To: x86@kernel.org Cc: Rick Edgecombe , Yu-cheng Yu , Dave Hansen , Thomas Gleixner , Ingo Molnar , Borislav Petkov , "H. Peter Anvin" , Andy Lutomirski , Kees Cook , Peter Zijlstra , Shuah Khan , linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 7/7] selftests/x86: test usermode IBT Date: Sun, 17 May 2026 13:30:24 -0500 Message-ID: <20260517183024.16292-8-ripatel@wii.dev> In-Reply-To: <20260517183024.16292-1-ripatel@wii.dev> References: <20260517183024.16292-1-ripatel@wii.dev> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Authenticated-Id: ripatel@wii.dev Content-Type: text/plain; charset="utf-8" Adds a basic selftest exercising a usermode IBT violation. Signed-off-by: Richard Patel --- tools/testing/selftests/x86/Makefile | 5 +- tools/testing/selftests/x86/user_ibt.c | 157 +++++++++++++++++++++++++ 2 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/x86/user_ibt.c diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests= /x86/Makefile index 434065215d12..203c3d9073f2 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 \ + user_ibt # 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)/user_ibt_64: CFLAGS +=3D -fcf-protection=3Dbranch diff --git a/tools/testing/selftests/x86/user_ibt.c b/tools/testing/selftes= ts/x86/user_ibt.c new file mode 100644 index 000000000000..795011503335 --- /dev/null +++ b/tools/testing/selftests/x86/user_ibt.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Test kernel support for userspace Indirect Branch Tracking (IBT). + * Enables IBT manually via prctl(). Must be compiled with + * -fcf-protection=3Dbranch to enable ENDBR64 instrumentation. + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../kselftest.h" + +/* + * Allow building this test with old kernel headers. + */ +#ifndef PR_SET_CFI +#define PR_GET_CFI 80 +#define PR_SET_CFI 81 +#endif +#ifndef PR_CFI_ENABLE +#define PR_CFI_ENABLE (1UL << 0) +#define PR_CFI_DISABLE (1UL << 1) +#endif +#ifndef PR_CFI_BRANCH_LANDING_PADS +#define PR_CFI_BRANCH_LANDING_PADS 0 +#endif +#ifndef SEGV_CPERR +#define SEGV_CPERR 10 +#endif + +#if !defined(__CET__) || (__CET__ & 1) !=3D 1 +int main(int argc, char *argv[]) +{ + ksft_print_header(); + ksft_exit_skip("Compiler does not support CET.\n"); + return 0; +} +#else +void __attribute__((naked)) valid_target(void) +{ + asm volatile ( + "endbr64\n" + "ret\n" + ); +} + +void __attribute__((nocf_check, naked)) invalid_target(void) +{ + asm volatile ("ret\n"); +} + +void __attribute__((naked)) user_ibt_basic_test(void) +{ + asm volatile ( + "leaq valid_target(%rip), %rax\n" + "call *%rax\n" + "ret\n" + ); +} + +void __attribute__((naked)) user_ibt_notrack_test(void) +{ + asm volatile ( + "leaq invalid_target(%rip), %rax\n" + "notrack call *%rax\n" + "ret\n" + ); +} + +static sigjmp_buf jmpbuf; +static sig_atomic_t got_signal; +static sig_atomic_t got_cperr; + +static void segv_handler(int signum, siginfo_t *si, void *uc) +{ + got_signal =3D true; + got_cperr =3D si->si_code =3D=3D SEGV_CPERR; + siglongjmp(jmpbuf, 1); +} + +int user_ibt_violation_test(void) +{ + struct sigaction sa =3D {}; + struct sigaction oldsa; + size_t volatile ptr; + + got_signal =3D false; + got_cperr =3D false; + + sa.sa_sigaction =3D segv_handler; + sa.sa_flags =3D SA_SIGINFO; + if (sigaction(SIGSEGV, &sa, &oldsa)) { + ksft_perror("SIGSEGV handler setup failed"); + return 1; + } + + if (!sigsetjmp(jmpbuf, 1)) { + /* + * Force an indirect call and drop 'nocf_check' attribute. + * Obfuscate cast through a temp local to suppress + * -Wincompatible-pointer-types (which correctly detects + * the nocf_check attribute mismatch) + */ + ptr =3D (size_t)invalid_target; + ((void (* volatile)(void))ptr)(); + /* Fall through in case this didn't SIGSEGV */ + } + + if (sigaction(SIGSEGV, &oldsa, NULL)) { + ksft_perror("SIGSEGV handler restore failed"); + return 1; + } + + if (!got_signal) { + ksft_print_msg("IBT violation did not generate SIGSEGV\n"); + return 1; + } + if (!got_cperr) { + ksft_print_msg("IBT violation generated unknown segfault\n"); + return 1; + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + unsigned long lpad_status =3D PR_CFI_ENABLE; + + ksft_print_header(); + ksft_set_plan(3); + + if (syscall(__NR_prctl, PR_SET_CFI, PR_CFI_BRANCH_LANDING_PADS, lpad_stat= us, 0, 0)) { + if (errno =3D=3D EINVAL || errno =3D=3D EOPNOTSUPP) + ksft_exit_skip("User IBT is not supported.\n"); + ksft_exit_fail_perror("Failed to enable user IBT"); + } + + user_ibt_basic_test(); + ksft_test_result_pass("valid indirect call with endbr64\n"); + + user_ibt_notrack_test(); + ksft_test_result_pass("notrack indirect call to non-endbr target\n"); + + ksft_test_result(!user_ibt_violation_test(), + "indirect call to non-endbr target raises SIGSEGV\n"); + + ksft_finished(); +} +#endif --=20 2.47.3