feat(ibpb): now also check for IBPB on variant 2

In addition to IBRS (and microcode support), IBPB
must be used to mitigate variant 2, if retpoline
support is not available. The vulnerability status
of a system will be defined as "non vulnerable"
if IBRS and IBPB are both enabled, or if IBPB
is enabled with a value of 2 for RedHat kernels,
see https://access.redhat.com/articles/3311301
This commit is contained in:
Stéphane Lesimple 2018-01-21 13:48:05 +01:00
parent 3e454f1817
commit 443d9a2ae9

View File

@ -862,8 +862,9 @@ check_variant2()
sys_interface_available=1 sys_interface_available=1
else else
_info "* Mitigation 1" _info "* Mitigation 1"
_info "* Hardware (CPU microcode) support for mitigation" _info " * Hardware support (CPU microcode)"
_info_nol "* The SPEC_CTRL MSR is available: " _info " * Indirect Branch Restricted Speculation (IBRS)"
_info_nol " * SPEC_CTRL MSR is available: "
if [ ! -e /dev/cpu/0/msr ]; then if [ ! -e /dev/cpu/0/msr ]; then
# try to load the module ourselves (and remember it so we can rmmod it afterwards) # try to load the module ourselves (and remember it so we can rmmod it afterwards)
load_msr load_msr
@ -873,7 +874,8 @@ check_variant2()
else else
# the new MSR 'SPEC_CTRL' is at offset 0x48 # the new MSR 'SPEC_CTRL' is at offset 0x48
# here we use dd, it's the same as using 'rdmsr 0x48' but without needing the rdmsr tool # here we use dd, it's the same as using 'rdmsr 0x48' but without needing the rdmsr tool
# if we get a read error, the MSR is not there # if we get a read error, the MSR is not there. bs has to be 8 for msr
# skip=9 because 8*9=72=0x48
dd if=/dev/cpu/0/msr of=/dev/null bs=8 count=1 skip=9 2>/dev/null dd if=/dev/cpu/0/msr of=/dev/null bs=8 count=1 skip=9 2>/dev/null
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
pstatus green YES pstatus green YES
@ -882,23 +884,20 @@ check_variant2()
fi fi
fi fi
unload_msr _info_nol " * CPU indicates IBRS capability: "
# CPUID test
_info_nol "* The SPEC_CTRL CPUID feature bit is set: "
if [ ! -e /dev/cpu/0/cpuid ]; then if [ ! -e /dev/cpu/0/cpuid ]; then
# try to load the module ourselves (and remember it so we can rmmod it afterwards) # try to load the module ourselves (and remember it so we can rmmod it afterwards)
load_cpuid load_cpuid
fi fi
if [ ! -e /dev/cpu/0/cpuid ]; then if [ ! -e /dev/cpu/0/cpuid ]; then
pstatus yellow UNKNOWN "couldn't read /dev/cpu/0/cpuidr, is cpuid support enabled in your kernel?" pstatus yellow UNKNOWN "couldn't read /dev/cpu/0/cpuid, is cpuid support enabled in your kernel?"
else else
# from kernel src: { X86_FEATURE_SPEC_CTRL, CPUID_EDX,26, 0x00000007, 0 }, # from kernel src: { X86_FEATURE_SPEC_CTRL, CPUID_EDX,26, 0x00000007, 0 },
if [ "$opt_verbose" -ge 3 ]; then if [ "$opt_verbose" -ge 3 ]; then
dd if=/dev/cpu/0/cpuid bs=16 skip=7 iflag=skip_bytes count=1 >/dev/null 2>/dev/null dd if=/dev/cpu/0/cpuid bs=16 skip=7 iflag=skip_bytes count=1 >/dev/null 2>/dev/null
_debug "cpuid: reading leaf7 of cpuid on cpu0, ret=$?" _debug "cpuid: reading leaf7 of cpuid on cpu0, ret=$?"
_debug "cpuid: leaf7 eax-ebx-ecd-edx: "$(dd if=/dev/cpu/0/cpuid bs=16 skip=7 iflag=skip_bytes count=1 2>/dev/null | od -x -A n) _debug "cpuid: leaf7 eax-ebx-ecx-edx: "$(dd if=/dev/cpu/0/cpuid bs=16 skip=7 iflag=skip_bytes count=1 2>/dev/null | od -x -A n)
_debug "cpuid: leaf7 edx higher-half is: "$(dd if=/dev/cpu/0/cpuid bs=16 skip=7 iflag=skip_bytes count=1 2>/dev/null | dd bs=1 skip=15 count=1 2>/dev/null | od -x -A n) _debug "cpuid: leaf7 edx higher byte is: "$(dd if=/dev/cpu/0/cpuid bs=16 skip=7 iflag=skip_bytes count=1 2>/dev/null | dd bs=1 skip=15 count=1 2>/dev/null | od -x -A n)
fi fi
# getting high byte of edx on leaf7 of cpuinfo in decimal # getting high byte of edx on leaf7 of cpuinfo in decimal
edx_hb=$(dd if=/dev/cpu/0/cpuid bs=16 skip=7 iflag=skip_bytes count=1 2>/dev/null | dd bs=1 skip=15 count=1 2>/dev/null | od -t u -A n | awk '{print $1}') edx_hb=$(dd if=/dev/cpu/0/cpuid bs=16 skip=7 iflag=skip_bytes count=1 2>/dev/null | dd bs=1 skip=15 count=1 2>/dev/null | od -t u -A n | awk '{print $1}')
@ -906,48 +905,102 @@ check_variant2()
edx_bit26=$(( edx_hb & 8 )) edx_bit26=$(( edx_hb & 8 ))
_debug "cpuid: edx_bit26=$edx_bit26" _debug "cpuid: edx_bit26=$edx_bit26"
if [ "$edx_bit26" -eq 8 ]; then if [ "$edx_bit26" -eq 8 ]; then
pstatus green YES pstatus green YES "SPEC_CTRL feature bit"
cpuid_spec_ctrl=1
else else
pstatus red NO pstatus red NO
fi fi
fi fi
unload_cpuid
# hardware support according to kernel # hardware support according to kernel
if [ "$opt_verbose" -ge 2 ]; then if [ "$opt_verbose" -ge 2 ]; then
_verbose_nol "* The kernel has set the spec_ctrl flag in cpuinfo: " # the spec_ctrl flag in cpuinfo is set if and only if the kernel sees
# that the spec_ctrl cpuinfo bit set. we already check that ourselves above
# but let's check it anyway (in verbose mode only)
_verbose_nol " * Kernel has set the spec_ctrl flag in cpuinfo: "
if [ "$opt_live" = 1 ]; then if [ "$opt_live" = 1 ]; then
if grep ^flags /proc/cpuinfo | grep -qw spec_ctrl; then if grep ^flags /proc/cpuinfo | grep -qw spec_ctrl; then
pstatus green YES pstatus green YES
else else
pstatus red NO pstatus blue NO
fi fi
else else
pstatus blue N/A "not testable in offline mode" pstatus blue N/A "not testable in offline mode"
fi fi
fi fi
_info_nol "* Kernel support for IBRS: " # IBPB
_info " * Indirect Branch Prediction Barrier (IBPB)"
_info_nol " * PRED_CMD MSR is available: "
if [ ! -e /dev/cpu/0/msr ]; then
pstatus yellow UNKNOWN "couldn't read /dev/cpu/0/msr, is msr support enabled in your kernel?"
else
# the new MSR 'PRED_CTRL' is at offset 0x49, write-only
# here we use dd, it's the same as using 'wrmsr 0x49 0' but without needing the wrmsr tool
# if we get a write error, the MSR is not there
$echo_cmd -ne "\0\0\0\0\0\0\0\0" | dd of=/dev/cpu/0/msr bs=8 count=1 seek=73 oflag=seek_bytes 2>/dev/null
if [ $? -eq 0 ]; then
pstatus green YES
else
pstatus red NO
fi
fi
_info_nol " * CPU indicates IBPB capability: "
if [ ! -e /dev/cpu/0/cpuid ]; then
pstatus yellow UNKNOWN "couldn't read /dev/cpu/0/cpuidr, is cpuid support enabled in your kernel?"
else
# CPUID EAX=0x80000008, ECX=0x00 return EBX[12] indicates support for just IBPB.
if [ "$opt_verbose" -ge 3 ]; then
dd if=/dev/cpu/0/cpuid bs=16 skip=2147483656 iflag=skip_bytes count=1 >/dev/null 2>/dev/null
_debug "cpuid: reading leaf80000008 of cpuid on cpu0, ret=$?"
_debug "cpuid: leaf80000008 eax-ebx-ecx-edx: "$(dd if=/dev/cpu/0/cpuid bs=16 skip=2147483656 iflag=skip_bytes count=1 2>/dev/null | od -x -A n)
_debug "cpuid: leaf80000008 ebx 3rd byte is: "$(dd if=/dev/cpu/0/cpuid bs=16 skip=2147483656 iflag=skip_bytes count=1 2>/dev/null | dd bs=1 skip=5 count=1 2>/dev/null | od -x -A n)
fi
# getting high byte of edx on leaf7 of cpuinfo in decimal
ebx_b3=$(dd if=/dev/cpu/0/cpuid bs=16 skip=2147483656 iflag=skip_bytes count=1 2>/dev/null | dd bs=1 skip=5 count=1 2>/dev/null | od -t u -A n | awk '{print $1}')
_debug "cpuid: leaf80000008 ebx 3rd byte: $ebx_b3 (decimal)"
ebx_bit12=$(( ebx_b3 & 16 ))
_debug "cpuid: ebx_bit12=$ebx_bit12"
if [ "$ebx_bit12" -eq 16 ]; then
pstatus green YES "IBPB_SUPPORT feature bit"
cpuid_ibpb=1
elif [ "$cpuid_spec_ctrl" = 1 ]; then
pstatus green YES "SPEC_CTRL feature bit"
else
pstatus red NO
fi
fi
_info_nol " * Kernel is compiled with IBRS/IBPB support: "
ibrs_can_tell=0 ibrs_can_tell=0
if [ "$opt_live" = 1 ]; then if [ "$opt_live" = 1 ]; then
ibrs_can_tell=1 ibrs_can_tell=1
mount_debugfs mount_debugfs
for ibrs_file in \ for dir in \
/sys/kernel/debug/ibrs_enabled \ /sys/kernel/debug \
/sys/kernel/debug/x86/ibrs_enabled \ /sys/kernel/debug/x86 \
/proc/sys/kernel/ibrs_enabled; do /proc/sys/kernel; do
if [ -e "$ibrs_file" ]; then if [ -e "$dir/ibrs_enabled" ]; then
# if the file is there, we have IBRS compiled-in # if the file is there, we have IBRS compiled-in
# /sys/kernel/debug/ibrs_enabled: vanilla # /sys/kernel/debug/ibrs_enabled: vanilla
# /sys/kernel/debug/x86/ibrs_enabled: RedHat (see https://access.redhat.com/articles/3311301) # /sys/kernel/debug/x86/ibrs_enabled: RedHat (see https://access.redhat.com/articles/3311301)
# /proc/sys/kernel/ibrs_enabled: OpenSUSE tumbleweed # /proc/sys/kernel/ibrs_enabled: OpenSUSE tumbleweed
pstatus green YES pstatus green YES
ibrs_knob_dir=$dir
ibrs_supported=1 ibrs_supported=1
ibrs_enabled=$(cat "$ibrs_file" 2>/dev/null) ibrs_enabled=$(cat "$dir/ibrs_enabled" 2>/dev/null)
_debug "ibrs: found $ibrs_file=$ibrs_enabled" _debug "ibrs: found $dir/ibrs_enabled=$ibrs_enabled"
if [ -e "$dir/ibpb_enabled" ]; then
ibpb_enabled=$(cat "$dir/ibpb_enabled" 2>/dev/null)
_debug "ibpb: found $dir/ibpb_enabled=$ibpb_enabled"
else
_debug "ibpb: no ibpb_enabled file in $dir"
fi
break break
else else
_debug "ibrs: file $ibrs_file doesn't exist" _debug "ibrs: $dir/ibrs_enabled file doesn't exist"
fi fi
done done
# on some newer kernels, the spec_ctrl_ibrs flag in /proc/cpuinfo # on some newer kernels, the spec_ctrl_ibrs flag in /proc/cpuinfo
@ -960,6 +1013,7 @@ check_variant2()
ibrs_supported=1 ibrs_supported=1
# enabled=2 -> kernel & user # enabled=2 -> kernel & user
ibrs_enabled=2 ibrs_enabled=2
# XXX and what about ibpb ?
fi fi
fi fi
fi fi
@ -980,32 +1034,59 @@ check_variant2()
fi fi
fi fi
_info_nol "* IBRS enabled for Kernel space: " _info " * Currently enabled features"
_info_nol " * IBRS enabled for Kernel space: "
if [ "$opt_live" = 1 ]; then if [ "$opt_live" = 1 ]; then
if [ "$ibpb_enabled" = 2 ]; then
# if ibpb=2, ibrs is forcefully=0
pstatus blue NO "IBPB used instead of IBRS in all kernel entrypoints"
else
# 0 means disabled # 0 means disabled
# 1 is enabled only for kernel space # 1 is enabled only for kernel space
# 2 is enabled for kernel and user space # 2 is enabled for kernel and user space
case "$ibrs_enabled" in case "$ibrs_enabled" in
"") [ "$ibrs_supported" = 1 ] && pstatus yellow UNKNOWN || pstatus red NO;; "") [ "$ibrs_supported" = 1 ] && pstatus yellow UNKNOWN || pstatus red NO;;
0) pstatus red NO;; 0) pstatus red NO "echo 1 > $ibrs_knob_dir/ibrs_enabled";;
1 | 2) pstatus green YES;; 1 | 2) pstatus green YES;;
*) pstatus yellow UNKNOWN;; *) pstatus yellow UNKNOWN;;
esac esac
fi
else
pstatus blue N/A "not testable in offline mode"
fi
_info_nol " * IBRS enabled for User space: "
if [ "$opt_live" = 1 ]; then
if [ "$ibpb_enabled" = 2 ]; then
# if ibpb=2, ibrs is forcefully=0
pstatus blue NO "IBPB used instead of IBRS in all kernel entrypoints"
else
case "$ibrs_enabled" in
"") [ "$ibrs_supported" = 1 ] && pstatus yellow UNKNOWN || pstatus red NO;;
0 | 1) pstatus red NO "echo 2 > $ibrs_knob_dir/ibrs_enabled";;
2) pstatus green YES;;
*) pstatus yellow UNKNOWN;;
esac
fi
else
pstatus blue N/A "not testable in offline mode"
fi
_info_nol " * IBPB enabled: "
if [ "$opt_live" = 1 ]; then
case "$ibpb_enabled" in
"") [ "$ibrs_supported" = 1 ] && pstatus yellow UNKNOWN || pstatus red NO;;
0) pstatus red NO "echo 1 > $ibrs_knob_dir/ibpb_enabled";;
1) pstatus green YES;;
2) pstatus green YES "IBPB used instead of IBRS in all kernel entrypoints";;
*) pstatus yellow UNKNOWN;;
esac
else else
pstatus blue N/A "not testable in offline mode" pstatus blue N/A "not testable in offline mode"
fi fi
_info_nol "* IBRS enabled for User space: " unload_msr
if [ "$opt_live" = 1 ]; then unload_cpuid
case "$ibrs_enabled" in
"") [ "$ibrs_supported" = 1 ] && pstatus yellow UNKNOWN || pstatus red NO;;
0 | 1) pstatus red NO;;
2) pstatus green YES;;
*) pstatus yellow UNKNOWN;;
esac
else
pstatus blue N/A "not testable in offline mode"
fi
_info "* Mitigation 2" _info "* Mitigation 2"
_info_nol "* Kernel compiled with retpoline option: " _info_nol "* Kernel compiled with retpoline option: "
@ -1068,14 +1149,16 @@ check_variant2()
if [ "$retpoline" = 1 -a "$retpoline_compiler" = 1 ]; then if [ "$retpoline" = 1 -a "$retpoline_compiler" = 1 ]; then
pvulnstatus CVE-2017-5715 OK "retpoline mitigate the vulnerability" pvulnstatus CVE-2017-5715 OK "retpoline mitigate the vulnerability"
elif [ "$opt_live" = 1 ]; then elif [ "$opt_live" = 1 ]; then
if [ "$ibrs_enabled" = 1 -o "$ibrs_enabled" = 2 ]; then if [ "$ibrs_enabled" = 1 -o "$ibrs_enabled" = 2 ] && [ "$ibpb_enabled" = 1 ]; then
pvulnstatus CVE-2017-5715 OK "IBRS mitigates the vulnerability" pvulnstatus CVE-2017-5715 OK "IBRS/IBPB are mitigating the vulnerability"
elif [ "$ibpb_enabled" = 2 ]; then
pvulnstatus CVE-2017-5715 OK "Full IBPB is mitigating the vulnerability"
else else
pvulnstatus CVE-2017-5715 VULN "IBRS hardware + kernel support OR kernel with retpoline are needed to mitigate the vulnerability" pvulnstatus CVE-2017-5715 VULN "IBRS hardware + kernel support OR kernel with retpoline are needed to mitigate the vulnerability"
fi fi
else else
if [ "$ibrs_supported" = 1 ]; then if [ "$ibrs_supported" = 1 ]; then
pvulnstatus CVE-2017-5715 OK "offline mode: IBRS will mitigate the vulnerability if enabled at runtime" pvulnstatus CVE-2017-5715 OK "offline mode: IBRS/IBPB will mitigate the vulnerability if enabled at runtime"
elif [ "$ibrs_can_tell" = 1 ]; then elif [ "$ibrs_can_tell" = 1 ]; then
pvulnstatus CVE-2017-5715 VULN "IBRS hardware + kernel support OR kernel with retpoline are needed to mitigate the vulnerability" pvulnstatus CVE-2017-5715 VULN "IBRS hardware + kernel support OR kernel with retpoline are needed to mitigate the vulnerability"
else else