Coverage Report

Created: 2026-04-09 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fwupd/libfwupdplugin/fu-intel-me-device.c
Line
Count
Source
1
/*
2
 * Copyright 2025 Richard Hughes <richard@hughsie.com>
3
 *
4
 * SPDX-License-Identifier: LGPL-2.1-or-later
5
 */
6
7
#include "config.h"
8
9
#include "fwupd-security-attr-private.h"
10
11
#include "fu-intel-me-device.h"
12
#include "fu-string.h"
13
14
struct _FuIntelMeDevice {
15
  FuDevice parent_instance;
16
  FuIntelMeFamily family;
17
  FuIntelMeIssue issue;
18
  FuMeHfsCws working_state;
19
  FuStructIntelMeHfsts *hfsts[7]; /* 1-6, 0 unused */
20
};
21
22
0
G_DEFINE_TYPE(FuIntelMeDevice, fu_intel_me_device, FU_TYPE_DEVICE)
23
0
24
0
/**
25
0
 * fu_intel_me_device_get_family:
26
0
 * @self: a #FuIntelMeDevice
27
0
 *
28
0
 * Gets the ME device family.
29
0
 *
30
0
 * Returns: a #FuIntelMeFamily, e.g. #FU_INTEL_ME_FAMILY_CSME11
31
0
 *
32
0
 * Since: 2.1.1
33
0
 **/
34
0
FuIntelMeFamily
35
0
fu_intel_me_device_get_family(FuIntelMeDevice *self)
36
0
{
37
0
  g_return_val_if_fail(FU_IS_INTEL_ME_DEVICE(self), FU_INTEL_ME_FAMILY_UNKNOWN);
38
0
  return self->family;
39
0
}
40
41
/**
42
 * fu_intel_me_device_get_issue:
43
 * @self: a #FuIntelMeDevice
44
 *
45
 * Gets the ME device issue.
46
 *
47
 * Returns: a #FuIntelMeIssue, e.g. #FU_INTEL_ME_ISSUE_NOT_VULNERABLE
48
 *
49
 * Since: 2.1.1
50
 **/
