Add many new plugins to support for the Host Security ID

The HSI specification is currently incomplete and in active development.

Sample output for my Lenovo P50 Laptop:

    Host Security ID: HSI:2+UA!

    HSI-1
    ✔  UEFI dbx: OK
    ✔  TPM: v2.0
    ✔  SPI: Write disabled
    ✔  SPI: Lock enabled
    ✔  SPI: SMM required
    ✔  UEFI Secure Boot: Enabled

    HSI-2
    ✔  TPM Reconstruction: Matched PCR0 reading

    HSI-3
    ✘  Linux Kernel S3 Sleep: Deep sleep available

    HSI-4
    ✘  Intel CET: Unavailable

    Runtime Suffix -U
    ✔  Firmware Updates: Newest release is 8 months old

    Runtime Suffix -A
    ✔  Firmware Attestation: OK

    Runtime Suffix -!
    ✔  fwupd plugins: OK
    ✔  Linux Kernel: OK
    ✔  Linux Kernel: Locked down
    ✘  Linux Swap: Not encrypted
This commit is contained in:
Richard Hughes 2020-05-01 15:51:44 +01:00
parent f58ac7316c
commit c1eda7d516
40 changed files with 1279 additions and 62 deletions

View File

@ -329,6 +329,8 @@ mkdir -p --mode=0700 $RPM_BUILD_ROOT%{_localstatedir}/lib/fwupd/gnupg
/usr/lib/udev/rules.d/*.rules /usr/lib/udev/rules.d/*.rules
/usr/lib/systemd/system-shutdown/fwupd.shutdown /usr/lib/systemd/system-shutdown/fwupd.shutdown
%dir %{_libdir}/fwupd-plugins-3 %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_altos.so
%{_libdir}/fwupd-plugins-3/libfu_plugin_amt.so %{_libdir}/fwupd-plugins-3/libfu_plugin_amt.so
%{_libdir}/fwupd-plugins-3/libfu_plugin_ata.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 %endif
%{_libdir}/fwupd-plugins-3/libfu_plugin_fresco_pd.so %{_libdir}/fwupd-plugins-3/libfu_plugin_fresco_pd.so
%{_libdir}/fwupd-plugins-3/libfu_plugin_jabra.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_swap.so
%{_libdir}/fwupd-plugins-3/libfu_plugin_linux_tainted.so
%if 0%{?have_modem_manager} %if 0%{?have_modem_manager}
%{_libdir}/fwupd-plugins-3/libfu_plugin_modem_manager.so %{_libdir}/fwupd-plugins-3/libfu_plugin_modem_manager.so
%endif %endif

View File

@ -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.

View File

@ -0,0 +1,81 @@
/*
* Copyright (C) 2020 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#include "config.h"
#include <string.h>
#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)
{
}

View File

@ -0,0 +1,16 @@
/*
* Copyright (C) 2020 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#pragma once
#include <gio/gio.h>
#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);

View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 2020 Richard Hughes <richard@hughsie.com>
*
* 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);
}

View File

@ -0,0 +1,65 @@
/*
* Copyright (C) 2020 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#include "config.h"
#include <fwupd.h>
#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 ();
}

View File

@ -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

Binary file not shown.

Binary file not shown.

View File

@ -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.

View File

@ -0,0 +1,54 @@
/*
* Copyright (C) 2020 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#include "config.h"
#include <string.h>
#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)
{
}

View File

@ -0,0 +1,16 @@
/*
* Copyright (C) 2020 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#pragma once
#include <gio/gio.h>
#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);

View File

@ -0,0 +1,57 @@
/*
* Copyright (C) 2020 Richard Hughes <richard@hughsie.com>
*
* 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);
}

View File

@ -0,0 +1,64 @@
/*
* Copyright (C) 2020 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#include "config.h"
#include <fwupd.h>
#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 ();
}

View File

@ -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

Binary file not shown.

Binary file not shown.

View File

@ -10,23 +10,29 @@
#include "fu-hash.h" #include "fu-hash.h"
#include "fu-cpu-device.h" #include "fu-cpu-device.h"
struct FuPluginData {
gboolean has_cet;
};
void void
fu_plugin_init (FuPlugin *plugin) fu_plugin_init (FuPlugin *plugin)
{ {
fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_set_build_hash (plugin, FU_BUILD_HASH);
fu_plugin_alloc_data (plugin, sizeof (FuPluginData));
} }
gboolean gboolean
fu_plugin_coldplug (FuPlugin *plugin, GError **error) fu_plugin_coldplug (FuPlugin *plugin, GError **error)
{ {
FuPluginData *data = fu_plugin_get_data (plugin);
gsize length; gsize length;
g_autofree gchar *data = NULL; g_autofree gchar *buf = NULL;
g_auto(GStrv) lines = 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; return FALSE;
lines = g_strsplit (data, "\n\n", 0); lines = g_strsplit (buf, "\n\n", 0);
for (guint i = 0; lines[i] != NULL; i++) { for (guint i = 0; lines[i] != NULL; i++) {
g_autoptr(FuCpuDevice) dev = NULL; g_autoptr(FuCpuDevice) dev = NULL;
if (strlen (lines[i]) == 0) if (strlen (lines[i]) == 0)
@ -34,8 +40,36 @@ fu_plugin_coldplug (FuPlugin *plugin, GError **error)
dev = fu_cpu_device_new (lines[i]); dev = fu_cpu_device_new (lines[i]);
if (!fu_device_setup (FU_DEVICE (dev), error)) if (!fu_device_setup (FU_DEVICE (dev), error))
return FALSE; 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)); fu_plugin_device_add (plugin, FU_DEVICE (dev));
} }
return TRUE; 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");
}

View File

@ -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.

View File

@ -0,0 +1,94 @@
/*
* Copyright (C) 2020 Richard Hughes <richard@hughsie.com>
*
* 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");
}

View File

@ -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,
],
)

View File

@ -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.

View File

@ -0,0 +1,47 @@
/*
* Copyright (C) 2020 Richard Hughes <richard@hughsie.com>
*
* 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);
}

View File

@ -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,
],
)

View File

@ -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.

View File

@ -0,0 +1,139 @@
/*
* Copyright (C) 2020 Richard Hughes <richard@hughsie.com>
*
* 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);
}

View File

@ -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,
],
)

View File

@ -5,4 +5,4 @@ Introduction
------------ ------------
This plugin checks if the currently available swap partitions and files are 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.

View File

@ -11,6 +11,7 @@
#include "fu-linux-swap.h" #include "fu-linux-swap.h"
struct FuPluginData { struct FuPluginData {
GFile *file;
GFileMonitor *monitor; GFileMonitor *monitor;
}; };
@ -25,6 +26,8 @@ void
fu_plugin_destroy (FuPlugin *plugin) fu_plugin_destroy (FuPlugin *plugin)
{ {
FuPluginData *data = fu_plugin_get_data (plugin); FuPluginData *data = fu_plugin_get_data (plugin);
if (data->file != NULL)
g_object_unref (data->file);
if (data->monitor != NULL) if (data->monitor != NULL)
g_object_unref (data->monitor); g_object_unref (data->monitor);
} }
@ -36,41 +39,72 @@ fu_plugin_linux_swap_changed_cb (GFileMonitor *monitor,
GFileMonitorEvent event_type, GFileMonitorEvent event_type,
gpointer user_data) gpointer user_data)
{ {
g_debug ("swap changed"); FuPlugin *plugin = FU_PLUGIN (user_data);
fu_plugin_security_changed (plugin);
} }
gboolean gboolean
fu_plugin_startup (FuPlugin *plugin, GError **error) fu_plugin_startup (FuPlugin *plugin, GError **error)
{ {
FuPluginData *data = fu_plugin_get_data (plugin); FuPluginData *data = fu_plugin_get_data (plugin);
gsize bufsz = 0;
g_autofree gchar *buf = NULL;
g_autofree gchar *fn = NULL; g_autofree gchar *fn = NULL;
g_autofree gchar *procfs = 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); procfs = fu_common_get_path (FU_PATH_KIND_PROCFS);
fn = g_build_filename (procfs, "swaps", NULL); fn = g_build_filename (procfs, "swaps", NULL);
file = g_file_new_for_path (fn); data->file = g_file_new_for_path (fn);
data->monitor = g_file_monitor (file, G_FILE_MONITOR_NONE, NULL, error); data->monitor = g_file_monitor (data->file, G_FILE_MONITOR_NONE, NULL, error);
if (data->monitor == NULL) if (data->monitor == NULL)
return FALSE; return FALSE;
g_signal_connect (data->monitor, "changed", g_signal_connect (data->monitor, "changed",
G_CALLBACK (fu_plugin_linux_swap_changed_cb), plugin); 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; 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");
}

View File

@ -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.

View File

@ -0,0 +1,92 @@
/*
* Copyright (C) 2020 Richard Hughes <richard@hughsie.com>
*
* 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);
}

View File

@ -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,
],
)

View File

@ -1,3 +1,5 @@
subdir('acpi-dmar')
subdir('acpi-facp')
subdir('ccgx') subdir('ccgx')
subdir('cpu') subdir('cpu')
subdir('dfu') subdir('dfu')
@ -7,7 +9,11 @@ subdir('ep963x')
subdir('fastboot') subdir('fastboot')
subdir('fresco-pd') subdir('fresco-pd')
subdir('jabra') subdir('jabra')
subdir('linux-lockdown')
subdir('linux-sleep')
subdir('linux-spi-lpc')
subdir('linux-swap') subdir('linux-swap')
subdir('linux-tainted')
subdir('steelseries') subdir('steelseries')
subdir('dell-dock') subdir('dell-dock')
subdir('nitrokey') subdir('nitrokey')

View File

@ -131,16 +131,23 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs)
FuPluginData *data = fu_plugin_get_data (plugin); FuPluginData *data = fu_plugin_get_data (plugin);
g_autoptr(FwupdSecurityAttr) attr = NULL; g_autoptr(FwupdSecurityAttr) attr = NULL;
/* create attr */
attr = fwupd_security_attr_new ("org.trustedcomputinggroup.TpmEventLog"); attr = fwupd_security_attr_new ("org.trustedcomputinggroup.TpmEventLog");
fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT); fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT);
fwupd_security_attr_set_name (attr, "TPM Reconstruction"); fwupd_security_attr_set_name (attr, "TPM Reconstruction");
fu_security_attrs_append (attrs, attr);
/* check reconstructed to PCR0 */
if (!fu_plugin_get_enabled (plugin)) { if (!fu_plugin_get_enabled (plugin)) {
fwupd_security_attr_set_result (attr, "No binary bios measurements available"); fwupd_security_attr_set_result (attr, "No binary bios measurements available");
} else if (data->reconstructed) { return;
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");
} }
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");
} }

