]> git.proxmox.com Git - fwupd.git/commitdiff
Move the AMT functionality to the Intel MEI plugin
authorRichard Hughes <richard@hughsie.com>
Wed, 12 Oct 2022 09:11:52 +0000 (10:11 +0100)
committerRichard Hughes <richard@hughsie.com>
Thu, 13 Oct 2022 17:34:00 +0000 (18:34 +0100)
16 files changed:
contrib/freebsd/Makefile
meson_options.txt
plugins/amt/README.md [deleted file]
plugins/amt/amt.quirk [deleted file]
plugins/amt/fu-amt-device.c [deleted file]
plugins/amt/fu-amt-device.h [deleted file]
plugins/amt/fu-amt-plugin.c [deleted file]
plugins/amt/fu-amt-plugin.h [deleted file]
plugins/amt/meson.build [deleted file]
plugins/intel-me/README.md
plugins/intel-me/fu-intel-me-amt-device.c [new file with mode: 0644]
plugins/intel-me/fu-intel-me-amt-device.h [new file with mode: 0644]
plugins/intel-me/fu-intel-me-plugin.c
plugins/intel-me/intel-me.quirk
plugins/intel-me/meson.build
plugins/meson.build

index 79a47eb606c2830960f058c7cfddea8a77824831..9b4a440bc42bdc48c1bbe0e06192e89086a188af 100644 (file)
@@ -42,7 +42,7 @@ USE_LDCONFIG= yes
 SHEBANG_GLOB=  *.py
 
 MESON_ARGS=    -Dgudev=disabled \
-               -Dplugin_amt=false \
+               -Dplugin_intel_me=false \
                -Dpolkit=disabled \
                -Dsystemd=disabled \
                -Doffline=false \