51
FuIntelMeIssue
52
fu_intel_me_device_get_issue(FuIntelMeDevice *self)
53
0
{
54
0
  g_return_val_if_fail(FU_IS_INTEL_ME_DEVICE(self), FU_INTEL_ME_ISSUE_UNKNOWN);
55
0
  return self->issue;
56
0
}
57
58
static void
59
fu_intel_me_device_to_string(FuDevice *device, guint idt, GString *str)
60
0
{
61
0
  FuIntelMeDevice *self = FU_INTEL_ME_DEVICE(device);
62
0
  fwupd_codec_string_append(str, idt, "Family", fu_intel_me_family_to_string(self->family));
63
0
  fwupd_codec_string_append(str, idt, "Issue", fu_intel_me_issue_to_string(self->issue));
64
0
  fwupd_codec_string_append(str,
65
0
          idt,
66
0
          "WorkingState",
67
0
          fu_me_hfs_cws_to_string(self->working_state));
68
0
  for (guint i = 1; i < G_N_ELEMENTS(self->hfsts); i++) {
69
0
    g_autofree gchar *title = g_strdup_printf("Hfsts%x", i);
70
0
    if (self->hfsts[i] != NULL)
71
0
      fwupd_codec_string_append_hex(
72
0
          str,
73
0
          idt,
74
0
          title,
75
0
          fu_struct_intel_me_hfsts_get_value(self->hfsts[i]));
76
0
  }
77
0
}
78
79
typedef struct {
80
  guint8 major;
81
  guint8 minor;
82
  guint8 patch;
83
  guint16 buildno;
84
} FuIntelMeVersions;
85
86
static FuIntelMeVersions *
87
fu_intel_me_device_parse_versions(FuIntelMeDevice *self, GError **error)
88
0
{
89
0
  const gchar *version = fu_device_get_version(FU_DEVICE(self));
90
0
  guint64 tmp64 = 0;
91
0
  g_autofree FuIntelMeVersions *vers = g_new0(FuIntelMeVersions, 1);
92
0
  g_auto(GStrv) split = NULL;
93
94
  /* parse vers */
95
0
  split = g_strsplit(version, ".", -1);
96
0
  if (g_strv_length(split) != 4) {
97
0
    g_set_error(error,
98
0
          FWUPD_ERROR,
99
0
          FWUPD_ERROR_INVALID_DATA,
100
0
          "expected major.minor.micro.build, got %s",
101
0
          version);
102
0
    return NULL;
103
0
  }
104
0
  if (!fu_strtoull(split[0], &tmp64, 0, G_MAXUINT8, FU_INTEGER_BASE_AUTO, error)) {
105
0
    g_prefix_error(error, "failed to process major version %s: ", split[0]);
106
0
    return NULL;
107
0
  }
108
0
  vers->major = tmp64;
109
0
  if (!fu_strtoull(split[1], &tmp64, 0, G_MAXUINT8, FU_INTEGER_BASE_AUTO, error)) {
110
0
    g_prefix_error(error, "failed to process minor version %s: ", split[1]);
111
0
    return NULL;
112
0
  }
113
0
  vers->minor = tmp64;
114
0
  if (!fu_strtoull(split[2], &tmp64, 0, G_MAXUINT8, FU_INTEGER_BASE_AUTO, error)) {
115
0
    g_prefix_error(error, "failed to process patch version %s: ", split[2]);
116
0
    return NULL;
117
0
  }
118
0
  vers->patch = tmp64;
119
0
  if (!fu_strtoull(split[3], &tmp64, 0, G_MAXUINT16, FU_INTEGER_BASE_AUTO, error)) {
120
0
    g_prefix_error(error, "failed to process buildno version %s: ", split[3]);
121
0
    return NULL;
122
0
  }
123
0
  vers->buildno = tmp64;
124
125
  /* success */
126
0
  return g_steal_pointer(&vers);
127
0
}
128
129
static void
130
fu_intel_me_device_version_notify_cb(FuDevice *device, GParamSpec *pspec, gpointer user_data)
131
0
{
132
0
  FuIntelMeDevice *self = FU_INTEL_ME_DEVICE(device);
133
0
  g_autofree FuIntelMeVersions *vers = NULL;
134
0
  g_autoptr(GError) error = NULL;
135
0
  struct {
136
0
    FuIntelMeFamily family;
137
0
    guint8 major_eq;
138
0
    guint8 minor_eq;
139
0
    guint8 patch_ge;
140
0
  } verdata[] = {
141
0
      {FU_INTEL_ME_FAMILY_TXE, 3, 1, 92},
142
0
      {FU_INTEL_ME_FAMILY_TXE, 4, 0, 45},
143
0
      {FU_INTEL_ME_FAMILY_CSME11, 11, 8, 92},
144
0
      {FU_INTEL_ME_FAMILY_CSME11, 11, 12, 92},
145
0
      {FU_INTEL_ME_FAMILY_CSME11, 11, 22, 92},
146
0
      {FU_INTEL_ME_FAMILY_CSME11, 12, 0, 90},
147
0
      {FU_INTEL_ME_FAMILY_CSME11, 13, 0, 60},
148
0
      {FU_INTEL_ME_FAMILY_CSME11, 13, 30, 30},
149
0
      {FU_INTEL_ME_FAMILY_CSME11, 13, 50, 20},
150
0
      {FU_INTEL_ME_FAMILY_CSME11, 14, 1, 65},
151
0
      {FU_INTEL_ME_FAMILY_CSME11, 14, 5, 45},
152
0
      {FU_INTEL_ME_FAMILY_CSME11, 15, 0, 40},
153
0
      {FU_INTEL_ME_FAMILY_CSME11, 15, 40, 20},
154
0
  };
155
156
  /* parse into 4 sections */
157
0
  if (fu_device_get_version(device) == NULL)
158
0
    return;
159
0
  vers = fu_intel_me_device_parse_versions(self, &error);
160
0
  if (vers == NULL) {
161
0
    g_warning("failed to parse ME version: %s", error->message);
162
0
    return;
163
0
  }
164
165
  /* set the family */
166
0
  if (vers->major == 0) {
167
0
    self->family = FU_INTEL_ME_FAMILY_UNKNOWN;
168
0
  } else if (vers->major == 1 || vers->major == 2 || vers->major == 3 || vers->major == 4 ||
169
0
       vers->major == 5) {
170
    /* not completely true, but good enough for 2025... */
171
0
    self->family = FU_INTEL_ME_FAMILY_TXE;
172
0
  } else if (vers->major == 6 || vers->major == 7 || vers->major == 8 || vers->major == 9 ||
173
0
       vers->major == 10) {
174
0
    self->family = FU_INTEL_ME_FAMILY_ME;
175
0
  } else if (vers->major == 11 || vers->major == 12 || vers->major == 13 ||
176
0
       vers->major == 14 || vers->major == 15) {
177
0
    self->family = FU_INTEL_ME_FAMILY_CSME11;
178
0
  } else if (vers->major == 16 || vers->major == 17) {
179
0
    self->family = FU_INTEL_ME_FAMILY_CSME16;
180
0
  } else {
181
0
    self->family = FU_INTEL_ME_FAMILY_CSME18;
182
0
  }
183
184
  /* check the AMT version for issues using the data from:
185
   * https://downloadcenter.intel.com/download/28632 */
186
0
  self->issue = FU_INTEL_ME_ISSUE_NOT_VULNERABLE;
187
0
  for (guint i = 0; i < G_N_ELEMENTS(verdata); i++) {
188
0
    if (self->family == verdata[i].family && vers->major == verdata[i].major_eq &&
189
0
        vers->minor == verdata[i].minor_eq) {
190
0
      self->issue = vers->patch >= verdata[i].patch_ge
191
0
            ? FU_INTEL_ME_ISSUE_PATCHED
192
0
            : FU_INTEL_ME_ISSUE_VULNERABLE;
193
0
      break;
194
0
    }
195
0
  }
196
0
}
197
198
/**
199
 * fu_intel_me_device_get_hfsts: (skip):
200
 * @self: a #FuIntelMeDevice
201
 * @idx: index, 1-6
202
 *
203
 * Gets a HFSTSx register.
204
 *
205
 * Returns: (transfer none): a #FuStructIntelMeHfsts, or %NULL if unset
206
 *
207
 * Since: 2.1.1
208
 **/
