# vim: set ts=4 sw=4 sts=4 et:
###############################
# CVE-2023-28746, RFDS, Register File Data Sampling

check_CVE_2023_28746() {
    check_cve 'CVE-2023-28746'
}

check_CVE_2023_28746_linux() {
    local status sys_interface_available msg kernel_rfds kernel_rfds_err rfds_mitigated
    status=UNK
    sys_interface_available=0
    msg=''

    if sys_interface_check "$VULN_SYSFS_BASE/reg_file_data_sampling"; then
        # this kernel has the /sys interface, trust it over everything
        sys_interface_available=1
        #
        # Kernel source inventory for reg_file_data_sampling (RFDS)
        #
        # --- sysfs messages ---
        # all versions:
        #   "Not affected"                      (cpu_show_common, pre-existing)
        #
        # --- mainline ---
        # 8076fcde016c (v6.9-rc1, initial RFDS sysfs):
        #   "Vulnerable"                        (RFDS_MITIGATION_OFF)
        #   "Vulnerable: No microcode"          (RFDS_MITIGATION_UCODE_NEEDED)
        #   "Mitigation: Clear Register File"   (RFDS_MITIGATION_VERW)
        # b8ce25df2999 (v6.15, added AUTO state):
        #   no string changes; RFDS_MITIGATION_AUTO is internal, resolved before display
        # 203d81f8e167 (v6.17, restructured):
        #   no string changes; added rfds_update_mitigation() + rfds_apply_mitigation()
        #
        # --- stable backports ---
        # 5.10.215, 5.15.154, 6.1.82, 6.6.22, 6.7.10, 6.8.1:
        #   same 3 strings as mainline; no structural differences
        #   macro ALDERLAKE_N (0xBE) used instead of mainline ATOM_GRACEMONT (same model)
        #
        # --- Kconfig symbols ---
        # 8076fcde016c (v6.9-rc1): CONFIG_MITIGATION_RFDS (default y)
        #   no renames across any version
        #
        # --- kernel functions (for $opt_map / System.map) ---
        # 8076fcde016c (v6.9-rc1): rfds_select_mitigation(), rfds_parse_cmdline(),
        #   rfds_show_state(), cpu_show_reg_file_data_sampling(), vulnerable_to_rfds()
        # 203d81f8e167 (v6.17): + rfds_update_mitigation(), rfds_apply_mitigation()
        #
        # --- CPU affection logic (for is_cpu_affected) ---
        # 8076fcde016c (v6.9-rc1, initial model list):
        #   Intel: ATOM_GOLDMONT (0x5C), ATOM_GOLDMONT_D (0x5F),
        #          ATOM_GOLDMONT_PLUS (0x7A), ATOM_TREMONT_D (0x86),
        #          ATOM_TREMONT (0x96), ATOM_TREMONT_L (0x9C),
        #          ATOM_GRACEMONT (0xBE), ALDERLAKE (0x97),
        #          ALDERLAKE_L (0x9A), RAPTORLAKE (0xB7),
        #          RAPTORLAKE_P (0xBA), RAPTORLAKE_S (0xBF)
        # 722fa0dba74f (v6.15, P-only hybrid exclusion):
        #   ALDERLAKE (0x97) and RAPTORLAKE (0xB7) narrowed to Atom core type only
        #   via X86_HYBRID_CPU_TYPE_ATOM check in vulnerable_to_rfds(); P-cores on
        #   these hybrid models are not affected, only E-cores (Gracemont) are.
        #   (not modeled here, we conservatively flag all steppings per whitelist principle,
        #   because detecting the active core type at runtime is unreliable from userspace)
        # immunity: ARCH_CAP_RFDS_NO (bit 27 of IA32_ARCH_CAPABILITIES)
        # mitigation: ARCH_CAP_RFDS_CLEAR (bit 28 of IA32_ARCH_CAPABILITIES)
        # vendor scope: Intel only
        #
        # all messages start with either "Not affected", "Mitigation", or "Vulnerable"
        status=$ret_sys_interface_check_status
    fi

    if [ "$opt_sysfs_only" != 1 ]; then
        if is_x86_cpu; then
            pr_info_nol "* CPU microcode mitigates the vulnerability: "
            if [ "$cap_rfds_clear" = 1 ]; then
                pstatus green YES "RFDS_CLEAR capability indicated by microcode"
            elif [ "$cap_rfds_clear" = 0 ]; then
                pstatus yellow NO
            else
                pstatus yellow UNKNOWN "couldn't read MSR"
            fi
        fi

        if is_x86_kernel; then
            pr_info_nol "* Kernel supports RFDS mitigation (VERW on transitions): "
            kernel_rfds=''
            kernel_rfds_err=''
            if [ -n "$g_kernel_err" ]; then
                kernel_rfds_err="$g_kernel_err"
            elif grep -q 'Clear Register File' "$g_kernel"; then
                kernel_rfds="found 'Clear Register File' string in kernel image"
            elif grep -q 'reg_file_data_sampling' "$g_kernel"; then
                kernel_rfds="found reg_file_data_sampling in kernel image"
            fi
            if [ -z "$kernel_rfds" ] && [ -r "$opt_config" ]; then
                if grep -q '^CONFIG_MITIGATION_RFDS=y' "$opt_config"; then
                    kernel_rfds="RFDS mitigation config option found enabled in kernel config"
                fi
            fi
            if [ -z "$kernel_rfds" ] && [ -n "$opt_map" ]; then
                if grep -q 'rfds_select_mitigation' "$opt_map"; then
                    kernel_rfds="found rfds_select_mitigation in System.map"
                fi
            fi
            if [ -n "$kernel_rfds" ]; then
                pstatus green YES "$kernel_rfds"
            elif [ -n "$kernel_rfds_err" ]; then
                pstatus yellow UNKNOWN "$kernel_rfds_err"
            else
                pstatus yellow NO
            fi
        fi

        if is_x86_cpu && [ "$g_mode" = live ] && [ "$sys_interface_available" = 1 ]; then
            pr_info_nol "* RFDS mitigation is enabled and active: "
            if echo "$ret_sys_interface_check_fullmsg" | grep -qi '^Mitigation'; then
                rfds_mitigated=1
                pstatus green YES
            else
                rfds_mitigated=0
                pstatus yellow NO
            fi
        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 [ "$opt_sysfs_only" != 1 ]; then
            if [ "$cap_rfds_clear" = 1 ]; then
                if [ -n "$kernel_rfds" ]; then
                    if [ "$g_mode" = live ]; then
                        if [ "$rfds_mitigated" = 1 ]; then
                            pvulnstatus "$cve" OK "Your microcode and kernel are both up to date for this mitigation, and mitigation is enabled"
                        else
                            pvulnstatus "$cve" VULN "Your microcode and kernel are both up to date for this mitigation, but the mitigation is not active"
                            explain "The RFDS mitigation has been disabled. Remove 'reg_file_data_sampling=off' or 'mitigations=off'\n " \
                                "from your kernel command line to re-enable it."
                        fi
                    else
                        pvulnstatus "$cve" OK "Your microcode and kernel are both up to date for this mitigation"
                    fi
                else
                    pvulnstatus "$cve" VULN "Your microcode supports mitigation, but your kernel doesn't, upgrade it to mitigate the vulnerability"
                    explain "Update your kernel to a version that supports RFDS mitigation (Linux 6.9+, or check if your distro\n " \
                        "has a backport). Your CPU microcode already provides the RFDS_CLEAR capability."
                fi
            else
                if [ -n "$kernel_rfds" ]; then
                    pvulnstatus "$cve" VULN "Your kernel supports mitigation, but your CPU microcode also needs to be updated to mitigate the vulnerability"
                    explain "Update your CPU microcode (via BIOS/firmware update or linux-firmware package) to a version that\n " \
                        "provides the RFDS_CLEAR capability."
                else
                    pvulnstatus "$cve" VULN "Neither your kernel or your microcode support mitigation, upgrade both to mitigate the vulnerability"
                    explain "Update both your CPU microcode (via BIOS/firmware update from your OEM) and your kernel to a version\n " \
                        "that supports RFDS mitigation (Linux 6.9+, or check if your distro has a backport)."
                fi
            fi
        else
            pvulnstatus "$cve" "$status" "$ret_sys_interface_check_fullmsg"
        fi
    else
        pvulnstatus "$cve" "$status" "$msg"
    fi
}

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