Skip to content

Commit

Permalink
Detect the AMD TSME encryption state for HSI
Browse files Browse the repository at this point in the history
  • Loading branch information
hughsie committed Jan 6, 2021
1 parent cf10029 commit b63cfa9
Show file tree
Hide file tree
Showing 10 changed files with 143 additions and 22 deletions.
13 changes: 9 additions & 4 deletions docs/hsi.xml
Expand Up @@ -710,10 +710,10 @@
</refsect3>

<refsect3 id="org.fwupd.hsi.EncryptedRam">
<title>DRAM total memory encryption (TME)</title>
<title>DRAM memory encryption</title>
<para>
Total memory encryption technology is used by the firmware on supported
SOCs to encrypt all data on external memory buses.
TME (Intel) or TSME (AMD) is used by the firmware on supported SOCs to
encrypt all data on external memory buses.
It mitigates against an attacker being able to capture memory data while
the system is running or to capture memory by removing a DRAM chip.
</para>
Expand All @@ -732,7 +732,12 @@
<ulink url="https://software.intel.com/content/www/us/en/develop/blogs/intel-releases-new-technology-specification-for-memory-encryption.html">
Intel TME Press Release
</ulink>
</listitem>0
</listitem>
<listitem>
<ulink url="https://en.wikichip.org/wiki/x86/sme">
WikiChip SME Overview
</ulink>
</listitem>
</itemizedlist>
</para>
</note>
Expand Down
4 changes: 4 additions & 0 deletions libfwupdplugin/README.md
@@ -0,0 +1,4 @@
Planned API/ABI changes for next release
========================================