209
FuStructIntelMeHfsts *
210
fu_intel_me_device_get_hfsts(FuIntelMeDevice *self, guint idx)
211
0
{
212
0
  g_return_val_if_fail(FU_IS_INTEL_ME_DEVICE(self), NULL);
213
0
  g_return_val_if_fail(idx != 0, NULL);
214
0
  g_return_val_if_fail(idx < G_N_ELEMENTS(self->hfsts), NULL);
215
0
  return self->hfsts[idx];
216
0
}
217
218
/**
219
 * fu_intel_me_device_set_hfsts: (skip):
220
 * @self: a #FuIntelMeDevice
221
 * @idx: index, 1-6
222
 * @hfsts: a #FuStructIntelMeHfsts
223
 *
224
 * Sets a HFSTSx register.
225
 *
226
 * Since: 2.1.1
227
 **/
228
void
229
fu_intel_me_device_set_hfsts(FuIntelMeDevice *self, guint idx, FuStructIntelMeHfsts *hfsts)
230
0
{
231
0
  g_return_if_fail(FU_IS_INTEL_ME_DEVICE(self));
232
0
  g_return_if_fail(idx != 0);
233
0
  g_return_if_fail(idx < G_N_ELEMENTS(self->hfsts));
234
235
  /* not 100% true, but the CWS section is the same for CSME11 and CSME18 */
236
0
  if (idx == 1) {
237
0
    g_autoptr(FuMeiCsme11Hfsts1) st = NULL;
238
0
    st = fu_mei_csme11_hfsts1_parse(hfsts->buf->data, hfsts->buf->len, 0x0, NULL);
239
0
    if (st != NULL)
240
0
      self->working_state = fu_mei_csme11_hfsts1_get_working_state(st);
241
0
  }
242
243
  /* save buffer for later */
244
0
  if (self->hfsts[idx] != NULL)
245
0
    fu_struct_intel_me_hfsts_unref(self->hfsts[idx]);
246
0
  self->hfsts[idx] = fu_struct_intel_me_hfsts_ref(hfsts);
247
0
}
248
249
static void
250
fu_intel_me_device_add_attrs_csme11_manufacturing_mode(FuIntelMeDevice *self,
251
                   FuMeiCsme11Hfsts1 *hfsts1,
252
                   FuSecurityAttrs *attrs)
253
0
{
254
0
  g_autoptr(FwupdSecurityAttr) attr = NULL;
255
256
  /*
257
   * For CSMEv11->CSMEv15 `mfg_mode` is used to indicate the ME being in manufacturing mode,
258
   * but for CSMEv16+ this bit has been repurposed to indicate whether BIOS has write access
259
   * to the flash descriptor.
260
   */
261
0
  if (self->family == FU_INTEL_ME_FAMILY_CSME16)
262
0
    return;
263
264
  /* create attr */
265
0
  attr = fu_device_security_attr_new(FU_DEVICE(self),
266
0
             FWUPD_SECURITY_ATTR_ID_MEI_MANUFACTURING_MODE);
267
0
  fwupd_security_attr_set_result_success(attr, FWUPD_SECURITY_ATTR_RESULT_LOCKED);
268
0
  fu_security_attrs_append(attrs, attr);
269
270
  /* manufacturing mode */
271
0
  fwupd_security_attr_add_metadata(attr, "kind", fu_intel_me_family_to_string(self->family));
272
0
  if (fu_mei_csme11_hfsts1_get_mfg_mode(hfsts1)) {
273
0
    fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED);
274
0
    fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM);
275
0
    return;
276
0
  }
277
278
  /* success */
279
0
  fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS);
280
0
}
281
282
static void
283
fu_intel_me_device_add_attrs_csme18_manufacturing_mode(FuIntelMeDevice *self,
284
                   FuMeiCsme18Hfsts1 *hfsts1,
285
                   FuSecurityAttrs *attrs)
