# vim: set ts=4 sw=4 sts=4 et:
###############################
# CVE-2024-36350, TSA-SQ, Transient Scheduler Attack Store Queue

check_CVE_2024_36350() {
    check_cve 'CVE-2024-36350'
}

check_CVE_2024_36350_linux() {
    local status sys_interface_available msg kernel_tsa kernel_tsa_err smt_enabled
    status=UNK
    sys_interface_available=0
    msg=''

    if sys_interface_check "$VULN_SYSFS_BASE/tsa"; then
        # this kernel has the /sys interface, trust it over everything
        sys_interface_available=1
        #
        # Complete sysfs message inventory for tsa
        #
        # all versions:
        #   "Not affected"                                                  (cpu_show_common, pre-existing)
        #
        # --- mainline ---
        # d8010d4ba43e (v6.16-rc6, initial TSA sysfs):
        #   "Vulnerable"                                                    (TSA_MITIGATION_NONE)
        #   "Vulnerable: No microcode"                                      (TSA_MITIGATION_UCODE_NEEDED)
        #   "Mitigation: Clear CPU buffers: user/kernel boundary"           (TSA_MITIGATION_USER_KERNEL)
        #   "Mitigation: Clear CPU buffers: VM"                             (TSA_MITIGATION_VM)
        #   "Mitigation: Clear CPU buffers"                                 (TSA_MITIGATION_FULL)
        # 6b21d2f0dc73 (v6.17-rc1, attack vector controls):
        #   no string changes; only mitigation selection logic changed
        #   (AUTO can now resolve to USER_KERNEL or VM based on attack vector config)
        #
        # --- stable backports ---
        # 6.16.y: d8010d4ba43e (same as mainline), same strings.
        # 6.17.y: has 6b21d2f0dc73 (attack vector controls), same strings.
        # 5.10.y (78192f511f40), 5.15.y (f2b75f1368af), 6.1.y (d12145e8454f),
        # 6.6.y (90293047df18), 6.12.y (7a0395f6607a), 6.15.y (ab0f6573b211):
        #   different UCODE_NEEDED string:
        #   "Vulnerable: Clear CPU buffers attempted, no microcode"         (TSA_MITIGATION_UCODE_NEEDED)
        #   all other strings identical to mainline.
        #   default is FULL (no AUTO enum); USER_KERNEL/VM only via cmdline tsa=user/tsa=vm.
        #   VM-forced mitigation: when UCODE_NEEDED and running in a VM, forces FULL
        #   (stable-only logic, not in mainline).
        #
        # --- RHEL/CentOS ---
        # rocky9 (5.14-based), rocky10 (6.12-based): same strings as mainline.
        #   "Vulnerable: No microcode" for UCODE_NEEDED (matches mainline, NOT the stable variant).
        # rocky8 (4.18-based), centos7 (3.10-based): no TSA support.
        #
        # all messages start with either "Not affected", "Mitigation", or "Vulnerable"
        status=$ret_sys_interface_check_status
    fi

    if [ "$opt_sysfs_only" != 1 ]; then
        check_has_vmm
        # Override: when running as a hypervisor, "user/kernel boundary" mode
        # (tsa=user) leaves the VM exit boundary uncovered — guests can exploit
        # TSA to leak host data.  The kernel correctly reports its own mode, but
        # the script must flag this as insufficient for a VMM host.
        if [ "$sys_interface_available" = 1 ] && [ "$g_has_vmm" != 0 ]; then
            if echo "$ret_sys_interface_check_fullmsg" | grep -q 'user/kernel boundary'; then
                status=VULN
                msg="Vulnerable: TSA mitigation limited to user/kernel boundary (tsa=user), VM exit boundary is not covered"
            fi
        fi

        pr_info_nol "* Kernel supports TSA mitigation: "
        kernel_tsa=''
        kernel_tsa_err=''
        if [ -n "$g_kernel_err" ]; then
            kernel_tsa_err="$g_kernel_err"
        # commit d8010d4ba43e: "Transient Scheduler Attacks:" is printed by tsa_select_mitigation()
        elif is_x86_kernel && grep -q 'Transient Scheduler Attacks' "$g_kernel"; then
            kernel_tsa="found TSA mitigation message in kernel image"
        fi
        if [ -z "$kernel_tsa" ] && is_x86_kernel && [ -r "$opt_config" ]; then
            if grep -q '^CONFIG_MITIGATION_TSA=y' "$opt_config"; then
                kernel_tsa="CONFIG_MITIGATION_TSA=y found in kernel config"
            fi
        fi
        if [ -z "$kernel_tsa" ] && is_x86_kernel && [ -n "$opt_map" ]; then
            if grep -q 'tsa_select_mitigation' "$opt_map"; then
                kernel_tsa="found tsa_select_mitigation in System.map"
            fi
        fi
        if [ -n "$kernel_tsa" ]; then
            pstatus green YES "$kernel_tsa"
        elif [ -n "$kernel_tsa_err" ]; then
            pstatus yellow UNKNOWN "$kernel_tsa_err"
        else
            pstatus yellow NO
        fi

        if is_amd || is_hygon; then
            pr_info_nol "* CPU explicitly indicates not vulnerable to TSA-SQ (TSA_SQ_NO): "
            if [ "$cap_tsa_sq_no" = 1 ]; then
                pstatus green YES
            elif [ "$cap_tsa_sq_no" = 0 ]; then
                pstatus yellow NO
            else
                pstatus yellow UNKNOWN "couldn't read CPUID leaf 0x80000021"
            fi

            pr_info_nol "* Microcode supports VERW buffer clearing: "
            if [ "$cap_verw_clear" = 1 ]; then
                pstatus green YES
            elif [ "$cap_verw_clear" = 0 ]; then
                pstatus yellow NO
            else
                pstatus yellow UNKNOWN "couldn't read CPUID leaf 0x80000021"
            fi
        fi

        pr_info_nol "* Hyper-Threading (SMT) is enabled: "
        is_cpu_smt_enabled
        smt_enabled=$?
        if [ "$smt_enabled" = 0 ]; then
            pstatus yellow YES
        else
            pstatus green 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_verw_clear" = 1 ] && [ -n "$kernel_tsa" ]; then
                if [ "$opt_paranoid" = 1 ] && [ "$smt_enabled" = 0 ]; then
                    pvulnstatus "$cve" VULN "Mitigation active but SMT must be disabled for full TSA-SQ protection"
                    explain "Disable SMT by adding \`nosmt\` to your kernel command line for complete protection against cross-thread TSA-SQ leakage."
                else
                    pvulnstatus "$cve" OK "Both kernel and microcode mitigate the vulnerability"
                fi
            elif [ "$cap_verw_clear" = 1 ]; then
                pvulnstatus "$cve" VULN "Microcode supports mitigation but kernel is too old"
                explain "Update your kernel to a version that supports CONFIG_MITIGATION_TSA (Linux 6.16+),\n " \
                    "or check if your distribution has backported the TSA mitigation."
            elif [ -n "$kernel_tsa" ]; then
                pvulnstatus "$cve" VULN "Kernel supports mitigation but microcode is too old"
                explain "Update your CPU microcode via a BIOS/firmware update from your OEM.\n " \
                    "The microcode must expose the VERW_CLEAR capability (CPUID 0x80000021 EAX bit 5)."
            else
                pvulnstatus "$cve" VULN "Neither kernel nor microcode mitigate the vulnerability"
                explain "Both a kernel update (CONFIG_MITIGATION_TSA, Linux 6.16+) and a microcode/firmware update\n " \
                    "from your OEM are needed to mitigate this vulnerability."
            fi
        else
            pvulnstatus "$cve" "$status" "$ret_sys_interface_check_fullmsg"
        fi
    else
        pvulnstatus "$cve" "$status" "$msg"
        if echo "$msg" | grep -q 'VM exit boundary'; then
            explain "This system runs a hypervisor but TSA mitigation only clears CPU buffers at\n " \
                "user/kernel transitions (tsa=user). Guests can exploit TSA to leak host data\n " \
                "across VM exit. Use \`tsa=on\` (or remove \`tsa=user\`) to cover both boundaries."
        fi
    fi
}

check_CVE_2024_36350_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
}
