* [PATCH 0/6] platform/x86/intel: Harden PMT discovery against malformed device data
@ 2026-10-31 1:29 David E. Box
2026-10-31 1:29 ` [PATCH 1/6] platform/x86/intel/pmt/discovery: Bound attr_size against feature_table capacity David E. Box
` (5 more replies)
0 siblings, 6 replies; 7+ messages in thread
From: David E. Box @ 2026-10-31 1:29 UTC (permalink / raw)
To: Hans de Goede, Ilpo Järvinen, platform-driver-x86
Cc: David E. Box, linux-kernel
The Intel VSEC and PMT drivers build kernel copies and MMIO mappings from
discovery data read from the device:
1. DVSEC/VSEC config space,
2. the PMT discovery tables,
3. the feature tables pointed to from the discovery tables.
Several of these fields are used without being validated against the
buffers or BARs they describe, so a device reporting out-of-spec values can
make the drivers write past kernel structures, index past arrays, or map
MMIO outside of their own BARs.
These issues were found during an internal AI-assisted review of the PMT
codebase. An LLM was also used to draft the fixes and to build the test
tooling described below. Each finding was verified against the code, and
each patch was reviewed and tested before posting.
Patches 1-3 fix memory safety issues in the PMT discovery driver:
1. attr_size from the feature header sets the length of a
memcpy_fromio() into the fixed-size struct feature_table. The only
check was against the MMIO source size, which is also device
controlled, allowing an overflow of up to 1020 bytes. Bound it by
the destination, and skip the feature rather than failing probe.
2. Replace a WARN() on a bad table size with dev_err_probe(), since
malformed device data should not panic panic_on_warn systems.
3. The feature id is used as a BIT() shift and as an index into
pmt_feature_names[] before it is validated.
Patches 4-6 validate the MMIO ranges built from discovery data against
the BAR they claim to be in:
4. In the vsec driver, reject a DVSEC/VSEC table BAR index (tbir) that
is out of range or not a memory BAR, and discovery tables that
extend past the end of their BAR. The discovery BAR is recorded and
a helper is exported so the PMT drivers can apply the same check to
the ranges they build.
5. In the PMT discovery driver, check feature table resources against
the discovery BAR before mapping them.
6. In the PMT class driver, check telemetry and crashlog regions before
they are mapped, and mmappable by userspace, including ACCESS_BARID
regions whose BAR index can name the nonexistent BARs 6 and 7.
All patches carry Fixes tags. Patches 5 and 6 depend on the helper added
in patch 4.
Testing:
The malformed-data cases were tested on an emulated OOBMSM-style PMT device
in QEMU, extended with fault injection to corrupt one discovery field at a
time. With KASAN and UBSAN enabled, v7.3 showed each bug:
- an oops from the attr_size overflow corrupting struct feature (1),
- a WARN on a short table (2),
- a shift-out-of-bounds from the unvalidated feature id (3),
and discovery tables, feature tables and telemetry regions mapped
outside the BAR (4-6).
With the series, every case was rejected with its message and
no warnings, sanitizer reports or out-of-BAR mappings.
For regressions, PMT state with and without the series was compared on
- Diamond Rapids (OOBMSM with enhanaced discovery),
- Tiger Lake (which uses early client flag, shifted table offset)
- Nova Lake with a Battlemage card (VSEC data registered by xe).
The devices, telemetry and crashlog regions, and features were identical.
All regions read and mmapped in full and the discovery KUnit test passed.
The runtime testing above was done with the series on v7.3.
David E. Box (6):
platform/x86/intel/pmt/discovery: Bound attr_size against
feature_table capacity
platform/x86/intel/pmt/discovery: Avoid WARN for malformed tables
platform/x86/intel/pmt/discovery: Validate feature id before use
platform/x86/intel/vsec: Validate discovery table bounds against the
BAR
platform/x86/intel/pmt/discovery: Validate feature table against the
BAR
platform/x86/intel/pmt: Validate telemetry regions against the BAR
drivers/platform/x86/intel/pmt/class.c | 21 +++++
drivers/platform/x86/intel/pmt/discovery.c | 36 +++++++--
drivers/platform/x86/intel/vsec.c | 93 ++++++++++++++++++++--
include/linux/intel_vsec.h | 8 ++
4 files changed, 147 insertions(+), 11 deletions(-)
base-commit: c339f4010dea8b0d754f84ace70cd1b089878ef8
--
2.43.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 1/6] platform/x86/intel/pmt/discovery: Bound attr_size against feature_table capacity
2026-10-31 1:29 [PATCH 0/6] platform/x86/intel: Harden PMT discovery against malformed device data David E. Box
@ 2026-10-31 1:29 ` David E. Box
2026-10-31 1:29 ` [PATCH 2/6] platform/x86/intel/pmt/discovery: Avoid WARN for malformed tables David E. Box
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: David E. Box @ 2026-10-31 1:29 UTC (permalink / raw)
To: Hans de Goede, Ilpo Järvinen, platform-driver-x86
Cc: David E. Box, linux-kernel
The feature header's attr_size field is fully device-controlled (8 bits,
up to 255) and is used to compute the length passed to memcpy_fromio()
when copying attribute fields into struct feature_table. The only
existing bounds check validates this length against the mapped MMIO
source resource (res_size), which is itself sized from another
device-controlled field (disc_tbl->size) and has no relationship to
the fixed destination struct's actual capacity.
A malicious or compromised PMT endpoint can report a large enough
disc_tbl->size (to satisfy the source-side check) together with
attr_size = 0xff, causing memcpy_fromio() to write up to 1020 bytes
into struct feature_table's 16-byte caps/union region, corrupting
adjacent fields (guids, kobj, priv, list, attr_group, id) and
neighboring heap allocations.
Check the attribute payload size against the space from the end of the
header to the end of the union before the copy occurs. Skip a feature
that fails the check rather than failing probe, so one malformed table
does not take down the features that were described correctly.
Fixes: d9a078809356 ("platform/x86/intel/pmt: Add PMT Discovery driver")
Assisted-by: LLM
Signed-off-by: David E. Box <david.e.box@linux.intel.com>
---
drivers/platform/x86/intel/pmt/discovery.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/drivers/platform/x86/intel/pmt/discovery.c b/drivers/platform/x86/intel/pmt/discovery.c
index f4203d240f54..47a4def6e6b9 100644
--- a/drivers/platform/x86/intel/pmt/discovery.c
+++ b/drivers/platform/x86/intel/pmt/discovery.c
@@ -24,6 +24,7 @@
#include <linux/overflow.h>
#include <linux/pci.h>
#include <linux/slab.h>
+#include <linux/stddef.h>
#include <linux/string_choices.h>
#include <linux/sysfs.h>
#include <linux/types.h>
@@ -38,6 +39,9 @@
#define DT_TBIR GENMASK(2, 0)
#define FEAT_ATTR_SIZE(x) ((x) * sizeof(u32))
#define PMT_GUID_SIZE(x) ((x) * sizeof(u32))
+/* Space for attribute fields between the header and the guids pointer */
+#define FEAT_ATTR_CAPACITY (offsetofend(struct feature_table, rmid) - \
+ sizeof(struct feature_header))
#define PMT_ACCESS_TYPE_RSVD 0xF
#define SKIP_FEATURE 1
@@ -420,6 +424,18 @@ pmt_feature_get_feature_table(struct pmt_features_priv *priv,
header = &feat_tbl->header;
memcpy_fromio(header, feat_offset, sizeof(*header));
+ /*
+ * The attribute fields are copied into the fixed caps and union
+ * fields following the header. Skip, rather than fail on, a feature
+ * whose attributes don't fit so the remaining features still probe.
+ */
+ if (FEAT_ATTR_SIZE(header->attr_size) > FEAT_ATTR_CAPACITY) {
+ dev_warn(priv->dev, "Skipping feature %s: bad attr_size %u\n",
+ pmt_feature_names[feature->id], header->attr_size);
+ devm_iounmap(priv->dev, feat_base);
+ return SKIP_FEATURE;
+ }
+
/* Validate fields fit within mapped resource */
size = sizeof(*header) + FEAT_ATTR_SIZE(header->attr_size) +
PMT_GUID_SIZE(header->num_guids);
--
2.43.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 2/6] platform/x86/intel/pmt/discovery: Avoid WARN for malformed tables
2026-10-31 1:29 [PATCH 0/6] platform/x86/intel: Harden PMT discovery against malformed device data David E. Box
2026-10-31 1:29 ` [PATCH 1/6] platform/x86/intel/pmt/discovery: Bound attr_size against feature_table capacity David E. Box
@ 2026-10-31 1:29 ` David E. Box
2026-10-31 1:29 ` [PATCH 3/6] platform/x86/intel/pmt/discovery: Validate feature id before use David E. Box
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: David E. Box @ 2026-10-31 1:29 UTC (permalink / raw)
To: Hans de Goede, Ilpo Järvinen, platform-driver-x86
Cc: David E. Box, linux-kernel
The feature table contents are supplied by the device, so an invalid table
size is an expected probe error. WARN() is not appropriate for malformed
device data because systems with panic_on_warn set will panic.
Use dev_err_probe() instead. This preserves the diagnostic and -EINVAL
return while being a better fit for the probe failure path.
Fixes: d9a078809356 ("platform/x86/intel/pmt: Add PMT Discovery driver")
Signed-off-by: David E. Box <david.e.box@linux.intel.com>
---
drivers/platform/x86/intel/pmt/discovery.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/platform/x86/intel/pmt/discovery.c b/drivers/platform/x86/intel/pmt/discovery.c
index 47a4def6e6b9..143d2b3be562 100644
--- a/drivers/platform/x86/intel/pmt/discovery.c
+++ b/drivers/platform/x86/intel/pmt/discovery.c
@@ -440,8 +440,9 @@ pmt_feature_get_feature_table(struct pmt_features_priv *priv,
size = sizeof(*header) + FEAT_ATTR_SIZE(header->attr_size) +
PMT_GUID_SIZE(header->num_guids);
res_size = resource_size(&res);
- if (WARN(size > res_size, "Bad table size %zu > %pa", size, &res_size))
- return -EINVAL;
+ if (size > res_size)
+ return dev_err_probe(priv->dev, -EINVAL,
+ "Bad table size %zu > %pa\n", size, &res_size);
/* Get the feature attributes, including capability fields */
tbl_offset += sizeof(*header);
--
2.43.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 3/6] platform/x86/intel/pmt/discovery: Validate feature id before use
2026-10-31 1:29 [PATCH 0/6] platform/x86/intel: Harden PMT discovery against malformed device data David E. Box
2026-10-31 1:29 ` [PATCH 1/6] platform/x86/intel/pmt/discovery: Bound attr_size against feature_table capacity David E. Box
2026-10-31 1:29 ` [PATCH 2/6] platform/x86/intel/pmt/discovery: Avoid WARN for malformed tables David E. Box
@ 2026-10-31 1:29 ` David E. Box
2026-10-31 1:29 ` [PATCH 4/6] platform/x86/intel/vsec: Validate discovery table bounds against the BAR David E. Box
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: David E. Box @ 2026-10-31 1:29 UTC (permalink / raw)
To: Hans de Goede, Ilpo Järvinen, platform-driver-x86
Cc: David E. Box, linux-kernel
pmt_feature_get_disc_table() reads the feature id from device MMIO and
uses it in the duplicate check, as BIT(disc_tbl->id) and as an index
into pmt_feature_names[], before pmt_feature_id_is_valid() is called.
The id is a 32-bit field, so a malformed table can supply a shift count of
BITS_PER_LONG or more, which is undefined. Validate the id before it is
used.
Fixes: d9a078809356 ("platform/x86/intel/pmt: Add PMT Discovery driver")
Signed-off-by: David E. Box <david.e.box@linux.intel.com>
---
drivers/platform/x86/intel/pmt/discovery.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/platform/x86/intel/pmt/discovery.c b/drivers/platform/x86/intel/pmt/discovery.c
index 143d2b3be562..24ba7211e59d 100644
--- a/drivers/platform/x86/intel/pmt/discovery.c
+++ b/drivers/platform/x86/intel/pmt/discovery.c
@@ -348,6 +348,10 @@ pmt_feature_get_disc_table(struct pmt_features_priv *priv,
devm_iounmap(priv->dev, disc_base);
+ /* The id is used as a bit position and array index below */
+ if (!pmt_feature_id_is_valid(disc_tbl->id))
+ return SKIP_FEATURE;
+
if (priv->mask & BIT(disc_tbl->id))
return dev_err_probe(priv->dev, -EINVAL, "Duplicate feature: %s\n",
pmt_feature_names[disc_tbl->id]);
@@ -363,9 +367,6 @@ pmt_feature_get_disc_table(struct pmt_features_priv *priv,
if (disc_tbl->version > MAX_FEATURE_VERSION)
return SKIP_FEATURE;
- if (!pmt_feature_id_is_valid(disc_tbl->id))
- return SKIP_FEATURE;
-
priv->mask |= BIT(disc_tbl->id);
return 0;
--
2.43.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 4/6] platform/x86/intel/vsec: Validate discovery table bounds against the BAR
2026-10-31 1:29 [PATCH 0/6] platform/x86/intel: Harden PMT discovery against malformed device data David E. Box
` (2 preceding siblings ...)
2026-10-31 1:29 ` [PATCH 3/6] platform/x86/intel/pmt/discovery: Validate feature id before use David E. Box
@ 2026-10-31 1:29 ` David E. Box
2026-10-31 1:29 ` [PATCH 5/6] platform/x86/intel/pmt/discovery: Validate feature table " David E. Box
2026-10-31 1:29 ` [PATCH 6/6] platform/x86/intel/pmt: Validate telemetry regions " David E. Box
5 siblings, 0 replies; 7+ messages in thread
From: David E. Box @ 2026-10-31 1:29 UTC (permalink / raw)
To: Hans de Goede, Ilpo Järvinen, platform-driver-x86
Cc: David E. Box, linux-kernel
The DVSEC/VSEC table offset, entry size, and entry count are read from
device configuration space, but the resulting resource ranges were never
checked against the BAR they claim to reside in. A device reporting a
large offset could produce resources outside its BAR, pointing at unmapped
physical address gaps or MMIO belonging to other devices.
Additionally, INTEL_DVSEC_TABLE_BAR() masks the table register to three
bits, so tbir may be 6 or 7 even though only BARs 0-5 are valid. Those
values silently selected the ROM BAR or a bridge resource slot.
Reject headers whose tbir (bar index) is out of range or whose BAR is not a
populated memory BAR, and any discovery table resource that does not fit
within that BAR. These rejections cause the capability to not be
registered, so log them as warnings.
The PMT drivers also map ranges built from discovery data, but they only
receive the resolved discovery table resources and cannot tell which BAR
those came from. Record the discovery BAR index in struct
intel_vsec_device, along with whether the tables are BAR relative at all,
and export intel_vsec_check_bar_resource() to check a resource against a
given BAR.
Fixes: a3c8f906ed5f ("platform/x86/intel: Move intel_pmt from MFD to Auxiliary Bus")
Assisted-by: LLM
Signed-off-by: David E. Box <david.e.box@linux.intel.com>
---
drivers/platform/x86/intel/vsec.c | 93 +++++++++++++++++++++++++++++--
include/linux/intel_vsec.h | 8 +++
2 files changed, 96 insertions(+), 5 deletions(-)
diff --git a/drivers/platform/x86/intel/vsec.c b/drivers/platform/x86/intel/vsec.c
index 380d8231549f..4395663d8edd 100644
--- a/drivers/platform/x86/intel/vsec.c
+++ b/drivers/platform/x86/intel/vsec.c
@@ -104,6 +104,76 @@ static bool intel_vsec_supported(u16 id, unsigned long caps)
}
}
+/* Return the resource of a populated memory BAR, or NULL if there is none */
+static const struct resource *intel_vsec_mem_bar(struct pci_dev *pdev,
+ unsigned int bar)
+{
+ if (bar >= PCI_STD_NUM_BARS)
+ return NULL;
+
+ if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
+ return NULL;
+
+ return pci_resource_n(pdev, bar);
+}
+
+/**
+ * intel_vsec_check_bar_resource() - Check a resource lies within a PCI BAR
+ * @intel_vsec_dev: vsec device the resource was derived from
+ * @bar: index of the BAR the device places @res in
+ * @res: resource to check
+ *
+ * Discovery table locations and the tables they reference are read from the
+ * device, so ranges built from them must be checked against the BAR they
+ * claim to live in before being mapped. For a resource in the same BAR as
+ * the discovery tables, pass @intel_vsec_dev->tbir as @bar.
+ *
+ * Return: 0 if @res is within BAR @bar or the device's tables are not BAR
+ * relative, -EINVAL if @bar is not a valid memory BAR or @res is outside it.
+ */
+int intel_vsec_check_bar_resource(struct intel_vsec_device *intel_vsec_dev,
+ unsigned int bar, const struct resource *res)
+{
+ const struct resource *bar_res;
+
+ /* ACPI tables are read from _DSD, and a supplied base is not BAR relative */
+ if (!intel_vsec_dev->bar_relative)
+ return 0;
+
+ bar_res = intel_vsec_mem_bar(to_pci_dev(intel_vsec_dev->dev), bar);
+ if (!bar_res || !resource_contains(bar_res, res))
+ return -EINVAL;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(intel_vsec_check_bar_resource, "INTEL_VSEC");
+
+/*
+ * For DVSEC/VSEC discovery the table location is read from device config
+ * space. Check that it names a memory BAR the tables can be checked against.
+ */
+static int intel_vsec_check_table_bar(struct device *dev,
+ const struct intel_vsec_header *header,
+ const struct intel_vsec_platform_info *info,
+ bool *bar_relative)
+{
+ *bar_relative = false;
+
+ /* Not BAR relative: ACPI tables come from _DSD, or a base was supplied */
+ if (info->src == INTEL_VSEC_DISC_ACPI || info->base_addr || !dev_is_pci(dev))
+ return 0;
+
+ if (!intel_vsec_mem_bar(to_pci_dev(dev), header->tbir)) {
+ dev_warn(dev, "BAR %u is not a valid memory BAR for header id %d\n",
+ header->tbir, header->id);
+ return -EINVAL;
+ }
+
+ *bar_relative = true;
+
+ return 0;
+}
+
static void intel_vsec_remove_aux(void *data)
{
auxiliary_device_delete(data);
@@ -297,7 +367,8 @@ static int intel_vsec_add_dev(struct device *dev, struct intel_vsec_header *head
struct resource *tmp;
struct device *parent;
unsigned long quirks = info->quirks;
- int i;
+ bool bar_relative;
+ int i, ret;
if (info->parent)
parent = info->parent;
@@ -317,16 +388,23 @@ static int intel_vsec_add_dev(struct device *dev, struct intel_vsec_header *head
return -EINVAL;
}
+ if (quirks & VSEC_QUIRK_TABLE_SHIFT)
+ header->offset >>= TABLE_OFFSET_SHIFT;
+
+ ret = intel_vsec_check_table_bar(dev, header, info, &bar_relative);
+ if (ret)
+ return ret;
+
intel_vsec_dev = kzalloc_flex(*intel_vsec_dev, resource, header->num_entries);
if (!intel_vsec_dev)
return -ENOMEM;
intel_vsec_dev->num_resources = header->num_entries;
+ intel_vsec_dev->dev = dev;
+ intel_vsec_dev->tbir = header->tbir;
+ intel_vsec_dev->bar_relative = bar_relative;
res = intel_vsec_dev->resource;
- if (quirks & VSEC_QUIRK_TABLE_SHIFT)
- header->offset >>= TABLE_OFFSET_SHIFT;
-
/*
* The DVSEC/VSEC contains the starting offset and count for a block of
* discovery tables. Create a resource array of these tables to the
@@ -344,6 +422,12 @@ static int intel_vsec_add_dev(struct device *dev, struct intel_vsec_header *head
tmp->end = tmp->start + (header->entry_size * sizeof(u32)) - 1;
tmp->flags = IORESOURCE_MEM;
+ if (intel_vsec_check_bar_resource(intel_vsec_dev, header->tbir, tmp)) {
+ dev_warn(dev, "Discovery table %d for header id %d exceeds BAR %u\n",
+ i, header->id, header->tbir);
+ return -EINVAL;
+ }
+
/* Check resource is not in use */
if (!request_mem_region(tmp->start, resource_size(tmp), ""))
return -EBUSY;
@@ -351,7 +435,6 @@ static int intel_vsec_add_dev(struct device *dev, struct intel_vsec_header *head
release_mem_region(tmp->start, resource_size(tmp));
}
- intel_vsec_dev->dev = dev;
intel_vsec_dev->quirks = info->quirks;
intel_vsec_dev->base_addr = info->base_addr;
intel_vsec_dev->priv_data = info->priv_data;
diff --git a/include/linux/intel_vsec.h b/include/linux/intel_vsec.h
index 8686e79c4f75..feb4420617bc 100644
--- a/include/linux/intel_vsec.h
+++ b/include/linux/intel_vsec.h
@@ -160,6 +160,10 @@ struct intel_vsec_platform_info {
* @quirks: specified quirks
* @base_addr: base address of entries (if specified)
* @cap_id: the enumerated id of the vsec feature
+ * @tbir: PCI BAR index of the discovery tables. Valid only when
+ * @bar_relative is set
+ * @bar_relative: discovery tables are located in PCI BAR @tbir. Not set for
+ * ACPI discovery or a supplied base address
* @resource: PCI discovery resources (BAR windows), one per discovery
* instance. Valid only when @src == INTEL_VSEC_DISC_PCI
*/
@@ -176,6 +180,8 @@ struct intel_vsec_device {
unsigned long quirks;
u64 base_addr;
unsigned long cap_id;
+ u8 tbir;
+ bool bar_relative;
struct resource resource[] __counted_by(num_resources);
};
@@ -219,6 +225,8 @@ struct pmt_feature_group {
int intel_vsec_add_aux(struct device *parent,
struct intel_vsec_device *intel_vsec_dev,
const char *name);
+int intel_vsec_check_bar_resource(struct intel_vsec_device *intel_vsec_dev,
+ unsigned int bar, const struct resource *res);
static inline struct intel_vsec_device *dev_to_ivdev(struct device *dev)
{
--
2.43.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 5/6] platform/x86/intel/pmt/discovery: Validate feature table against the BAR
2026-10-31 1:29 [PATCH 0/6] platform/x86/intel: Harden PMT discovery against malformed device data David E. Box
` (3 preceding siblings ...)
2026-10-31 1:29 ` [PATCH 4/6] platform/x86/intel/vsec: Validate discovery table bounds against the BAR David E. Box
@ 2026-10-31 1:29 ` David E. Box
2026-10-31 1:29 ` [PATCH 6/6] platform/x86/intel/pmt: Validate telemetry regions " David E. Box
5 siblings, 0 replies; 7+ messages in thread
From: David E. Box @ 2026-10-31 1:29 UTC (permalink / raw)
To: Hans de Goede, Ilpo Järvinen, platform-driver-x86
Cc: David E. Box, linux-kernel
For ACCESS_LOCAL features, the feature table resource is built from the
discovery table's offset and size fields, which are both read from the
device. The offset is a 32-bit value applied past the end of the discovery
region and the size is a 16-bit dword count, yet the resulting range is
never checked against the BAR the discovery table lives in. A malicious or
broken device can therefore direct the driver to map and read MMIO outside
of its BAR.
Use intel_vsec_check_bar_resource() to reject feature tables that do not
fit within the discovery BAR recorded by the vsec driver before mapping
them.
Fixes: d9a078809356 ("platform/x86/intel/pmt: Add PMT Discovery driver")
Signed-off-by: David E. Box <david.e.box@linux.intel.com>
---
drivers/platform/x86/intel/pmt/discovery.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/platform/x86/intel/pmt/discovery.c b/drivers/platform/x86/intel/pmt/discovery.c
index 24ba7211e59d..6717121dc6f2 100644
--- a/drivers/platform/x86/intel/pmt/discovery.c
+++ b/drivers/platform/x86/intel/pmt/discovery.c
@@ -376,6 +376,7 @@ static int
pmt_feature_get_feature_table(struct pmt_features_priv *priv,
struct feature *feature,
struct feature_discovery_table *disc_tbl,
+ struct intel_vsec_device *ivdev,
struct resource *disc_res)
{
struct feature_table *feat_tbl = &feature->table;
@@ -404,6 +405,10 @@ pmt_feature_get_feature_table(struct pmt_features_priv *priv,
*/
res = DEFINE_RES_MEM(disc_res->end + disc_tbl->offset + 1,
disc_tbl->size * sizeof(u32));
+
+ if (intel_vsec_check_bar_resource(ivdev, ivdev->tbir, &res))
+ return dev_err_probe(priv->dev, -EINVAL,
+ "Feature table %pR outside of BAR\n", &res);
break;
default:
@@ -494,7 +499,7 @@ static int pmt_features_discovery(struct pmt_features_priv *priv,
if (ret)
return ret;
- ret = pmt_feature_get_feature_table(priv, feature, &disc_tbl, disc_res);
+ ret = pmt_feature_get_feature_table(priv, feature, &disc_tbl, ivdev, disc_res);
if (ret)
return ret;
@@ -653,3 +658,4 @@ MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");
MODULE_DESCRIPTION("Intel PMT Discovery driver");
MODULE_LICENSE("GPL");
MODULE_IMPORT_NS("INTEL_PMT");
+MODULE_IMPORT_NS("INTEL_VSEC");
--
2.43.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 6/6] platform/x86/intel/pmt: Validate telemetry regions against the BAR
2026-10-31 1:29 [PATCH 0/6] platform/x86/intel: Harden PMT discovery against malformed device data David E. Box
` (4 preceding siblings ...)
2026-10-31 1:29 ` [PATCH 5/6] platform/x86/intel/pmt/discovery: Validate feature table " David E. Box
@ 2026-10-31 1:29 ` David E. Box
5 siblings, 0 replies; 7+ messages in thread
From: David E. Box @ 2026-10-31 1:29 UTC (permalink / raw)
To: Hans de Goede, Ilpo Järvinen, platform-driver-x86
Cc: David E. Box, linux-kernel
pmt_resolve_access_pci() computes the base address of a telemetry or
crashlog region from the base offset and BAR index in the device's
discovery header, and the region size also comes from the device. The
resulting range is ioremapped by intel_pmt_dev_register() and can be
mmapped by userspace through sysfs, but it is never checked against the
BAR it claims to be in. A malicious or broken device can therefore
direct the driver at MMIO outside its BAR. For ACCESS_BARID the BAR
index is three bits, so it may also select BAR 6 or 7, which are not
standard BARs.
Check the region against its BAR before it is mapped: the BAR holding the
discovery table for ACCESS_LOCAL, or the BAR named in the header for
ACCESS_BARID.
Fixes: e2729113ce66 ("platform/x86: Intel PMT class driver")
Assisted-by: LLM
Signed-off-by: David E. Box <david.e.box@linux.intel.com>
---
drivers/platform/x86/intel/pmt/class.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/drivers/platform/x86/intel/pmt/class.c b/drivers/platform/x86/intel/pmt/class.c
index 2b11c4012f6a..8f87f8db3966 100644
--- a/drivers/platform/x86/intel/pmt/class.c
+++ b/drivers/platform/x86/intel/pmt/class.c
@@ -214,6 +214,10 @@ static int pmt_resolve_access_pci(struct intel_pmt_entry *entry,
struct device *dev = &ivdev->auxdev.dev;
struct intel_pmt_header *header = &entry->header;
struct resource *disc_res;
+ struct resource res;
+ /* BAR the region lives in, the discovery BAR unless the device names one */
+ unsigned int bar = ivdev->tbir;
+ int ret;
u8 bir;
/*
@@ -258,6 +262,7 @@ static int pmt_resolve_access_pci(struct intel_pmt_entry *entry,
(disc_res->start <= pci_resource_end(pci_dev, i))) {
entry->base_addr = pci_resource_start(pci_dev, i) +
header->base_offset;
+ bar = i;
break;
}
if (!entry->base_addr)
@@ -280,6 +285,7 @@ static int pmt_resolve_access_pci(struct intel_pmt_entry *entry,
*/
entry->base_addr = pci_resource_start(pci_dev, bir) +
GET_ADDRESS(header->base_offset);
+ bar = bir;
break;
default:
dev_err(dev, "Unsupported access type %d\n",
@@ -287,6 +293,20 @@ static int pmt_resolve_access_pci(struct intel_pmt_entry *entry,
return -EINVAL;
}
+ /*
+ * The base offset and size come from the device. Make sure the region
+ * lies within the BAR it claims to be in before it is mapped.
+ */
+ if (header->size) {
+ res = DEFINE_RES_MEM(entry->base_addr, header->size);
+
+ ret = intel_vsec_check_bar_resource(ivdev, bar, &res);
+ if (ret) {
+ dev_err(dev, "Region %pR is outside of its BAR\n", &res);
+ return ret;
+ }
+ }
+
return 0;
}
@@ -574,3 +594,4 @@ module_exit(pmt_class_exit);
MODULE_AUTHOR("Alexander Duyck <alexander.h.duyck@linux.intel.com>");
MODULE_DESCRIPTION("Intel PMT Class driver");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("INTEL_VSEC");
--
2.43.0
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-10-31 1:29 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-31 1:29 [PATCH 0/6] platform/x86/intel: Harden PMT discovery against malformed device data David E. Box
2026-10-31 1:29 ` [PATCH 1/6] platform/x86/intel/pmt/discovery: Bound attr_size against feature_table capacity David E. Box
2026-10-31 1:29 ` [PATCH 2/6] platform/x86/intel/pmt/discovery: Avoid WARN for malformed tables David E. Box
2026-10-31 1:29 ` [PATCH 3/6] platform/x86/intel/pmt/discovery: Validate feature id before use David E. Box
2026-10-31 1:29 ` [PATCH 4/6] platform/x86/intel/vsec: Validate discovery table bounds against the BAR David E. Box
2026-10-31 1:29 ` [PATCH 5/6] platform/x86/intel/pmt/discovery: Validate feature table " David E. Box
2026-10-31 1:29 ` [PATCH 6/6] platform/x86/intel/pmt: Validate telemetry regions " David E. Box
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®