286
0
{
287
0
  g_autoptr(FwupdSecurityAttr) attr = NULL;
288
289
  /* create attr */
290
0
  attr = fu_device_security_attr_new(FU_DEVICE(self),
291
0
             FWUPD_SECURITY_ATTR_ID_MEI_MANUFACTURING_MODE);
292
0
  fwupd_security_attr_set_result_success(attr, FWUPD_SECURITY_ATTR_RESULT_LOCKED);
293
0
  fu_security_attrs_append(attrs, attr);
294
295
  /* manufacturing mode, BIOS has access to the SPI descriptor */
296
0
  if (fu_mei_csme18_hfsts1_get_spi_protection_mode(hfsts1)) {
297
0
    fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED);
298
0
    fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM);
299
0
    return;
300
0
  }
301
302
  /* running in debug mode */
303
0
  if (fu_mei_csme18_hfsts1_get_operation_mode(hfsts1) == FU_ME_HFS_MODE_DEBUG ||
304
0
      fu_mei_csme18_hfsts1_get_operation_mode(hfsts1) == FU_ME_HFS_MODE_ENHANCED_DEBUG) {
305
0
    fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID);
306
0
    fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM);
307
0
    return;
308
0
  }
309
310
  /* success */
311
0
  fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS);
312
0
}
313
314
static void
315
fu_intel_me_device_add_attrs_csme11_override_strap(FuIntelMeDevice *self,
316
               FuMeiCsme11Hfsts1 *hfsts1,
317
               FuSecurityAttrs *attrs)
318
0
{
319
0
  g_autoptr(FwupdSecurityAttr) attr = NULL;
320
321
  /* create attr */
322
0
  attr =
323
0
      fu_device_security_attr_new(FU_DEVICE(self), FWUPD_SECURITY_ATTR_ID_MEI_OVERRIDE_STRAP);
324
0
  fwupd_security_attr_set_result_success(attr, FWUPD_SECURITY_ATTR_RESULT_LOCKED);
325
0
  fu_security_attrs_append(attrs, attr);
326
327
  /* flash descriptor security override strap */
328
0
  fwupd_security_attr_add_metadata(attr, "kind", fu_intel_me_family_to_string(self->family));
329
0
  if (fu_mei_csme11_hfsts1_get_operation_mode(hfsts1) == FU_ME_HFS_MODE_OVERRIDE_JUMPER) {
330
0
    fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED);
331
0
    fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM);
332
0
    return;
333
0
  }
334
335
  /* success */
336
0
  fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS);
337
0
}
338
339
static void
340
fu_intel_me_device_add_attrs_csme18_override_strap(FuIntelMeDevice *self,
341
               FuMeiCsme18Hfsts1 *hfsts1,
342
               FuSecurityAttrs *attrs)
343
0
{
344
0
  g_autoptr(FwupdSecurityAttr) attr = NULL;
345
346
  /* create attr */
347
0
  attr =
348
0
      fu_device_security_attr_new(FU_DEVICE(self), FWUPD_SECURITY_ATTR_ID_MEI_OVERRIDE_STRAP);
349
0
  fwupd_security_attr_set_result_success(attr, FWUPD_SECURITY_ATTR_RESULT_LOCKED);
350
0
  fu_security_attrs_append(attrs, attr);
351
352
  /* flash descriptor security override strap */
353
0
  fwupd_security_attr_add_metadata(attr, "kind", fu_intel_me_family_to_string(self->family));
354
0
  if (fu_mei_csme18_hfsts1_get_operation_mode(hfsts1) == FU_ME_HFS_MODE_OVERRIDE_JUMPER) {
355
0
    fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_NOT_LOCKED);
356
0
    fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM);
357
0
    return;
358
0
  }
359
360
  /* success */
361
0
  fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS);
362
0
}
363
364
static void
365
fu_intel_me_device_add_attrs_csme11_bootguard_enabled(FuIntelMeDevice *self,
366
                  FuMeiCsme11Hfsts6 *hfsts6,
367
                  FuSecurityAttrs *attrs)
368
0
{
369
0
  g_autoptr(FwupdSecurityAttr) attr = NULL;
370
371
  /* create attr */
372
0
  attr = fu_device_security_attr_new(FU_DEVICE(self),
373
0
             FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ENABLED);
374
0
  fwupd_security_attr_set_result_success(attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED);
375
0
  fu_security_attrs_append(attrs, attr);
376
377
  /* disabled at runtime? */
378
0
  if (fu_mei_csme11_hfsts6_get_boot_guard_disable(hfsts6)) {
379
0
    fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED);
380
0
    fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM);
381
0
    return;
382
0
  }
383
384
  /* success */
385
0
  fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS);
386
0
}
387
388
static void
389
fu_intel_me_device_add_attrs_csme18_bootguard_enabled(FuIntelMeDevice *self,
390
                  FuMeiCsme18Hfsts5 *hfsts5,
391
                  FuSecurityAttrs *attrs)
392
0
{
393
0
  g_autoptr(FwupdSecurityAttr) attr = NULL;
394
395
  /* create attr */
396
0
  attr = fu_device_security_attr_new(FU_DEVICE(self),
397
0
             FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ENABLED);
398
0
  fwupd_security_attr_set_result_success(attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED);
399
0
  fu_security_attrs_append(attrs, attr);
400
401
  /* disabled at runtime? */
402
0
  if (!fu_mei_csme18_hfsts5_get_valid(hfsts5)) {
403
0
    fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED);
404
0
    fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM);
