Skip to content

Commit 2022eb8

Browse files
committed
PCI/CMA: Expose in sysfs whether devices are authenticated
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. 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. Signed-off-by: Lukas Wunner <[email protected]>
1 parent 6ad7b56 commit 2022eb8

File tree

9 files changed

+114
-0
lines changed

9 files changed

+114
-0
lines changed

Documentation/ABI/testing/sysfs-bus-pci

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,3 +500,30 @@ Description:
500500
console drivers from the device. Raw users of pci-sysfs
501501
resourceN attributes must be terminated prior to resizing.
502502
Success of the resizing operation is not guaranteed.
503+
504+
What: /sys/bus/pci/devices/.../authenticated
505+
Date: June 2023
506+
Contact: Lukas Wunner <[email protected]>
507+
Description:
508+
This file contains 1 if the device authenticated successfully
509+
with CMA-SPDM (PCIe r6.1 sec 6.31). It contains 0 if the
510+
device failed authentication (and may thus be malicious).
511+
512+
Writing anything to this file causes reauthentication.
513+
That may be opportune after updating the CMA keyring.
514+
515+
The file is not visible if authentication is unsupported
516+
by the device.
517+
518+
If the kernel could not determine whether authentication is
519+
supported because memory was low or DOE communication with
520+
the device was not working, the file is visible but accessing
521+
it fails with error code ENOTTY.
522+
523+
This prevents downgrade attacks where an attacker consumes
524+
memory or disturbs DOE communication in order to create the
525+
appearance that a device does not support authentication.
526+
527+
The reason why authentication support could not be determined
528+
is apparent from "dmesg". To probe for authentication support
529+
again, exercise the "remove" and "rescan" attributes.

drivers/pci/Kconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ config PCI_CMA
129129
A PCI DOE mailbox is used as transport for DMTF SPDM based
130130
attestation, measurement and secure channel establishment.
131131

132+
config PCI_CMA_SYSFS
133+
def_bool PCI_CMA && SYSFS
134+
132135
config PCI_DOE
133136
bool
134137

drivers/pci/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen-pcifront.o
3333
obj-$(CONFIG_VGA_ARB) += vgaarb.o
3434
obj-$(CONFIG_PCI_DOE) += doe.o
3535
obj-$(CONFIG_PCI_CMA) += cma.o cma-x509.o cma.asn1.o
36+
obj-$(CONFIG_PCI_CMA_SYSFS) += cma-sysfs.o
3637

3738
$(obj)/cma-x509.o: $(obj)/cma.asn1.h
3839
$(obj)/cma.asn1.o: $(obj)/cma.asn1.c $(obj)/cma.asn1.h

drivers/pci/cma-sysfs.c

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Component Measurement and Authentication (CMA-SPDM, PCIe r6.1 sec 6.31)
4+
*
5+
* Copyright (C) 2023 Intel Corporation
6+
*/
7+
8+
#include <linux/pci.h>
9+
#include <linux/sysfs.h>
10+
11+
#include "pci.h"
12+
13+
static ssize_t authenticated_store(struct device *dev,
14+
struct device_attribute *attr,
15+
const char *buf, size_t count)
16+
{
17+
struct pci_dev *pdev = to_pci_dev(dev);
18+
ssize_t rc;
19+
20+
if (!pdev->cma_capable &&
21+
(pdev->cma_init_failed || pdev->doe_init_failed))
22+
return -ENOTTY;
23+
24+
rc = pci_cma_reauthenticate(pdev);
25+
if (rc)
26+
return rc;
27+
28+
return count;
29+
}
30+
31+
static ssize_t authenticated_show(struct device *dev,
32+
struct device_attribute *attr, char *buf)
33+
{
34+
struct pci_dev *pdev = to_pci_dev(dev);
35+
36+
if (!pdev->cma_capable &&
37+
(pdev->cma_init_failed || pdev->doe_init_failed))
38+
return -ENOTTY;
39+
40+
return sysfs_emit(buf, "%u\n", test_bit(PCI_CMA_AUTHENTICATED,
41+
&pdev->priv_flags));
42+
}
43+
static DEVICE_ATTR_RW(authenticated);
44+
45+
static struct attribute *pci_cma_attrs[] = {
46+
&dev_attr_authenticated.attr,
47+
NULL
48+
};
49+
50+
static umode_t pci_cma_attrs_are_visible(struct kobject *kobj,
51+
struct attribute *a, int n)
52+
{
53+
struct device *dev = kobj_to_dev(kobj);
54+
struct pci_dev *pdev = to_pci_dev(dev);
55+
56+
/*
57+
* If CMA or DOE initialization failed, CMA attributes must be visible
58+
* and return an error on access. This prevents downgrade attacks
59+
* where an attacker disturbs memory allocation or DOE communication
60+
* in order to create the appearance that CMA is unsupported.
61+
* The attacker may achieve that by simply hogging memory.
62+
*/
63+
if (!pdev->cma_capable &&
64+
!pdev->cma_init_failed && !pdev->doe_init_failed)
65+
return 0;
66+
67+
return a->mode;
68+
}
69+
70+
const struct attribute_group pci_cma_attr_group = {
71+
.attrs = pci_cma_attrs,
72+
.is_visible = pci_cma_attrs_are_visible,
73+
};

