mirror of
				https://github.com/speed47/spectre-meltdown-checker.git
				synced 2025-10-31 20:50:55 +01:00 
			
		
		
		
	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:
		| @@ -861,9 +861,10 @@ check_variant2() | ||||
| 		# this kernel has the /sys interface, trust it over everything | ||||
| 		sys_interface_available=1 | ||||
| 	else | ||||
| 		_info "* Mitigation 1" | ||||
| 		_info "*   Hardware (CPU microcode) support for mitigation" | ||||
| 		_info_nol "*     The SPEC_CTRL MSR is available: " | ||||
| 		_info     "* Mitigation 1" | ||||
| 		_info     "  * Hardware support (CPU microcode)" | ||||
| 		_info     "    * Indirect Branch Restricted Speculation (IBRS)" | ||||
| 		_info_nol "      * SPEC_CTRL MSR is available: " | ||||
| 		if [ ! -e /dev/cpu/0/msr ]; then | ||||
| 			# try to load the module ourselves (and remember it so we can rmmod it afterwards) | ||||
| 			load_msr | ||||
| @@ -873,7 +874,8 @@ check_variant2() | ||||
| 		else | ||||
| 			# 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 | ||||
| 			# 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 | ||||
| 			if [ $? -eq 0 ]; then | ||||
| 				pstatus green YES | ||||
| @@ -882,23 +884,20 @@ check_variant2() | ||||
| 			fi | ||||
| 		fi | ||||
|  | ||||
| 		unload_msr | ||||
|  | ||||
| 		# CPUID test | ||||
| 		_info_nol "*     The SPEC_CTRL CPUID feature bit is set: " | ||||
| 		_info_nol "      * CPU indicates IBRS capability: " | ||||
| 		if [ ! -e /dev/cpu/0/cpuid ]; then | ||||
| 			# try to load the module ourselves (and remember it so we can rmmod it afterwards) | ||||
| 			load_cpuid | ||||
| 		fi | ||||
| 		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 | ||||
| 			# from kernel src: { X86_FEATURE_SPEC_CTRL,        CPUID_EDX,26, 0x00000007, 0 }, | ||||
| 			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 | ||||
| 				_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 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 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 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 | ||||
| 			# 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}') | ||||
| @@ -906,48 +905,102 @@ check_variant2() | ||||
| 			edx_bit26=$(( edx_hb & 8 )) | ||||
| 			_debug "cpuid: edx_bit26=$edx_bit26" | ||||
| 			if [ "$edx_bit26" -eq 8 ]; then | ||||
| 				pstatus green YES | ||||
| 				pstatus green YES "SPEC_CTRL feature bit" | ||||
| 				cpuid_spec_ctrl=1 | ||||
| 			else | ||||
| 				pstatus red NO | ||||
| 			fi | ||||
| 		fi | ||||
| 		unload_cpuid | ||||
|  | ||||
| 		# hardware support according to kernel | ||||
| 		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 grep ^flags /proc/cpuinfo | grep -qw spec_ctrl; then | ||||
| 					pstatus green YES | ||||
| 				else | ||||
| 					pstatus red NO | ||||
| 					pstatus blue NO | ||||
| 				fi | ||||
| 			else | ||||
| 				pstatus blue N/A "not testable in offline mode" | ||||
| 			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 | ||||
|  | ||||
| 		if [ "$opt_live" = 1 ]; then | ||||
| 			ibrs_can_tell=1 | ||||
| 			mount_debugfs | ||||
| 			for ibrs_file in \ | ||||
| 				/sys/kernel/debug/ibrs_enabled \ | ||||
| 				/sys/kernel/debug/x86/ibrs_enabled \ | ||||
| 				/proc/sys/kernel/ibrs_enabled; do | ||||
| 				if [ -e "$ibrs_file" ]; then | ||||
| 			for dir in \ | ||||
| 				/sys/kernel/debug \ | ||||
| 				/sys/kernel/debug/x86 \ | ||||
| 				/proc/sys/kernel; do | ||||
| 				if [ -e "$dir/ibrs_enabled" ]; then | ||||
| 					# if the file is there, we have IBRS compiled-in | ||||
| 					# /sys/kernel/debug/ibrs_enabled: vanilla | ||||
| 					# /sys/kernel/debug/x86/ibrs_enabled: RedHat (see https://access.redhat.com/articles/3311301) | ||||
| 					# /proc/sys/kernel/ibrs_enabled: OpenSUSE tumbleweed | ||||
| 					pstatus green YES | ||||
| 					ibrs_knob_dir=$dir | ||||
| 					ibrs_supported=1 | ||||
| 					ibrs_enabled=$(cat "$ibrs_file" 2>/dev/null) | ||||
| 					_debug "ibrs: found $ibrs_file=$ibrs_enabled" | ||||
| 					ibrs_enabled=$(cat "$dir/ibrs_enabled" 2>/dev/null) | ||||
| 					_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 | ||||
| 				else | ||||
| 					_debug "ibrs: file $ibrs_file doesn't exist" | ||||
| 					_debug "ibrs: $dir/ibrs_enabled file doesn't exist" | ||||
| 				fi | ||||
| 			done | ||||
| 			# on some newer kernels, the spec_ctrl_ibrs flag in /proc/cpuinfo | ||||
| @@ -960,6 +1013,7 @@ check_variant2() | ||||
| 					ibrs_supported=1 | ||||
| 					# enabled=2 -> kernel & user | ||||
| 					ibrs_enabled=2 | ||||
| 					# XXX and what about ibpb ? | ||||
| 				fi | ||||
| 			fi | ||||
| 		fi | ||||
| @@ -980,33 +1034,60 @@ check_variant2() | ||||
| 			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 | ||||
| 			# 0 means disabled | ||||
| 			# 1 is enabled only for kernel space | ||||
| 			# 2 is enabled for kernel and user space | ||||
| 			case "$ibrs_enabled" in | ||||
| 				"") [ "$ibrs_supported" = 1 ] && pstatus yellow UNKNOWN || pstatus red NO;; | ||||
| 				0)     pstatus red NO;; | ||||
| 				1 | 2) pstatus green YES;; | ||||
| 				*)     pstatus yellow UNKNOWN;; | ||||
| 			esac | ||||
| 			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 | ||||
| 				# 1 is enabled only for kernel space | ||||
| 				# 2 is enabled for kernel and user space | ||||
| 				case "$ibrs_enabled" in | ||||
| 					"") [ "$ibrs_supported" = 1 ] && pstatus yellow UNKNOWN || pstatus red NO;; | ||||
| 					0)     pstatus red NO "echo 1 > $ibrs_knob_dir/ibrs_enabled";; | ||||
| 					1 | 2) pstatus green YES;; | ||||
| 					*)     pstatus yellow UNKNOWN;; | ||||
| 				esac | ||||
| 			fi | ||||
| 		else | ||||
| 			pstatus blue N/A "not testable in offline mode" | ||||
| 		fi | ||||
|  | ||||
| 		_info_nol "*   IBRS enabled for User space: " | ||||
| 		_info_nol "    * IBRS enabled for User space: " | ||||
| 		if [ "$opt_live" = 1 ]; then | ||||
| 			case "$ibrs_enabled" in | ||||
| 			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 | 1) pstatus red NO;; | ||||
| 				2) pstatus green YES;; | ||||
| 				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 | ||||
| 			pstatus blue N/A "not testable in offline mode" | ||||
| 		fi | ||||
|  | ||||
| 		unload_msr | ||||
| 		unload_cpuid | ||||
|  | ||||
| 		_info "* Mitigation 2" | ||||
| 		_info_nol "*   Kernel compiled with retpoline option: " | ||||
| 		# We check the RETPOLINE kernel options | ||||
| @@ -1068,14 +1149,16 @@ check_variant2() | ||||
| 		if [ "$retpoline" = 1 -a "$retpoline_compiler" = 1 ]; then | ||||
| 			pvulnstatus CVE-2017-5715 OK "retpoline mitigate the vulnerability" | ||||
| 		elif [ "$opt_live" = 1 ]; then | ||||
| 			if [ "$ibrs_enabled" = 1 -o "$ibrs_enabled" = 2 ]; then | ||||
| 				pvulnstatus CVE-2017-5715 OK "IBRS mitigates the vulnerability" | ||||
| 			if [ "$ibrs_enabled" = 1 -o "$ibrs_enabled" = 2 ] && [ "$ibpb_enabled" = 1 ]; then | ||||
| 				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 | ||||
| 				pvulnstatus CVE-2017-5715 VULN "IBRS hardware + kernel support OR kernel with retpoline are needed to mitigate the vulnerability" | ||||
| 			fi | ||||
| 		else | ||||
| 			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 | ||||
| 				pvulnstatus CVE-2017-5715 VULN "IBRS hardware + kernel support OR kernel with retpoline are needed to mitigate the vulnerability" | ||||
| 			else | ||||
|   | ||||
		Reference in New Issue
	
	Block a user