405
0
    return;
406
0
  }
407
408
  /* success */
409
0
  fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS);
410
0
}
411
412
static void
413
fu_intel_me_device_add_attrs_csme11_bootguard_verified(FuIntelMeDevice *self,
414
                   FuMeiCsme11Hfsts6 *hfsts6,
415
                   FuSecurityAttrs *attrs)
416
0
{
417
0
  g_autoptr(FwupdSecurityAttr) attr = NULL;
418
419
  /* create attr */
420
0
  attr = fu_device_security_attr_new(FU_DEVICE(self),
421
0
             FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_VERIFIED);
422
0
  fwupd_security_attr_set_result_success(attr, FWUPD_SECURITY_ATTR_RESULT_VALID);
423
0
  fu_security_attrs_append(attrs, attr);
424
425
  /* actively disabled */
426
0
  if (fu_mei_csme11_hfsts6_get_boot_guard_disable(hfsts6)) {
427
0
    fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED);
428
0
    return;
429
0
  }
430
431
  /* measured boot is not sufficient, verified is required */
432
0
  if (!fu_mei_csme11_hfsts6_get_verified_boot(hfsts6)) {
433
0
    fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID);
434
0
    fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM);
435
0
    return;
436
0
  }
437
438
  /* success */
439
0
  fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS);
440
0
}
441
442
static void
443
fu_intel_me_device_add_attrs_csme11_bootguard_acm(FuIntelMeDevice *self,
444
              FuMeiCsme11Hfsts6 *hfsts6,
445
              FuSecurityAttrs *attrs)
446
0
{
447
0
  g_autoptr(FwupdSecurityAttr) attr = NULL;
448
449
  /* create attr */
450
0
  attr = fu_device_security_attr_new(FU_DEVICE(self),
451
0
             FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ACM);
452
0
  fwupd_security_attr_set_result_success(attr, FWUPD_SECURITY_ATTR_RESULT_VALID);
453
0
  fu_security_attrs_append(attrs, attr);
454
455
  /* actively disabled */
456
0
  if (fu_mei_csme11_hfsts6_get_boot_guard_disable(hfsts6)) {
457
0
    fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED);
458
0
    return;
459
0
  }
460
461
  /* ACM protection required */
462
0
  if (!fu_mei_csme11_hfsts6_get_force_boot_guard_acm(hfsts6)) {
463
0
    fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID);
464
0
    fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM);
465
0
    return;
466
0
  }
467
468
  /* success */
469
0
  fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS);
470
0
}
471
472
static void
473
fu_intel_me_device_add_attrs_csme18_bootguard_acm(FuIntelMeDevice *self,
474
              FuMeiCsme18Hfsts5 *hfsts5,
475
              FuSecurityAttrs *attrs)
476
0
{
477
0
  g_autoptr(FwupdSecurityAttr) attr = NULL;
478
479
  /* create attr */
480
0
  attr = fu_device_security_attr_new(FU_DEVICE(self),
481
0
             FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ACM);
482
0
  fwupd_security_attr_set_result_success(attr, FWUPD_SECURITY_ATTR_RESULT_VALID);
483
0
  fu_security_attrs_append(attrs, attr);
484
485
  /* ACM protection required */
486
0
  if (!fu_mei_csme18_hfsts5_get_btg_acm_active(hfsts5)) {
487
0
    fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID);
488
0
    fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM);
489
0
    return;
490
0
  }
491
0
  if (!fu_mei_csme18_hfsts5_get_acm_done_sts(hfsts5)) {
492
0
    fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED);
493
0
    fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM);
494
0
    return;
495
0
  }
496
497
  /* success */
498
0
  fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS);
499
0
}
500
501
static void
502
fu_intel_me_device_add_attrs_csme11_bootguard_policy(FuIntelMeDevice *self,
503
                 FuMeiCsme11Hfsts6 *hfsts6,
504
                 FuSecurityAttrs *attrs)
505
0
{
506
0
  g_autoptr(FwupdSecurityAttr) attr = NULL;
507
508
  /* create attr */
509
0
  attr = fu_device_security_attr_new(FU_DEVICE(self),
510
0
             FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_POLICY);
511
0
  fwupd_security_attr_set_result_success(attr, FWUPD_SECURITY_ATTR_RESULT_VALID);
512
0
  fu_security_attrs_append(attrs, attr);
513
514
  /* actively disabled */
515
0
  if (fu_mei_csme11_hfsts6_get_boot_guard_disable(hfsts6)) {
516
0
    fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED);
517
0
    return;
518
0
  }
519
520
  /* policy must be to immediately shutdown or after 30 mins -- the latter isn't ideal but
521
   * we've been testing for this accidentally for a long time now */
