split script in multiple files, reassembled through build.sh

This commit is contained in:
Stéphane Lesimple
2026-03-30 20:04:16 +02:00
parent 7e660812e9
commit cebda01d05
47 changed files with 7712 additions and 7617 deletions

235
src/vulns/CVE-2017-5753.sh Normal file
View File

@@ -0,0 +1,235 @@
# vim: set ts=4 sw=4 sts=4 et:
###################
# SPECTRE 1 SECTION
# CVE-2017-5753 Spectre Variant 1 (bounds check bypass) - entry point
check_CVE_2017_5753() {
check_cve 'CVE-2017-5753'
}
# CVE-2017-5753 Spectre Variant 1 (bounds check bypass) - Linux mitigation check
check_CVE_2017_5753_linux() {
local status sys_interface_available msg v1_mask_nospec nb_lfence v1_lfence ret explain_text
status=UNK
sys_interface_available=0
msg=''
if sys_interface_check "$VULN_SYSFS_BASE/spectre_v1"; then
# this kernel has the /sys interface, trust it over everything
# v0.33+: don't. some kernels have backported the array_index_mask_nospec() workaround without
# modifying the vulnerabilities/spectre_v1 file. that's bad. we can't trust it when it says Vulnerable :(
# see "silent backport" detection at the bottom of this func
sys_interface_available=1
status=$ret_sys_interface_check_status
fi
if [ "$opt_sysfs_only" != 1 ]; then
# no /sys interface (or offline mode), fallback to our own ways
pr_info_nol "* Kernel has array_index_mask_nospec: "
# vanilla: look for the Linus' mask aka array_index_mask_nospec()
# that is inlined at least in raw_copy_from_user (__get_user_X symbols)
#mov PER_CPU_VAR(current_task), %_ASM_DX
#cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX
#jae bad_get_user
# /* array_index_mask_nospec() are the 2 opcodes that follow */
#+sbb %_ASM_DX, %_ASM_DX
#+and %_ASM_DX, %_ASM_AX
#ASM_STAC
# x86 64bits: jae(0x0f 0x83 0x?? 0x?? 0x?? 0x??) sbb(0x48 0x19 0xd2) and(0x48 0x21 0xd0)
# x86 32bits: cmp(0x3b 0x82 0x?? 0x?? 0x00 0x00) jae(0x73 0x??) sbb(0x19 0xd2) and(0x21 0xd0)
#
# arm32
##ifdef CONFIG_THUMB2_KERNEL
##define CSDB ".inst.w 0xf3af8014"
##else
##define CSDB ".inst 0xe320f014" e320f014
##endif
#asm volatile(
# "cmp %1, %2\n" e1500003
#" sbc %0, %1, %1\n" e0c03000
#CSDB
#: "=r" (mask)
#: "r" (idx), "Ir" (sz)
#: "cc");
#
# http://git.arm.linux.org.uk/cgit/linux-arm.git/commit/?h=spectre&id=a78d156587931a2c3b354534aa772febf6c9e855
v1_mask_nospec=''
if [ -n "$g_kernel_err" ]; then
pstatus yellow UNKNOWN "couldn't check ($g_kernel_err)"
elif ! command -v perl >/dev/null 2>&1; then
pstatus yellow UNKNOWN "missing 'perl' binary, please install it"
else
perl -ne '/\x0f\x83....\x48\x19\xd2\x48\x21\xd0/ and $found++; END { exit($found) }' "$g_kernel"
ret=$?
if [ "$ret" -gt 0 ]; then
pstatus green YES "$ret occurrence(s) found of x86 64 bits array_index_mask_nospec()"
v1_mask_nospec="x86 64 bits array_index_mask_nospec"
else
perl -ne '/\x3b\x82..\x00\x00\x73.\x19\xd2\x21\xd0/ and $found++; END { exit($found) }' "$g_kernel"
ret=$?
if [ "$ret" -gt 0 ]; then
pstatus green YES "$ret occurrence(s) found of x86 32 bits array_index_mask_nospec()"
v1_mask_nospec="x86 32 bits array_index_mask_nospec"
else
ret=$("${opt_arch_prefix}objdump" "$g_objdump_options" "$g_kernel" | grep -w -e f3af8014 -e e320f014 -B2 | grep -B1 -w sbc | grep -w -c cmp)
if [ "$ret" -gt 0 ]; then
pstatus green YES "$ret occurrence(s) found of arm 32 bits array_index_mask_nospec()"
v1_mask_nospec="arm 32 bits array_index_mask_nospec"
else
pstatus yellow NO
fi
fi
fi
fi
pr_info_nol "* Kernel has the Red Hat/Ubuntu patch: "
check_redhat_canonical_spectre
if [ "$g_redhat_canonical_spectre" = -1 ]; then
pstatus yellow UNKNOWN "missing '${opt_arch_prefix}strings' tool, please install it, usually it's in the binutils package"
elif [ "$g_redhat_canonical_spectre" = -2 ]; then
pstatus yellow UNKNOWN "couldn't check ($g_kernel_err)"
elif [ "$g_redhat_canonical_spectre" = 1 ]; then
pstatus green YES
elif [ "$g_redhat_canonical_spectre" = 2 ]; then
pstatus green YES "but without IBRS"
else
pstatus yellow NO
fi
pr_info_nol "* Kernel has mask_nospec64 (arm64): "
#.macro mask_nospec64, idx, limit, tmp
#sub \tmp, \idx, \limit
#bic \tmp, \tmp, \idx
#and \idx, \idx, \tmp, asr #63
#csdb
#.endm
#$ aarch64-linux-gnu-objdump -d vmlinux | grep -w bic -A1 -B1 | grep -w sub -A2 | grep -w and -B2
#ffffff8008082e44: cb190353 sub x19, x26, x25
#ffffff8008082e48: 8a3a0273 bic x19, x19, x26
#ffffff8008082e4c: 8a93ff5a and x26, x26, x19, asr #63
#ffffff8008082e50: d503229f hint #0x14
# /!\ can also just be "csdb" instead of "hint #0x14" for native objdump
#
# if we have v1_mask_nospec or g_redhat_canonical_spectre>0, don't bother disassembling the kernel, the answer is no.
if [ -n "$v1_mask_nospec" ] || [ "$g_redhat_canonical_spectre" -gt 0 ]; then
pstatus yellow NO
elif [ -n "$g_kernel_err" ]; then
pstatus yellow UNKNOWN "couldn't check ($g_kernel_err)"
elif ! command -v perl >/dev/null 2>&1; then
pstatus yellow UNKNOWN "missing 'perl' binary, please install it"
elif ! command -v "${opt_arch_prefix}objdump" >/dev/null 2>&1; then
pstatus yellow UNKNOWN "missing '${opt_arch_prefix}objdump' tool, please install it, usually it's in the binutils package"
else
"${opt_arch_prefix}objdump" "$g_objdump_options" "$g_kernel" | perl -ne 'push @r, $_; /\s(hint|csdb)\s/ && $r[0]=~/\ssub\s+(x\d+)/ && $r[1]=~/\sbic\s+$1,\s+$1,/ && $r[2]=~/\sand\s/ && exit(9); shift @r if @r>3'
ret=$?
if [ "$ret" -eq 9 ]; then
pstatus green YES "mask_nospec64 macro is present and used"
v1_mask_nospec="arm64 mask_nospec64"
else
pstatus yellow NO
fi
fi
pr_info_nol "* Kernel has array_index_nospec (arm64): "
# in 4.19+ kernels, the mask_nospec64 asm64 macro is replaced by array_index_nospec, defined in nospec.h, and used in invoke_syscall()
# ffffff8008090a4c: 2a0203e2 mov w2, w2
# ffffff8008090a50: eb0200bf cmp x5, x2
# ffffff8008090a54: da1f03e2 ngc x2, xzr
# ffffff8008090a58: d503229f hint #0x14
# /!\ can also just be "csdb" instead of "hint #0x14" for native objdump
#
# if we have v1_mask_nospec or g_redhat_canonical_spectre>0, don't bother disassembling the kernel, the answer is no.
if [ -n "$v1_mask_nospec" ] || [ "$g_redhat_canonical_spectre" -gt 0 ]; then
pstatus yellow NO
elif [ -n "$g_kernel_err" ]; then
pstatus yellow UNKNOWN "couldn't check ($g_kernel_err)"
elif ! command -v perl >/dev/null 2>&1; then
pstatus yellow UNKNOWN "missing 'perl' binary, please install it"
elif ! command -v "${opt_arch_prefix}objdump" >/dev/null 2>&1; then
pstatus yellow UNKNOWN "missing '${opt_arch_prefix}objdump' tool, please install it, usually it's in the binutils package"
else
"${opt_arch_prefix}objdump" -d "$g_kernel" | perl -ne 'push @r, $_; /\s(hint|csdb)\s/ && $r[0]=~/\smov\s+(w\d+),\s+(w\d+)/ && $r[1]=~/\scmp\s+(x\d+),\s+(x\d+)/ && $r[2]=~/\sngc\s+$2,/ && exit(9); shift @r if @r>3'
ret=$?
if [ "$ret" -eq 9 ]; then
pstatus green YES "array_index_nospec macro is present and used"
v1_mask_nospec="arm64 array_index_nospec"
else
pstatus yellow NO
fi
fi
if [ "$opt_verbose" -ge 2 ] || { [ -z "$v1_mask_nospec" ] && [ "$g_redhat_canonical_spectre" != 1 ] && [ "$g_redhat_canonical_spectre" != 2 ]; }; then
# this is a slow heuristic and we don't need it if we already know the kernel is patched
# but still show it in verbose mode
pr_info_nol "* Checking count of LFENCE instructions following a jump in kernel... "
if [ -n "$g_kernel_err" ]; then
pstatus yellow UNKNOWN "couldn't check ($g_kernel_err)"
else
if ! command -v "${opt_arch_prefix}objdump" >/dev/null 2>&1; then
pstatus yellow UNKNOWN "missing '${opt_arch_prefix}objdump' tool, please install it, usually it's in the binutils package"
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.
# v0.33+: now only count lfence opcodes after a jump, way less error-prone
# non patched kernel have between 0 and 20 matches, patched ones have at least 40-45
nb_lfence=$("${opt_arch_prefix}objdump" "$g_objdump_options" "$g_kernel" 2>/dev/null | grep -w -B1 lfence | grep -Ewc 'jmp|jne|je')
if [ "$nb_lfence" -lt 30 ]; then
pstatus yellow NO "only $nb_lfence jump-then-lfence instructions found, should be >= 30 (heuristic)"
else
v1_lfence=1
pstatus green YES "$nb_lfence jump-then-lfence instructions found, which is >= 30 (heuristic)"
fi
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
# report status
if ! is_cpu_affected "$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 affected"
elif [ -z "$msg" ]; then
# if msg is empty, sysfs check didn't fill it, rely on our own test
if [ -n "$v1_mask_nospec" ]; then
pvulnstatus "$cve" OK "Kernel source has been patched to mitigate the vulnerability ($v1_mask_nospec)"
elif [ "$g_redhat_canonical_spectre" = 1 ] || [ "$g_redhat_canonical_spectre" = 2 ]; then
pvulnstatus "$cve" OK "Kernel source has been patched to mitigate the vulnerability (Red Hat/Ubuntu patch)"
elif [ "$v1_lfence" = 1 ]; then
pvulnstatus "$cve" OK "Kernel source has PROBABLY been patched to mitigate the vulnerability (jump-then-lfence instructions heuristic)"
elif [ -n "$g_kernel_err" ]; then
pvulnstatus "$cve" UNK "Couldn't find kernel image or tools missing to execute the checks"
explain "Re-run this script with root privileges, after installing the missing tools indicated above"
else
pvulnstatus "$cve" VULN "Kernel source needs to be patched to mitigate the vulnerability"
explain "Your kernel is too old to have the mitigation for Variant 1, you should upgrade to a newer kernel. If you're using a Linux distro and didn't compile the kernel yourself, you should upgrade your distro to get a newer kernel."
fi
else
if [ "$msg" = "Vulnerable" ] && [ -n "$v1_mask_nospec" ]; then
pvulnstatus "$cve" OK "Kernel source has been patched to mitigate the vulnerability (silent backport of array_index_mask_nospec)"
else
if [ "$msg" = "Vulnerable" ]; then
msg="Kernel source needs to be patched to mitigate the vulnerability"
explain_text="Your kernel is too old to have the mitigation for Variant 1, you should upgrade to a newer kernel. If you're using a Linux distro and didn't compile the kernel yourself, you should upgrade your distro to get a newer kernel."
fi
pvulnstatus "$cve" "$status" "$msg"
[ -n "${explain_text:-}" ] && explain "$explain_text"
unset explain_text
fi
fi
}
# CVE-2017-5753 Spectre Variant 1 (bounds check bypass) - BSD mitigation check
check_CVE_2017_5753_bsd() {
if ! is_cpu_affected "$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 affected"
else
pvulnstatus "$cve" VULN "no mitigation for BSD yet"
fi
}