feat: implement CVE-2024-28956 (ITS, Indirect Target Selection) vulnerability and mitigation detection

This commit is contained in:
Stéphane Lesimple
2026-04-04 14:36:14 +02:00
parent fdf3d9dbb9
commit 55f98bd8b3
7 changed files with 209 additions and 6 deletions

View File

@@ -161,6 +161,7 @@ CVE-2023-20569|INCEPTION|inception|Inception, return address security (RAS)
CVE-2023-23583|REPTAR|reptar|Reptar, redundant prefix issue
CVE-2024-36350|TSA_SQ|tsa|Transient Scheduler Attack - Store Queue (TSA-SQ)
CVE-2024-36357|TSA_L1|tsa|Transient Scheduler Attack - L1 (TSA-L1)
CVE-2024-28956|ITS|its|Indirect Target Selection (ITS)
'
# Derive the supported CVE list from the registry

View File

@@ -106,9 +106,10 @@ is_cpu_affected() {
_set_immune tsa
# Retbleed: AMD (CVE-2022-29900) and Intel (CVE-2022-29901) specific:
_set_immune retbleed
# Downfall & Reptar are Intel specific, look for "is_intel" below:
# Downfall, Reptar & ITS are Intel specific, look for "is_intel" below:
_set_immune downfall
_set_immune reptar
_set_immune its
if is_cpu_mds_free; then
_infer_immune msbds
@@ -261,6 +262,32 @@ is_cpu_affected() {
fi
set +u
fi
# ITS (Indirect Target Selection, CVE-2024-28956)
# kernel vulnerable_to_its() + cpu_vuln_blacklist (159013a7ca18)
# immunity: ARCH_CAP_ITS_NO (bit 62 of IA32_ARCH_CAPABILITIES)
# immunity: X86_FEATURE_BHI_CTRL (none of the affected CPUs have this)
# vendor scope: Intel only (family 6), with stepping constraints on some models
if [ "$cap_its_no" = 1 ]; then
pr_debug "is_cpu_affected: its: not affected (ITS_NO)"
_set_immune its
elif [ "$cpu_family" = 6 ]; then
set -u
if { [ "$cpu_model" = "$INTEL_FAM6_SKYLAKE_X" ] && [ "$cpu_stepping" -gt 5 ]; } ||
{ [ "$cpu_model" = "$INTEL_FAM6_KABYLAKE_L" ] && [ "$cpu_stepping" -gt 11 ]; } ||
{ [ "$cpu_model" = "$INTEL_FAM6_KABYLAKE" ] && [ "$cpu_stepping" -gt 12 ]; } ||
[ "$cpu_model" = "$INTEL_FAM6_ICELAKE_L" ] ||
[ "$cpu_model" = "$INTEL_FAM6_ICELAKE_D" ] ||
[ "$cpu_model" = "$INTEL_FAM6_ICELAKE_X" ] ||
[ "$cpu_model" = "$INTEL_FAM6_COMETLAKE" ] ||
[ "$cpu_model" = "$INTEL_FAM6_COMETLAKE_L" ] ||
[ "$cpu_model" = "$INTEL_FAM6_TIGERLAKE_L" ] ||
[ "$cpu_model" = "$INTEL_FAM6_TIGERLAKE" ] ||
[ "$cpu_model" = "$INTEL_FAM6_ROCKETLAKE" ]; then
pr_debug "is_cpu_affected: its: affected"
_set_vuln its
fi
set +u
fi
# Reptar
# the only way to know whether a CPU is vuln, is to check whether there is a known ucode update for it,
# as the mitigation is only ucode-based and there's no flag exposed by the kernel or by an updated ucode.
@@ -520,12 +547,12 @@ is_cpu_affected() {
_infer_immune itlbmh
fi
# shellcheck disable=SC2154 # affected_zenbleed/inception/retbleed/tsa/downfall/reptar set via eval (_set_immune)
# shellcheck disable=SC2154 # affected_zenbleed/inception/retbleed/tsa/downfall/reptar/its set via eval (_set_immune)
{
pr_debug "is_cpu_affected: final results: variant1=$affected_variant1 variant2=$affected_variant2 variant3=$affected_variant3 variant3a=$affected_variant3a"
pr_debug "is_cpu_affected: final results: variant4=$affected_variant4 variantl1tf=$affected_variantl1tf msbds=$affected_msbds mfbds=$affected_mfbds"
pr_debug "is_cpu_affected: final results: mlpds=$affected_mlpds mdsum=$affected_mdsum taa=$affected_taa itlbmh=$affected_itlbmh srbds=$affected_srbds"
pr_debug "is_cpu_affected: final results: zenbleed=$affected_zenbleed inception=$affected_inception retbleed=$affected_retbleed tsa=$affected_tsa downfall=$affected_downfall reptar=$affected_reptar"
pr_debug "is_cpu_affected: final results: zenbleed=$affected_zenbleed inception=$affected_inception retbleed=$affected_retbleed tsa=$affected_tsa downfall=$affected_downfall reptar=$affected_reptar its=$affected_its"
}
affected_variantl1tf_sgx="$affected_variantl1tf"
# even if we are affected to L1TF, if there's no SGX, we're not affected to the original foreshadow

View File

@@ -734,6 +734,7 @@ check_cpu() {
cap_tsx_ctrl_msr=-1
cap_gds_ctrl=-1
cap_gds_no=-1
cap_its_no=-1
if [ "$cap_arch_capabilities" = -1 ]; then
pstatus yellow UNKNOWN
elif [ "$cap_arch_capabilities" != 1 ]; then
@@ -748,6 +749,7 @@ check_cpu() {
cap_tsx_ctrl_msr=0
cap_gds_ctrl=0
cap_gds_no=0
cap_its_no=0
pstatus yellow NO
else
read_msr $MSR_IA32_ARCH_CAPABILITIES
@@ -763,6 +765,7 @@ check_cpu() {
cap_tsx_ctrl_msr=0
cap_gds_ctrl=0
cap_gds_no=0
cap_its_no=0
if [ $ret = $READ_MSR_RET_OK ]; then
capabilities=$ret_read_msr_value
# https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/arch/x86/include/asm/msr-index.h#n82
@@ -778,7 +781,8 @@ check_cpu() {
[ $((ret_read_msr_value_lo >> 8 & 1)) -eq 1 ] && cap_taa_no=1
[ $((ret_read_msr_value_lo >> 25 & 1)) -eq 1 ] && cap_gds_ctrl=1
[ $((ret_read_msr_value_lo >> 26 & 1)) -eq 1 ] && cap_gds_no=1
pr_debug "capabilities says rdcl_no=$cap_rdcl_no ibrs_all=$cap_ibrs_all rsba=$cap_rsba l1dflush_no=$cap_l1dflush_no ssb_no=$cap_ssb_no mds_no=$cap_mds_no taa_no=$cap_taa_no pschange_msc_no=$cap_pschange_msc_no"
[ $((ret_read_msr_value_hi >> 30 & 1)) -eq 1 ] && cap_its_no=1
pr_debug "capabilities says rdcl_no=$cap_rdcl_no ibrs_all=$cap_ibrs_all rsba=$cap_rsba l1dflush_no=$cap_l1dflush_no ssb_no=$cap_ssb_no mds_no=$cap_mds_no taa_no=$cap_taa_no pschange_msc_no=$cap_pschange_msc_no its_no=$cap_its_no"
if [ "$cap_ibrs_all" = 1 ]; then
pstatus green YES
else

163
src/vulns/CVE-2024-28956.sh Normal file
View File

@@ -0,0 +1,163 @@
# vim: set ts=4 sw=4 sts=4 et:
###############################
# CVE-2024-28956, ITS, Indirect Target Selection
check_CVE_2024_28956() {
check_cve 'CVE-2024-28956'
}
check_CVE_2024_28956_linux() {
local status sys_interface_available msg kernel_its kernel_its_err ret
status=UNK
sys_interface_available=0
msg=''
if sys_interface_check "$VULN_SYSFS_BASE/indirect_target_selection"; then
# this kernel has the /sys interface, trust it over everything
sys_interface_available=1
#
# Kernel source inventory for indirect_target_selection (ITS)
#
# --- sysfs messages ---
# all versions:
# "Not affected" (cpu_show_common, pre-existing)
#
# --- mainline ---
# f4818881c47f (v6.15-rc2, initial ITS sysfs):
# "Vulnerable" (ITS_MITIGATION_OFF)
# "Mitigation: Aligned branch/return thunks" (ITS_MITIGATION_ALIGNED_THUNKS)
# "Mitigation: Retpolines, Stuffing RSB" (ITS_MITIGATION_RETPOLINE_STUFF)
# 2665281a07e1 (v6.15-rc2, added vmexit option):
# "Mitigation: Vulnerable, KVM: Not affected" (ITS_MITIGATION_VMEXIT_ONLY)
# facd226f7e0c (v6.15-rc2, added stuff cmdline option):
# no string changes; added "stuff" boot param value
# 61ab72c2c6bf (v6.16-rc1, restructured select/update/apply):
# no string changes; added ITS_MITIGATION_AUTO (internal, resolved before display)
# split into its_select_mitigation() + its_update_mitigation() + its_apply_mitigation()
# 0cdd2c4f35cf (v6.18-rc1, attack vector controls):
# no string changes; added per-vector on/off control
#
# --- stable backports ---
# 5.10.y, 5.15.y, 6.1.y: 3 strings only (no VMEXIT_ONLY, no RETPOLINE_STUFF
# in 5.10/5.15/6.1). Uses CONFIG_RETPOLINE/CONFIG_RETHUNK (not CONFIG_MITIGATION_*).
# 6.6.y, 6.12.y, 6.14.y, 6.15.y: all 4 strings, full vmexit+stuff support.
# 6.16.y+: restructured 3-phase select/update/apply.
# Not backported to: 5.4.y, 6.11.y, 6.13.y.
#
# --- RHEL/CentOS ---
# rocky9 (5.14): all 4 strings, restructured 3-phase version.
# rocky10 (6.12): all 4 strings, restructured 3-phase version.
# Not backported to: centos7, rocky8.
#
# --- Kconfig symbols ---
# f4818881c47f (v6.15-rc2): CONFIG_MITIGATION_ITS (default y)
# depends on CPU_SUP_INTEL && X86_64 && MITIGATION_RETPOLINE && MITIGATION_RETHUNK
# stable 5.10.y, 5.15.y, 6.1.y: CONFIG_MITIGATION_ITS
# depends on CONFIG_RETPOLINE && CONFIG_RETHUNK (pre-rename names)
#
# --- kernel functions (for $opt_map / System.map) ---
# f4818881c47f (v6.15-rc2): its_select_mitigation(), its_parse_cmdline(),
# its_show_state()
# 61ab72c2c6bf (v6.16-rc1): split into its_select_mitigation() +
# its_update_mitigation() + its_apply_mitigation()
# stable 5.10.y-6.15.y: its_select_mitigation() (no split)
# rocky9, rocky10: its_select_mitigation() + its_update_mitigation() +
# its_apply_mitigation()
#
# --- CPU affection logic (for is_cpu_affected) ---
# X86_BUG_ITS is set when ALL conditions are true:
# 1. Intel vendor, family 6
# 2. CPU matches model blacklist (with stepping constraints)
# 3. ARCH_CAP_ITS_NO (bit 62 of IA32_ARCH_CAPABILITIES) is NOT set
# 4. X86_FEATURE_BHI_CTRL is NOT present
# 159013a7ca18 (v6.15-rc2, initial model list):
# Intel: SKYLAKE_X (stepping > 5), KABYLAKE_L (stepping > 0xb),
# KABYLAKE (stepping > 0xc), ICELAKE_L, ICELAKE_D, ICELAKE_X,
# COMETLAKE, COMETLAKE_L, TIGERLAKE_L, TIGERLAKE, ROCKETLAKE
# (all steppings unless noted)
# ITS_NATIVE_ONLY flag (X86_BUG_ITS_NATIVE_ONLY): set for
# ICELAKE_L, ICELAKE_D, ICELAKE_X, TIGERLAKE_L, TIGERLAKE, ROCKETLAKE
# These CPUs are affected for user-to-kernel but NOT guest-to-host (VMX)
# immunity: ARCH_CAP_ITS_NO (bit 62 of IA32_ARCH_CAPABILITIES)
# immunity: X86_FEATURE_BHI_CTRL (none of the affected CPUs have this)
# vendor scope: Intel only
#
# all messages start with either "Not affected", "Vulnerable", or "Mitigation"
status=$ret_sys_interface_check_status
fi
if [ "$opt_sysfs_only" != 1 ]; then
pr_info_nol "* Kernel supports ITS mitigation: "
kernel_its=''
kernel_its_err=''
if [ -n "$g_kernel_err" ]; then
kernel_its_err="$g_kernel_err"
elif grep -q 'indirect_target_selection' "$g_kernel"; then
kernel_its="found indirect_target_selection in kernel image"
fi
if [ -z "$kernel_its" ] && [ -r "$opt_config" ]; then
if grep -q '^CONFIG_MITIGATION_ITS=y' "$opt_config"; then
kernel_its="ITS mitigation config option found enabled in kernel config"
fi
fi
if [ -z "$kernel_its" ] && [ -n "$opt_map" ]; then
if grep -q 'its_select_mitigation' "$opt_map"; then
kernel_its="found its_select_mitigation in System.map"
fi
fi
if [ -n "$kernel_its" ]; then
pstatus green YES "$kernel_its"
elif [ -n "$kernel_its_err" ]; then
pstatus yellow UNKNOWN "$kernel_its_err"
else
pstatus yellow NO
fi
pr_info_nol "* CPU explicitly indicates not being affected by ITS (ITS_NO): "
if [ "$cap_its_no" = -1 ]; then
pstatus yellow UNKNOWN
elif [ "$cap_its_no" = 1 ]; then
pstatus green YES
else
pstatus yellow NO
fi
elif [ "$sys_interface_available" = 0 ]; then
# we have no sysfs but were asked to use it only!
msg="/sys vulnerability interface use forced, but it's not available!"
status=UNK
fi
if ! is_cpu_affected "$cve"; then
# override status & msg in case CPU is not vulnerable after all
pvulnstatus "$cve" OK "your CPU vendor reported your CPU model as not affected"
elif [ -z "$msg" ]; then
# if msg is empty, sysfs check didn't fill it, rely on our own test
if [ "$opt_sysfs_only" != 1 ]; then
if [ "$cap_its_no" = 1 ]; then
pvulnstatus "$cve" OK "CPU is not affected (ITS_NO)"
elif [ -n "$kernel_its" ]; then
pvulnstatus "$cve" OK "Kernel mitigates the vulnerability"
elif [ -z "$kernel_its" ] && [ -z "$kernel_its_err" ]; then
pvulnstatus "$cve" VULN "Your kernel doesn't support ITS mitigation"
explain "Update your kernel to a version that includes ITS mitigation (Linux 6.15+, or check\n" \
"if your distro has a backport). Also update your CPU microcode to ensure IBPB fully\n" \
"flushes indirect branch predictions (microcode-20250512+)."
else
pvulnstatus "$cve" UNK "couldn't determine mitigation status: $kernel_its_err"
fi
else
pvulnstatus "$cve" "$status" "$ret_sys_interface_check_fullmsg"
fi
else
pvulnstatus "$cve" "$status" "$msg"
fi
}
check_CVE_2024_28956_bsd() {
if ! is_cpu_affected "$cve"; then
pvulnstatus "$cve" OK "your CPU vendor reported your CPU model as not affected"
else
pvulnstatus "$cve" UNK "your CPU is affected, but mitigation detection has not yet been implemented for BSD in this script"
fi
}