[PATCH] platform/x86: Export LPC attributes for the system SPI chip

Mario.Limonciello at dell.com Mario.Limonciello at dell.com
Thu May 7 17:45:27 UTC 2020


> Export standard LPC configuration values from various LPC/eSPI
> controllers. This allows userspace components such as fwupd to
> verify the most basic SPI protections are set correctly.
> For instance, checking BIOSWE is disabled and BLE is enabled.
> 
> More cutting-edge checks (e.g. PRx and BootGuard) can be added
> once the basics are in place. Exporting these values from the
> kernel allows us to report the security level of the platform
> without rebooting and running an unsigned EFI binary like
> chipsec.
> 
> Signed-off-by: Richard Hughes <richard at hughsie.com>
> ---
>  MAINTAINERS                          |   6 +
>  drivers/platform/x86/Kconfig         |  10 ++
>  drivers/platform/x86/Makefile        |   1 +
>  drivers/platform/x86/intel_spi_lpc.c | 183 +++++++++++++++++++++++++++
>  4 files changed, 200 insertions(+)
>  create mode 100644 drivers/platform/x86/intel_spi_lpc.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 2926327e4976..2779a8d48f1c 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -401,6 +401,12 @@ L:	platform-driver-x86 at vger.kernel.org
>  S:	Maintained
>  F:	drivers/platform/x86/i2c-multi-instantiate.c
> 
> +SPI LPC configuration
> +M:	Richard Hughes <richard at hughsie.com>
> +L:	platform-driver-x86 at vger.kernel.org
> +S:	Maintained
> +F:	drivers/platform/x86/intel_spi_lpc.c
> +
>  ACPI PMIC DRIVERS
>  M:	"Rafael J. Wysocki" <rjw at rjwysocki.net>
>  M:	Len Brown <lenb at kernel.org>
> diff --git a/drivers/platform/x86/Kconfig
> b/drivers/platform/x86/Kconfig
> index 0ad7ad8cf8e1..5f7441cde5e7 100644
> --- a/drivers/platform/x86/Kconfig
> +++ b/drivers/platform/x86/Kconfig
> @@ -837,6 +837,16 @@ config INTEL_VBTN
>  	  To compile this driver as a module, choose M here: the module
> will
>  	  be called intel_vbtn.
> 
> +config INTEL_SPI_LPC
> +	tristate "Intel SPI LPC configuration"
> +	depends on SECURITY
> +	help
> +	  Export LPC configuration attributes for the system SPI chip.
> +
> +	  To compile this driver as a module, choose M here: the module
> will
> +	  be called intel_spi_lpc.
> +	  If unsure, say N.
> +
>  config SURFACE3_WMI
>  	tristate "Surface 3 WMI Driver"
>  	depends on ACPI_WMI
> diff --git a/drivers/platform/x86/Makefile
> b/drivers/platform/x86/Makefile
> index 53408d965874..e8f6901bb165 100644
> --- a/drivers/platform/x86/Makefile
> +++ b/drivers/platform/x86/Makefile
> @@ -78,6 +78,7 @@ obj-$(CONFIG_INTEL_INT0002_VGPIO)	+=
> intel_int0002_vgpio.o
>  obj-$(CONFIG_INTEL_MENLOW)		+= intel_menlow.o
>  obj-$(CONFIG_INTEL_OAKTRAIL)		+= intel_oaktrail.o
>  obj-$(CONFIG_INTEL_VBTN)		+= intel-vbtn.o
> +obj-$(CONFIG_INTEL_SPI_LPC)		+= intel_spi_lpc.o
> 
>  # Microsoft
>  obj-$(CONFIG_SURFACE3_WMI)		+= surface3-wmi.o
> diff --git a/drivers/platform/x86/intel_spi_lpc.c
> b/drivers/platform/x86/intel_spi_lpc.c
> new file mode 100644
> index 000000000000..dd573593a0f5
> --- /dev/null
> +++ b/drivers/platform/x86/intel_spi_lpc.c
> @@ -0,0 +1,183 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * SPI LPC flash platform security driver
> + *
> + * Copyright 2020 (c) Richard Hughes (richard at hughsie.com)
> + *
> + * This file is licensed under  the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/security.h>
> +#include <linux/pci.h>
> +
> +/* LPC bridge PCI config space registers */
> +#define BIOS_CNTL_REG				0xDC
> +#define BIOS_CNTL_WRITE_ENABLE_MASK		0x01
> +#define BIOS_CNTL_LOCK_ENABLE_MASK		0x02
> +#define BIOS_CNTL_WP_DISABLE_MASK		0x20
> +
> +/*
> + * This data only exists for exporting the supported PCI ids via
> + * MODULE_DEVICE_TABLE.  We do not actually register a pci_driver.
> + */
> +static const struct pci_device_id pci_tbl[] = {
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x02a4)}, /* Comet Lake SPI */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x34a4)}, /* Ice Lake-LP SPI
> */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x9c66)}, /* 8 Series SPI */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x9ce6)}, /* Wildcat Point-LP
> GSPI */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x9d2a)}, /* Sunrise Point-
> LP/SPI */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x9d4e)}, /* Sunrise Point
> LPC/eSPI */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x9da4)}, /* Cannon Point-LP
> SPI */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa140)}, /* Sunrise Point-H
> LPC */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa141)}, /* Sunrise Point-H
> LPC */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa142)}, /* Sunrise Point-H
> LPC */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa143)}, /* H110 LPC/eSPI */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa144)}, /* H170 LPC/eSPI */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa145)}, /* Z170 LPC/eSPI */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa146)}, /* Q170 LPC/eSPI */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa147)}, /* Q150 LPC/eSPI */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa148)}, /* B150 LPC/eSPI */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa149)}, /* C236 LPC/eSPI */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa14a)}, /* C232 LPC/eSPI */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa14b)}, /* Sunrise Point-H
> LPC */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa14c)}, /* Sunrise Point-H
> LPC */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa14d)}, /* QM170 LPC/eSPI */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa14e)}, /* HM170 LPC/eSPI */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa14f)}, /* Sunrise Point-H
> LPC */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa150)}, /* CM236 LPC/eSPI */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa151)}, /* Sunrise Point-H
> LPC */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa152)}, /* HM175 LPC/eSPI */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa153)}, /* QM175 LPC/eSPI */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa154)}, /* CM238 LPC/eSPI */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa155)}, /* Sunrise Point-H
> LPC */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa1c1)}, /* C621 LPC/eSPI */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa1c2)}, /* C622 LPC/eSPI */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa1c3)}, /* C624 LPC/eSPI */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa1c4)}, /* C625 LPC/eSPI */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa1c5)}, /* C626 LPC/eSPI */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa1c6)}, /* C627 LPC/eSPI */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa1c7)}, /* C628 LPC/eSPI */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa304)}, /* H370 LPC/eSPI */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa305)}, /* Z390 LPC/eSPI */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa306)}, /* Q370 LPC/eSPI */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa30c)}, /* QM370 LPC/eSPI */
> +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa324)}, /* Cannon Lake PCH

This captures a lot of old ones, but I think you're missing a few of
the other more recent ones the kernel knows about.

Tiger Lake: f13e18048bdfcea2c3e25ec691cb6b4d8ab3cf21
Canon Lake: 4b97ba73dcdc24fd968cbeb970ae57212e2c1c73
Jasper Lake: 307dd80885af7183696ab6d81d73afc7a5148df6
Comet Lake H: 5a0feb6287e37018af4cbd7754786522ae712980
Comet Lake V: 701a1676f313dbae578f31da4e06c5487c8aa7bb
Elkhart Lake: ba0d4e04a5b57ef048dbf3afd9107ae6ca353258

To echo Andy's question, I would wonder if it makes sense to just export
these attributes in securityfs directly from the intel-spi-pci driver rather
than to have another driver in platform-x86 to get the information.

Then for the eSPI cases, can it export using intel-spi-platform instead of
a large whitelist in this driver?


> SPI */
> +	{0, }
> +};
> +MODULE_DEVICE_TABLE(pci, pci_tbl);
> +
> +struct dentry *spi_dir;
> +struct dentry *spi_bioswe;
> +struct dentry *spi_ble;
> +struct dentry *spi_smm_bwp;
> +struct pci_dev *dev;
> +const u8 bios_cntl_off = BIOS_CNTL_REG;
> +
> +static ssize_t bioswe_read(struct file *filp, char __user *buf,
> +			   size_t count, loff_t *ppos)
> +{
> +	char tmp[2];
> +	u8 bios_cntl_val;
> +
> +	pci_read_config_byte(dev, bios_cntl_off, &bios_cntl_val);
> +	sprintf(tmp, "%d\n",
> +		bios_cntl_val & BIOS_CNTL_WRITE_ENABLE_MASK ? 1 : 0);
> +	return simple_read_from_buffer(buf, count, ppos, tmp,
> sizeof(tmp));
> +}
> +
> +static const struct file_operations spi_bioswe_ops = {
> +	.read  = bioswe_read,
> +};
> +
> +static ssize_t ble_read(struct file *filp, char __user *buf,
> +			size_t count, loff_t *ppos)
> +{
> +	char tmp[2];
> +	u8 bios_cntl_val;
> +
> +	pci_read_config_byte(dev, bios_cntl_off, &bios_cntl_val);
> +	sprintf(tmp, "%d\n",
> +		bios_cntl_val & BIOS_CNTL_LOCK_ENABLE_MASK ? 1 : 0);
> +	return simple_read_from_buffer(buf, count, ppos, tmp,
> sizeof(tmp));
> +}
> +
> +static const struct file_operations spi_ble_ops = {
> +	.read  = ble_read,
> +};
> +
> +static ssize_t smm_bwp_read(struct file *filp, char __user *buf,
> +			    size_t count, loff_t *ppos)
> +{
> +	char tmp[2];
> +	u8 bios_cntl_val;
> +
> +	pci_read_config_byte(dev, bios_cntl_off, &bios_cntl_val);
> +	sprintf(tmp, "%d\n",
> +		bios_cntl_val & BIOS_CNTL_WP_DISABLE_MASK ? 1 : 0);
> +	return simple_read_from_buffer(buf, count, ppos, tmp,
> sizeof(tmp));
> +}
> +
> +static const struct file_operations spi_smm_bwp_ops = {
> +	.read  = smm_bwp_read,
> +};
> +
> +static int __init mod_init(void)
> +{
> +	int i;
> +
> +	/* Find SPI Controller */
> +	for (i = 0; !dev && pci_tbl[i].vendor; ++i)
> +		dev = pci_get_device(pci_tbl[i].vendor,
> +				     pci_tbl[i].device, NULL);
> +	if (!dev)
> +		return -ENODEV;
> +
> +	spi_dir = securityfs_create_dir("spi", NULL);
> +	if (IS_ERR(spi_dir))
> +		return -1;
> +
> +	spi_bioswe =
> +	    securityfs_create_file("bioswe",
> +				   0600, spi_dir, NULL,
> +				   &spi_bioswe_ops);
> +	if (IS_ERR(spi_bioswe))
> +		goto out;
> +	spi_ble =
> +	    securityfs_create_file("ble",
> +				   0600, spi_dir, NULL,
> +				   &spi_ble_ops);
> +	if (IS_ERR(spi_ble))
> +		goto out;
> +	spi_smm_bwp =
> +	    securityfs_create_file("smm_bwp",
> +				   0600, spi_dir, NULL,
> +				   &spi_smm_bwp_ops);
> +	if (IS_ERR(spi_smm_bwp))
> +		goto out;
> +
> +	return 0;
> +out:
> +	securityfs_remove(spi_bioswe);
> +	securityfs_remove(spi_ble);
> +	securityfs_remove(spi_smm_bwp);
> +	securityfs_remove(spi_dir);
> +	return -1;
> +}
> +
> +static void __exit mod_exit(void)
> +{
> +	securityfs_remove(spi_bioswe);
> +	securityfs_remove(spi_ble);
> +	securityfs_remove(spi_smm_bwp);
> +	securityfs_remove(spi_dir);
> +}
> +
> +module_init(mod_init);
> +module_exit(mod_exit);
> +
> +MODULE_DESCRIPTION("SPI LPC flash platform security driver");
> +MODULE_AUTHOR("Richard Hughes <richard at hughsie.com>");
> +MODULE_LICENSE("GPL");
> 




More information about the Linux-security-module-archive mailing list