WoTTsecurity / api

API and Dashboard
https://dash.wott.io
MIT License
0 stars 2 forks source link

Add check for Meltdown / Spectre #482

Closed vpetersson closed 5 years ago

vpetersson commented 5 years ago

Meltdown/Spectre was a big thing. Let's add a security check for it.

We should be able to check it as follows:

grep CONFIG_PAGE_TABLE_ISOLATION=y /boot/config-`uname -r` && echo "patched :)" || echo "unpatched :("
CONFIG_PAGE_TABLE_ISOLATION=y
patched :)

(The patched/unpateched is obviously just for readability)

a-martynovich commented 5 years ago

Kernel configs are not available unless the kernel was built with exported configs. This is not always the case.

vpetersson commented 5 years ago

Yes, you're right. I'm open to better checks.

vpetersson commented 5 years ago

https://www.ostechnix.com/check-meltdown-spectre-vulnerabilities-patch-linux/

a-martynovich commented 5 years ago

If kernel configs are not exported I don't see any other way to check if CONFIG_PAGE_TABLE_ISOLATION is on. All other methods given in this article don't work.

But I have a better idea. If a user has a "standard" kernel running (the one from Debian/Ubuntu repo) we can check it for vulns related to meltdown/spectre, their list is here. Otherwise, i.e. custom kernel is running, if the kernel is older than 4.14.12, 4.9.75, or 4.4.110 (needs some versioning logic here) it's vulnerable. If it's newer - we try "heuristics" described in the article.

By the way this script checks for all meltdown/spectre vulnerabilities using just grep, perl and binutils. Looks cool.

a-martynovich commented 5 years ago

