From: James Morse james.morse@arm.com
hulk inclusion category: feature bugzilla: 28055 CVE: NA
------------------------------
The MPAM table holds a PPTT-offset that describes a cache. Add a helper acpi_pptt_validate_cache_node(), which checks this offset really is in the PPTT, on a node boundary, and that node really is a cache.
With this the MPAM probe code can go poking through struct cacheinfo looking for a level with a matching firmware_node.
Signed-off-by: James Morse james.morse@arm.com Signed-off-by: Wang ShaoBo bobo.shaobowang@huawei.com Reviewed-By: Xie XiuQi xiexiuqi@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/acpi/pptt.c | 38 ++++++++++++++++++++++++++++++++++++++ include/linux/acpi.h | 4 ++++ 2 files changed, 42 insertions(+)
diff --git a/drivers/acpi/pptt.c b/drivers/acpi/pptt.c index 705719342f2b..057c7c92d8d6 100644 --- a/drivers/acpi/pptt.c +++ b/drivers/acpi/pptt.c @@ -276,6 +276,44 @@ static struct acpi_pptt_processor *acpi_find_processor_node(struct acpi_table_he
return NULL; } +/** + * acpi_validate_cache_node() - Given an offset in the table, check this is + * a cache node. + * Used for cross-table pointers. + * + * Return the cache pointer for a valid cache, or NULL. + */ +struct acpi_pptt_cache * +acpi_pptt_validate_cache_node(struct acpi_table_header *table_hdr, u32 offset) +{ + struct acpi_subtable_header *entry, *cache; + unsigned long table_end; + + if ((offset < sizeof(*table_hdr)) || (offset >= table_hdr->length)) + return NULL; + + table_end = (unsigned long)table_hdr + table_hdr->length; + entry = ACPI_ADD_PTR(struct acpi_subtable_header, table_hdr, + sizeof(struct acpi_table_pptt)); + + cache = ACPI_ADD_PTR(struct acpi_subtable_header, table_hdr, offset); + + /* Walk every node to check offset is on a node boundary */ + while ((unsigned long)(entry + 1) < table_end) { + if (entry->length == 0) { + pr_err("Invalid zero length subtable\n"); + break; + } + if ((entry->type == ACPI_PPTT_TYPE_CACHE) && (entry == cache)) + return (struct acpi_pptt_cache *)entry; + + entry = ACPI_ADD_PTR(struct acpi_subtable_header, entry, + entry->length); + } + + return NULL; +} +
static int acpi_find_cache_levels(struct acpi_table_header *table_hdr, u32 acpi_cpu_id) diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 4edd872b4f98..7ebb80874284 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -638,6 +638,10 @@ static inline u64 acpi_arch_get_root_pointer(void) } #endif
+struct acpi_pptt_cache * +acpi_pptt_validate_cache_node(struct acpi_table_header *table_hdr, + u32 offset); + #else /* !CONFIG_ACPI */
#define acpi_disabled 1