# vim: set ts=4 sw=4 sts=4 et:
###############################
# CVE-2018-12207, iTLB Multihit, No eXcuses, Machine Check Exception on Page Size Changes

check_CVE_2018_12207() {
    check_cve 'CVE-2018-12207'
}

check_CVE_2018_12207_linux() {
    local status sys_interface_available msg kernel_itlbmh kernel_itlbmh_err
    status=UNK
    sys_interface_available=0
    msg=''
    if sys_interface_check "$VULN_SYSFS_BASE/itlb_multihit"; 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
        check_has_vmm

        pr_info_nol "* iTLB Multihit mitigation is supported by kernel: "
        kernel_itlbmh=''
        if [ -n "$g_kernel_err" ]; then
            kernel_itlbmh_err="$g_kernel_err"
        # commit 5219505fcbb640e273a0d51c19c38de0100ec5a9
        elif is_x86_kernel && grep -q 'itlb_multihit' "$g_kernel"; then
            kernel_itlbmh="found itlb_multihit in kernel image"
        fi
        if [ -n "$kernel_itlbmh" ]; then
            pstatus green YES "$kernel_itlbmh"
        elif [ -n "$kernel_itlbmh_err" ]; then
            pstatus yellow UNKNOWN "$kernel_itlbmh_err"
        else
            pstatus yellow NO
        fi

        pr_info_nol "* iTLB Multihit 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 -qF 'Mitigation'; then
                    pstatus green YES "$ret_sys_interface_check_fullmsg"
                else
                    pstatus yellow NO
                fi
            else
                pstatus yellow NO "itlb_multihit 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 [ "$g_has_vmm" = 0 ]; then
        pvulnstatus "$cve" OK "this system is not running a hypervisor"
    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 [ "$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 iTLB Multihit mitigation, update it"
            else
                if [ -n "$kernel_itlbmh" ]; then
                    pvulnstatus "$cve" OK "Your kernel supports iTLB Multihit mitigation"
                else
                    pvulnstatus "$cve" VULN "Your kernel doesn't support iTLB Multihit mitigation, update it"
                fi
            fi
        else
            # --sysfs-only: sysfs was available (otherwise msg would be set), use its result
            pvulnstatus "$cve" "$status" "$ret_sys_interface_check_fullmsg"
        fi
    else
        # msg was set explicitly: either sysfs-not-available error, or a sysfs override
        pvulnstatus "$cve" "$status" "$msg"
    fi
}

check_CVE_2018_12207_bsd() {
    local kernel_2m_x_ept
    pr_info_nol "* Kernel supports disabling superpages for executable mappings under EPT: "
    kernel_2m_x_ept=$(sysctl -n vm.pmap.allow_2m_x_ept 2>/dev/null)
    if [ -z "$kernel_2m_x_ept" ]; then
        pstatus yellow NO
    else
        pstatus green YES
    fi

    pr_info_nol "* Superpages are disabled for executable mappings under EPT: "
    if [ "$kernel_2m_x_ept" = 0 ]; then
        pstatus green YES
    else
        pstatus yellow NO
    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 "$kernel_2m_x_ept" ]; then
        pvulnstatus "$cve" VULN "Your kernel doesn't support mitigating this CVE, you should update it"
    elif [ "$kernel_2m_x_ept" != 0 ]; then
        pvulnstatus "$cve" VULN "Your kernel supports mitigating this CVE, but the mitigation is disabled"
        explain "To enable the mitigation, use \`sysctl vm.pmap.allow_2m_x_ept=0\`"
    else
        pvulnstatus "$cve" OK "Your kernel has support for mitigation and the mitigation is enabled"
    fi
}
