diff options
author | Shiju Jose <shiju.jose@huawei.com> | 2023-09-20 21:03:36 +0300 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2023-11-28 20:19:37 +0300 |
commit | b7765b0a034553018f0d815e27f3e9d4178a31a5 (patch) | |
tree | 14c3c24c213cb7fecfb8bedc5113f4bdb64ff1b7 /drivers/pci | |
parent | 4dd0547e8b45faf6f95373be5436b66cde326c0e (diff) | |
download | linux-b7765b0a034553018f0d815e27f3e9d4178a31a5.tar.xz |
ACPI: APEI: Fix AER info corruption when error status data has multiple sections
[ Upstream commit e2abc47a5a1a9f641e7cacdca643fdd40729bf6e ]
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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/pcie/aer.c | 10 |
1 files changed, 10 insertions, 0 deletions
diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index 9c8fd69ae5ad..40d84cb0c601 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" @@ -997,6 +998,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); |