# vim: set ts=4 sw=4 sts=4 et:
###############################
# CVE-2018-3620, Foreshadow-NG (OS/SMM), L1 Terminal Fault

check_CVE_2018_3620() {
    check_cve 'CVE-2018-3620'
}

check_CVE_2018_3620_linux() {
    local status sys_interface_available msg pteinv_supported pteinv_active
    status=UNK
    sys_interface_available=0
    msg=''
    if sys_interface_check "$VULN_SYSFS_BASE/l1tf"; then
        # this kernel has the /sys interface, trust it over everything
        sys_interface_available=1
        status=$ret_sys_interface_check_status
        msg=$ret_sys_interface_check_fullmsg
    fi
    if [ "$opt_sysfs_only" != 1 ]; then
        pr_info_nol "* Kernel supports PTE inversion: "
        if ! command -v "${opt_arch_prefix}strings" >/dev/null 2>&1; then
            pstatus yellow UNKNOWN "missing 'strings' tool, please install it"
            pteinv_supported=-1
        elif [ -n "$g_kernel_err" ]; then
            pstatus yellow UNKNOWN "$g_kernel_err"
            pteinv_supported=-1
        else
            if "${opt_arch_prefix}strings" "$g_kernel" | grep -Fq 'PTE Inversion'; then
                pstatus green YES "found in kernel image"
                pr_debug "pteinv: found pte inversion evidence in kernel image"
                pteinv_supported=1
            else
                pstatus yellow NO
                pteinv_supported=0
            fi
        fi

        pr_info_nol "* PTE inversion enabled and active: "
        if [ "$g_mode" = live ]; then
            if [ -n "$ret_sys_interface_check_fullmsg" ]; then
                if echo "$ret_sys_interface_check_fullmsg" | grep -q 'Mitigation: PTE Inversion'; then
                    pstatus green YES
                    pteinv_active=1
                else
                    pstatus yellow NO
                    pteinv_active=0
                fi
            else
                pstatus yellow UNKNOWN "sysfs interface not available"
                pteinv_active=-1
            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 [ "$opt_sysfs_only" != 1 ]; then
            if [ "$pteinv_supported" = 1 ]; then
                if [ "$pteinv_active" = 1 ] || [ "$g_mode" != live ]; then
                    pvulnstatus "$cve" OK "PTE inversion mitigates the vulnerability"
                else
                    pvulnstatus "$cve" VULN "Your kernel supports PTE inversion but it doesn't seem to be enabled"
                fi
            else
                pvulnstatus "$cve" VULN "Your kernel doesn't support PTE inversion, update it"
            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_3620_bsd() {
    local bsd_zero_reserved
    pr_info_nol "* Kernel reserved the memory page at physical address 0x0: "
    if ! kldstat -q -m vmm; then
        kldload vmm 2>/dev/null && g_kldload_vmm=1
        pr_debug "attempted to load module vmm, g_kldload_vmm=$g_kldload_vmm"
    else
        pr_debug "vmm module already loaded"
    fi
    if sysctl hw.vmm.vmx.l1d_flush >/dev/null 2>&1; then
        # https://security.FreeBSD.org/patches/SA-18:09/l1tf-11.2.patch
        # this is very difficult to detect that the kernel reserved the 0 page, but this fix
        # is part of the exact same patch than the other L1TF CVE, so we detect it
        # and deem it as OK if the other patch is there
        pstatus green YES
        bsd_zero_reserved=1
    else
        pstatus yellow NO
        bsd_zero_reserved=0
    fi

    if ! is_cpu_affected "$cve"; then
        pvulnstatus "$cve" OK "your CPU vendor reported your CPU model as not affected"
    else
        if [ "$bsd_zero_reserved" = 1 ]; then
            pvulnstatus "$cve" OK "kernel mitigates the vulnerability"
        else
            pvulnstatus "$cve" VULN "your kernel needs to be updated"
        fi
    fi
}
