[PATCH 2/3] platform/x86/amd: hfi: Fix out-of-bounds reads when parsing ranking data

From: Mario Limonciello

Date: Mon Sep 21 2026 - 13:36:47 EST


amd_hfi_fill_metadata() parses CPU core ranking data out of the
firmware-provided PCC shared memory but trusts two values it should not:

- n_bitmaps is used to bound the outer loop that reads the APIC ID
bitmaps from table_data[], but it is never validated against the size
of the shared memory region (pcct_ext->length). A firmware-supplied
count larger than the region reads past the end of table_data.

- When resolving the base of the ranking data for a processor, the
pointer is shifted by an extra "i * nr_class" term, where i is the
current bitmap index. The per-processor offset is already applied
through apic_index, which uses the running count of active processors
(apic_start). The extra shift compounds for every logical processor
beyond the first bitmap (APIC ID >= 32), reading out of bounds.

Both result in out-of-bounds reads that can corrupt the ranking metrics,
oops, or otherwise destabilise the system.

Reject an n_bitmaps value that would not fit within the shared memory
region, and drop the bogus "i * nr_class" term so the ranking data is
addressed only through its correct per-processor offset.

Cc: stable@xxxxxxxxxxxxxxx
Fixes: d4e95ea7a78e ("platform/x86: hfi: Parse CPU core ranking data from shared memory")
Signed-off-by: Mario Limonciello <mario.limonciello@xxxxxxx>
---
drivers/platform/x86/amd/hfi/hfi.c | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/drivers/platform/x86/amd/hfi/hfi.c b/drivers/platform/x86/amd/hfi/hfi.c
index e1c776b71f3e6..6d1d3b6c28a97 100644
--- a/drivers/platform/x86/amd/hfi/hfi.c
+++ b/drivers/platform/x86/amd/hfi/hfi.c
@@ -20,6 +20,7 @@
#include <linux/module.h>
#include <linux/mailbox_client.h>
#include <linux/mutex.h>
+#include <linux/overflow.h>
#include <linux/percpu-defs.h>
#include <linux/platform_device.h>
#include <linux/smp.h>
@@ -168,6 +169,21 @@ static int amd_hfi_fill_metadata(struct amd_hfi_data *amd_hfi_data)
return -EINVAL;
}

+ /*
+ * The bitmaps enumerating the APIC IDs occupy the first n_bitmaps
+ * words of table_data. Reject a firmware-provided count that would
+ * push those reads past the end of the shared memory region.
+ */
+ if (struct_size(amd_hfi_data->shmem, table_data, amd_hfi_data->shmem->n_bitmaps) >
+ pcct_ext->length) {
+ dev_err(amd_hfi_data->dev, "invalid number of bitmaps: %u\n",
+ amd_hfi_data->shmem->n_bitmaps);
+ return -EINVAL;
+ }
+
+ /* The ranking data for each processor follows the bitmaps */
+ u32 *table = amd_hfi_data->shmem->table_data + amd_hfi_data->shmem->n_bitmaps;
+
for (unsigned int i = 0; i < amd_hfi_data->shmem->n_bitmaps; i++) {
u32 bitmap = amd_hfi_data->shmem->table_data[i];

@@ -192,10 +208,6 @@ static int amd_hfi_fill_metadata(struct amd_hfi_data *amd_hfi_data)
info = per_cpu_ptr(&amd_hfi_cpuinfo, cpu_index);
apic_index = apic_start * info->nr_class * 2;
for (unsigned int k = 0; k < info->nr_class; k++) {
- u32 *table = amd_hfi_data->shmem->table_data +
- amd_hfi_data->shmem->n_bitmaps +
- i * info->nr_class;
-
info->amd_hfi_classes[k].eff = table[apic_index + 2 * k];
info->amd_hfi_classes[k].perf = table[apic_index + 2 * k + 1];
}
--
2.55.0