mirror of
https://git.proxmox.com/git/fwupd
synced 2025-08-07 17:45:23 +00:00
Add a new plugin to get more Intel ME MCA data
This allows us to get the OEM Public Key BootGuard hashes. Also add a new HSI test for leaked bootguard keys.
This commit is contained in:
parent
ef04d0578f
commit
0f8ec55f46
27
docs/hsi.md
27
docs/hsi.md
@ -350,6 +350,33 @@ To meet HSI-1 on systems that run this test, the result must be `locked`. *[v1.5
|
|||||||
|
|
||||||
- [Chromium documentation for Intel ME](https://chromium.googlesource.com/chromiumos/third_party/flashrom/+/master/Documentation/mysteries_intel.txt)
|
- [Chromium documentation for Intel ME](https://chromium.googlesource.com/chromiumos/third_party/flashrom/+/master/Documentation/mysteries_intel.txt)
|
||||||
|
|
||||||
|
<a id="org.fwupd.hsi.Mei.BootGuardPlatformKey"></a>
|
||||||
|
|
||||||
|
### [ME BootGuard Platform Key](#org.fwupd.hsi.Mei.BootGuardPlatformKey)
|
||||||
|
|
||||||
|
The BootGuard Platform Key is fused into the CPU PCH during manufacturing by the OEM.
|
||||||
|
|
||||||
|
At bootup, an authenticated code module computes a hash of the Platform Key and and compares it
|
||||||
|
with the one stored in field-programmable fuses.
|
||||||
|
If the key matches the ACM will pass control to the firmware, otherwise the boot process will stop.
|
||||||
|
|
||||||
|
In 2022 a number of Platform **secret** Keys were leaked by Lenovo and confirmed by Intel.
|
||||||
|
|
||||||
|
**Impact:** A custom system firmware can be signed using the leaked private key to completely
|
||||||
|
disable UEFI Secure Boot and allow complete persistent compromise of the affected machine.
|
||||||
|
|
||||||
|
**Possible results:**
|
||||||
|
|
||||||
|
- `valid`: device uses a BootGuard Platform Key that is not known to be compromised
|
||||||
|
- `not-valid`: device uses a key that is compromised
|
||||||
|
|
||||||
|
To meet HSI-1 on systems that run this test, the result must be `valid`. *[v1.8.7]*
|
||||||
|
|
||||||
|
**References:**
|
||||||
|
|
||||||
|
- [Intel leak checker](https://github.com/phretor/intel-leak-checker/)
|
||||||
|
- [Tom's Hardware Article](https://www.tomshardware.com/news/intel-confirms-6gb-alder-lake-bios-source-code-leak-new-details-emerge)
|
||||||
|
|
||||||
<a id="org.fwupd.hsi.Mei.Version"></a>
|
<a id="org.fwupd.hsi.Mei.Version"></a>
|
||||||
|
|
||||||
### [CSME Version](#org.fwupd.hsi.Mei.Version)
|
### [CSME Version](#org.fwupd.hsi.Mei.Version)
|
||||||
|
@ -166,6 +166,14 @@ G_BEGIN_DECLS
|
|||||||
* Since: 1.5.0
|
* Since: 1.5.0
|
||||||
**/
|
**/
|
||||||
#define FWUPD_SECURITY_ATTR_ID_MEI_OVERRIDE_STRAP "org.fwupd.hsi.Mei.OverrideStrap"
|
#define FWUPD_SECURITY_ATTR_ID_MEI_OVERRIDE_STRAP "org.fwupd.hsi.Mei.OverrideStrap"
|
||||||
|
/**
|
||||||
|
* FWUPD_SECURITY_ATTR_ID_MEI_KEY_MANIFEST:
|
||||||
|
*
|
||||||
|
* Host Security ID attribute for Intel ME Key Manifest
|
||||||
|
*
|
||||||
|
* Since: 1.8.7
|
||||||
|
**/
|
||||||
|
#define FWUPD_SECURITY_ATTR_ID_MEI_KEY_MANIFEST "org.fwupd.hsi.Mei.KeyManifest"
|
||||||
/**
|
/**
|
||||||
* FWUPD_SECURITY_ATTR_ID_MEI_VERSION:
|
* FWUPD_SECURITY_ATTR_ID_MEI_VERSION:
|
||||||
*
|
*
|
||||||
|
@ -157,6 +157,8 @@ fu_mei_device_connect(FuMeiDevice *self, guchar req_protocol_version, GError **e
|
|||||||
|
|
||||||
if (!fwupd_guid_from_string(priv->uuid, &guid_le, FWUPD_GUID_FLAG_MIXED_ENDIAN, error))
|
if (!fwupd_guid_from_string(priv->uuid, &guid_le, FWUPD_GUID_FLAG_MIXED_ENDIAN, error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
if (g_getenv("FU_MEI_DEVICE_DEBUG") != NULL)
|
||||||
|
fu_dump_raw(G_LOG_DOMAIN, "guid_le", (guint8 *)&guid_le, sizeof(guid_le));
|
||||||
memcpy(&data.in_client_uuid, &guid_le, sizeof(guid_le));
|
memcpy(&data.in_client_uuid, &guid_le, sizeof(guid_le));
|
||||||
if (!fu_udev_device_ioctl(FU_UDEV_DEVICE(self),
|
if (!fu_udev_device_ioctl(FU_UDEV_DEVICE(self),
|
||||||
IOCTL_MEI_CONNECT_CLIENT,
|
IOCTL_MEI_CONNECT_CLIENT,
|
||||||
|
@ -330,6 +330,7 @@ static struct {
|
|||||||
{FWUPD_SECURITY_ATTR_ID_IOMMU, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT},
|
{FWUPD_SECURITY_ATTR_ID_IOMMU, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT},
|
||||||
{FWUPD_SECURITY_ATTR_ID_MEI_MANUFACTURING_MODE, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL},
|
{FWUPD_SECURITY_ATTR_ID_MEI_MANUFACTURING_MODE, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL},
|
||||||
{FWUPD_SECURITY_ATTR_ID_MEI_OVERRIDE_STRAP, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL},
|
{FWUPD_SECURITY_ATTR_ID_MEI_OVERRIDE_STRAP, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL},
|
||||||
|
{FWUPD_SECURITY_ATTR_ID_MEI_KEY_MANIFEST, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL},
|
||||||
{FWUPD_SECURITY_ATTR_ID_MEI_VERSION, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL},
|
{FWUPD_SECURITY_ATTR_ID_MEI_VERSION, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL},
|
||||||
{FWUPD_SECURITY_ATTR_ID_PLATFORM_DEBUG_ENABLED, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL},
|
{FWUPD_SECURITY_ATTR_ID_PLATFORM_DEBUG_ENABLED, FWUPD_SECURITY_ATTR_LEVEL_CRITICAL},
|
||||||
{FWUPD_SECURITY_ATTR_ID_PLATFORM_DEBUG_LOCKED, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT},
|
{FWUPD_SECURITY_ATTR_ID_PLATFORM_DEBUG_LOCKED, FWUPD_SECURITY_ATTR_LEVEL_IMPORTANT},
|
||||||
|
19
plugins/intel-me/README.md
Normal file
19
plugins/intel-me/README.md
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# Intel ME
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
This plugin is used to talk to the Intel ME device, typically CSME.
|
||||||
|
|
||||||
|
It allows us to get the Platform Key as used for BootGuard.
|
||||||
|
|
||||||
|
## GUID Generation
|
||||||
|
|
||||||
|
These devices use the existing GUIDs provided by the ME host interfaces.
|
||||||
|
|
||||||
|
## Vendor ID Security
|
||||||
|
|
||||||
|
The devices are not upgradable and thus require no vendor ID set.
|
||||||
|
|
||||||
|
## External Interface Access
|
||||||
|
|
||||||
|
This plugin requires `ioctl(IOCTL_MEI_CONNECT_CLIENT)` to `/dev/mei0`.
|
99
plugins/intel-me/fu-intel-me-common.c
Normal file
99
plugins/intel-me/fu-intel-me-common.c
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Richard Hughes <richard@hughsie.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "fu-intel-me-common.h"
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
fu_intel_me_mkhi_result_to_error(FuMkhiResult result, GError **error)
|
||||||
|
{
|
||||||
|
if (result == MKHI_STATUS_SUCCESS)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
switch (result) {
|
||||||
|
case MKHI_STATUS_NOT_SUPPORTED:
|
||||||
|
case MKHI_STATUS_NOT_AVAILABLE:
|
||||||
|
case MKHI_STATUS_NOT_SET:
|
||||||
|
g_set_error(error,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_NOT_SUPPORTED,
|
||||||
|
"not supported [0x%x]",
|
||||||
|
result);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_set_error(error, G_IO_ERROR, G_IO_ERROR_FAILED, "generic failure [0x%x]", result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
fu_intel_me_mkhi_verify_header(const FuMkhiHeader hdr_req,
|
||||||
|
const FuMkhiHeader hdr_res,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
if (hdr_req.group_id != hdr_res.group_id) {
|
||||||
|
g_set_error(error,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_INVALID_DATA,
|
||||||
|
"invalid response group ID, requested 0x%x and got 0x%x",
|
||||||
|
hdr_req.group_id,
|
||||||
|
hdr_res.group_id);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (hdr_req.command != hdr_res.command) {
|
||||||
|
g_set_error(error,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_INVALID_DATA,
|
||||||
|
"invalid response command, requested 0x%x and got 0x%x",
|
||||||
|
(guint)hdr_req.command,
|
||||||
|
(guint)hdr_res.command);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (!hdr_res.is_resp) {
|
||||||
|
g_set_error_literal(error,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_INVALID_DATA,
|
||||||
|
"invalid response group ID, not a response!");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return fu_intel_me_mkhi_result_to_error(hdr_res.result, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
GString *
|
||||||
|
fu_intel_me_convert_checksum(GByteArray *buf, GError **error)
|
||||||
|
{
|
||||||
|
gboolean seen_non00_data = FALSE;
|
||||||
|
gboolean seen_nonff_data = FALSE;
|
||||||
|
g_autoptr(GString) checksum = g_string_new(NULL);
|
||||||
|
|
||||||
|
/* create checksum, but only if non-zero and set */
|
||||||
|
for (gsize i = 0; i < buf->len; i++) {
|
||||||
|
if (!seen_non00_data && buf->data[i] != 0x00)
|
||||||
|
seen_non00_data = TRUE;
|
||||||
|
if (!seen_nonff_data && buf->data[i] != 0xFF)
|
||||||
|
seen_nonff_data = TRUE;
|
||||||
|
g_string_append_printf(checksum, "%02x", buf->data[i]);
|
||||||
|
}
|
||||||
|
if (!seen_non00_data) {
|
||||||
|
g_set_error_literal(error,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_NOT_INITIALIZED,
|
||||||
|
"buffer was all 0x00");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!seen_nonff_data) {
|
||||||
|
g_set_error_literal(error,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_NOT_INITIALIZED,
|
||||||
|
"buffer was all 0xFF");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* success */
|
||||||
|
return g_steal_pointer(&checksum);
|
||||||
|
}
|
64
plugins/intel-me/fu-intel-me-common.h
Normal file
64
plugins/intel-me/fu-intel-me-common.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Richard Hughes <richard@hughsie.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gio/gio.h>
|
||||||
|
|
||||||
|
typedef struct __attribute__((packed)) {
|
||||||
|
guint8 group_id;
|
||||||
|
guint8 command : 7;
|
||||||
|
guint8 is_resp : 1;
|
||||||
|
guint8 rsvd;
|
||||||
|
guint8 result;
|
||||||
|
} FuMkhiHeader;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MKHI_GROUP_ID_CBM,
|
||||||
|
MKHI_GROUP_ID_PM, /* no longer used */
|
||||||
|
MKHI_GROUP_ID_PWD,
|
||||||
|
MKHI_GROUP_ID_FWCAPS,
|
||||||
|
MKHI_GROUP_ID_APP, /* no longer used */
|
||||||
|
MKHI_GROUP_ID_FWUPDATE, /* for manufacturing downgrade */
|
||||||
|
MKHI_GROUP_ID_FIRMWARE_UPDATE,
|
||||||
|
MKHI_GROUP_ID_BIST,
|
||||||
|
MKHI_GROUP_ID_MDES,
|
||||||
|
MKHI_GROUP_ID_ME_DBG,
|
||||||
|
MKHI_GROUP_ID_MCA, /* sometimes called "FPF" */
|
||||||
|
MKHI_GROUP_ID_GEN = 0xFF
|
||||||
|
} FuMkhiGroupId;
|
||||||
|
|
||||||
|
#define MCA_READ_FILE_EX 0x02
|
||||||
|
#define MCA_READ_FILE_EX_CMD 0x0A
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MKHI_STATUS_SUCCESS,
|
||||||
|
MKHI_STATUS_INVALID_STATE,
|
||||||
|
MKHI_STATUS_MESSAGE_SKIPPED,
|
||||||
|
MKHI_STATUS_SIZE_ERROR = 0x05,
|
||||||
|
MKHI_STATUS_NOT_SET = 0x0F, /* guessed */
|
||||||
|
MKHI_STATUS_NOT_AVAILABLE = 0x18, /* guessed */
|
||||||
|
MKHI_STATUS_INVALID_ACCESS = 0x84,
|
||||||
|
MKHI_STATUS_INVALID_PARAMS = 0x85,
|
||||||
|
MKHI_STATUS_NOT_READY = 0x88,
|
||||||
|
MKHI_STATUS_NOT_SUPPORTED = 0x89,
|
||||||
|
MKHI_STATUS_INVALID_ADDRESS = 0x8C,
|
||||||
|
MKHI_STATUS_INVALID_COMMAND = 0x8D,
|
||||||
|
MKHI_STATUS_FAILURE = 0x9E,
|
||||||
|
MKHI_STATUS_INVALID_RESOURCE = 0xE4,
|
||||||
|
MKHI_STATUS_RESOURCE_IN_USE = 0xE5,
|
||||||
|
MKHI_STATUS_NO_RESOURCE = 0xE6,
|
||||||
|
MKHI_STATUS_GENERAL_ERROR = 0xFF
|
||||||
|
} FuMkhiResult;
|
||||||
|
|
||||||
|
GString *
|
||||||
|
fu_intel_me_convert_checksum(GByteArray *buf, GError **error);
|
||||||
|
gboolean
|
||||||
|
fu_intel_me_mkhi_result_to_error(FuMkhiResult result, GError **error);
|
||||||
|
gboolean
|
||||||
|
fu_intel_me_mkhi_verify_header(const FuMkhiHeader hdr_req,
|
||||||
|
const FuMkhiHeader hdr_res,
|
||||||
|
GError **error);
|
191
plugins/intel-me/fu-intel-me-heci-device.c
Normal file
191
plugins/intel-me/fu-intel-me-heci-device.c
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Richard Hughes <richard@hughsie.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <fwupdplugin.h>
|
||||||
|
|
||||||
|
#include "fu-intel-me-common.h"
|
||||||
|
#include "fu-intel-me-heci-device.h"
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(FuIntelMeHeciDevice, fu_intel_me_heci_device, FU_TYPE_MEI_DEVICE)
|
||||||
|
|
||||||
|
#define FU_INTEL_ME_HECI_DEVICE_TIMEOUT 200 /* ms */
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
fu_intel_me_heci_device_open(FuDevice *device, GError **error)
|
||||||
|
{
|
||||||
|
/* open then create context */
|
||||||
|
if (!FU_DEVICE_CLASS(fu_intel_me_heci_device_parent_class)->open(device, error))
|
||||||
|
return FALSE;
|
||||||
|
return fu_mei_device_connect(FU_MEI_DEVICE(device), 0, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GByteArray *
|
||||||
|
fu_intel_me_heci_device_read_file_response(GByteArray *buf_res, guint32 datasz_req, GError **error)
|
||||||
|
{
|
||||||
|
guint32 datasz_res = 0;
|
||||||
|
g_autoptr(GByteArray) buf = g_byte_array_new();
|
||||||
|
|
||||||
|
/* verify payload size */
|
||||||
|
if (!fu_memread_uint32_safe(buf_res->data,
|
||||||
|
buf_res->len,
|
||||||
|
sizeof(FuMkhiHeader),
|
||||||
|
&datasz_res,
|
||||||
|
G_LITTLE_ENDIAN,
|
||||||
|
error))
|
||||||
|
return NULL;
|
||||||
|
if (datasz_res > datasz_req || datasz_res == 0x0) {
|
||||||
|
g_set_error(error,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_INVALID_DATA,
|
||||||
|
"invalid response data size, requested 0x%x and got 0x%x",
|
||||||
|
datasz_req,
|
||||||
|
datasz_res);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy out payload */
|
||||||
|
for (gsize i = 0; i < datasz_res; i++) {
|
||||||
|
guint8 tmp = 0;
|
||||||
|
if (!fu_memread_uint8_safe(buf_res->data,
|
||||||
|
buf_res->len,
|
||||||
|
sizeof(FuMkhiHeader) + sizeof(guint32) + i,
|
||||||
|
&tmp,
|
||||||
|
error))
|
||||||
|
return NULL;
|
||||||
|
fu_byte_array_append_uint8(buf, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* success */
|
||||||
|
return g_steal_pointer(&buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
GByteArray *
|
||||||
|
fu_intel_me_heci_device_read_file(FuIntelMeHeciDevice *self, const gchar *filename, GError **error)
|
||||||
|
{
|
||||||
|
FuMkhiHeader hdr_res = {0};
|
||||||
|
gsize filenamesz = strlen(filename);
|
||||||
|
guint datasz_req = 0x80;
|
||||||
|
g_autoptr(GByteArray) buf_fn = g_byte_array_new();
|
||||||
|
g_autoptr(GByteArray) buf_req = g_byte_array_new();
|
||||||
|
g_autoptr(GByteArray) buf_res = g_byte_array_new();
|
||||||
|
const FuMkhiHeader hdr_req = {.group_id = MKHI_GROUP_ID_MCA, .command = MCA_READ_FILE_EX};
|
||||||
|
|
||||||
|
/* filename must be a specific size */
|
||||||
|
fu_byte_array_set_size(buf_fn, 0x40, 0x0);
|
||||||
|
if (!fu_memcpy_safe(buf_fn->data,
|
||||||
|
buf_fn->len - 1,
|
||||||
|
0x0,
|
||||||
|
(const guint8 *)filename,
|
||||||
|
filenamesz,
|
||||||
|
0x0,
|
||||||
|
filenamesz,
|
||||||
|
error))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* request */
|
||||||
|
g_byte_array_append(buf_req, (const guint8 *)&hdr_req, sizeof(hdr_req));
|
||||||
|
g_byte_array_append(buf_req, buf_fn->data, buf_fn->len); /* Filename */
|
||||||
|
fu_byte_array_append_uint32(buf_req, 0x0, G_LITTLE_ENDIAN); /* Offset */
|
||||||
|
fu_byte_array_append_uint32(buf_req, datasz_req, G_LITTLE_ENDIAN); /* DataSize */
|
||||||
|
fu_byte_array_append_uint8(buf_req, (1 << 3)); /* Flags?? */
|
||||||
|
if (!fu_mei_device_write(FU_MEI_DEVICE(self),
|
||||||
|
buf_req->data,
|
||||||
|
buf_req->len,
|
||||||
|
FU_INTEL_ME_HECI_DEVICE_TIMEOUT,
|
||||||
|
error))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* response */
|
||||||
|
fu_byte_array_set_size(buf_res, sizeof(hdr_res) + sizeof(guint32) + datasz_req, 0x0);
|
||||||
|
if (!fu_mei_device_read(FU_MEI_DEVICE(self),
|
||||||
|
buf_res->data,
|
||||||
|
buf_res->len,
|
||||||
|
NULL,
|
||||||
|
FU_INTEL_ME_HECI_DEVICE_TIMEOUT,
|
||||||
|
error))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* verify header */
|
||||||
|
if (!fu_memcpy_safe((guint8 *)&hdr_res,
|
||||||
|
sizeof(hdr_res),
|
||||||
|
0x0, /* dst */
|
||||||
|
buf_res->data,
|
||||||
|
buf_res->len,
|
||||||
|
0x0, /* src */
|
||||||
|
sizeof(hdr_req),
|
||||||
|
error))
|
||||||
|
return NULL;
|
||||||
|
if (!fu_intel_me_mkhi_verify_header(hdr_req, hdr_res, error))
|
||||||
|
return NULL;
|
||||||
|
return fu_intel_me_heci_device_read_file_response(buf_res, datasz_req, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
GByteArray *
|
||||||
|
fu_intel_me_heci_device_read_file_ex(FuIntelMeHeciDevice *self,
|
||||||
|
guint32 file_id,
|
||||||
|
guint32 section,
|
||||||
|
guint32 datasz_req,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
FuMkhiHeader hdr_res = {0};
|
||||||
|
g_autoptr(GByteArray) buf_req = g_byte_array_new();
|
||||||
|
g_autoptr(GByteArray) buf_res = g_byte_array_new();
|
||||||
|
const FuMkhiHeader hdr_req = {.group_id = MKHI_GROUP_ID_MCA,
|
||||||
|
.command = MCA_READ_FILE_EX_CMD};
|
||||||
|
|
||||||
|
/* request */
|
||||||
|
g_byte_array_append(buf_req, (const guint8 *)&hdr_req, sizeof(hdr_req));
|
||||||
|
fu_byte_array_append_uint32(buf_req, file_id, G_LITTLE_ENDIAN); /* FileId */
|
||||||
|
fu_byte_array_append_uint32(buf_req, 0x0, G_LITTLE_ENDIAN); /* Offset */
|
||||||
|
fu_byte_array_append_uint32(buf_req, datasz_req, G_LITTLE_ENDIAN); /* DataSize */
|
||||||
|
fu_byte_array_append_uint8(buf_req, section); /* Flags */
|
||||||
|
if (!fu_mei_device_write(FU_MEI_DEVICE(self),
|
||||||
|
buf_req->data,
|
||||||
|
buf_req->len,
|
||||||
|
FU_INTEL_ME_HECI_DEVICE_TIMEOUT,
|
||||||
|
error))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* response */
|
||||||
|
fu_byte_array_set_size(buf_res, sizeof(hdr_res) + sizeof(guint32) + datasz_req, 0x0);
|
||||||
|
if (!fu_mei_device_read(FU_MEI_DEVICE(self),
|
||||||
|
buf_res->data,
|
||||||
|
buf_res->len,
|
||||||
|
NULL,
|
||||||
|
FU_INTEL_ME_HECI_DEVICE_TIMEOUT,
|
||||||
|
error))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* verify header */
|
||||||
|
if (!fu_memcpy_safe((guint8 *)&hdr_res,
|
||||||
|
sizeof(hdr_res),
|
||||||
|
0x0, /* dst */
|
||||||
|
buf_res->data,
|
||||||
|
buf_res->len,
|
||||||
|
0x0, /* src */
|
||||||
|
sizeof(hdr_req),
|
||||||
|
error))
|
||||||
|
return NULL;
|
||||||
|
if (!fu_intel_me_mkhi_verify_header(hdr_req, hdr_res, error))
|
||||||
|
return NULL;
|
||||||
|
return fu_intel_me_heci_device_read_file_response(buf_res, datasz_req, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_intel_me_heci_device_init(FuIntelMeHeciDevice *self)
|
||||||
|
{
|
||||||
|
fu_device_add_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_INTERNAL);
|
||||||
|
fu_device_add_icon(FU_DEVICE(self), "computer");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_intel_me_heci_device_class_init(FuIntelMeHeciDeviceClass *klass)
|
||||||
|
{
|
||||||
|
FuDeviceClass *klass_device = FU_DEVICE_CLASS(klass);
|
||||||
|
klass_device->open = fu_intel_me_heci_device_open;
|
||||||
|
}
|
29
plugins/intel-me/fu-intel-me-heci-device.h
Normal file
29
plugins/intel-me/fu-intel-me-heci-device.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Richard Hughes <richard@hughsie.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fwupdplugin.h>
|
||||||
|
|
||||||
|
#define FU_TYPE_INTEL_ME_HECI_DEVICE (fu_intel_me_heci_device_get_type())
|
||||||
|
G_DECLARE_DERIVABLE_TYPE(FuIntelMeHeciDevice,
|
||||||
|
fu_intel_me_heci_device,
|
||||||
|
FU,
|
||||||
|
INTEL_ME_HECI_DEVICE,
|
||||||
|
FuMeiDevice)
|
||||||
|
|
||||||
|
struct _FuIntelMeHeciDeviceClass {
|
||||||
|
FuMeiDeviceClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
GByteArray *
|
||||||
|
fu_intel_me_heci_device_read_file(FuIntelMeHeciDevice *self, const gchar *filename, GError **error);
|
||||||
|
GByteArray *
|
||||||
|
fu_intel_me_heci_device_read_file_ex(FuIntelMeHeciDevice *self,
|
||||||
|
guint32 file_id,
|
||||||
|
guint32 section,
|
||||||
|
guint32 datasz_req,
|
||||||
|
GError **error);
|
173
plugins/intel-me/fu-intel-me-mca-device.c
Normal file
173
plugins/intel-me/fu-intel-me-mca-device.c
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Richard Hughes <richard@hughsie.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "fu-intel-me-common.h"
|
||||||
|
#include "fu-intel-me-mca-device.h"
|
||||||
|
|
||||||
|
struct _FuIntelMeMcaDevice {
|
||||||
|
FuIntelMeHeciDevice parent_instance;
|
||||||
|
gboolean using_leaked_km;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(FuIntelMeMcaDevice, fu_intel_me_mca_device, FU_TYPE_INTEL_ME_HECI_DEVICE)
|
||||||
|
|
||||||
|
#define MCA_SECTION_ME 0x00 /* OEM Public Key Hash ME FW */
|
||||||
|
#define MCA_SECTION_UEP 0x04 /* OEM Public Key Hash UEP */
|
||||||
|
#define MCA_SECTION_FPF 0x08 /* OEM Public Key Hash FPF */
|
||||||
|
|
||||||
|
static const gchar *
|
||||||
|
fu_intel_me_mca_device_section_to_string(guint8 section)
|
||||||
|
{
|
||||||
|
if (section == MCA_SECTION_ME)
|
||||||
|
return "ME";
|
||||||
|
if (section == MCA_SECTION_UEP)
|
||||||
|
return "UEP";
|
||||||
|
if (section == MCA_SECTION_FPF)
|
||||||
|
return "FPF";
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
fu_intel_me_mca_device_add_checksum_for_id(FuIntelMeMcaDevice *self,
|
||||||
|
guint32 file_id,
|
||||||
|
guint32 section,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
g_autoptr(GByteArray) buf = NULL;
|
||||||
|
g_autoptr(GString) checksum = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call READ_FILE_EX with a larger-than-required data size -- which hopefully works when
|
||||||
|
* SHA512 results start being returned too.
|
||||||
|
*
|
||||||
|
* CometLake: 0x20 (SHA256)
|
||||||
|
* TigerLake: 0x30 (SHA384)
|
||||||
|
*/
|
||||||
|
buf = fu_intel_me_heci_device_read_file_ex(FU_INTEL_ME_HECI_DEVICE(self),
|
||||||
|
file_id,
|
||||||
|
section,
|
||||||
|
0x40,
|
||||||
|
error);
|
||||||
|
if (buf == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* convert into checksum, but only if non-zero and set */
|
||||||
|
checksum = fu_intel_me_convert_checksum(buf, error);
|
||||||
|
if (checksum == NULL)
|
||||||
|
return FALSE;
|
||||||
|
fu_device_add_checksum(FU_DEVICE(self), checksum->str);
|
||||||
|
|
||||||
|
/* success */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
fu_intel_me_mca_device_setup(FuDevice *device, GError **error)
|
||||||
|
{
|
||||||
|
FuIntelMeMcaDevice *self = FU_INTEL_ME_MCA_DEVICE(device);
|
||||||
|
const guint32 sections[] = {MCA_SECTION_FPF, MCA_SECTION_UEP, MCA_SECTION_ME, G_MAXUINT32};
|
||||||
|
const guint32 file_ids[] = {0x40002300, /* CometLake: OEM Public Key Hash */
|
||||||
|
0x40005B00, /* TigerLake: 1st OEM Public Key Hash */
|
||||||
|
0x40005C00 /* TigerLake: 2nd OEM Public Key Hash */,
|
||||||
|
G_MAXUINT32};
|
||||||
|
const gchar *leaked_kms[] = {"05a92e16da51d10882bfa7e3ba449184ce48e94fa9903e07983d2112ab"
|
||||||
|
"54ecf20fbb07512cea2c13b167c0e252c6a704",
|
||||||
|
"2e357bca116cf3da637bb5803be3550873eddb5a4431a49df1770aca83"
|
||||||
|
"5d94853b458239d207653dce277910d9e5aa0b",
|
||||||
|
"b52a825cf0be60027f12a226226b055ed68efaa9273695d45d859c0ed3"
|
||||||
|
"3d063143974f4b4c59fabfc5afeadab0b00f09",
|
||||||
|
NULL};
|
||||||
|
|
||||||
|
/* look for all the possible OEM Public Key hashes using the CML+ method */
|
||||||
|
for (guint i = 0; file_ids[i] != G_MAXUINT32; i++) {
|
||||||
|
for (guint j = 0; sections[j] != G_MAXUINT32; j++) {
|
||||||
|
g_autoptr(GError) error_local = NULL;
|
||||||
|
if (!fu_intel_me_mca_device_add_checksum_for_id(self,
|
||||||
|
file_ids[i],
|
||||||
|
sections[j],
|
||||||
|
&error_local)) {
|
||||||
|
if (g_error_matches(error_local,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_NOT_SUPPORTED) ||
|
||||||
|
g_error_matches(error_local,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_NOT_INITIALIZED)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
g_warning("failed to get public key using file-id 0x%x, "
|
||||||
|
"section %s [0x%x]: %s",
|
||||||
|
file_ids[i],
|
||||||
|
fu_intel_me_mca_device_section_to_string(sections[j]),
|
||||||
|
sections[j],
|
||||||
|
error_local->message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* no point even adding */
|
||||||
|
if (fu_device_get_checksums(device)->len == 0) {
|
||||||
|
g_set_error_literal(error,
|
||||||
|
FWUPD_ERROR,
|
||||||
|
FWUPD_ERROR_NOT_SUPPORTED,
|
||||||
|
"no OEM public keys found");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check for any of the leaked keys */
|
||||||
|
for (guint i = 0; leaked_kms[i] != NULL; i++) {
|
||||||
|
if (fu_device_has_checksum(self, leaked_kms[i])) {
|
||||||
|
self->using_leaked_km = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* success */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_intel_me_mca_device_add_security_attrs(FuDevice *device, FuSecurityAttrs *attrs)
|
||||||
|
{
|
||||||
|
FuIntelMeMcaDevice *self = FU_INTEL_ME_MCA_DEVICE(device);
|
||||||
|
g_autoptr(FwupdSecurityAttr) attr = NULL;
|
||||||
|
|
||||||
|
/* create attr */
|
||||||
|
attr =
|
||||||
|
fu_device_security_attr_new(FU_DEVICE(self), FWUPD_SECURITY_ATTR_ID_MEI_KEY_MANIFEST);
|
||||||
|
fu_security_attrs_append(attrs, attr);
|
||||||
|
|
||||||
|
/* verify keys */
|
||||||
|
if (fu_device_get_checksums(device)->len == 0) {
|
||||||
|
fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_MISSING_DATA);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (self->using_leaked_km) {
|
||||||
|
fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_NOT_VALID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* success */
|
||||||
|
fwupd_security_attr_add_flag(attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS);
|
||||||
|
fwupd_security_attr_set_result(attr, FWUPD_SECURITY_ATTR_RESULT_VALID);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_intel_me_mca_device_init(FuIntelMeMcaDevice *self)
|
||||||
|
{
|
||||||
|
fu_device_set_logical_id(FU_DEVICE(self), "MCA");
|
||||||
|
fu_device_set_name(FU_DEVICE(self), "BootGuard Configuration");
|
||||||
|
fu_device_add_parent_guid(FU_DEVICE(self), "main-system-firmware");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_intel_me_mca_device_class_init(FuIntelMeMcaDeviceClass *klass)
|
||||||
|
{
|
||||||
|
FuDeviceClass *klass_device = FU_DEVICE_CLASS(klass);
|
||||||
|
klass_device->setup = fu_intel_me_mca_device_setup;
|
||||||
|
klass_device->add_security_attrs = fu_intel_me_mca_device_add_security_attrs;
|
||||||
|
}
|
18
plugins/intel-me/fu-intel-me-mca-device.h
Normal file
18
plugins/intel-me/fu-intel-me-mca-device.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Richard Hughes <richard@hughsie.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fwupdplugin.h>
|
||||||
|
|
||||||
|
#include "fu-intel-me-heci-device.h"
|
||||||
|
|
||||||
|
#define FU_TYPE_INTEL_ME_MCA_DEVICE (fu_intel_me_mca_device_get_type())
|
||||||
|
G_DECLARE_FINAL_TYPE(FuIntelMeMcaDevice,
|
||||||
|
fu_intel_me_mca_device,
|
||||||
|
FU,
|
||||||
|
INTEL_ME_MCA_DEVICE,
|
||||||
|
FuIntelMeHeciDevice)
|
90
plugins/intel-me/fu-intel-me-mkhi-device.c
Normal file
90
plugins/intel-me/fu-intel-me-mkhi-device.c
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Richard Hughes <richard@hughsie.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "fu-intel-me-common.h"
|
||||||
|
#include "fu-intel-me-mkhi-device.h"
|
||||||
|
|
||||||
|
struct _FuIntelMeMkhiDevice {
|
||||||
|
FuIntelMeHeciDevice parent_instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(FuIntelMeMkhiDevice, fu_intel_me_mkhi_device, FU_TYPE_INTEL_ME_HECI_DEVICE)
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
fu_intel_me_mkhi_device_add_checksum_for_filename(FuIntelMeMkhiDevice *self,
|
||||||
|
const gchar *filename,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
g_autoptr(GByteArray) buf = NULL;
|
||||||
|
g_autoptr(GString) checksum = NULL;
|
||||||
|
|
||||||
|
/* read from the MFS */
|
||||||
|
buf = fu_intel_me_heci_device_read_file(FU_INTEL_ME_HECI_DEVICE(self), filename, error);
|
||||||
|
if (buf == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* convert into checksum, but only if non-zero and set */
|
||||||
|
checksum = fu_intel_me_convert_checksum(buf, error);
|
||||||
|
if (checksum == NULL)
|
||||||
|
return FALSE;
|
||||||
|
fu_device_add_checksum(FU_DEVICE(self), checksum->str);
|
||||||
|
|
||||||
|
/* success */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
fu_intel_me_mkhi_device_setup(FuDevice *device, GError **error)
|
||||||
|
{
|
||||||
|
FuIntelMeMkhiDevice *self = FU_INTEL_ME_MKHI_DEVICE(device);
|
||||||
|
const gchar *fns[] = {"/fpf/OemCred", NULL};
|
||||||
|
|
||||||
|
/* this is the legacy way to get the hash, which is removed in newer ME versions due to
|
||||||
|
* possible path traversal attacks */
|
||||||
|
for (guint i = 0; fns[i] != NULL; i++) {
|
||||||
|
g_autoptr(GError) error_local = NULL;
|
||||||
|
g_autoptr(GByteArray) buf = NULL;
|
||||||
|
if (!fu_intel_me_mkhi_device_add_checksum_for_filename(self,
|
||||||
|
fns[i],
|
||||||
|
&error_local)) {
|
||||||
|
if (g_error_matches(error_local, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
g_warning("failed to get public key using %s: %s",
|
||||||
|
fns[i],
|
||||||
|
error_local->message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* no point even adding */
|
||||||
|
if (fu_device_get_checksums(device)->len == 0) {
|
||||||
|
g_set_error_literal(error,
|
||||||
|
FWUPD_ERROR,
|
||||||
|
FWUPD_ERROR_NOT_SUPPORTED,
|
||||||
|
"no OEM public keys found");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* success */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_intel_me_mkhi_device_init(FuIntelMeMkhiDevice *self)
|
||||||
|
{
|
||||||
|
fu_device_set_logical_id(FU_DEVICE(self), "MKHI");
|
||||||
|
fu_device_set_name(FU_DEVICE(self), "BootGuard Configuration");
|
||||||
|
fu_device_add_parent_guid(FU_DEVICE(self), "main-system-firmware");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_intel_me_mkhi_device_class_init(FuIntelMeMkhiDeviceClass *klass)
|
||||||
|
{
|
||||||
|
FuDeviceClass *klass_device = FU_DEVICE_CLASS(klass);
|
||||||
|
klass_device->setup = fu_intel_me_mkhi_device_setup;
|
||||||
|
}
|
18
plugins/intel-me/fu-intel-me-mkhi-device.h
Normal file
18
plugins/intel-me/fu-intel-me-mkhi-device.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Richard Hughes <richard@hughsie.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fwupdplugin.h>
|
||||||
|
|
||||||
|
#include "fu-intel-me-heci-device.h"
|
||||||
|
|
||||||
|
#define FU_TYPE_INTEL_ME_MKHI_DEVICE (fu_intel_me_mkhi_device_get_type())
|
||||||
|
G_DECLARE_FINAL_TYPE(FuIntelMeMkhiDevice,
|
||||||
|
fu_intel_me_mkhi_device,
|
||||||
|
FU,
|
||||||
|
INTEL_ME_MKHI_DEVICE,
|
||||||
|
FuIntelMeHeciDevice)
|
38
plugins/intel-me/fu-intel-me-plugin.c
Normal file
38
plugins/intel-me/fu-intel-me-plugin.c
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Richard Hughes <richard@hughsie.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "fu-intel-me-mca-device.h"
|
||||||
|
#include "fu-intel-me-mkhi-device.h"
|
||||||
|
#include "fu-intel-me-plugin.h"
|
||||||
|
|
||||||
|
struct _FuIntelMePlugin {
|
||||||
|
FuPlugin parent_instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE(FuIntelMePlugin, fu_intel_me_plugin, FU_TYPE_PLUGIN)
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_intel_me_plugin_init(FuIntelMePlugin *self)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_intel_me_plugin_constructed(GObject *obj)
|
||||||
|
{
|
||||||
|
FuPlugin *plugin = FU_PLUGIN(obj);
|
||||||
|
fu_plugin_add_udev_subsystem(plugin, "mei");
|
||||||
|
fu_plugin_add_device_gtype(plugin, FU_TYPE_INTEL_ME_MCA_DEVICE);
|
||||||
|
fu_plugin_add_device_gtype(plugin, FU_TYPE_INTEL_ME_MKHI_DEVICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fu_intel_me_plugin_class_init(FuIntelMePluginClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
||||||
|
object_class->constructed = fu_intel_me_plugin_constructed;
|
||||||
|
}
|
11
plugins/intel-me/fu-intel-me-plugin.h
Normal file
11
plugins/intel-me/fu-intel-me-plugin.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Richard Hughes <richard@hughsie.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <fwupdplugin.h>
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE(FuIntelMePlugin, fu_intel_me_plugin, FU, INTEL_ME_PLUGIN, FuPlugin)
|
9
plugins/intel-me/intel-me.quirk
Normal file
9
plugins/intel-me/intel-me.quirk
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# MKHI (legacy)
|
||||||
|
[8e6a6715-9abc-4043-88ef-9e39c6f63e0f]
|
||||||
|
Plugin = intel_me
|
||||||
|
GType = FuIntelMeMkhiDevice
|
||||||
|
|
||||||
|
# MCA?
|
||||||
|
[dd17041c-09ea-4b17-a271-5b989867ec65]
|
||||||
|
Plugin = intel_me
|
||||||
|
GType = FuIntelMeMcaDevice
|
18
plugins/intel-me/meson.build
Normal file
18
plugins/intel-me/meson.build
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
if get_option('plugin_amt').disable_auto_if(host_machine.system() != 'linux').allowed()
|
||||||
|
cargs = ['-DG_LOG_DOMAIN="FuPluginIntelMe"']
|
||||||
|
|
||||||
|
plugin_quirks += files('intel-me.quirk')
|
||||||
|
plugin_builtins += static_library('fu_plugin_intel_me',
|
||||||
|
sources: [
|
||||||
|
'fu-intel-me-common.c',
|
||||||
|
'fu-intel-me-plugin.c',
|
||||||
|
'fu-intel-me-heci-device.c',
|
||||||
|
'fu-intel-me-mca-device.c',
|
||||||
|
'fu-intel-me-mkhi-device.c',
|
||||||
|
],
|
||||||
|
include_directories: plugin_incdirs,
|
||||||
|
link_with: plugin_libs,
|
||||||
|
c_args: cargs,
|
||||||
|
dependencies: plugin_deps,
|
||||||
|
)
|
||||||
|
endif
|
@ -52,6 +52,7 @@ subdir('genesys')
|
|||||||
subdir('goodix-moc')
|
subdir('goodix-moc')
|
||||||
subdir('gpio')
|
subdir('gpio')
|
||||||
subdir('hailuck')
|
subdir('hailuck')
|
||||||
|
subdir('intel-me')
|
||||||
subdir('intel-spi')
|
subdir('intel-spi')
|
||||||
subdir('intel-usb4')
|
subdir('intel-usb4')
|
||||||
subdir('iommu')
|
subdir('iommu')
|
||||||
|
@ -146,6 +146,11 @@ fu_security_attr_get_name(FwupdSecurityAttr *attr)
|
|||||||
* end users on consumer boards */
|
* end users on consumer boards */
|
||||||
return g_strdup(_("MEI override"));
|
return g_strdup(_("MEI override"));
|
||||||
}
|
}
|
||||||
|
if (g_strcmp0(appstream_id, FWUPD_SECURITY_ATTR_ID_MEI_KEY_MANIFEST) == 0) {
|
||||||
|
/* TRANSLATORS: Title: MEI = Intel Management Engine, and key refer
|
||||||
|
* to the private/public key used to secure loading of firmware */
|
||||||
|
return g_strdup(_("MEI key manifest"));
|
||||||
|
}
|
||||||
if (g_strcmp0(appstream_id, FWUPD_SECURITY_ATTR_ID_MEI_VERSION) == 0) {
|
if (g_strcmp0(appstream_id, FWUPD_SECURITY_ATTR_ID_MEI_VERSION) == 0) {
|
||||||
/* TRANSLATORS: Title: MEI = Intel Management Engine */
|
/* TRANSLATORS: Title: MEI = Intel Management Engine */
|
||||||
const gchar *kind = fwupd_security_attr_get_metadata(attr, "kind");
|
const gchar *kind = fwupd_security_attr_get_metadata(attr, "kind");
|
||||||
@ -322,6 +327,11 @@ fu_security_attr_get_title(FwupdSecurityAttr *attr)
|
|||||||
* boards */
|
* boards */
|
||||||
return _("Intel Management Engine Override");
|
return _("Intel Management Engine Override");
|
||||||
}
|
}
|
||||||
|
if (g_strcmp0(appstream_id, FWUPD_SECURITY_ATTR_ID_MEI_KEY_MANIFEST) == 0) {
|
||||||
|
/* TRANSLATORS: Title: MEI = Intel Management Engine, and key refers
|
||||||
|
* to the private/public key used to secure loading of firmware */
|
||||||
|
return g_strdup(_("MEI Key Manifest"));
|
||||||
|
}
|
||||||
if (g_strcmp0(appstream_id, FWUPD_SECURITY_ATTR_ID_MEI_VERSION) == 0) {
|
if (g_strcmp0(appstream_id, FWUPD_SECURITY_ATTR_ID_MEI_VERSION) == 0) {
|
||||||
/* TRANSLATORS: Title: MEI = Intel Management Engine */
|
/* TRANSLATORS: Title: MEI = Intel Management Engine */
|
||||||
return _("Intel Management Engine Version");
|
return _("Intel Management Engine Version");
|
||||||
@ -496,6 +506,11 @@ fu_security_attr_get_description(FwupdSecurityAttr *attr)
|
|||||||
return _("Intel Management Engine Override disables checks for device software "
|
return _("Intel Management Engine Override disables checks for device software "
|
||||||
"tampering.");
|
"tampering.");
|
||||||
}
|
}
|
||||||
|
if (g_strcmp0(appstream_id, FWUPD_SECURITY_ATTR_ID_MEI_KEY_MANIFEST) == 0) {
|
||||||
|
/* TRANSLATORS: longer description */
|
||||||
|
return _("The Intel Management Engine Key Manifest must be valid so "
|
||||||
|
"that the device firmware can be trusted by the CPU.");
|
||||||
|
}
|
||||||
if (g_strcmp0(appstream_id, FWUPD_SECURITY_ATTR_ID_MEI_VERSION) == 0) {
|
if (g_strcmp0(appstream_id, FWUPD_SECURITY_ATTR_ID_MEI_VERSION) == 0) {
|
||||||
/* TRANSLATORS: longer description */
|
/* TRANSLATORS: longer description */
|
||||||
return _("The Intel Management Engine controls device components and needs "
|
return _("The Intel Management Engine controls device components and needs "
|
||||||
|
Loading…
Reference in New Issue
Block a user