View File

@ -11,10 +11,52 @@
#include "fu-tpm-device.h" #include "fu-tpm-device.h"
struct FuPluginData {
gboolean has_tpm;
gboolean has_tpm_v20;
};
void void
fu_plugin_init (FuPlugin *plugin) fu_plugin_init (FuPlugin *plugin)
{ {
fu_plugin_alloc_data (plugin, sizeof (FuPluginData));
fu_plugin_set_build_hash (plugin, FU_BUILD_HASH); fu_plugin_set_build_hash (plugin, FU_BUILD_HASH);
fu_plugin_add_udev_subsystem (plugin, "tpm"); fu_plugin_add_udev_subsystem (plugin, "tpm");
fu_plugin_set_device_gtype (plugin, FU_TYPE_TPM_DEVICE); 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");
}

View File

@ -12,6 +12,7 @@
struct _FuTpmDevice { struct _FuTpmDevice {
FuUdevDevice parent_instance; FuUdevDevice parent_instance;
gchar *family;
}; };
G_DEFINE_TYPE (FuTpmDevice, fu_tpm_device, FU_TYPE_UDEV_DEVICE) 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) 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 static gboolean
fu_tpm_device_probe (FuUdevDevice *device, GError **error) fu_tpm_device_probe (FuUdevDevice *device, GError **error)
{ {
@ -134,6 +141,7 @@ fu_tpm_device_convert_manufacturer (const gchar *manufacturer)
static gboolean static gboolean
fu_tpm_device_setup (FuDevice *device, GError **error) fu_tpm_device_setup (FuDevice *device, GError **error)
{ {
FuTpmDevice *self = FU_TPM_DEVICE (device);
FwupdVersionFormat verfmt; FwupdVersionFormat verfmt;
TSS2_RC rc; TSS2_RC rc;
const gchar *tmp; const gchar *tmp;
@ -141,7 +149,6 @@ fu_tpm_device_setup (FuDevice *device, GError **error)
guint32 version1 = 0; guint32 version1 = 0;
guint32 version2 = 0; guint32 version2 = 0;
guint64 version_raw; guint64 version_raw;
g_autofree gchar *family = NULL;
g_autofree gchar *id1 = NULL; g_autofree gchar *id1 = NULL;
g_autofree gchar *id2 = NULL; g_autofree gchar *id2 = NULL;
g_autofree gchar *id3 = NULL; g_autofree gchar *id3 = NULL;
@ -171,8 +178,8 @@ fu_tpm_device_setup (FuDevice *device, GError **error)
} }
/* lookup guaranteed details from TPM */ /* lookup guaranteed details from TPM */
family = fu_tpm_device_get_string (ctx, TPM2_PT_FAMILY_INDICATOR, error); self->family = fu_tpm_device_get_string (ctx, TPM2_PT_FAMILY_INDICATOR, error);
if (family == NULL) { if (self->family == NULL) {
g_prefix_error (error, "failed to read TPM family"); g_prefix_error (error, "failed to read TPM family");
return FALSE; return FALSE;
} }
@ -202,9 +209,9 @@ fu_tpm_device_setup (FuDevice *device, GError **error)
fu_device_add_instance_id (device, id1); fu_device_add_instance_id (device, id1);
id2 = g_strdup_printf ("TPM\\VEN_%s&MOD_%s", manufacturer, model); id2 = g_strdup_printf ("TPM\\VEN_%s&MOD_%s", manufacturer, model);
fu_device_add_instance_id (device, id2); 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); 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); fu_device_add_instance_id (device, id4);
/* enforce vendors can only ship updates for their own hardware */ /* enforce vendors can only ship updates for their own hardware */
@ -245,6 +252,8 @@ fu_tpm_device_init (FuTpmDevice *self)
static void static void
fu_tpm_device_finalize (GObject *object) 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); G_OBJECT_CLASS (fu_tpm_device_parent_class)->finalize (object);
} }