index 71292cdec1974681fb7ebb5da4d1b562520bdfa2..e23e2dc4345b96a946cf94af8786969295dfb77c 100644 (file)
@@ -15,7 +15,6 @@ option('gnutls', type: 'feature', description : 'GnuTLS support', deprecated: {'
 option('sqlite', type: 'feature', description : 'sqlite support', deprecated: {'true': 'enabled', 'false': 'disabled'})
 option('lzma', type: 'feature', description : 'LZMA support', deprecated: {'true': 'enabled', 'false': 'disabled'})
 option('cbor', type: 'feature', description : 'CBOR support for coSWID and uSWID')
-option('plugin_amt', type : 'feature', description : 'Intel AMT support', deprecated: {'true': 'enabled', 'false': 'disabled'})
 option('plugin_acpi_phat', type : 'feature', description : 'ACPI PHAT support', deprecated: {'true': 'enabled', 'false': 'disabled'})
 option('plugin_android_boot', type : 'feature', description : 'Android Boot support')
 option('plugin_bcm57xx', type : 'feature', description : 'BCM57xx support', deprecated: {'true': 'enabled', 'false': 'disabled'})
@@ -45,6 +44,7 @@ option('plugin_modem_manager', type : 'feature', description : 'ModemManager sup
 option('plugin_msr', type : 'feature', description : 'MSR support', deprecated: {'true': 'enabled', 'false': 'disabled'})
 option('plugin_mtd', type : 'feature', description : 'MTD support', deprecated: {'true': 'enabled', 'false': 'disabled'})
 option('plugin_flashrom', type : 'feature', description : 'flashrom support', deprecated: {'true': 'enabled', 'false': 'disabled'})
+option('plugin_intel_me', type : 'feature', description : 'enable Intel ME support')
 option('plugin_intel_spi', type : 'boolean', value : false, description : 'enable Intel SPI support')
 option('plugin_uf2', type : 'feature', description : 'support for UF2', deprecated: {'true': 'enabled', 'false': 'disabled'})
 option('plugin_upower', type : 'feature', description : 'support for UPower', deprecated: {'true': 'enabled', 'false': 'disabled'})
diff --git a/plugins/amt/README.md b/plugins/amt/README.md
deleted file mode 100644 (file)
index ec73789..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-# Intel Management Engine
-
-## Introduction
-
-This plugin is used to get the version number on the Intel Management Engine.
-
-If AMT is enabled and provisioned and the AMT version is between 6.0 and 11.2,
-and you have not upgraded your firmware, you are vulnerable to CVE-2017-5689 and
-you should disable AMT in your system firmware.
-
-This code is inspired by 'AMT status checker for Linux' by Matthew Garrett
-which can be found here: <https://github.com/mjg59/mei-amt-check>
-
-That tool in turn is heavily based on mei-amt-version from samples/mei in the
-Linux source tree and copyright Intel Corporation.
-
-## GUID Generation
-
-These devices use the existing GUID provided by the AMT host interface.
-
-## Vendor ID Security
-
-The device is not upgradable and thus requires no vendor ID set.
-
-## External Interface Access
-
-This plugin requires read only access to `/dev/mei0`.
diff --git a/plugins/amt/amt.quirk b/plugins/amt/amt.quirk
deleted file mode 100644 (file)
index c88423b..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-# PTHI client (via the HECI device)
-[12f80028-b4b7-4b2d-aca8-46e0ff65814c]
-Plugin = amt
diff --git a/plugins/amt/fu-amt-device.c b/plugins/amt/fu-amt-device.c
deleted file mode 100644 (file)
index c7bf502..0000000
+++ /dev/null
@@ -1,372 +0,0 @@
-/*
- * Copyright (C) 2012 Intel Corporation.
- * Copyright (C) 2017 Google, Inc.
- * Copyright (C) 2017 Richard Hughes <richard@hughsie.com>
- *
- * SPDX-License-Identifier: LGPL-2.1+
- */
-
-#include "config.h"
-
-#include "fu-amt-device.h"
-
-struct _FuAmtDevice {
-       FuMeiDevice parent_instance;
-};
-
-G_DEFINE_TYPE(FuAmtDevice, fu_amt_device, FU_TYPE_MEI_DEVICE)
-
-#define AMT_MAJOR_VERSION 1
-#define AMT_MINOR_VERSION 1
-
-#define AMT_STATUS_SUCCESS               0x0
-#define AMT_STATUS_INTERNAL_ERROR        0x1
-#define AMT_STATUS_NOT_READY             0x2
-#define AMT_STATUS_INVALID_AMT_MODE      0x3
-#define AMT_STATUS_INVALID_MESSAGE_LENGTH 0x4
-
-#define AMT_STATUS_HOST_IF_EMPTY_RESPONSE 0x4000
-#define AMT_STATUS_SDK_RESOURCES         0x1004
-
-#define AMT_BIOS_VERSION_LEN   65
-#define AMT_VERSIONS_NUMBER    50
-#define AMT_UNICODE_STRING_LEN 20
-
-struct amt_unicode_string {
-       guint16 length;
-       char string[AMT_UNICODE_STRING_LEN];
-} __attribute__((packed));
-
-struct amt_version_type {
-       struct amt_unicode_string description;
-       struct amt_unicode_string version;
-} __attribute__((packed));
-
-struct amt_version {
-       guint8 major;
-       guint8 minor;
-} __attribute__((packed));
-
-struct amt_code_versions {
-       guint8 bios[AMT_BIOS_VERSION_LEN];
-       guint32 count;
-       struct amt_version_type versions[AMT_VERSIONS_NUMBER];
-} __attribute__((packed));
-
-struct amt_provisioning_state {
-       guint8 bios[AMT_BIOS_VERSION_LEN];
-       guint32 count;
-       guint8 state;
-} __attribute__((packed));
-
-/***************************************************************************
- * Intel Advanced Management Technology Host Interface
- ***************************************************************************/
-
-struct amt_host_if_msg_header {
-       struct amt_version version;
-       guint16 _reserved;
-       guint32 command;
-       guint32 length;
-} __attribute__((packed));
-
-struct amt_host_if_resp_header {
-       struct amt_host_if_msg_header header;
-       guint32 status;
-       guchar data[0];
-} __attribute__((packed));
-
-#define AMT_HOST_IF_CODE_VERSIONS_REQUEST  0x0400001A
-#define AMT_HOST_IF_CODE_VERSIONS_RESPONSE 0x0480001A
-
-const struct amt_host_if_msg_header CODE_VERSION_REQ = {
-    .version = {AMT_MAJOR_VERSION, AMT_MINOR_VERSION},
-    ._reserved = 0,
-    .command = AMT_HOST_IF_CODE_VERSIONS_REQUEST,
-    .length = 0};
-
-#define AMT_HOST_IF_PROVISIONING_MODE_REQUEST  0x04000008
-#define AMT_HOST_IF_PROVISIONING_MODE_RESPONSE 0x04800008
-
-const struct amt_host_if_msg_header PROVISIONING_MODE_REQUEST = {
-    .version = {AMT_MAJOR_VERSION, AMT_MINOR_VERSION},
-    ._reserved = 0,
-    .command = AMT_HOST_IF_PROVISIONING_MODE_REQUEST,
-    .length = 0};
-
-#define AMT_HOST_IF_PROVISIONING_STATE_REQUEST 0x04000011
-#define AMT_HOST_IF_PROVISIONING_STATE_RESPONSE 0x04800011
-
-const struct amt_host_if_msg_header PROVISIONING_STATE_REQUEST = {
-    .version = {AMT_MAJOR_VERSION, AMT_MINOR_VERSION},
-    ._reserved = 0,
-    .command = AMT_HOST_IF_PROVISIONING_STATE_REQUEST,
-    .length = 0};
-
-struct amt_host_if {
-       FuAmtDevice self;
-};
-
-static gboolean
-fu_amt_device_verify_code_versions(const struct amt_host_if_resp_header *resp, GError **error)
-{
-       struct amt_code_versions *code_ver = (struct amt_code_versions *)resp->data;
-       gsize code_ver_len = resp->header.length - sizeof(guint32);
-       guint32 ver_type_cnt = code_ver_len - sizeof(code_ver->bios) - sizeof(code_ver->count);
-       if (code_ver->count != ver_type_cnt / sizeof(struct amt_version_type)) {
-               g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "invalid offset");
-               return FALSE;
-       }
-       for (guint32 i = 0; i < code_ver->count; i++) {
-               guint32 len = code_ver->versions[i].description.length;
-               if (len > AMT_UNICODE_STRING_LEN) {
-                       g_set_error_literal(error,
-                                           FWUPD_ERROR,
-                                           FWUPD_ERROR_INTERNAL,
-                                           "string too large");
-                       return FALSE;
-               }
-               len = code_ver->versions[i].version.length;
-               if (code_ver->versions[i].version.string[len] != '\0' ||
-                   len != strlen(code_ver->versions[i].version.string)) {
-                       g_set_error_literal(error,
-                                           FWUPD_ERROR,
-                                           FWUPD_ERROR_INTERNAL,
-                                           "string was invalid size");
-                       return FALSE;
-               }
-       }
-       return TRUE;
-}
-
-static gboolean
-fu_amt_device_status_set_error(guint32 status, GError **error)
-{
-       if (status == AMT_STATUS_SUCCESS)
-               return TRUE;
-       if (status == AMT_STATUS_INTERNAL_ERROR) {
-               g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "internal error");
-               return FALSE;
-       }
-       if (status == AMT_STATUS_NOT_READY) {
-               g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "not ready");
-               return FALSE;
-       }
-       if (status == AMT_STATUS_INVALID_AMT_MODE) {
-               g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "invalid AMT mode");
-               return FALSE;
-       }
-       if (status == AMT_STATUS_INVALID_MESSAGE_LENGTH) {
-               g_set_error_literal(error,
-                                   FWUPD_ERROR,
-                                   FWUPD_ERROR_INTERNAL,
-                                   "invalid message length");
-               return FALSE;
-       }
-       if (status == AMT_STATUS_HOST_IF_EMPTY_RESPONSE) {
-               g_set_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "Intel AMT is disabled");
-               return FALSE;
-       }
-       g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "unknown error");
-       return FALSE;
-}
-
-static gboolean
-fu_amt_device_host_if_call(FuAmtDevice *self,
-                          const guchar *command,
-                          gssize command_sz,
-                          guint8 **read_buf,
-                          guint32 rcmd,
-                          guint expected_sz,
-                          unsigned long send_timeout,
-                          GError **error)
-{
-       gsize in_buf_sz = fu_mei_device_get_max_msg_length(FU_MEI_DEVICE(self));
-       gsize out_buf_sz;
-       struct amt_host_if_resp_header *msg_hdr;
-
-       *read_buf = (guint8 *)g_malloc0(in_buf_sz);
-       msg_hdr = (struct amt_host_if_resp_header *)*read_buf;
-
-       if (!fu_mei_device_write(FU_MEI_DEVICE(self), command, command_sz, send_timeout, error))
-               return FALSE;
-       if (!fu_mei_device_read(FU_MEI_DEVICE(self),
-                               *read_buf,
-                               in_buf_sz,
-                               &out_buf_sz,
-                               2000,
-                               error))
-               return FALSE;
-       if (out_buf_sz <= 0) {
-               g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_READ, "empty response");
-               return FALSE;
-       }
-       if (expected_sz && expected_sz != out_buf_sz) {
-               g_set_error(error,
-                           FWUPD_ERROR,
-                           FWUPD_ERROR_WRITE,
-                           "expected %u but got %u",
-                           (guint)expected_sz,
-                           (guint)out_buf_sz);
-               return FALSE;
-       }
-       if (!fu_amt_device_status_set_error(msg_hdr->status, error))
-               return FALSE;
-       if (out_buf_sz < sizeof(struct amt_host_if_resp_header)) {
-               g_set_error_literal(error,
-                                   FWUPD_ERROR,
-                                   FWUPD_ERROR_READ,
-                                   "invalid response: too small");
-               return FALSE;
-       }
-       if (out_buf_sz != (msg_hdr->header.length + sizeof(struct amt_host_if_msg_header))) {
-               g_set_error_literal(error,
-                                   FWUPD_ERROR,
-                                   FWUPD_ERROR_READ,
-                                   "invalid response: headerlen");
-               return FALSE;
-       }
-       if (msg_hdr->header.command != rcmd) {
-               g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_READ, "invalid response: rcmd");
-               return FALSE;
-       }
-       if (msg_hdr->header._reserved != 0) {
-               g_set_error_literal(error,
-                                   FWUPD_ERROR,
-                                   FWUPD_ERROR_READ,
-                                   "invalid response: reserved");
-               return FALSE;
-       }
-       if (msg_hdr->header.version.major != AMT_MAJOR_VERSION ||
-           msg_hdr->header.version.minor < AMT_MINOR_VERSION) {
-               g_set_error_literal(error,
-                                   FWUPD_ERROR,
-                                   FWUPD_ERROR_READ,
-                                   "invalid response: version");
-               return FALSE;
-       }
-       return TRUE;
-}
-
-static gboolean
-fu_amt_device_get_provisioning_state(FuAmtDevice *self, guint8 *state, GError **error)
-{
-       g_autofree struct amt_host_if_resp_header *response = NULL;
-       if (!fu_amt_device_host_if_call(self,
-                                       (const guchar *)&PROVISIONING_STATE_REQUEST,
-                                       sizeof(PROVISIONING_STATE_REQUEST),
-                                       (guint8 **)&response,
-                                       AMT_HOST_IF_PROVISIONING_STATE_RESPONSE,
-                                       0,
-                                       5000,
-                                       error)) {
-               g_prefix_error(error, "unable to get provisioning state: ");
-               return FALSE;
-       }
-       *state = response->data[0];
-       return TRUE;
-}
-
-static gboolean
-fu_amt_device_open(FuDevice *device, GError **error)
-{
-       /* open then create context */
-       if (!FU_DEVICE_CLASS(fu_amt_device_parent_class)->open(device, error))
-               return FALSE;
-       return fu_mei_device_connect(FU_MEI_DEVICE(device), 0, error);
-}
-
-static gboolean
-fu_amt_device_setup(FuDevice *device, GError **error)
-{
-       FuAmtDevice *self = FU_AMT_DEVICE(device);
-       guint8 state;
-       struct amt_code_versions ver;
-       g_autofree struct amt_host_if_resp_header *response = NULL;
-       g_autoptr(GString) version_bl = g_string_new(NULL);
-       g_autoptr(GString) version_fw = g_string_new(NULL);
-
-       /* check version */
-       if (!fu_amt_device_host_if_call(self,
-                                       (const guchar *)&CODE_VERSION_REQ,
-                                       sizeof(CODE_VERSION_REQ),
-                                       (guint8 **)&response,
-                                       AMT_HOST_IF_CODE_VERSIONS_RESPONSE,
-                                       0,
-                                       5000,
-                                       error)) {
-               g_prefix_error(error, "Failed to check version: ");
-               return FALSE;
-       }
-       if (!fu_amt_device_verify_code_versions(response, error)) {
-               g_prefix_error(error, "failed to verify code versions: ");
-               return FALSE;
-       }
-       memcpy(&ver, response->data, sizeof(struct amt_code_versions));
-
-       if (!fu_amt_device_get_provisioning_state(self, &state, error))
-               return FALSE;
-       switch (state) {
-       case 0:
-               fu_device_set_name(device, "AMT [unprovisioned]");
-               break;
-       case 1:
-               fu_device_set_name(device, "AMT [being provisioned]");
-               break;
-       case 2:
-               fu_device_set_name(device, "AMT [provisioned]");
-               break;
-       default:
-               fu_device_set_name(device, "AMT [unknown]");
-               break;
-       }
-
-       /* add guid */
-       fu_device_add_parent_guid(device, "main-system-firmware");
-
-       /* get version numbers */
-       for (guint i = 0; i < ver.count; i++) {
-               if (g_strcmp0(ver.versions[i].description.string, "AMT") == 0) {
-                       g_string_append(version_fw, ver.versions[i].version.string);
-                       continue;
-               }
-               if (g_strcmp0(ver.versions[i].description.string, "Recovery Version") == 0) {
-                       g_string_append(version_bl, ver.versions[i].version.string);
-                       continue;
-               }
-               if (g_strcmp0(ver.versions[i].description.string, "Build Number") == 0) {
-                       g_string_append_printf(version_fw, ".%s", ver.versions[i].version.string);
-                       continue;
-               }
-               if (g_strcmp0(ver.versions[i].description.string, "Recovery Build Num") == 0) {
-                       g_string_append_printf(version_bl, ".%s", ver.versions[i].version.string);
-                       continue;
-               }
-       }
-       if (version_fw->len > 0)
-               fu_device_set_version(device, version_fw->str);
-       if (version_bl->len > 0)
-               fu_device_set_version_bootloader(device, version_bl->str);
-
-       /* success */
-       return TRUE;
-}
-
-static void
-fu_amt_device_init(FuAmtDevice *self)
-{
-       fu_device_set_version_format(FU_DEVICE(self), FWUPD_VERSION_FORMAT_INTEL_ME);
-       fu_device_add_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_INTERNAL);
-       fu_device_add_icon(FU_DEVICE(self), "computer");
-       fu_device_set_summary(FU_DEVICE(self),
-                             "Hardware and firmware technology for remote "
-                             "out-of-band management");
-}
-
-static void
-fu_amt_device_class_init(FuAmtDeviceClass *klass)
-{
-       FuDeviceClass *klass_device = FU_DEVICE_CLASS(klass);
-       klass_device->open = fu_amt_device_open;
-       klass_device->setup = fu_amt_device_setup;
-}
diff --git a/plugins/amt/fu-amt-device.h b/plugins/amt/fu-amt-device.h
deleted file mode 100644 (file)
index d694825..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * Copyright (C) 2022 Richard Hughes <richard@hughsie.com>
- *
- * SPDX-License-Identifier: LGPL-2.1+
- */
-
-#pragma once
-
-#include <fwupdplugin.h>
-
-#define FU_TYPE_AMT_DEVICE (fu_amt_device_get_type())
-G_DECLARE_FINAL_TYPE(FuAmtDevice, fu_amt_device, FU, AMT_DEVICE, FuMeiDevice)
diff --git a/plugins/amt/fu-amt-plugin.c b/plugins/amt/fu-amt-plugin.c
deleted file mode 100644 (file)
index e9de8ef..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2022 Richard Hughes <richard@hughsie.com>
- *
- * SPDX-License-Identifier: LGPL-2.1+
- */
-
-#include "config.h"
-
-#include "fu-amt-device.h"
-#include "fu-amt-plugin.h"
-
-struct _FuAmtPlugin {
-       FuPlugin parent_instance;
-};
-
-G_DEFINE_TYPE(FuAmtPlugin, fu_amt_plugin, FU_TYPE_PLUGIN)
-
-static void
-fu_amt_plugin_init(FuAmtPlugin *self)
-{
-}
-
-static void
-fu_amt_plugin_constructed(GObject *obj)
-{
-       FuPlugin *plugin = FU_PLUGIN(obj);
-       fu_plugin_add_udev_subsystem(plugin, "mei");
-       fu_plugin_add_device_gtype(plugin, FU_TYPE_AMT_DEVICE);
-}
-
-static void
-fu_amt_plugin_class_init(FuAmtPluginClass *klass)
-{
-       GObjectClass *object_class = G_OBJECT_CLASS(klass);
-       object_class->constructed = fu_amt_plugin_constructed;
-}
diff --git a/plugins/amt/fu-amt-plugin.h b/plugins/amt/fu-amt-plugin.h
deleted file mode 100644 (file)
index cb82b07..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- * Copyright (C) 2022 Richard Hughes <richard@hughsie.com>
- *
- * SPDX-License-Identifier: LGPL-2.1+
- */
-
-#pragma once
-
-#include <fwupdplugin.h>
-
-G_DECLARE_FINAL_TYPE(FuAmtPlugin, fu_amt_plugin, FU, AMT_PLUGIN, FuPlugin)
diff --git a/plugins/amt/meson.build b/plugins/amt/meson.build
deleted file mode 100644 (file)
index c5b36fb..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-if get_option('plugin_amt').disable_auto_if(host_machine.system() != 'linux').allowed()
-cargs = ['-DG_LOG_DOMAIN="FuPluginAmt"']
-
-plugin_quirks += files('amt.quirk')
-plugin_builtins += static_library('fu_plugin_amt',
-  sources: [
-    'fu-amt-plugin.c',
-    'fu-amt-device.c',
-  ],
-  include_directories: plugin_incdirs,
-  link_with: plugin_libs,
-  c_args: cargs,
-  dependencies: plugin_deps,
-)
-endif
index 5657a98b0018032e49d8ffea041eafedb33f9154..a0675f4b631eaf58ad9ef61e6c232ff123d53153 100644 (file)
@@ -4,7 +4,18 @@
 
 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.
