feat(sysfs): print details even with sysfs

Before, when the /sys kernel vulnerability interface
was available, we would bypass all our tests and just
print the output of the vulnerability interface. Now,
we still rely on it when available, but we run our
checks anyway, except for variant 1 where the current
method of mitigation detection doesn't add much value
to the bare /sys check
This commit is contained in:
Stéphane Lesimple 2018-01-21 18:02:11 +01:00
parent 443d9a2ae9
commit ff5c92fa6f

View File

@ -34,6 +34,7 @@ show_usage()
--no-color Don't use color codes --no-color Don't use color codes
--verbose, -v Increase verbosity level --verbose, -v Increase verbosity level
--no-sysfs Don't use the /sys interface even if present --no-sysfs Don't use the /sys interface even if present
--sysfs-only Only use the /sys interface, don't run our own checks
--coreos Special mode for CoreOS (use an ephemeral toolbox to inspect kernel) --coreos Special mode for CoreOS (use an ephemeral toolbox to inspect kernel)
--batch text Produce machine readable output, this is the default if --batch is specified alone --batch text Produce machine readable output, this is the default if --batch is specified alone
--batch json Produce JSON output formatted for Puppet, Ansible, Chef... --batch json Produce JSON output formatted for Puppet, Ansible, Chef...
@ -91,6 +92,7 @@ opt_variant2=0
opt_variant3=0 opt_variant3=0
opt_allvariants=1 opt_allvariants=1
opt_no_sysfs=0 opt_no_sysfs=0
opt_sysfs_only=0
opt_coreos=0 opt_coreos=0
global_critical=0 global_critical=0
@ -343,6 +345,9 @@ while [ -n "$1" ]; do
elif [ "$1" = "--no-sysfs" ]; then elif [ "$1" = "--no-sysfs" ]; then
opt_no_sysfs=1 opt_no_sysfs=1
shift shift
elif [ "$1" = "--sysfs-only" ]; then
opt_sysfs_only=1
shift
elif [ "$1" = "--coreos" ]; then elif [ "$1" = "--coreos" ]; then
opt_coreos=1 opt_coreos=1
shift shift
@ -404,6 +409,11 @@ done
show_header show_header
if [ "$opt_no_sysfs" = 1 -a "$opt_sysfs_only" = 1 ]; then
_warn "Incompatible options specified (--no-sysfs and --sysfs-only), aborting"
exit 255
fi
# print status function # print status function
pstatus() pstatus()
{ {
@ -771,7 +781,7 @@ _info
sys_interface_check() sys_interface_check()
{ {
[ "$opt_live" = 1 -a "$opt_no_sysfs" = 0 -a -r "$1" ] || return 1 [ "$opt_live" = 1 -a "$opt_no_sysfs" = 0 -a -r "$1" ] || return 1
_info_nol "* Checking whether we're safe according to the /sys interface: " _info_nol "* Mitigated according to the /sys interface: "
if grep -qi '^not affected' "$1"; then if grep -qi '^not affected' "$1"; then
# Not affected # Not affected
status=OK status=OK
@ -805,7 +815,7 @@ check_variant1()
if sys_interface_check "/sys/devices/system/cpu/vulnerabilities/spectre_v1"; then if sys_interface_check "/sys/devices/system/cpu/vulnerabilities/spectre_v1"; then
# this kernel has the /sys interface, trust it over everything # this kernel has the /sys interface, trust it over everything
sys_interface_available=1 sys_interface_available=1
else elif [ "$opt_sysfs_only" != 1 ]; then
# no /sys interface (or offline mode), fallback to our own ways # no /sys interface (or offline mode), fallback to our own ways
_info_nol "* Checking count of LFENCE opcodes in kernel: " _info_nol "* Checking count of LFENCE opcodes in kernel: "
if [ -n "$vmlinux_err" ]; then if [ -n "$vmlinux_err" ]; then
@ -835,6 +845,10 @@ check_variant1()
fi fi
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 fi
# if we have the /sys interface, don't even check is_cpu_vulnerable ourselves, the kernel already does it # if we have the /sys interface, don't even check is_cpu_vulnerable ourselves, the kernel already does it
@ -860,7 +874,8 @@ check_variant2()
if sys_interface_check "/sys/devices/system/cpu/vulnerabilities/spectre_v2"; then if sys_interface_check "/sys/devices/system/cpu/vulnerabilities/spectre_v2"; then
# this kernel has the /sys interface, trust it over everything # this kernel has the /sys interface, trust it over everything
sys_interface_available=1 sys_interface_available=1
else fi
if [ "$opt_sysfs_only" != 1 ]; then
_info "* Mitigation 1" _info "* Mitigation 1"
_info " * Hardware support (CPU microcode)" _info " * Hardware support (CPU microcode)"
_info " * Indirect Branch Restricted Speculation (IBRS)" _info " * Indirect Branch Restricted Speculation (IBRS)"
@ -1109,13 +1124,22 @@ check_variant2()
# See gcc commit https://github.com/hjl-tools/gcc/commit/23b517d4a67c02d3ef80b6109218f2aadad7bd79 # See gcc commit https://github.com/hjl-tools/gcc/commit/23b517d4a67c02d3ef80b6109218f2aadad7bd79
# In latest retpoline LKML patches, the noretpoline_setup symbol exists only if CONFIG_RETPOLINE is set # In latest retpoline LKML patches, the noretpoline_setup symbol exists only if CONFIG_RETPOLINE is set
# *AND* if the compiler is retpoline-compliant, so look for that symbol # *AND* if the compiler is retpoline-compliant, so look for that symbol
if [ -n "$opt_map" ]; then if [ -e "/sys/devices/system/cpu/vulnerabilities/spectre_v2" ]; then
if grep -qw Minimal /sys/devices/system/cpu/vulnerabilities/spectre_v2; then
pstatus red NO "kernel reports minimal retpoline compilation"
elif grep -qw Full /sys/devices/system/cpu/vulnerabilities/spectre_v2; then
retpoline_compiler=1
pstatus green YES "kernel reports full retpoline compilation"
else
pstatus yellow UNKNOWN
fi
elif [ -n "$opt_map" ]; then
# look for the symbol # look for the symbol
if grep -qw noretpoline_setup "$opt_map"; then if grep -qw noretpoline_setup "$opt_map"; then
retpoline_compiler=1 retpoline_compiler=1
pstatus green YES "noretpoline_setup symbol found in System.map" pstatus green YES "noretpoline_setup symbol found in System.map"
else else
pstatus red NO pstatus yellow UNKNOWN
fi fi
elif [ -n "$vmlinux" ]; then elif [ -n "$vmlinux" ]; then
# look for the symbol # look for the symbol
@ -1125,7 +1149,7 @@ check_variant2()
retpoline_compiler=1 retpoline_compiler=1
pstatus green YES "noretpoline_setup found in vmlinux symbols" pstatus green YES "noretpoline_setup found in vmlinux symbols"
else else
pstatus red NO pstatus yellow UNKNOWN
fi fi
elif grep -q noretpoline_setup "$vmlinux"; then elif grep -q noretpoline_setup "$vmlinux"; then
# if we don't have nm, nevermind, the symbol name is long enough to not have # if we don't have nm, nevermind, the symbol name is long enough to not have
@ -1133,40 +1157,46 @@ check_variant2()
retpoline_compiler=1 retpoline_compiler=1
pstatus green YES "noretpoline_setup found in vmlinux" pstatus green YES "noretpoline_setup found in vmlinux"
else else
pstatus red NO pstatus yellow UNKNOWN
fi fi
else else
pstatus yellow UNKNOWN "couldn't find your kernel image or System.map" pstatus yellow UNKNOWN "couldn't find your kernel image or System.map"
fi fi
elif [ "$sys_interface_available" = 0 ]; then
# 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 fi
cve='CVE-2017-5715'
# if we have the /sys interface, don't even check is_cpu_vulnerable ourselves, the kernel already does it # if we have the /sys interface, don't even check is_cpu_vulnerable ourselves, the kernel already does it
if [ "$sys_interface_available" = 0 ] && ! is_cpu_vulnerable 2; then if [ "$sys_interface_available" = 0 ] && ! is_cpu_vulnerable 2; then
# override status & msg in case CPU is not vulnerable after all # override status & msg in case CPU is not vulnerable after all
pvulnstatus CVE-2017-5715 OK "your CPU vendor reported your CPU model as not vulnerable" pvulnstatus $cve OK "your CPU vendor reported your CPU model as not vulnerable"
elif [ -z "$msg" ]; then elif [ -z "$msg" ]; then
# if msg is empty, sysfs check didn't fill it, rely on our own test # if msg is empty, sysfs check didn't fill it, rely on our own test
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 OK "retpoline mitigates the vulnerability"
elif [ "$opt_live" = 1 ]; then elif [ "$opt_live" = 1 ]; then
if [ "$ibrs_enabled" = 1 -o "$ibrs_enabled" = 2 ] && [ "$ibpb_enabled" = 1 ]; then if [ "$ibrs_enabled" = 1 -o "$ibrs_enabled" = 2 ] && [ "$ibpb_enabled" = 1 ]; then
pvulnstatus CVE-2017-5715 OK "IBRS/IBPB are mitigating the vulnerability" pvulnstatus $cve OK "IBRS/IBPB are mitigating the vulnerability"
elif [ "$ibpb_enabled" = 2 ]; then elif [ "$ibpb_enabled" = 2 ]; then
pvulnstatus CVE-2017-5715 OK "Full IBPB is mitigating the vulnerability" pvulnstatus $cve 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 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/IBPB will mitigate the vulnerability if enabled at runtime" pvulnstatus $cve 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 VULN "IBRS hardware + kernel support OR kernel with retpoline are needed to mitigate the vulnerability"
else else
pvulnstatus CVE-2017-5715 UNK "offline mode: not enough information" pvulnstatus $cve UNK "offline mode: not enough information"
fi fi
fi fi
else else
pvulnstatus CVE-2017-5715 "$status" "$msg" [ "$msg" = "Vulnerable" ] && msg="IBRS hardware + kernel support OR kernel with retpoline are needed to mitigate the vulnerability"
pvulnstatus $cve "$status" "$msg"
fi fi
} }
@ -1182,7 +1212,7 @@ check_variant3()
if sys_interface_check "/sys/devices/system/cpu/vulnerabilities/meltdown"; then if sys_interface_check "/sys/devices/system/cpu/vulnerabilities/meltdown"; then
# this kernel has the /sys interface, trust it over everything # this kernel has the /sys interface, trust it over everything
sys_interface_available=1 sys_interface_available=1
else elif [ "$opt_sysfs_only" != 1 ]; then
_info_nol "* Kernel supports Page Table Isolation (PTI): " _info_nol "* Kernel supports Page Table Isolation (PTI): "
kpti_support=0 kpti_support=0
kpti_can_tell=0 kpti_can_tell=0
@ -1292,7 +1322,7 @@ check_variant3()
if [ "$opt_live" = 1 ]; then if [ "$opt_live" = 1 ]; then
# checking whether we're running under Xen PV 64 bits. If yes, we're not affected by variant3 # checking whether we're running under Xen PV 64 bits. If yes, we're not affected by variant3
_info_nol "* Checking if we're running under Xen PV (64 bits): " _info_nol "* Running under Xen PV (64 bits): "
if [ "$(uname -m)" = "x86_64" ]; then if [ "$(uname -m)" = "x86_64" ]; then
# XXX do we have a better way that relying on dmesg? # XXX do we have a better way that relying on dmesg?
dmesg_grep 'Booting paravirtualized kernel on Xen$'; ret=$? dmesg_grep 'Booting paravirtualized kernel on Xen$'; ret=$?
@ -1308,6 +1338,10 @@ check_variant3()
pstatus blue NO pstatus blue NO
fi fi
fi fi
elif [ "$sys_interface_available" = 0 ]; then
# 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 fi
# if we have the /sys interface, don't even check is_cpu_vulnerable ourselves, the kernel already does it # if we have the /sys interface, don't even check is_cpu_vulnerable ourselves, the kernel already does it
@ -1335,6 +1369,7 @@ check_variant3()
fi fi
fi fi
else else
[ "$msg" = "Vulnerable" ] && msg="PTI is needed to mitigate the vulnerability"
pvulnstatus $cve "$status" "$msg" pvulnstatus $cve "$status" "$msg"
fi fi
} }