From ae1c76ff830d146d41e88d6fba724c0a54bce868 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:45:20 +0200 Subject: Adding upstream version 1:43.6. Signed-off-by: Daniel Baumann --- .../cc-firmware-security-boot-dialog.c | 113 ++++ .../cc-firmware-security-boot-dialog.h | 37 ++ .../cc-firmware-security-boot-dialog.ui | 63 ++ .../cc-firmware-security-dialog.c | 442 +++++++++++++ .../cc-firmware-security-dialog.h | 38 ++ .../cc-firmware-security-dialog.ui | 271 ++++++++ .../firmware-security/cc-firmware-security-panel.c | 717 +++++++++++++++++++++ .../firmware-security/cc-firmware-security-panel.h | 34 + .../cc-firmware-security-panel.ui | 176 +++++ .../firmware-security/cc-firmware-security-utils.c | 373 +++++++++++ .../firmware-security/cc-firmware-security-utils.h | 133 ++++ .../firmware-security.gresource.xml | 9 + .../gnome-firmware-security-panel.desktop.in.in | 19 + panels/firmware-security/meson.build | 44 ++ panels/firmware-security/security-level.css | 119 ++++ 15 files changed, 2588 insertions(+) create mode 100644 panels/firmware-security/cc-firmware-security-boot-dialog.c create mode 100644 panels/firmware-security/cc-firmware-security-boot-dialog.h create mode 100644 panels/firmware-security/cc-firmware-security-boot-dialog.ui create mode 100644 panels/firmware-security/cc-firmware-security-dialog.c create mode 100644 panels/firmware-security/cc-firmware-security-dialog.h create mode 100644 panels/firmware-security/cc-firmware-security-dialog.ui create mode 100644 panels/firmware-security/cc-firmware-security-panel.c create mode 100644 panels/firmware-security/cc-firmware-security-panel.h create mode 100644 panels/firmware-security/cc-firmware-security-panel.ui create mode 100644 panels/firmware-security/cc-firmware-security-utils.c create mode 100644 panels/firmware-security/cc-firmware-security-utils.h create mode 100644 panels/firmware-security/firmware-security.gresource.xml create mode 100644 panels/firmware-security/gnome-firmware-security-panel.desktop.in.in create mode 100644 panels/firmware-security/meson.build create mode 100644 panels/firmware-security/security-level.css (limited to 'panels/firmware-security') diff --git a/panels/firmware-security/cc-firmware-security-boot-dialog.c b/panels/firmware-security/cc-firmware-security-boot-dialog.c new file mode 100644 index 0000000..bf8a0e7 --- /dev/null +++ b/panels/firmware-security/cc-firmware-security-boot-dialog.c @@ -0,0 +1,113 @@ +/* cc-firmware-security-boot-dialog.c + * + * Copyright (C) 2021 Red Hat, Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * Author: Kate Hsuan + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include + +#include "cc-firmware-security-boot-dialog.h" + +struct _CcFirmwareSecurityBootDialog +{ + GtkDialog parent; + + GtkWidget *secure_boot_icon; + GtkWidget *secure_boot_title; + GtkWidget *secure_boot_description; +}; + +G_DEFINE_TYPE (CcFirmwareSecurityBootDialog, cc_firmware_security_boot_dialog, GTK_TYPE_DIALOG) + +static void +cc_firmware_security_boot_dialog_class_init (CcFirmwareSecurityBootDialogClass *klass) +{ + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/firmware-security/cc-firmware-security-boot-dialog.ui"); + gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityBootDialog, secure_boot_title); + gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityBootDialog, secure_boot_icon); + gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityBootDialog, secure_boot_description); +} + +static void +cc_firmware_security_boot_dialog_init (CcFirmwareSecurityBootDialog *dialog) +{ + gtk_widget_init_template (GTK_WIDGET (dialog)); + load_custom_css ("/org/gnome/control-center/firmware-security/security-level.css"); +} + +GtkWidget * +cc_firmware_security_boot_dialog_new (SecureBootState secure_boot_state) +{ + CcFirmwareSecurityBootDialog *dialog; + g_autofree gchar *status_description = NULL; + + dialog = g_object_new (CC_TYPE_FIRMWARE_SECURITY_BOOT_DIALOG, + "use-header-bar", TRUE, + NULL); + + switch (secure_boot_state) + { + case SECURE_BOOT_STATE_ACTIVE: + /* TRANSLATORS: secure boot refers to the system firmware security mode */ + gtk_label_set_text (GTK_LABEL(dialog->secure_boot_title), _("Secure Boot is Active")); + gtk_image_set_from_icon_name (GTK_IMAGE (dialog->secure_boot_icon), "channel-secure-symbolic"); + gtk_widget_add_css_class (dialog->secure_boot_icon, "good"); + status_description = g_strdup_printf ("%s", + /* TRANSLATORS: this is the first section of the decription */ + _("Secure boot prevents malicious software from being loaded when the device starts. " + "It is currently turned on and is functioning correctly.")); + break; + + case SECURE_BOOT_STATE_PROBLEMS: + /* TRANSLATORS: secure boot refers to the system firmware security mode */ + gtk_label_set_text (GTK_LABEL (dialog->secure_boot_title), _("Secure Boot Has Problems")); + gtk_widget_add_css_class (dialog->secure_boot_icon, "error"); + status_description = g_strdup_printf ("%s\n\n%s\n\n%s", + /* TRANSLATORS: this is the first section of the decription. */ + _("Secure boot prevents malicious software from being loaded when the device " + "starts. It is currently turned on, but will not work due to having an invalid key."), + /* TRANSLATORS: this is the second section of description. */ + _("Secure boot problems can often be resolved from your computer's UEFI firmware settings " + "(BIOS) and your hardware manufacturer may provide information on how to do this."), + /* TRANSLATORS: this is the third section of description. */ + _("For help, contact your hardware manufacturer or IT support provider.")); + break; + + case SECURE_BOOT_STATE_INACTIVE: + case SECURE_BOOT_STATE_UNKNOWN: + /* TRANSLATORS: secure boot refers to the system firmware security mode */ + gtk_label_set_text (GTK_LABEL (dialog->secure_boot_title), _("Secure Boot is Turned Off")); + gtk_widget_add_css_class (dialog->secure_boot_icon, "error"); + status_description = g_strdup_printf ("%s\n\n%s", + /* TRANSLATORS: this is the first section of the description. */ + _("Secure boot prevents malicious software from being loaded when the device starts. It is " + "currently turned off."), + /* TRANSLATORS: this is the second section of the description. */ + _("Secure boot can often be turned on from your computer's UEFI firmware settings (BIOS). " + "For help, contact your hardware manufacturer or IT support provider.")); + break; + } + gtk_label_set_text (GTK_LABEL(dialog->secure_boot_description), status_description); + + return GTK_WIDGET (dialog); +} diff --git a/panels/firmware-security/cc-firmware-security-boot-dialog.h b/panels/firmware-security/cc-firmware-security-boot-dialog.h new file mode 100644 index 0000000..78b7d3a --- /dev/null +++ b/panels/firmware-security/cc-firmware-security-boot-dialog.h @@ -0,0 +1,37 @@ +/* cc-firmware-security-boot-dialog.h + * + * Copyright (C) 2021 Red Hat, Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * Author: Kate Hsuan + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#pragma once + +#include + +#include "cc-firmware-security-utils.h" + +G_BEGIN_DECLS + +#define CC_TYPE_FIRMWARE_SECURITY_BOOT_DIALOG (cc_firmware_security_boot_dialog_get_type ()) +G_DECLARE_FINAL_TYPE (CcFirmwareSecurityBootDialog, cc_firmware_security_boot_dialog, + CC, FIRMWARE_SECURITY_BOOT_DIALOG, GtkDialog) + +GtkWidget *cc_firmware_security_boot_dialog_new (SecureBootState secure_boot_state); + +G_END_DECLS diff --git a/panels/firmware-security/cc-firmware-security-boot-dialog.ui b/panels/firmware-security/cc-firmware-security-boot-dialog.ui new file mode 100644 index 0000000..8b8957e --- /dev/null +++ b/panels/firmware-security/cc-firmware-security-boot-dialog.ui @@ -0,0 +1,63 @@ + + + + diff --git a/panels/firmware-security/cc-firmware-security-dialog.c b/panels/firmware-security/cc-firmware-security-dialog.c new file mode 100644 index 0000000..2109aa5 --- /dev/null +++ b/panels/firmware-security/cc-firmware-security-dialog.c @@ -0,0 +1,442 @@ +/* cc-firmware-security-dialog.c + * + * Copyright (C) 2021 Red Hat, Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * Author: Kate Hsuan + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include + +#include "cc-firmware-security-panel.h" +#include "cc-firmware-security-dialog.h" +#include "cc-firmware-security-utils.h" + +struct _CcFirmwareSecurityDialog +{ + AdwWindow parent; + + GtkWidget *dialog_hsi_circle_box; + GtkWidget *dialog_hsi_circle_number; + + GtkWidget *hsi1_icon; + GtkWidget *hsi2_icon; + GtkWidget *hsi3_icon; + GtkWidget *hsi1_title; + GtkWidget *hsi2_title; + GtkWidget *hsi3_title; + + GtkWidget *firmware_security_dialog_title_label; + GtkWidget *firmware_security_dialog_body_label; + GtkWidget *firmware_security_dialog_min_row; + GtkWidget *firmware_security_dialog_basic_row; + GtkWidget *firmware_security_dialog_extend_row; + GtkWidget *firmware_security_dialog_hsi1_pg; + GtkWidget *firmware_security_dialog_hsi2_pg; + GtkWidget *firmware_security_dialog_hsi3_pg; + GtkWidget *firmware_security_dialog_hsi_label; + AdwLeaflet *leaflet; + AdwWindowTitle *second_page_title; + + gboolean is_created; + + GHashTable *hsi1_dict; + GHashTable *hsi2_dict; + GHashTable *hsi3_dict; + GHashTable *hsi4_dict; + + guint hsi_number; +}; + +G_DEFINE_TYPE (CcFirmwareSecurityDialog, cc_firmware_security_dialog, ADW_TYPE_WINDOW) + +static void +set_dialog_item_layer1 (CcFirmwareSecurityDialog *self, + const gchar *circle_str, + const gchar *title, + const gchar *body) +{ + g_autofree gchar *str = NULL; + + gtk_label_set_label (GTK_LABEL (self->dialog_hsi_circle_number), circle_str); + gtk_label_set_text (GTK_LABEL (self->firmware_security_dialog_title_label), title); + gtk_label_set_text (GTK_LABEL (self->firmware_security_dialog_body_label), body); + + if (self->hsi_number == G_MAXUINT) + { + gtk_widget_add_css_class (self->dialog_hsi_circle_box, "level1"); + gtk_widget_add_css_class (self->dialog_hsi_circle_number, "hsi1"); + gtk_widget_hide (self->hsi1_icon); + gtk_widget_hide (self->hsi2_icon); + gtk_widget_hide (self->hsi3_icon); + gtk_widget_hide (self->hsi1_title); + gtk_widget_hide (self->hsi2_title); + gtk_widget_hide (self->hsi3_title); + gtk_widget_hide (self->firmware_security_dialog_hsi_label); + return; + } + + gtk_image_set_from_icon_name (GTK_IMAGE (self->hsi1_icon), self->hsi_number >= 1 ? "emblem-ok" : "process-stop"); + gtk_label_set_text (GTK_LABEL (self->hsi1_title), self->hsi_number >= 1 ? _("Passed") : _("Failed")); + gtk_image_set_from_icon_name (GTK_IMAGE (self->hsi2_icon), self->hsi_number >= 2 ? "emblem-ok" : "process-stop"); + gtk_label_set_text (GTK_LABEL (self->hsi2_title), self->hsi_number >= 2 ? _("Passed") : _("Failed")); + gtk_image_set_from_icon_name (GTK_IMAGE (self->hsi3_icon), self->hsi_number >= 3 ? "emblem-ok" : "process-stop"); + gtk_label_set_text (GTK_LABEL (self->hsi3_title), self->hsi_number >= 3 ? _("Passed") : _("Failed")); + + gtk_widget_add_css_class (self->firmware_security_dialog_min_row, + self->hsi_number >= 1 ? "success-hsi-icon" : "error-hsi-icon"); + gtk_widget_add_css_class (self->firmware_security_dialog_min_row, + self->hsi_number >= 1 ? "success-title" : "error-title"); + gtk_widget_add_css_class (self->firmware_security_dialog_basic_row, + self->hsi_number >= 2 ? "success-hsi-icon" : "error-hsi-icon"); + gtk_widget_add_css_class (self->firmware_security_dialog_basic_row, + self->hsi_number >= 2 ? "success-title" : "error-title"); + gtk_widget_add_css_class (self->firmware_security_dialog_extend_row, + self->hsi_number >= 3 ? "success-hsi-icon" : "error-hsi-icon"); + gtk_widget_add_css_class (self->firmware_security_dialog_extend_row, + self->hsi_number >= 3 ? "success-title" : "error-title"); + + switch (self->hsi_number) + { + case 0: + gtk_widget_add_css_class (self->dialog_hsi_circle_box, "level0"); + gtk_widget_add_css_class (self->dialog_hsi_circle_number, "hsi0"); + break; + case 1: + gtk_widget_add_css_class (self->dialog_hsi_circle_box, "level1"); + gtk_widget_add_css_class (self->dialog_hsi_circle_number, "hsi1"); + break; + case 2: + gtk_widget_add_css_class (self->dialog_hsi_circle_box, "level2"); + gtk_widget_add_css_class (self->dialog_hsi_circle_number, "hsi2"); + break; + case 3: + case 4: + gtk_widget_add_css_class (self->dialog_hsi_circle_box, "level3"); + gtk_widget_add_css_class (self->dialog_hsi_circle_number, "hsi3"); + break; + } + + /* TRANSLATORS: HSI stands for Host Security ID and device refers to the computer as a whole */ + str = g_strdup_printf (_("Device conforms to HSI level %d"), self->hsi_number); + gtk_label_set_text (GTK_LABEL (self->firmware_security_dialog_hsi_label), str); +} + +static void +update_dialog (CcFirmwareSecurityDialog *self) +{ + switch (self->hsi_number) + { + case 0: + set_dialog_item_layer1 (self, + "0", + _("Security Level 0"), + _("This device has no protection against hardware security issues. This could " + "be because of a hardware or firmware configuration issue. It is " + "recommended to contact your IT support provider.")); + break; + + case 1: + set_dialog_item_layer1 (self, + "1", + _("Security Level 1"), + _("This device has minimal protection against hardware security issues. This " + "is the lowest device security level and only provides protection against " + "simple security threats.")); + break; + + case 2: + set_dialog_item_layer1 (self, + "2", + _("Security Level 2"), + _("This device has basic protection against hardware security issues. This " + "provides protection against some common security threats.")); + break; + + case 3: + case 4: + set_dialog_item_layer1 (self, + "3", + _("Security Level 3"), + _("This device has extended protection against hardware security issues. This " + "is the highest device security level and provides protection against " + "advanced security threats.")); + break; + + default: + set_dialog_item_layer1 (self, + "?", + _("Security Level"), + _("Security levels are not available for this device.")); + } +} + +static gchar * +fu_security_attr_get_description_for_dialog (FwupdSecurityAttr *attr) +{ + GString *str = g_string_new (attr->description); + + if (attr->flags & FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM && + attr->flags & FWUPD_SECURITY_ATTR_FLAG_ACTION_CONFIG_FW && + attr->flags & FWUPD_SECURITY_ATTR_FLAG_ACTION_CONFIG_FW) + { + g_string_append_printf (str, "\n\n%s %s", + /* TRANSLATORS: hardware manufacturer as in OEM */ + _("Contact your hardware manufacturer for help with security updates."), + /* TRANSLATORS: support technician as in someone with root */ + _("It might be possible to resolve this issue in the device’s UEFI " + "firmware settings, or by a support technician.")); + } + else if (attr->flags & FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM && + attr->flags & FWUPD_SECURITY_ATTR_FLAG_ACTION_CONFIG_FW) + { + g_string_append_printf (str, "\n\n%s %s", + /* TRANSLATORS: hardware manufacturer as in OEM */ + _("Contact your hardware manufacturer for help with security updates."), + _("It might be possible to resolve this issue in the device’s UEFI firmware settings.")); + } + else if (attr->flags & FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM) + { + g_string_append_printf (str, "\n\n%s", + /* TRANSLATORS: hardware manufacturer as in OEM */ + _("Contact your hardware manufacturer for help with security updates.")); + } + else if (attr->flags & FWUPD_SECURITY_ATTR_FLAG_ACTION_CONFIG_FW) + { + g_string_append_printf (str, "\n\n%s", + _("It might be possible to resolve this issue in the device’s UEFI firmware settings.")); + } + else if (attr->flags & FWUPD_SECURITY_ATTR_FLAG_ACTION_CONFIG_OS) + { + g_string_append_printf (str, "\n\n%s", + /* TRANSLATORS: support technician as in someone with root */ + _("It might be possible for a support technician to resolve this issue.")); + } + + return g_string_free (str, FALSE); +} + +static GtkWidget * +hsi_create_pg_row (const gchar *icon_name, + const gchar *style, + FwupdSecurityAttr *attr) +{ + GtkWidget *row; + GtkWidget *status_icon; + GtkWidget *status_label; + GtkWidget *actions_parent; + const gchar *result_str = NULL; + + row = adw_expander_row_new (); + adw_preferences_row_set_title (ADW_PREFERENCES_ROW (row), attr->title); + + result_str = fwupd_security_attr_result_to_string(attr->result); + if (result_str) + { + status_label = gtk_label_new (result_str); + if (firmware_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) + status_icon = gtk_image_new_from_icon_name ("emblem-ok"); + else + status_icon = gtk_image_new_from_icon_name ("process-stop"); + + adw_expander_row_add_action (ADW_EXPANDER_ROW (row), status_label); + adw_expander_row_add_action (ADW_EXPANDER_ROW (row), status_icon); + + gtk_widget_add_css_class (status_icon, "icon"); + gtk_widget_add_css_class (status_label, "hsi_label"); + + actions_parent = gtk_widget_get_parent (status_icon); + gtk_box_set_spacing (GTK_BOX (actions_parent), 6); + gtk_widget_set_margin_end (actions_parent, 12); + } + + if (attr->description != NULL) + { + GtkWidget *subrow = adw_action_row_new (); + g_autofree gchar *str = fu_security_attr_get_description_for_dialog (attr); + adw_action_row_set_subtitle (ADW_ACTION_ROW (subrow), str); + adw_expander_row_add_row (ADW_EXPANDER_ROW (row), subrow); + gtk_widget_add_css_class (subrow, "security-description-row"); + } + else + { + adw_expander_row_set_enable_expansion (ADW_EXPANDER_ROW (row), FALSE); + gtk_widget_add_css_class (row, "hide-arrow"); + } + + return row; +} + +static void +update_hsi_listbox (CcFirmwareSecurityDialog *self, + const gint hsi_level) +{ + g_autoptr (GList) hash_keys = NULL; + GHashTable *hsi_dict = NULL; + GtkWidget *pg_row; + GtkWidget *hsi_pg; + + switch (hsi_level) + { + case 1: + hsi_dict = self->hsi1_dict; + hsi_pg = self->firmware_security_dialog_hsi1_pg; + break; + case 2: + hsi_dict = self->hsi2_dict; + hsi_pg = self->firmware_security_dialog_hsi2_pg; + break; + case 3: + hsi_dict = self->hsi3_dict; + hsi_pg = self->firmware_security_dialog_hsi3_pg; + break; + case 4: + hsi_dict = self->hsi4_dict; + hsi_pg = self->firmware_security_dialog_hsi3_pg; + break; + } + + hash_keys = g_hash_table_get_keys (hsi_dict); + for (GList *item = g_list_first (hash_keys); item != NULL; item = g_list_next (item)) + { + FwupdSecurityAttr *attr = g_hash_table_lookup (hsi_dict, item->data); + if (g_strcmp0 (attr->appstream_id, FWUPD_SECURITY_ATTR_ID_SUPPORTED_CPU) == 0) + continue; + if (attr->title == NULL) + continue; + if (firmware_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) + { + pg_row = hsi_create_pg_row ("emblem-ok", "color_green", attr); + gtk_widget_add_css_class (pg_row, "success-icon"); + gtk_widget_add_css_class (pg_row, "success-title"); + } + else + { + pg_row = hsi_create_pg_row ("process-stop", "color_dim", attr); + gtk_widget_add_css_class (pg_row, "error-icon"); + gtk_widget_add_css_class (pg_row, "error-title"); + } + adw_preferences_group_add (ADW_PREFERENCES_GROUP (hsi_pg), GTK_WIDGET (pg_row)); + } + self->is_created = TRUE; +} + +static void +on_hsi_clicked_cb (GtkWidget *widget, + CcFirmwareSecurityDialog *self) +{ + adw_leaflet_navigate (self->leaflet, ADW_NAVIGATION_DIRECTION_FORWARD); + + if (!self->is_created) + { + update_hsi_listbox (self, 1); + update_hsi_listbox (self, 2); + update_hsi_listbox (self, 3); + update_hsi_listbox (self, 4); + self->is_created = TRUE; + } + + if (widget == self->firmware_security_dialog_min_row) + { + adw_window_title_set_title (self->second_page_title, _("Security Level 1")); + gtk_widget_set_visible (self->firmware_security_dialog_hsi1_pg, TRUE); + } + else if (widget == self->firmware_security_dialog_basic_row) + { + adw_window_title_set_title (self->second_page_title, _("Security Level 2")); + gtk_widget_set_visible (self->firmware_security_dialog_hsi2_pg, TRUE); + } + else if (widget == self->firmware_security_dialog_extend_row) + { + adw_window_title_set_title (self->second_page_title, _("Security Level 3")); + gtk_widget_set_visible (self->firmware_security_dialog_hsi3_pg, TRUE); + } +} + +static void +on_fw_back_button_clicked_cb (GtkWidget *widget, + gpointer data) +{ + CcFirmwareSecurityDialog *self = CC_FIRMWARE_SECURITY_DIALOG (data); + + adw_leaflet_navigate (self->leaflet, ADW_NAVIGATION_DIRECTION_BACK); + + gtk_widget_set_visible (self->firmware_security_dialog_hsi1_pg, FALSE); + gtk_widget_set_visible (self->firmware_security_dialog_hsi2_pg, FALSE); + gtk_widget_set_visible (self->firmware_security_dialog_hsi3_pg, FALSE); +} + +static void +cc_firmware_security_dialog_class_init (CcFirmwareSecurityDialogClass *klass) +{ + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/firmware-security/cc-firmware-security-dialog.ui"); + + gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, dialog_hsi_circle_box); + gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, dialog_hsi_circle_number); + gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, hsi1_icon); + gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, hsi2_icon); + gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, hsi3_icon); + gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, hsi1_title); + gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, hsi2_title); + gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, hsi3_title); + gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, firmware_security_dialog_title_label); + gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, firmware_security_dialog_body_label); + gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, firmware_security_dialog_hsi_label); + gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, firmware_security_dialog_min_row); + gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, firmware_security_dialog_basic_row); + gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, firmware_security_dialog_extend_row); + gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, firmware_security_dialog_hsi1_pg); + gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, firmware_security_dialog_hsi2_pg); + gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, firmware_security_dialog_hsi3_pg); + gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, leaflet); + gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, second_page_title); + + gtk_widget_class_bind_template_callback (widget_class, on_hsi_clicked_cb); + gtk_widget_class_bind_template_callback (widget_class, on_fw_back_button_clicked_cb); +} + +static void +cc_firmware_security_dialog_init (CcFirmwareSecurityDialog *dialog) +{ + gtk_widget_init_template (GTK_WIDGET (dialog)); + load_custom_css ("/org/gnome/control-center/firmware-security/security-level.css"); +} + +GtkWidget * +cc_firmware_security_dialog_new (guint hsi_number, + GHashTable *hsi1_dict, + GHashTable *hsi2_dict, + GHashTable *hsi3_dict, + GHashTable *hsi4_dict) +{ + CcFirmwareSecurityDialog *dialog; + + dialog = g_object_new (CC_TYPE_FIRMWARE_SECURITY_DIALOG, NULL); + dialog->hsi_number = hsi_number; + dialog->is_created = FALSE; + dialog->hsi1_dict = hsi1_dict; + dialog->hsi2_dict = hsi2_dict; + dialog->hsi3_dict = hsi3_dict; + dialog->hsi4_dict = hsi4_dict; + update_dialog (dialog); + + return GTK_WIDGET (dialog); +} diff --git a/panels/firmware-security/cc-firmware-security-dialog.h b/panels/firmware-security/cc-firmware-security-dialog.h new file mode 100644 index 0000000..3857fb2 --- /dev/null +++ b/panels/firmware-security/cc-firmware-security-dialog.h @@ -0,0 +1,38 @@ +/* cc-firmware-security-dialog.h + * + * Copyright (C) 2021 Red Hat, Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * Author: Kate Hsuan + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define CC_TYPE_FIRMWARE_SECURITY_DIALOG (cc_firmware_security_dialog_get_type ()) +G_DECLARE_FINAL_TYPE (CcFirmwareSecurityDialog, cc_firmware_security_dialog, CC, FIRMWARE_SECURITY_DIALOG, AdwWindow) + +GtkWidget * cc_firmware_security_dialog_new (guint hsi_number, + GHashTable *hsi1_dict, + GHashTable *hsi2_dict, + GHashTable *hsi3_dict, + GHashTable *hsi4_dict); + +G_END_DECLS diff --git a/panels/firmware-security/cc-firmware-security-dialog.ui b/panels/firmware-security/cc-firmware-security-dialog.ui new file mode 100644 index 0000000..c1a3a67 --- /dev/null +++ b/panels/firmware-security/cc-firmware-security-dialog.ui @@ -0,0 +1,271 @@ + + + + diff --git a/panels/firmware-security/cc-firmware-security-panel.c b/panels/firmware-security/cc-firmware-security-panel.c new file mode 100644 index 0000000..d48e7ab --- /dev/null +++ b/panels/firmware-security/cc-firmware-security-panel.c @@ -0,0 +1,717 @@ +/* cc-firmware-security-panel.c + * + * Copyright (C) 2021 Red Hat, Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * Author: Kate Hsuan + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "shell/cc-application.h" + +#include "cc-firmware-security-panel.h" +#include "cc-firmware-security-resources.h" +#include "cc-firmware-security-dialog.h" +#include "cc-firmware-security-boot-dialog.h" +#include "cc-firmware-security-utils.h" +#include "cc-util.h" + +#include +#include + +struct _CcfirmwareSecurityPanel +{ + CcPanel parent_instance; + + GtkButton *hsi_button; + GtkButton *secure_boot_button; + + /* HSI button */ + GtkWidget *hsi_grid; + + GtkWidget *hsi_circle_box; + GtkWidget *hsi_circle_number; + + GtkWidget *hsi_label; + GtkWidget *hsi_description; + + /* secure boot button */ + GtkWidget *secure_boot_button_grid; + GtkWidget *secure_boot_icon; + GtkWidget *secure_boot_label; + GtkWidget *secure_boot_description; + + /* event listbox */ + GtkWidget *firmware_security_log_listbox; + GtkWidget *firmware_security_log_stack; + GtkWidget *firmware_security_log_pgroup; + + GDBusProxy *bus_proxy; + GDBusProxy *properties_bus_proxy; + + GHashTable *hsi1_dict; + GHashTable *hsi2_dict; + GHashTable *hsi3_dict; + GHashTable *hsi4_dict; + + guint hsi_number; + SecureBootState secure_boot_state; +}; + +CC_PANEL_REGISTER (CcfirmwareSecurityPanel, cc_firmware_security_panel) + +static void +set_hsi_button_view (CcfirmwareSecurityPanel *self); + +static void +set_secure_boot_button_view (CcfirmwareSecurityPanel *self) +{ + FwupdSecurityAttr *attr; + guint64 sb_flags = 0; + guint64 pk_flags = 0; + + /* get HSI-1 flags if set */ + attr = g_hash_table_lookup (self->hsi1_dict, FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT); + if (attr != NULL) + sb_flags = attr->flags; + attr = g_hash_table_lookup (self->hsi1_dict, FWUPD_SECURITY_ATTR_ID_UEFI_PK); + if (attr != NULL) + pk_flags = attr->flags; + + /* enabled and valid */ + if ((sb_flags & FWUPD_SECURITY_ATTR_FLAG_SUCCESS) > 0 && + (pk_flags & FWUPD_SECURITY_ATTR_FLAG_SUCCESS) > 0) + { + self->secure_boot_state = SECURE_BOOT_STATE_ACTIVE; + } + else if ((sb_flags & FWUPD_SECURITY_ATTR_RESULT_ENABLED) > 0) + { + self->secure_boot_state = SECURE_BOOT_STATE_PROBLEMS; + } + else + { + self->secure_boot_state = SECURE_BOOT_STATE_INACTIVE; + } + + /* update UI */ + if (self->secure_boot_state == SECURE_BOOT_STATE_ACTIVE) + { + gtk_label_set_text (GTK_LABEL (self->secure_boot_label), _("Secure Boot is Active")); + gtk_label_set_text (GTK_LABEL (self->secure_boot_description), _("Protected against malicious software when the device starts.")); + gtk_image_set_from_icon_name (GTK_IMAGE (self->secure_boot_icon), "channel-secure-symbolic"); + gtk_widget_add_css_class (self->secure_boot_icon, "good"); + } + else if (self->secure_boot_state == SECURE_BOOT_STATE_PROBLEMS) + { + gtk_label_set_text (GTK_LABEL (self->secure_boot_label), _("Secure Boot has Problems")); + gtk_label_set_text (GTK_LABEL (self->secure_boot_description), _("Some protection when the device is started.")); + gtk_widget_add_css_class (self->secure_boot_icon, "error"); + } + else + { + gtk_label_set_text (GTK_LABEL (self->secure_boot_label), _("Secure Boot is Off")); + gtk_label_set_text (GTK_LABEL (self->secure_boot_description), _("No protection when the device is started.")); + gtk_widget_add_css_class (self->secure_boot_icon, "error"); + } +} + +static gchar * +fu_security_attr_get_description_for_eventlog (FwupdSecurityAttr *attr) +{ + GString *str = g_string_new (attr->description); + + /* nothing to do */ + if (attr->flags & FWUPD_SECURITY_ATTR_FLAG_SUCCESS) + return g_string_free (str, FALSE); + + if (attr->flags & FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM && + attr->flags & FWUPD_SECURITY_ATTR_FLAG_ACTION_CONFIG_FW) + { + g_string_append_printf (str, "\n\n%s", + /* TRANSLATORS: this is to explain an event that has already happened */ + _("This issue could have been caused by a change in UEFI firmware " + "settings, an operating system configuration change, or because of " + "malicious software on this system.")); + } + else if (attr->flags & FWUPD_SECURITY_ATTR_FLAG_ACTION_CONFIG_FW) + { + g_string_append_printf (str, "\n\n%s", + /* TRANSLATORS: this is to explain an event that has already happened */ + _("This issue could have been caused by a change in the UEFI firmware " + "settings, or because of malicious software on this system.")); + } + else if (attr->flags & FWUPD_SECURITY_ATTR_FLAG_ACTION_CONFIG_OS) + { + g_string_append_printf (str, "\n\n%s", + /* TRANSLATORS: this is to explain an event that has already happened */ + _("This issue could have been caused by an operating system configuration " + "change, or because of malicious software on this system.")); + } + + return g_string_free (str, FALSE); +} + +static void +parse_event_variant_iter (CcfirmwareSecurityPanel *self, + GVariantIter *iter) +{ + g_autofree gchar *date_string = NULL; + g_autoptr (GDateTime) date = NULL; + g_autoptr (FwupdSecurityAttr) attr = fu_security_attr_new_from_variant(iter); + GtkWidget *row; + + /* unknown to us */ + if (attr->appstream_id == NULL || attr->title == NULL) + return; + + /* skip events that have either been added or removed with no prior value */ + if (attr->result == FWUPD_SECURITY_ATTR_RESULT_UNKNOWN || + attr->result_fallback == FWUPD_SECURITY_ATTR_RESULT_UNKNOWN) + return; + + /* build new row */ + date = g_date_time_new_from_unix_local (attr->timestamp); + date_string = g_date_time_format (date, "\%F \%H:\%m:\%S"); + + row = adw_expander_row_new (); + if (attr->flags & FWUPD_SECURITY_ATTR_FLAG_SUCCESS) + { + adw_expander_row_set_icon_name (ADW_EXPANDER_ROW (row), "emblem-ok"); + gtk_widget_add_css_class (row, "success-icon"); + } + else + { + adw_expander_row_set_icon_name (ADW_EXPANDER_ROW (row), "process-stop"); + gtk_widget_add_css_class (row, "error-icon"); + } + + if (attr->description != NULL) + { + GtkWidget *subrow = adw_action_row_new (); + g_autofree gchar *str = fu_security_attr_get_description_for_eventlog (attr); + adw_action_row_set_subtitle (ADW_ACTION_ROW (subrow), str); + adw_expander_row_add_row (ADW_EXPANDER_ROW (row), subrow); + } + else + { + adw_expander_row_set_enable_expansion (ADW_EXPANDER_ROW (row), FALSE); + gtk_widget_add_css_class (row, "hide-arrow"); + } + + adw_preferences_row_set_title (ADW_PREFERENCES_ROW (row), attr->title); + adw_expander_row_set_subtitle (ADW_EXPANDER_ROW (row), date_string); + adw_preferences_group_add (ADW_PREFERENCES_GROUP (self->firmware_security_log_pgroup), GTK_WIDGET (row)); + + adw_view_stack_set_visible_child_name (ADW_VIEW_STACK (self->firmware_security_log_stack), "page2"); +} + +static void +parse_variant_iter (CcfirmwareSecurityPanel *self, + GVariantIter *iter) +{ + g_autoptr (FwupdSecurityAttr) attr = fu_security_attr_new_from_variant(iter); + const gchar *appstream_id = attr->appstream_id; + + /* invalid */ + if (appstream_id == NULL) + return; + + /* in fwupd <= 1.8.3 org.fwupd.hsi.Uefi.SecureBoot was incorrectly marked as HSI-0, + * so lower the HSI number forcefully if this attribute failed -- the correct thing + * to do of course is to update fwupd to a newer build */ + if (g_strcmp0 (attr->appstream_id, FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT) == 0 && + (attr->flags & FWUPD_SECURITY_ATTR_FLAG_SUCCESS) == 0) + { + self->hsi_number = 0; + set_hsi_button_view (self); + } + + /* insert into correct hash table */ + switch (attr->hsi_level) + { + case 1: + g_hash_table_insert (self->hsi1_dict, + g_strdup (appstream_id), + g_steal_pointer (&attr)); + break; + case 2: + g_hash_table_insert (self->hsi2_dict, + g_strdup (appstream_id), + g_steal_pointer (&attr)); + break; + case 3: + g_hash_table_insert (self->hsi3_dict, + g_strdup (appstream_id), + g_steal_pointer (&attr)); + break; + case 4: + g_hash_table_insert (self->hsi4_dict, + g_strdup (appstream_id), + g_steal_pointer (&attr)); + break; + } +} + +static void +parse_data_from_variant (CcfirmwareSecurityPanel *self, + GVariant *value, + const gboolean is_event) +{ + const gchar *type_string; + g_autoptr (GVariantIter) iter = NULL; + + type_string = g_variant_get_type_string (value); + if (g_strcmp0 (type_string, "(a{sv})") == 0) + { + g_variant_get (value, "(a{sv})", &iter); + if (is_event) + parse_event_variant_iter (self, iter); + else + parse_variant_iter (self, iter); + } + else if (g_strcmp0 (type_string, "a{sv}") == 0) + { + g_variant_get (value, "a{sv}", &iter); + if (is_event) + parse_event_variant_iter (self, iter); + else + parse_variant_iter (self, iter); + } + else + { + g_warning ("type %s not known", type_string); + } +} + +static void +parse_array_from_variant (CcfirmwareSecurityPanel *self, + GVariant *value, + const gboolean is_event) +{ + gsize sz; + g_autoptr (GVariant) untuple = NULL; + + untuple = g_variant_get_child_value (value, 0); + sz = g_variant_n_children (untuple); + for (guint i = 0; i < sz; i++) + { + g_autoptr (GVariant) data = NULL; + data = g_variant_get_child_value (untuple, i); + if (is_event) + parse_data_from_variant (self, data, TRUE); + else + parse_data_from_variant (self, data, FALSE); + } +} + +static void +on_bus_event_done_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr (GError) error = NULL; + g_autoptr (GVariant) val = NULL; + CcfirmwareSecurityPanel *self = CC_FIRMWARE_SECURITY_PANEL (user_data); + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) + { + g_warning ("failed to get Security Attribute Event: %s", error->message); + return; + } + + parse_array_from_variant (self, val, TRUE); +} + +static void +on_bus_done (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + CcfirmwareSecurityPanel *self = CC_FIRMWARE_SECURITY_PANEL (user_data); + g_autoptr (GError) error = NULL; + g_autoptr (GVariant) val = NULL; + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) + { + CcApplication *application = CC_APPLICATION (g_application_get_default ()); + g_warning ("failed to get Security Attribute: %s", error->message); + cc_shell_model_set_panel_visibility (cc_application_get_model (application), + "firmware-security", + CC_PANEL_HIDDEN); + set_secure_boot_button_view (self); + return; + } + + parse_array_from_variant (self, val, FALSE); + set_secure_boot_button_view (self); +} + +static void +on_bus_ready_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr (GError) error = NULL; + CcfirmwareSecurityPanel *self = CC_FIRMWARE_SECURITY_PANEL (user_data); + + self->bus_proxy = g_dbus_proxy_new_for_bus_finish (res, &error); + if (self->bus_proxy == NULL) + { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("failed to connect fwupd: %s", error->message); + + return; + } + + g_dbus_proxy_call (self->bus_proxy, + "GetHostSecurityAttrs", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + cc_panel_get_cancellable (CC_PANEL (self)), + on_bus_done, + self); + g_dbus_proxy_call (self->bus_proxy, + "GetHostSecurityEvents", + g_variant_new ("(u)", + 100), + G_DBUS_CALL_FLAGS_NONE, + -1, + cc_panel_get_cancellable (CC_PANEL (self)), + on_bus_event_done_cb, + self); +} + +static void +on_hsi_button_clicked_cb (GtkWidget *widget, + gpointer data) +{ + GtkWidget *toplevel; + CcShell *shell; + GtkWidget *dialog; + CcfirmwareSecurityPanel *self = CC_FIRMWARE_SECURITY_PANEL (data); + + dialog = cc_firmware_security_dialog_new (self->hsi_number, + self->hsi1_dict, + self->hsi2_dict, + self->hsi3_dict, + self->hsi4_dict); + shell = cc_panel_get_shell (CC_PANEL (self)); + toplevel = cc_shell_get_toplevel (shell); + gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (toplevel)); + gtk_widget_show (GTK_WIDGET (dialog)); +} + +static void +on_secure_boot_button_clicked_cb (GtkWidget *widget, + gpointer data) +{ + GtkWidget *toplevel; + CcShell *shell; + GtkWidget *boot_dialog; + CcfirmwareSecurityPanel *self = CC_FIRMWARE_SECURITY_PANEL (data); + + boot_dialog = cc_firmware_security_boot_dialog_new (self->secure_boot_state); + shell = cc_panel_get_shell (CC_PANEL (self)); + toplevel = cc_shell_get_toplevel (shell); + gtk_window_set_transient_for (GTK_WINDOW (boot_dialog), GTK_WINDOW (toplevel)); + gtk_widget_show (boot_dialog); +} + +static void +set_hsi_button_view_contain (CcfirmwareSecurityPanel *self, + guint hsi_number, + gchar *title, + const gchar *description) +{ + switch (hsi_number) + { + case 0: + gtk_label_set_label (GTK_LABEL (self->hsi_circle_number), "0"); + gtk_widget_add_css_class (self->hsi_circle_box, "level0"); + gtk_widget_add_css_class (self->hsi_circle_number, "hsi0"); + break; + case 1: + gtk_label_set_label (GTK_LABEL (self->hsi_circle_number), "1"); + gtk_widget_add_css_class (self->hsi_circle_box, "level1"); + gtk_widget_add_css_class (self->hsi_circle_number, "hsi1"); + break; + case 2: + gtk_label_set_label (GTK_LABEL (self->hsi_circle_number), "2"); + gtk_widget_add_css_class (self->hsi_circle_box, "level2"); + gtk_widget_add_css_class (self->hsi_circle_number, "hsi2"); + break; + case 3: + case 4: + gtk_label_set_label (GTK_LABEL (self->hsi_circle_number), "3"); + gtk_widget_add_css_class (self->hsi_circle_box, "level3"); + gtk_widget_add_css_class (self->hsi_circle_number, "hsi3"); + break; + default: + gtk_label_set_label (GTK_LABEL (self->hsi_circle_number), "?"); + gtk_widget_add_css_class (self->hsi_circle_box, "level1"); + gtk_widget_add_css_class (self->hsi_circle_number, "hsi1"); + break; + } + + gtk_label_set_text (GTK_LABEL (self->hsi_label), title); + gtk_label_set_text (GTK_LABEL (self->hsi_description), description); +} + +static void +set_hsi_button_view (CcfirmwareSecurityPanel *self) +{ + switch (self->hsi_number) + { + case 0: + set_hsi_button_view_contain (self, + self->hsi_number, + /* TRANSLATORS: in reference to firmware protection: 0/4 stars */ + _("Security Level 0"), + _("Exposed to serious security threats.")); + break; + case 1: + set_hsi_button_view_contain (self, + self->hsi_number, + /* TRANSLATORS: in reference to firmware protection: 1/4 stars */ + _("Security Level 1"), + _("Limited protection against simple security threats.")); + break; + case 2: + set_hsi_button_view_contain (self, + self->hsi_number, + /* TRANSLATORS: in reference to firmware protection: 2/4 stars */ + _("Security Level 2"), + _("Protected against common security threats.")); + break; + case 3: + set_hsi_button_view_contain (self, + self->hsi_number, + /* TRANSLATORS: in reference to firmware protection: 3/4 stars */ + _("Security Level 3"), + _("Protected against a wide range of security threats.")); + break; + case 4: + set_hsi_button_view_contain (self, + /* Based on current HSI definition, the max HSI value would be 3. */ + 3, + /* TRANSLATORS: in reference to firmware protection: 4/4 stars */ + _("Comprehensive Protection"), + _("Protected against a wide range of security threats.")); + break; + case G_MAXUINT: + set_hsi_button_view_contain (self, + self->hsi_number, + /* TRANSLATORS: in reference to firmware protection: ??? stars */ + _("Security Level"), + _("Security levels are not available for this device.")); + break; + default: + g_warning ("incorrect HSI number %u", self->hsi_number); + } +} + +static void +on_properties_bus_done_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + g_autoptr (GError) error = NULL; + g_autoptr (GVariant) val = NULL; + const gchar *hsi_str = NULL; + CcfirmwareSecurityPanel *self = CC_FIRMWARE_SECURITY_PANEL (user_data); + + val = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), res, &error); + if (val == NULL) + { + g_warning ("failed to get HSI number"); + return; + } + + /* parse value */ + hsi_str = g_variant_get_data (val); + if (hsi_str != NULL && g_str_has_prefix (hsi_str, "HSI:INVALID")) + { + self->hsi_number = G_MAXUINT; + } + else if (hsi_str != NULL && g_str_has_prefix (hsi_str, "HSI:")) + { + self->hsi_number = g_ascii_strtoll (hsi_str + 4, NULL, 10); + } + set_hsi_button_view (self); +} + +static void +on_properties_bus_ready_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + CcfirmwareSecurityPanel *self = CC_FIRMWARE_SECURITY_PANEL (user_data); + g_autoptr (GError) error = NULL; + + self->properties_bus_proxy = g_dbus_proxy_new_for_bus_finish (res, &error); + if (self->properties_bus_proxy == NULL) + { + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_warning ("failed to connect fwupd: %s", error->message); + + return; + } + + g_dbus_proxy_call (self->properties_bus_proxy, + "Get", + g_variant_new ("(ss)", + "org.freedesktop.fwupd", + "HostSecurityId"), + G_DBUS_CALL_FLAGS_NONE, + -1, + cc_panel_get_cancellable (CC_PANEL (self)), + on_properties_bus_done_cb, + self); +} + +static void +update_panel_visibility (const gchar *chassis_type) +{ + CcApplication *application; + gboolean visible = TRUE; + + /* there's no point showing this */ + if (g_strcmp0 (chassis_type, "vm") == 0 || g_strcmp0 (chassis_type, "") == 0) + visible = FALSE; + application = CC_APPLICATION (g_application_get_default ()); + cc_shell_model_set_panel_visibility (cc_application_get_model (application), + "firmware-security", + visible ? CC_PANEL_VISIBLE : CC_PANEL_HIDDEN); + g_debug ("Firmware Security panel visible: %s as chassis was %s", + visible ? "yes" : "no", + chassis_type); +} + +void +cc_firmware_security_panel_static_init_func (void) +{ + g_autoptr(GDBusConnection) connection = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) inner = NULL; + g_autoptr(GVariant) variant = NULL; + + connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); + if (!connection) + { + g_warning ("system bus not available: %s", error->message); + return; + } + variant = g_dbus_connection_call_sync (connection, + "org.freedesktop.hostname1", + "/org/freedesktop/hostname1", + "org.freedesktop.DBus.Properties", + "Get", + g_variant_new ("(ss)", + "org.freedesktop.hostname1", + "Chassis"), + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + if (!variant) + { + g_warning ("Cannot get org.freedesktop.hostname1.Chassis: %s", error->message); + return; + } + g_variant_get (variant, "(v)", &inner); + update_panel_visibility (g_variant_get_string (inner, NULL)); +} + +static void +cc_firmware_security_panel_finalize (GObject *object) +{ + CcfirmwareSecurityPanel *self = CC_FIRMWARE_SECURITY_PANEL (object); + + g_clear_pointer (&self->hsi1_dict, g_hash_table_unref); + g_clear_pointer (&self->hsi2_dict, g_hash_table_unref); + g_clear_pointer (&self->hsi3_dict, g_hash_table_unref); + g_clear_pointer (&self->hsi4_dict, g_hash_table_unref); + + g_clear_object (&self->bus_proxy); + g_clear_object (&self->properties_bus_proxy); + + G_OBJECT_CLASS (cc_firmware_security_panel_parent_class)->finalize (object); +} + + +static void +cc_firmware_security_panel_class_init (CcfirmwareSecurityPanelClass *klass) +{ + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = cc_firmware_security_panel_finalize; + + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/firmware-security/cc-firmware-security-panel.ui"); + + gtk_widget_class_bind_template_child (widget_class, CcfirmwareSecurityPanel, firmware_security_log_pgroup); + gtk_widget_class_bind_template_child (widget_class, CcfirmwareSecurityPanel, firmware_security_log_stack); + gtk_widget_class_bind_template_child (widget_class, CcfirmwareSecurityPanel, hsi_button); + gtk_widget_class_bind_template_child (widget_class, CcfirmwareSecurityPanel, hsi_description); + gtk_widget_class_bind_template_child (widget_class, CcfirmwareSecurityPanel, hsi_circle_box); + gtk_widget_class_bind_template_child (widget_class, CcfirmwareSecurityPanel, hsi_circle_number); + gtk_widget_class_bind_template_child (widget_class, CcfirmwareSecurityPanel, hsi_label); + gtk_widget_class_bind_template_child (widget_class, CcfirmwareSecurityPanel, secure_boot_button); + gtk_widget_class_bind_template_child (widget_class, CcfirmwareSecurityPanel, secure_boot_description); + gtk_widget_class_bind_template_child (widget_class, CcfirmwareSecurityPanel, secure_boot_icon); + gtk_widget_class_bind_template_child (widget_class, CcfirmwareSecurityPanel, secure_boot_label); + + gtk_widget_class_bind_template_callback (widget_class, on_hsi_button_clicked_cb); + gtk_widget_class_bind_template_callback (widget_class, on_secure_boot_button_clicked_cb); +} + +static void +cc_firmware_security_panel_init (CcfirmwareSecurityPanel *self) +{ + g_resources_register (cc_firmware_security_get_resource ()); + + gtk_widget_init_template (GTK_WIDGET (self)); + + self->hsi1_dict = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) fu_security_attr_free); + self->hsi2_dict = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) fu_security_attr_free); + self->hsi3_dict = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) fu_security_attr_free); + self->hsi4_dict = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) fu_security_attr_free); + + load_custom_css ("/org/gnome/control-center/firmware-security/security-level.css"); + + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.freedesktop.fwupd", + "/", + "org.freedesktop.DBus.Properties", + cc_panel_get_cancellable (CC_PANEL (self)), + on_properties_bus_ready_cb, + self); + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.freedesktop.fwupd", + "/", + "org.freedesktop.fwupd", + cc_panel_get_cancellable (CC_PANEL (self)), + on_bus_ready_cb, + self); +} diff --git a/panels/firmware-security/cc-firmware-security-panel.h b/panels/firmware-security/cc-firmware-security-panel.h new file mode 100644 index 0000000..1c7a024 --- /dev/null +++ b/panels/firmware-security/cc-firmware-security-panel.h @@ -0,0 +1,34 @@ +/* cc-firmware-security-panel.h + * + * Copyright (C) 2021 Red Hat, Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * Author: Kate Hsuan + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define CC_TYPE_FIRMWARE_SECURITY_PANEL (cc_firmware_security_panel_get_type ()) +G_DECLARE_FINAL_TYPE (CcfirmwareSecurityPanel, cc_firmware_security_panel, CC, FIRMWARE_SECURITY_PANEL, CcPanel) + +void cc_firmware_security_panel_static_init_func (void); + +G_END_DECLS diff --git a/panels/firmware-security/cc-firmware-security-panel.ui b/panels/firmware-security/cc-firmware-security-panel.ui new file mode 100644 index 0000000..f975ee7 --- /dev/null +++ b/panels/firmware-security/cc-firmware-security-panel.ui @@ -0,0 +1,176 @@ + + + + diff --git a/panels/firmware-security/cc-firmware-security-utils.c b/panels/firmware-security/cc-firmware-security-utils.c new file mode 100644 index 0000000..f6df3ae --- /dev/null +++ b/panels/firmware-security/cc-firmware-security-utils.c @@ -0,0 +1,373 @@ +/* cc-firmware-security-utils.c + * + * Copyright (C) 2021 Red Hat, Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * Author: Kate Hsuan + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include + +#include "cc-firmware-security-utils.h" + +/* we don't need to keep this up to date, as any new attrs added by fwupd >= 1.8.3 will also + * come with translated titles *and* descriptions */ +static const gchar * +fu_security_attr_get_title_fallback (const gchar *appstream_id) +{ + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_SPI_BIOSWE) == 0) + { + /* TRANSLATORS: Title: firmware refers to the flash chip in the computer */ + return _("Firmware Write Protection"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_SPI_BLE) == 0) + { + /* TRANSLATORS: Title: firmware refers to the flash chip in the computer */ + return _("Firmware Write Protection Lock"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_SPI_SMM_BWP) == 0) + { + /* TRANSLATORS: Title: SPI refers to the flash chip in the computer */ + return _("Firmware BIOS Region"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_SPI_DESCRIPTOR) == 0) + { + /* TRANSLATORS: Title: firmware refers to the flash chip in the computer */ + return _("Firmware BIOS Descriptor"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_PREBOOT_DMA_PROTECTION) == 0) + { + /* TRANSLATORS: Title: DMA as in https://en.wikipedia.org/wiki/DMA_attack */ + return _("Pre-boot DMA Protection"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ENABLED) == 0) + { + /* TRANSLATORS: Title: BootGuard is a trademark from Intel */ + return _("Intel BootGuard"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_VERIFIED) == 0) + { + /* TRANSLATORS: Title: BootGuard is a trademark from Intel, + * verified boot refers to the way the boot process is verified */ + return _("Intel BootGuard Verified Boot"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ACM) == 0) + { + /* TRANSLATORS: Title: BootGuard is a trademark from Intel, + * ACM means to verify the integrity of Initial Boot Block */ + return _("Intel BootGuard ACM Protected"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_POLICY) == 0) + { + /* TRANSLATORS: Title: BootGuard is a trademark from Intel, + * error policy is what to do on failure */ + return _("Intel BootGuard Error Policy"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_OTP) == 0) + { + /* TRANSLATORS: Title: BootGuard is a trademark from Intel */ + return _("Intel BootGuard Fuse"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_CET_ENABLED) == 0) + { + /* TRANSLATORS: Title: CET = Control-flow Enforcement Technology, + * enabled means supported by the processor */ + return _("Intel CET Enabled"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_CET_ACTIVE) == 0) + { + /* TRANSLATORS: Title: CET = Control-flow Enforcement Technology, + * active means being used by the OS */ + return _("Intel CET Active"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_INTEL_SMAP) == 0) + { + /* TRANSLATORS: Title: SMAP = Supervisor Mode Access Prevention */ + return _("Intel SMAP"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_ENCRYPTED_RAM) == 0) + { + /* TRANSLATORS: Title: Memory contents are encrypted, e.g. Intel TME */ + return _("Encrypted RAM"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_IOMMU) == 0) + { + /* TRANSLATORS: Title: + * https://en.wikipedia.org/wiki/Input%E2%80%93output_memory_management_unit */ + return _("IOMMU Protection"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_KERNEL_LOCKDOWN) == 0) + { + /* TRANSLATORS: Title: lockdown is a security mode of the kernel */ + return _("Linux Kernel Lockdown"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_KERNEL_TAINTED) == 0) + { + /* TRANSLATORS: Title: if it's tainted or not */ + return _("Linux Kernel Verification"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_KERNEL_SWAP) == 0) + { + /* TRANSLATORS: Title: swap space or swap partition */ + return _("Linux Swap"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_RAM) == 0) + { + /* TRANSLATORS: Title: sleep state */ + return _("Suspend To RAM"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_IDLE) == 0) + { + /* TRANSLATORS: Title: a better sleep state */ + return _("Suspend To Idle"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_UEFI_PK) == 0) + { + /* TRANSLATORS: Title: PK is the 'platform key' for the machine */ + return _("UEFI Platform Key"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT) == 0) + { + /* TRANSLATORS: Title: SB is a way of locking down UEFI */ + return _("UEFI Secure Boot"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_TPM_EMPTY_PCR) == 0) + { + /* TRANSLATORS: Title: PCRs (Platform Configuration Registers) shouldn't be empty */ + return _("TPM Platform Configuration"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_TPM_RECONSTRUCTION_PCR0) == 0) + { + /* TRANSLATORS: Title: the PCR is rebuilt from the TPM event log */ + return _("TPM Reconstruction"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_TPM_VERSION_20) == 0) + { + /* TRANSLATORS: Title: TPM = Trusted Platform Module */ + return _("TPM v2.0"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_MEI_MANUFACTURING_MODE) == 0) + { + /* TRANSLATORS: Title: MEI = Intel Management Engine */ + return _("Intel Management Engine Manufacturing Mode"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_MEI_OVERRIDE_STRAP) == 0) + { + /* TRANSLATORS: Title: MEI = Intel Management Engine, and the "override" is enabled + * with a jumper -- luckily it is probably not accessible to end users on consumer + * boards */ + return _("Intel Management Engine Override"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_MEI_VERSION) == 0) + { + /* TRANSLATORS: Title: MEI = Intel Management Engine */ + return _("Intel Management Engine Version"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_FWUPD_UPDATES) == 0) + { + /* TRANSLATORS: Title: if firmware updates are available */ + return _("Firmware Updates"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_FWUPD_ATTESTATION) == 0) + { + /* TRANSLATORS: Title: if we can verify the firmware checksums */ + return _("Firmware Attestation"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_FWUPD_PLUGINS) == 0) + { + /* TRANSLATORS: Title: if the fwupd plugins are all present and correct */ + return _("Firmware Updater Verification"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_PLATFORM_DEBUG_ENABLED) == 0 || + g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_PLATFORM_DEBUG_LOCKED) == 0) + { + /* TRANSLATORS: Title: Allows debugging of parts using proprietary hardware */ + return _("Platform Debugging"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_SUPPORTED_CPU) == 0) + { + /* TRANSLATORS: Title: if fwupd supports HSI on this chip */ + return _("Processor Security Checks"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_AMD_ROLLBACK_PROTECTION) == 0) + { + /* TRANSLATORS: Title: if firmware enforces rollback protection */ + return _("AMD Rollback Protection"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_AMD_SPI_REPLAY_PROTECTION) == 0) + { + /* TRANSLATORS: Title: if hardware enforces control of SPI replays */ + return _("AMD Firmware Replay Protection"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_AMD_SPI_WRITE_PROTECTION) == 0) + { + /* TRANSLATORS: Title: if hardware enforces control of SPI writes */ + return _("AMD Firmware Write Protection"); + } + if (g_strcmp0 (appstream_id, FWUPD_SECURITY_ATTR_ID_PLATFORM_FUSED) == 0) + { + /* TRANSLATORS: Title: if the part has been fused */ + return _("Fused Platform"); + } + return NULL; +} + +const gchar * +fwupd_security_attr_result_to_string (FwupdSecurityAttrResult result) +{ + if (result == FWUPD_SECURITY_ATTR_RESULT_VALID) + { + /* TRANSLATORS: if the stauts is valid. For example security check is valid and key is valid. */ + return _("Valid"); + } + if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_VALID) + { + /* TRANSLATORS: if the status or key is not valid. */ + return _("Not Valid"); + } + if (result == FWUPD_SECURITY_ATTR_RESULT_ENABLED) + { + /* TRANSLATORS: if the function is enabled through BIOS or OS settings. */ + return _("Enabled"); + } + if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED) + { + /* TRANSLATORS: if the function is not enabled through BIOS or OS settings. */ + return _("Not Enabled"); + } + if (result == FWUPD_SECURITY_ATTR_RESULT_LOCKED) + { + /* TRANSLATORS: the memory space or system mode is locked to prevent from malicious modification. */ + return _("Locked"); + } + if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED) + { + /* TRANSLATORS: the memory space or system mode is not locked. */ + return _("Not Locked"); + } + if (result == FWUPD_SECURITY_ATTR_RESULT_ENCRYPTED) + { + /* TRANSLATORS: The data is encrypted to prevent from malicious reading. */ + return _("Encrypted"); + } + if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_ENCRYPTED) + { + /* TRANSLATORS: the data in memory is plane text. */ + return _("Not Encrypted"); + } + if (result == FWUPD_SECURITY_ATTR_RESULT_TAINTED) + { + /* TRANSLATORS: Linux kernel is tainted by third party kernel module. */ + return _("Tainted"); + } + if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_TAINTED) + { + /* TRANSLATORS: All the loaded kernel module are licensed. */ + return _("Not Tainted"); + } + if (result == FWUPD_SECURITY_ATTR_RESULT_FOUND) + { + /* TRANSLATORS: the feature can be detected. */ + return _("Found"); + } + if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND) + { + /* TRANSLATORS: the feature can't be detected. */ + return _("Not Found"); + } + if (result == FWUPD_SECURITY_ATTR_RESULT_SUPPORTED) + { + /* TRANSLATORS: the function is supported by hardware. */ + return _("Supported"); + } + if (result == FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED) + { + /* TRANSLATORS: the function isn't supported by hardware. */ + return _("Not Supported"); + } + return NULL; +} + + +/* ->summary and ->description are translated */ +FwupdSecurityAttr * +fu_security_attr_new_from_variant (GVariantIter *iter) +{ + FwupdSecurityAttr *attr = g_new0 (FwupdSecurityAttr, 1); + const gchar *key; + GVariant *value; + + while (g_variant_iter_next (iter, "{&sv}", &key, &value)) + { + if (g_strcmp0 (key, "AppstreamId") == 0) + attr->appstream_id = g_variant_dup_string (value, NULL); + else if (g_strcmp0 (key, "Flags") == 0) + attr->flags = g_variant_get_uint64(value); + else if (g_strcmp0 (key, "HsiLevel") == 0) + attr->hsi_level = g_variant_get_uint32 (value); + else if (g_strcmp0 (key, "HsiResult") == 0) + attr->result = g_variant_get_uint32 (value); + else if (g_strcmp0 (key, "HsiResultFallback") == 0) + attr->result_fallback = g_variant_get_uint32 (value); + else if (g_strcmp0 (key, "Created") == 0) + attr->timestamp = g_variant_get_uint64 (value); + else if (g_strcmp0 (key, "Description") == 0) + attr->description = g_strdup (dgettext ("fwupd", g_variant_get_string (value, NULL))); + else if (g_strcmp0 (key, "Summary") == 0) + attr->title = g_strdup (dgettext ("fwupd", g_variant_get_string (value, NULL))); + g_variant_unref (value); + } + + /* in fwupd <= 1.8.3 org.fwupd.hsi.Uefi.SecureBoot was incorrectly marked as HSI-0 */ + if (g_strcmp0 (attr->appstream_id, FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT) == 0) + attr->hsi_level = 1; + + /* fallback for older fwupd versions */ + if (attr->appstream_id != NULL && attr->title == NULL) + attr->title = g_strdup (fu_security_attr_get_title_fallback (attr->appstream_id)); + + /* success */ + return attr; +} + +void +fu_security_attr_free (FwupdSecurityAttr *attr) +{ + g_free (attr->appstream_id); + g_free (attr->title); + g_free (attr->description); + g_free (attr); +} + +gboolean +firmware_security_attr_has_flag (FwupdSecurityAttr *attr, + FwupdSecurityAttrFlags flag) +{ + return (attr->flags & flag) > 0; +} + +void +load_custom_css (const char *path) +{ + g_autoptr (GtkCssProvider) provider = gtk_css_provider_new (); + gtk_css_provider_load_from_resource (provider, path); + gtk_style_context_add_provider_for_display (gdk_display_get_default (), + GTK_STYLE_PROVIDER (provider), + GTK_STYLE_PROVIDER_PRIORITY_USER); +} diff --git a/panels/firmware-security/cc-firmware-security-utils.h b/panels/firmware-security/cc-firmware-security-utils.h new file mode 100644 index 0000000..08343f5 --- /dev/null +++ b/panels/firmware-security/cc-firmware-security-utils.h @@ -0,0 +1,133 @@ +/* cc-firmware-security-utils.h + * + * Copyright (C) 2021 Red Hat, Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * Author: Kate Hsuan + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +/* we don't need to keep this up to date and from fwupd >= 1.8.3 we only need the defines + * for the things we actually query, e.g. FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT */ +#define FWUPD_SECURITY_ATTR_ID_ACPI_DMAR "org.fwupd.hsi.AcpiDmar" +#define FWUPD_SECURITY_ATTR_ID_ENCRYPTED_RAM "org.fwupd.hsi.EncryptedRam" +#define FWUPD_SECURITY_ATTR_ID_FWUPD_ATTESTATION "org.fwupd.hsi.Fwupd.Attestation" +#define FWUPD_SECURITY_ATTR_ID_FWUPD_PLUGINS "org.fwupd.hsi.Fwupd.Plugins" +#define FWUPD_SECURITY_ATTR_ID_FWUPD_UPDATES "org.fwupd.hsi.Fwupd.Updates" +#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ENABLED "org.fwupd.hsi.IntelBootguard.Enabled" +#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_VERIFIED "org.fwupd.hsi.IntelBootguard.Verified" +#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ACM "org.fwupd.hsi.IntelBootguard.Acm" +#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_POLICY "org.fwupd.hsi.IntelBootguard.Policy" +#define FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_OTP "org.fwupd.hsi.IntelBootguard.Otp" +#define FWUPD_SECURITY_ATTR_ID_INTEL_CET_ENABLED "org.fwupd.hsi.IntelCet.Enabled" +#define FWUPD_SECURITY_ATTR_ID_INTEL_CET_ACTIVE "org.fwupd.hsi.IntelCet.Active" +#define FWUPD_SECURITY_ATTR_ID_INTEL_SMAP "org.fwupd.hsi.IntelSmap" +#define FWUPD_SECURITY_ATTR_ID_IOMMU "org.fwupd.hsi.Iommu" +#define FWUPD_SECURITY_ATTR_ID_KERNEL_LOCKDOWN "org.fwupd.hsi.Kernel.Lockdown" +#define FWUPD_SECURITY_ATTR_ID_KERNEL_SWAP "org.fwupd.hsi.Kernel.Swap" +#define FWUPD_SECURITY_ATTR_ID_KERNEL_TAINTED "org.fwupd.hsi.Kernel.Tainted" +#define FWUPD_SECURITY_ATTR_ID_MEI_MANUFACTURING_MODE "org.fwupd.hsi.Mei.ManufacturingMode" +#define FWUPD_SECURITY_ATTR_ID_MEI_OVERRIDE_STRAP "org.fwupd.hsi.Mei.OverrideStrap" +#define FWUPD_SECURITY_ATTR_ID_MEI_VERSION "org.fwupd.hsi.Mei.Version" +#define FWUPD_SECURITY_ATTR_ID_SPI_BIOSWE "org.fwupd.hsi.Spi.Bioswe" +#define FWUPD_SECURITY_ATTR_ID_SPI_BLE "org.fwupd.hsi.Spi.Ble" +#define FWUPD_SECURITY_ATTR_ID_SPI_SMM_BWP "org.fwupd.hsi.Spi.SmmBwp" +#define FWUPD_SECURITY_ATTR_ID_SPI_DESCRIPTOR "org.fwupd.hsi.Spi.Descriptor" +#define FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_IDLE "org.fwupd.hsi.SuspendToIdle" +#define FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_RAM "org.fwupd.hsi.SuspendToRam" +#define FWUPD_SECURITY_ATTR_ID_TPM_EMPTY_PCR "org.fwupd.hsi.Tpm.EmptyPcr" +#define FWUPD_SECURITY_ATTR_ID_TPM_RECONSTRUCTION_PCR0 "org.fwupd.hsi.Tpm.ReconstructionPcr0" +#define FWUPD_SECURITY_ATTR_ID_TPM_VERSION_20 "org.fwupd.hsi.Tpm.Version20" +#define FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT "org.fwupd.hsi.Uefi.SecureBoot" +#define FWUPD_SECURITY_ATTR_ID_INTEL_DCI_ENABLED "org.fwupd.hsi.IntelDci.Enabled" +#define FWUPD_SECURITY_ATTR_ID_INTEL_DCI_LOCKED "org.fwupd.hsi.IntelDci.Locked" +#define FWUPD_SECURITY_ATTR_ID_UEFI_PK "org.fwupd.hsi.Uefi.Pk" +#define FWUPD_SECURITY_ATTR_ID_PREBOOT_DMA_PROTECTION "org.fwupd.hsi.PrebootDma" +#define FWUPD_SECURITY_ATTR_ID_SUPPORTED_CPU "org.fwupd.hsi.SupportedCpu" +#define FWUPD_SECURITY_ATTR_ID_PLATFORM_DEBUG_LOCKED "org.fwupd.hsi.PlatformDebugLocked" +#define FWUPD_SECURITY_ATTR_ID_AMD_ROLLBACK_PROTECTION "org.fwupd.hsi.Amd.RollbackProtection" +#define FWUPD_SECURITY_ATTR_ID_AMD_SPI_WRITE_PROTECTION "org.fwupd.hsi.Amd.SpiWriteProtection" +#define FWUPD_SECURITY_ATTR_ID_AMD_SPI_REPLAY_PROTECTION "org.fwupd.hsi.Amd.SpiReplayProtection" +#define FWUPD_SECURITY_ATTR_ID_PLATFORM_DEBUG_ENABLED "org.fwupd.hsi.PlatformDebugEnabled" +#define FWUPD_SECURITY_ATTR_ID_PLATFORM_FUSED "org.fwupd.hsi.PlatformFused" + +typedef enum { + SECURE_BOOT_STATE_UNKNOWN, + SECURE_BOOT_STATE_ACTIVE, + SECURE_BOOT_STATE_INACTIVE, + SECURE_BOOT_STATE_PROBLEMS, +} SecureBootState; + +typedef enum { + FWUPD_SECURITY_ATTR_FLAG_NONE = 0, + FWUPD_SECURITY_ATTR_FLAG_SUCCESS = 1 << 0, + FWUPD_SECURITY_ATTR_FLAG_OBSOLETED = 1 << 1, + FWUPD_SECURITY_ATTR_FLAG_RUNTIME_UPDATES = 1 << 8, + FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ATTESTATION = 1 << 9, + FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE = 1 << 10, + FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM = 1 << 11, + FWUPD_SECURITY_ATTR_FLAG_ACTION_CONFIG_FW = 1 << 12, + FWUPD_SECURITY_ATTR_FLAG_ACTION_CONFIG_OS = 1 << 13, +} FwupdSecurityAttrFlags; + +typedef enum { + FWUPD_SECURITY_ATTR_RESULT_UNKNOWN, + FWUPD_SECURITY_ATTR_RESULT_ENABLED, + FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED, + FWUPD_SECURITY_ATTR_RESULT_VALID, + FWUPD_SECURITY_ATTR_RESULT_NOT_VALID, + FWUPD_SECURITY_ATTR_RESULT_LOCKED, + FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED, + FWUPD_SECURITY_ATTR_RESULT_ENCRYPTED, + FWUPD_SECURITY_ATTR_RESULT_NOT_ENCRYPTED, + FWUPD_SECURITY_ATTR_RESULT_TAINTED, + FWUPD_SECURITY_ATTR_RESULT_NOT_TAINTED, + FWUPD_SECURITY_ATTR_RESULT_FOUND, + FWUPD_SECURITY_ATTR_RESULT_NOT_FOUND, + FWUPD_SECURITY_ATTR_RESULT_SUPPORTED, + FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED, + FWUPD_SECURITY_ATTR_RESULT_LAST +} FwupdSecurityAttrResult; + +typedef struct { + FwupdSecurityAttrResult result; + FwupdSecurityAttrResult result_fallback; + FwupdSecurityAttrFlags flags; + guint32 hsi_level; + guint64 timestamp; + gchar *appstream_id; + gchar *title; + gchar *description; +} FwupdSecurityAttr; + +FwupdSecurityAttr *fu_security_attr_new_from_variant (GVariantIter *iter); +void fu_security_attr_free (FwupdSecurityAttr *attr); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (FwupdSecurityAttr, fu_security_attr_free) + +gboolean firmware_security_attr_has_flag (FwupdSecurityAttr *attr, + FwupdSecurityAttrFlags flag); +void load_custom_css (const char *path); +const gchar *fwupd_security_attr_result_to_string (FwupdSecurityAttrResult result); +gboolean fwupd_get_result_status (FwupdSecurityAttrResult result); + +G_END_DECLS diff --git a/panels/firmware-security/firmware-security.gresource.xml b/panels/firmware-security/firmware-security.gresource.xml new file mode 100644 index 0000000..f44f6fb --- /dev/null +++ b/panels/firmware-security/firmware-security.gresource.xml @@ -0,0 +1,9 @@ + + + + cc-firmware-security-panel.ui + cc-firmware-security-dialog.ui + cc-firmware-security-boot-dialog.ui + security-level.css + + diff --git a/panels/firmware-security/gnome-firmware-security-panel.desktop.in.in b/panels/firmware-security/gnome-firmware-security-panel.desktop.in.in new file mode 100644 index 0000000..184ee22 --- /dev/null +++ b/panels/firmware-security/gnome-firmware-security-panel.desktop.in.in @@ -0,0 +1,19 @@ +[Desktop Entry] +Name=Device Security +Comment=Host firmware security status +Exec=gnome-control-center firmware-security +# FIXME +# Translators: Do NOT translate or transliterate this text (this is an icon file name)! +Icon=security-high-symbolic +Terminal=false +Type=Application +NoDisplay=true +StartupNotify=true +Categories=GNOME;GTK;Settings;DesktopSettings;X-GNOME-Settings-Panel;X-GNOME-PrivacySettings; +OnlyShowIn=GNOME;Unity; +X-GNOME-Bugzilla-Bugzilla=GNOME +X-GNOME-Bugzilla-Product=gnome-control-center +X-GNOME-Bugzilla-Component=privacy +X-GNOME-Bugzilla-Version=@VERSION@ +# Translators: Search terms to find the Privacy panel. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! +Keywords=screen;lock;diagnostics;crash;private;recent;temporary;tmp;index;name;network;identity;privacy; diff --git a/panels/firmware-security/meson.build b/panels/firmware-security/meson.build new file mode 100644 index 0000000..0325568 --- /dev/null +++ b/panels/firmware-security/meson.build @@ -0,0 +1,44 @@ +panels_list += cappletname +desktop = 'gnome-@0@-panel.desktop'.format(cappletname) + +desktop_in = configure_file( + input: desktop + '.in.in', + output: desktop + '.in', + configuration: desktop_conf +) + +i18n.merge_file( + type: 'desktop', + input: desktop_in, + output: desktop, + po_dir: po_dir, + install: true, + install_dir: control_center_desktopdir +) + +sources = files('cc-firmware-security-utils.c', + 'cc-firmware-security-panel.c', + 'cc-firmware-security-dialog.c', + 'cc-firmware-security-boot-dialog.c') + +resource_data = files('cc-firmware-security-panel.ui', + 'cc-firmware-security-dialog.ui', + 'cc-firmware-security-boot-dialog.ui') + +sources += gnome.compile_resources( + 'cc-' + cappletname + '-resources', + cappletname + '.gresource.xml', + c_name: 'cc_' + cappletname.underscorify (), + dependencies: resource_data, + export: true +) + +cflags += '-DGNOMELOCALEDIR="@0@"'.format(control_center_localedir) + +panels_libs += static_library( + cappletname, + sources: sources, + include_directories: [top_inc, common_inc], + dependencies: common_deps, + c_args: cflags +) diff --git a/panels/firmware-security/security-level.css b/panels/firmware-security/security-level.css new file mode 100644 index 0000000..64d724f --- /dev/null +++ b/panels/firmware-security/security-level.css @@ -0,0 +1,119 @@ +.hsi-level-box { + border-radius: 9999px; + min-width: 64px; + min-height: 64px; + +} + +.hsi-level-box.level0 { + background-color: alpha(@error_color, .25); +} + +.hsi-level-box.level1 { + background-color: alpha(@light_4, .25); +} + +.hsi-level-box.level2 { + background-color: alpha(@warning_color, .25); +} + +.hsi-level-box.level3 { + background-color: alpha(@success_color, .25); +} + +.hsi-level-font { + font-size: 32px; + font-weight: 800; +} + +.hsi-level-font.hsi0 { + color: @error_color; +} + +.hsi-level-font.hsi1 { + color: @light_4; +} + +.hsi-level-font.hsi2 { + color: @warning_color; +} + +.hsi-level-font.hsi3 { + color: @success_color; +} + +.security-level-icon { + border-radius: 9999px; + min-width: 64px; + min-height: 64px; +} + +.security-level-icon.good { + color: @success_color; + background-color: alpha(@success_color, .25); +} + +.security-level-icon.error { + color: @error_color; + background-color: alpha(@error_color, .25); +} + +.security-level-icon.warning { + color: @warning_color; + background-color: alpha(@warning_color, .25); +} + +.security-level-icon.neutral { + color: @light_4; + background-color: alpha(@light_4, .25); +} + +#color_green { + color: @success_color; +} + +#color_dim { + color: @light_4f; +} + +row.success-icon image.icon { + color: @success_color; +} + +row.warning-icon image.icon { + color: @warning_color; +} + +row.error-icon image.icon { + color: @error_color; +} + +row.gray-icon image { + color: @light_4; +} + +row.success-hsi-icon image.hsi_icon { + color: @success_color; +} + +row.error-hsi-icon image.hsi_icon { + color: @error_color; +} + +row.success-title label.hsi_label { + font-weight: bold; + color: @success_color; +} + +row.error-title label.hsi_label { + font-weight: bold; + color: @error_color; +} + +row.security-description-row label.subtitle { + padding: 12px 0; +} + +row.hide-arrow image.expander-row-arrow { + opacity: 0; +} -- cgit v1.2.3