+It allows us to get the Platform Key as used for BootGuard and to get the
+version number for the Intel AMT.
+
+If AMT is enabled and provisioned and the AMT version is between 6.0 and 11.2,
+and you have not upgraded your firmware, you are vulnerable to CVE-2017-5689 and
+you should disable AMT in your system firmware.
+
+This code is inspired by 'AMT status checker for Linux' by Matthew Garrett
+which can be found here: <https://github.com/mjg59/mei-amt-check>
+
+That tool in turn is heavily based on mei-amt-version from samples/mei in the
+Linux source tree and copyright Intel Corporation.
 
 ## GUID Generation
 
diff --git a/plugins/intel-me/fu-intel-me-amt-device.c b/plugins/intel-me/fu-intel-me-amt-device.c
new file mode 100644 (file)
index 0000000..141e0df
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 2012 Intel Corporation.
+ * Copyright (C) 2017 Google, Inc.
+ * Copyright (C) 2017 Richard Hughes <richard@hughsie.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "config.h"
+
+#include "fu-intel-me-amt-device.h"
+
+struct _FuIntelMeAmtDevice {
+       FuMeiDevice parent_instance;
+};
+
+G_DEFINE_TYPE(FuIntelMeAmtDevice, fu_intel_me_amt_device, FU_TYPE_MEI_DEVICE)
+
+#define AMT_MAJOR_VERSION 1
+#define AMT_MINOR_VERSION 1
+
+#define AMT_STATUS_SUCCESS               0x0
+#define AMT_STATUS_INTERNAL_ERROR        0x1
+#define AMT_STATUS_NOT_READY             0x2
+#define AMT_STATUS_INVALID_AMT_MODE      0x3
+#define AMT_STATUS_INVALID_MESSAGE_LENGTH 0x4
+
+#define AMT_STATUS_HOST_IF_EMPTY_RESPONSE 0x4000
+#define AMT_STATUS_SDK_RESOURCES         0x1004
+
+#define AMT_BIOS_VERSION_LEN   65
+#define AMT_VERSIONS_NUMBER    50
+#define AMT_UNICODE_STRING_LEN 20
+
+struct amt_unicode_string {
+       guint16 length;
+       char string[AMT_UNICODE_STRING_LEN];
+} __attribute__((packed));
+
+struct amt_version_type {
+       struct amt_unicode_string description;
+       struct amt_unicode_string version;
+} __attribute__((packed));
+
+struct amt_version {
+       guint8 major;
+       guint8 minor;
+} __attribute__((packed));
+
+struct amt_code_versions {
+       guint8 bios[AMT_BIOS_VERSION_LEN];
+       guint32 count;
+       struct amt_version_type versions[AMT_VERSIONS_NUMBER];
+} __attribute__((packed));
+
+struct amt_provisioning_state {
+       guint8 bios[AMT_BIOS_VERSION_LEN];
+       guint32 count;
+       guint8 state;
+} __attribute__((packed));
+
+/***************************************************************************
+ * Intel Advanced Management Technology Host Interface
+ ***************************************************************************/
+
+struct amt_host_if_msg_header {
+       struct amt_version version;
+       guint16 _reserved;
+       guint32 command;
+       guint32 length;
+} __attribute__((packed));
+
+struct amt_host_if_resp_header {
+       struct amt_host_if_msg_header header;
+       guint32 status;
+       guchar data[0];
+} __attribute__((packed));
+
+#define AMT_HOST_IF_CODE_VERSIONS_REQUEST  0x0400001A
+#define AMT_HOST_IF_CODE_VERSIONS_RESPONSE 0x0480001A
+
+const struct amt_host_if_msg_header CODE_VERSION_REQ = {
+    .version = {AMT_MAJOR_VERSION, AMT_MINOR_VERSION},
+    ._reserved = 0,
+    .command = AMT_HOST_IF_CODE_VERSIONS_REQUEST,
+    .length = 0};
+
+#define AMT_HOST_IF_PROVISIONING_MODE_REQUEST  0x04000008
+#define AMT_HOST_IF_PROVISIONING_MODE_RESPONSE 0x04800008
+
+const struct amt_host_if_msg_header PROVISIONING_MODE_REQUEST = {
+    .version = {AMT_MAJOR_VERSION, AMT_MINOR_VERSION},
+    ._reserved = 0,
+    .command = AMT_HOST_IF_PROVISIONING_MODE_REQUEST,
+    .length = 0};
+
+#define AMT_HOST_IF_PROVISIONING_STATE_REQUEST 0x04000011
+#define AMT_HOST_IF_PROVISIONING_STATE_RESPONSE 0x04800011
+
+const struct amt_host_if_msg_header PROVISIONING_STATE_REQUEST = {
+    .version = {AMT_MAJOR_VERSION, AMT_MINOR_VERSION},
+    ._reserved = 0,
+    .command = AMT_HOST_IF_PROVISIONING_STATE_REQUEST,
+    .length = 0};
+
+struct amt_host_if {
+       FuIntelMeAmtDevice self;
+};
+
+static gboolean
+fu_intel_me_amt_device_verify_code_versions(const struct amt_host_if_resp_header *resp,
+                                           GError **error)
+{
+       struct amt_code_versions *code_ver = (struct amt_code_versions *)resp->data;
+       gsize code_ver_len = resp->header.length - sizeof(guint32);
+       guint32 ver_type_cnt = code_ver_len - sizeof(code_ver->bios) - sizeof(code_ver->count);
+       if (code_ver->count != ver_type_cnt / sizeof(struct amt_version_type)) {
+               g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "invalid offset");
+               return FALSE;
+       }
+       for (guint32 i = 0; i < code_ver->count; i++) {
+               guint32 len = code_ver->versions[i].description.length;
+               if (len > AMT_UNICODE_STRING_LEN) {
+                       g_set_error_literal(error,
+                                           FWUPD_ERROR,
+                                           FWUPD_ERROR_INTERNAL,
+                                           "string too large");
+                       return FALSE;
+               }
+               len = code_ver->versions[i].version.length;
+               if (code_ver->versions[i].version.string[len] != '\0' ||
+                   len != strlen(code_ver->versions[i].version.string)) {
+                       g_set_error_literal(error,
+                                           FWUPD_ERROR,
+                                           FWUPD_ERROR_INTERNAL,
+                                           "string was invalid size");
+                       return FALSE;
+               }
+       }
+       return TRUE;
+}
+
+static gboolean
+fu_intel_me_amt_device_status_set_error(guint32 status, GError **error)
+{
+       if (status == AMT_STATUS_SUCCESS)
+               return TRUE;
+       if (status == AMT_STATUS_INTERNAL_ERROR) {
+               g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "internal error");
+               return FALSE;
+       }
+       if (status == AMT_STATUS_NOT_READY) {
+               g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "not ready");
+               return FALSE;
+       }
+       if (status == AMT_STATUS_INVALID_AMT_MODE) {
+               g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "invalid AMT mode");
+               return FALSE;
+       }
+       if (status == AMT_STATUS_INVALID_MESSAGE_LENGTH) {
+               g_set_error_literal(error,
+                                   FWUPD_ERROR,
+                                   FWUPD_ERROR_INTERNAL,
+                                   "invalid message length");
+               return FALSE;
+       }
+       if (status == AMT_STATUS_HOST_IF_EMPTY_RESPONSE) {
+               g_set_error(error, FWUPD_ERROR, FWUPD_ERROR_NOT_SUPPORTED, "Intel AMT is disabled");
+               return FALSE;
+       }
+       g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_INTERNAL, "unknown error");
+       return FALSE;
+}
+
+static gboolean
+fu_intel_me_amt_device_host_if_call(FuIntelMeAmtDevice *self,
+                                   const guchar *command,
+                                   gssize command_sz,
+                                   guint8 **read_buf,
+                                   guint32 rcmd,
+                                   guint expected_sz,
+                                   unsigned long send_timeout,
+                                   GError **error)
+{
+       gsize in_buf_sz = fu_mei_device_get_max_msg_length(FU_MEI_DEVICE(self));
+       gsize out_buf_sz;
+       struct amt_host_if_resp_header *msg_hdr;
+
+       *read_buf = (guint8 *)g_malloc0(in_buf_sz);
+       msg_hdr = (struct amt_host_if_resp_header *)*read_buf;
+
+       if (!fu_mei_device_write(FU_MEI_DEVICE(self), command, command_sz, send_timeout, error))
+               return FALSE;
+       if (!fu_mei_device_read(FU_MEI_DEVICE(self),
+                               *read_buf,
+                               in_buf_sz,
+                               &out_buf_sz,
+                               2000,
+                               error))
+               return FALSE;
+       if (out_buf_sz <= 0) {
+               g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_READ, "empty response");
+               return FALSE;
+       }
+       if (expected_sz && expected_sz != out_buf_sz) {
+               g_set_error(error,
+                           FWUPD_ERROR,
+                           FWUPD_ERROR_WRITE,
+                           "expected %u but got %u",
+                           (guint)expected_sz,
+                           (guint)out_buf_sz);
+               return FALSE;
+       }
+       if (!fu_intel_me_amt_device_status_set_error(msg_hdr->status, error))
+               return FALSE;
+       if (out_buf_sz < sizeof(struct amt_host_if_resp_header)) {
+               g_set_error_literal(error,
+                                   FWUPD_ERROR,
+                                   FWUPD_ERROR_READ,
+                                   "invalid response: too small");
+               return FALSE;
+       }
+       if (out_buf_sz != (msg_hdr->header.length + sizeof(struct amt_host_if_msg_header))) {
+               g_set_error_literal(error,
+                                   FWUPD_ERROR,
+                                   FWUPD_ERROR_READ,
+                                   "invalid response: headerlen");
+               return FALSE;
+       }
+       if (msg_hdr->header.command != rcmd) {
+               g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_READ, "invalid response: rcmd");
+               return FALSE;
+       }
+       if (msg_hdr->header._reserved != 0) {
+               g_set_error_literal(error,
+                                   FWUPD_ERROR,
+                                   FWUPD_ERROR_READ,
+                                   "invalid response: reserved");
+               return FALSE;
+       }
+       if (msg_hdr->header.version.major != AMT_MAJOR_VERSION ||
+           msg_hdr->header.version.minor < AMT_MINOR_VERSION) {
+               g_set_error_literal(error,
+                                   FWUPD_ERROR,
+                                   FWUPD_ERROR_READ,
+                                   "invalid response: version");
+               return FALSE;
+       }
+       return TRUE;
+}
+
+static gboolean
+fu_intel_me_amt_device_get_provisioning_state(FuIntelMeAmtDevice *self,
+                                             guint8 *state,
+                                             GError **error)
+{
+       g_autofree struct amt_host_if_resp_header *response = NULL;
+       if (!fu_intel_me_amt_device_host_if_call(self,
+                                                (const guchar *)&PROVISIONING_STATE_REQUEST,
+                                                sizeof(PROVISIONING_STATE_REQUEST),
+                                                (guint8 **)&response,
+                                                AMT_HOST_IF_PROVISIONING_STATE_RESPONSE,
+                                                0,
+                                                5000,
+                                                error)) {
+               g_prefix_error(error, "unable to get provisioning state: ");
+               return FALSE;
+       }
+       *state = response->data[0];
+       return TRUE;
+}
+
+static gboolean
+fu_intel_me_amt_device_open(FuDevice *device, GError **error)
+{
+       /* open then create context */
+       if (!FU_DEVICE_CLASS(fu_intel_me_amt_device_parent_class)->open(device, error))
+               return FALSE;
+       return fu_mei_device_connect(FU_MEI_DEVICE(device), 0, error);
+}
+
+static gboolean
+fu_intel_me_amt_device_setup(FuDevice *device, GError **error)
+{
+       FuIntelMeAmtDevice *self = FU_INTEL_ME_AMT_DEVICE(device);
+       guint8 state;
+       struct amt_code_versions ver;
+       g_autofree struct amt_host_if_resp_header *response = NULL;
+       g_autoptr(GString) version_bl = g_string_new(NULL);
+       g_autoptr(GString) version_fw = g_string_new(NULL);
+
+       /* check version */
+       if (!fu_intel_me_amt_device_host_if_call(self,
+                                                (const guchar *)&CODE_VERSION_REQ,
+                                                sizeof(CODE_VERSION_REQ),
+                                                (guint8 **)&response,
+                                                AMT_HOST_IF_CODE_VERSIONS_RESPONSE,
+                                                0,
+                                                5000,
+                                                error)) {
+               g_prefix_error(error, "Failed to check version: ");
+               return FALSE;
+       }
+       if (!fu_intel_me_amt_device_verify_code_versions(response, error)) {
+               g_prefix_error(error, "failed to verify code versions: ");
+               return FALSE;
+       }
+       memcpy(&ver, response->data, sizeof(struct amt_code_versions));
+
+       if (!fu_intel_me_amt_device_get_provisioning_state(self, &state, error))
+               return FALSE;
+       switch (state) {
+       case 0:
+               fu_device_set_name(device, "AMT [unprovisioned]");
+               break;
+       case 1:
+               fu_device_set_name(device, "AMT [being provisioned]");
+               break;
+       case 2:
+               fu_device_set_name(device, "AMT [provisioned]");
+               break;
+       default:
+               fu_device_set_name(device, "AMT [unknown]");
+               break;
+       }
+
+       /* add guid */
+       fu_device_add_parent_guid(device, "main-system-firmware");
+
+       /* get version numbers */
+       for (guint i = 0; i < ver.count; i++) {
+               if (g_strcmp0(ver.versions[i].description.string, "AMT") == 0) {
+                       g_string_append(version_fw, ver.versions[i].version.string);
+                       continue;
+               }
+               if (g_strcmp0(ver.versions[i].description.string, "Recovery Version") == 0) {
+                       g_string_append(version_bl, ver.versions[i].version.string);
+                       continue;
+               }
+               if (g_strcmp0(ver.versions[i].description.string, "Build Number") == 0) {
+                       g_string_append_printf(version_fw, ".%s", ver.versions[i].version.string);
+                       continue;
+               }
+               if (g_strcmp0(ver.versions[i].description.string, "Recovery Build Num") == 0) {
+                       g_string_append_printf(version_bl, ".%s", ver.versions[i].version.string);
+                       continue;
+               }
+       }
+       if (version_fw->len > 0)
+               fu_device_set_version(device, version_fw->str);
+       if (version_bl->len > 0)
+               fu_device_set_version_bootloader(device, version_bl->str);
+
+       /* success */
+       return TRUE;
+}
+
+static void
+fu_intel_me_amt_device_init(FuIntelMeAmtDevice *self)
+{
+       fu_device_set_logical_id(FU_DEVICE(self), "AMT");
+       fu_device_set_version_format(FU_DEVICE(self), FWUPD_VERSION_FORMAT_INTEL_ME);
+       fu_device_add_flag(FU_DEVICE(self), FWUPD_DEVICE_FLAG_INTERNAL);
+       fu_device_add_icon(FU_DEVICE(self), "computer");
+       fu_device_set_summary(FU_DEVICE(self),
+                             "Hardware and firmware technology for remote "
+                             "out-of-band management");
+}
+
+static void
+fu_intel_me_amt_device_class_init(FuIntelMeAmtDeviceClass *klass)
+{
+       FuDeviceClass *klass_device = FU_DEVICE_CLASS(klass);
+       klass_device->open = fu_intel_me_amt_device_open;
+       klass_device->setup = fu_intel_me_amt_device_setup;
+}
diff --git a/plugins/intel-me/fu-intel-me-amt-device.h b/plugins/intel-me/fu-intel-me-amt-device.h
new file mode 100644 (file)
index 0000000..72b220d
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2022 Richard Hughes <richard@hughsie.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#pragma once
+
+#include <fwupdplugin.h>
+
+#define FU_TYPE_INTEL_ME_AMT_DEVICE (fu_intel_me_amt_device_get_type())
+G_DECLARE_FINAL_TYPE(FuIntelMeAmtDevice,
+                    fu_intel_me_amt_device,
+                    FU,
+                    INTEL_ME_AMT_DEVICE,
+                    FuMeiDevice)
index 68f3139ac4e99c36a19a633912cf58d9507912a1..7d51e216b30b0045a24f47187ac53394a0bd6831 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "config.h"
 
