From nobody Fri Jun 12 07:26:31 2026 Received: from mail-108-mta47.mxroute.com (mail-108-mta47.mxroute.com [136.175.108.47]) (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 D66893EDE6A for ; Fri, 5 Jun 2026 18:53:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=136.175.108.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780685620; cv=none; b=BNVhQOjKUHV8kA1DxPXFiabdMhBYvh1VJpZraXHh7SOm0h1nLwjrWtgZkgvu3wgIpZCfZnrEBRflrqrIhsIfKwpNECo7pCklNiiH+Fi2PahOe029xSbpHcLCuTYbXcDrrnUJsY/ZP6d+XDsxfvKquGIYh7Gg+UIegMpIc8fGtMU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780685620; c=relaxed/simple; bh=3mYBSwPm2HNzbZQx6T/QDwCg0Hi1eJoSiWrbJcT/GQw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=m83dns+ZJdmZIl0S7VXtoct8boRtVMQiVb0J4K9Axa+Px6cO2JCp32jm1WML15xhHj7L5lLH/Qfj4sicTecGjUeXOJd1xaUQxa92yZoV9eT/Dv6auY+vKkd+3QOBeIqLNJoVmAybbHkX5FBtcSIVORc8wQLsNXGlhYtIgQX9QKY= 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=pass (2048-bit key) header.d=wii.dev header.i=@wii.dev header.b=dI1wX2vX; arc=none smtp.client-ip=136.175.108.47 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=pass (2048-bit key) header.d=wii.dev header.i=@wii.dev header.b="dI1wX2vX" Received: from filter006.mxroute.com ([136.175.111.3] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta47.mxroute.com (ZoneMTA) with ESMTPSA id 19e991d738f00067f7.00e for (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Fri, 05 Jun 2026 18:48:24 +0000 X-Zone-Loop: b5a1bab3ceaa981fef4991c8bd03807491927df0a178 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=B+Wl9Myy0ESgVPp15bKDoA4p/EMRfvxhxgVs0DeRndM=; b=dI1wX2vX+bpLSCQhuv1si7NznO ytc+BpziZqVuYYirVZD9a44yIKUXdxWF1bsV0I2a4Nv1YB7I77d1TSDtiJ9hYcKmd5to/DA9BzppH 6GT8jgOuGIJqkXziMSazdN+1bk47mJ9o0ET6Fwz3CZTtrKVZkXF9RlL0ipDcU8HFojq1P4J8M4yKE gfgwNcVO6wSSY03BPAVi6cgj5yk+/OF3ny5C4B9IZ+BMeibdRKk5q2Ln8XS+ouHR3afJuz2q8eel2 U18sejcQQECgcc1+2Zqn6y0IXBvzVWzdrEF7zulu010xnBoUpGWCPpWXuT4Glp+pFhB7Z03zyhNn+ SbXpbvcg==; From: Richard Patel To: x86@kernel.org, "H. Peter Anvin" , Peter Zijlstra Cc: Rick Edgecombe , Yu-cheng Yu , Dave Hansen , Thomas Gleixner , Ingo Molnar , Borislav Petkov , David Laight , Andy Lutomirski , Kees Cook , Shuah Khan , linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, Florian Weimer , Richard Patel Subject: [PATCH v2 1/5] x86: add userspace IBT config option Date: Fri, 5 Jun 2026 18:47:12 +0000 Message-ID: <20260605184715.3383415-3-ripatel@wii.dev> In-Reply-To: <20260605184715.3383415-2-ripatel@wii.dev> References: <20260605184715.3383415-2-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. Depends on usermode shadow stack, which enables XSAVES for the IA32_U_CET MSR, containing both SHSTK and IBT state. Signed-off-by: Richard Patel --- arch/x86/Kconfig | 18 ++++++++++++++++++ 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, 34 insertions(+), 3 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index f3f7cb01d69d..90d5d14fd407 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1901,6 +1901,24 @@ 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 + depends on X86_USER_SHADOW_STACK + 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 Fri Jun 12 07:26:31 2026 Received: from mail-108-mta245.mxroute.com (mail-108-mta245.mxroute.com [136.175.108.245]) (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 B2CA2377ED4 for ; Fri, 5 Jun 2026 18:53:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=136.175.108.245 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780685620; cv=none; b=GVb2gjHVdZ/NVksz04R7VreAykRLoeR4TN6RFfeKkrpufpbMA243PW594Lb5GHxKkhraVcILck2Lcc+JAOEo/6VsoSf+srmY6rJy+nxgNWo8VwoE3u7lbarMKSf7VSFA1X4jZmWr3g42ZFPWxI+mf5JTvsJoXRyYESLPXNceERU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780685620; c=relaxed/simple; bh=b5WOFM52SN13MEtWftN752/9cLw0JVPazUMHSdNkRmc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=i+sIQzCkEJv1Yg0QXpjAVGEfWwLV6TCrfEGcb9arZGNNarKlzCz07nXBofzMYs14eaShGQh5p09AddM2gKneW1ImHy/IJ8aep3wDWfbjruz1HUOEUzUpYidcra7MqWmQD/ojgpp0mRoXI0B2ObUe2yxwuqQZIpTCwgy62qWRxnI= 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=pass (2048-bit key) header.d=wii.dev header.i=@wii.dev header.b=pFVpl9XD; arc=none smtp.client-ip=136.175.108.245 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=pass (2048-bit key) header.d=wii.dev header.i=@wii.dev header.b="pFVpl9XD" Received: from filter006.mxroute.com ([136.175.111.3] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta245.mxroute.com (ZoneMTA) with ESMTPSA id 19e991d814b00067f7.00e for (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Fri, 05 Jun 2026 18:48:28 +0000 X-Zone-Loop: aef7fd3c295d34c1d13485d5c0d7e7ca4b8b52f1dec8 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=pFVpl9XDMdO6BbhkvYP+KOh2c9 72YC1t4AkFT6riWxUK1dJ3SfhIiqI/3PQ6ECLQMB6Kb/qV/SyVm06gQV1WEik8dJOdx7c+WLtx7Ws SgJsnBMI8hG5qoO9fex3sbyB6Y9bKv3XXldWsTzIyvsTrG8f9gd8oGfKcnB/WgNnSFSqHWXJcn40t N+UTBo3ntKWrvR6Qu103wBLpbJDjjzRLCa3QOpzkYSbaNRqjOLGU/+SOyY2voHtqzK4jgG4q3QyKi GDs4LjV2JeUYZeH6U74K7tFiQVV/3X1m2uFsvo6/DXqby2GD5sCK5Map2kCZVe0S1/z4B1Dtx0bVy gBcw94kw==; From: Richard Patel To: x86@kernel.org, "H. Peter Anvin" , Peter Zijlstra Cc: Rick Edgecombe , Yu-cheng Yu , Dave Hansen , Thomas Gleixner , Ingo Molnar , Borislav Petkov , David Laight , Andy Lutomirski , Kees Cook , Shuah Khan , linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, Florian Weimer , Richard Patel Subject: [PATCH v2 2/5] x86: shstk: don't clobber IBT bits in U_CET MSR Date: Fri, 5 Jun 2026 18:47:13 +0000 Message-ID: <20260605184715.3383415-4-ripatel@wii.dev> In-Reply-To: <20260605184715.3383415-2-ripatel@wii.dev> References: <20260605184715.3383415-2-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 Fri Jun 12 07:26:31 2026 Received: from mail-108-mta208.mxroute.com (mail-108-mta208.mxroute.com [136.175.108.208]) (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 B10B21C84A6 for ; Fri, 5 Jun 2026 18:53:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=136.175.108.208 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780685625; cv=none; b=CfLLzVTjiS2p/puyJDHo7Rw+Vb88gID2qteio87vBpfoe1ZqXfZS8xO9WZWSgxIFhwkVc3G4dlOUfhFQR7Npf4QB0luX6lccd7afLWwrwZn6hgGCNl6RKvai0GEto8E9NHowgxFRT2hdqvkn8XEttdxEps2tPmujdW2b7webin8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780685625; c=relaxed/simple; bh=7dF/Jnx0wdxiKwad9kq3Ay0lwkGHxkajtV3MvLcJ5q0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Ic60Sgcl8VpcVm776JIBqQ6s20NE4uvtYzzH50rxabYismcGC+D5Nmk1B+QIK2HAyGSu+dbI6WEwRaDMLJZBb5XIlDRoksH914OBVokbrYq0+PkXyc8/NbbeUfGCZjD4JA8PC4m5SXzT/DEDb4ywCoOCv8uSiAsq1zYIOkJ6a+c= 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=pass (2048-bit key) header.d=wii.dev header.i=@wii.dev header.b=oGUhd9TM; arc=none smtp.client-ip=136.175.108.208 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=pass (2048-bit key) header.d=wii.dev header.i=@wii.dev header.b="oGUhd9TM" Received: from filter006.mxroute.com ([136.175.111.3] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta208.mxroute.com (ZoneMTA) with ESMTPSA id 19e991d8f6800067f7.00e for (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Fri, 05 Jun 2026 18:48:31 +0000 X-Zone-Loop: 2d88685b7fee018320bbe90ea5cfc474abfc8a61cbf0 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=ZDXhhuq8nE1DCfiIOEaeZ0HqYW34V80BJ+yWskuv/Z0=; b=oGUhd9TMu7zTssEJT28yWbyMet wVda/NKP6QAFXL5ekm+rovvn0wi4QpmWN819qf4lJwsH/+UbuORvY0MwU/Oc880GiyG1HnWPzEFf/ nE4RWEyRgbzCwo+NL2DuFJrPNTMg/p6ZxiDvGxOTHTEJ5GC8p+/muCTMua50xCuy/eM9Q8OwbaExG pV3eA7DwFLt6Zq/+qnnQxX0yRrQ7lvqjC9w0VFrcyW4kkomMZjio+ou6+x2LakiSqufURMEwqJQkx P+VWucl2wT0SPvrJNVS/E+ABMYNSYYQBMgCcjXxKZ1tFfTutXe+06WC4rQxVg89Kbc07hR6t/RPNA TzzZhy7w==; From: Richard Patel To: x86@kernel.org, "H. Peter Anvin" , Peter Zijlstra Cc: Rick Edgecombe , Yu-cheng Yu , Dave Hansen , Thomas Gleixner , Ingo Molnar , Borislav Petkov , David Laight , Andy Lutomirski , Kees Cook , Shuah Khan , linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, Florian Weimer , Richard Patel Subject: [PATCH v2 3/5] x86: expose user IBT via PR_CFI_BRANCH_LANDING_PADS Date: Fri, 5 Jun 2026 18:47:14 +0000 Message-ID: <20260605184715.3383415-5-ripatel@wii.dev> In-Reply-To: <20260605184715.3383415-2-ripatel@wii.dev> References: <20260605184715.3383415-2-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 | 14 +++++ arch/x86/include/asm/processor.h | 5 ++ arch/x86/kernel/Makefile | 1 + arch/x86/kernel/ibt.c | 98 ++++++++++++++++++++++++++++++++ arch/x86/kernel/process_64.c | 2 + 5 files changed, 120 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..586e5fadf844 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__ + +#include + +#define PR_CFI_SUPPORTED_STATUS_MASK (PR_CFI_ENABLE | PR_CFI_DISABLE | PR_= CFI_LOCK) + +#ifdef CONFIG_X86_USER_IBT +void reset_thread_ibt(void); +#else +static inline void reset_thread_ibt(void) {} +#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 67dd932305db..7fbf10410973 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/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..682414fde5a4 --- /dev/null +++ b/arch/x86/kernel/ibt.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include + +static bool user_ibt_enabled(struct task_struct *task) +{ + return task->thread.ibt; +} + +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)) + 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)) + return -EINVAL; + + if (t !=3D current) + return -EINVAL; + + if (state & ~PR_CFI_SUPPORTED_STATUS_MASK) + 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)) + return -EINVAL; + + user_ibt_set_lock(task, true); + + return 0; +} + +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 Fri Jun 12 07:26:31 2026 Received: from mail-108-mta90.mxroute.com (mail-108-mta90.mxroute.com [136.175.108.90]) (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 D768B3DD84C for ; Fri, 5 Jun 2026 18:53:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=136.175.108.90 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780685630; cv=none; b=D+WsXyVl+wqc6gT9VgktRUke1P91S6vAp4kAnGANnKXc5I6Ro8oKZqhuSn+1f+knSrtFWuJkk/Ecwqe5HgDm/ExuJGVxpbfGkjkaygr307hT9iQ5x/lg1MSrWNKeHktUwSoWr4NQDov0mbGzhJyV23nOs7Gt4CnL4MM3H4e2nE8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780685630; c=relaxed/simple; bh=U881s5n9/+Yxk0Tltn7Rw415Nvtzme8MYOKwt5z08hY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=g479AWwGKKwaZE4QGWp8onD+v8v9IndzfFBQfj8K0uA63o4v9pZdCdfpM45JaHO7+PjP0B7whhyiNcRfIQ+jzP7j5X9bscCYJ9cek4uBkCLDkq9pMtNsXNZGgKItddWXOMa9qb/wmGoo9gGoeIaEU3A2oQ+VgGju+DMYANANsMU= 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=pass (2048-bit key) header.d=wii.dev header.i=@wii.dev header.b=WZ5fOsby; arc=none smtp.client-ip=136.175.108.90 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=pass (2048-bit key) header.d=wii.dev header.i=@wii.dev header.b="WZ5fOsby" Received: from filter006.mxroute.com ([136.175.111.3] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta90.mxroute.com (ZoneMTA) with ESMTPSA id 19e991d9c9800067f7.00e for (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Fri, 05 Jun 2026 18:48:35 +0000 X-Zone-Loop: e08f8501c6ed8f54bcd72ea227a772ba6f50b0b834dc 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=WZ5fOsbyQbvaroTQRcCkcW9W7e MB+jp/ZukqdrWvogamhTS44U2byoLfiZg6bTBv4LaWCHxhvcZgJob9h0CD8h18hwkc1ufuZwmowON G1Bu2wMt6UJSLzMAeah9MwIvZ+n0+aenatJ3OIHGIKOSj4NqaoQA8xfgS55xd90ArgXY6e2N6jF0R rASmViWwljyiQXEi++6WU+BQ64iC9RS5EZyJJwa1ndXofshSs/IvV/QvfRYzNI63R8KYTLL2J3iNg Nv986GsAOl9Oe33EbuamDCvlF4xO9LsFPmX8oYBr0rzpLOKZxjmYh9c9HOizmMxFmCakyv9NrkTgh t8HAxdMg==; From: Richard Patel To: x86@kernel.org, "H. Peter Anvin" , Peter Zijlstra Cc: Rick Edgecombe , Yu-cheng Yu , Dave Hansen , Thomas Gleixner , Ingo Molnar , Borislav Petkov , David Laight , Andy Lutomirski , Kees Cook , Shuah Khan , linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, Florian Weimer , Richard Patel Subject: [PATCH v2 4/5] x86/entry/vdso: build with IBT support Date: Fri, 5 Jun 2026 18:47:15 +0000 Message-ID: <20260605184715.3383415-6-ripatel@wii.dev> In-Reply-To: <20260605184715.3383415-2-ripatel@wii.dev> References: <20260605184715.3383415-2-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 Fri Jun 12 07:26:31 2026 Received: from mail-108-mta143.mxroute.com (mail-108-mta143.mxroute.com [136.175.108.143]) (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 EC56B3F077F for ; Fri, 5 Jun 2026 18:53:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=136.175.108.143 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780685635; cv=none; b=f6zcj+oX/QjZuY+3fb7MhAFTVXFqeU/PmDnkImjHC92MQsW9h4kVWVIb5nLLWVQ3AcmSn6HHnZzq3EdYuBxAfKpCK8rwnCdqlAsp6vlGF1cwdDOG6gSCfVVOTl5zqT6jZ6tgNkOmFbGhZmCs73ay6nIUf8KJGo2GiDcIDGg/80c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780685635; c=relaxed/simple; bh=+q11RDj3poboSxCnWMW12iGNK14GvewWRyWYUZQmlG8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=nZZ3qpdiBZQH/lwmh3PEge7X/5xuZSvsg3LJGV/OcfhEhmb0kIauJ9aRruPZVN0A4JcL9Q/1VtDu6XG8DCwyUCkSttvFeOkoMELdluIuLh61ouZdSQFGxGVIMAxT35Bm8BQe8JYLionqyWc5mXYxSijtvwfmB+PDJkpiC7YQG+A= 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=pass (2048-bit key) header.d=wii.dev header.i=@wii.dev header.b=pdZ+6WAC; arc=none smtp.client-ip=136.175.108.143 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=pass (2048-bit key) header.d=wii.dev header.i=@wii.dev header.b="pdZ+6WAC" Received: from filter006.mxroute.com ([136.175.111.3] filter006.mxroute.com) (Authenticated sender: mN4UYu2MZsgR) by mail-108-mta143.mxroute.com (ZoneMTA) with ESMTPSA id 19e991daf2000067f7.00e for (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384); Fri, 05 Jun 2026 18:48:39 +0000 X-Zone-Loop: a21af20fa5a61c6796114678351c19c6a0255bc0b4f0 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=CnvQbV3+nnyIgzzHQcF40GBllpWdxq0XjKnonBw2gVM=; b=pdZ+6WACcoHjKOC7RVf0TqVcw3 wmFFP+z7FPzjLDeFSBXJ36kWELVbg98fZTtsl45RZBrKgfRRer46qXd4rffJPn4typ6NSQBtlgtNV 6HuESq3fb8LpUNHM++8jwU82vBahsRONz2w/50G1TS/qP8gendd2JolCXuIP/3gE4pkON4f22PRCv nayHrGtaBmjaCtgxzjoCiX6qoU8VJjuB6mRnfR22c+4ZN5cRDf44yzCKbK7LBrEvGa5CtFKN2/YQc b680jSXtsQ3zCE//9Af9jHWd9CS55BnkxDu9k0oNw64u08Wz4zXOexmqGPvpoxOLNFh3oMZKUgZgR m5kibDIg==; From: Richard Patel To: x86@kernel.org, "H. Peter Anvin" , Peter Zijlstra Cc: Rick Edgecombe , Yu-cheng Yu , Dave Hansen , Thomas Gleixner , Ingo Molnar , Borislav Petkov , David Laight , Andy Lutomirski , Kees Cook , Shuah Khan , linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, Florian Weimer , Richard Patel Subject: [PATCH v2 5/5] selftests/x86: test usermode IBT Date: Fri, 5 Jun 2026 18:47:16 +0000 Message-ID: <20260605184715.3383415-7-ripatel@wii.dev> In-Reply-To: <20260605184715.3383415-2-ripatel@wii.dev> References: <20260605184715.3383415-2-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 | 247 +++++++++++++++++++++++++ 2 files changed, 251 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..59f2ba3ec4ea 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile @@ -13,7 +13,7 @@ CAN_BUILD_WITH_NOPIE :=3D $(shell ./check_cc.sh "$(CC)" t= rivial_program.c -no-pie) TARGETS_C_BOTHBITS :=3D single_step_syscall sysret_ss_attrs syscall_nt tes= t_mremap_vdso \ check_initial_reg_state sigreturn iopl ioperm \ test_vsyscall mov_ss_trap sigtrap_loop \ - syscall_arg_fault fsgsbase_restore sigaltstack + syscall_arg_fault fsgsbase_restore sigaltstack user_ibt TARGETS_C_BOTHBITS +=3D nx_stack TARGETS_C_32BIT_ONLY :=3D entry_from_vm86 test_syscall_vdso unwind_vdso \ test_FCMOV test_FCOMI test_FISTTP \ @@ -138,3 +138,6 @@ $(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_32: CFLAGS +=3D -fcf-protection=3Dbranch +$(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..b1038e5e5e64 --- /dev/null +++ b/tools/testing/selftests/x86/user_ibt.c @@ -0,0 +1,247 @@ +// 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 +#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, aligned(4096))) valid_target(void) +{ +#ifdef __x86_64__ + asm volatile("endbr64\n"); +#else + asm volatile("endbr32\n"); +#endif + asm volatile( + "ret\n" + ".p2align 12\n" + ); +} + +void __attribute__((nocf_check, naked, aligned(4096))) invalid_target(void) +{ + asm volatile( + "ret\n" + ".p2align 12\n" + ); +} + +void __attribute__((naked)) user_ibt_basic_test(void) +{ +#ifdef __x86_64__ + asm volatile( + "leaq valid_target(%rip), %rax\n" + "call *%rax\n" + "ret\n" + ); +#else + asm volatile( + "movl $valid_target, %eax\n" + "call *%eax\n" + "ret\n" + ); +#endif +} + +void __attribute__((naked)) user_ibt_notrack_test(void) +{ +#ifdef __x86_64__ + asm volatile ( + "leaq invalid_target(%rip), %rax\n" + "notrack call *%rax\n" + "ret\n" + ); +#else + asm volatile ( + "movl $invalid_target, %eax\n" + "notrack call *%eax\n" + "ret\n" + ); +#endif +} + +static sigjmp_buf jmpbuf; +static volatile sig_atomic_t num_segv; +static volatile sig_atomic_t got_cperr; + +static void segv_handler(int signum, siginfo_t *si, void *uc) +{ + num_segv++; + got_cperr =3D si->si_code =3D=3D SEGV_CPERR; + siglongjmp(jmpbuf, 1); +} + +int user_ibt_violation_test(void) +{ + struct sigaction sa =3D {}; + size_t volatile ptr; + + num_segv =3D 0; + got_cperr =3D false; + + sa.sa_sigaction =3D segv_handler; + sa.sa_flags =3D SA_SIGINFO; + if (sigaction(SIGSEGV, &sa, NULL)) + return 0; + + 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 */ + } + + signal(SIGSEGV, SIG_DFL); + + return num_segv =3D=3D 1 && got_cperr; +} + +static int user_ibt_signal_handler(void (*handler)(int, siginfo_t *, void = *), bool expect_segv) +{ + struct sigaction sa =3D {}; + pid_t pid =3D getpid(); + + if (pid < 0) + return 0; + num_segv =3D 0; + got_cperr =3D false; + + sa.sa_sigaction =3D handler; + sa.sa_flags =3D SA_SIGINFO; + if (sigaction(SIGPWR, &sa, NULL)) + return 0; + + sa.sa_sigaction =3D segv_handler; + sa.sa_flags =3D SA_SIGINFO; + if (sigaction(SIGSEGV, &sa, NULL)) + return 0; + + if (kill(getpid(), SIGPWR)) + return 0; + + signal(SIGSEGV, SIG_DFL); + signal(SIGPWR, SIG_DFL); + + return 1; +} + +int user_ibt_signal_handler_valid(void) +{ + user_ibt_signal_handler((void *)valid_target, false); + return num_segv =3D=3D 0; +} + +bool has_endbr_preamble(void *ptr) +{ + const unsigned char *p =3D ptr; + + if (!(p[0] =3D=3D 0xf3 && p[1] =3D=3D 0x0f && p[2] =3D=3D 0x1e)) + return false; +#ifdef __x86_64__ + return p[3] =3D=3D 0xfa; +#else + return p[3] =3D=3D 0xfb; +#endif +} + +int user_ibt_vdso(void) +{ + struct sigaction sa =3D {}; + struct timespec ts; + int ret =3D 1; + + sa.sa_sigaction =3D segv_handler; + sa.sa_flags =3D SA_SIGINFO; + if (sigaction(SIGSEGV, &sa, NULL)) + return 0; + + if (!sigsetjmp(jmpbuf, 1)) + (void)clock_gettime(CLOCK_REALTIME, &ts); + else + ret =3D 0; + + signal(SIGSEGV, SIG_DFL); + return ret; +} + +int main(int argc, char *argv[]) +{ + unsigned long lpad_status =3D PR_CFI_ENABLE; + + ksft_print_header(); + + if (!has_endbr_preamble((void *)printf)) + ksft_exit_skip("libc does not support IBT (needs -fcf-protection=3Dbranc= h)\n"); + + 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"); + } + + ksft_set_plan(5); + + 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_test_result(user_ibt_signal_handler_valid(), + "Signal handler sanity check\n"); + + ksft_test_result(user_ibt_vdso(), "vDSO supports IBT\n"); + + ksft_finished(); +} +#endif \ No newline at end of file --=20 2.47.3