522
0
  if (fu_mei_csme11_hfsts6_get_error_enforce_policy(hfsts6) !=
523
0
    FU_ME_HFS_ENFORCEMENT_POLICY_SHUTDOWN_NOW &&
524
0
      fu_mei_csme11_hfsts6_get_error_enforce_policy(hfsts6) !=
525
0
    FU_ME_HFS_ENFORCEMENT_POLICY_SHUTDOWN_30MINS) {
526
0
    fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID);
527
0
    fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM);
528
0
    return;
529
0
  }
530
531
  /* success */
532
0
  fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS);
533
0
}
534
535
static void
536
fu_intel_me_device_add_attrs_csme11_bootguard_otp(FuIntelMeDevice *self,
537
              FuMeiCsme11Hfsts6 *hfsts6,
538
              FuSecurityAttrs *attrs)
539
0
{
540
0
  g_autoptr(FwupdSecurityAttr) attr = NULL;
541
542
  /* create attr */
543
0
  attr = fu_device_security_attr_new(FU_DEVICE(self),
544
0
             FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_OTP);
545
0
  fwupd_security_attr_set_result_success(attr, FWUPD_SECURITY_ATTR_RESULT_VALID);
546
0
  fu_security_attrs_append(attrs, attr);
547
548
  /* actively disabled */
549
0
  if (fu_mei_csme11_hfsts6_get_boot_guard_disable(hfsts6)) {
550
0
    fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED);
551
0
    return;
552
0
  }
553
554
  /* ensure vendor set the FPF OTP fuse */
555
0
  if (!fu_mei_csme11_hfsts6_get_fpf_soc_lock(hfsts6)) {
556
0
    fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID);
557
0
    fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM);
558
0
    return;
559
0
  }
560
561
  /* success */
562
0
  fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS);
563
0
}
564
565
static void
566
fu_intel_me_device_add_attrs_csme18_bootguard_otp(FuIntelMeDevice *self,
567
              FuMeiCsme18Hfsts6 *hfsts6,
568
              FuSecurityAttrs *attrs)
569
0
{
570
0
  g_autoptr(FwupdSecurityAttr) attr = NULL;
571
572
  /* create attr */
573
0
  attr = fu_device_security_attr_new(FU_DEVICE(self),
574
0
             FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_OTP);
575
0
  fwupd_security_attr_set_result_success(attr, FWUPD_SECURITY_ATTR_RESULT_VALID);
576
0
  fu_security_attrs_append(attrs, attr);
577
578
  /* ensure vendor set the FPF configuration fuse */
579
0
  if (!fu_mei_csme18_hfsts6_get_fpf_soc_configuration_lock(hfsts6)) {
580
0
    fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID);
581
0
    fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM);
582
0
    return;
583
0
  }
584
585
  /* success */
586
0
  fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS);
587
0
}
588
589
static void
590
fu_intel_me_device_add_attrs_mei_version(FuIntelMeDevice *self, FuSecurityAttrs *attrs)
591
0
{
592
0
  g_autoptr(FwupdSecurityAttr) attr = NULL;
593
594
  /* create attr */
595
0
  attr = fu_device_security_attr_new(FU_DEVICE(self), FWUPD_SECURITY_ATTR_ID_MEI_VERSION);
596
0
  fwupd_security_attr_set_result_success(attr, FWUPD_SECURITY_ATTR_RESULT_VALID);
597
0
  fu_security_attrs_append(attrs, attr);
598
599
  /* format version as string */
600
0
  fwupd_security_attr_add_metadata(attr, "version", fu_device_get_version(FU_DEVICE(self)));
601
0
  fwupd_security_attr_add_metadata(attr, "kind", fu_intel_me_family_to_string(self->family));
602
603
  /* disabled, perhaps HAP? */
604
0
  if (self->working_state == FU_ME_HFS_CWS_DISABLED) {
605
0
    fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED);
606
0
    fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS);
607
0
    return;
608
0
  }
609
610
  /* flash descriptor security override strap */
611
0
  if (self->issue == FU_INTEL_ME_ISSUE_VULNERABLE) {
612
0
    fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID);
613
0
    fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_ACTION_CONTACT_OEM);
614
0
    return;
615
0
  }
616
617
  /* success */
618
0
  fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS);