+#include "fu-intel-me-amt-device.h"
 #include "fu-intel-me-mca-device.h"
 #include "fu-intel-me-mkhi-device.h"
 #include "fu-intel-me-plugin.h"
@@ -26,6 +27,7 @@ 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_AMT_DEVICE);
        fu_plugin_add_device_gtype(plugin, FU_TYPE_INTEL_ME_MCA_DEVICE);
        fu_plugin_add_device_gtype(plugin, FU_TYPE_INTEL_ME_MKHI_DEVICE);
 }
index f65dc13efa35b2ec5e8ed520d74375b848f0e970..0756d9011f49c4f80169c4760995d544817e4260 100644 (file)
@@ -1,3 +1,8 @@
+# PTHI client (via the HECI device)
+[12f80028-b4b7-4b2d-aca8-46e0ff65814c]
+Plugin = intel_me
+GType = FuIntelMeAmtDevice
+
 # MKHI (legacy)
 [8e6a6715-9abc-4043-88ef-9e39c6f63e0f]
 Plugin = intel_me
index 2efa22c6fc25b908d0dac6297493f6adae0c369e..186e3a7ad2ddae57036482d50cdb8ec637c43556 100644 (file)
@@ -1,4 +1,4 @@
-if get_option('plugin_amt').disable_auto_if(host_machine.system() != 'linux').allowed()
+if get_option('plugin_intel_me').disable_auto_if(host_machine.system() != 'linux').allowed()
 cargs = ['-DG_LOG_DOMAIN="FuPluginIntelMe"']
 
 plugin_quirks += files('intel-me.quirk')
@@ -6,6 +6,7 @@ plugin_builtins += static_library('fu_plugin_intel_me',
   sources: [
     'fu-intel-me-common.c',
     'fu-intel-me-plugin.c',
+    'fu-intel-me-amt-device.c',
     'fu-intel-me-heci-device.c',
     'fu-intel-me-mca-device.c',
     'fu-intel-me-mkhi-device.c',
index 39a759fe2ba16d3e028e661a2c4a4c94735a2be2..2536a63c1bf6836a22e3a19d0d51d827afd8036d 100644 (file)
@@ -20,7 +20,6 @@ subdir('acpi-facp')
 subdir('acpi-ivrs')
 subdir('acpi-phat')
 subdir('amd-pmc')
-subdir('amt')
 subdir('analogix')
 subdir('android-boot')
 subdir('ata')