From 1a668189703f5063ab96e3a4ba79ced9158f6be2 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Mon, 31 Jan 2022 16:57:10 -0600 Subject: [PATCH] Add new plugin for AMD PSP This plugin reads in values exported by the PSP on supported AMD SOCs to calculate the system state based on this information --- contrib/fwupd.spec.in | 1 + plugins/meson.build | 1 + plugins/pci-psp/README.md | 16 ++ plugins/pci-psp/fu-plugin-pci-psp.c | 278 ++++++++++++++++++++++++++++ plugins/pci-psp/meson.build | 31 ++++ plugins/pci-psp/pci-psp.quirk | 2 + 6 files changed, 329 insertions(+) create mode 100644 plugins/pci-psp/README.md create mode 100644 plugins/pci-psp/fu-plugin-pci-psp.c create mode 100644 plugins/pci-psp/meson.build create mode 100644 plugins/pci-psp/pci-psp.quirk diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index e26013a44..c62f94359 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -455,6 +455,7 @@ done %{_libdir}/fwupd-plugins-%{fwupdplugin_version}/libfu_plugin_acpi_dmar.so %{_libdir}/fwupd-plugins-%{fwupdplugin_version}/libfu_plugin_acpi_ivrs.so %{_libdir}/fwupd-plugins-%{fwupdplugin_version}/libfu_plugin_msr.so +%{_libdir}/fwupd-plugins-%{fwupdplugin_version}/libfu_plugin_pci_psp.so %endif %{_libdir}/fwupd-plugins-%{fwupdplugin_version}/libfu_plugin_mtd.so %{_libdir}/fwupd-plugins-%{fwupdplugin_version}/libfu_plugin_nitrokey.so diff --git a/plugins/meson.build b/plugins/meson.build index fb1723259..e02323f90 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -66,6 +66,7 @@ subdir('optionrom') subdir('parade-lspcon') subdir('pci-bcr') subdir('pci-mei') +subdir('pci-psp') subdir('pixart-rf') subdir('platform-integrity') subdir('powerd') diff --git a/plugins/pci-psp/README.md b/plugins/pci-psp/README.md new file mode 100644 index 000000000..e2956a8ee --- /dev/null +++ b/plugins/pci-psp/README.md @@ -0,0 +1,16 @@ +# PCI PSP + +## Introduction + +This plugin checks all information reported from the AMD Platform Security processor into +the operating system on select SOCs. + +The lack of these sysfs files does *NOT* indicate the lack of these security features, it only +indicates the lack of the ability to export it to the operating system. + +The availability of the sysfs files indicates that the PSP supports exporting this information +into the operating system. + +## External Interface Access + +This plugin requires read only access to attributes located within `/sys/bus/pci/devices/`. diff --git a/plugins/pci-psp/fu-plugin-pci-psp.c b/plugins/pci-psp/fu-plugin-pci-psp.c new file mode 100644 index 000000000..0295744e0 --- /dev/null +++ b/plugins/pci-psp/fu-plugin-pci-psp.c @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2022 Advanced Micro Devices Inc. + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +static void +fu_plugin_pci_psp_init(FuPlugin *plugin) +{ + fu_plugin_add_udev_subsystem(plugin, "pci"); +} + +static gboolean +fu_plugin_pci_psp_backend_device_added(FuPlugin *plugin, FuDevice *device, GError **error) +{ + /* interesting device? */ + if (!FU_IS_UDEV_DEVICE(device)) + return TRUE; + if (g_strcmp0(fu_udev_device_get_subsystem(FU_UDEV_DEVICE(device)), "pci") != 0) + return TRUE; + + fu_plugin_cache_add(plugin, "pci-psp-device", device); + + return TRUE; +} + +static gboolean +fu_plugin_pci_psp_get_attr(FwupdSecurityAttr *attr, + const gchar *path, + const gchar *file, + gboolean *out, + GError **error) +{ + g_autofree gchar *fn = g_build_filename(path, file, NULL); + g_autofree gchar *buf = NULL; + gsize bufsz = 0; + + if (!g_file_get_contents(fn, &buf, &bufsz, error)) { + g_prefix_error(error, "could not open %s: ", fn); + fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_MISSING_DATA); + return FALSE; + } + *out = fu_common_strtoull(buf) ? TRUE : FALSE; + + return TRUE; +} + +static void +fu_plugin_add_security_attrs_tsme(const gchar *path, FuSecurityAttrs *attrs) +{ + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GError) error_local = NULL; + gboolean val; + + attr = fwupd_security_attr_new(FWUPD_SECURITY_ATTR_ID_ENCRYPTED_RAM); + fwupd_security_attr_set_plugin(attr, "pci_psp"); + fwupd_security_attr_set_level(attr, FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_PROTECTION); + fu_security_attrs_append(attrs, attr); + + if (!fu_plugin_pci_psp_get_attr(attr, path, "tsme_status", &val, &error_local)) { + g_debug("%s", error_local->message); + return; + } + + if (val) + fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_ENCRYPTED); + + /* success */ + fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); +} + +static void +fu_plugin_add_security_attrs_fused_part(const gchar *path, FuSecurityAttrs *attrs) +{ + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GError) error_local = NULL; + gboolean val; + + attr = fwupd_security_attr_new(FWUPD_SECURITY_ATTR_ID_PLATFORM_FUSED); + fwupd_security_attr_set_plugin(attr, "pci_psp"); + fwupd_security_attr_set_level(attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fu_security_attrs_append(attrs, attr); + + if (!fu_plugin_pci_psp_get_attr(attr, path, "fused_part", &val, &error_local)) { + g_debug("%s", error_local->message); + return; + } + + if (!val) { + g_debug("part is not fused"); + fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED); + return; + } + + /* success */ + fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_LOCKED); + fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); +} + +static void +fu_plugin_add_security_attrs_debug_locked_part(const gchar *path, FuSecurityAttrs *attrs) +{ + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GError) error_local = NULL; + gboolean val; + + attr = fwupd_security_attr_new(FWUPD_SECURITY_ATTR_ID_PLATFORM_DEBUG_LOCKED); + fwupd_security_attr_set_plugin(attr, "pci_psp"); + fwupd_security_attr_set_level(attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT); + fu_security_attrs_append(attrs, attr); + + if (!fu_plugin_pci_psp_get_attr(attr, path, "debug_lock_on", &val, &error_local)) { + g_debug("%s", error_local->message); + return; + } + + if (!val) { + g_debug("debug lock disabled"); + fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED); + return; + } + + /* success */ + fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_LOCKED); + fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); +} + +static void +fu_plugin_add_security_attrs_rollback_protection(const gchar *path, FuSecurityAttrs *attrs) +{ + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GError) error_local = NULL; + gboolean val; + + attr = fwupd_security_attr_new(FWUPD_SECURITY_ATTR_ID_AMD_ROLLBACK_PROTECTION); + fwupd_security_attr_set_plugin(attr, "pci_psp"); + fwupd_security_attr_set_level(attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fu_security_attrs_append(attrs, attr); + + if (!fu_plugin_pci_psp_get_attr(attr, path, "anti_rollback_status", &val, &error_local)) { + g_debug("%s", error_local->message); + return; + } + + if (!val) { + g_debug("rollback protection not enforced"); + fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); + return; + } + + fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); + fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); +} + +static void +fu_plugin_add_security_attrs_rom_armor(const gchar *path, FuSecurityAttrs *attrs) +{ + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GError) error_local = NULL; + gboolean val; + + /* create attr */ + attr = fwupd_security_attr_new(FWUPD_SECURITY_ATTR_ID_AMD_SPI_WRITE_PROTECTION); + fwupd_security_attr_set_plugin(attr, "pci_psp"); + fwupd_security_attr_set_level(attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT); + fu_security_attrs_append(attrs, attr); + + if (!fu_plugin_pci_psp_get_attr(attr, path, "rom_armor_enforced", &val, &error_local)) { + g_debug("%s", error_local->message); + return; + } + + if (!val) { + g_debug("ROM armor not enforced"); + fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); + return; + } + + /* success */ + fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); + fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); +} + +static void +fu_plugin_add_security_attrs_rpmc(const gchar *path, FuSecurityAttrs *attrs) +{ + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GError) error_local = NULL; + gboolean val; + + /* create attr */ + attr = fwupd_security_attr_new(FWUPD_SECURITY_ATTR_ID_AMD_SPI_REPLAY_PROTECTION); + fwupd_security_attr_set_plugin(attr, "pci_psp"); + fwupd_security_attr_set_level(attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL); + fu_security_attrs_append(attrs, attr); + + if (!fu_plugin_pci_psp_get_attr(attr, path, "rpmc_spirom_available", &val, &error_local)) { + g_debug("%s", error_local->message); + return; + } + + if (!val) { + g_debug("no RPMC compatible SPI rom present"); + fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED); + return; + } + + if (!fu_plugin_pci_psp_get_attr(attr, + path, + "rpmc_production_enabled", + &val, + &error_local)) { + g_debug("%s", error_local->message); + return; + } + + if (!val) { + g_debug("no RPMC compatible SPI rom present"); + fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED); + return; + } + + /* success */ + fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED); + fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); +} + +static void +fu_plugin_pci_psp_set_missing_data(FuSecurityAttrs *attrs) +{ + g_autoptr(FwupdSecurityAttr) attr = NULL; + + attr = fwupd_security_attr_new(FWUPD_SECURITY_ATTR_ID_SUPPORTED_CPU); + fwupd_security_attr_set_plugin(attr, "pci_psp"); + fwupd_security_attr_set_level(attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_add_obsolete(attr, "cpu"); + fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_MISSING_DATA); + fu_security_attrs_append(attrs, attr); +} + +static void +fu_plugin_pci_psp_add_security_attrs(FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuDevice *psp_device = fu_plugin_cache_lookup(plugin, "pci-psp-device"); + const gchar *sysfs_path = NULL; + + /* only AMD */ + if (fu_common_get_cpu_vendor() != FU_CPU_VENDOR_AMD) + return; + + /* ccp not loaded */ + if (psp_device) + sysfs_path = fu_udev_device_get_sysfs_path(FU_UDEV_DEVICE(psp_device)); + if (sysfs_path == NULL) { + fu_plugin_pci_psp_set_missing_data(attrs); + return; + } + + fu_plugin_add_security_attrs_tsme(sysfs_path, attrs); + fu_plugin_add_security_attrs_fused_part(sysfs_path, attrs); + fu_plugin_add_security_attrs_debug_locked_part(sysfs_path, attrs); + fu_plugin_add_security_attrs_rollback_protection(sysfs_path, attrs); + fu_plugin_add_security_attrs_rpmc(sysfs_path, attrs); + fu_plugin_add_security_attrs_rom_armor(sysfs_path, attrs); +} + +void +fu_plugin_init_vfuncs(FuPluginVfuncs *vfuncs) +{ + vfuncs->build_hash = FU_BUILD_HASH; + vfuncs->init = fu_plugin_pci_psp_init; + vfuncs->add_security_attrs = fu_plugin_pci_psp_add_security_attrs; + vfuncs->backend_device_added = fu_plugin_pci_psp_backend_device_added; +} diff --git a/plugins/pci-psp/meson.build b/plugins/pci-psp/meson.build new file mode 100644 index 000000000..2b34ea281 --- /dev/null +++ b/plugins/pci-psp/meson.build @@ -0,0 +1,31 @@ +if get_option('hsi') and \ + host_machine.system() == 'linux' and \ + host_cpu == 'x86_64' +cargs = ['-DG_LOG_DOMAIN="FuPluginPciPsp"'] + +install_data(['pci-psp.quirk'], + install_dir: join_paths(datadir, 'fwupd', 'quirks.d') +) + +shared_module('fu_plugin_pci_psp', + fu_hash, + sources : [ + 'fu-plugin-pci-psp.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + install : true, + install_dir: plugin_dir, + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + dependencies : [ + plugin_deps, + ], +) +endif diff --git a/plugins/pci-psp/pci-psp.quirk b/plugins/pci-psp/pci-psp.quirk new file mode 100644 index 000000000..1f0709d33 --- /dev/null +++ b/plugins/pci-psp/pci-psp.quirk @@ -0,0 +1,2 @@ +[PCI\DRIVER_ccp] +Plugin = pci_psp