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 |
|
|
|