mirror of
				https://github.com/speed47/spectre-meltdown-checker.git
				synced 2025-10-29 19:50:52 +01:00 
			
		
		
		
	feat(cpu) add STIBP, RDCL_NO, IBRS_ALL checks
Move all the CPU checks to their own section, for clarity. We now check for IBRS, IBPB, STIBP, RDCL_NO and IBRS_ALL. We also show whether the system CPU is vulnerable to the three variants, regardless of the fact that mitigations are in place or not, which is determined in each vuln- specific section.
This commit is contained in:
		| @@ -199,6 +199,8 @@ is_cpu_vulnerable() | |||||||
| 	variant3='' | 	variant3='' | ||||||
| 	# we also set a friendly name for the CPU to be used in the script if needed | 	# we also set a friendly name for the CPU to be used in the script if needed | ||||||
| 	cpu_friendly_name=$(grep '^model name' /proc/cpuinfo | cut -d: -f2- | head -1 | sed -e 's/^ *//') | 	cpu_friendly_name=$(grep '^model name' /proc/cpuinfo | cut -d: -f2- | head -1 | sed -e 's/^ *//') | ||||||
|  | 	# variant 0 is just for us to fill the cpu_friendly_name var | ||||||
|  | 	[ "$1" = 0 ] && return 0 | ||||||
|  |  | ||||||
| 	if grep -q GenuineIntel /proc/cpuinfo; then | 	if grep -q GenuineIntel /proc/cpuinfo; then | ||||||
| 		# Intel | 		# Intel | ||||||
| @@ -217,6 +219,13 @@ is_cpu_vulnerable() | |||||||
| 			[ -z "$variant2" ] && variant2=immune | 			[ -z "$variant2" ] && variant2=immune | ||||||
| 			[ -z "$variant3" ] && variant3=immune | 			[ -z "$variant3" ] && variant3=immune | ||||||
| 		fi | 		fi | ||||||
|  | 		if [ "$capabilities_rdcl_no" = 1 ]; then | ||||||
|  | 			# capability bit for future Intel processor that will explicitly state | ||||||
|  | 			# that they're not vulnerable to Meltdown | ||||||
|  | 			# this var is set in check_cpu() | ||||||
|  | 			[ -z "$variant3" ] && variant3=immune | ||||||
|  | 			_debug "is_cpu_vulnerable: RDCL_NO is set so not vuln to meltdown" | ||||||
|  | 		fi | ||||||
| 	elif grep -q AuthenticAMD /proc/cpuinfo; then | 	elif grep -q AuthenticAMD /proc/cpuinfo; then | ||||||
| 		# AMD revised their statement about variant2 => vulnerable | 		# AMD revised their statement about variant2 => vulnerable | ||||||
| 		# https://www.amd.com/en/corporate/speculative-execution | 		# https://www.amd.com/en/corporate/speculative-execution | ||||||
| @@ -664,7 +673,7 @@ if [ "$opt_live" = 1 ]; then | |||||||
| 	_info "Checking for vulnerabilities on current system" | 	_info "Checking for vulnerabilities on current system" | ||||||
| 	_info "Kernel is \033[35m"$(uname -s) $(uname -r) $(uname -v) $(uname -m)"\033[0m" | 	_info "Kernel is \033[35m"$(uname -s) $(uname -r) $(uname -v) $(uname -m)"\033[0m" | ||||||
| 	# call is_cpu_vulnerable to fill the cpu_friendly_name var | 	# call is_cpu_vulnerable to fill the cpu_friendly_name var | ||||||
| 	is_cpu_vulnerable 1 | 	is_cpu_vulnerable 0 | ||||||
| 	_info "CPU is \033[35m$cpu_friendly_name\033[0m" | 	_info "CPU is \033[35m$cpu_friendly_name\033[0m" | ||||||
|  |  | ||||||
| 	# try to find the image of the current running kernel | 	# try to find the image of the current running kernel | ||||||
| @@ -804,80 +813,11 @@ sys_interface_check() | |||||||
| 	return 0 | 	return 0 | ||||||
| } | } | ||||||
|  |  | ||||||
| ################### | check_cpu() | ||||||
| # SPECTRE VARIANT 1 |  | ||||||
| check_variant1() |  | ||||||
| { | { | ||||||
| 	_info "\033[1;34mCVE-2017-5753 [bounds check bypass] aka 'Spectre Variant 1'\033[0m" | 	_info "\033[1;34mHardware check\033[0m" | ||||||
|  |  | ||||||
| 	status=UNK | 	_info     "* Hardware support (CPU microcode) for mitigation techniques" | ||||||
| 	sys_interface_available=0 |  | ||||||
| 	msg='' |  | ||||||
| 	if sys_interface_check "/sys/devices/system/cpu/vulnerabilities/spectre_v1"; then |  | ||||||
| 		# this kernel has the /sys interface, trust it over everything |  | ||||||
| 		sys_interface_available=1 |  | ||||||
| 	elif [ "$opt_sysfs_only" != 1 ]; then |  | ||||||
| 		# no /sys interface (or offline mode), fallback to our own ways |  | ||||||
| 		_info_nol "* Checking count of LFENCE opcodes in kernel: " |  | ||||||
| 		if [ -n "$vmlinux_err" ]; then |  | ||||||
| 			msg="couldn't check ($vmlinux_err)" |  | ||||||
| 			status=UNK |  | ||||||
| 			pstatus yellow UNKNOWN |  | ||||||
| 		else |  | ||||||
| 			if ! which objdump >/dev/null 2>&1; then |  | ||||||
| 				msg="missing 'objdump' tool, please install it, usually it's in the binutils package" |  | ||||||
| 				status=UNK |  | ||||||
| 				pstatus yellow UNKNOWN |  | ||||||
| 			else |  | ||||||
| 				# here we disassemble the kernel and count the number of occurrences of the LFENCE opcode |  | ||||||
| 				# in non-patched kernels, this has been empirically determined as being around 40-50 |  | ||||||
| 				# in patched kernels, this is more around 70-80, sometimes way higher (100+) |  | ||||||
| 				# v0.13: 68 found in a 3.10.23-xxxx-std-ipv6-64 (with lots of modules compiled-in directly), which doesn't have the LFENCE patches, |  | ||||||
| 				# so let's push the threshold to 70. |  | ||||||
| 				nb_lfence=$(objdump -d "$vmlinux" | grep -wc lfence) |  | ||||||
| 				if [ "$nb_lfence" -lt 70 ]; then |  | ||||||
| 					msg="only $nb_lfence opcodes found, should be >= 70, heuristic to be improved when official patches become available" |  | ||||||
| 					status=VULN |  | ||||||
| 					pstatus red NO |  | ||||||
| 				else |  | ||||||
| 					msg="$nb_lfence opcodes found, which is >= 70, heuristic to be improved when official patches become available" |  | ||||||
| 					status=OK |  | ||||||
| 					pstatus green YES |  | ||||||
| 				fi |  | ||||||
| 			fi |  | ||||||
| 		fi |  | ||||||
| 	else |  | ||||||
| 		# 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 1; then |  | ||||||
| 		# override status & msg in case CPU is not vulnerable after all |  | ||||||
| 		msg="your CPU vendor reported your CPU model as not vulnerable" |  | ||||||
| 		status=OK |  | ||||||
| 	fi |  | ||||||
|  |  | ||||||
| 	# report status |  | ||||||
| 	pvulnstatus CVE-2017-5753 "$status" "$msg" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| ################### |  | ||||||
| # SPECTRE VARIANT 2 |  | ||||||
| check_variant2() |  | ||||||
| { |  | ||||||
| 	_info "\033[1;34mCVE-2017-5715 [branch target injection] aka 'Spectre Variant 2'\033[0m" |  | ||||||
|  |  | ||||||
| 	status=UNK |  | ||||||
| 	sys_interface_available=0 |  | ||||||
| 	msg='' |  | ||||||
| 	if sys_interface_check "/sys/devices/system/cpu/vulnerabilities/spectre_v2"; then |  | ||||||
| 		# this kernel has the /sys interface, trust it over everything |  | ||||||
| 		sys_interface_available=1 |  | ||||||
| 	fi |  | ||||||
| 	if [ "$opt_sysfs_only" != 1 ]; then |  | ||||||
| 		_info     "* Mitigation 1" |  | ||||||
| 		_info     "  * Hardware support (CPU microcode)" |  | ||||||
| 	_info     "  * Indirect Branch Restricted Speculation (IBRS)" | 	_info     "  * Indirect Branch Restricted Speculation (IBRS)" | ||||||
| 	_info_nol "    * SPEC_CTRL MSR is available: " | 	_info_nol "    * SPEC_CTRL MSR is available: " | ||||||
| 	if [ ! -e /dev/cpu/0/msr ]; then | 	if [ ! -e /dev/cpu/0/msr ]; then | ||||||
| @@ -966,7 +906,7 @@ check_variant2() | |||||||
|  |  | ||||||
| 	_info_nol "    * CPU indicates IBPB capability: " | 	_info_nol "    * CPU indicates IBPB capability: " | ||||||
| 	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 | ||||||
| 		# CPUID EAX=0x80000008, ECX=0x00 return EBX[12] indicates support for just IBPB. | 		# CPUID EAX=0x80000008, ECX=0x00 return EBX[12] indicates support for just IBPB. | ||||||
| 		if [ "$opt_verbose" -ge 3 ]; then | 		if [ "$opt_verbose" -ge 3 ]; then | ||||||
| @@ -1003,7 +943,7 @@ check_variant2() | |||||||
|  |  | ||||||
| 	_info_nol "    * CPU indicates STIBP capability: " | 	_info_nol "    * CPU indicates STIBP capability: " | ||||||
| 	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 | ||||||
| 		# A processor supports STIBP if it enumerates CPUID (EAX=7H,ECX=0):EDX[27] as 1 | 		# A processor supports STIBP if it enumerates CPUID (EAX=7H,ECX=0):EDX[27] as 1 | ||||||
| 		if [ "$opt_verbose" -ge 3 ]; then | 		if [ "$opt_verbose" -ge 3 ]; then | ||||||
| @@ -1018,13 +958,158 @@ check_variant2() | |||||||
| 		edx_bit27=$(( edx_hb & 8 )) | 		edx_bit27=$(( edx_hb & 8 )) | ||||||
| 		_debug "cpuid: edx_bit27=$edx_bit27" | 		_debug "cpuid: edx_bit27=$edx_bit27" | ||||||
| 		if [ "$edx_bit27" -eq 8 ]; then | 		if [ "$edx_bit27" -eq 8 ]; then | ||||||
| 				pstatus green YES "STIBP feature bit" | 			pstatus green YES | ||||||
| 			cpuid_stibp=1 | 			cpuid_stibp=1 | ||||||
| 		else | 		else | ||||||
| 			pstatus red NO | 			pstatus red NO | ||||||
| 		fi | 		fi | ||||||
| 	fi | 	fi | ||||||
|  |  | ||||||
|  | 	_info     "  * Enhanced IBRS (IBRS_ALL)" | ||||||
|  | 	_info_nol "    * CPU indicates ARCH_CAPABILITIES MSR availability: " | ||||||
|  | 	if [ ! -e /dev/cpu/0/cpuid ]; then | ||||||
|  | 		pstatus yellow UNKNOWN "couldn't read /dev/cpu/0/cpuid, is cpuid support enabled in your kernel?" | ||||||
|  | 	else | ||||||
|  | 		# A processor supports STIBP if it enumerates CPUID (EAX=7H,ECX=0):EDX[27] as 1 | ||||||
|  | 		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-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}') | ||||||
|  | 		_debug "cpuid: leaf7 edx higher byte: $edx_hb (decimal)" | ||||||
|  | 		edx_bit29=$(( edx_hb & 32 )) | ||||||
|  | 		_debug "cpuid: edx_bit29=$edx_bit29" | ||||||
|  | 		if [ "$edx_bit27" -eq 32 ]; then | ||||||
|  | 			pstatus green YES | ||||||
|  | 			cpuid_arch_capabilities=1 | ||||||
|  | 		else | ||||||
|  | 			pstatus red NO | ||||||
|  | 		fi | ||||||
|  | 	fi | ||||||
|  |  | ||||||
|  | 	_info_nol "    * ARCH_CAPABILITIES MSR advertises IBRS_ALL capability: " | ||||||
|  | 	if [ "$cpuid_arch_capabilities" != 1 ]; then | ||||||
|  | 		pstatus red NO | ||||||
|  | 	elif [ ! -e /dev/cpu/0/msr ]; then | ||||||
|  | 		spec_ctrl_msr=-1 | ||||||
|  | 		pstatus yellow UNKNOWN "couldn't read /dev/cpu/0/msr, is msr support enabled in your kernel?" | ||||||
|  | 	else | ||||||
|  | 		# the new MSR 'ARCH_CAPABILITIES' is at offset 0x10a | ||||||
|  | 		# here we use dd, it's the same as using 'rdmsr 0x10a' but without needing the rdmsr tool | ||||||
|  | 		# if we get a read error, the MSR is not there. bs has to be 8 for msr | ||||||
|  | 		capabilities=$(dd if=/dev/cpu/0/msr bs=8 count=1 skip=266 iflag=skip_bytes 2>/dev/null | od -t u1 -A n | awk '{print $8}') | ||||||
|  | 		if [ $? -eq 0 ]; then | ||||||
|  | 			_debug "capabilities MSR lower byte is $capabilities (decimal)" | ||||||
|  | 			capabilities_rdcl_no=0 | ||||||
|  | 			[ $(( capabilities & 1 )) -eq 1 ] && capabilities_rdcl_no=1 | ||||||
|  | 			[ $(( capabilities & 2 )) -eq 2 ] && capabilities_ibrs_all=1 | ||||||
|  | 			_debug "capabilities says rdcl_no=$capabilities_rdcl_no ibrs_all=$capabilities_ibrs_all" | ||||||
|  | 			if [ "$capabilities_ibrs_all" = 1 ]; then | ||||||
|  | 				pstatus green YES | ||||||
|  | 			else | ||||||
|  | 				pstatus red NO | ||||||
|  | 			fi | ||||||
|  | 		else | ||||||
|  | 			pstatus yellow UNKNOWN | ||||||
|  | 		fi | ||||||
|  | 	fi | ||||||
|  |  | ||||||
|  | 	_info_nol "  * CPU explicitly indicates not being vulnerable to Meltdown (RDCL_NO): " | ||||||
|  | 	if [ "$capabilities_rdcl_no" = 1 ]; then | ||||||
|  | 		pstatus green YES | ||||||
|  | 	else | ||||||
|  | 		pstatus blue NO | ||||||
|  | 	fi | ||||||
|  |  | ||||||
|  | 	_info     "* CPU vulnerability to the three speculative execution attacks variants" | ||||||
|  | 	for v in 1 2 3; do | ||||||
|  | 		_info_nol "  * Vulnerable to Variant $v: " | ||||||
|  | 		if is_cpu_vulnerable $v; then | ||||||
|  | 			pstatus red YES | ||||||
|  | 		else | ||||||
|  | 			pstatus green NO | ||||||
|  | 		fi | ||||||
|  | 	done | ||||||
|  |  | ||||||
|  | 	_info | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ################### | ||||||
|  | # SPECTRE VARIANT 1 | ||||||
|  | check_variant1() | ||||||
|  | { | ||||||
|  | 	_info "\033[1;34mCVE-2017-5753 [bounds check bypass] aka 'Spectre Variant 1'\033[0m" | ||||||
|  |  | ||||||
|  | 	status=UNK | ||||||
|  | 	sys_interface_available=0 | ||||||
|  | 	msg='' | ||||||
|  | 	if sys_interface_check "/sys/devices/system/cpu/vulnerabilities/spectre_v1"; then | ||||||
|  | 		# this kernel has the /sys interface, trust it over everything | ||||||
|  | 		sys_interface_available=1 | ||||||
|  | 	elif [ "$opt_sysfs_only" != 1 ]; then | ||||||
|  | 		# no /sys interface (or offline mode), fallback to our own ways | ||||||
|  | 		_info_nol "* Checking count of LFENCE opcodes in kernel: " | ||||||
|  | 		if [ -n "$vmlinux_err" ]; then | ||||||
|  | 			msg="couldn't check ($vmlinux_err)" | ||||||
|  | 			status=UNK | ||||||
|  | 			pstatus yellow UNKNOWN | ||||||
|  | 		else | ||||||
|  | 			if ! which objdump >/dev/null 2>&1; then | ||||||
|  | 				msg="missing 'objdump' tool, please install it, usually it's in the binutils package" | ||||||
|  | 				status=UNK | ||||||
|  | 				pstatus yellow UNKNOWN | ||||||
|  | 			else | ||||||
|  | 				# here we disassemble the kernel and count the number of occurrences of the LFENCE opcode | ||||||
|  | 				# in non-patched kernels, this has been empirically determined as being around 40-50 | ||||||
|  | 				# in patched kernels, this is more around 70-80, sometimes way higher (100+) | ||||||
|  | 				# v0.13: 68 found in a 3.10.23-xxxx-std-ipv6-64 (with lots of modules compiled-in directly), which doesn't have the LFENCE patches, | ||||||
|  | 				# so let's push the threshold to 70. | ||||||
|  | 				nb_lfence=$(objdump -d "$vmlinux" | grep -wc lfence) | ||||||
|  | 				if [ "$nb_lfence" -lt 70 ]; then | ||||||
|  | 					msg="only $nb_lfence opcodes found, should be >= 70, heuristic to be improved when official patches become available" | ||||||
|  | 					status=VULN | ||||||
|  | 					pstatus red NO | ||||||
|  | 				else | ||||||
|  | 					msg="$nb_lfence opcodes found, which is >= 70, heuristic to be improved when official patches become available" | ||||||
|  | 					status=OK | ||||||
|  | 					pstatus green YES | ||||||
|  | 				fi | ||||||
|  | 			fi | ||||||
|  | 		fi | ||||||
|  | 	else | ||||||
|  | 		# 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 1; then | ||||||
|  | 		# override status & msg in case CPU is not vulnerable after all | ||||||
|  | 		msg="your CPU vendor reported your CPU model as not vulnerable" | ||||||
|  | 		status=OK | ||||||
|  | 	fi | ||||||
|  |  | ||||||
|  | 	# report status | ||||||
|  | 	pvulnstatus CVE-2017-5753 "$status" "$msg" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ################### | ||||||
|  | # SPECTRE VARIANT 2 | ||||||
|  | check_variant2() | ||||||
|  | { | ||||||
|  | 	_info "\033[1;34mCVE-2017-5715 [branch target injection] aka 'Spectre Variant 2'\033[0m" | ||||||
|  |  | ||||||
|  | 	status=UNK | ||||||
|  | 	sys_interface_available=0 | ||||||
|  | 	msg='' | ||||||
|  | 	if sys_interface_check "/sys/devices/system/cpu/vulnerabilities/spectre_v2"; then | ||||||
|  | 		# this kernel has the /sys interface, trust it over everything | ||||||
|  | 		sys_interface_available=1 | ||||||
|  | 	fi | ||||||
|  | 	if [ "$opt_sysfs_only" != 1 ]; then | ||||||
|  | 		_info     "* Mitigation 1" | ||||||
| 		_info_nol "  * Kernel is compiled with IBRS/IBPB support: " | 		_info_nol "  * Kernel is compiled with IBRS/IBPB support: " | ||||||
| 		ibrs_can_tell=0 | 		ibrs_can_tell=0 | ||||||
|  |  | ||||||
| @@ -1429,6 +1514,7 @@ check_variant3() | |||||||
| 	fi | 	fi | ||||||
| } | } | ||||||
|  |  | ||||||
|  | check_cpu | ||||||
| # now run the checks the user asked for | # now run the checks the user asked for | ||||||
| if [ "$opt_variant1" = 1 -o "$opt_allvariants" = 1 ]; then | if [ "$opt_variant1" = 1 -o "$opt_allvariants" = 1 ]; then | ||||||
| 	check_variant1 | 	check_variant1 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user