GCC Code Coverage Report


Directory: ./
File: panels/privacy/firmware-security/cc-firmware-security-dialog.c
Date: 2024-05-03 09:46:52
Exec Total Coverage
Lines: 0 196 0.0%
Functions: 0 12 0.0%
Branches: 0 165 0.0%

Line Branch Exec Source
1 /* cc-firmware-security-dialog.c
2 *
3 * Copyright (C) 2021 Red Hat, Inc
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see <http://www.gnu.org/licenses/>.
17 *
18 * Author: Kate Hsuan <hpa@redhat.com>
19 *
20 * SPDX-License-Identifier: GPL-2.0-or-later
21 */
22
23 #include "config.h"
24
25 #include <glib/gi18n-lib.h>
26 #include <glibtop/fsusage.h>
27 #include <glibtop/mountlist.h>
28 #include <glibtop/mem.h>
29 #include <glibtop/sysinfo.h>
30
31 #include "cc-firmware-security-page.h"
32 #include "cc-firmware-security-dialog.h"
33 #include "cc-firmware-security-utils.h"
34
35 struct _CcFirmwareSecurityDialog
36 {
37 AdwDialog parent;
38
39 GtkWidget *firmware_security_dialog_icon;
40
41
42
43 GtkWidget *firmware_security_dialog_title_label;
44 GtkWidget *firmware_security_dialog_body_label;
45 GtkWidget *firmware_security_dialog_min_row;
46 AdwToastOverlay *toast_overlay;
47
48 gboolean is_created;
49
50 GHashTable *hsi1_dict;
51 GHashTable *hsi2_dict;
52 GHashTable *hsi3_dict;
53 GHashTable *hsi4_dict;
54 GHashTable *runtime_dict;
55
56 GString *event_log_str;
57
58 guint hsi_number;
59 };
60
61 G_DEFINE_TYPE (CcFirmwareSecurityDialog, cc_firmware_security_dialog, ADW_TYPE_DIALOG)
62
63 static void
64 set_dialog_item_layer1 (CcFirmwareSecurityDialog *self,
65 const gchar *icon_name,
66 const gchar *title,
67 const gchar *body)
68 {
69 g_autofree gchar *str = NULL;
70
71 gtk_image_set_from_icon_name (GTK_IMAGE (self->firmware_security_dialog_icon), icon_name);
72 gtk_label_set_text (GTK_LABEL (self->firmware_security_dialog_title_label), title);
73 gtk_label_set_text (GTK_LABEL (self->firmware_security_dialog_body_label), body);
74
75 if (self->hsi_number == G_MAXUINT)
76 {
77 gtk_widget_add_css_class (self->firmware_security_dialog_icon, "neutral");
78 return;
79 }
80
81 switch (self->hsi_number)
82 {
83 case 0:
84 gtk_widget_add_css_class (self->firmware_security_dialog_icon, "error");
85 break;
86 case 1:
87 gtk_widget_add_css_class (self->firmware_security_dialog_icon, "warning");
88 break;
89 case 2:
90 case 3:
91 case 4:
92 case 5:
93 gtk_widget_add_css_class (self->firmware_security_dialog_icon, "good");
94 break;
95 default:
96 gtk_widget_add_css_class (self->firmware_security_dialog_icon, "neutral");
97 }
98 }
99
100 static void
101 update_dialog (CcFirmwareSecurityDialog *self)
102 {
103 switch (self->hsi_number)
104 {
105 case 0:
106 set_dialog_item_layer1 (self,
107 "dialog-warning-symbolic",
108 _("Security Checks Failed"),
109 /* TRANSLATORS: This is the description to describe the failure on
110 checking the security items. */
111 _("Hardware does not pass checks. "
112 "This means that you are not protected against common hardware security issues."
113 "\n\n"
114 "It may be possible to resolve hardware security issues by updating your firmware or changing device configuration options. "
115 "However, failures can stem from the physical hardware itself and may not be fixable."));
116 break;
117
118 case 1:
119 set_dialog_item_layer1 (self,
120 "channel-secure-symbolic",
121 _("Basic Security Checks Passed"),
122 /* TRANSLATORS: This description describes the device passing the
123 minimum requirement of security check.*/
124 _("This device meets basic security requirements and has protection against some hardware security threats. "
125 "However, it lacks other recommended protections."));
126 break;
127
128 case 2:
129 case 3:
130 case 4:
131 case 5:
132 set_dialog_item_layer1 (self,
133 "security-high-symbolic",
134 _("Protected"),
135 /* TRANSLATOR: This description describes the devices passing
136 the extended security check. */
137 _("This device passes current security tests. "
138 "It is protected against the majority of hardware security threats."));
139 break;
140
141 default:
142 set_dialog_item_layer1 (self,
143 "dialog-question-symbolic",
144 _("Checks Unavailable"),
145 /* TRANSLATORS: When the security result is unavailable, this description is shown. */
146 _("Device security checks are not available for this device. "
147 "It is not possible to tell whether it meets hardware security requirements."));
148 }
149 }
150
151 static gchar *
152 get_os_name (void)
153 {
154 g_autofree gchar *name = NULL;
155 g_autofree gchar *version_id = NULL;
156 g_autofree gchar *pretty_name = NULL;
157
158 name = g_get_os_info (G_OS_INFO_KEY_NAME);
159 version_id = g_get_os_info (G_OS_INFO_KEY_VERSION_ID);
160 pretty_name = g_get_os_info (G_OS_INFO_KEY_PRETTY_NAME);
161
162 if (pretty_name)
163 return g_steal_pointer (&pretty_name);
164 else if (name && version_id)
165 return g_strdup_printf ("%s %s", name, version_id);
166 else
167 return g_strdup (_("Unknown"));
168 }
169
170 static gchar*
171 cpu_get_model ()
172 {
173 gchar *model;
174 const glibtop_sysinfo * sysinfo;
175
176 glibtop_init();
177 sysinfo = glibtop_get_sysinfo ();
178 model = g_strdup (g_hash_table_lookup (sysinfo->cpuinfo [1].values, "model name"));
179 glibtop_close ();
180
181 return model;
182 }
183
184 static gchar*
185 fwupd_get_property (const char *property_name)
186 {
187 g_autoptr(GDBusConnection) connection = NULL;
188 g_autoptr(GError) error = NULL;
189 g_autoptr(GVariant) inner = NULL;
190 g_autoptr(GVariant) variant = NULL;
191 const gchar *ret_property;
192
193 connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
194 if (!connection)
195 {
196 g_warning ("system bus not available: %s", error->message);
197 return NULL;
198 }
199 variant = g_dbus_connection_call_sync (connection,
200 "org.freedesktop.fwupd",
201 "/",
202 "org.freedesktop.DBus.Properties",
203 "Get",
204 g_variant_new ("(ss)",
205 "org.freedesktop.fwupd",
206 property_name),
207 NULL,
208 G_DBUS_CALL_FLAGS_NONE,
209 -1,
210 NULL,
211 &error);
212 if (!variant)
213 {
214 g_warning ("Cannot get org.freedesktop.fwupd: %s", error->message);
215 return NULL;
216 }
217 g_variant_get (variant, "(v)", &inner);
218 ret_property = g_variant_get_string (inner, NULL);
219
220 return g_strdup (ret_property);
221 }
222
223 static void
224 on_hsi_detail_button_clicked_cb (CcFirmwareSecurityDialog *self)
225 {
226 GdkClipboard *clip_board;
227 GdkDisplay *display;
228 g_autoptr (GList) hash_keys;
229 g_autoptr (GString) result_str;
230 g_autofree gchar *date_string = NULL;
231 g_autoptr (GDateTime) date = NULL;
232 g_autofree gchar *fwupd_ver = NULL;
233 g_autofree gchar *vendor = NULL;
234 g_autofree gchar *product = NULL;
235 g_autofree gchar *os_name = NULL;
236 g_autofree gchar *hsi_level = NULL;
237 g_autofree gchar *cpu_model = NULL;
238 const gchar *hsi_result;
239 g_autoptr (GString) tmp_str;
240
241 GHashTable *hsi_dict = NULL;
242
243 tmp_str = g_string_new (NULL);
244
245 result_str = g_string_new (NULL);
246
247 // TRANSLATORS: device security report fields are left untranslated as developers expect bug reports in English
248 g_string_append (result_str, "Device Security Report");
249 g_string_append (result_str, "\n======================\n\n");
250
251 g_string_append (result_str, "Report details");
252 g_string_append (result_str, "\n");
253
254 g_string_append (result_str, " ");
255 hsi_report_title_print_padding ("Date generated:", result_str, 0);
256 date = g_date_time_new_now_local ();
257 date_string = g_date_time_format (date, "%Y-%m-%d %H:%M:%S");
258
259 g_string_append_printf (result_str, "%s\n", date_string);
260
261 g_string_append (result_str, " ");
262 hsi_report_title_print_padding ("fwupd version:", result_str, 00);
263 fwupd_ver = fwupd_get_property ("DaemonVersion");
264 g_string_append_printf (result_str, "%s", fwupd_ver);
265 g_string_append (result_str, "\n\n");
266
267 g_string_append (result_str, "System details");
268 g_string_append (result_str, "\n");
269
270 g_string_append (result_str, " ");
271 hsi_report_title_print_padding ("Hardware model:", result_str, 0);
272 vendor = fwupd_get_property ("HostVendor");
273 product = fwupd_get_property ("HostProduct");
274 g_string_append_printf (result_str, "%s %s\n", vendor, product);
275
276 g_string_append (result_str, " ");
277 hsi_report_title_print_padding ("Processor:", result_str, 0);
278 cpu_model = cpu_get_model ();
279 g_string_append_printf (result_str, "%s\n", cpu_model);
280
281 g_string_append (result_str, " ");
282 hsi_report_title_print_padding ("OS:", result_str, 0);
283 os_name = get_os_name ();
284 g_string_append_printf (result_str, "%s\n", os_name);
285
286 g_string_append (result_str, " ");
287 hsi_report_title_print_padding ("Security level:", result_str, 0);
288 hsi_level = fwupd_get_property ("HostSecurityId");
289 g_string_append_printf (result_str, "%s\n", hsi_level);
290 g_string_append (result_str, "\n");
291
292 for (int i = 1; i <=5; i++)
293 {
294 switch (i)
295 {
296 case 1:
297 hsi_dict = self->hsi1_dict;
298 break;
299 case 2:
300 hsi_dict = self->hsi2_dict;
301 break;
302 case 3:
303 hsi_dict = self->hsi3_dict;
304 break;
305 case 4:
306 hsi_dict = self->hsi4_dict;
307 break;
308 case 5:
309 hsi_dict = self->runtime_dict;
310 }
311
312 if (i <= 4)
313 {
314 g_string_append_printf (result_str, "HSI-");
315 g_string_append_printf (result_str, "%i ", i);
316 g_string_append (result_str, "Tests");
317 g_string_append (result_str, "\n");
318 }
319 else
320 {
321 g_string_append (result_str, "Runtime Tests");
322 g_string_append (result_str, "\n");
323 }
324
325 hash_keys = g_hash_table_get_keys (hsi_dict);
326 for (GList *item = g_list_first (hash_keys); item != NULL; item = g_list_next (item))
327 {
328 FwupdSecurityAttr *attr = g_hash_table_lookup (hsi_dict, item->data);
329 if (g_strcmp0 (attr->appstream_id, FWUPD_SECURITY_ATTR_ID_SUPPORTED_CPU) == 0)
330 continue;
331 if (attr->title == NULL)
332 continue;
333 g_string_printf (tmp_str, "%s:", attr->title);
334 g_string_append (result_str, " ");
335 hsi_report_title_print_padding (tmp_str->str, result_str, 0);
336 if (firmware_security_attr_has_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS))
337 {
338 /* Passed */
339 g_string_append (result_str, "Pass");
340 g_string_append (result_str, " ");
341 }
342 else
343 {
344 /* Failed */
345 result_str = g_string_overwrite (result_str, result_str->len-2, "! Fail");
346 g_string_append (result_str, " ");
347 }
348 hsi_result = fwupd_security_attr_result_to_string (attr->result);
349 if (hsi_result) {
350 g_string_append_printf (result_str, "(%s)", hsi_result);
351 }
352 g_string_append (result_str, "\n");
353 }
354 g_string_append (result_str, "\n");
355 }
356
357 g_string_append (result_str, "Host security events");
358 g_string_append (result_str, "\n");
359 g_string_append (result_str, self->event_log_str->str);
360 g_string_append (result_str, "\n");
361 g_string_append (result_str, "For information on the contents of this report, see https://fwupd.github.io/hsi.html");
362
363 display = gdk_display_get_default ();
364 clip_board = gdk_display_get_clipboard (display);
365 gdk_clipboard_set_text (clip_board, result_str->str);
366 adw_toast_overlay_add_toast (self->toast_overlay, adw_toast_new (_("Report copied to clipboard")));
367 }
368
369 static void
370 cc_firmware_security_dialog_class_init (CcFirmwareSecurityDialogClass *klass)
371 {
372 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
373
374 gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/privacy/firmware-security/cc-firmware-security-dialog.ui");
375
376 gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, firmware_security_dialog_icon);
377 gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, firmware_security_dialog_title_label);
378 gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, firmware_security_dialog_body_label);
379 gtk_widget_class_bind_template_child (widget_class, CcFirmwareSecurityDialog, toast_overlay);
380
381 gtk_widget_class_bind_template_callback (widget_class, on_hsi_detail_button_clicked_cb);
382 }
383
384 static void
385 cc_firmware_security_dialog_init (CcFirmwareSecurityDialog *dialog)
386 {
387 gtk_widget_init_template (GTK_WIDGET (dialog));
388 load_custom_css ("/org/gnome/control-center/privacy/firmware-security/security-level.css");
389 }
390
391 GtkWidget *
392 cc_firmware_security_dialog_new (guint hsi_number,
393 GHashTable *hsi1_dict,
394 GHashTable *hsi2_dict,
395 GHashTable *hsi3_dict,
396 GHashTable *hsi4_dict,
397 GHashTable *runtime_dict,
398 GString *event_log_str)
399 {
400 CcFirmwareSecurityDialog *dialog;
401
402 dialog = g_object_new (CC_TYPE_FIRMWARE_SECURITY_DIALOG, NULL);
403 dialog->hsi_number = hsi_number;
404 dialog->is_created = FALSE;
405 dialog->hsi1_dict = hsi1_dict;
406 dialog->hsi2_dict = hsi2_dict;
407 dialog->hsi3_dict = hsi3_dict;
408 dialog->hsi4_dict = hsi4_dict;
409 dialog->runtime_dict = runtime_dict;
410 dialog->event_log_str = event_log_str;
411 update_dialog (dialog);
412
413 return GTK_WIDGET (dialog);
414 }
415