Skip to content

Commit b057e2f

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 <lukas@wunner.de>
1 parent 3f887bb commit b057e2f

File tree

9 files changed

+113
-0
lines changed

9 files changed

+113
-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 <lukas@wunner.de>
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
36+
obj-$(CONFIG_PCI_CMA_SYSFS) += cma-sysfs.o
3637

3738
# Endpoint library must be initialized before its users
3839
obj-$(CONFIG_PCI_ENDPOINT) += endpoint/

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: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ void pci_cma_init(struct pci_dev *pdev)
6262
pdev->spdm_state = spdm_create(&pdev->dev, spdm_doe_transport, doe,
6363
PCI_DOE_MAX_PAYLOAD, cma_keyring);
6464
if (!pdev->spdm_state) {
65+
pdev->cma_init_failed = true;
6566
return;
6667
}
6768

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
@@ -320,6 +320,7 @@ static inline void pci_doe_disconnected(struct pci_dev *pdev) { }
320320
void pci_cma_init(struct pci_dev *pdev);
321321
void pci_cma_destroy(struct pci_dev *pdev);
322322
int pci_cma_reauthenticate(struct pci_dev *pdev);
323+
extern const struct attribute_group pci_cma_attr_group;
323324
#else
324325
static inline void pci_cma_init(struct pci_dev *pdev) { }
325326
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)