/src/fwupd/libfwupdplugin/fu-security-attrs.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright 2020 Richard Hughes <richard@hughsie.com> |
3 | | * |
4 | | * SPDX-License-Identifier: LGPL-2.1-or-later |
5 | | */ |
6 | | |
7 | 0 | #define G_LOG_DOMAIN "FuSecurityAttrs" |
8 | | |
9 | | #include "config.h" |
10 | | |
11 | | #include <fwupd.h> |
12 | | #include <glib/gi18n.h> |
13 | | |
14 | | #include "fwupd-security-attr-private.h" |
15 | | |
16 | | #include "fu-security-attr.h" |
17 | | #include "fu-security-attrs-private.h" |
18 | | #include "fu-security-attrs.h" |
19 | | |
20 | | /** |
21 | | * FuSecurityAttrs: |
22 | | * |
23 | | * A set of Host Security ID attributes that represents the system state. |
24 | | */ |
25 | | |
26 | | struct _FuSecurityAttrs { |
27 | | GObject parent_instance; |
28 | | GPtrArray *attrs; |
29 | | }; |
30 | | |
31 | | /* probably sane to *not* make this part of the ABI */ |
32 | 0 | #define FWUPD_SECURITY_ATTR_ID_DOC_URL "https://fwupd.github.io/libfwupdplugin/hsi.html" |
33 | | |
34 | | static void |
35 | | fu_security_attrs_codec_iface_init(FwupdCodecInterface *iface); |
36 | | |
37 | 0 | G_DEFINE_TYPE_WITH_CODE(FuSecurityAttrs, |
38 | 0 | fu_security_attrs, |
39 | 0 | G_TYPE_OBJECT, |
40 | 0 | G_IMPLEMENT_INTERFACE(FWUPD_TYPE_CODEC, fu_security_attrs_codec_iface_init)) |
41 | 0 |
|
42 | 0 | static void |
43 | 0 | fu_security_attrs_finalize(GObject *obj) |
44 | 0 | { |
45 | 0 | FuSecurityAttrs *self = FU_SECURITY_ATTRS(obj); |
46 | 0 | g_ptr_array_unref(self->attrs); |
47 | 0 | G_OBJECT_CLASS(fu_security_attrs_parent_class)->finalize(obj); |
48 | 0 | } |
49 | | |
50 | | static void |
51 | | fu_security_attrs_class_init(FuSecurityAttrsClass *klass) |
52 | 0 | { |
53 | 0 | GObjectClass *object_class = G_OBJECT_CLASS(klass); |
54 | 0 | object_class->finalize = fu_security_attrs_finalize; |
55 | 0 | } |
56 | | |
57 | | static void |
58 | | fu_security_attrs_init(FuSecurityAttrs *self) |
59 | 0 | { |
60 | 0 | self->attrs = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref); |
61 | 0 | } |
62 | | |
63 | | /** |
64 | | * fu_security_attrs_append_internal: |
65 | | * @self: a #FuSecurityAttrs |
66 | | * @attr: a #FwupdSecurityAttr |
67 | | * |
68 | | * Adds a #FwupdSecurityAttr to the array with no sanity checks. |
69 | | * |
70 | | * Since: 1.7.1 |
71 | | **/ |
72 | | void |
73 | | fu_security_attrs_append_internal(FuSecurityAttrs *self, FwupdSecurityAttr *attr) |
74 | 0 | { |
75 | 0 | g_return_if_fail(FU_IS_SECURITY_ATTRS(self)); |
76 | 0 | g_return_if_fail(FWUPD_IS_SECURITY_ATTR(attr)); |
77 | 0 | g_ptr_array_add(self->attrs, g_object_ref(attr)); |
78 | 0 | } |
79 | | |
80 | | /** |
81 | | * fu_security_attrs_is_valid: |
82 | | * @self: a #FuSecurityAttrs |
83 | | * |
84 | | * Adds a #FwupdSecurityAttr to the array with no sanity checks. |
85 | | * |
86 | | * Returns: %TRUE if the collection is valid |
87 | | * |
88 | | * Since: 2.0.7 |
89 | | **/ |
90 | | gboolean |
91 | | fu_security_attrs_is_valid(FuSecurityAttrs *self) |
92 | 0 | { |
93 | 0 | g_return_val_if_fail(FU_IS_SECURITY_ATTRS(self), FALSE); |
94 | 0 | return self->attrs->len > 0; |
95 | 0 | } |
96 | | |
97 | | /** |
98 | | * fu_security_attrs_append: |
99 | | * @self: a #FuSecurityAttrs |
100 | | * @attr: a #FwupdSecurityAttr |
101 | | * |
102 | | * Adds a #FwupdSecurityAttr to the array. |
103 | | * |
104 | | * Since: 1.5.0 |
105 | | **/ |
106 | | void |
107 | | fu_security_attrs_append(FuSecurityAttrs *self, FwupdSecurityAttr *attr) |
108 | 0 | { |
109 | 0 | g_return_if_fail(FU_IS_SECURITY_ATTRS(self)); |
110 | 0 | g_return_if_fail(FWUPD_IS_SECURITY_ATTR(attr)); |
111 | | |
112 | | /* sanity check */ |
113 | 0 | if (fwupd_security_attr_get_plugin(attr) == NULL) { |
114 | 0 | g_warning("%s has no plugin set", fwupd_security_attr_get_appstream_id(attr)); |
115 | 0 | } |
116 | | |
117 | | /* sanity check, and correctly prefix the URLs with the current mirror */ |
118 | 0 | if (fwupd_security_attr_get_url(attr) == NULL) { |
119 | 0 | g_autofree gchar *url = NULL; |
120 | 0 | url = g_strdup_printf("%s#%s", |
121 | 0 | FWUPD_SECURITY_ATTR_ID_DOC_URL, |
122 | 0 | fwupd_security_attr_get_appstream_id(attr)); |
123 | 0 | fwupd_security_attr_set_url(attr, url); |
124 | 0 | } else if (g_str_has_prefix(fwupd_security_attr_get_url(attr), "#")) { |
125 | 0 | g_autofree gchar *url = NULL; |
126 | 0 | url = g_strdup_printf("%s%s", |
127 | 0 | FWUPD_SECURITY_ATTR_ID_DOC_URL, |
128 | 0 | fwupd_security_attr_get_url(attr)); |
129 | 0 | fwupd_security_attr_set_url(attr, url); |
130 | 0 | } |
131 | 0 | fu_security_attrs_append_internal(self, attr); |
132 | 0 | } |
133 | | |
134 | | /** |
135 | | * fu_security_attrs_get_by_appstream_id: |
136 | | * @self: a #FuSecurityAttrs |
137 | | * @appstream_id: an ID, e.g. %FWUPD_SECURITY_ATTR_ID_ENCRYPTED_RAM |
138 | | * @error: (nullable): optional return location for an error |
139 | | * |
140 | | * Gets a specific #FwupdSecurityAttr from the array. |
141 | | * |
142 | | * Returns: (transfer full): a #FwupdSecurityAttr or %NULL |
143 | | * |
144 | | * Since: 1.9.6 |
145 | | **/ |
146 | | FwupdSecurityAttr * |
147 | | fu_security_attrs_get_by_appstream_id(FuSecurityAttrs *self, |
148 | | const gchar *appstream_id, |
149 | | GError **error) |
150 | 0 | { |
151 | 0 | g_return_val_if_fail(FU_IS_SECURITY_ATTRS(self), NULL); |
152 | 0 | if (self->attrs->len == 0) { |
153 | 0 | g_set_error_literal(error, |
154 | 0 | FWUPD_ERROR, |
155 | 0 | FWUPD_ERROR_NOT_FOUND, |
156 | 0 | "no attributes are loaded"); |
157 | 0 | return NULL; |
158 | 0 | } |
159 | 0 | for (guint i = 0; i < self->attrs->len; i++) { |
160 | 0 | FwupdSecurityAttr *attr = g_ptr_array_index(self->attrs, i); |
161 | 0 | if (g_strcmp0(fwupd_security_attr_get_appstream_id(attr), appstream_id) == 0) |
162 | 0 | return g_object_ref(attr); |
163 | 0 | } |
164 | 0 | g_set_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_FOUND, "no attr with ID %s", appstream_id); |
165 | 0 | return NULL; |
166 | 0 | } |
167 | | |
168 | | /** |
169 | | * fu_security_attrs_to_variant: |
170 | | * @self: a #FuSecurityAttrs |
171 | | * |
172 | | * Serializes the #FwupdSecurityAttr objects. |
173 | | * |
174 | | * Returns: a #GVariant or %NULL |
175 | | * |
176 | | * Since: 1.5.0 |
177 | | **/ |
178 | | GVariant * |
179 | | fu_security_attrs_to_variant(FuSecurityAttrs *self) |
180 | 0 | { |
181 | 0 | GVariantBuilder builder; |
182 | |
|
183 | 0 | g_return_val_if_fail(FU_IS_SECURITY_ATTRS(self), NULL); |
184 | | |
185 | 0 | g_variant_builder_init(&builder, G_VARIANT_TYPE("aa{sv}")); |
186 | 0 | for (guint i = 0; i < self->attrs->len; i++) { |
187 | 0 | FwupdSecurityAttr *attr = g_ptr_array_index(self->attrs, i); |
188 | 0 | if (fwupd_security_attr_has_flag(attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)) |
189 | 0 | continue; |
190 | 0 | g_variant_builder_add_value( |
191 | 0 | &builder, |
192 | 0 | fwupd_codec_to_variant(FWUPD_CODEC(attr), FWUPD_CODEC_FLAG_NONE)); |
193 | 0 | } |
194 | 0 | return g_variant_new("(aa{sv})", &builder); |
195 | 0 | } |
196 | | |
197 | | /** |
198 | | * fu_security_attrs_get_all: |
199 | | * @self: a #FuSecurityAttrs |
200 | | * @fwupd_version: (nullable): fwupd version string, e.g. `2.0.7` |
201 | | * |
202 | | * Gets all the non-obsoleted attributes in the object. |
203 | | * |
204 | | * Returns: (transfer container) (element-type FwupdSecurityAttr): attributes |
205 | | * |
206 | | * Since: 1.5.0 |
207 | | **/ |
208 | | GPtrArray * |
209 | | fu_security_attrs_get_all(FuSecurityAttrs *self, const gchar *fwupd_version) |
210 | 0 | { |
211 | 0 | g_autoptr(GPtrArray) all = g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref); |
212 | 0 | g_return_val_if_fail(FU_IS_SECURITY_ATTRS(self), NULL); |
213 | 0 | for (guint i = 0; i < self->attrs->len; i++) { |
214 | 0 | FwupdSecurityAttr *attr = g_ptr_array_index(self->attrs, i); |
215 | 0 | if (fwupd_security_attr_has_flag(attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)) |
216 | 0 | continue; |
217 | 0 | if (!fu_security_attr_check_fwupd_version(attr, fwupd_version)) |
218 | 0 | continue; |
219 | 0 | g_ptr_array_add(all, g_object_ref(attr)); |
220 | 0 | } |
221 | 0 | return g_steal_pointer(&all); |
222 | 0 | } |
223 | | |
224 | | /** |
225 | | * fu_security_attrs_get_all_mutable: (skip): |
226 | | **/ |
227 | | GPtrArray * |
228 | | fu_security_attrs_get_all_mutable(FuSecurityAttrs *self) |
229 | 0 | { |
230 | 0 | g_return_val_if_fail(FU_IS_SECURITY_ATTRS(self), NULL); |
231 | 0 | return g_ptr_array_ref(self->attrs); |
232 | 0 | } |
233 | | |
234 | | /** |
235 | | * fu_security_attrs_remove_all: |
236 | | * @self: a #FuSecurityAttrs |
237 | | * |
238 | | * Removes all the attributes in the object. |
239 | | * |
240 | | * Since: 1.5.0 |
241 | | **/ |
242 | | void |
243 | | fu_security_attrs_remove_all(FuSecurityAttrs *self) |
244 | 0 | { |
245 | 0 | g_return_if_fail(FU_IS_SECURITY_ATTRS(self)); |
246 | 0 | return g_ptr_array_set_size(self->attrs, 0); |
247 | 0 | } |
248 | | |
249 | | /** |
250 | | * fu_security_attrs_calculate_hsi: |
251 | | * @self: a #FuSecurityAttrs |
252 | | * @fwupd_version: fwupd version, e.g. `2.0.7` |
253 | | * @flags: HSI attribute flags |
254 | | * |
255 | | * Calculates the HSI string from the appended attributes. |
256 | | * |
257 | | * Returns: (transfer full): a string or %NULL |
258 | | * |
259 | | * Since: 2.0.7 |
260 | | **/ |
261 | | gchar * |
262 | | fu_security_attrs_calculate_hsi(FuSecurityAttrs *self, |
263 | | const gchar *fwupd_version, |
264 | | FuSecurityAttrsFlags flags) |
265 | 0 | { |
266 | 0 | guint hsi_number = 0; |
267 | 0 | FwupdSecurityAttrFlags attr_flags = FWUPD_SECURITY_ATTR_FLAG_NONE; |
268 | 0 | g_autoptr(GString) str = g_string_new("HSI:"); |
269 | 0 | const FwupdSecurityAttrFlags hpi_suffixes[] = { |
270 | 0 | FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE, |
271 | 0 | FWUPD_SECURITY_ATTR_FLAG_NONE, |
272 | 0 | }; |
273 | |
|
274 | 0 | g_return_val_if_fail(FU_IS_SECURITY_ATTRS(self), NULL); |
275 | | |
276 | | /* find the highest HSI number where there are no failures and at least |
277 | | * one success */ |
278 | 0 | for (guint j = 1; j <= FWUPD_SECURITY_ATTR_LEVEL_LAST; j++) { |
279 | 0 | gboolean success_cnt = 0; |
280 | 0 | gboolean failure_cnt = 0; |
281 | 0 | for (guint i = 0; i < self->attrs->len; i++) { |
282 | 0 | FwupdSecurityAttr *attr = g_ptr_array_index(self->attrs, i); |
283 | 0 | if (fwupd_security_attr_get_level(attr) != j) |
284 | 0 | continue; |
285 | 0 | if (!fu_security_attr_check_fwupd_version(attr, fwupd_version)) |
286 | 0 | continue; |
287 | 0 | if (fwupd_security_attr_has_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) |
288 | 0 | success_cnt++; |
289 | 0 | else if (!fwupd_security_attr_has_flag(attr, |
290 | 0 | FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)) |
291 | 0 | failure_cnt++; |
292 | 0 | } |
293 | | |
294 | | /* abort */ |
295 | 0 | if (failure_cnt > 0) |
296 | 0 | break; |
297 | | |
298 | | /* we matched at least one thing on this level */ |
299 | 0 | if (success_cnt > 0) |
300 | 0 | hsi_number = j; |
301 | 0 | } |
302 | | |
303 | | /* get a logical OR of the runtime flags */ |
304 | 0 | for (guint i = 0; i < self->attrs->len; i++) { |
305 | 0 | FwupdSecurityAttr *attr = g_ptr_array_index(self->attrs, i); |
306 | 0 | if (fwupd_security_attr_has_flag(attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)) |
307 | 0 | continue; |
308 | 0 | if (fwupd_security_attr_has_flag(attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE) && |
309 | 0 | fwupd_security_attr_has_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) |
310 | 0 | continue; |
311 | 0 | if (!fu_security_attr_check_fwupd_version(attr, fwupd_version)) |
312 | 0 | continue; |
313 | | |
314 | 0 | attr_flags |= fwupd_security_attr_get_flags(attr); |
315 | 0 | } |
316 | |
|
317 | 0 | g_string_append_printf(str, "%u", hsi_number); |
318 | 0 | if (attr_flags & FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE) { |
319 | 0 | for (guint j = 0; hpi_suffixes[j] != FWUPD_SECURITY_ATTR_FLAG_NONE; j++) { |
320 | 0 | if (attr_flags & hpi_suffixes[j]) |
321 | 0 | g_string_append( |
322 | 0 | str, |
323 | 0 | fwupd_security_attr_flag_to_suffix(hpi_suffixes[j])); |
324 | 0 | } |
325 | 0 | } |
326 | |
|
327 | 0 | if (flags & FU_SECURITY_ATTRS_FLAG_ADD_VERSION) { |
328 | 0 | g_string_append_printf(str, |
329 | 0 | " (v%d.%d.%d)", |
330 | 0 | FWUPD_MAJOR_VERSION, |
331 | 0 | FWUPD_MINOR_VERSION, |
332 | 0 | FWUPD_MICRO_VERSION); |
333 | 0 | } |
334 | |
|
335 | 0 | return g_string_free(g_steal_pointer(&str), FALSE); |
336 | 0 | } |
337 | | |
338 | | static gchar * |
339 | | fu_security_attrs_get_sort_key(FwupdSecurityAttr *attr) |
340 | 0 | { |
341 | 0 | GString *str = g_string_new(NULL); |
342 | | |
343 | | /* level */ |
344 | 0 | g_string_append_printf(str, "%u", fwupd_security_attr_get_level(attr)); |
345 | | |
346 | | /* success -> fail -> obsoletes */ |
347 | 0 | if (fwupd_security_attr_has_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) { |
348 | 0 | g_string_append(str, "0"); |
349 | 0 | } else if (!fwupd_security_attr_has_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS) && |
350 | 0 | !fwupd_security_attr_has_flag(attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)) { |
351 | 0 | g_string_append(str, "1"); |
352 | 0 | } else { |
353 | 0 | g_string_append(str, "9"); |
354 | 0 | } |
355 | | |
356 | | /* prefer name, but fallback to appstream-id for tests */ |
357 | 0 | if (fwupd_security_attr_get_name(attr) != NULL) { |
358 | 0 | g_string_append(str, fwupd_security_attr_get_name(attr)); |
359 | 0 | } else { |
360 | 0 | g_string_append(str, fwupd_security_attr_get_appstream_id(attr)); |
361 | 0 | } |
362 | 0 | return g_string_free(str, FALSE); |
363 | 0 | } |
364 | | |
365 | | static gint |
366 | | fu_security_attrs_sort_cb(gconstpointer item1, gconstpointer item2) |
367 | 0 | { |
368 | 0 | FwupdSecurityAttr *attr1 = *((FwupdSecurityAttr **)item1); |
369 | 0 | FwupdSecurityAttr *attr2 = *((FwupdSecurityAttr **)item2); |
370 | 0 | g_autofree gchar *sort1 = fu_security_attrs_get_sort_key(attr1); |
371 | 0 | g_autofree gchar *sort2 = fu_security_attrs_get_sort_key(attr2); |
372 | 0 | return g_strcmp0(sort1, sort2); |
373 | 0 | } |
374 | | |
375 | | const struct { |
376 | | const gchar *appstream_id; |
377 | | FwupdSecurityAttrLevel level; |
378 | | } appstream_id_level_map[] = { |
379 | | {FWUPD_SECURITY_ATTR_ID_AMD_ROLLBACK_PROTECTION, FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_PROTECTION}, |
380 | | {FWUPD_SECURITY_ATTR_ID_AMD_SPI_REPLAY_PROTECTION, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL}, |
381 | | {FWUPD_SECURITY_ATTR_ID_AMD_SPI_WRITE_PROTECTION, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT}, |
382 | | {FWUPD_SECURITY_ATTR_ID_AMD_PLATFORM_SECURE_BOOT, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT}, |
383 | | {FWUPD_SECURITY_ATTR_ID_ENCRYPTED_RAM, FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_PROTECTION}, |
384 | | {FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ACM, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT}, |
385 | | {FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ENABLED, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT}, |
386 | | {FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_OTP, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT}, |
387 | | {FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_POLICY, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL}, |
388 | | {FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_VERIFIED, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT}, |
389 | | {FWUPD_SECURITY_ATTR_ID_CET_ACTIVE, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL}, |
390 | | {FWUPD_SECURITY_ATTR_ID_CET_ENABLED, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL}, |
391 | | {FWUPD_SECURITY_ATTR_ID_INTEL_GDS, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT}, |
392 | | {FWUPD_SECURITY_ATTR_ID_SMAP, FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_PROTECTION}, |
393 | | {FWUPD_SECURITY_ATTR_ID_IOMMU, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT}, |
394 | | {FWUPD_SECURITY_ATTR_ID_MEI_MANUFACTURING_MODE, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL}, |
395 | | {FWUPD_SECURITY_ATTR_ID_MEI_OVERRIDE_STRAP, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL}, |
396 | | {FWUPD_SECURITY_ATTR_ID_MEI_KEY_MANIFEST, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL}, |
397 | | {FWUPD_SECURITY_ATTR_ID_MEI_VERSION, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL}, |
398 | | {FWUPD_SECURITY_ATTR_ID_PLATFORM_DEBUG_ENABLED, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL}, |
399 | | {FWUPD_SECURITY_ATTR_ID_PLATFORM_DEBUG_LOCKED, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT}, |
400 | | {FWUPD_SECURITY_ATTR_ID_PLATFORM_FUSED, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL}, |
401 | | {FWUPD_SECURITY_ATTR_ID_PREBOOT_DMA_PROTECTION, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL}, |
402 | | {FWUPD_SECURITY_ATTR_ID_SPI_BIOSWE, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL}, |
403 | | {FWUPD_SECURITY_ATTR_ID_SPI_BLE, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL}, |
404 | | {FWUPD_SECURITY_ATTR_ID_SPI_DESCRIPTOR, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL}, |
405 | | {FWUPD_SECURITY_ATTR_ID_SPI_SMM_BWP, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL}, |
406 | | {FWUPD_SECURITY_ATTR_ID_SUPPORTED_CPU, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL}, |
407 | | {FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_IDLE, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL}, |
408 | | {FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_RAM, FWUPD_SECURITY_ATTR_LEVEL_THEORETICAL}, |
409 | | {FWUPD_SECURITY_ATTR_ID_TPM_EMPTY_PCR, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL}, |
410 | | {FWUPD_SECURITY_ATTR_ID_TPM_RECONSTRUCTION_PCR0, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT}, |
411 | | {FWUPD_SECURITY_ATTR_ID_TPM_VERSION_20, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL}, |
412 | | {FWUPD_SECURITY_ATTR_ID_UEFI_PK, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL}, |
413 | | {FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL}, |
414 | | {FWUPD_SECURITY_ATTR_ID_UEFI_BOOTSERVICE_VARS, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL}, |
415 | | {FWUPD_SECURITY_ATTR_ID_BIOS_ROLLBACK_PROTECTION, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT}, |
416 | | {FWUPD_SECURITY_ATTR_ID_BIOS_CAPSULE_UPDATES, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL}, |
417 | | {FWUPD_SECURITY_ATTR_ID_AMD_SMM_LOCKED, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL}, |
418 | | {FWUPD_SECURITY_ATTR_ID_UEFI_MEMORY_PROTECTION, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT}, |
419 | | {FWUPD_SECURITY_ATTR_ID_UEFI_DB, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT}, |
420 | | {FWUPD_SECURITY_ATTR_ID_HP_SURESTART, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT}, |
421 | | {FWUPD_SECURITY_ATTR_ID_AMD_ENTRY_SIGN, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL}, |
422 | | }; |
423 | | |
424 | | static void |
425 | | fu_security_attrs_ensure_level(FwupdSecurityAttr *attr) |
426 | 0 | { |
427 | 0 | const gchar *appstream_id = fwupd_security_attr_get_appstream_id(attr); |
428 | | |
429 | | /* already set */ |
430 | 0 | if (fwupd_security_attr_get_level(attr) != FWUPD_SECURITY_ATTR_LEVEL_NONE) |
431 | 0 | return; |
432 | | |
433 | | /* not required */ |
434 | 0 | if (fwupd_security_attr_has_flag(attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE)) |
435 | 0 | return; |
436 | | |
437 | | /* map ID to level in one place */ |
438 | 0 | for (guint i = 0; i < G_N_ELEMENTS(appstream_id_level_map); i++) { |
439 | 0 | if (g_strcmp0(appstream_id, appstream_id_level_map[i].appstream_id) == 0) { |
440 | 0 | fwupd_security_attr_set_level(attr, appstream_id_level_map[i].level); |
441 | 0 | return; |
442 | 0 | } |
443 | 0 | } |
444 | | |
445 | | /* somebody forgot to add to the level map... */ |
446 | 0 | g_warning("cannot map %s to a HSI level, assuming critical", appstream_id); |
447 | 0 | fwupd_security_attr_set_level(attr, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL); |
448 | 0 | } |
449 | | |
450 | | const struct { |
451 | | const gchar *appstream_id; |
452 | | const gchar *fwupd_version; |
453 | | } appstream_id_version_map[] = { |
454 | | {FWUPD_SECURITY_ATTR_ID_AMD_ROLLBACK_PROTECTION, "1.8.0"}, |
455 | | {FWUPD_SECURITY_ATTR_ID_AMD_SMM_LOCKED, "2.0.2"}, |
456 | | {FWUPD_SECURITY_ATTR_ID_AMD_SPI_REPLAY_PROTECTION, "1.8.0"}, |
457 | | {FWUPD_SECURITY_ATTR_ID_AMD_SPI_WRITE_PROTECTION, "1.8.0"}, |
458 | | {FWUPD_SECURITY_ATTR_ID_BIOS_CAPSULE_UPDATES, "1.9.6"}, |
459 | | {FWUPD_SECURITY_ATTR_ID_BIOS_ROLLBACK_PROTECTION, "1.8.8"}, |
460 | | {FWUPD_SECURITY_ATTR_ID_AMD_ENTRY_SIGN, "2.1.2"}, |
461 | | {FWUPD_SECURITY_ATTR_ID_AMD_PLATFORM_SECURE_BOOT, "2.1.1"}, |
462 | | {FWUPD_SECURITY_ATTR_ID_CET_ACTIVE, "2.0.0"}, |
463 | | {FWUPD_SECURITY_ATTR_ID_CET_ENABLED, "2.0.0"}, |
464 | | {FWUPD_SECURITY_ATTR_ID_ENCRYPTED_RAM, "1.5.0"}, |
465 | | {FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ACM, "1.5.0"}, |
466 | | {FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ENABLED, "1.5.0"}, |
467 | | {FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_OTP, "1.5.0"}, |
468 | | {FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_POLICY, "1.5.0"}, |
469 | | {FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_VERIFIED, "1.5.0"}, |
470 | | {FWUPD_SECURITY_ATTR_ID_INTEL_GDS, "1.9.4"}, |
471 | | {FWUPD_SECURITY_ATTR_ID_IOMMU, "1.5.0"}, |
472 | | {FWUPD_SECURITY_ATTR_ID_KERNEL_LOCKDOWN, "1.5.0"}, |
473 | | {FWUPD_SECURITY_ATTR_ID_KERNEL_TAINTED, "1.5.0"}, |
474 | | {FWUPD_SECURITY_ATTR_ID_MEI_KEY_MANIFEST, "1.8.7"}, |
475 | | {FWUPD_SECURITY_ATTR_ID_MEI_MANUFACTURING_MODE, "1.5.0"}, |
476 | | {FWUPD_SECURITY_ATTR_ID_MEI_OVERRIDE_STRAP, "1.5.0"}, |
477 | | {FWUPD_SECURITY_ATTR_ID_MEI_VERSION, "1.5.0"}, |
478 | | {FWUPD_SECURITY_ATTR_ID_PLATFORM_DEBUG_ENABLED, "1.5.0"}, |
479 | | {FWUPD_SECURITY_ATTR_ID_PLATFORM_DEBUG_LOCKED, "1.8.0"}, |
480 | | {FWUPD_SECURITY_ATTR_ID_PLATFORM_FUSED, "1.8.0"}, |
481 | | {FWUPD_SECURITY_ATTR_ID_PREBOOT_DMA_PROTECTION, "1.8.0"}, |
482 | | {FWUPD_SECURITY_ATTR_ID_SMAP, "2.0.0"}, |
483 | | {FWUPD_SECURITY_ATTR_ID_SPI_BIOSWE, "1.5.0"}, |
484 | | {FWUPD_SECURITY_ATTR_ID_SPI_BLE, "1.5.0"}, |
485 | | {FWUPD_SECURITY_ATTR_ID_SPI_DESCRIPTOR, "1.6.0"}, |
486 | | {FWUPD_SECURITY_ATTR_ID_SPI_SMM_BWP, "1.5.0"}, |
487 | | {FWUPD_SECURITY_ATTR_ID_SUPPORTED_CPU, "1.8.0"}, |
488 | | {FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_IDLE, "1.5.0"}, |
489 | | {FWUPD_SECURITY_ATTR_ID_SUSPEND_TO_RAM, "1.5.0"}, |
490 | | {FWUPD_SECURITY_ATTR_ID_TPM_EMPTY_PCR, "1.7.2"}, |
491 | | {FWUPD_SECURITY_ATTR_ID_TPM_RECONSTRUCTION_PCR0, "1.5.0"}, |
492 | | {FWUPD_SECURITY_ATTR_ID_TPM_VERSION_20, "1.5.0"}, |
493 | | {FWUPD_SECURITY_ATTR_ID_UEFI_BOOTSERVICE_VARS, "1.9.3"}, |
494 | | {FWUPD_SECURITY_ATTR_ID_UEFI_DB, "2.0.8"}, |
495 | | {FWUPD_SECURITY_ATTR_ID_UEFI_MEMORY_PROTECTION, "2.0.7"}, |
496 | | {FWUPD_SECURITY_ATTR_ID_UEFI_PK, "1.5.0"}, |
497 | | {FWUPD_SECURITY_ATTR_ID_UEFI_SECUREBOOT, "1.5.0"}, |
498 | | {FWUPD_SECURITY_ATTR_ID_HP_SURESTART, "2.1.1"}, |
499 | | }; |
500 | | |
501 | | static void |
502 | | fu_security_attrs_ensure_fwupd_version(FwupdSecurityAttr *attr) |
503 | 0 | { |
504 | 0 | const gchar *appstream_id = fwupd_security_attr_get_appstream_id(attr); |
505 | | |
506 | | /* already set */ |
507 | 0 | if (fwupd_security_attr_get_fwupd_version(attr) != NULL) |
508 | 0 | return; |
509 | | |
510 | | /* not required */ |
511 | 0 | if (fwupd_security_attr_has_flag(attr, FWUPD_SECURITY_ATTR_FLAG_RUNTIME_ISSUE)) |
512 | 0 | return; |
513 | | |
514 | | /* map ID to fwupd version in one place */ |
515 | 0 | for (guint i = 0; i < G_N_ELEMENTS(appstream_id_version_map); i++) { |
516 | 0 | if (g_strcmp0(appstream_id, appstream_id_version_map[i].appstream_id) == 0) { |
517 | 0 | fwupd_security_attr_set_fwupd_version( |
518 | 0 | attr, |
519 | 0 | appstream_id_version_map[i].fwupd_version); |
520 | 0 | return; |
521 | 0 | } |
522 | 0 | } |
523 | | |
524 | | /* somebody forgot to add to the level map... */ |
525 | 0 | g_warning("cannot map %s to a fwupd version", appstream_id); |
526 | 0 | } |
527 | | |
528 | | /** |
529 | | * fu_security_attrs_depsolve: |
530 | | * @self: a #FuSecurityAttrs |
531 | | * |
532 | | * Marks any attributes with %FWUPD_SECURITY_ATTR_FLAG_OBSOLETED that have been |
533 | | * defined as obsoleted by other attributes. |
534 | | * |
535 | | * It is only required to call this function once, and should be done when all |
536 | | * attributes have been added. This will also sort the attrs. |
537 | | * |
538 | | * Since: 1.5.0 |
539 | | **/ |
540 | | void |
541 | | fu_security_attrs_depsolve(FuSecurityAttrs *self) |
542 | 0 | { |
543 | 0 | g_return_if_fail(FU_IS_SECURITY_ATTRS(self)); |
544 | | |
545 | | /* assign HSI levels if not already done */ |
546 | 0 | for (guint i = 0; i < self->attrs->len; i++) { |
547 | 0 | FwupdSecurityAttr *attr = g_ptr_array_index(self->attrs, i); |
548 | 0 | fu_security_attrs_ensure_level(attr); |
549 | 0 | fu_security_attrs_ensure_fwupd_version(attr); |
550 | 0 | } |
551 | | |
552 | | /* set flat where required */ |
553 | 0 | for (guint i = 0; i < self->attrs->len; i++) { |
554 | 0 | FwupdSecurityAttr *attr = g_ptr_array_index(self->attrs, i); |
555 | 0 | const gchar *attr_id = fwupd_security_attr_get_appstream_id(attr); |
556 | 0 | const gchar *attr_plugin = fwupd_security_attr_get_plugin(attr); |
557 | 0 | GPtrArray *obsoletes = fwupd_security_attr_get_obsoletes(attr); |
558 | |
|
559 | 0 | for (guint j = 0; j < self->attrs->len; j++) { |
560 | 0 | FwupdSecurityAttr *attr_tmp = g_ptr_array_index(self->attrs, j); |
561 | 0 | const gchar *attr_tmp_id = fwupd_security_attr_get_appstream_id(attr_tmp); |
562 | 0 | const gchar *attr_tmp_plugin = fwupd_security_attr_get_plugin(attr_tmp); |
563 | | |
564 | | /* skip self */ |
565 | 0 | if (g_strcmp0(attr_plugin, attr_tmp_plugin) == 0 && |
566 | 0 | g_strcmp0(attr_id, attr_tmp_id) == 0) |
567 | 0 | continue; |
568 | | |
569 | | /* add duplicate (negative) attributes when obsolete not explicitly set |
570 | | */ |
571 | 0 | if (obsoletes->len == 0) { |
572 | 0 | if (g_strcmp0(attr_id, attr_tmp_id) != 0) |
573 | 0 | continue; |
574 | 0 | if (fwupd_security_attr_has_flag(attr, |
575 | 0 | FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) |
576 | 0 | continue; |
577 | 0 | if (fwupd_security_attr_has_flag(attr_tmp, |
578 | 0 | FWUPD_SECURITY_ATTR_FLAG_SUCCESS)) |
579 | 0 | continue; |
580 | | |
581 | 0 | if (fwupd_security_attr_has_obsolete(attr, attr_id)) |
582 | 0 | continue; |
583 | 0 | if (fwupd_security_attr_has_obsolete(attr_tmp, attr_id)) |
584 | 0 | continue; |
585 | 0 | g_debug("duplicate security attr %s from plugin %s implicitly " |
586 | 0 | "obsoleted by plugin %s", |
587 | 0 | attr_id, |
588 | 0 | attr_plugin, |
589 | 0 | attr_tmp_plugin); |
590 | 0 | fwupd_security_attr_add_obsolete(attr, attr_id); |
591 | 0 | } |
592 | | |
593 | | /* walk all the obsoletes for matches appstream ID or plugin */ |
594 | 0 | for (guint k = 0; k < obsoletes->len; k++) { |
595 | 0 | const gchar *obsolete = g_ptr_array_index(obsoletes, k); |
596 | |
|
597 | 0 | if (g_strcmp0(attr_tmp_id, obsolete) == 0 || |
598 | 0 | g_strcmp0(attr_tmp_plugin, obsolete) == 0) { |
599 | 0 | g_debug("security attr %s:%s obsoleted by %s:%s", |
600 | 0 | attr_tmp_id, |
601 | 0 | attr_tmp_plugin, |
602 | 0 | attr_id, |
603 | 0 | attr_plugin); |
604 | 0 | fwupd_security_attr_add_flag( |
605 | 0 | attr_tmp, |
606 | 0 | FWUPD_SECURITY_ATTR_FLAG_OBSOLETED); |
607 | 0 | } |
608 | 0 | } |
609 | 0 | } |
610 | 0 | } |
611 | | |
612 | | /* sort */ |
613 | 0 | g_ptr_array_sort(self->attrs, fu_security_attrs_sort_cb); |
614 | 0 | } |
615 | | |
616 | | static void |
617 | | fu_security_attrs_add_json(FwupdCodec *codec, FwupdJsonObject *json_obj, FwupdCodecFlags flags) |
618 | 0 | { |
619 | 0 | FuSecurityAttrs *self = FU_SECURITY_ATTRS(codec); |
620 | 0 | g_autoptr(GPtrArray) items = fu_security_attrs_get_all(self, NULL); |
621 | 0 | g_autoptr(FwupdJsonArray) json_arr = fwupd_json_array_new(); |
622 | |
|
623 | 0 | for (guint i = 0; i < items->len; i++) { |
624 | 0 | FwupdSecurityAttr *attr = g_ptr_array_index(items, i); |
625 | 0 | guint64 created = fwupd_security_attr_get_created(attr); |
626 | 0 | g_autoptr(FwupdJsonObject) json_obj_tmp = fwupd_json_object_new(); |
627 | |
|
628 | 0 | if (fwupd_security_attr_has_flag(attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)) |
629 | 0 | continue; |
630 | 0 | fwupd_security_attr_set_created(attr, 0); |
631 | 0 | fwupd_codec_to_json(FWUPD_CODEC(attr), json_obj_tmp, FWUPD_CODEC_FLAG_NONE); |
632 | 0 | fwupd_security_attr_set_created(attr, created); |
633 | 0 | fwupd_json_array_add_object(json_arr, json_obj_tmp); |
634 | 0 | } |
635 | 0 | fwupd_json_object_add_array(json_obj, "SecurityAttributes", json_arr); |
636 | 0 | } |
637 | | |
638 | | static gboolean |
639 | | fu_security_attrs_from_json(FwupdCodec *codec, FwupdJsonObject *json_obj, GError **error) |
640 | 0 | { |
641 | 0 | FuSecurityAttrs *self = FU_SECURITY_ATTRS(codec); |
642 | 0 | g_autoptr(FwupdJsonArray) json_arr = NULL; |
643 | | |
644 | | /* this has to exist */ |
645 | 0 | json_arr = fwupd_json_object_get_array(json_obj, "SecurityAttributes", error); |
646 | 0 | if (json_arr == NULL) |
647 | 0 | return FALSE; |
648 | 0 | for (guint i = 0; i < fwupd_json_array_get_size(json_arr); i++) { |
649 | 0 | g_autoptr(FwupdJsonObject) json_obj_tmp = NULL; |
650 | 0 | g_autoptr(FwupdSecurityAttr) attr = fwupd_security_attr_new(NULL); |
651 | |
|
652 | 0 | json_obj_tmp = fwupd_json_array_get_object(json_arr, i, error); |
653 | 0 | if (json_obj_tmp == NULL) |
654 | 0 | return FALSE; |
655 | 0 | if (!fwupd_codec_from_json(FWUPD_CODEC(attr), json_obj_tmp, error)) |
656 | 0 | return FALSE; |
657 | 0 | if (fwupd_security_attr_has_flag(attr, FWUPD_SECURITY_ATTR_FLAG_OBSOLETED)) |
658 | 0 | continue; |
659 | 0 | fu_security_attrs_append(self, attr); |
660 | 0 | } |
661 | | |
662 | | /* success */ |
663 | 0 | return TRUE; |
664 | 0 | } |
665 | | |
666 | | static void |
667 | | fu_security_attrs_codec_iface_init(FwupdCodecInterface *iface) |
668 | 0 | { |
669 | 0 | iface->add_json = fu_security_attrs_add_json; |
670 | 0 | iface->from_json = fu_security_attrs_from_json; |
671 | 0 | } |
672 | | |
673 | | /** |
674 | | * fu_security_attrs_compare: |
675 | | * @attrs1: a #FuSecurityAttrs |
676 | | * @attrs2: another #FuSecurityAttrs, perhaps newer in some way |
677 | | * |
678 | | * Compares the two objects, returning the differences. |
679 | | * |
680 | | * If the two sets of attrs are considered the same then an empty array is returned. |
681 | | * Only the AppStream ID results are compared, extra metadata is ignored. |
682 | | * |
683 | | * Returns: (element-type FwupdSecurityAttr) (transfer container): differences |
684 | | * |
685 | | * Since: 1.9.2 |
686 | | */ |
687 | | GPtrArray * |
688 | | fu_security_attrs_compare(FuSecurityAttrs *attrs1, FuSecurityAttrs *attrs2) |
689 | 0 | { |
690 | 0 | g_autoptr(GHashTable) hash1 = g_hash_table_new(g_str_hash, g_str_equal); |
691 | 0 | g_autoptr(GHashTable) hash2 = g_hash_table_new(g_str_hash, g_str_equal); |
692 | 0 | g_autoptr(GPtrArray) array1 = fu_security_attrs_get_all(attrs1, NULL); |
693 | 0 | g_autoptr(GPtrArray) array2 = fu_security_attrs_get_all(attrs2, NULL); |
694 | 0 | g_autoptr(GPtrArray) results = |
695 | 0 | g_ptr_array_new_with_free_func((GDestroyNotify)g_object_unref); |
696 | |
|
697 | 0 | g_return_val_if_fail(FU_IS_SECURITY_ATTRS(attrs1), NULL); |
698 | 0 | g_return_val_if_fail(FU_IS_SECURITY_ATTRS(attrs2), NULL); |
699 | | |
700 | | /* create hash tables of appstream-id -> FwupdSecurityAttr */ |
701 | 0 | for (guint i = 0; i < array1->len; i++) { |
702 | 0 | FwupdSecurityAttr *attr1 = g_ptr_array_index(array1, i); |
703 | 0 | g_hash_table_insert(hash1, |
704 | 0 | (gpointer)fwupd_security_attr_get_appstream_id(attr1), |
705 | 0 | (gpointer)attr1); |
706 | 0 | } |
707 | 0 | for (guint i = 0; i < array2->len; i++) { |
708 | 0 | FwupdSecurityAttr *attr2 = g_ptr_array_index(array2, i); |
709 | 0 | g_hash_table_insert(hash2, |
710 | 0 | (gpointer)fwupd_security_attr_get_appstream_id(attr2), |
711 | 0 | (gpointer)attr2); |
712 | 0 | } |
713 | | |
714 | | /* present in attrs2, not present in attrs1 */ |
715 | 0 | for (guint i = 0; i < array2->len; i++) { |
716 | 0 | FwupdSecurityAttr *attr1; |
717 | 0 | FwupdSecurityAttr *attr2 = g_ptr_array_index(array2, i); |
718 | 0 | attr1 = g_hash_table_lookup(hash1, fwupd_security_attr_get_appstream_id(attr2)); |
719 | 0 | if (attr1 == NULL) { |
720 | 0 | g_autoptr(FwupdSecurityAttr) attr = fwupd_security_attr_copy(attr2); |
721 | 0 | g_ptr_array_add(results, g_steal_pointer(&attr)); |
722 | 0 | continue; |
723 | 0 | } |
724 | 0 | } |
725 | | |
726 | | /* present in attrs1, not present in attrs2 */ |
727 | 0 | for (guint i = 0; i < array1->len; i++) { |
728 | 0 | FwupdSecurityAttr *attr1 = g_ptr_array_index(array1, i); |
729 | 0 | FwupdSecurityAttr *attr2; |
730 | 0 | attr2 = g_hash_table_lookup(hash2, fwupd_security_attr_get_appstream_id(attr1)); |
731 | 0 | if (attr2 == NULL) { |
732 | 0 | g_autoptr(FwupdSecurityAttr) attr = fwupd_security_attr_copy(attr1); |
733 | 0 | fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_UNKNOWN); |
734 | 0 | fwupd_security_attr_set_result_fallback( |
735 | 0 | attr, /* flip these around */ |
736 | 0 | fwupd_security_attr_get_result(attr1)); |
737 | 0 | g_ptr_array_add(results, g_steal_pointer(&attr)); |
738 | 0 | continue; |
739 | 0 | } |
740 | 0 | } |
741 | | |
742 | | /* find any attributes that differ */ |
743 | 0 | for (guint i = 0; i < array2->len; i++) { |
744 | 0 | FwupdSecurityAttr *attr1; |
745 | 0 | FwupdSecurityAttr *attr2 = g_ptr_array_index(array2, i); |
746 | 0 | attr1 = g_hash_table_lookup(hash1, fwupd_security_attr_get_appstream_id(attr2)); |
747 | 0 | if (attr1 == NULL) |
748 | 0 | continue; |
749 | | |
750 | | /* result of specific attr differed */ |
751 | 0 | if (fwupd_security_attr_get_result(attr1) != |
752 | 0 | fwupd_security_attr_get_result(attr2)) { |
753 | 0 | g_autoptr(FwupdSecurityAttr) attr = fwupd_security_attr_copy(attr1); |
754 | 0 | fwupd_security_attr_set_result(attr, fwupd_security_attr_get_result(attr2)); |
755 | 0 | fwupd_security_attr_set_result_fallback( |
756 | 0 | attr, |
757 | 0 | fwupd_security_attr_get_result(attr1)); |
758 | 0 | fwupd_security_attr_set_flags(attr, fwupd_security_attr_get_flags(attr2)); |
759 | 0 | g_ptr_array_add(results, g_steal_pointer(&attr)); |
760 | 0 | } |
761 | 0 | } |
762 | | |
763 | | /* success */ |
764 | 0 | return g_steal_pointer(&results); |
765 | 0 | } |
766 | | |
767 | | /** |
768 | | * fu_security_attrs_equal: |
769 | | * @attrs1: a #FuSecurityAttrs |
770 | | * @attrs2: another #FuSecurityAttrs |
771 | | * |
772 | | * Tests the objects for equality. Only the AppStream ID results are compared, extra metadata |
773 | | * is ignored. |
774 | | * |
775 | | * Returns: %TRUE if the set of attrs can be considered equal |
776 | | * |
777 | | * Since: 1.9.2 |
778 | | */ |
779 | | gboolean |
780 | | fu_security_attrs_equal(FuSecurityAttrs *attrs1, FuSecurityAttrs *attrs2) |
781 | 0 | { |
782 | 0 | g_autoptr(GPtrArray) compare = fu_security_attrs_compare(attrs1, attrs2); |
783 | 0 | return compare->len == 0; |
784 | 0 | } |
785 | | |
786 | | /** |
787 | | * fu_security_attrs_new: |
788 | | * |
789 | | * Returns: a security attribute |
790 | | * |
791 | | * Since: 1.5.0 |
792 | | **/ |
793 | | FuSecurityAttrs * |
794 | | fu_security_attrs_new(void) |
795 | 0 | { |
796 | 0 | return g_object_new(FU_TYPE_SECURITY_ATTRS, NULL); |
797 | 0 | } |