feat: add detection of iTLB Multihit vuln/mitigation (CVE-2018-12207)

This commit is contained in:
Stéphane Lesimple
2019-11-24 19:25:56 +01:00
parent 8ddf6b2d6d
commit bd47275501
3 changed files with 293 additions and 139 deletions

View File

@ -163,7 +163,7 @@ global_critical=0
global_unknown=0
nrpe_vuln=''
supported_cve_list='CVE-2017-5753 CVE-2017-5715 CVE-2017-5754 CVE-2018-3640 CVE-2018-3639 CVE-2018-3615 CVE-2018-3620 CVE-2018-3646 CVE-2018-12126 CVE-2018-12130 CVE-2018-12127 CVE-2019-11091 CVE-2019-11135'
supported_cve_list='CVE-2017-5753 CVE-2017-5715 CVE-2017-5754 CVE-2018-3640 CVE-2018-3639 CVE-2018-3615 CVE-2018-3620 CVE-2018-3646 CVE-2018-12126 CVE-2018-12130 CVE-2018-12127 CVE-2019-11091 CVE-2019-11135 CVE-2018-12207'
# find a sane command to print colored messages, we prefer `printf` over `echo`
# because `printf` behavior is more standard across Linux/BSD
@ -285,7 +285,8 @@ cve2name()
CVE-2018-12130) echo "ZombieLoad, microarchitectural fill buffer data sampling (MFBDS)";;
CVE-2018-12127) echo "RIDL, microarchitectural load port data sampling (MLPDS)";;
CVE-2019-11091) echo "RIDL, microarchitectural data sampling uncacheable memory (MDSUM)";;
CVE-2019-11135) echo "Transactional Synchronization Extensions (TSX) Asynchronous Abort (TAA)";;
CVE-2019-11135) echo "ZombieLoad V2, TSX Asynchronous Abort (TAA)";;
CVE-2018-12207) echo "No eXcuses, iTLB Multihit";;
*) echo "$0: error: invalid CVE '$1' passed to cve2name()" >&2; exit 255;;
esac
}
@ -308,6 +309,7 @@ _is_cpu_vulnerable_cached()
CVE-2018-12127) return $variant_mlpds;;
CVE-2019-11091) return $variant_mdsum;;
CVE-2019-11135) return $variant_taa;;
CVE-2018-12207) return $variant_itlbmh;;
*) echo "$0: error: invalid variant '$1' passed to is_cpu_vulnerable()" >&2; exit 255;;
esac
}
@ -335,6 +337,7 @@ is_cpu_vulnerable()
variant_mlpds=''
variant_mdsum=''
variant_taa=''
variant_itlbmh=''
if is_cpu_mds_free; then
[ -z "$variant_msbds" ] && variant_msbds=immune
@ -406,25 +409,55 @@ is_cpu_vulnerable()
[ "$cpu_model" = "$INTEL_FAM6_ATOM_BONNELL_MID" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT_MID" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT_X" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT_D" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_AIRMONT" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_AIRMONT_MID" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_AIRMONT_NP" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT_X" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT_D" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT_PLUS" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_TREMONT_D" ] || \
[ "$cpu_model" = "$INTEL_FAM6_XEON_PHI_KNL" ] || \
[ "$cpu_model" = "$INTEL_FAM6_XEON_PHI_KNM" ]; then
_debug "is_cpu_vulnerable: intel family 6 but model known to be immune"
_debug "is_cpu_vulnerable: intel family 6 but model known to be immune to l1tf"
[ -z "$variantl1tf" ] && variantl1tf=immune
else
_debug "is_cpu_vulnerable: intel family 6 is vuln"
[ -z "$variantl1tf" ] && variantl1tf=vuln
_debug "is_cpu_vulnerable: intel family 6 is vuln to l1tf"
variantl1tf=vuln
fi
elif [ "$cpu_family" -lt 6 ]; then
_debug "is_cpu_vulnerable: intel family < 6 is immune"
_debug "is_cpu_vulnerable: intel family < 6 is immune to l1tf"
[ -z "$variantl1tf" ] && variantl1tf=immune
fi
# iTLB MultiHit
# commit f9aa6b73a407b714c9aac44734eb4045c893c6f7
if [ "$cpu_model" = 6 ]; then
if [ "$cpu_model" = "$INTEL_FAM6_ATOM_SALTWELL" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SALTWELL_TABLET" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SALTWELL_MID" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_BONNELL" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_BONNELL_MID" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT_D" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT_MID" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_AIRMONT" ] || \
[ "$cpu_model" = "$INTEL_FAM6_XEON_PHI_KNL" ] || \
[ "$cpu_model" = "$INTEL_FAM6_XEON_PHI_KNM" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_AIRMONT_MID" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT_D" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT_PLUS" ]; then
_debug "is_cpu_vulnerable: intel family 6 but model known to be immune to itlbmh"
[ -z "$variantitlbmh" ] && variantitlbmh=immune
else
_debug "is_cpu_vulnerable: intel family 6 is vuln to itlbmh"
variantitlbmh=vuln
fi
elif [ "$cpu_family" -lt 6 ]; then
_debug "is_cpu_vulnerable: intel family < 6 is immune to itlbmh"
[ -z "$variantitlbmh" ] && variantitlbmh=immune
fi
elif is_amd || is_hygon; then
# AMD revised their statement about variant2 => vulnerable
# https://www.amd.com/en/corporate/speculative-execution
@ -439,10 +472,12 @@ is_cpu_vulnerable()
_debug "is_cpu_vulnerable: cpu not affected by speculative store bypass so not vuln to variant4"
fi
variantl1tf=immune
variantitlbmh=immune
elif [ "$cpu_vendor" = CAVIUM ]; then
variant3=immune
variant3a=immune
variantl1tf=immune
variantitlbmh=immune
elif [ "$cpu_vendor" = ARM ]; then
# ARM
# reference: https://developer.arm.com/support/security-update
@ -531,19 +566,21 @@ is_cpu_vulnerable()
_debug "is_cpu_vulnerable: for cpu$i and so far, we have <$variant1> <$variant2> <$variant3> <$variant3a> <$variant4>"
done
variantl1tf=immune
variantitlbmh=immune
fi
_debug "is_cpu_vulnerable: temp results are <$variant1> <$variant2> <$variant3> <$variant3a> <$variant4> <$variantl1tf>"
[ "$variant1" = "immune" ] && variant1=1 || variant1=0
[ "$variant2" = "immune" ] && variant2=1 || variant2=0
[ "$variant3" = "immune" ] && variant3=1 || variant3=0
[ "$variant3a" = "immune" ] && variant3a=1 || variant3a=0
[ "$variant4" = "immune" ] && variant4=1 || variant4=0
[ "$variantl1tf" = "immune" ] && variantl1tf=1 || variantl1tf=0
[ "$variant_msbds" = "immune" ] && variant_msbds=1 || variant_msbds=0
[ "$variant_mfbds" = "immune" ] && variant_mfbds=1 || variant_mfbds=0
[ "$variant_mlpds" = "immune" ] && variant_mlpds=1 || variant_mlpds=0
[ "$variant_mdsum" = "immune" ] && variant_mdsum=1 || variant_mdsum=0
[ "$variant_taa" = "immune" ] && variant_taa=1 || variant_taa=0
[ "$variant1" = "immune" ] && variant1=1 || variant1=0
[ "$variant2" = "immune" ] && variant2=1 || variant2=0
[ "$variant3" = "immune" ] && variant3=1 || variant3=0
[ "$variant3a" = "immune" ] && variant3a=1 || variant3a=0
[ "$variant4" = "immune" ] && variant4=1 || variant4=0
[ "$variantl1tf" = "immune" ] && variantl1tf=1 || variantl1tf=0
[ "$variant_msbds" = "immune" ] && variant_msbds=1 || variant_msbds=0
[ "$variant_mfbds" = "immune" ] && variant_mfbds=1 || variant_mfbds=0
[ "$variant_mlpds" = "immune" ] && variant_mlpds=1 || variant_mlpds=0
[ "$variant_mdsum" = "immune" ] && variant_mdsum=1 || variant_mdsum=0
[ "$variant_taa" = "immune" ] && variant_taa=1 || variant_taa=0
[ "$variant_itlbmh" = "immune" ] && variant_itlbmh=1 || variant_itlbmh=0
variantl1tf_sgx="$variantl1tf"
# even if we are vulnerable to L1TF, if there's no SGX, we're safe for the original foreshadow
[ "$cpuid_sgx" = 0 ] && variantl1tf_sgx=1
@ -608,7 +645,7 @@ is_cpu_mds_free()
if is_intel; then
if [ "$cpu_family" = 6 ]; then
if [ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT_X" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT_D" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT_PLUS" ]; then
return 0
fi
@ -675,7 +712,7 @@ is_cpu_ssb_free()
if [ "$cpu_family" = 6 ]; then
if [ "$cpu_model" = "$INTEL_FAM6_ATOM_AIRMONT" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT_X" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT_D" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT_MID" ]; then
return 0
elif [ "$cpu_model" = "$INTEL_FAM6_CORE_YONAH" ] || \
@ -1077,6 +1114,7 @@ pvulnstatus()
CVE-2018-12127) aka="MLPDS";;
CVE-2019-11091) aka="MDSUM";;
CVE-2019-11135) aka="TAA";;
CVE-2018-12207) aka="ITLBMH";;
*) echo "$0: error: invalid CVE '$1' passed to pvulnstatus()" >&2; exit 255;;
esac
@ -1513,66 +1551,68 @@ parse_cpu_details()
ucode_found=$(printf "model 0x%x family 0x%x stepping 0x%x ucode 0x%x cpuid 0x%x" "$cpu_model" "$cpu_family" "$cpu_stepping" "$cpu_ucode" "$cpu_cpuid")
# also define those that we will need in other funcs
# taken from ttps://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/include/asm/intel-family.h
# taken from https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/include/asm/intel-family.h
# curl -s 'https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/arch/x86/include/asm/intel-family.h' | awk '/#define INTEL_FAM6/ {print $2"=$(( "$3" )) # "$4,$5,$6,$7,$8,$9}'
# shellcheck disable=SC2034
{
INTEL_FAM6_CORE_YONAH=$(( 0x0E )) #
INTEL_FAM6_CORE2_MEROM=$(( 0x0F )) #
INTEL_FAM6_CORE2_MEROM_L=$(( 0x16 )) #
INTEL_FAM6_CORE2_PENRYN=$(( 0x17 )) #
INTEL_FAM6_CORE2_DUNNINGTON=$(( 0x1D )) #
INTEL_FAM6_NEHALEM=$(( 0x1E )) #
INTEL_FAM6_NEHALEM_G=$(( 0x1F )) # /* Auburndale / Havendale */
INTEL_FAM6_NEHALEM_EP=$(( 0x1A )) #
INTEL_FAM6_NEHALEM_EX=$(( 0x2E )) #
INTEL_FAM6_WESTMERE=$(( 0x25 )) #
INTEL_FAM6_WESTMERE_EP=$(( 0x2C )) #
INTEL_FAM6_WESTMERE_EX=$(( 0x2F )) #
INTEL_FAM6_SANDYBRIDGE=$(( 0x2A )) #
INTEL_FAM6_SANDYBRIDGE_X=$(( 0x2D )) #
INTEL_FAM6_IVYBRIDGE=$(( 0x3A )) #
INTEL_FAM6_IVYBRIDGE_X=$(( 0x3E )) #
INTEL_FAM6_HASWELL=$(( 0x3C )) #
INTEL_FAM6_HASWELL_X=$(( 0x3F )) #
INTEL_FAM6_HASWELL_L=$(( 0x45 )) #
INTEL_FAM6_HASWELL_G=$(( 0x46 )) #
INTEL_FAM6_BROADWELL=$(( 0x3D )) #
INTEL_FAM6_BROADWELL_G=$(( 0x47 )) #
INTEL_FAM6_BROADWELL_X=$(( 0x4F )) #
INTEL_FAM6_BROADWELL_D=$(( 0x56 )) #
INTEL_FAM6_SKYLAKE_L=$(( 0x4E )) #
INTEL_FAM6_SKYLAKE=$(( 0x5E )) #
INTEL_FAM6_SKYLAKE_X=$(( 0x55 )) #
INTEL_FAM6_KABYLAKE_L=$(( 0x8E )) #
INTEL_FAM6_KABYLAKE=$(( 0x9E )) #
INTEL_FAM6_CANNONLAKE_L=$(( 0x66 )) #
INTEL_FAM6_ICELAKE_X=$(( 0x6A )) #
INTEL_FAM6_ICELAKE_D=$(( 0x6C )) #
INTEL_FAM6_ICELAKE=$(( 0x7D )) #
INTEL_FAM6_ICELAKE_L=$(( 0x7E )) #
INTEL_FAM6_ICELAKE_NNPI=$(( 0x9D )) #
INTEL_FAM6_TIGERLAKE_L=$(( 0x8C )) #
INTEL_FAM6_TIGERLAKE=$(( 0x8D )) #
INTEL_FAM6_COMETLAKE=$(( 0xA5 )) #
INTEL_FAM6_COMETLAKE_L=$(( 0xA6 )) #
INTEL_FAM6_ATOM_BONNELL=$(( 0x1C )) # /* Diamondville, Pineview */
INTEL_FAM6_ATOM_BONNELL_MID=$(( 0x26 )) # /* Silverthorne, Lincroft */
INTEL_FAM6_ATOM_SALTWELL=$(( 0x36 )) # /* Cedarview */
INTEL_FAM6_ATOM_SALTWELL_MID=$(( 0x27 )) # /* Penwell */
INTEL_FAM6_ATOM_SALTWELL_TABLET=$(( 0x35 )) # /* Cloverview */
INTEL_FAM6_ATOM_SILVERMONT=$(( 0x37 )) # /* Bay Trail, Valleyview */
INTEL_FAM6_ATOM_SILVERMONT_D=$(( 0x4D )) # /* Avaton, Rangely */
INTEL_FAM6_ATOM_SILVERMONT_MID=$(( 0x4A )) # /* Merriefield */
INTEL_FAM6_ATOM_AIRMONT=$(( 0x4C )) # /* Cherry Trail, Braswell */
INTEL_FAM6_ATOM_AIRMONT_MID=$(( 0x5A )) # /* Moorefield */
INTEL_FAM6_ATOM_AIRMONT_NP=$(( 0x75 )) # /* Lightning Mountain */
INTEL_FAM6_ATOM_GOLDMONT=$(( 0x5C )) # /* Apollo Lake */
INTEL_FAM6_ATOM_GOLDMONT_D=$(( 0x5F )) # /* Denverton */
INTEL_FAM6_ATOM_GOLDMONT_PLUS=$(( 0x7A )) # /* Gemini Lake */
INTEL_FAM6_ATOM_TREMONT_D=$(( 0x86 )) # /* Jacobsville */
INTEL_FAM6_ATOM_TREMONT=$(( 0x96 )) # /* Elkhart Lake */
INTEL_FAM6_XEON_PHI_KNL=$(( 0x57 )) # /* Knights Landing */
INTEL_FAM6_XEON_PHI_KNM=$(( 0x85 )) # /* Knights Mill */
INTEL_FAM6_CORE_YONAH=$(( 0x0E ))
INTEL_FAM6_CORE2_MEROM=$(( 0x0F ))
INTEL_FAM6_CORE2_MEROM_L=$(( 0x16 ))
INTEL_FAM6_CORE2_PENRYN=$(( 0x17 ))
INTEL_FAM6_CORE2_DUNNINGTON=$(( 0x1D ))
INTEL_FAM6_NEHALEM=$(( 0x1E ))
INTEL_FAM6_NEHALEM_G=$(( 0x1F ))
INTEL_FAM6_NEHALEM_EP=$(( 0x1A ))
INTEL_FAM6_NEHALEM_EX=$(( 0x2E ))
INTEL_FAM6_WESTMERE=$(( 0x25 ))
INTEL_FAM6_WESTMERE_EP=$(( 0x2C ))
INTEL_FAM6_WESTMERE_EX=$(( 0x2F ))
INTEL_FAM6_SANDYBRIDGE=$(( 0x2A ))
INTEL_FAM6_SANDYBRIDGE_X=$(( 0x2D ))
INTEL_FAM6_IVYBRIDGE=$(( 0x3A ))
INTEL_FAM6_IVYBRIDGE_X=$(( 0x3E ))
INTEL_FAM6_HASWELL_CORE=$(( 0x3C ))
INTEL_FAM6_HASWELL_X=$(( 0x3F ))
INTEL_FAM6_HASWELL_ULT=$(( 0x45 ))
INTEL_FAM6_HASWELL_GT3E=$(( 0x46 ))
INTEL_FAM6_BROADWELL_CORE=$(( 0x3D ))
INTEL_FAM6_BROADWELL_GT3E=$(( 0x47 ))
INTEL_FAM6_BROADWELL_X=$(( 0x4F ))
INTEL_FAM6_BROADWELL_XEON_D=$(( 0x56 ))
INTEL_FAM6_SKYLAKE_MOBILE=$(( 0x4E ))
INTEL_FAM6_SKYLAKE_DESKTOP=$(( 0x5E ))
INTEL_FAM6_SKYLAKE_X=$(( 0x55 ))
INTEL_FAM6_KABYLAKE_MOBILE=$(( 0x8E ))
INTEL_FAM6_KABYLAKE_DESKTOP=$(( 0x9E ))
# /* "Small Core" Processors (Atom) */
INTEL_FAM6_ATOM_BONNELL=$(( 0x1C ))
INTEL_FAM6_ATOM_BONNELL_MID=$(( 0x26 ))
INTEL_FAM6_ATOM_SALTWELL_MID=$(( 0x27 ))
INTEL_FAM6_ATOM_SALTWELL_TABLET=$(( 0x35 ))
INTEL_FAM6_ATOM_SALTWELL=$(( 0x36 ))
INTEL_FAM6_ATOM_SILVERMONT=$(( 0x37 ))
INTEL_FAM6_ATOM_SILVERMONT_MID=$(( 0x4A ))
INTEL_FAM6_ATOM_SILVERMONT_X=$(( 0x4D ))
INTEL_FAM6_ATOM_AIRMONT=$(( 0x4C ))
INTEL_FAM6_ATOM_AIRMONT_MID=$(( 0x5A ))
INTEL_FAM6_ATOM_GOLDMONT=$(( 0x5C ))
INTEL_FAM6_ATOM_GOLDMONT_X=$(( 0x5F ))
INTEL_FAM6_ATOM_GOLDMONT_PLUS=$(( 0x7A ))
# /* Xeon Phi */
INTEL_FAM6_XEON_PHI_KNL=$(( 0x57 ))
INTEL_FAM6_XEON_PHI_KNM=$(( 0x85 ))
}
parse_cpu_details_done=1
}
@ -1639,7 +1679,7 @@ is_ucode_blacklisted()
$INTEL_FAM6_BROADWELL_XEON_D,0x03,0x07000011 \
$INTEL_FAM6_BROADWELL_X,0x01,0x0b000023 \
$INTEL_FAM6_BROADWELL_X,0x01,0x0b000025 \
$INTEL_FAM6_HASWELL_ULT,0x01,0x21 \
$INTEL_FAM6_HASWELL_L,0x01,0x21 \
$INTEL_FAM6_HASWELL_GT3E,0x01,0x18 \
$INTEL_FAM6_HASWELL_CORE,0x03,0x23 \
$INTEL_FAM6_HASWELL_X,0x02,0x3b \
@ -1648,10 +1688,10 @@ is_ucode_blacklisted()
$INTEL_FAM6_SANDYBRIDGE_X,0x06,0x61b \
$INTEL_FAM6_SANDYBRIDGE_X,0x07,0x712
do
model=$(echo $tuple | cut -d, -f1)
stepping=$(( $(echo $tuple | cut -d, -f2) ))
model=$(echo "$tuple" | cut -d, -f1)
stepping=$(( $(echo "$tuple" | cut -d, -f2) ))
if [ "$cpu_model" = "$model" ] && [ "$cpu_stepping" = "$stepping" ]; then
ucode=$(( $(echo $tuple | cut -d, -f3) ))
ucode=$(( $(echo "$tuple" | cut -d, -f3) ))
if [ "$cpu_ucode" = "$ucode" ]; then
_debug "is_ucode_blacklisted: we have a match! ($cpu_model/$cpu_stepping/$cpu_ucode)"
return 0
@ -1678,11 +1718,11 @@ is_skylake_cpu()
parse_cpu_details
is_intel || return 1
[ "$cpu_family" = 6 ] || return 1
if [ "$cpu_model" = $INTEL_FAM6_SKYLAKE_MOBILE ] || \
[ "$cpu_model" = $INTEL_FAM6_SKYLAKE_DESKTOP ] || \
[ "$cpu_model" = $INTEL_FAM6_SKYLAKE_X ] || \
[ "$cpu_model" = $INTEL_FAM6_KABYLAKE_MOBILE ] || \
[ "$cpu_model" = $INTEL_FAM6_KABYLAKE_DESKTOP ]; then
if [ "$cpu_model" = $INTEL_FAM6_SKYLAKE_L ] || \
[ "$cpu_model" = $INTEL_FAM6_SKYLAKE ] || \
[ "$cpu_model" = $INTEL_FAM6_SKYLAKE_X ] || \
[ "$cpu_model" = $INTEL_FAM6_KABYLAKE_L ] || \
[ "$cpu_model" = $INTEL_FAM6_KABYLAKE ]; then
return 0
fi
return 1
@ -2138,7 +2178,7 @@ sys_interface_check()
# Not affected
status=OK
pstatus green YES "$fullmsg"
elif echo "$msg" | grep -qi '^mitigation'; then
elif echo "$msg" | grep -qEi '^(kvm: )?mitigation'; then
# Mitigation: PTI
status=OK
pstatus green YES "$fullmsg"
@ -2709,6 +2749,7 @@ check_cpu()
capabilities_rsba=-1
capabilities_l1dflush_no=-1
capabilities_ssb_no=-1
capabilities_pschange_msc_no=-1
if [ "$cpuid_arch_capabilities" = -1 ]; then
pstatus yellow UNKNOWN
elif [ "$cpuid_arch_capabilities" != 1 ]; then
@ -2719,6 +2760,7 @@ check_cpu()
capabilities_rsba=0
capabilities_l1dflush_no=0
capabilities_ssb_no=0
capabilities_pschange_msc_no=0
pstatus yellow NO
elif [ ! -e /dev/cpu/0/msr ] && [ ! -e /dev/cpuctl0 ]; then
spec_ctrl_msr=-1
@ -2752,6 +2794,7 @@ check_cpu()
capabilities_rsba=0
capabilities_l1dflush_no=0
capabilities_ssb_no=0
capabilities_pschange_msc_no=0
if [ $val -eq 0 ]; then
_debug "capabilities MSR is $capabilities (decimal)"
[ $(( capabilities >> 0 & 1 )) -eq 1 ] && capabilities_rdcl_no=1
@ -2760,8 +2803,9 @@ check_cpu()
[ $(( capabilities >> 3 & 1 )) -eq 1 ] && capabilities_l1dflush_no=1
[ $(( capabilities >> 4 & 1 )) -eq 1 ] && capabilities_ssb_no=1
[ $(( capabilities >> 5 & 1 )) -eq 1 ] && capabilities_mds_no=1
[ $(( capabilities >> 6 & 1 )) -eq 1 ] && capabilities_pschange_msc_no=1
[ $(( capabilities >> 8 & 1 )) -eq 1 ] && capabilities_taa_no=1
_debug "capabilities says rdcl_no=$capabilities_rdcl_no ibrs_all=$capabilities_ibrs_all rsba=$capabilities_rsba l1dflush_no=$capabilities_l1dflush_no ssb_no=$capabilities_ssb_no mds_no=$capabilities_mds_no taa_no=$capabilities_taa_no"
_debug "capabilities says rdcl_no=$capabilities_rdcl_no ibrs_all=$capabilities_ibrs_all rsba=$capabilities_rsba l1dflush_no=$capabilities_l1dflush_no ssb_no=$capabilities_ssb_no mds_no=$capabilities_mds_no taa_no=$capabilities_taa_no pschange_msc_no=$capabilities_pschange_msc_no"
if [ "$capabilities_ibrs_all" = 1 ]; then
if [ $cpu_mismatch -eq 0 ]; then
pstatus green YES
@ -2827,7 +2871,7 @@ check_cpu()
pstatus yellow NO
fi
_info_nol " * CPU explicitly indicates not being vulnerable to TSX Asynchrnonous Abort (TAA_NO): "
_info_nol " * CPU explicitly indicates not being vulnerable to TSX Asynchronous Abort (TAA_NO): "
if [ "$capabilities_taa_no" = -1 ]; then
pstatus yellow UNKNOWN
elif [ "$capabilities_taa_no" = 1 ]; then
@ -2835,6 +2879,15 @@ check_cpu()
else
pstatus yellow NO
fi
_info_nol " * CPU explicitly indicates not being vulnerable to iTLB Multihit (PSCHANGE_MSC_NO): "
if [ "$capabilities_pschange_msc_no" = -1 ]; then
pstatus yellow UNKNOWN
elif [ "$capabilities_pschange_msc_no" = 1 ]; then
pstatus green YES
else
pstatus yellow NO
fi
fi
_info_nol " * CPU supports Software Guard Extensions (SGX): "
@ -2918,6 +2971,52 @@ check_redhat_canonical_spectre()
fi
}
check_has_vmm()
{
_info_nol "* This system is a host running a hypervisor: "
has_vmm=$opt_vmm
if [ "$has_vmm" = -1 ] && [ "$opt_paranoid" = 1 ]; then
# In paranoid mode, if --vmm was not specified on the command-line,
# we want to be secure before everything else, so assume we're running
# a hypervisor, as this requires more mitigations
has_vmm=2
elif [ "$has_vmm" = -1 ]; then
# Here, we want to know if we are hosting a hypervisor, and running some VMs on it.
# If we find no evidence that this is the case, assume we're not (to avoid scaring users),
# this can always be overridden with --vmm in any case.
has_vmm=0
if command -v pgrep >/dev/null 2>&1; then
# remove xenbus and xenwatch, also present inside domU
# remove libvirtd as it can also be used to manage containers and not VMs
if pgrep qemu >/dev/null || pgrep kvm >/dev/null || \
pgrep xenstored >/dev/null || pgrep xenconsoled >/dev/null; then
has_vmm=1
fi
else
# ignore SC2009 as `ps ax` is actually used as a fallback if `pgrep` isn't installed
# shellcheck disable=SC2009
if ps ax | grep -vw grep | grep -q -e '\<qemu' -e '/qemu' -e '<\kvm' -e '/kvm' -e '/xenstored' -e '/xenconsoled'; then
has_vmm=1
fi
fi
fi
if [ "$has_vmm" = 0 ]; then
if [ "$opt_vmm" != -1 ]; then
pstatus green NO "forced from command line"
else
pstatus green NO
fi
else
if [ "$opt_vmm" != -1 ]; then
pstatus blue YES "forced from command line"
elif [ "$has_vmm" = 2 ]; then
pstatus blue YES "paranoid mode"
else
pstatus blue YES
fi
fi
}
###################
# SPECTRE 1 SECTION
@ -4210,7 +4309,7 @@ check_CVE_2018_3615()
_info "\033[1;34m$cve aka '$(cve2name "$cve")'\033[0m"
_info_nol "* CPU microcode mitigates the vulnerability: "
if ( [ "$cpu_flush_cmd" = 1 ] || ( [ "$msr_locked_down" = 1 ] && [ "$cpuid_l1df" = 1 ] ) ) && [ "$cpuid_sgx" = 1 ]; then
if { [ "$cpu_flush_cmd" = 1 ] || { [ "$msr_locked_down" = 1 ] && [ "$cpuid_l1df" = 1 ]; }; } && [ "$cpuid_sgx" = 1 ]; then
# no easy way to detect a fixed SGX but we know that
# microcodes that have the FLUSH_CMD MSR also have the
# fixed SGX (for CPUs that support it), because Intel
@ -4229,7 +4328,7 @@ check_CVE_2018_3615()
if ! is_cpu_vulnerable "$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 vulnerable"
elif [ "$cpu_flush_cmd" = 1 ] || ( [ "$msr_locked_down" = 1 ] && [ "$cpuid_l1df" = 1 ] ) ; then
elif [ "$cpu_flush_cmd" = 1 ] || { [ "$msr_locked_down" = 1 ] && [ "$cpuid_l1df" = 1 ]; } ; then
pvulnstatus $cve OK "your CPU microcode mitigates the vulnerability"
else
pvulnstatus $cve VULN "your CPU supports SGX and the microcode is not up to date"
@ -4377,48 +4476,7 @@ check_CVE_2018_3646_linux()
fi
l1d_mode=-1
if [ "$opt_sysfs_only" != 1 ]; then
_info_nol "* This system is a host running a hypervisor: "
has_vmm=$opt_vmm
if [ "$has_vmm" = -1 ] && [ "$opt_paranoid" = 1 ]; then
# In paranoid mode, if --vmm was not specified on the command-line,
# we want to be secure before everything else, so assume we're running
# a hypervisor, as this requires more mitigations
has_vmm=2
elif [ "$has_vmm" = -1 ]; then
# Here, we want to know if we are hosting a hypervisor, and running some VMs on it.
# If we find no evidence that this is the case, assume we're not (to avoid scaring users),
# this can always be overridden with --vmm in any case.
has_vmm=0
if command -v pgrep >/dev/null 2>&1; then
# remove xenbus and xenwatch, also present inside domU
# remove libvirtd as it can also be used to manage containers and not VMs
if pgrep qemu >/dev/null || pgrep kvm >/dev/null || \
pgrep xenstored >/dev/null || pgrep xenconsoled >/dev/null; then
has_vmm=1
fi
else
# ignore SC2009 as `ps ax` is actually used as a fallback if `pgrep` isn't installed
# shellcheck disable=SC2009
if ps ax | grep -vw grep | grep -q -e '\<qemu' -e '/qemu' -e '<\kvm' -e '/kvm' -e '/xenstored' -e '/xenconsoled'; then
has_vmm=1
fi
fi
fi
if [ "$has_vmm" = 0 ]; then
if [ "$opt_vmm" != -1 ]; then
pstatus green NO "forced from command line"
else
pstatus green NO
fi
else
if [ "$opt_vmm" != -1 ]; then
pstatus blue YES "forced from command line"
elif [ "$has_vmm" = 2 ]; then
pstatus blue YES "paranoid mode"
else
pstatus blue YES
fi
fi
check_has_vmm
_info "* Mitigation 1 (KVM)"
_info_nol " * EPT is disabled: "
@ -4978,6 +5036,95 @@ check_CVE_2019_11135_linux()
fi
}
#######################
# iTLB Multihit section
check_CVE_2018_12207()
{
cve='CVE-2018-12207'
_info "\033[1;34m$cve aka '$(cve2name "$cve")'\033[0m"
if [ "$os" = Linux ]; then
check_CVE_2018_12207_linux
#elif echo "$os" | grep -q BSD; then
# check_CVE_2018_12207_bsd
else
_warn "Unsupported OS ($os)"
fi
}
check_CVE_2018_12207_linux()
{
status=UNK
sys_interface_available=0
msg=''
if sys_interface_check "/sys/devices/system/cpu/vulnerabilities/itlb_multihit"; then
# this kernel has the /sys interface, trust it over everything
sys_interface_available=1
fi
if [ "$opt_sysfs_only" != 1 ]; then
check_has_vmm
_info_nol "* iTLB Multihit mitigation is supported by kernel: "
kernel_itlbmh=''
if [ -n "$kernel_err" ]; then
kernel_itlbmh_err="$kernel_err"
# commit 5219505fcbb640e273a0d51c19c38de0100ec5a9
elif grep -q 'itlb_multihit' "$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
_info_nol "* iTLB Multihit mitigation enabled and active: "
if [ "$opt_live" = 1 ]; then
if [ -n "$fullmsg" ]; then
if echo "$fullmsg" | grep -qF 'Mitigation'; then
pstatus green YES "$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 offline 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_vulnerable "$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 vulnerable"
elif [ "$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_live" = 1 ]; 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
pvulnstatus $cve "$status" "$msg"
fi
}
#######################
# END OF VULNS SECTIONS
if [ "$opt_no_hw" = 0 ] && [ -z "$opt_arch_prefix" ]; then
check_cpu
check_cpu_vulnerabilities