* Remove fu_common_is_cpu_intel()
39 changes: 31 additions & 8 deletions libfwupdplugin/fu-common.c
Expand Up @@ -2236,26 +2236,49 @@ fu_common_cpuid (guint32 leaf,
* Uses CPUID to discover the CPU vendor and check if it is Intel.
*
* Return value: %TRUE if the vendor was Intel.
* Deprecated: 1.5.5: Use fu_common_get_cpu_vendor() instead.
*
* Since: 1.5.0
**/
gboolean
fu_common_is_cpu_intel (void)
{
return fu_common_get_cpu_vendor () == FU_CPU_VENDOR_INTEL;
}

/**
* fu_common_get_cpu_vendor:
*
* Uses CPUID to discover the CPU vendor.
*
* Return value: a #FuCpuVendor, e.g. %FU_CPU_VENDOR_AMD if the vendor was AMD.
*
* Since: 1.5.5
**/
FuCpuVendor
fu_common_get_cpu_vendor (void)
{
#ifdef HAVE_CPUID_H
guint ebx = 0;
guint ecx = 0;
guint edx = 0;

if (!fu_common_cpuid (0x0, NULL, &ebx, &ecx, &edx, NULL))
return FALSE;
#ifdef HAVE_CPUID_H
if (ebx == signature_INTEL_ebx &&
edx == signature_INTEL_edx &&
ecx == signature_INTEL_ecx) {
return TRUE;
if (fu_common_cpuid (0x0, NULL, &ebx, &ecx, &edx, NULL)) {
if (ebx == signature_INTEL_ebx &&
edx == signature_INTEL_edx &&
ecx == signature_INTEL_ecx) {
return FU_CPU_VENDOR_INTEL;
}
if (ebx == signature_AMD_ebx &&
edx == signature_AMD_edx &&
ecx == signature_AMD_ecx) {
return FU_CPU_VENDOR_AMD;
}
}
#endif
return FALSE;

/* failed */
return FU_CPU_VENDOR_UNKNOWN;
}

/**
Expand Down
20 changes: 19 additions & 1 deletion libfwupdplugin/fu-common.h
Expand Up @@ -84,6 +84,22 @@ typedef enum {
FU_PATH_KIND_LAST
} FuPathKind;

/**
* FuCpuVendor:
* @FU_CPU_VENDOR_UNKNOWN: Unknown
* @FU_CPU_VENDOR_INTEL: Intel
* @FU_CPU_VENDOR_AMD: AMD
*
* The CPU vendor.
**/
typedef enum {
FU_CPU_VENDOR_UNKNOWN,
FU_CPU_VENDOR_INTEL,
FU_CPU_VENDOR_AMD,
/*< private >*/
FU_CPU_VENDOR_LAST
} FuCpuVendor;

typedef void (*FuOutputHandler) (const gchar *line,
gpointer user_data);

Expand Down Expand Up @@ -260,7 +276,9 @@ gboolean fu_common_cpuid (guint32 leaf,
guint32 *edx,
GError **error)
G_GNUC_WARN_UNUSED_RESULT;
gboolean fu_common_is_cpu_intel (void);
gboolean fu_common_is_cpu_intel (void)
G_DEPRECATED_FOR(fu_common_get_cpu_vendor);
FuCpuVendor fu_common_get_cpu_vendor (void);
gboolean fu_common_is_live_media (void);
GPtrArray *fu_common_get_volumes_by_kind (const gchar *kind,
GError **error)
Expand Down
1 change: 1 addition & 0 deletions libfwupdplugin/fwupdplugin.map
Expand Up @@ -702,6 +702,7 @@ LIBFWUPDPLUGIN_1.5.4 {

LIBFWUPDPLUGIN_1.5.5 {
global:
fu_common_get_cpu_vendor;
fu_common_strsafe;
fu_device_add_internal_flag;
fu_device_has_internal_flag;
Expand Down
2 changes: 1 addition & 1 deletion plugins/acpi-dmar/fu-plugin-acpi-dmar.c
Expand Up @@ -27,7 +27,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs)
g_autoptr(GError) error_local = NULL;

/* only Intel */
if (!fu_common_is_cpu_intel ())
if (fu_common_get_cpu_vendor () != FU_CPU_VENDOR_INTEL)
return;

/* create attr */
Expand Down
2 changes: 1 addition & 1 deletion plugins/cpu/fu-plugin-cpu.c
Expand Up @@ -158,7 +158,7 @@ void
fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs)
{
/* only Intel */
if (!fu_common_is_cpu_intel ())
if (fu_common_get_cpu_vendor () != FU_CPU_VENDOR_INTEL)
return;

fu_plugin_add_security_attrs_intel_cet_enabled (plugin, attrs);
Expand Down
80 changes: 75 additions & 5 deletions plugins/msr/fu-plugin-msr.c
Expand Up @@ -21,13 +21,25 @@ typedef union {
} __attribute__((packed)) fields;
} FuMsrIa32Debug;

typedef union {
guint32 data;
struct {
guint32 unknown0 : 23; /* 0 -> 22 inc */
guint32 sev_is_enabled : 1;
guint32 unknown1 : 8;
} __attribute__((packed)) fields;
} FuMsrK8Syscfg;

struct FuPluginData {
gboolean ia32_debug_supported;
FuMsrIa32Debug ia32_debug;
gboolean k8_syscfg_supported;
FuMsrK8Syscfg k8_syscfg;
};

#define PCI_MSR_IA32_DEBUG_INTERFACE 0xc80
#define PCI_MSR_IA32_BIOS_SIGN_ID 0x8b
#define PCI_MSR_K8_SYSCFG 0xC0010010

void
fu_plugin_init (FuPlugin *plugin)
Expand All @@ -41,12 +53,23 @@ gboolean
fu_plugin_startup (FuPlugin *plugin, GError **error)
{
FuPluginData *priv = fu_plugin_get_data (plugin);
guint eax = 0;
guint ecx = 0;

/* sdbg is supported: https://en.wikipedia.org/wiki/CPUID */
if (!fu_common_cpuid (0x01, NULL, NULL, &ecx, NULL, error))
return FALSE;
priv->ia32_debug_supported = ((ecx >> 11) & 0x1) > 0;
if (fu_common_get_cpu_vendor () == FU_CPU_VENDOR_INTEL) {
if (!fu_common_cpuid (0x01, NULL, NULL, &ecx, NULL, error))
return FALSE;
priv->ia32_debug_supported = ((ecx >> 11) & 0x1) > 0;
}

/* indicates support for SEV */
if (fu_common_get_cpu_vendor () == FU_CPU_VENDOR_AMD) {
if (!fu_common_cpuid (0x8000001f, &eax, NULL, NULL, NULL, error))
return FALSE;
priv->k8_syscfg_supported = ((eax >> 0) & 0x1) > 0;
}

return TRUE;
}

Expand Down Expand Up @@ -91,6 +114,21 @@ fu_plugin_udev_device_added (FuPlugin *plugin, FuUdevDevice *device, GError **er
priv->ia32_debug.fields.debug_occurred);
}

/* grab MSR */
if (priv->k8_syscfg_supported) {
if (!fu_udev_device_pread_full (device, PCI_MSR_K8_SYSCFG,
buf, sizeof(buf), error)) {
g_prefix_error (error, "could not read MSR_K8_SYSCFG: ");
return FALSE;
}
if (!fu_common_read_uint32_safe (buf, sizeof(buf), 0x0,
&priv->k8_syscfg.data, G_LITTLE_ENDIAN,
error))
return FALSE;
g_debug ("MSR_K8_SYSCFG: sev_is_enabled=%i",
priv->k8_syscfg.fields.sev_is_enabled);
}

/* get microcode version */
if (device_cpu != NULL) {
guint32 ver_raw;
Expand Down Expand Up @@ -134,7 +172,7 @@ fu_plugin_add_security_attr_dci_enabled (FuPlugin *plugin, FuSecurityAttrs *attr
g_autoptr(FwupdSecurityAttr) attr = NULL;

/* this MSR is only valid for a subset of Intel CPUs */
if (!fu_common_is_cpu_intel ())
if (fu_common_get_cpu_vendor () != FU_CPU_VENDOR_INTEL)
return;
if (!priv->ia32_debug_supported)
return;
Expand Down Expand Up @@ -163,7 +201,7 @@ fu_plugin_add_security_attr_dci_locked (FuPlugin *plugin, FuSecurityAttrs *attrs
g_autoptr(FwupdSecurityAttr) attr = NULL;

/* this MSR is only valid for a subset of Intel CPUs */
if (!fu_common_is_cpu_intel ())
if (fu_common_get_cpu_vendor () != FU_CPU_VENDOR_INTEL)
return;
if (!priv->ia32_debug_supported)
return;
Expand All @@ -185,9 +223,41 @@ fu_plugin_add_security_attr_dci_locked (FuPlugin *plugin, FuSecurityAttrs *attrs
fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_LOCKED);
}

static void
fu_plugin_add_security_attr_amd_tsme_enabled (FuPlugin *plugin, FuSecurityAttrs *attrs)
{
FuPluginData *priv = fu_plugin_get_data (plugin);
g_autoptr(FwupdSecurityAttr) attr = NULL;

/* this MSR is only valid for a subset of AMD CPUs */
if (fu_common_get_cpu_vendor () != FU_CPU_VENDOR_AMD)
return;

/* create attr */
attr = fwupd_security_attr_new (FWUPD_SECURITY_ATTR_ID_ENCRYPTED_RAM);
fwupd_security_attr_set_plugin (attr, fu_plugin_get_name (plugin));
fwupd_security_attr_set_level (attr, FWUPD_SECURITY_ATTR_LEVEL_SYSTEM_PROTECTION);
fu_security_attrs_append (attrs, attr);

/* check fields */
if (!priv->k8_syscfg_supported) {
fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_SUPPORTED);
return;
}
if (!priv->k8_syscfg.fields.sev_is_enabled) {
fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_NOT_ENABLED);
return;
}

/* success */
fwupd_security_attr_add_flag (attr, FWUPD_SECURITY_ATTR_FLAG_SUCCESS);
fwupd_security_attr_set_result (attr, FWUPD_SECURITY_ATTR_RESULT_ENABLED);
}

void
fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs)
{
fu_plugin_add_security_attr_dci_enabled (plugin, attrs);
fu_plugin_add_security_attr_dci_locked (plugin, attrs);
fu_plugin_add_security_attr_amd_tsme_enabled (plugin, attrs);
}
2 changes: 1 addition & 1 deletion plugins/pci-bcr/fu-plugin-pci-bcr.c
Expand Up @@ -167,7 +167,7 @@ void
fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs)
{
/* only Intel */
if (!fu_common_is_cpu_intel ())
if (fu_common_get_cpu_vendor () != FU_CPU_VENDOR_INTEL)
return;

/* add attrs */
Expand Down
2 changes: 1 addition & 1 deletion plugins/pci-mei/fu-plugin-pci-mei.c
Expand Up @@ -467,7 +467,7 @@ fu_plugin_add_security_attrs (FuPlugin *plugin, FuSecurityAttrs *attrs)
FuPluginData *priv = fu_plugin_get_data (plugin);

/* only Intel */
if (!fu_common_is_cpu_intel ())
if (fu_common_get_cpu_vendor () != FU_CPU_VENDOR_INTEL)
return;
if (!priv->has_device)
return;
Expand Down

0 comments on commit b63cfa9

Please sign in to comment.