View File

@ -10,3 +10,5 @@
#define FU_TYPE_TPM_DEVICE (fu_tpm_device_get_type ()) #define FU_TYPE_TPM_DEVICE (fu_tpm_device_get_type ())
G_DECLARE_FINAL_TYPE (FuTpmDevice, fu_tpm_device, FU, TPM_DEVICE, FuUdevDevice) G_DECLARE_FINAL_TYPE (FuTpmDevice, fu_tpm_device, FU, TPM_DEVICE, FuUdevDevice)
const gchar *fu_tpm_device_get_family (FuTpmDevice *self);

View File

@ -5,4 +5,4 @@ Introduction
------------ ------------
This plugin checks if the UEFI dbx contains all the most recent blacklisted 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.

View File

@ -32,6 +32,17 @@ fu_plugin_destroy (FuPlugin *plugin)
gboolean gboolean
fu_plugin_startup (FuPlugin *plugin, GError **error) 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); FuPluginData *data = fu_plugin_get_data (plugin);
GPtrArray *checksums; GPtrArray *checksums;
@ -41,46 +52,55 @@ fu_plugin_startup (FuPlugin *plugin, GError **error)
g_autofree guint8 *buf_update = NULL; g_autofree guint8 *buf_update = NULL;
g_autoptr(FuUefiDbxFile) dbx_system = NULL; g_autoptr(FuUefiDbxFile) dbx_system = NULL;
g_autoptr(FuUefiDbxFile) dbx_update = NULL; g_autoptr(FuUefiDbxFile) dbx_update = NULL;
g_autoptr(FwupdSecurityAttr) attr = NULL;
g_autoptr(GError) error_local = NULL; g_autoptr(GError) error_local = NULL;
/* get binary blob */ /* create attr */
data->fn = fu_uefi_dbx_get_dbxupdate (error); attr = fwupd_security_attr_new ("org.uefi.SecureBoot.dbx");
if (data->fn == NULL) { 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 *dbxdir = NULL;
g_autofree gchar *result = NULL;
dbxdir = fu_common_get_path (FU_PATH_KIND_EFIDBXDIR); dbxdir = fu_common_get_path (FU_PATH_KIND_EFIDBXDIR);
g_set_error (error, result = g_strdup_printf ("DBX can be downloaded from %s and decompressed into %s: ",
FWUPD_ERROR, FU_UEFI_DBX_DATA_URL, dbxdir);
FWUPD_ERROR_NOT_SUPPORTED, fwupd_security_attr_set_result (attr, result);
"file can be downloaded from %s and decompressed into %s: ", return;
FU_UEFI_DBX_DATA_URL, dbxdir);
return FALSE;
} }
/* get update dbx */ /* get update dbx */
if (!g_file_get_contents (data->fn, (gchar **) &buf_update, &bufsz, error)) { if (!g_file_get_contents (data->fn, (gchar **) &buf_update, &bufsz, &error_local)) {
g_prefix_error (error, "failed to load %s: ", data->fn); g_warning ("failed to load %s: %s", data->fn, error_local->message);
return FALSE; fwupd_security_attr_set_result (attr, "Failed to load update DBX");
return;
} }
dbx_update = fu_uefi_dbx_file_new (buf_update, bufsz, dbx_update = fu_uefi_dbx_file_new (buf_update, bufsz,
FU_UEFI_DBX_FILE_PARSE_FLAGS_IGNORE_HEADER, FU_UEFI_DBX_FILE_PARSE_FLAGS_IGNORE_HEADER,
error); &error_local);
if (dbx_update == NULL) { if (dbx_update == NULL) {
g_prefix_error (error, "could not parse %s: ", data->fn); g_warning ("failed to parse %s: %s", data->fn, error_local->message);
return FALSE; fwupd_security_attr_set_result (attr, "Failed to parse update DBX");
return;
} }
/* get system dbx */ /* get system dbx */
if (!fu_efivar_get_data ("d719b2cb-3d3a-4596-a3bc-dad00e67656f", "dbx", if (!fu_efivar_get_data ("d719b2cb-3d3a-4596-a3bc-dad00e67656f", "dbx",
&buf_system, &bufsz, NULL, error)) { &buf_system, &bufsz, NULL, &error_local)) {
g_prefix_error (error, "failed to get dbx: "); g_warning ("failed to load EFI dbx: %s", error_local->message);
return FALSE; fwupd_security_attr_set_result (attr, "Failed to load EFI DBX");
return;
} }
dbx_system = fu_uefi_dbx_file_new (buf_system, bufsz, dbx_system = fu_uefi_dbx_file_new (buf_system, bufsz,
FU_UEFI_DBX_FILE_PARSE_FLAGS_NONE, FU_UEFI_DBX_FILE_PARSE_FLAGS_NONE,
error); &error_local);
if (dbx_system == NULL) { if (dbx_system == NULL) {
g_prefix_error (error, "could not parse variable: "); g_warning ("failed to parse EFI dbx: %s", error_local->message);
return FALSE; fwupd_security_attr_set_result (attr, "Failed to parse EFI DBX");
return;
} }
/* look for each checksum in the update in the system version */ /* 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++) { for (guint i = 0; i < checksums->len; i++) {
const gchar *checksum = g_ptr_array_index (checksums, i); const gchar *checksum = g_ptr_array_index (checksums, i);
if (!fu_uefi_dbx_file_has_checksum (dbx_system, checksum)) { 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; missing_cnt += 1;
} }
} }
if (missing_cnt > 0)
g_warning ("%u hashes missing", missing_cnt); /* add security attribute */
return TRUE; 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);
} }

View File

@ -91,6 +91,28 @@ fu_plugin_get_results (FuPlugin *plugin, FuDevice *device, GError **error)
return TRUE; 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 * static GBytes *
fu_plugin_uefi_get_splash_data (guint width, guint height, GError **error) fu_plugin_uefi_get_splash_data (guint width, guint height, GError **error)
{ {