# vim: set ts=4 sw=4 sts=4 et:
###############################
# CVE-2025-54505, FPDSS, AMD Zen1 Floating-Point Divider Stale Data Leak

check_CVE_2025_54505() {
    check_cve 'CVE-2025-54505'
}

# Print remediation advice for FPDSS when reporting VULN
# Callers: check_CVE_2025_54505_linux
_cve_2025_54505_explain_fix() {
    explain "Update your kernel to one that carries commit e55d98e77561 (\"x86/CPU: Fix FPDSS on Zen1\", mainline Linux 7.1),\n " \
        "or the equivalent backport from your distribution. The kernel sets bit 9 of MSR 0xc0011028 unconditionally on\n " \
        "every Zen1 CPU at boot, which disables the hardware optimization responsible for the leak.\n " \
        "To manually mitigate the issue right now, you may use the following command:\n " \
        "\`wrmsr -a 0xc0011028 \$((\$(rdmsr -c 0xc0011028) | (1<<9)))\`,\n " \
        "however note that this manual mitigation will only be active until the next reboot.\n " \
        "No microcode update is required: the chicken bit is present on every Zen1 CPU."
}

check_CVE_2025_54505_linux() {
    local status sys_interface_available msg kernel_mitigated dmesg_fpdss msr_fpdss ret
    status=UNK
    sys_interface_available=0
    msg=''
    # No sysfs interface exists for this vulnerability (no /sys/devices/system/cpu/vulnerabilities/fpdss).
    # sys_interface_available stays 0.
    #
    # Kernel source inventory for FPDSS, traced via git blame:
    #
    # --- sysfs messages ---
    # none: this vulnerability has no sysfs entry
    #
    # --- Kconfig symbols ---
    # none: the mitigation is unconditional, not configurable (no CONFIG_* knob)
    #
    # --- kernel functions (for $opt_map / System.map) ---
    # none: the fix is two inline lines in init_amd_zen1(), no dedicated function
    #
    # --- dmesg ---
    # e55d98e77561 (v7.1, initial fix): "AMD Zen1 FPDSS bug detected, enabling mitigation."
    #   (printed via pr_notice_once on every Zen1 CPU)
    #
    # --- /proc/cpuinfo bugs field ---
    # none: no X86_BUG_FPDSS flag defined; no cpuinfo exposure
    #
    # --- MSR ---
    # e55d98e77561 (v7.1): MSR_AMD64_FP_CFG = 0xc0011028, bit 9 = ZEN1_DENORM_FIX_BIT
    #   kernel calls msr_set_bit() unconditionally on any Zen1 CPU in init_amd_zen1().
    #   The bit is present in Zen1 silicon independently of microcode (no microcode
    #   revision gate in the kernel, unlike Zenbleed which uses amd_zenbleed_microcode[]).
    #
    # --- CPU affection logic (for is_cpu_affected) ---
    # e55d98e77561 (v7.1): applied unconditionally in init_amd_zen1(), i.e. all Zen1
    #   AMD: family 0x17 models 0x00-0x2f, 0x50-0x5f (same cohort as DIV0)
    # vendor scope: AMD only (Zen1 microarchitecture)
    #
    # --- stable backports ---
    # as of this writing, no stable/LTS backport has landed; only mainline (Linux 7.1).

    if [ "$opt_sysfs_only" != 1 ]; then
        pr_info_nol "* Kernel supports FPDSS mitigation: "
        kernel_mitigated=''
        if [ -n "$g_kernel_err" ]; then
            pstatus yellow UNKNOWN "$g_kernel_err"
        elif is_x86_kernel && grep -q 'AMD Zen1 FPDSS bug detected' "$g_kernel"; then
            kernel_mitigated="found FPDSS mitigation message in kernel image"
            pstatus green YES "$kernel_mitigated"
        else
            pstatus yellow NO
        fi

        pr_info_nol "* FPDSS mitigation enabled and active: "
        msr_fpdss=''
        dmesg_fpdss=''
        if [ "$g_mode" = live ] && is_x86_cpu && is_cpu_affected "$cve"; then
            # guard with is_cpu_affected to avoid #GP on non-Zen1 CPUs where 0xc0011028 is undefined
            read_msr 0xc0011028
            ret=$?
            if [ "$ret" = "$READ_MSR_RET_OK" ]; then
                if [ $((ret_read_msr_value_lo >> 9 & 1)) -eq 1 ]; then
                    msr_fpdss=1
                    pstatus green YES "ZEN1_DENORM_FIX_BIT set in FP_CFG MSR"
                else
                    msr_fpdss=0
                    pstatus yellow NO "ZEN1_DENORM_FIX_BIT is cleared in FP_CFG MSR"
                fi
            else
                # MSR unreadable (lockdown, no msr module, etc.): fall back to dmesg
                dmesg_grep 'AMD Zen1 FPDSS bug detected'
                ret=$?
                if [ "$ret" -eq 0 ]; then
                    dmesg_fpdss=1
                    pstatus green YES "FPDSS mitigation message found in dmesg"
                elif [ "$ret" -eq 2 ]; then
                    pstatus yellow UNKNOWN "couldn't read MSR and dmesg is truncated"
                else
                    pstatus yellow UNKNOWN "couldn't read MSR and no FPDSS message in dmesg"
                fi
            fi
        elif [ "$g_mode" = live ]; then
            pstatus blue N/A "CPU is incompatible"
        else
            pstatus blue N/A "not testable in no-runtime mode"
        fi
    elif [ "$sys_interface_available" = 0 ]; then
        msg="/sys vulnerability interface use forced, but it's not available!"
        status=UNK
    fi

    if ! is_cpu_affected "$cve"; then
        pvulnstatus "$cve" OK "your CPU vendor reported your CPU model as not affected"
    elif [ -z "$msg" ]; then
        if [ "$opt_sysfs_only" != 1 ]; then
            if [ "$g_mode" = live ]; then
                if [ "$msr_fpdss" = 1 ] || [ "$dmesg_fpdss" = 1 ]; then
                    pvulnstatus "$cve" OK "ZEN1_DENORM_FIX_BIT is set in FP_CFG MSR, mitigation is active"
                elif [ "$msr_fpdss" = 0 ]; then
                    pvulnstatus "$cve" VULN "ZEN1_DENORM_FIX_BIT is cleared in FP_CFG MSR, FPDSS can leak data between threads"
                    _cve_2025_54505_explain_fix
                elif [ -n "$kernel_mitigated" ]; then
                    # MSR unreadable at runtime, but kernel image carries the mitigation code
                    # and init_amd_zen1() sets the bit unconditionally, so mitigation is active
                    pvulnstatus "$cve" OK "kernel image carries FPDSS mitigation code (init_amd_zen1 sets the MSR bit unconditionally at boot)"
                else
                    pvulnstatus "$cve" VULN "your kernel doesn't support FPDSS mitigation"
                    _cve_2025_54505_explain_fix
                fi
            else
                if [ -n "$kernel_mitigated" ]; then
                    pvulnstatus "$cve" OK "Mitigation: FPDSS message found in kernel image"
                else
                    pvulnstatus "$cve" VULN "your kernel doesn't support FPDSS mitigation"
                    _cve_2025_54505_explain_fix
                fi
            fi
        else
            pvulnstatus "$cve" "$status" "no sysfs interface available for this CVE, use --no-sysfs to check"
        fi
    else
        pvulnstatus "$cve" "$status" "$msg"
    fi
}

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