619
0
}
620
621
static void
622
fu_intel_me_device_add_security_attrs(FuDevice *device, FuSecurityAttrs *attrs)
623
0
{
624
0
  FuIntelMeDevice *self = FU_INTEL_ME_DEVICE(device);
625
626
  /* run CSME-specific tests depending on version */
627
0
  if ((self->family == FU_INTEL_ME_FAMILY_CSME11 ||
628
0
       self->family == FU_INTEL_ME_FAMILY_CSME16) &&
629
0
      self->hfsts[1] != NULL && self->hfsts[6] != NULL) {
630
0
    g_autoptr(FuMeiCsme11Hfsts1) hfsts1 = NULL;
631
0
    g_autoptr(FuMeiCsme11Hfsts6) hfsts6 = NULL;
632
633
    /* CSME 11 to 17 */
634
0
    hfsts1 = fu_mei_csme11_hfsts1_parse(self->hfsts[1]->buf->data,
635
0
                self->hfsts[1]->buf->len,
636
0
                0x0,
637
0
                NULL);
638
0
    if (hfsts1 == NULL)
639
0
      return;
640
0
    hfsts6 = fu_mei_csme11_hfsts6_parse(self->hfsts[6]->buf->data,
641
0
                self->hfsts[6]->buf->len,
642
0
                0x0,
643
0
                NULL);
644
0
    if (hfsts6 == NULL)
645
0
      return;
646
647
0
    fu_intel_me_device_add_attrs_csme11_manufacturing_mode(self, hfsts1, attrs);
648
0
    fu_intel_me_device_add_attrs_csme11_override_strap(self, hfsts1, attrs);
649
0
    fu_intel_me_device_add_attrs_csme11_bootguard_enabled(self, hfsts6, attrs);
650
0
    fu_intel_me_device_add_attrs_csme11_bootguard_verified(self, hfsts6, attrs);
651
0
    fu_intel_me_device_add_attrs_csme11_bootguard_acm(self, hfsts6, attrs);
652
0
    fu_intel_me_device_add_attrs_csme11_bootguard_policy(self, hfsts6, attrs);
653
0
    fu_intel_me_device_add_attrs_csme11_bootguard_otp(self, hfsts6, attrs);
654
655
0
  } else if (self->family == FU_INTEL_ME_FAMILY_CSME18 && self->hfsts[1] != NULL &&
656
0
       self->hfsts[5] != NULL && self->hfsts[6] != NULL) {
657
0
    g_autoptr(FuMeiCsme18Hfsts1) hfsts1 = NULL;
658
0
    g_autoptr(FuMeiCsme18Hfsts5) hfsts5 = NULL;
659
0
    g_autoptr(FuMeiCsme18Hfsts6) hfsts6 = NULL;
660
661
    /* CSME 18+ */
662
0
    hfsts1 = fu_mei_csme18_hfsts1_parse(self->hfsts[1]->buf->data,
663
0
                self->hfsts[1]->buf->len,
664
0
                0x0,
665
0
                NULL);
666
0
    if (hfsts1 == NULL)
667
0
      return;
668
0
    hfsts5 = fu_mei_csme18_hfsts5_parse(self->hfsts[5]->buf->data,
669
0
                self->hfsts[5]->buf->len,
670
0
                0x0,
671
0
                NULL);
672
0
    if (hfsts5 == NULL)
673
0
      return;
674
0
    hfsts6 = fu_mei_csme18_hfsts6_parse(self->hfsts[6]->buf->data,
675
0
                self->hfsts[6]->buf->len,
676
0
                0x0,
677
0
                NULL);
678
0
    if (hfsts6 == NULL)
679
0
      return;
680
0
    fu_intel_me_device_add_attrs_csme18_manufacturing_mode(self, hfsts1, attrs);
681
0
    fu_intel_me_device_add_attrs_csme18_override_strap(self, hfsts1, attrs);
682
0
    fu_intel_me_device_add_attrs_csme18_bootguard_enabled(self, hfsts5, attrs);
683
0
    fu_intel_me_device_add_attrs_csme18_bootguard_acm(self, hfsts5, attrs);
684
0
    fu_intel_me_device_add_attrs_csme18_bootguard_otp(self, hfsts6, attrs);
685
0
  } else {
686
0
    g_autoptr(FwupdSecurityAttr) attr = NULL;
687
688
    /* not supported */
689
0
    attr = fu_device_security_attr_new(FU_DEVICE(self),
690
0
               FWUPD_SECURITY_ATTR_ID_INTEL_BOOTGUARD_ENABLED);
691
0
    fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED);
692
0
    fu_security_attrs_append(attrs, attr);
693
0
    return;
694
0
  }
695
696
  /* all */
697
0
  fu_intel_me_device_add_attrs_mei_version(self, attrs);
