# vim: set ts=4 sw=4 sts=4 et:
###############################
# CVE-2019-11135, TAA, ZombieLoad V2, TSX Asynchronous Abort

check_CVE_2019_11135() {
    check_cve 'CVE-2019-11135'
}

check_CVE_2019_11135_linux() {
    local status sys_interface_available msg kernel_taa kernel_taa_err
    status=UNK
    sys_interface_available=0
    msg=''
    if sys_interface_check "$VULN_SYSFS_BASE/tsx_async_abort"; 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 "* TAA mitigation is supported by kernel: "
        kernel_taa=''
        if [ -n "$g_kernel_err" ]; then
            kernel_taa_err="$g_kernel_err"
        elif is_x86_kernel && grep -q 'tsx_async_abort' "$g_kernel"; then
            kernel_taa="found tsx_async_abort in kernel image"
        fi
        if [ -n "$kernel_taa" ]; then
            pstatus green YES "$kernel_taa"
        elif [ -n "$kernel_taa_err" ]; then
            pstatus yellow UNKNOWN "$kernel_taa_err"
        else
            pstatus yellow NO
        fi

        pr_info_nol "* TAA mitigation 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 "tsx_async_abort 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"
    elif [ -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" VULN "Your kernel doesn't support TAA mitigation, update it"
        else
            if [ -n "$kernel_taa" ]; then
                pvulnstatus "$cve" OK "Your kernel supports TAA mitigation"
            else
                pvulnstatus "$cve" VULN "Your kernel doesn't support TAA mitigation, update it"
            fi
        fi
    else
        if [ "$opt_paranoid" = 1 ]; then
            # in paranoid mode, TSX or SMT enabled are not OK, even if TAA is mitigated
            # first check sysfs, then fall back to MSR-based detection for older kernels
            # that may not report TSX as disabled even when microcode has done so
            tsx_disabled=0
            if echo "$ret_sys_interface_check_fullmsg" | grep -qF 'TSX disabled'; then
                tsx_disabled=1
            elif [ "$cap_tsx_ctrl_rtm_disable" = 1 ] && [ "$cap_tsx_ctrl_cpuid_clear" = 1 ]; then
                # TSX disabled via IA32_TSX_CTRL MSR (0x122)
                tsx_disabled=1
            elif [ "$cap_tsx_force_abort_rtm_disable" = 1 ] && [ "$cap_tsx_force_abort_cpuid_clear" = 1 ]; then
                # TSX disabled via IA32_TSX_FORCE_ABORT MSR (0x10F), for older Skylake-era CPUs
                tsx_disabled=1
            fi
            if [ "$tsx_disabled" = 0 ]; then
                pvulnstatus "$cve" VULN "TSX must be disabled for full mitigation"
            elif echo "$ret_sys_interface_check_fullmsg" | grep -qF 'SMT vulnerable'; then
                pvulnstatus "$cve" VULN "SMT (HyperThreading) must be disabled for full mitigation"
            elif echo "$ret_sys_interface_check_fullmsg" | grep -qF 'SMT Host state unknown'; then
                # "SMT Host state unknown" is emitted whenever the HYPERVISOR
                # CPUID bit is set -- true both inside a guest AND on a Xen dom0
                # (#343). In a guest we can't see the host's SMT scheduling; on
                # dom0/bare metal the local SMT state is authoritative, so trust
                # it there.
                if is_running_as_guest; then
                    pvulnstatus "$cve" UNK "TAA is mitigated and TSX is disabled, but SMT (Hyper-Threading) cross-thread protection can't be verified from inside a VM guest: it depends on the hypervisor host's SMT/core-scheduling configuration"
                elif is_cpu_smt_enabled; then
                    pvulnstatus "$cve" VULN "SMT (HyperThreading) must be disabled for full mitigation"
                else
                    pvulnstatus "$cve" "$status" "$msg"
                fi
            else
                pvulnstatus "$cve" "$status" "$msg"
            fi
        else
            pvulnstatus "$cve" "$status" "$msg"
        fi
    fi
}

check_CVE_2019_11135_bsd() {
    local taa_enable taa_state mds_disable kernel_taa kernel_mds
    pr_info_nol "* Kernel supports TAA mitigation (machdep.mitigations.taa.enable): "
    taa_enable=$(sysctl -n machdep.mitigations.taa.enable 2>/dev/null)
    if [ -n "$taa_enable" ]; then
        kernel_taa=1
        case "$taa_enable" in
            0) pstatus yellow YES "disabled" ;;
            1) pstatus green YES "TSX disabled via MSR" ;;
            2) pstatus green YES "VERW mitigation" ;;
            3) pstatus green YES "auto" ;;
            *) pstatus yellow YES "unknown value: $taa_enable" ;;
        esac
    else
        kernel_taa=0
        pstatus yellow NO
    fi

    pr_info_nol "* TAA mitigation state: "
    taa_state=$(sysctl -n machdep.mitigations.taa.state 2>/dev/null)
    if [ -n "$taa_state" ]; then
        if echo "$taa_state" | grep -qi 'not.affected\|mitigation'; then
            pstatus green YES "$taa_state"
        else
            pstatus yellow NO "$taa_state"
        fi
    else
        # fallback: TAA is also mitigated by MDS VERW if enabled
        mds_disable=$(sysctl -n hw.mds_disable 2>/dev/null)
        if [ -z "$mds_disable" ]; then
            mds_disable=$(sysctl -n machdep.mitigations.mds.disable 2>/dev/null)
        fi
        if [ -n "$mds_disable" ] && [ "$mds_disable" != 0 ]; then
            kernel_mds=1
            pstatus green YES "MDS VERW mitigation active (also covers TAA)"
        else
            kernel_mds=0
            pstatus yellow NO "no TAA or MDS sysctl found"
        fi
    fi

    if ! is_cpu_affected "$cve"; then
        pvulnstatus "$cve" OK "your CPU vendor reported your CPU model as not affected"
    elif [ "$kernel_taa" = 1 ] && [ "$taa_enable" != 0 ]; then
        pvulnstatus "$cve" OK "TAA mitigation is enabled"
    elif [ "$kernel_mds" = 1 ]; then
        pvulnstatus "$cve" OK "MDS VERW mitigation is active and also covers TAA"
    elif [ "$kernel_taa" = 1 ] && [ "$taa_enable" = 0 ]; then
        pvulnstatus "$cve" VULN "TAA mitigation is supported but disabled"
        explain "To enable TAA mitigation, run \`sysctl machdep.mitigations.taa.enable=3' for auto mode.\n " \
            "To make this persistent, add 'machdep.mitigations.taa.enable=3' to /etc/sysctl.conf."
    else
        pvulnstatus "$cve" VULN "your kernel doesn't support TAA mitigation, update it"
    fi
}
