fwupd/plugins/tpm-eventlog/fu-plugin-tpm-eventlog.c
Richard Hughes f58ac7316c hsi: Abstract out the list of FwupdSecurityAttr objects for plugins
This exports FuSecurityAttrs into libfwupdplugin so that we can pass the plugins
this object rather than a 'bare' GPtrArray. This greatly simplifies the object
ownership, and also allows us to check the object type before adding.

In the future we could also check for duplicate appstream IDs or missing
properties at insertion time.

This change also changes the fu_plugin_add_security_attrs() to not return an
error. This forces the plugin to handle the error, storing the failure in the
attribute itself.

Only the plugin know if a missing file it needs to read indicates a runtime
problem or a simple failure to obtain a specific HSI level.
2020-05-12 16:47:24 +01:00

147 lines
4.2 KiB
C

/*
* Copyright (C) 2019 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#include "config.h"
#include "fu-hash.h"
#include "fu-plugin-vfuncs.h"
#include "fu-tpm-eventlog-device.h"
#include "fu-efivar.h"
struct FuPluginData {
GPtrArray *pcr0s;
gboolean secure_boot_problem;
gboolean reconstructed;
};
void
fu_plugin_init (FuPlugin *plugin)
{
fu_plugin_alloc_data (plugin, sizeof (FuPluginData));
fu_plugin_add_rule (plugin, FU_PLUGIN_RULE_RUN_BEFORE, "uefi");
fu_plugin_set_build_hash (plugin, FU_BUILD_HASH);
}
void
fu_plugin_destroy (FuPlugin *plugin)
{
FuPluginData *data = fu_plugin_get_data (plugin);
if (data->pcr0s != NULL)
g_ptr_array_unref (data->pcr0s);
}
gboolean
fu_plugin_coldplug (FuPlugin *plugin, GError **error)
{
FuPluginData *data = fu_plugin_get_data (plugin);
gsize bufsz = 0;
const gchar *fn = "/sys/kernel/security/tpm0/binary_bios_measurements";
g_autofree gchar *str = NULL;
g_autofree guint8 *buf = NULL;
g_autoptr(FuTpmEventlogDevice) dev = NULL;
g_autoptr(GError) error_local = NULL;
if (!g_file_get_contents (fn, (gchar **) &buf, &bufsz, &error_local)) {
if (fu_efivar_supported (NULL) && !fu_efivar_secure_boot_enabled ()) {
data->secure_boot_problem = TRUE;
return TRUE;
}
g_propagate_error (error, g_steal_pointer (&error_local));
return FALSE;
}
if (!g_file_get_contents (fn, (gchar **) &buf, &bufsz, error))
return FALSE;
if (bufsz == 0) {
g_set_error (error,
FWUPD_ERROR,
FWUPD_ERROR_INVALID_FILE,
"failed to read data from %s", fn);
return FALSE;
}
dev = fu_tpm_eventlog_device_new (buf, bufsz, error);
if (dev == NULL)
return FALSE;
if (!fu_device_setup (FU_DEVICE (dev), error))
return FALSE;
/* save this so we can compare against system-firmware */
data->pcr0s = fu_tpm_eventlog_device_get_checksums (dev, 0, error);
if (data->pcr0s == NULL)
return FALSE;
for (guint i = 0; i < data->pcr0s->len; i++) {
const gchar *csum = g_ptr_array_index (data->pcr0s, i);
fu_device_add_checksum (FU_DEVICE (dev), csum);
}
/* add optional report metadata */
str = fu_tpm_eventlog_device_report_metadata (dev);
g_debug ("using TPM event log report data of:\n%s", str);
fu_plugin_add_report_metadata (plugin, "TpmEventLog", str);
fu_plugin_device_add (plugin, FU_DEVICE (dev));
return TRUE;
}
void
fu_plugin_device_registered (FuPlugin *plugin, FuDevice *device)
{
FuPluginData *data = fu_plugin_get_data (plugin);
GPtrArray *checksums;
/* only care about UEFI devices from ESRT */
if (g_strcmp0 (fu_device_get_plugin (device), "uefi") != 0)
return;
/* only the system-firmware device gets checksums */
checksums = fu_device_get_checksums (device);
if (checksums->len == 0)
return;
if (data->secure_boot_problem) {
fu_device_set_update_message (device,
"Platform firmware measurement unavailable. Secure boot is disabled in BIOS setup, "
"enabling it may fix this issue");
return;
}
for (guint i = 0; i < checksums->len; i++) {
const gchar *checksum = g_ptr_array_index (checksums, i);
for (guint j = 0; j < data->pcr0s->len; j++) {
const gchar *checksum_tmp = g_ptr_array_index (data->pcr0s, j);
if (g_strcmp0 (checksum, checksum_tmp) == 0) {
data->reconstructed = TRUE;
return;
}
}
}
/* urgh, this is unexpected */
fu_device_set_update_message (device,
"TPM PCR0 differs from reconstruction, "
"please see https://github.com/fwupd/fwupd/wiki/TPM-PCR0-differs-from-reconstruction");
}
void
fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs)
{
FuPluginData *data = fu_plugin_get_data (plugin);
g_autoptr(FwupdSecurityAttr) attr = NULL;
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");
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");
}
fu_security_attrs_append (attrs, attr);
}