On Thu, 28 Sep 2023, Lukas Wunner wrote: > The PCI core has just been amended to authenticate CMA-capable devices > on enumeration and store the result in an "authenticated" bit in struct > pci_dev->spdm_state. > > Expose the bit to user space through an eponymous sysfs attribute. > > Allow user space to trigger reauthentication (e.g. after it has updated > the CMA keyring) by writing to the sysfs attribute. > > Subject to further discussion, a future commit might add a user-defined > policy to forbid driver binding to devices which failed authentication, > similar to the "authorized" attribute for USB. > > Alternatively, authentication success might be signaled to user space > through a uevent, whereupon it may bind a (blacklisted) driver. > A uevent signaling authentication failure might similarly cause user > space to unbind or outright remove the potentially malicious device. > > Traffic from devices which failed authentication could also be filtered > through ACS I/O Request Blocking Enable (PCIe r6.1 sec 7.7.11.3) or > through Link Disable (PCIe r6.1 sec 7.5.3.7). Unlike an IOMMU, that > will not only protect the host, but also prevent malicious peer-to-peer > traffic to other devices. IMO it would be good to mention the DOE stuff also in the changelog (it's currently only in the sysfs docs). -- i. > Signed-off-by: Lukas Wunner <lukas@xxxxxxxxx> > --- > Documentation/ABI/testing/sysfs-bus-pci | 27 +++++++++ > drivers/pci/Kconfig | 3 + > drivers/pci/Makefile | 1 + > drivers/pci/cma-sysfs.c | 73 +++++++++++++++++++++++++ > drivers/pci/cma.c | 2 + > drivers/pci/doe.c | 2 + > drivers/pci/pci-sysfs.c | 3 + > drivers/pci/pci.h | 1 + > include/linux/pci.h | 2 + > 9 files changed, 114 insertions(+) > create mode 100644 drivers/pci/cma-sysfs.c > > diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci > index ecf47559f495..2ea9b8deffcc 100644 > --- a/Documentation/ABI/testing/sysfs-bus-pci > +++ b/Documentation/ABI/testing/sysfs-bus-pci > @@ -500,3 +500,30 @@ Description: > console drivers from the device. Raw users of pci-sysfs > resourceN attributes must be terminated prior to resizing. > Success of the resizing operation is not guaranteed. > + > +What: /sys/bus/pci/devices/.../authenticated > +Date: September 2023 > +Contact: Lukas Wunner <lukas@xxxxxxxxx> > +Description: > + This file contains 1 if the device authenticated successfully > + with CMA-SPDM (PCIe r6.1 sec 6.31). It contains 0 if the > + device failed authentication (and may thus be malicious). > + > + Writing anything to this file causes reauthentication. > + That may be opportune after updating the .cma keyring. > + > + The file is not visible if authentication is unsupported > + by the device. > + > + If the kernel could not determine whether authentication is > + supported because memory was low or DOE communication with > + the device was not working, the file is visible but accessing > + it fails with error code ENOTTY. > + > + This prevents downgrade attacks where an attacker consumes > + memory or disturbs DOE communication in order to create the > + appearance that a device does not support authentication. > + > + The reason why authentication support could not be determined > + is apparent from "dmesg". To probe for authentication support > + again, exercise the "remove" and "rescan" attributes. > diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig > index c9aa5253ac1f..51df3be3438e 100644 > --- a/drivers/pci/Kconfig > +++ b/drivers/pci/Kconfig > @@ -129,6 +129,9 @@ config PCI_CMA > A PCI DOE mailbox is used as transport for DMTF SPDM based > attestation, measurement and secure channel establishment. > > +config PCI_CMA_SYSFS > + def_bool PCI_CMA && SYSFS > + > config PCI_DOE > bool > > diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile > index a18812b8832b..612ae724cd2d 100644 > --- a/drivers/pci/Makefile > +++ b/drivers/pci/Makefile > @@ -35,6 +35,7 @@ obj-$(CONFIG_PCI_DOE) += doe.o > obj-$(CONFIG_PCI_DYNAMIC_OF_NODES) += of_property.o > > obj-$(CONFIG_PCI_CMA) += cma.o cma-x509.o cma.asn1.o > +obj-$(CONFIG_PCI_CMA_SYSFS) += cma-sysfs.o > $(obj)/cma-x509.o: $(obj)/cma.asn1.h > $(obj)/cma.asn1.o: $(obj)/cma.asn1.c $(obj)/cma.asn1.h > > diff --git a/drivers/pci/cma-sysfs.c b/drivers/pci/cma-sysfs.c > new file mode 100644 > index 000000000000..b2d45f96601a > --- /dev/null > +++ b/drivers/pci/cma-sysfs.c > @@ -0,0 +1,73 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Component Measurement and Authentication (CMA-SPDM, PCIe r6.1 sec 6.31) > + * > + * Copyright (C) 2023 Intel Corporation > + */ > + > +#include <linux/pci.h> > +#include <linux/spdm.h> > +#include <linux/sysfs.h> > + > +#include "pci.h" > + > +static ssize_t authenticated_store(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t count) > +{ > + struct pci_dev *pdev = to_pci_dev(dev); > + ssize_t rc; > + > + if (!pdev->cma_capable && > + (pdev->cma_init_failed || pdev->doe_init_failed)) > + return -ENOTTY; > + > + rc = pci_cma_reauthenticate(pdev); > + if (rc) > + return rc; > + > + return count; > +} > + > +static ssize_t authenticated_show(struct device *dev, > + struct device_attribute *attr, char *buf) > +{ > + struct pci_dev *pdev = to_pci_dev(dev); > + > + if (!pdev->cma_capable && > + (pdev->cma_init_failed || pdev->doe_init_failed)) > + return -ENOTTY; > + > + return sysfs_emit(buf, "%u\n", spdm_authenticated(pdev->spdm_state)); > +} > +static DEVICE_ATTR_RW(authenticated); > + > +static struct attribute *pci_cma_attrs[] = { > + &dev_attr_authenticated.attr, > + NULL > +}; > + > +static umode_t pci_cma_attrs_are_visible(struct kobject *kobj, > + struct attribute *a, int n) > +{ > + struct device *dev = kobj_to_dev(kobj); > + struct pci_dev *pdev = to_pci_dev(dev); > + > + /* > + * If CMA or DOE initialization failed, CMA attributes must be visible > + * and return an error on access. This prevents downgrade attacks > + * where an attacker disturbs memory allocation or DOE communication > + * in order to create the appearance that CMA is unsupported. > + * The attacker may achieve that by simply hogging memory. > + */ > + if (!pdev->cma_capable && > + !pdev->cma_init_failed && !pdev->doe_init_failed) > + return 0; > + > + return a->mode; > +} > + > +const struct attribute_group pci_cma_attr_group = { > + .attrs = pci_cma_attrs, > + .is_visible = pci_cma_attrs_are_visible, > +}; > diff --git a/drivers/pci/cma.c b/drivers/pci/cma.c > index 89d23fdc37ec..c539ad85a28f 100644 > --- a/drivers/pci/cma.c > +++ b/drivers/pci/cma.c > @@ -52,6 +52,7 @@ void pci_cma_init(struct pci_dev *pdev) > int rc; > > if (!pci_cma_keyring) { > + pdev->cma_init_failed = true; > return; > } > > @@ -67,6 +68,7 @@ void pci_cma_init(struct pci_dev *pdev) > PCI_DOE_MAX_PAYLOAD, pci_cma_keyring, > pci_cma_validate); > if (!pdev->spdm_state) { > + pdev->cma_init_failed = true; > return; > } > > diff --git a/drivers/pci/doe.c b/drivers/pci/doe.c > index 79f0336eb0c3..fabbda68edac 100644 > --- a/drivers/pci/doe.c > +++ b/drivers/pci/doe.c > @@ -686,6 +686,7 @@ void pci_doe_init(struct pci_dev *pdev) > PCI_EXT_CAP_ID_DOE))) { > doe_mb = pci_doe_create_mb(pdev, offset); > if (IS_ERR(doe_mb)) { > + pdev->doe_init_failed = true; > pci_err(pdev, "[%x] failed to create mailbox: %ld\n", > offset, PTR_ERR(doe_mb)); > continue; > @@ -693,6 +694,7 @@ void pci_doe_init(struct pci_dev *pdev) > > rc = xa_insert(&pdev->doe_mbs, offset, doe_mb, GFP_KERNEL); > if (rc) { > + pdev->doe_init_failed = true; > pci_err(pdev, "[%x] failed to insert mailbox: %d\n", > offset, rc); > pci_doe_destroy_mb(doe_mb); > diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c > index d9eede2dbc0e..7024e08e1b9a 100644 > --- a/drivers/pci/pci-sysfs.c > +++ b/drivers/pci/pci-sysfs.c > @@ -1655,6 +1655,9 @@ static const struct attribute_group *pci_dev_attr_groups[] = { > #endif > #ifdef CONFIG_PCIEASPM > &aspm_ctrl_attr_group, > +#endif > +#ifdef CONFIG_PCI_CMA_SYSFS > + &pci_cma_attr_group, > #endif > NULL, > }; > diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h > index 71092ccf4fbd..d80cc06be0cc 100644 > --- a/drivers/pci/pci.h > +++ b/drivers/pci/pci.h > @@ -328,6 +328,7 @@ void pci_cma_destroy(struct pci_dev *pdev); > int pci_cma_reauthenticate(struct pci_dev *pdev); > struct x509_certificate; > int pci_cma_validate(struct device *dev, struct x509_certificate *leaf_cert); > +extern const struct attribute_group pci_cma_attr_group; > #else > static inline void pci_cma_init(struct pci_dev *pdev) { } > static inline void pci_cma_destroy(struct pci_dev *pdev) { } > diff --git a/include/linux/pci.h b/include/linux/pci.h > index 2bc11d8b567e..2c5fde81bb85 100644 > --- a/include/linux/pci.h > +++ b/include/linux/pci.h > @@ -516,10 +516,12 @@ struct pci_dev { > #endif > #ifdef CONFIG_PCI_DOE > struct xarray doe_mbs; /* Data Object Exchange mailboxes */ > + unsigned int doe_init_failed:1; > #endif > #ifdef CONFIG_PCI_CMA > struct spdm_state *spdm_state; /* Security Protocol and Data Model */ > unsigned int cma_capable:1; /* Authentication supported */ > + unsigned int cma_init_failed:1; > #endif > u16 acs_cap; /* ACS Capability offset */ > phys_addr_t rom; /* Physical address if not from BAR */ >