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 dfed6f35c5
commit 4af11551ba
7 changed files with 209 additions and 6 deletions

View File

@@ -1 +1 @@
23
24

View File

@@ -710,7 +710,7 @@ CVEs that need VMM context should call `check_has_vmm` early in their `_linux()`
- **Always handle both live and offline modes** - use `$opt_live` to branch, and print `N/A "not testable in offline mode"` for runtime-only checks when offline.
- **Use `explain()`** when reporting VULN to give actionable remediation advice (see "Cross-Cutting Features" above).
- **Handle `--paranoid` and `--vmm`** when the CVE has stricter mitigation tiers or VMM-specific aspects (see "Cross-Cutting Features" above).
- **All indentation must use tabs** (CI enforces this).
- **All indentation must use 4 spaces** (CI enforces this via `fmt-check`; the vim modeline `et` enables expandtab).
- **Stay POSIX-compatible** - no bashisms, no GNU-only flags in portable code paths.
## Function documentation headers

8
dist/README.md vendored
View File

@@ -30,6 +30,7 @@ CVE | Name | Aliases
[CVE-2023-23583](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-23583) | Redundant Prefix Issue | Reptar
[CVE-2024-36350](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-36350) | Transient Scheduler Attack, Store Queue | TSA-SQ
[CVE-2024-36357](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-36357) | Transient Scheduler Attack, L1 | TSA-L1
[CVE-2024-28956](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-28956) | Indirect Target Selection | ITS
## Am I at risk?
@@ -61,6 +62,7 @@ CVE-2023-20593 (Zenbleed) | 💥 | 💥 | 💥 | 💥 | Microcode update (or ker
CVE-2023-23583 (Reptar) | ☠️ | ☠️ | ☠️ | ☠️ | Microcode update
CVE-2024-36350 (TSA-SQ) | 💥 | 💥 (1) | 💥 | 💥 (1) | Microcode + kernel update
CVE-2024-36357 (TSA-L1) | 💥 | 💥 (1) | 💥 | 💥 (1) | Microcode + kernel update
CVE-2024-28956 (ITS) | 💥 | ✅ | 💥 (4) | ✅ | Microcode + kernel update
> 💥 Data can be leaked across this boundary.
@@ -74,6 +76,8 @@ CVE-2024-36357 (TSA-L1) | 💥 | 💥 (1) | 💥 | 💥 (1) | Microcode + kernel
> (3) CVE-2018-3615 (Foreshadow SGX) inverts the normal trust model: the OS reads SGX enclave data. It is irrelevant unless the system runs SGX enclaves, and the attacker must already have OS-level access.
> (4) VM→Host leakage applies only to certain affected CPU models (Skylake-X, Kaby Lake, Comet Lake). Ice Lake, Tiger Lake, and Rocket Lake are only affected for native (user-to-kernel) attacks, not guest-to-host.
## Detailed CVE descriptions
<details>
@@ -165,6 +169,10 @@ On AMD Zen 3 and Zen 4 processors, the CPU's transient scheduler may speculative
On AMD Zen 3 and Zen 4 processors, the CPU's transient scheduler may speculatively retrieve stale data from the L1 data cache during certain timing windows, allowing an attacker to infer data in the L1D cache across privilege boundaries. Mitigation requires the same microcode and kernel updates as TSA-SQ: a microcode update exposing VERW_CLEAR and a kernel update (CONFIG_MITIGATION_TSA, Linux 6.16+) that clears CPU buffers via VERW on privilege transitions. Performance impact is low to medium.
**CVE-2024-28956 — Indirect Target Selection (ITS)**
On certain Intel processors (Skylake-X stepping 6+, Kaby Lake, Comet Lake, Ice Lake, Tiger Lake, Rocket Lake), an attacker can train the indirect branch predictor to speculatively execute a targeted gadget in the kernel, bypassing eIBRS protections. The Branch Target Buffer (BTB) uses only partial address bits to index indirect branch targets, allowing user-space code to influence kernel-space speculative execution. Some affected CPUs (Ice Lake, Tiger Lake, Rocket Lake) are only vulnerable to native user-to-kernel attacks, not guest-to-host (VMX) attacks. Mitigation requires both a microcode update (IPU 2025.1 / microcode-20250512+, which fixes IBPB to fully flush indirect branch predictions) and a kernel update (CONFIG_MITIGATION_ITS, Linux 6.15+) that aligns branch/return thunks or uses RSB stuffing. Performance impact is low.
</details>
## Unsupported CVEs

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
}