From 3d6acc460eedbd3089697f8a32a7faa7a8791bd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Lesimple?= Date: Mon, 30 Mar 2026 20:53:13 +0200 Subject: [PATCH] fix: rework read_msr for values > INT32_MAX (#507) --- src/libs/340_cpu_msr.sh | 30 +++++++++++++++++++++--------- src/libs/350_cpu_detect2.sh | 3 ++- src/libs/400_hw_check.sh | 36 +++++++++++++++++------------------- src/vulns/CVE-2023-20593.sh | 2 +- 4 files changed, 41 insertions(+), 30 deletions(-) diff --git a/src/libs/340_cpu_msr.sh b/src/libs/340_cpu_msr.sh index 45cba8c..9cb4a65 100644 --- a/src/libs/340_cpu_msr.sh +++ b/src/libs/340_cpu_msr.sh @@ -155,7 +155,7 @@ readonly READ_MSR_RET_KO=1 readonly READ_MSR_RET_ERR=2 # Read an MSR register value across one or all cores # Args: $1=msr_address $2=cpu_index(optional, default 0) -# Sets: ret_read_msr_value, ret_read_msr_msg +# Sets: ret_read_msr_value, ret_read_msr_value_hi, ret_read_msr_value_lo, ret_read_msr_msg # Returns: READ_MSR_RET_OK | READ_MSR_RET_KO | READ_MSR_RET_ERR read_msr() { local ret core first_core_ret first_core_value @@ -187,21 +187,31 @@ read_msr() { # Read an MSR register value from a single CPU core # Args: $1=core $2=msr_address -# Sets: ret_read_msr_value, ret_read_msr_msg +# Sets: ret_read_msr_value, ret_read_msr_value_hi, ret_read_msr_value_lo, ret_read_msr_msg # Returns: READ_MSR_RET_OK | READ_MSR_RET_KO | READ_MSR_RET_ERR read_msr_one_core() { - local ret core msr msr_dec mockvarname msr_h msr_l + local ret core msr msr_dec mockvarname msr_h msr_l mockval core="$1" msr_dec=$(($2)) msr=$(printf "0x%x" "$msr_dec") ret_read_msr_value='' + ret_read_msr_value_hi='' + ret_read_msr_value_lo='' ret_read_msr_msg='unknown error' mockvarname="SMC_MOCK_RDMSR_${msr}" # shellcheck disable=SC2086,SC1083 if [ -n "$(eval echo \${$mockvarname:-})" ]; then - ret_read_msr_value="$(eval echo \$$mockvarname)" + mockval="$(eval echo \$$mockvarname)" + # accept both legacy decimal (small values) and new 16-char hex format + if [ "${#mockval}" -eq 16 ]; then + ret_read_msr_value="$mockval" + else + ret_read_msr_value=$(printf '%016x' "$mockval") + fi + ret_read_msr_value_hi=$((0x${ret_read_msr_value%????????})) + ret_read_msr_value_lo=$((0x${ret_read_msr_value#????????})) pr_debug "read_msr: MOCKING enabled for msr $msr, returning $ret_read_msr_value" g_mocked=1 return $READ_MSR_RET_OK @@ -235,7 +245,7 @@ read_msr_one_core() { # MSR 0x10: 0x000003e1 0xb106dded msr_h=$(echo "$msr" | awk '{print $3}') msr_l=$(echo "$msr" | awk '{print $4}') - ret_read_msr_value=$((msr_h << 32 | msr_l)) + ret_read_msr_value=$(printf '%08x%08x' "$((msr_h))" "$((msr_l))") else # for Linux if [ ! -r $CPU_DEV_BASE/"$core"/msr ]; then @@ -245,15 +255,15 @@ read_msr_one_core() { # if rdmsr is available, use it elif command -v rdmsr >/dev/null 2>&1 && [ "${SMC_NO_RDMSR:-}" != 1 ]; then pr_debug "read_msr: using rdmsr on $msr" - ret_read_msr_value=$(rdmsr -r $msr_dec 2>/dev/null | od -t u8 -A n) + ret_read_msr_value=$(rdmsr -r $msr_dec 2>/dev/null | od -A n -t x8) # or if we have perl, use it, any 5.x version will work elif command -v perl >/dev/null 2>&1 && [ "${SMC_NO_PERL:-}" != 1 ]; then pr_debug "read_msr: using perl on $msr" - ret_read_msr_value=$(perl -e "open(M,'<','$CPU_DEV_BASE/$core/msr') and seek(M,$msr_dec,0) and read(M,\$_,8) and print" | od -t u8 -A n) + ret_read_msr_value=$(perl -e "open(M,'<','$CPU_DEV_BASE/$core/msr') and seek(M,$msr_dec,0) and read(M,\$_,8) and print" | od -A n -t x8) # fallback to dd if it supports skip_bytes elif dd if=/dev/null of=/dev/null bs=8 count=1 skip="$msr_dec" iflag=skip_bytes 2>/dev/null; then pr_debug "read_msr: using dd on $msr" - ret_read_msr_value=$(dd if=$CPU_DEV_BASE/"$core"/msr bs=8 count=1 skip="$msr_dec" iflag=skip_bytes 2>/dev/null | od -t u8 -A n) + ret_read_msr_value=$(dd if=$CPU_DEV_BASE/"$core"/msr bs=8 count=1 skip="$msr_dec" iflag=skip_bytes 2>/dev/null | od -A n -t x8) else pr_debug "read_msr: got no rdmsr, perl or recent enough dd!" g_mockme=$(printf "%b\n%b" "$g_mockme" "SMC_MOCK_RDMSR_${msr}_RET=$READ_MSR_RET_ERR") @@ -266,8 +276,10 @@ read_msr_one_core() { return $READ_MSR_RET_KO fi # remove sparse spaces od might give us - ret_read_msr_value=$((ret_read_msr_value)) + ret_read_msr_value=$(printf '%s' "$ret_read_msr_value" | tr -d ' \t\n' | tr '[:upper:]' '[:lower:]') fi + ret_read_msr_value_hi=$((0x${ret_read_msr_value%????????})) + ret_read_msr_value_lo=$((0x${ret_read_msr_value#????????})) g_mockme=$(printf "%b\n%b" "$g_mockme" "SMC_MOCK_RDMSR_${msr}='$ret_read_msr_value'") pr_debug "read_msr: MSR=$msr value is $ret_read_msr_value" return $READ_MSR_RET_OK diff --git a/src/libs/350_cpu_detect2.sh b/src/libs/350_cpu_detect2.sh index f2df9d7..1445efa 100644 --- a/src/libs/350_cpu_detect2.sh +++ b/src/libs/350_cpu_detect2.sh @@ -69,7 +69,8 @@ parse_cpu_details() { read_msr 0x17 ret=$? if [ $ret = $READ_MSR_RET_OK ]; then - cpu_platformid=$((1 << ((ret_read_msr_value >> 18) & 7))) + # platform ID (bits 52:50) = bits 18:20 of the upper 32-bit word + cpu_platformid=$((1 << ((ret_read_msr_value_hi >> 18) & 7))) fi fi diff --git a/src/libs/400_hw_check.sh b/src/libs/400_hw_check.sh index ba1e004..46d4f26 100644 --- a/src/libs/400_hw_check.sh +++ b/src/libs/400_hw_check.sh @@ -768,18 +768,18 @@ check_cpu() { if [ $ret = $READ_MSR_RET_OK ]; then capabilities=$ret_read_msr_value # https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/arch/x86/include/asm/msr-index.h#n82 - pr_debug "capabilities MSR is $capabilities (decimal)" - [ $((capabilities >> 0 & 1)) -eq 1 ] && cap_rdcl_no=1 - [ $((capabilities >> 1 & 1)) -eq 1 ] && cap_ibrs_all=1 - [ $((capabilities >> 2 & 1)) -eq 1 ] && cap_rsba=1 - [ $((capabilities >> 3 & 1)) -eq 1 ] && cap_l1dflush_no=1 - [ $((capabilities >> 4 & 1)) -eq 1 ] && cap_ssb_no=1 - [ $((capabilities >> 5 & 1)) -eq 1 ] && cap_mds_no=1 - [ $((capabilities >> 6 & 1)) -eq 1 ] && cap_pschange_msc_no=1 - [ $((capabilities >> 7 & 1)) -eq 1 ] && cap_tsx_ctrl_msr=1 - [ $((capabilities >> 8 & 1)) -eq 1 ] && cap_taa_no=1 - [ $((capabilities >> 25 & 1)) -eq 1 ] && cap_gds_ctrl=1 - [ $((capabilities >> 26 & 1)) -eq 1 ] && cap_gds_no=1 + pr_debug "capabilities MSR is $capabilities (hex)" + [ $(( ret_read_msr_value_lo >> 0 & 1 )) -eq 1 ] && cap_rdcl_no=1 + [ $(( ret_read_msr_value_lo >> 1 & 1 )) -eq 1 ] && cap_ibrs_all=1 + [ $(( ret_read_msr_value_lo >> 2 & 1 )) -eq 1 ] && cap_rsba=1 + [ $(( ret_read_msr_value_lo >> 3 & 1 )) -eq 1 ] && cap_l1dflush_no=1 + [ $(( ret_read_msr_value_lo >> 4 & 1 )) -eq 1 ] && cap_ssb_no=1 + [ $(( ret_read_msr_value_lo >> 5 & 1 )) -eq 1 ] && cap_mds_no=1 + [ $(( ret_read_msr_value_lo >> 6 & 1 )) -eq 1 ] && cap_pschange_msc_no=1 + [ $(( ret_read_msr_value_lo >> 7 & 1 )) -eq 1 ] && cap_tsx_ctrl_msr=1 + [ $(( ret_read_msr_value_lo >> 8 & 1 )) -eq 1 ] && cap_taa_no=1 + [ $(( ret_read_msr_value_lo >> 25 & 1 )) -eq 1 ] && cap_gds_ctrl=1 + [ $(( ret_read_msr_value_lo >> 26 & 1 )) -eq 1 ] && cap_gds_no=1 pr_debug "capabilities says rdcl_no=$cap_rdcl_no ibrs_all=$cap_ibrs_all rsba=$cap_rsba l1dflush_no=$cap_l1dflush_no ssb_no=$cap_ssb_no mds_no=$cap_mds_no taa_no=$cap_taa_no pschange_msc_no=$cap_pschange_msc_no" if [ "$cap_ibrs_all" = 1 ]; then pstatus green YES @@ -869,9 +869,8 @@ check_cpu() { read_msr 0x122 ret=$? if [ "$ret" = $READ_MSR_RET_OK ]; then - g_tsx_ctrl_msr=$ret_read_msr_value - cap_tsx_ctrl_rtm_disable=$((g_tsx_ctrl_msr >> 0 & 1)) - cap_tsx_ctrl_cpuid_clear=$((g_tsx_ctrl_msr >> 1 & 1)) + cap_tsx_ctrl_rtm_disable=$(( ret_read_msr_value_lo >> 0 & 1 )) + cap_tsx_ctrl_cpuid_clear=$(( ret_read_msr_value_lo >> 1 & 1 )) fi pr_info_nol " * TSX_CTRL MSR indicates TSX RTM is disabled: " @@ -909,9 +908,8 @@ check_cpu() { read_msr 0x123 ret=$? if [ "$ret" = $READ_MSR_RET_OK ]; then - g_mcu_opt_ctrl=$ret_read_msr_value - cap_gds_mitg_dis=$((g_mcu_opt_ctrl >> 4 & 1)) - cap_gds_mitg_lock=$((g_mcu_opt_ctrl >> 5 & 1)) + cap_gds_mitg_dis=$(( ret_read_msr_value_lo >> 4 & 1 )) + cap_gds_mitg_lock=$(( ret_read_msr_value_lo >> 5 & 1 )) fi pr_info_nol " * GDS microcode mitigation is disabled (GDS_MITG_DIS): " @@ -1018,7 +1016,7 @@ check_cpu() { read_msr 0x123 ret=$? if [ $ret = $READ_MSR_RET_OK ]; then - if [ "$ret_read_msr_value" = 0 ]; then + if [ "$ret_read_msr_value" = "0000000000000000" ]; then #SRBDS mitigation control exists and is enabled via microcode cap_srbds_on=1 else diff --git a/src/vulns/CVE-2023-20593.sh b/src/vulns/CVE-2023-20593.sh index eedc24c..38ab657 100644 --- a/src/vulns/CVE-2023-20593.sh +++ b/src/vulns/CVE-2023-20593.sh @@ -38,7 +38,7 @@ check_CVE_2023_20593_linux() { read_msr 0xc0011029 ret=$? if [ "$ret" = "$READ_MSR_RET_OK" ]; then - if [ $((ret_read_msr_value >> 9 & 1)) -eq 1 ]; then + if [ $(( ret_read_msr_value_lo >> 9 & 1 )) -eq 1 ]; then pstatus green YES "FP_BACKUP_FIX bit set in DE_CFG" fp_backup_fix=1 else