drivers/pci/cma.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ void pci_cma_init(struct pci_dev *pdev)
5252
int rc;
5353

5454
if (!pci_cma_keyring) {
55+
pdev->cma_init_failed = true;
5556
return;
5657
}
5758

@@ -67,6 +68,7 @@ void pci_cma_init(struct pci_dev *pdev)
6768
PCI_DOE_MAX_PAYLOAD, pci_cma_keyring,
6869
pci_cma_validate);
6970
if (!pdev->spdm_state) {
71+
pdev->cma_init_failed = true;
7072
return;
7173
}
7274

drivers/pci/doe.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,13 +686,15 @@ void pci_doe_init(struct pci_dev *pdev)
686686
PCI_EXT_CAP_ID_DOE))) {
687687
doe_mb = pci_doe_create_mb(pdev, offset);
688688
if (IS_ERR(doe_mb)) {
689+
pdev->doe_init_failed = true;
689690
pci_err(pdev, "[%x] failed to create mailbox: %ld\n",
690691
offset, PTR_ERR(doe_mb));
691692
continue;
692693
}
693694

694695
rc = xa_insert(&pdev->doe_mbs, offset, doe_mb, GFP_KERNEL);
695696
if (rc) {
697+
pdev->doe_init_failed = true;
696698
pci_err(pdev, "[%x] failed to insert mailbox: %d\n",
697699
offset, rc);
698700
pci_doe_destroy_mb(doe_mb);

drivers/pci/pci-sysfs.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1651,6 +1651,9 @@ static const struct attribute_group *pci_dev_attr_groups[] = {
16511651
#endif
16521652
#ifdef CONFIG_PCIEASPM
16531653
&aspm_ctrl_attr_group,
1654+
#endif
1655+
#ifdef CONFIG_PCI_CMA_SYSFS
1656+
&pci_cma_attr_group,
16541657
#endif
16551658
NULL,
16561659
};

drivers/pci/pci.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@ void pci_cma_destroy(struct pci_dev *pdev);
322322
int pci_cma_reauthenticate(struct pci_dev *pdev);
323323
struct x509_certificate;
324324
int pci_cma_validate(struct device *dev, struct x509_certificate *leaf_cert);
325+
extern const struct attribute_group pci_cma_attr_group;
325326
#else
326327
static inline void pci_cma_init(struct pci_dev *pdev) { }
327328
static inline void pci_cma_destroy(struct pci_dev *pdev) { }

include/linux/pci.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,10 +515,12 @@ struct pci_dev {
515515
#endif
516516
#ifdef CONFIG_PCI_DOE
517517
struct xarray doe_mbs; /* Data Object Exchange mailboxes */
518+
unsigned int doe_init_failed:1;
518519
#endif
519520
#ifdef CONFIG_PCI_CMA
520521
struct spdm_state *spdm_state;
521522
unsigned int cma_capable:1;
523+
unsigned int cma_init_failed:1;
522524
#endif
523525
u16 acs_cap; /* ACS Capability offset */
524526
phys_addr_t rom; /* Physical address if not from BAR */

0 commit comments

Comments
 (0)