mirror of
https://git.proxmox.com/git/fwupd
synced 2025-05-18 00:31:54 +00:00

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.
242 lines
6.6 KiB
C
242 lines
6.6 KiB
C
/*
|
|
* Copyright (C) 2020 Richard Hughes <richard@hughsie.com>
|
|
*
|
|
* SPDX-License-Identifier: LGPL-2.1+
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <glib/gi18n.h>
|
|
|
|
#include "fu-security-attrs-private.h"
|
|
|
|
struct _FuSecurityAttrs {
|
|
GObject parent_instance;
|
|
GPtrArray *attrs;
|
|
};
|
|
|
|
G_DEFINE_TYPE (FuSecurityAttrs, fu_security_attrs, G_TYPE_OBJECT)
|
|
|
|
static void
|
|
fu_security_attrs_finalize (GObject *obj)
|
|
{
|
|
FuSecurityAttrs *self = FU_SECURITY_ATTRS (obj);
|
|
g_ptr_array_unref (self->attrs);
|
|
G_OBJECT_CLASS (fu_security_attrs_parent_class)->finalize (obj);
|
|
}
|
|
|
|
static void
|
|
fu_security_attrs_class_init (FuSecurityAttrsClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
object_class->finalize = fu_security_attrs_finalize;
|
|
}
|
|
|
|
static void
|
|
fu_security_attrs_init (FuSecurityAttrs *self)
|
|
{
|
|
self->attrs = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
|
|
}
|
|
|
|
/**
|
|
* fu_security_attrs_append:
|
|
* @self: A #FuSecurityAttrs
|
|
* @attr: a #FwupdSecurityAttr
|
|
*
|
|
* Adds a #FwupdSecurityAttr to the array.
|
|
*
|
|
* Since: 1.5.0
|
|
**/
|
|
void
|
|
fu_security_attrs_append (FuSecurityAttrs *self, FwupdSecurityAttr *attr)
|
|
{
|
|
g_return_if_fail (FU_IS_SECURITY_ATTRS (self));
|
|
g_return_if_fail (FWUPD_IS_SECURITY_ATTR (attr));
|
|
g_ptr_array_add (self->attrs, g_object_ref (attr));
|
|
}
|
|
|
|
/**
|
|
* fu_security_attrs_to_variant:
|
|
* @self: A #FuSecurityAttrs
|
|
*
|
|
* Converts the #FwupdSecurityAttr objects into a variant array.
|
|
*
|
|
* Returns: a #GVariant or %NULL
|
|
*
|
|
* Since: 1.5.0
|
|
**/
|
|
GVariant *
|
|
fu_security_attrs_to_variant (FuSecurityAttrs *self)
|
|
{
|
|
GVariantBuilder builder;
|
|
|
|
g_return_val_if_fail (FU_IS_SECURITY_ATTRS (self), NULL);
|
|
g_return_val_if_fail (self->attrs->len > 0, NULL);
|
|
g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
|
|
|
|
for (guint i = 0; i < self->attrs->len; i++) {
|
|
FwupdSecurityAttr *security_attr = g_ptr_array_index (self->attrs, i);
|
|
GVariant *tmp = fwupd_security_attr_to_variant (security_attr);
|
|
g_variant_builder_add_value (&builder, tmp);
|
|
}
|
|
return g_variant_new ("(aa{sv})", &builder);
|
|
}
|
|
|
|
/**
|
|
* fu_security_attrs_get_all:
|
|
* @self: A #FuSecurityAttrs
|
|
*
|
|
* Gets all the attributes in the object.
|
|
*
|
|
* Returns: (transfer container) (element-type FwupdSecurityAttr): attributes
|
|
*
|
|
* Since: 1.5.0
|
|
**/
|
|
GPtrArray *
|
|
fu_security_attrs_get_all (FuSecurityAttrs *self)
|
|
{
|
|
g_return_val_if_fail (FU_IS_SECURITY_ATTRS (self), NULL);
|
|
return g_ptr_array_ref (self->attrs);
|
|
}
|
|
|
|
/**
|
|
* fu_security_attrs_calculate_hsi:
|
|
* @self: A #FuSecurityAttrs
|
|
*
|
|
* Calculates the HSI string from the appended attribues.
|
|
*
|
|
* Returns: (transfer full): a string or %NULL
|
|
*
|
|
* Since: 1.5.0
|
|
**/
|
|
gchar *
|
|
fu_security_attrs_calculate_hsi (FuSecurityAttrs *self)
|
|
{
|
|
guint hsi_number = 0;
|
|
FwupdSecurityAttrFlags flags = FWUPD_SECURITY_ATTR_FLAG_NONE;
|
|
GString *str = g_string_new ("HSI:");
|
|
const FwupdSecurityAttrFlags hpi_suffixes[] = {
|
|
FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES,
|
|
FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION,
|
|
FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE,
|
|
FWUPD_SECURITY_ATTR_FLAG_NONE,
|
|
};
|
|
|
|
g_return_val_if_fail (FU_IS_SECURITY_ATTRS (self), NULL);
|
|
|
|
/* find the highest HSI number where there are no failures and at least
|
|
* one success */
|
|
for (guint j = 1; j <= FWUPD_SECURITY_ATTR_LEVEL_LAST; j++) {
|
|
gboolean success_cnt = 0;
|
|
gboolean failure_cnt = 0;
|
|
for (guint i = 0; i < self->attrs->len; i++) {
|
|
FwupdSecurityAttr *attr = g_ptr_array_index (self->attrs, i);
|
|
if (fwupd_security_attr_get_level (attr) != j)
|
|
continue;
|
|
if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS))
|
|
success_cnt++;
|
|
else if (!fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED))
|
|
failure_cnt++;
|
|
}
|
|
|
|
/* abort */
|
|
if (failure_cnt > 0) {
|
|
hsi_number = j - 1;
|
|
break;
|
|
}
|
|
|
|
/* we matched at least one thing on this level */
|
|
if (success_cnt > 0)
|
|
hsi_number = j;
|
|
}
|
|
|
|
/* get a logical OR of the runtime flags */
|
|
for (guint i = 0; i < self->attrs->len; i++) {
|
|
FwupdSecurityAttr *attr = g_ptr_array_index (self->attrs, i);
|
|
if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED))
|
|
continue;
|
|
/* positive things */
|
|
if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES) ||
|
|
fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION)) {
|
|
if (!fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS))
|
|
continue;
|
|
}
|
|
/* negative things */
|
|
if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE)) {
|
|
if (fwupd_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS))
|
|
continue;
|
|
}
|
|
flags |= fwupd_security_attr_get_flags (attr);
|
|
}
|
|
|
|
g_string_append_printf (str, "%u", hsi_number);
|
|
if (flags & (FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES |
|
|
FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION |
|
|
FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE)) {
|
|
g_string_append (str, "+");
|
|
for (guint j = 0; hpi_suffixes[j] != FWUPD_SECURITY_ATTR_FLAG_NONE; j++) {
|
|
if (flags & hpi_suffixes[j])
|
|
g_string_append (str, fwupd_security_attr_flag_to_suffix (hpi_suffixes[j]));
|
|
}
|
|
}
|
|
return g_string_free (str, FALSE);
|
|
}
|
|
|
|
/**
|
|
* fu_security_attrs_depsolve:
|
|
* @self: A #FuSecurityAttrs
|
|
*
|
|
* Marks any attributes with %FWUPD_SECURITY_ATTR_FLAG_OBSOLETED that have been
|
|
* defined as obsoleted by other attributes.
|
|
*
|
|
* It is only required to call this function once, and should be done when all
|
|
* attributes have been added.
|
|
*
|
|
* Since: 1.5.0
|
|
**/
|
|
void
|
|
fu_security_attrs_depsolve (FuSecurityAttrs *self)
|
|
{
|
|
g_autoptr(GHashTable) attrs_by_id = NULL;
|
|
|
|
g_return_if_fail (FU_IS_SECURITY_ATTRS (self));
|
|
|
|
/* make hash of ID -> object */
|
|
attrs_by_id = g_hash_table_new (g_str_hash, g_str_equal);
|
|
for (guint i = 0; i < self->attrs->len; i++) {
|
|
FwupdSecurityAttr *attr = g_ptr_array_index (self->attrs, i);
|
|
g_hash_table_insert (attrs_by_id,
|
|
(gpointer) fwupd_security_attr_get_appstream_id (attr),
|
|
(gpointer) attr);
|
|
}
|
|
|
|
/* set flat where required */
|
|
for (guint i = 0; i < self->attrs->len; i++) {
|
|
FwupdSecurityAttr *attr = g_ptr_array_index (self->attrs, i);
|
|
GPtrArray *obsoletes = fwupd_security_attr_get_obsoletes (attr);
|
|
for (guint j = 0; j < obsoletes->len; j++) {
|
|
const gchar *obsolete = g_ptr_array_index (obsoletes, j);
|
|
FwupdSecurityAttr *attr_tmp = g_hash_table_lookup (attrs_by_id, obsolete);
|
|
if (attr_tmp != NULL) {
|
|
g_debug ("security attr %s obsoleted by %s", obsolete,
|
|
fwupd_security_attr_get_appstream_id (attr));
|
|
fwupd_security_attr_add_flag (attr_tmp,
|
|
FWUPD_SECURITY_ATTR_FLAG_OBSOLETED);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* fu_security_attrs_new:
|
|
*
|
|
* Returns: a #FuSecurityAttrs
|
|
*
|
|
* Since: 1.5.0
|
|
**/
|
|
FuSecurityAttrs *
|
|
fu_security_attrs_new (void)
|
|
{
|
|
return g_object_new (FU_TYPE_SECURITY_ATTRS, NULL);
|
|
}
|