fwupd/plugins/linux-lockdown/fu-plugin-linux-lockdown.c
Richard Hughes b333e0045c Split out a shared system context
There is a lot of code in fwupd that just assigns a shared object type to
a FuPlugin, and then for each device on that plugin assigns that same shared
object to each FuDevice.

Rather than proxy several kinds of information stores over two different levels
of abstraction create a 'context' which contains the shared *system* state
between the daemon, the plugins and the daemon.

This will allow us to hold other per-machine state in the future, for instance
the system battery level or AC state.
2021-04-01 21:11:29 +01:00

142 lines
4.1 KiB
C

/*
* Copyright (C) 2020 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#include "config.h"
#include "fu-plugin-vfuncs.h"
typedef enum {
FU_PLUGIN_LINUX_LOCKDOWN_UNKNOWN,
FU_PLUGIN_LINUX_LOCKDOWN_INVALID,
FU_PLUGIN_LINUX_LOCKDOWN_NONE,
FU_PLUGIN_LINUX_LOCKDOWN_INTEGRITY,
FU_PLUGIN_LINUX_LOCKDOWN_CONFIDENTIALITY,
} FuPluginLinuxLockdown;
struct FuPluginData {
GFile *file;
GFileMonitor *monitor;
FuPluginLinuxLockdown lockdown;
};
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_file_monitor_cancel (data->monitor);
g_object_unref (data->monitor);
}
}
static const gchar *
fu_plugin_linux_lockdown_to_string (FuPluginLinuxLockdown lockdown)
{
if (lockdown == FU_PLUGIN_LINUX_LOCKDOWN_NONE)
return "none";
if (lockdown == FU_PLUGIN_LINUX_LOCKDOWN_INTEGRITY)
return "integrity";
if (lockdown == FU_PLUGIN_LINUX_LOCKDOWN_CONFIDENTIALITY)
return "confidentiality";
if (lockdown == FU_PLUGIN_LINUX_LOCKDOWN_INVALID)
return "invalid";
return NULL;
}
static void
fu_plugin_linux_lockdown_rescan (FuPlugin *plugin)
{
FuPluginData *data = fu_plugin_get_data (plugin);
gsize bufsz = 0;
g_autofree gchar *buf = NULL;
/* load file */
if (!g_file_load_contents (data->file, NULL, &buf, &bufsz, NULL, NULL)) {
data->lockdown = FU_PLUGIN_LINUX_LOCKDOWN_INVALID;
} else if (g_strstr_len (buf, bufsz, "[none]") != NULL) {
data->lockdown = FU_PLUGIN_LINUX_LOCKDOWN_NONE;
} else if (g_strstr_len (buf, bufsz, "[integrity]") != NULL) {
data->lockdown = FU_PLUGIN_LINUX_LOCKDOWN_INTEGRITY;
} else if (g_strstr_len (buf, bufsz, "[confidentiality]") != NULL) {
data->lockdown = FU_PLUGIN_LINUX_LOCKDOWN_CONFIDENTIALITY;
} else {
data->lockdown = FU_PLUGIN_LINUX_LOCKDOWN_UNKNOWN;
}
/* update metadata */
fu_plugin_add_report_metadata (plugin, "LinuxLockdown",
fu_plugin_linux_lockdown_to_string (data->lockdown));
}
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);
FuContext *ctx = fu_plugin_get_context (plugin);
fu_plugin_linux_lockdown_rescan (plugin);
fu_context_security_changed (ctx);
}
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);
fu_plugin_linux_lockdown_rescan (plugin);
return 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 (FWUPD_SECURITY_ATTR_ID_KERNEL_LOCKDOWN);
fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin));
fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE);
fu_security_attrs_append (attrs, attr);
/* load file */
if (data->lockdown == FU_PLUGIN_LINUX_LOCKDOWN_INVALID ||
data->lockdown == FU_PLUGIN_LINUX_LOCKDOWN_UNKNOWN) {
fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID);
return;
}
if (data->lockdown == FU_PLUGIN_LINUX_LOCKDOWN_NONE) {
fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED);
return;
}
/* success */
fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS);
fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED);
}