Just found this SO thread where they give one simple command to check for PTI: cat /sys/devices/system/cpu/vulnerabilities/* | grep PTI. It works on my Ubuntu, although I'm afraid if this list of vulnerabilities in sysfs may be a switchable option. Also grep -q "cpu_insecure\|cpu_meltdown\|kaiser" /proc/cpuinfo && echo "patched :)" \ || echo "unpatched :(" works too.

Checking dmesg or systemd journal is not an option because they both get rotated after some uptime, and the message about PTI is among the very first.

a-martynovich commented 5 years ago

And there's another mitigation agains Spectre v2, called Retpoline. Need to check for CONFIG_RETPOLINE, or

$ cat /sys/devices/system/cpu/vulnerabilities/spectre_v2
Mitigation: Full generic retpoline, IBPB: conditional, IBRS_FW, STIBP: conditional, RSB filling

also

$ grep  "cpu_insecure\|cpu_meltdown\|kaiser" /proc/cpuinfo 
bugs        : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs
vpetersson commented 5 years ago

@a-martynovich Let's assume everyone will be using upstream kernels (which is the case for most today), in which case, checking the kernel against the CVE list is perhaps the path of least resistance.

a-martynovich commented 5 years ago

@vpetersson By upstream you mean kernel upstream or Ubuntu/Debian upstream?

vpetersson commented 5 years ago

Upstream from Ubuntu/Debian.

a-martynovich commented 5 years ago

Another addition. This article states that most AMD and ARM CPUs are not subject to these vulnerabilities. We should only check x86 (i386 and x86_64) and make sure it's an Intel CPU. Agent needs to send CPU model in ping.

vpetersson commented 5 years ago

Yep, this is a sensible filter. The bug was Intel only.

a-martynovich commented 5 years ago

We want to see which deb package contains the currently running kernel. Here's how I think we can do it with some level of certainty.

Get the currently running kernel version:

# uname -a
Linux artem-linux-gf 5.0.0-32-generic #34~18.04.2-Ubuntu SMP Thu Oct 10 10:36:02 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

Find which vmlinuz has the same version:

# file /boot/vmlinuz-5.0.0-32-generic
/boot/vmlinuz-5.0.0-32-generic: Linux kernel x86 boot executable bzImage, version 5.0.0-32-generic (buildd@lgw01-amd64-015) #34~18.04.2-Ubuntu SMP Thu Oct 10 10:36:02 UTC 2019, RO-rootFS, swap_dev 0x8, Normal VGA

We can't tell with 100% certainty if the currently running kernel was loaded from this vmlinuz unless we compare the checksum of the running kernel and the uncompressed file, but having identical versions (5.0.0-32-generic ... #34~18.04.2-Ubuntu SMP Thu Oct 10 10:36:02 UTC 2019) is already enough IMO.

Find which installed deb package has this vmlinuz:

# dpkg -L linux-image-5.0.0-32-generic
/.
/boot
/boot/vmlinuz-5.0.0-32-generic
...

This means the currently running kernel is installed with linux-image-5.0.0-32-generic. Should work on Debian too.

Doesn't work on Raspbian because its kernel gets installed as part of raspberrypi-kernel package which contains kernel packed into "ARM boot executable zImage". To see which kernel is inside we need to extract the kernel from the image. That's not very easy and IMO not worth it.

a-martynovich commented 5 years ago

Here's what I learned from studying kernel source code and Debian repos. All kernels used by all Debian suites since Jessie are patched against all known CPU vulnerabilities. That includes versions 3.16, 4.4, 4.9 and 5.0+. The patches export vulnerability status at /sys/devices/system/cpu/vulnerabilities/*, and the possible status values are described in the docs. Also it's possible to disable every one of them by passing options to the kernel, but this should be reflected in status files as well (needs additional checking).

There're six mitigations (below are corresponding files in /sys/devices/system/cpu/vulnerabilities):

If any of these are absent or have status different from Not affected or Mitigation: ... this means the system is probably vulnerable. Otherwise the system is protected.

It is possible to bind-mount anything over /sys/devices/system/cpu/vulnerabilities in which case these files won't be available. Also they won't be available if the kernel does not have the protection compiled in. In this case we should check the kernel against the list of corresponding CVEs. If the kernel is not vulnerable to any of CVEs (meaning it has all the patches) but it has any mitigations disabled in its cmdline then it's vulnerable.

Here's what the agent should send to the server:

{ cpu: {vendor: "Intel", vulnerable: true/false/null, mitigations_disabled: true/false}}

In case if vulnerable == null the server should check the kernel against the list of corresponding CVEs and report it as vulnerable if either a CVE is found or mitigations_disabled==true.

Kernel cmdline parameters which disable miitigations:

mds=off
pti=off
nopti
mitigations=off
nospectre_v1
nospectre_v2
spectre_v2=off
spectre_v2_user=off
spec_store_bypass_disable=off

CVEs:

Most of these CVEs affect not only the kernel (linux* packages) but also xen, qemu and nvidia drivers. Therefore not only the currently installed and running kernel package should be queried for CVEs, but also all the listed CVEs should be queried for any installed package.

In case of Jessie, if any Nvidia drivers (nvidia-graphics-drivers or nvidia-graphics-drivers-legacy*) is installed from non-free repo the system will be vulnerable to some of these CVEs and there's no fix (and there won't be any). I think it should be told to the user. The user has an option to uninstall the drivers.

a-martynovich commented 5 years ago

To find out which kernel is currently running we need to get the BOOT_IMAGE kernel cmdline parameter which points to a file in /boot. Then find which deb binary package contains this file and send the corresponding source package to the server.

rptrchv commented 5 years ago

@vpetersson do we need a security tab section for this check or having only recommended action is enough?

vpetersson commented 5 years ago

yes, let's add a security tab section for this too.

rptrchv commented 5 years ago

@a-martynovich ^

a-martynovich commented 5 years ago

@vpetersson Please provide text for the recommended action.

vpetersson commented 5 years ago

@a-martynovich / @rptrchv found it here.

Header: $HOST is vulnerable to Meltdown/Spectre
We detected that $HOST is vulnerable to Meltdown/Spectre. You can learn more about these issues <a href="https://meltdownattack.com/">here</a>. To fix the issue, please run `apt-get update && apt-get install $PACKAGES`
a-martynovich commented 5 years ago

@vpetersson I've changed the text, but I had to write apt-get update && apt-get upgrade instead because the current code doesn't report which packages are affected (other than the kernel). Is this ok or should i list which packages are affected?

vpetersson commented 5 years ago

Yeah that's fine for now.