698
0
}
699
700
static gboolean
701
fu_intel_me_device_from_json(FuDevice *device, FwupdJsonObject *json_obj, GError **error)
702
0
{
703
0
  FuIntelMeDevice *self = FU_INTEL_ME_DEVICE(device);
704
0
  const gchar *version;
705
706
  /* optional properties */
707
0
  version = fwupd_json_object_get_string(json_obj, "Version", NULL);
708
0
  if (version != NULL)
709
0
    fu_device_set_version(device, version);
710
0
  for (guint i = 1; i < G_N_ELEMENTS(self->hfsts); i++) {
711
0
    gint64 tmp64 = 0;
712
0
    g_autofree gchar *title = g_strdup_printf("Hfsts%x", i);
713
0
    g_autoptr(FuStructIntelMeHfsts) st = fu_struct_intel_me_hfsts_new();
714
715
0
    if (!fwupd_json_object_get_integer_with_default(json_obj, title, &tmp64, 0, error))
716
0
      return FALSE;
717
0
    fu_struct_intel_me_hfsts_set_value(st, (guint32)tmp64);
718
0
    fu_intel_me_device_set_hfsts(self, i, st);
719
0
  }
720
721
  /* success */
722
0
  return TRUE;
723
0
}
724
725
static void
726
fu_intel_me_device_add_json(FuDevice *device, FwupdJsonObject *json_obj, FwupdCodecFlags flags)
727
0
{
728
0
  FuIntelMeDevice *self = FU_INTEL_ME_DEVICE(device);
729
0
  fwupd_json_object_add_string(json_obj, "GType", "FuIntelMeDevice");
730
0
  fwupd_json_object_add_string(json_obj, "BackendName", "udev");
731
0
  if (fu_device_get_version(device) != NULL)
732
0
    fwupd_json_object_add_string(json_obj, "Version", fu_device_get_version(device));
733
0
  for (guint i = 1; i < G_N_ELEMENTS(self->hfsts); i++) {
734
0
    g_autofree gchar *title = g_strdup_printf("Hfsts%x", i);
735
0
    if (self->hfsts[i] == NULL)
736
0
      continue;
737
0
    fwupd_json_object_add_integer(json_obj,
738
0
                title,
739
0
                fu_struct_intel_me_hfsts_get_value(self->hfsts[i]));
740
0
  }
741
0
}
742
743
static void
744
fu_intel_me_device_init(FuIntelMeDevice *self)
745
0
{
746
0
  fu_device_set_name(FU_DEVICE(self), "ME");
747
0
  fu_device_set_version_format(FU_DEVICE(self), FWUPD_VERSION_FORMAT_QUAD);
748
0
  fu_device_set_physical_id(FU_DEVICE(self), "PCI_SLOT_NAME=0000:00:16.0");
749
0
  fu_device_add_icon(FU_DEVICE(self), "cpu");
750
0
  fu_device_add_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_CAN_EMULATION_TAG);
751
0
  fu_device_add_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_INTERNAL);
752
0
  g_signal_connect(FWUPD_DEVICE(self),
753
0
       "notify::version",
754
0
       G_CALLBACK(fu_intel_me_device_version_notify_cb),
755
0
       NULL);
756
0
}
757
758
static void
759
fu_intel_me_device_constructed(GObject *obj)
760
0
{
761
0
  FuIntelMeDevice *self = FU_INTEL_ME_DEVICE(obj);
762
0
  fu_device_add_instance_id_full(FU_DEVICE(self),
763
0
               "PCI\\VEN_8086",
764
0
               FU_DEVICE_INSTANCE_FLAG_QUIRKS);
765
766
  /* chain up to parent */
767
0
  G_OBJECT_CLASS(fu_intel_me_device_parent_class)->constructed(obj);
768
0
}
769
770
static void
771
fu_intel_me_device_finalize(GObject *object)
772
0
{
773
0
  FuIntelMeDevice *self = FU_INTEL_ME_DEVICE(object);
774
775
0
  for (guint i = 1; i < G_N_ELEMENTS(self->hfsts); i++) {
776
0
    if (self->hfsts[i] != NULL)
777
0
      fu_struct_intel_me_hfsts_unref(self->hfsts[i]);
778
0
  }
779
780
0
  G_OBJECT_CLASS(fu_intel_me_device_parent_class)->finalize(object);
781
0
}
782
783
static void
784
fu_intel_me_device_class_init(FuIntelMeDeviceClass *klass)
785
0
{
786
0
  GObjectClass *object_class = G_OBJECT_CLASS(klass);
787
0
  FuDeviceClass *device_class = FU_DEVICE_CLASS(klass);
788
0
  object_class->constructed = fu_intel_me_device_constructed;
789
0
  object_class->finalize = fu_intel_me_device_finalize;
790
0
  device_class->to_string = fu_intel_me_device_to_string;
791
0
  device_class->from_json = fu_intel_me_device_from_json;
792
0
  device_class->add_json = fu_intel_me_device_add_json;
793
0
  device_class->add_security_attrs = fu_intel_me_device_add_security_attrs;
794
0
}
795
796
/**
797
 * fu_intel_me_device_new:
798
 * @ctx: a #FuContext
799
 *
800
 * Creates a new Intel ME device.
801
 *
802
 * Returns: (transfer full): a #FuIntelMeDevice
803
 *
804
 * Since: 2.1.1
805
 **/
806
FuIntelMeDevice *
807
fu_intel_me_device_new(FuContext *ctx)
808
0
{
809
0
  return g_object_new(FU_TYPE_INTEL_ME_DEVICE, "context", ctx, NULL);
810
0
}