# vim: set ts=4 sw=4 sts=4 et:
###############################
# CVE-2020-0543, SRBDS, CROSSTalk, Special Register Buffer Data Sampling

check_CVE_2020_0543() {
    check_cve 'CVE-2020-0543'
}

check_CVE_2020_0543_linux() {
    local status sys_interface_available msg kernel_srbds kernel_srbds_err
    status=UNK
    sys_interface_available=0
    msg=''
    if sys_interface_check "$VULN_SYSFS_BASE/srbds"; then
        # this kernel has the /sys interface, trust it over everything
        sys_interface_available=1
        status=$ret_sys_interface_check_status
    fi
    if [ "$opt_sysfs_only" != 1 ]; then
        pr_info_nol "* SRBDS mitigation control is supported by the kernel: "
        kernel_srbds=''
        if [ -n "$g_kernel_err" ]; then
            kernel_srbds_err="$g_kernel_err"
        elif is_x86_kernel && grep -q 'Dependent on hypervisor' "$g_kernel"; then
            kernel_srbds="found SRBDS implementation evidence in kernel image. Your kernel is up to date for SRBDS mitigation"
        fi
        if [ -n "$kernel_srbds" ]; then
            pstatus green YES "$kernel_srbds"
        elif [ -n "$kernel_srbds_err" ]; then
            pstatus yellow UNKNOWN "$kernel_srbds_err"
        else
            pstatus yellow NO
        fi
        pr_info_nol "* SRBDS mitigation control is enabled and active: "
        if [ "$g_mode" = live ]; then
            if [ -n "$ret_sys_interface_check_fullmsg" ]; then
                if echo "$ret_sys_interface_check_fullmsg" | grep -qE '^Mitigation'; then
                    pstatus green YES "$ret_sys_interface_check_fullmsg"
                else
                    pstatus yellow NO
                fi
            else
                pstatus yellow NO "SRBDS not found in sysfs hierarchy"
            fi
        else
            pstatus blue N/A "not testable in no-runtime mode"
        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"
    else
        if [ "$opt_sysfs_only" != 1 ]; then
            if [ "$cap_srbds" = 1 ]; then
                # SRBDS mitigation control exists
                if [ "$cap_srbds_on" = 1 ]; then
                    # SRBDS mitigation control is enabled
                    if [ -z "$msg" ]; then
                        # if msg is empty, sysfs check didn't fill it, rely on our own test
                        if [ "$g_mode" = live ]; then
                            # if we're in live mode and $msg is empty, sysfs file is not there so kernel is too old
                            pvulnstatus "$cve" OK "Your microcode is up to date for SRBDS mitigation control. The kernel needs to be updated"
                        fi
                    else
                        if [ -n "$kernel_srbds" ]; then
                            pvulnstatus "$cve" OK "Your microcode and kernel are both up to date for SRBDS mitigation control. Mitigation is enabled"
                        else
                            pvulnstatus "$cve" OK "Your microcode is up to date for SRBDS mitigation control. The kernel needs to be updated"
                        fi
                    fi
                elif [ "$cap_srbds_on" = 0 ]; then
                    # SRBDS mitigation control is disabled
                    if [ -z "$msg" ]; then
                        if [ "$g_mode" = live ]; then
                            # if we're in live mode and $msg is empty, sysfs file is not there so kernel is too old
                            pvulnstatus "$cve" VULN "Your microcode is up to date for SRBDS mitigation control. The kernel needs to be updated. Mitigation is disabled"
                        fi
                    else
                        if [ -n "$kernel_srbds" ]; then
                            pvulnstatus "$cve" VULN "Your microcode and kernel are both up to date for SRBDS mitigation control. Mitigation is disabled"
                        else
                            pvulnstatus "$cve" VULN "Your microcode is up to date for SRBDS mitigation control. The kernel needs to be updated. Mitigation is disabled"
                        fi
                    fi
                else
                    # rdmsr: CPU 0 cannot read MSR 0x00000123
                    pvulnstatus "$cve" UNK "Not able to enumerate MSR for SRBDS mitigation control"
                fi
            else
                # [ $cap_srbds != 1 ]
                pvulnstatus "$cve" VULN "Your CPU microcode may need to be updated to mitigate the vulnerability"
            fi
        else
            # sysfs only: return the status/msg we got
            pvulnstatus "$cve" "$status" "$ret_sys_interface_check_fullmsg"
            return
        fi
    fi
}

# FreeBSD uses the name "rngds" (Random Number Generator Data Sampling) for SRBDS
check_CVE_2020_0543_bsd() {
    local rngds_enable rngds_state kernel_rngds
    pr_info_nol "* Kernel supports SRBDS mitigation (machdep.mitigations.rngds.enable): "
    rngds_enable=$(sysctl -n machdep.mitigations.rngds.enable 2>/dev/null)
    if [ -n "$rngds_enable" ]; then
        kernel_rngds=1
        case "$rngds_enable" in
            0) pstatus yellow YES "optimized (RDRAND/RDSEED not locked, faster but vulnerable)" ;;
            1) pstatus green YES "mitigated" ;;
            *) pstatus yellow YES "unknown value: $rngds_enable" ;;
        esac
    else
        kernel_rngds=0
        pstatus yellow NO
    fi

    pr_info_nol "* SRBDS mitigation state: "
    rngds_state=$(sysctl -n machdep.mitigations.rngds.state 2>/dev/null)
    if [ -n "$rngds_state" ]; then
        if echo "$rngds_state" | grep -qi 'not.affected\|mitigat'; then
            pstatus green YES "$rngds_state"
        else
            pstatus yellow NO "$rngds_state"
        fi
    else
        pstatus yellow NO "sysctl not available"
    fi

    if ! is_cpu_affected "$cve"; then
        pvulnstatus "$cve" OK "your CPU vendor reported your CPU model as not affected"
    elif [ "$kernel_rngds" = 1 ] && [ "$rngds_enable" = 1 ]; then
        pvulnstatus "$cve" OK "SRBDS mitigation is enabled"
    elif [ "$kernel_rngds" = 1 ] && [ "$rngds_enable" = 0 ]; then
        pvulnstatus "$cve" VULN "SRBDS mitigation is supported but set to optimized mode (disabled for RDRAND/RDSEED)"
        explain "To enable full SRBDS mitigation, run \`sysctl machdep.mitigations.rngds.enable=1'.\n " \
            "To make this persistent, add 'machdep.mitigations.rngds.enable=1' to /etc/sysctl.conf."
    else
        pvulnstatus "$cve" VULN "your kernel doesn't support SRBDS mitigation, update it"
    fi
}
