summaryrefslogtreecommitdiff
path: root/drivers/pci/pcie
diff options
context:
space:
mode:
authorShiju Jose <shiju.jose@huawei.com>2023-09-21 02:03:36 +0800
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2023-09-21 20:44:23 +0200
commite2abc47a5a1a9f641e7cacdca643fdd40729bf6e (patch)
tree971e7bc4ab175eda0f423a06e34a4c32308efae5 /drivers/pci/pcie
parentce9ecca0238b140b88f43859b211c9fdfd8e5b70 (diff)
ACPI: APEI: Fix AER info corruption when error status data has multiple sections
ghes_handle_aer() passes AER data to the PCI core for logging and recovery by calling aer_recover_queue() with a pointer to struct aer_capability_regs. The problem was that aer_recover_queue() queues the pointer directly without copying the aer_capability_regs data. The pointer was to the ghes->estatus buffer, which could be reused before aer_recover_work_func() reads the data. To avoid this problem, allocate a new aer_capability_regs structure from the ghes_estatus_pool, copy the AER data from the ghes->estatus buffer into it, pass a pointer to the new struct to aer_recover_queue(), and free it after aer_recover_work_func() has processed it. Reported-by: Bjorn Helgaas <helgaas@kernel.org> Acked-by: Bjorn Helgaas <bhelgaas@google.com> Signed-off-by: Shiju Jose <shiju.jose@huawei.com> [ rjw: Subject edits ] Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/pci/pcie')
-rw-r--r--drivers/pci/pcie/aer.c10
1 files changed, 10 insertions, 0 deletions
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c
index e85ff946e8c8..ba1ce820c141 100644
--- a/drivers/pci/pcie/aer.c
+++ b/drivers/pci/pcie/aer.c
@@ -29,6 +29,7 @@
#include <linux/kfifo.h>
#include <linux/slab.h>
#include <acpi/apei.h>
+#include <acpi/ghes.h>
#include <ras/ras_event.h>
#include "../pci.h"
@@ -996,6 +997,15 @@ static void aer_recover_work_func(struct work_struct *work)
continue;
}
cper_print_aer(pdev, entry.severity, entry.regs);
+ /*
+ * Memory for aer_capability_regs(entry.regs) is being allocated from the
+ * ghes_estatus_pool to protect it from overwriting when multiple sections
+ * are present in the error status. Thus free the same after processing
+ * the data.
+ */
+ ghes_estatus_pool_region_free((unsigned long)entry.regs,
+ sizeof(struct aer_capability_regs));
+
if (entry.severity == AER_NONFATAL)
pcie_do_recovery(pdev, pci_channel_io_normal,
aer_root_reset);