diff --git a/contrib/fwupd.spec.in b/contrib/fwupd.spec.in index b4a2bfb29..78f3777f8 100644 --- a/contrib/fwupd.spec.in +++ b/contrib/fwupd.spec.in @@ -329,6 +329,8 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg /usr/lib/udev/rules.d/*.rules /usr/lib/systemd/system-shutdown/fwupd.shutdown %dir %{_libdir}/fwupd-plugins-3 +%{_libdir}/fwupd-plugins-3/libfu_plugin_acpi_dmar.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_acpi_facp.so %{_libdir}/fwupd-plugins-3/libfu_plugin_altos.so %{_libdir}/fwupd-plugins-3/libfu_plugin_amt.so %{_libdir}/fwupd-plugins-3/libfu_plugin_ata.so @@ -352,7 +354,11 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg %endif %{_libdir}/fwupd-plugins-3/libfu_plugin_fresco_pd.so %{_libdir}/fwupd-plugins-3/libfu_plugin_jabra.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_linux_lockdown.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_linux_sleep.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_linux_spi_lpc.so %{_libdir}/fwupd-plugins-3/libfu_plugin_linux_swap.so +%{_libdir}/fwupd-plugins-3/libfu_plugin_linux_tainted.so %if 0%{?have_modem_manager} %{_libdir}/fwupd-plugins-3/libfu_plugin_modem_manager.so %endif diff --git a/plugins/acpi-dmar/README.md b/plugins/acpi-dmar/README.md new file mode 100644 index 000000000..da544cb50 --- /dev/null +++ b/plugins/acpi-dmar/README.md @@ -0,0 +1,8 @@ +DMA Protection +============== + +Introduction +------------ + +This plugin checks if DMA remapping for Thunderbolt devices is available. The +result will be stored in an security attribute for HSI. diff --git a/plugins/acpi-dmar/fu-acpi-dmar.c b/plugins/acpi-dmar/fu-acpi-dmar.c new file mode 100644 index 000000000..e972d0e65 --- /dev/null +++ b/plugins/acpi-dmar/fu-acpi-dmar.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" +#include "fu-acpi-dmar.h" + +struct _FuAcpiDmar { + GObject parent_instance; + gboolean opt_in; +}; + +G_DEFINE_TYPE (FuAcpiDmar, fu_acpi_dmar, G_TYPE_OBJECT) + +#define DMAR_DMA_CTRL_PLATFORM_OPT_IN_FLAG 2 + +FuAcpiDmar * +fu_acpi_dmar_new (GBytes *blob, GError **error) +{ + FuAcpiDmar *self = g_object_new (FU_TYPE_ACPI_DMAR, NULL); + gchar creator_id[5] = { '\0' }; + gchar oem_table_id[9] = { '\0' }; + gchar signature[5] = { '\0' }; + gsize bufsz = 0; + guint8 flags = 0; + const guint8 *buf = g_bytes_get_data (blob, &bufsz); + + /* parse table */ + if (!fu_memcpy_safe ((guint8 *) signature, sizeof(signature), 0x0, /* dst */ + buf, bufsz, 0x00, /* src */ + sizeof(signature) - 1, error)) + return FALSE; + if (strcmp (signature, "DMAR") != 0) { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + "Not a DMAR table, got %s", + signature); + return FALSE; + } + if (!fu_memcpy_safe ((guint8 *) oem_table_id, sizeof(oem_table_id), 0x0,/* dst */ + buf, bufsz, 0x10, /* src */ + sizeof(oem_table_id) - 1, error)) + return FALSE; + g_debug ("OemTableId: %s", oem_table_id); + if (!fu_memcpy_safe ((guint8 *) creator_id, sizeof(creator_id), 0x0, /* dst */ + buf, bufsz, 0x1c, /* src */ + sizeof(creator_id) - 1, error)) + return FALSE; + g_debug ("CreatorId: %s", creator_id); + if (!fu_memcpy_safe (&flags, sizeof(flags), 0x0, /* dst */ + buf, bufsz, 0x25, /* src */ + sizeof(flags), error)) + return FALSE; + g_debug ("Flags: 0x%02x", flags); + self->opt_in = (flags & DMAR_DMA_CTRL_PLATFORM_OPT_IN_FLAG) > 0; + return self; +} + +gboolean +fu_acpi_dmar_get_opt_in (FuAcpiDmar *self) +{ + g_return_val_if_fail (FU_IS_ACPI_DMAR (self), FALSE); + return self->opt_in; +} + +static void +fu_acpi_dmar_class_init (FuAcpiDmarClass *klass) +{ +} + +static void +fu_acpi_dmar_init (FuAcpiDmar *self) +{ +} diff --git a/plugins/acpi-dmar/fu-acpi-dmar.h b/plugins/acpi-dmar/fu-acpi-dmar.h new file mode 100644 index 000000000..57dcc0f8e --- /dev/null +++ b/plugins/acpi-dmar/fu-acpi-dmar.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#define FU_TYPE_ACPI_DMAR (fu_acpi_dmar_get_type ()) +G_DECLARE_FINAL_TYPE (FuAcpiDmar, fu_acpi_dmar, FU, ACPI_DMAR, GObject) + +FuAcpiDmar *fu_acpi_dmar_new (GBytes *blob, + GError **error); +gboolean fu_acpi_dmar_get_opt_in (FuAcpiDmar *self); diff --git a/plugins/acpi-dmar/fu-plugin-acpi-dmar.c b/plugins/acpi-dmar/fu-plugin-acpi-dmar.c new file mode 100644 index 000000000..02b42e330 --- /dev/null +++ b/plugins/acpi-dmar/fu-plugin-acpi-dmar.c @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" +#include "fu-hash.h" +#include "fu-acpi-dmar.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + g_autofree gchar *fn = NULL; + g_autofree gchar *path = NULL; + g_autoptr(FuAcpiDmar) dmar = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GBytes) blob = NULL; + g_autoptr(GError) error_local = NULL; + + /* only Intel */ + if (!fu_common_is_cpu_intel ()) + return; + + /* create attr */ + attr = fwupd_security_attr_new ("org.uefi.ACPI.Dmar"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL); + fwupd_security_attr_set_name (attr, "Pre-boot kernel DMA protection"); + fu_security_attrs_append (attrs, attr); + + /* load DMAR table */ + path = fu_common_get_path (FU_PATH_KIND_ACPI_TABLES); + fn = g_build_filename (path, "DMAR", NULL); + blob = fu_common_get_contents_bytes (fn, &error_local); + if (blob == NULL) { + g_warning ("failed to load %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, "Could not load DMAR"); + return; + } + dmar = fu_acpi_dmar_new (blob, &error_local); + if (dmar == NULL) { + g_warning ("failed to parse %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, "Could not parse DMAR"); + return; + } + if (!fu_acpi_dmar_get_opt_in (dmar)) { + fwupd_security_attr_set_result (attr, "Unavailable"); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); +} diff --git a/plugins/acpi-dmar/fu-self-test.c b/plugins/acpi-dmar/fu-self-test.c new file mode 100644 index 000000000..aa9bf7f2a --- /dev/null +++ b/plugins/acpi-dmar/fu-self-test.c @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" + +#include "fu-acpi-dmar.h" + +static void +fu_acpi_dmar_opt_in_func (void) +{ + g_autoptr(FuAcpiDmar) dmar = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GBytes) blob = NULL; + g_autofree gchar *fn = NULL; + + fn = g_build_filename (TESTDATADIR, "DMAR", NULL); + blob = fu_common_get_contents_bytes (fn, &error); + g_assert_no_error (error); + g_assert_nonnull (blob); + dmar = fu_acpi_dmar_new (blob, &error); + g_assert_no_error (error); + g_assert_nonnull (dmar); + g_assert_true (fu_acpi_dmar_get_opt_in (dmar)); +} + +static void +fu_acpi_dmar_opt_out_func (void) +{ + g_autoptr(FuAcpiDmar) dmar = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GBytes) blob = NULL; + g_autofree gchar *fn = NULL; + + fn = g_build_filename (TESTDATADIR, "DMAR-OPTOUT", NULL); + blob = fu_common_get_contents_bytes (fn, &error); + g_assert_no_error (error); + g_assert_nonnull (blob); + dmar = fu_acpi_dmar_new (blob, &error); + g_assert_no_error (error); + g_assert_nonnull (dmar); + g_assert_false (fu_acpi_dmar_get_opt_in (dmar)); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + /* only critical and error are fatal */ + g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); + g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); + + /* tests go here */ + g_test_add_func ("/acpi-dmar/opt-in", fu_acpi_dmar_opt_in_func); + g_test_add_func ("/acpi-dmar/opt-out", fu_acpi_dmar_opt_out_func); + + return g_test_run (); +} diff --git a/plugins/acpi-dmar/meson.build b/plugins/acpi-dmar/meson.build new file mode 100644 index 000000000..95df341ee --- /dev/null +++ b/plugins/acpi-dmar/meson.build @@ -0,0 +1,51 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginAcpiDmar"'] + +shared_module('fu_plugin_acpi_dmar', + fu_hash, + sources : [ + 'fu-plugin-acpi-dmar.c', + 'fu-acpi-dmar.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, + ], +) + +if get_option('tests') + testdatadir = join_paths(meson.current_source_dir(), 'tests') + cargs += '-DTESTDATADIR="' + testdatadir + '"' + e = executable( + 'acpi-dmar-self-test', + fu_hash, + sources : [ + 'fu-self-test.c', + 'fu-acpi-dmar.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + dependencies : [ + plugin_deps, + ], + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + ) + test('acpi-dmar-self-test', e) +endif diff --git a/plugins/acpi-dmar/tests/DMAR b/plugins/acpi-dmar/tests/DMAR new file mode 100644 index 000000000..0a64fc85e Binary files /dev/null and b/plugins/acpi-dmar/tests/DMAR differ diff --git a/plugins/acpi-dmar/tests/DMAR-OPTOUT b/plugins/acpi-dmar/tests/DMAR-OPTOUT new file mode 100644 index 000000000..d55cec2df Binary files /dev/null and b/plugins/acpi-dmar/tests/DMAR-OPTOUT differ diff --git a/plugins/acpi-facp/README.md b/plugins/acpi-facp/README.md new file mode 100644 index 000000000..5a4bd120d --- /dev/null +++ b/plugins/acpi-facp/README.md @@ -0,0 +1,8 @@ +ACPI FACP +========= + +Introduction +------------ + +This plugin checks if S2I sleep is available. The result will be stored in an +security attribute for HSI. diff --git a/plugins/acpi-facp/fu-acpi-facp.c b/plugins/acpi-facp/fu-acpi-facp.c new file mode 100644 index 000000000..0adc47271 --- /dev/null +++ b/plugins/acpi-facp/fu-acpi-facp.c @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" +#include "fu-acpi-facp.h" + +struct _FuAcpiFacp { + GObject parent_instance; + gboolean get_s2i; +}; + +G_DEFINE_TYPE (FuAcpiFacp, fu_acpi_facp, G_TYPE_OBJECT) + +#define LOW_POWER_S0_IDLE_CAPABLE (1 << 21) + +FuAcpiFacp * +fu_acpi_facp_new (GBytes *blob, GError **error) +{ + FuAcpiFacp *self = g_object_new (FU_TYPE_ACPI_FACP, NULL); + gsize bufsz = 0; + guint32 flags = 0; + const guint8 *buf = g_bytes_get_data (blob, &bufsz); + + /* parse table */ + if (!fu_common_read_uint32_safe (buf, bufsz, 0x70, &flags, G_LITTLE_ENDIAN, error)) + return FALSE; + g_debug ("Flags: 0x%04x", flags); + self->get_s2i = (flags & LOW_POWER_S0_IDLE_CAPABLE) > 0; + return self; +} + +gboolean +fu_acpi_facp_get_s2i (FuAcpiFacp *self) +{ + g_return_val_if_fail (FU_IS_ACPI_FACP (self), FALSE); + return self->get_s2i; +} + +static void +fu_acpi_facp_class_init (FuAcpiFacpClass *klass) +{ +} + +static void +fu_acpi_facp_init (FuAcpiFacp *self) +{ +} diff --git a/plugins/acpi-facp/fu-acpi-facp.h b/plugins/acpi-facp/fu-acpi-facp.h new file mode 100644 index 000000000..f143c233c --- /dev/null +++ b/plugins/acpi-facp/fu-acpi-facp.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#pragma once + +#include + +#define FU_TYPE_ACPI_FACP (fu_acpi_facp_get_type ()) +G_DECLARE_FINAL_TYPE (FuAcpiFacp, fu_acpi_facp, FU, ACPI_FACP, GObject) + +FuAcpiFacp *fu_acpi_facp_new (GBytes *blob, + GError **error); +gboolean fu_acpi_facp_get_s2i (FuAcpiFacp *self); diff --git a/plugins/acpi-facp/fu-plugin-acpi-facp.c b/plugins/acpi-facp/fu-plugin-acpi-facp.c new file mode 100644 index 000000000..2575a5802 --- /dev/null +++ b/plugins/acpi-facp/fu-plugin-acpi-facp.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" +#include "fu-hash.h" +#include "fu-acpi-facp.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + g_autofree gchar *fn = NULL; + g_autofree gchar *path = NULL; + g_autoptr(FuAcpiFacp) facp = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GBytes) blob = NULL; + g_autoptr(GError) error_local = NULL; + + /* create attr */ + attr = fwupd_security_attr_new ("org.uefi.ACPI.Facp"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL); + fwupd_security_attr_set_name (attr, "Suspend2Idle"); + fu_security_attrs_append (attrs, attr); + + /* load FACP table */ + path = fu_common_get_path (FU_PATH_KIND_ACPI_TABLES); + fn = g_build_filename (path, "FACP", NULL); + blob = fu_common_get_contents_bytes (fn, &error_local); + if (blob == NULL) { + g_warning ("failed to load %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, "Could not load FACP"); + return; + } + facp = fu_acpi_facp_new (blob, &error_local); + if (facp == NULL) { + g_warning ("failed to parse %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, "Could not parse FACP"); + return; + } + if (!fu_acpi_facp_get_s2i (facp)) { + fwupd_security_attr_set_result (attr, "Default set as suspend-to-ram (S3)"); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); +} diff --git a/plugins/acpi-facp/fu-self-test.c b/plugins/acpi-facp/fu-self-test.c new file mode 100644 index 000000000..2fd4ca43e --- /dev/null +++ b/plugins/acpi-facp/fu-self-test.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include + +#include "fu-common.h" + +#include "fu-acpi-facp.h" + +static void +fu_acpi_facp_s2i_disabled_func (void) +{ + g_autofree gchar *fn = NULL; + g_autoptr(FuAcpiFacp) facp = NULL; + g_autoptr(GBytes) blob = NULL; + g_autoptr(GError) error = NULL; + + fn = g_build_filename (TESTDATADIR, "FACP", NULL); + blob = fu_common_get_contents_bytes (fn, &error); + g_assert_no_error (error); + g_assert_nonnull (blob); + facp = fu_acpi_facp_new (blob, &error); + g_assert_no_error (error); + g_assert_nonnull (facp); + g_assert_false (fu_acpi_facp_get_s2i (facp)); +} + +static void +fu_acpi_facp_s2i_enabled_func (void) +{ + g_autofree gchar *fn = NULL; + g_autoptr(FuAcpiFacp) facp = NULL; + g_autoptr(GBytes) blob = NULL; + g_autoptr(GError) error = NULL; + + fn = g_build_filename (TESTDATADIR, "FACP-S2I", NULL); + blob = fu_common_get_contents_bytes (fn, &error); + g_assert_no_error (error); + g_assert_nonnull (blob); + facp = fu_acpi_facp_new (blob, &error); + g_assert_no_error (error); + g_assert_nonnull (facp); + g_assert_true (fu_acpi_facp_get_s2i (facp)); +} + +int +main (int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + /* only critical and error are fatal */ + g_log_set_fatal_mask (NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL); + g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); + + /* tests go here */ + g_test_add_func ("/acpi-facp/s2i{disabled}", fu_acpi_facp_s2i_disabled_func); + g_test_add_func ("/acpi-facp/s2i{enabled}", fu_acpi_facp_s2i_enabled_func); + return g_test_run (); +} diff --git a/plugins/acpi-facp/meson.build b/plugins/acpi-facp/meson.build new file mode 100644 index 000000000..9a3c96a25 --- /dev/null +++ b/plugins/acpi-facp/meson.build @@ -0,0 +1,51 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginAcpiFacp"'] + +shared_module('fu_plugin_acpi_facp', + fu_hash, + sources : [ + 'fu-plugin-acpi-facp.c', + 'fu-acpi-facp.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, + ], +) + +if get_option('tests') + testdatadir = join_paths(meson.current_source_dir(), 'tests') + cargs += '-DTESTDATADIR="' + testdatadir + '"' + e = executable( + 'acpi-facp-self-test', + fu_hash, + sources : [ + 'fu-self-test.c', + 'fu-acpi-facp.c', + ], + include_directories : [ + root_incdir, + fwupd_incdir, + fwupdplugin_incdir, + ], + dependencies : [ + plugin_deps, + ], + link_with : [ + fwupd, + fwupdplugin, + ], + c_args : cargs, + ) + test('acpi-facp-self-test', e) +endif diff --git a/plugins/acpi-facp/tests/FACP b/plugins/acpi-facp/tests/FACP new file mode 100644 index 000000000..e438f978c Binary files /dev/null and b/plugins/acpi-facp/tests/FACP differ diff --git a/plugins/acpi-facp/tests/FACP-S2I b/plugins/acpi-facp/tests/FACP-S2I new file mode 100644 index 000000000..6ee6211d2 Binary files /dev/null and b/plugins/acpi-facp/tests/FACP-S2I differ diff --git a/plugins/cpu/fu-plugin-cpu.c b/plugins/cpu/fu-plugin-cpu.c index 43e58e12d..d62a3e5e4 100644 --- a/plugins/cpu/fu-plugin-cpu.c +++ b/plugins/cpu/fu-plugin-cpu.c @@ -10,23 +10,29 @@ #include "fu-hash.h" #include "fu-cpu-device.h" +struct FuPluginData { + gboolean has_cet; +}; + void fu_plugin_init (FuPlugin *plugin) { fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); + fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); } gboolean fu_plugin_coldplug (FuPlugin *plugin, GError **error) { + FuPluginData *data = fu_plugin_get_data (plugin); gsize length; - g_autofree gchar *data = NULL; + g_autofree gchar *buf = NULL; g_auto(GStrv) lines = NULL; - if (!g_file_get_contents ("/proc/cpuinfo", &data, &length, error)) + if (!g_file_get_contents ("/proc/cpuinfo", &buf, &length, error)) return FALSE; - lines = g_strsplit (data, "\n\n", 0); + lines = g_strsplit (buf, "\n\n", 0); for (guint i = 0; lines[i] != NULL; i++) { g_autoptr(FuCpuDevice) dev = NULL; if (strlen (lines[i]) == 0) @@ -34,8 +40,36 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error) dev = fu_cpu_device_new (lines[i]); if (!fu_device_setup (FU_DEVICE (dev), error)) return FALSE; + if (fu_cpu_device_has_shstk (dev) && + fu_cpu_device_has_ibt (dev)) + data->has_cet = TRUE; fu_plugin_device_add (plugin, FU_DEVICE (dev)); } return TRUE; } + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* only Intel */ + if (!fu_common_is_cpu_intel ()) + return; + + /* create attr */ + attr = fwupd_security_attr_new ("com.intel.CET"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_PROTECTION); + fwupd_security_attr_set_name (attr, "Intel CET"); + fu_security_attrs_append (attrs, attr); + + /* check for CET */ + if (!data->has_cet) { + fwupd_security_attr_set_result (attr, "Unavailable"); + return; + } + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, "SHSTK+IBT"); +} diff --git a/plugins/linux-lockdown/README.md b/plugins/linux-lockdown/README.md new file mode 100644 index 000000000..0cd58d6b9 --- /dev/null +++ b/plugins/linux-lockdown/README.md @@ -0,0 +1,8 @@ +Linux Kernel Lockdown +===================== + +Introduction +------------ + +This plugin checks if the currently running kernel is locked down. The result +will be stored in an security attribute for HSI. diff --git a/plugins/linux-lockdown/fu-plugin-linux-lockdown.c b/plugins/linux-lockdown/fu-plugin-linux-lockdown.c new file mode 100644 index 000000000..ed00e63fc --- /dev/null +++ b/plugins/linux-lockdown/fu-plugin-linux-lockdown.c @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" +#include "fu-hash.h" + +struct FuPluginData { + GFile *file; + GFileMonitor *monitor; +}; + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + +void +fu_plugin_destroy (FuPlugin *plugin) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + if (data->file != NULL) + g_object_unref (data->file); + if (data->monitor != NULL) + g_object_unref (data->monitor); +} + +static void +fu_plugin_linux_lockdown_changed_cb (GFileMonitor *monitor, + GFile *file, + GFile *other_file, + GFileMonitorEvent event_type, + gpointer user_data) +{ + FuPlugin *plugin = FU_PLUGIN (user_data); + fu_plugin_security_changed (plugin); +} + +gboolean +fu_plugin_startup (FuPlugin *plugin, GError **error) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + g_autofree gchar *path = NULL; + g_autofree gchar *fn = NULL; + + path = fu_common_get_path (FU_PATH_KIND_SYSFSDIR_SECURITY); + fn = g_build_filename (path, "lockdown", NULL); + data->file = g_file_new_for_path (fn); + data->monitor = g_file_monitor (data->file, G_FILE_MONITOR_NONE, NULL, error); + if (data->monitor == NULL) + return FALSE; + g_signal_connect (data->monitor, "changed", + G_CALLBACK (fu_plugin_linux_lockdown_changed_cb), plugin); + return TRUE; +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + gsize bufsz = 0; + g_autofree gchar *buf = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GError) error_local = NULL; + + /* create attr */ + attr = fwupd_security_attr_new ("org.kernel.CheckLockdown"); + fwupd_security_attr_set_name (attr, "Linux Kernel"); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); + fu_security_attrs_append (attrs, attr); + + /* load file */ + if (!g_file_load_contents (data->file, NULL, &buf, &bufsz, NULL, &error_local)) { + g_autofree gchar *fn = g_file_get_path (data->file); + g_warning ("could not open %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, "Could not open file"); + return; + } + if (g_strstr_len (buf, bufsz, "[integrity]") == NULL && + g_strstr_len (buf, bufsz, "[confidentiality]") == NULL) { + fwupd_security_attr_set_result (attr, "Not locked down"); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, "Locked down"); +} diff --git a/plugins/linux-lockdown/meson.build b/plugins/linux-lockdown/meson.build new file mode 100644 index 000000000..82857848f --- /dev/null +++ b/plugins/linux-lockdown/meson.build @@ -0,0 +1,23 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginLinuxLockdown"'] + +shared_module('fu_plugin_linux_lockdown', + fu_hash, + sources : [ + 'fu-plugin-linux-lockdown.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, + ], +) diff --git a/plugins/linux-sleep/README.md b/plugins/linux-sleep/README.md new file mode 100644 index 000000000..b7864933e --- /dev/null +++ b/plugins/linux-sleep/README.md @@ -0,0 +1,8 @@ +Linux Kernel Sleep +================== + +Introduction +------------ + +This plugin checks if s3 sleep is available. The result will be stored in an +security attribute for HSI. diff --git a/plugins/linux-sleep/fu-plugin-linux-sleep.c b/plugins/linux-sleep/fu-plugin-linux-sleep.c new file mode 100644 index 000000000..c7f8793fa --- /dev/null +++ b/plugins/linux-sleep/fu-plugin-linux-sleep.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" +#include "fu-hash.h" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + gsize bufsz = 0; + g_autofree gchar *buf = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GError) error_local = NULL; + g_autoptr(GFile) file = g_file_new_for_path ("/sys/power/mem_sleep"); + + /* create attr */ + attr = fwupd_security_attr_new ("org.kernel.CheckS3Sleep"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL); + fwupd_security_attr_set_name (attr, "Linux Kernel S3 Sleep"); + fu_security_attrs_append (attrs, attr); + + /* load file */ + if (!g_file_load_contents (file, NULL, &buf, &bufsz, NULL, &error_local)) { + g_autofree gchar *fn = g_file_get_path (file); + g_warning ("could not open %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, "Deep sleep status unavailable"); + return; + } + if (g_strstr_len (buf, bufsz, "[deep]") != NULL) { + fwupd_security_attr_set_result (attr, "System configured to suspend-to-ram (S3)"); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); +} diff --git a/plugins/linux-sleep/meson.build b/plugins/linux-sleep/meson.build new file mode 100644 index 000000000..a1a288d3f --- /dev/null +++ b/plugins/linux-sleep/meson.build @@ -0,0 +1,23 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginLinuxSleep"'] + +shared_module('fu_plugin_linux_sleep', + fu_hash, + sources : [ + 'fu-plugin-linux-sleep.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, + ], +) diff --git a/plugins/linux-spi-lpc/README.md b/plugins/linux-spi-lpc/README.md new file mode 100644 index 000000000..04d1909b2 --- /dev/null +++ b/plugins/linux-spi-lpc/README.md @@ -0,0 +1,8 @@ +Linux SPI LPC +============= + +Introduction +------------ + +This plugin checks if the system SPI chip is locked. The result will be stored +in an security attribute for HSI. diff --git a/plugins/linux-spi-lpc/fu-plugin-linux-spi-lpc.c b/plugins/linux-spi-lpc/fu-plugin-linux-spi-lpc.c new file mode 100644 index 000000000..2ff323c2f --- /dev/null +++ b/plugins/linux-spi-lpc/fu-plugin-linux-spi-lpc.c @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + + +#include "fu-plugin-vfuncs.h" +#include "fu-hash.h" + +#define FU_PLUGIN_LINUX_SPI_LPC_SYSFS_DIR "/sys/kernel/security/spi" + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + +static void +fu_plugin_add_security_attr_bioswe (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + gsize bufsz = 0; + g_autofree gchar *buf = NULL; + g_autofree gchar *fn = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GError) error_local = NULL; + + /* create attr */ + attr = fwupd_security_attr_new ("org.kernel.BIOSWE"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_set_name (attr, "SPI"); + fu_security_attrs_append (attrs, attr); + + /* load file */ + fn = g_build_filename (FU_PLUGIN_LINUX_SPI_LPC_SYSFS_DIR, "bioswe", NULL); + if (!g_file_get_contents (fn, &buf, &bufsz, &error_local)) { + g_warning ("could not open %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, "Could not open file"); + return; + } + if (g_strcmp0 (buf, "0\n") != 0) { + fwupd_security_attr_set_result (attr, "Write enabled"); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, "Write disabled"); +} + +static void +fu_plugin_add_security_attr_ble (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + gsize bufsz = 0; + g_autofree gchar *buf = NULL; + g_autofree gchar *fn = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GError) error_local = NULL; + + /* create attr */ + attr = fwupd_security_attr_new ("org.kernel.BLE"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_set_name (attr, "SPI"); + fu_security_attrs_append (attrs, attr); + + /* load file */ + fn = g_build_filename (FU_PLUGIN_LINUX_SPI_LPC_SYSFS_DIR, "ble", NULL); + if (!g_file_get_contents (fn, &buf, &bufsz, &error_local)) { + g_warning ("could not open %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, "Could not open file"); + return; + } + if (g_strcmp0 (buf, "1\n") != 0) { + fwupd_security_attr_set_result (attr, "Lock disabled"); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, "Lock enabled"); +} + +static void +fu_plugin_add_security_attr_smm_bwp (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + gsize bufsz = 0; + g_autofree gchar *buf = NULL; + g_autofree gchar *fn = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GError) error_local = NULL; + + /* create attr */ + attr = fwupd_security_attr_new ("org.kernel.SMM_BWP"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_set_name (attr, "BIOS region of SPI"); + fu_security_attrs_append (attrs, attr); + + /* load file */ + fn = g_build_filename (FU_PLUGIN_LINUX_SPI_LPC_SYSFS_DIR, "smm_bwp", NULL); + if (!g_file_get_contents (fn, &buf, &bufsz, &error_local)) { + g_warning ("could not open %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, "Could not open file"); + return; + } + if (g_strcmp0 (buf, "1\n") != 0) { + fwupd_security_attr_set_result (attr, "Writable by OS"); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, "Writable only through BIOS"); +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + /* only Intel */ + if (!fu_common_is_cpu_intel ()) + return; + + /* maybe the kernel module does not exist */ + if (!g_file_test (FU_PLUGIN_LINUX_SPI_LPC_SYSFS_DIR, G_FILE_TEST_IS_DIR)) { + g_autoptr(FwupdSecurityAttr) attr = NULL; + attr = fwupd_security_attr_new ("org.kernel.BIOSWE"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_set_name (attr, "SPI"); + fwupd_security_attr_set_result (attr, "Kernel support not present"); + fu_security_attrs_append (attrs, attr); + return; + } + + /* look for the three files in sysfs */ + fu_plugin_add_security_attr_bioswe (plugin, attrs); + fu_plugin_add_security_attr_ble (plugin, attrs); + fu_plugin_add_security_attr_smm_bwp (plugin, attrs); +} diff --git a/plugins/linux-spi-lpc/meson.build b/plugins/linux-spi-lpc/meson.build new file mode 100644 index 000000000..cba7801bc --- /dev/null +++ b/plugins/linux-spi-lpc/meson.build @@ -0,0 +1,23 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginLinuxSpiLpc"'] + +shared_module('fu_plugin_linux_spi_lpc', + fu_hash, + sources : [ + 'fu-plugin-linux-spi-lpc.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, + ], +) diff --git a/plugins/linux-swap/README.md b/plugins/linux-swap/README.md index c4b49aa20..f7e28574a 100644 --- a/plugins/linux-swap/README.md +++ b/plugins/linux-swap/README.md @@ -5,4 +5,4 @@ Introduction ------------ This plugin checks if the currently available swap partitions and files are -all encrypted. +all encrypted. The result will be stored in an security attribute for HSI. diff --git a/plugins/linux-swap/fu-plugin-linux-swap.c b/plugins/linux-swap/fu-plugin-linux-swap.c index ed6e6a06a..646e3f00d 100644 --- a/plugins/linux-swap/fu-plugin-linux-swap.c +++ b/plugins/linux-swap/fu-plugin-linux-swap.c @@ -11,6 +11,7 @@ #include "fu-linux-swap.h" struct FuPluginData { + GFile *file; GFileMonitor *monitor; }; @@ -25,6 +26,8 @@ void fu_plugin_destroy (FuPlugin *plugin) { FuPluginData *data = fu_plugin_get_data (plugin); + if (data->file != NULL) + g_object_unref (data->file); if (data->monitor != NULL) g_object_unref (data->monitor); } @@ -36,41 +39,72 @@ fu_plugin_linux_swap_changed_cb (GFileMonitor *monitor, GFileMonitorEvent event_type, gpointer user_data) { - g_debug ("swap changed"); + FuPlugin *plugin = FU_PLUGIN (user_data); + fu_plugin_security_changed (plugin); } gboolean fu_plugin_startup (FuPlugin *plugin, GError **error) { FuPluginData *data = fu_plugin_get_data (plugin); - gsize bufsz = 0; - g_autofree gchar *buf = NULL; g_autofree gchar *fn = NULL; g_autofree gchar *procfs = NULL; - g_autoptr(FuLinuxSwap) swap = NULL; - g_autoptr(GFile) file = NULL; procfs = fu_common_get_path (FU_PATH_KIND_PROCFS); fn = g_build_filename (procfs, "swaps", NULL); - file = g_file_new_for_path (fn); - data->monitor = g_file_monitor (file, G_FILE_MONITOR_NONE, NULL, error); + data->file = g_file_new_for_path (fn); + data->monitor = g_file_monitor (data->file, G_FILE_MONITOR_NONE, NULL, error); if (data->monitor == NULL) return FALSE; g_signal_connect (data->monitor, "changed", G_CALLBACK (fu_plugin_linux_swap_changed_cb), plugin); - - /* load list of linux_swaps */ - if (!g_file_get_contents (fn, &buf, &bufsz, error)) { - g_prefix_error (error, "could not open %s: ", fn); - return FALSE; - } - swap = fu_linux_swap_new (buf, bufsz, error); - if (swap == NULL) { - g_prefix_error (error, "could not parse %s: ", fn); - return FALSE; - } - g_debug ("swap %s and %s", - fu_linux_swap_get_enabled (swap) ? "enabled" : "disabled", - fu_linux_swap_get_encrypted (swap) ? "encrypted" : "unencrypted"); return TRUE; } + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + gsize bufsz = 0; + g_autofree gchar *buf = NULL; + g_autoptr(FuLinuxSwap) swap = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GError) error_local = NULL; + + /* create attr */ + attr = fwupd_security_attr_new ("org.kernel.Swap"); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); + fwupd_security_attr_set_name (attr, "Linux Swap"); + fu_security_attrs_append (attrs, attr); + + /* load list of swaps */ + if (!g_file_load_contents (data->file, NULL, &buf, &bufsz, NULL, &error_local)) { + g_autofree gchar *fn = g_file_get_path (data->file); + g_warning ("could not open %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, "Could not open file"); + return; + } + swap = fu_linux_swap_new (buf, bufsz, &error_local); + if (swap == NULL) { + g_autofree gchar *fn = g_file_get_path (data->file); + g_warning ("could not parse %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, "Could not parse file"); + return; + } + + /* none configured */ + if (!fu_linux_swap_get_enabled (swap)) { + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + return; + } + + /* add security attribute */ + if (!fu_linux_swap_get_encrypted (swap)) { + fwupd_security_attr_set_result (attr, "Not encrypted"); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, "Encrypted"); +} diff --git a/plugins/linux-tainted/README.md b/plugins/linux-tainted/README.md new file mode 100644 index 000000000..3c1a72d71 --- /dev/null +++ b/plugins/linux-tainted/README.md @@ -0,0 +1,8 @@ +Linux Kernel Tainted +==================== + +Introduction +------------ + +This plugin checks if the currently running kernel is tainted. The result will +be stored in an security attribute for HSI. diff --git a/plugins/linux-tainted/fu-plugin-linux-tainted.c b/plugins/linux-tainted/fu-plugin-linux-tainted.c new file mode 100644 index 000000000..de543ee14 --- /dev/null +++ b/plugins/linux-tainted/fu-plugin-linux-tainted.c @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2020 Richard Hughes + * + * SPDX-License-Identifier: LGPL-2.1+ + */ + +#include "config.h" + +#include "fu-plugin-vfuncs.h" +#include "fu-hash.h" + +struct FuPluginData { + GFile *file; + GFileMonitor *monitor; +}; + +void +fu_plugin_init (FuPlugin *plugin) +{ + fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); + fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); +} + +void +fu_plugin_destroy (FuPlugin *plugin) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + if (data->file != NULL) + g_object_unref (data->file); + if (data->monitor != NULL) + g_object_unref (data->monitor); +} + +static void +fu_plugin_linux_tainted_changed_cb (GFileMonitor *monitor, + GFile *file, + GFile *other_file, + GFileMonitorEvent event_type, + gpointer user_data) +{ + FuPlugin *plugin = FU_PLUGIN (user_data); + fu_plugin_security_changed (plugin); +} + +gboolean +fu_plugin_startup (FuPlugin *plugin, GError **error) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + g_autofree gchar *fn = NULL; + g_autofree gchar *procfs = NULL; + + procfs = fu_common_get_path (FU_PATH_KIND_PROCFS); + fn = g_build_filename (procfs, "sys", "kernel", "tainted", NULL); + data->file = g_file_new_for_path (fn); + data->monitor = g_file_monitor (data->file, G_FILE_MONITOR_NONE, NULL, error); + if (data->monitor == NULL) + return FALSE; + g_signal_connect (data->monitor, "changed", + G_CALLBACK (fu_plugin_linux_tainted_changed_cb), plugin); + return TRUE; +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + gsize bufsz = 0; + g_autofree gchar *buf = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; + g_autoptr(GError) error_local = NULL; + + /* create attr */ + attr = fwupd_security_attr_new ("org.kernel.CheckTainted"); + fwupd_security_attr_set_name (attr, "Linux Kernel"); + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE); + fu_security_attrs_append (attrs, attr); + + /* load file */ + if (!g_file_load_contents (data->file, NULL, &buf, &bufsz, NULL, &error_local)) { + g_autofree gchar *fn = g_file_get_path (data->file); + g_warning ("could not open %s: %s", fn, error_local->message); + fwupd_security_attr_set_result (attr, "Could not open file"); + return; + } + if (g_strcmp0 (buf, "0\n") != 0) { + fwupd_security_attr_set_result (attr, "Tainted"); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); +} diff --git a/plugins/linux-tainted/meson.build b/plugins/linux-tainted/meson.build new file mode 100644 index 000000000..41d12a073 --- /dev/null +++ b/plugins/linux-tainted/meson.build @@ -0,0 +1,23 @@ +cargs = ['-DG_LOG_DOMAIN="FuPluginLinuxTainted"'] + +shared_module('fu_plugin_linux_tainted', + fu_hash, + sources : [ + 'fu-plugin-linux-tainted.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, + ], +) diff --git a/plugins/meson.build b/plugins/meson.build index f916228a6..f63e4f52a 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -1,3 +1,5 @@ +subdir('acpi-dmar') +subdir('acpi-facp') subdir('ccgx') subdir('cpu') subdir('dfu') @@ -7,7 +9,11 @@ subdir('ep963x') subdir('fastboot') subdir('fresco-pd') subdir('jabra') +subdir('linux-lockdown') +subdir('linux-sleep') +subdir('linux-spi-lpc') subdir('linux-swap') +subdir('linux-tainted') subdir('steelseries') subdir('dell-dock') subdir('nitrokey') diff --git a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c index 4fec2f1c6..442649353 100644 --- a/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c +++ b/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c @@ -131,16 +131,23 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) FuPluginData *data = fu_plugin_get_data (plugin); g_autoptr(FwupdSecurityAttr) attr = NULL; + /* create attr */ attr = fwupd_security_attr_new ("org.trustedcomputinggroup.TpmEventLog"); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT); fwupd_security_attr_set_name (attr, "TPM Reconstruction"); + fu_security_attrs_append (attrs, attr); + + /* check reconstructed to PCR0 */ if (!fu_plugin_get_enabled (plugin)) { fwupd_security_attr_set_result (attr, "No binary bios measurements available"); - } else if (data->reconstructed) { - fwupd_security_attr_set_result (attr, "Matched PCR0 reading"); - fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); - } else { - fwupd_security_attr_set_result (attr, "Did not match PCR0 reading"); + return; } - fu_security_attrs_append (attrs, attr); + if (!data->reconstructed) { + fwupd_security_attr_set_result (attr, "Did not match PCR0 reading"); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, "Matched PCR0 reading"); } diff --git a/plugins/tpm/fu-plugin-tpm.c b/plugins/tpm/fu-plugin-tpm.c index fec3842eb..918d2b86e 100644 --- a/plugins/tpm/fu-plugin-tpm.c +++ b/plugins/tpm/fu-plugin-tpm.c @@ -11,10 +11,52 @@ #include "fu-tpm-device.h" +struct FuPluginData { + gboolean has_tpm; + gboolean has_tpm_v20; +}; + void fu_plugin_init (FuPlugin *plugin) { + fu_plugin_alloc_data (plugin, sizeof (FuPluginData)); fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_add_udev_subsystem (plugin, "tpm"); fu_plugin_set_device_gtype (plugin, FU_TYPE_TPM_DEVICE); } + +void +fu_plugin_device_added (FuPlugin *plugin, FuDevice *dev) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + data->has_tpm = TRUE; + if (g_strcmp0 (fu_tpm_device_get_family (FU_TPM_DEVICE (dev)), "2.0") == 0) + data->has_tpm_v20 = TRUE; +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* create attr */ + attr = fwupd_security_attr_new ("org.trustedcomputinggroup.Tpm"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_set_name (attr, "TPM"); + fu_security_attrs_append (attrs, attr); + + /* check exists, and in v2.0 mode */ + if (!data->has_tpm) { + fwupd_security_attr_set_result (attr, "Not found"); + return; + } + if (!data->has_tpm_v20) { + fwupd_security_attr_set_result (attr, "Not in v2.0 mode"); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, "v2.0"); +} diff --git a/plugins/tpm/fu-tpm-device.c b/plugins/tpm/fu-tpm-device.c index fd3a95abd..90dde789e 100644 --- a/plugins/tpm/fu-tpm-device.c +++ b/plugins/tpm/fu-tpm-device.c @@ -12,6 +12,7 @@ struct _FuTpmDevice { FuUdevDevice parent_instance; + gchar *family; }; G_DEFINE_TYPE (FuTpmDevice, fu_tpm_device, FU_TYPE_UDEV_DEVICE) @@ -22,6 +23,12 @@ static void Esys_Finalize_autoptr_cleanup (ESYS_CONTEXT *esys_context) } G_DEFINE_AUTOPTR_CLEANUP_FUNC (ESYS_CONTEXT, Esys_Finalize_autoptr_cleanup) +const gchar * +fu_tpm_device_get_family (FuTpmDevice *self) +{ + return self->family; +} + static gboolean fu_tpm_device_probe (FuUdevDevice *device, GError **error) { @@ -134,6 +141,7 @@ fu_tpm_device_convert_manufacturer (const gchar *manufacturer) static gboolean fu_tpm_device_setup (FuDevice *device, GError **error) { + FuTpmDevice *self = FU_TPM_DEVICE (device); FwupdVersionFormat verfmt; TSS2_RC rc; const gchar *tmp; @@ -141,7 +149,6 @@ fu_tpm_device_setup (FuDevice *device, GError **error) guint32 version1 = 0; guint32 version2 = 0; guint64 version_raw; - g_autofree gchar *family = NULL; g_autofree gchar *id1 = NULL; g_autofree gchar *id2 = NULL; g_autofree gchar *id3 = NULL; @@ -171,8 +178,8 @@ fu_tpm_device_setup (FuDevice *device, GError **error) } /* lookup guaranteed details from TPM */ - family = fu_tpm_device_get_string (ctx, TPM2_PT_FAMILY_INDICATOR, error); - if (family == NULL) { + self->family = fu_tpm_device_get_string (ctx, TPM2_PT_FAMILY_INDICATOR, error); + if (self->family == NULL) { g_prefix_error (error, "failed to read TPM family"); return FALSE; } @@ -202,9 +209,9 @@ fu_tpm_device_setup (FuDevice *device, GError **error) fu_device_add_instance_id (device, id1); id2 = g_strdup_printf ("TPM\\VEN_%s&MOD_%s", manufacturer, model); fu_device_add_instance_id (device, id2); - id3 = g_strdup_printf ("TPM\\VEN_%s&DEV_%04X&VER_%s", manufacturer, tpm_type, family); + id3 = g_strdup_printf ("TPM\\VEN_%s&DEV_%04X&VER_%s", manufacturer, tpm_type, self->family); fu_device_add_instance_id (device, id3); - id4 = g_strdup_printf ("TPM\\VEN_%s&MOD_%s&VER_%s", manufacturer, model, family); + id4 = g_strdup_printf ("TPM\\VEN_%s&MOD_%s&VER_%s", manufacturer, model, self->family); fu_device_add_instance_id (device, id4); /* enforce vendors can only ship updates for their own hardware */ @@ -245,6 +252,8 @@ fu_tpm_device_init (FuTpmDevice *self) static void fu_tpm_device_finalize (GObject *object) { + FuTpmDevice *self = FU_TPM_DEVICE (object); + g_free (self->family); G_OBJECT_CLASS (fu_tpm_device_parent_class)->finalize (object); } diff --git a/plugins/tpm/fu-tpm-device.h b/plugins/tpm/fu-tpm-device.h index 55c1ef312..0584f9d26 100644 --- a/plugins/tpm/fu-tpm-device.h +++ b/plugins/tpm/fu-tpm-device.h @@ -10,3 +10,5 @@ #define FU_TYPE_TPM_DEVICE (fu_tpm_device_get_type ()) G_DECLARE_FINAL_TYPE (FuTpmDevice, fu_tpm_device, FU, TPM_DEVICE, FuUdevDevice) + +const gchar *fu_tpm_device_get_family (FuTpmDevice *self); diff --git a/plugins/uefi-dbx/README.md b/plugins/uefi-dbx/README.md index d1c22a9fd..cdd07c988 100644 --- a/plugins/uefi-dbx/README.md +++ b/plugins/uefi-dbx/README.md @@ -5,4 +5,4 @@ Introduction ------------ This plugin checks if the UEFI dbx contains all the most recent blacklisted -checksums. +checksums. The result will be stored in an security attribute for HSI. diff --git a/plugins/uefi-dbx/fu-plugin-uefi-dbx.c b/plugins/uefi-dbx/fu-plugin-uefi-dbx.c index a2089858d..b38836967 100644 --- a/plugins/uefi-dbx/fu-plugin-uefi-dbx.c +++ b/plugins/uefi-dbx/fu-plugin-uefi-dbx.c @@ -32,6 +32,17 @@ fu_plugin_destroy (FuPlugin *plugin) gboolean fu_plugin_startup (FuPlugin *plugin, GError **error) +{ + FuPluginData *data = fu_plugin_get_data (plugin); + data->fn = fu_uefi_dbx_get_dbxupdate (error); + if (data->fn == NULL) + return FALSE; + g_debug ("using %s", data->fn); + return TRUE; +} + +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) { FuPluginData *data = fu_plugin_get_data (plugin); GPtrArray *checksums; @@ -41,46 +52,55 @@ fu_plugin_startup (FuPlugin *plugin, GError **error) g_autofree guint8 *buf_update = NULL; g_autoptr(FuUefiDbxFile) dbx_system = NULL; g_autoptr(FuUefiDbxFile) dbx_update = NULL; + g_autoptr(FwupdSecurityAttr) attr = NULL; g_autoptr(GError) error_local = NULL; - /* get binary blob */ - data->fn = fu_uefi_dbx_get_dbxupdate (error); - if (data->fn == NULL) { + /* create attr */ + attr = fwupd_security_attr_new ("org.uefi.SecureBoot.dbx"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_set_name (attr, "UEFI dbx"); + fu_security_attrs_append (attrs, attr); + + /* no binary blob */ + if (!fu_plugin_get_enabled (plugin)) { g_autofree gchar *dbxdir = NULL; + g_autofree gchar *result = NULL; dbxdir = fu_common_get_path (FU_PATH_KIND_EFIDBXDIR); - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_NOT_SUPPORTED, - "file can be downloaded from %s and decompressed into %s: ", - FU_UEFI_DBX_DATA_URL, dbxdir); - return FALSE; + result = g_strdup_printf ("DBX can be downloaded from %s and decompressed into %s: ", + FU_UEFI_DBX_DATA_URL, dbxdir); + fwupd_security_attr_set_result (attr, result); + return; } /* get update dbx */ - if (!g_file_get_contents (data->fn, (gchar **) &buf_update, &bufsz, error)) { - g_prefix_error (error, "failed to load %s: ", data->fn); - return FALSE; + if (!g_file_get_contents (data->fn, (gchar **) &buf_update, &bufsz, &error_local)) { + g_warning ("failed to load %s: %s", data->fn, error_local->message); + fwupd_security_attr_set_result (attr, "Failed to load update DBX"); + return; } dbx_update = fu_uefi_dbx_file_new (buf_update, bufsz, FU_UEFI_DBX_FILE_PARSE_FLAGS_IGNORE_HEADER, - error); + &error_local); if (dbx_update == NULL) { - g_prefix_error (error, "could not parse %s: ", data->fn); - return FALSE; + g_warning ("failed to parse %s: %s", data->fn, error_local->message); + fwupd_security_attr_set_result (attr, "Failed to parse update DBX"); + return; } /* get system dbx */ if (!fu_efivar_get_data ("d719b2cb-3d3a-4596-a3bc-dad00e67656f", "dbx", - &buf_system, &bufsz, NULL, error)) { - g_prefix_error (error, "failed to get dbx: "); - return FALSE; + &buf_system, &bufsz, NULL, &error_local)) { + g_warning ("failed to load EFI dbx: %s", error_local->message); + fwupd_security_attr_set_result (attr, "Failed to load EFI DBX"); + return; } dbx_system = fu_uefi_dbx_file_new (buf_system, bufsz, FU_UEFI_DBX_FILE_PARSE_FLAGS_NONE, - error); + &error_local); if (dbx_system == NULL) { - g_prefix_error (error, "could not parse variable: "); - return FALSE; + g_warning ("failed to parse EFI dbx: %s", error_local->message); + fwupd_security_attr_set_result (attr, "Failed to parse EFI DBX"); + return; } /* look for each checksum in the update in the system version */ @@ -88,11 +108,18 @@ fu_plugin_startup (FuPlugin *plugin, GError **error) for (guint i = 0; i < checksums->len; i++) { const gchar *checksum = g_ptr_array_index (checksums, i); if (!fu_uefi_dbx_file_has_checksum (dbx_system, checksum)) { - g_debug ("%s missing from the system dbx", checksum); + g_debug ("%s missing from the system DBX", checksum); missing_cnt += 1; } } - if (missing_cnt > 0) - g_warning ("%u hashes missing", missing_cnt); - return TRUE; + + /* add security attribute */ + if (missing_cnt > 0) { + g_autofree gchar *summary = g_strdup_printf ("%u hashes missing", missing_cnt); + fwupd_security_attr_set_result (attr, summary); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); } diff --git a/plugins/uefi/fu-plugin-uefi.c b/plugins/uefi/fu-plugin-uefi.c index 204b338a0..ba9563716 100644 --- a/plugins/uefi/fu-plugin-uefi.c +++ b/plugins/uefi/fu-plugin-uefi.c @@ -91,6 +91,28 @@ fu_plugin_get_results (FuPlugin *plugin, FuDevice *device, GError **error) return TRUE; } +void +fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs) +{ + g_autoptr(FwupdSecurityAttr) attr = NULL; + + /* create attr */ + attr = fwupd_security_attr_new ("com.uefi.SecureBoot"); + fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); + fwupd_security_attr_set_name (attr, "UEFI Secure Boot"); + fu_security_attrs_append (attrs, attr); + + /* SB disabled */ + if (!fu_efivar_secure_boot_enabled ()) { + fwupd_security_attr_set_result (attr, "Disabled"); + return; + } + + /* success */ + fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS); + fwupd_security_attr_set_result (attr, "Enabled"); +} + static GBytes * fu_plugin_uefi_get_splash_data (guint width, guint height, GError **error) {