Ejemplo n.º 1
0
def cpu_vulnerabilities():
    """
    Query sysfs for CPU vulnerabilities mitigation.
    :return: A dict where
        'vendor': "Vendor ID" field returned by lscpu. Possible values: GenuineIntel, AuthenticAMD, ARM.
        'vulnerable': False if not vulnerable, True if vulnerable, None if in doubt. Present if vendor is GenuineIntel.
        'mitigations_disabled': whether any mitigation was disabled in kernel cmdline. Present if vulnerable is None.
    """
    from sh import lscpu
    os.environ[
        'LC_ALL'] = 'en_US'  # switch language to English to be able to parse lscpu output.
    vendor_id = None
    for line in lscpu().stdout.decode().split('\n'):
        param = line.split(':', 1)
        if param and param[0] == 'Vendor ID':
            vendor_id = param[1].strip()
            break
    # TODO: switch LC_ALL back?

    res = {'vendor': vendor_id}
    if vendor_id != "GenuineIntel":
        # Not an Intel CPU, most probably not vulnerable
        return res

    sys_vulnerabilities = Path('/sys/devices/system/cpu/vulnerabilities')
    if not sys_vulnerabilities.is_dir():
        # Directory does not exist: either smth is bind-mounted over it or the kernel is too old.
        vulnerable = None
    else:
        vulnerable = False
        vulns = ['l1tf', 'meltdown', 'spectre_v1', 'spectre_v2']
        if detect_cloud() != CloudProvider.AMAZON:
            # AWS reports no mitigation for those vulnerabilities, as if they are not mitigated at all.
            # But we decided to trust AWS and assume it's not vulnerable.
            vulns += ['spec_store_bypass', 'mds']
        for name in vulns:
            status_file = sys_vulnerabilities / name
            if status_file.is_file():
                # If CPU is not prone to this vulnerability the status file will start with
                # 'Not affected' or 'Mitigation: ...'. Otherwise it will start with 'Vulnerable: ...'.
                if status_file.read_text().startswith('Vulnerable'):
                    vulnerable = True
                    break
            else:
                # Status file does not exist: smth is bind-mounted over it or the kernel is not completely patched.
                vulnerable = None
                break

    res['vulnerable'] = vulnerable

    # If we can't confidently tell if CPU is vulnerable we search cmdline for mitigation disablement params and let
    # the server do the rest.
    if vulnerable is None:
        mitigations_disabled = False
        mitigation_cmdline_params = {
            'nopti': '',
            'nospectre_v1': '',
            'nospectre_v2': '',
            'mds': 'off',
            'pti': 'off',
            'mitigations': 'off',
            'spectre_v2': 'off',
            'spectre_v2_user': '******',
            'spec_store_bypass_disable': 'off'
        }
        cmdline = kernel_cmdline()
        for pname, pvalue in mitigation_cmdline_params.items():
            if cmdline.get(pname) == pvalue:
                mitigations_disabled = True
                break
        res['mitigations_disabled'] = mitigations_disabled

    return res
Ejemplo n.º 2
0
 def ui_command_lscpu(self):
     """ lscpu - CPU architecture information helper. """
     print sh.lscpu()