Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'acpi-apei'

Merge ACPI APEI support updates for 6.20-rc1/7.0-rc1:

- Make read-only array non_mmio_desc[] static const (Colin Ian King)

- Prevent the APEI GHES support code on ARM from accessing memory out
of bounds or going past the ARM processor CPER record buffer (Mauro
Carvalho Chehab)

- Prevent cper_print_fw_err() from dumping the entire memory on systems
with defective firmware (Mauro Carvalho Chehab)

- Improve ghes_notify_nmi() status check to avoid unnecessary overhead
in the NMI handler by carrying out all of the requisite preparations
and the NMI registration time (Tony Luck)

- Refactor the GHES driver by extracting common functionality into
reusable helper functions to reduce code duplication and improve
the ghes_notify_sea() status check in analogy with the previous
ghes_notify_nmi() status check improvement (Shuai Xue)

- Make ELOG and GHES log and trace consistently and support the CPER
CXL protocol analogously (Fabio De Francesco)

- Disable KASAN instrumentation in the APEI GHES driver when compile
testing with clang < 18 (Nathan Chancellor)

- Let ghes_edac be the preferred driver to load on __ZX__ and _BYO_
systems by extending the platform detection list in the APEI GHES
driver (Tony W Wang-oc)

* acpi-apei:
ACPI: APEI: GHES: Add ghes_edac support for __ZX__ and _BYO_ systems
ACPI: APEI: GHES: Disable KASAN instrumentation when compile testing with clang < 18
ACPI: extlog: Trace CPER CXL Protocol Error Section
ACPI: APEI: GHES: Add helper to copy CPER CXL protocol error info to work struct
ACPI: APEI: GHES: Add helper for CPER CXL protocol errors checks
ACPI: extlog: Trace CPER PCI Express Error Section
ACPI: extlog: Trace CPER Non-standard Section Body
ACPI: APEI: GHES: Improve ghes_notify_sea() status check
ACPI: APEI: GHES: Extract helper functions for error status handling
ACPI: APEI: GHES: Improve ghes_notify_nmi() status check
EFI/CPER: don't dump the entire memory region
APEI/GHES: ensure that won't go past CPER allocated record
EFI/CPER: don't go past the ARM processor CPER record buffer
APEI/GHES: ARM processor Error: don't go past allocated memory
ACPI: APEI: EINJ: make read-only array non_mmio_desc static const

+325 -59
+2
drivers/acpi/Kconfig
··· 494 494 tristate "Extended Error Log support" 495 495 depends on X86_MCE && X86_LOCAL_APIC && EDAC 496 496 select UEFI_CPER 497 + select ACPI_APEI 498 + select ACPI_APEI_GHES 497 499 help 498 500 Certain usages such as Predictive Failure Analysis (PFA) require 499 501 more information about the error than what can be described in
+64
drivers/acpi/acpi_extlog.c
··· 12 12 #include <linux/ratelimit.h> 13 13 #include <linux/edac.h> 14 14 #include <linux/ras.h> 15 + #include <cxl/event.h> 15 16 #include <acpi/ghes.h> 16 17 #include <asm/cpu.h> 17 18 #include <asm/mce.h> ··· 133 132 return 1; 134 133 } 135 134 135 + static void extlog_print_pcie(struct cper_sec_pcie *pcie_err, 136 + int severity) 137 + { 138 + #ifdef ACPI_APEI_PCIEAER 139 + struct aer_capability_regs *aer; 140 + struct pci_dev *pdev; 141 + unsigned int devfn; 142 + unsigned int bus; 143 + int aer_severity; 144 + int domain; 145 + 146 + if (!(pcie_err->validation_bits & CPER_PCIE_VALID_DEVICE_ID && 147 + pcie_err->validation_bits & CPER_PCIE_VALID_AER_INFO)) 148 + return; 149 + 150 + aer_severity = cper_severity_to_aer(severity); 151 + aer = (struct aer_capability_regs *)pcie_err->aer_info; 152 + domain = pcie_err->device_id.segment; 153 + bus = pcie_err->device_id.bus; 154 + devfn = PCI_DEVFN(pcie_err->device_id.device, 155 + pcie_err->device_id.function); 156 + pdev = pci_get_domain_bus_and_slot(domain, bus, devfn); 157 + if (!pdev) 158 + return; 159 + 160 + pci_print_aer(pdev, aer_severity, aer); 161 + pci_dev_put(pdev); 162 + #endif 163 + } 164 + 165 + static void 166 + extlog_cxl_cper_handle_prot_err(struct cxl_cper_sec_prot_err *prot_err, 167 + int severity) 168 + { 169 + #ifdef ACPI_APEI_PCIEAER 170 + struct cxl_cper_prot_err_work_data wd; 171 + 172 + if (cxl_cper_sec_prot_err_valid(prot_err)) 173 + return; 174 + 175 + if (cxl_cper_setup_prot_err_work_data(&wd, prot_err, severity)) 176 + return; 177 + 178 + cxl_cper_handle_prot_err(&wd); 179 + #endif 180 + } 181 + 136 182 static int extlog_print(struct notifier_block *nb, unsigned long val, 137 183 void *data) 138 184 { ··· 231 183 if (gdata->error_data_length >= sizeof(*mem)) 232 184 trace_extlog_mem_event(mem, err_seq, fru_id, fru_text, 233 185 (u8)gdata->error_severity); 186 + } else if (guid_equal(sec_type, &CPER_SEC_CXL_PROT_ERR)) { 187 + struct cxl_cper_sec_prot_err *prot_err = 188 + acpi_hest_get_payload(gdata); 189 + 190 + extlog_cxl_cper_handle_prot_err(prot_err, 191 + gdata->error_severity); 192 + } else if (guid_equal(sec_type, &CPER_SEC_PCIE)) { 193 + struct cper_sec_pcie *pcie_err = acpi_hest_get_payload(gdata); 194 + 195 + extlog_print_pcie(pcie_err, gdata->error_severity); 196 + } else { 197 + void *err = acpi_hest_get_payload(gdata); 198 + 199 + log_non_standard_event(sec_type, fru_id, fru_text, 200 + gdata->error_severity, err, 201 + gdata->error_data_length); 234 202 } 235 203 } 236 204
+5
drivers/acpi/apei/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 2 obj-$(CONFIG_ACPI_APEI) += apei.o 3 3 obj-$(CONFIG_ACPI_APEI_GHES) += ghes.o 4 + # clang versions prior to 18 may blow out the stack with KASAN 5 + ifeq ($(CONFIG_COMPILE_TEST)_$(CONFIG_CC_IS_CLANG)_$(call clang-min-version, 180000),y_y_) 6 + KASAN_SANITIZE_ghes.o := n 7 + endif 8 + obj-$(CONFIG_ACPI_APEI_PCIEAER) += ghes_helpers.o 4 9 obj-$(CONFIG_ACPI_APEI_EINJ) += einj.o 5 10 einj-y := einj-core.o 6 11 einj-$(CONFIG_ACPI_APEI_EINJ_CXL) += einj-cxl.o
+1 -1
drivers/acpi/apei/einj-core.c
··· 679 679 * region intersects with known resource. So do an allow list check for 680 680 * IORES_DESCs that definitely or most likely not MMIO. 681 681 */ 682 - int non_mmio_desc[] = { 682 + static const int non_mmio_desc[] = { 683 683 IORES_DESC_CRASH_KERNEL, 684 684 IORES_DESC_ACPI_TABLES, 685 685 IORES_DESC_ACPI_NV_STORAGE,
+138 -49
drivers/acpi/apei/ghes.c
··· 29 29 #include <linux/cper.h> 30 30 #include <linux/cleanup.h> 31 31 #include <linux/platform_device.h> 32 + #include <linux/minmax.h> 32 33 #include <linux/mutex.h> 33 34 #include <linux/ratelimit.h> 34 35 #include <linux/vmalloc.h> ··· 295 294 error_block_length = GHES_ESTATUS_MAX_SIZE; 296 295 } 297 296 ghes->estatus = kmalloc(error_block_length, GFP_KERNEL); 297 + ghes->estatus_length = error_block_length; 298 298 if (!ghes->estatus) { 299 299 rc = -ENOMEM; 300 300 goto err_unmap_status_addr; ··· 367 365 struct acpi_hest_generic_status *estatus) 368 366 { 369 367 u32 len = cper_estatus_len(estatus); 368 + u32 max_len = min(ghes->generic->error_block_length, 369 + ghes->estatus_length); 370 370 371 371 if (len < sizeof(*estatus)) { 372 372 pr_warn_ratelimited(FW_WARN GHES_PFX "Truncated error status block!\n"); 373 373 return -EIO; 374 374 } 375 375 376 - if (len > ghes->generic->error_block_length) { 376 + if (!len || len > max_len) { 377 377 pr_warn_ratelimited(FW_WARN GHES_PFX "Invalid error status block length!\n"); 378 378 return -EIO; 379 379 } ··· 556 552 { 557 553 struct cper_sec_proc_arm *err = acpi_hest_get_payload(gdata); 558 554 int flags = sync ? MF_ACTION_REQUIRED : 0; 555 + int length = gdata->error_data_length; 559 556 char error_type[120]; 560 557 bool queued = false; 561 558 int sec_sev, i; 562 559 char *p; 563 560 564 561 sec_sev = ghes_severity(gdata->error_severity); 565 - log_arm_hw_error(err, sec_sev); 562 + if (length >= sizeof(*err)) { 563 + log_arm_hw_error(err, sec_sev); 564 + } else { 565 + pr_warn(FW_BUG "arm error length: %d\n", length); 566 + pr_warn(FW_BUG "length is too small\n"); 567 + pr_warn(FW_BUG "firmware-generated error record is incorrect\n"); 568 + return false; 569 + } 570 + 566 571 if (sev != GHES_SEV_RECOVERABLE || sec_sev != GHES_SEV_RECOVERABLE) 567 572 return false; 568 573 569 574 p = (char *)(err + 1); 575 + length -= sizeof(err); 576 + 570 577 for (i = 0; i < err->err_info_num; i++) { 571 - struct cper_arm_err_info *err_info = (struct cper_arm_err_info *)p; 572 - bool is_cache = err_info->type & CPER_ARM_CACHE_ERROR; 573 - bool has_pa = (err_info->validation_bits & CPER_ARM_INFO_VALID_PHYSICAL_ADDR); 578 + struct cper_arm_err_info *err_info; 579 + bool is_cache, has_pa; 580 + 581 + /* Ensure we have enough data for the error info header */ 582 + if (length < sizeof(*err_info)) 583 + break; 584 + 585 + err_info = (struct cper_arm_err_info *)p; 586 + 587 + /* Validate the claimed length before using it */ 588 + length -= err_info->length; 589 + if (length < 0) 590 + break; 591 + 592 + is_cache = err_info->type & CPER_ARM_CACHE_ERROR; 593 + has_pa = (err_info->validation_bits & CPER_ARM_INFO_VALID_PHYSICAL_ADDR); 574 594 575 595 /* 576 596 * The field (err_info->error_info & BIT(26)) is fixed to set to ··· 739 711 { 740 712 #ifdef CONFIG_ACPI_APEI_PCIEAER 741 713 struct cxl_cper_prot_err_work_data wd; 742 - u8 *dvsec_start, *cap_start; 743 714 744 - if (!(prot_err->valid_bits & PROT_ERR_VALID_AGENT_ADDRESS)) { 745 - pr_err_ratelimited("CXL CPER invalid agent type\n"); 715 + if (cxl_cper_sec_prot_err_valid(prot_err)) 746 716 return; 747 - } 748 - 749 - if (!(prot_err->valid_bits & PROT_ERR_VALID_ERROR_LOG)) { 750 - pr_err_ratelimited("CXL CPER invalid protocol error log\n"); 751 - return; 752 - } 753 - 754 - if (prot_err->err_len != sizeof(struct cxl_ras_capability_regs)) { 755 - pr_err_ratelimited("CXL CPER invalid RAS Cap size (%u)\n", 756 - prot_err->err_len); 757 - return; 758 - } 759 - 760 - if (!(prot_err->valid_bits & PROT_ERR_VALID_SERIAL_NUMBER)) 761 - pr_warn(FW_WARN "CXL CPER no device serial number\n"); 762 717 763 718 guard(spinlock_irqsave)(&cxl_cper_prot_err_work_lock); 764 719 765 720 if (!cxl_cper_prot_err_work) 766 721 return; 767 722 768 - switch (prot_err->agent_type) { 769 - case RCD: 770 - case DEVICE: 771 - case LD: 772 - case FMLD: 773 - case RP: 774 - case DSP: 775 - case USP: 776 - memcpy(&wd.prot_err, prot_err, sizeof(wd.prot_err)); 777 - 778 - dvsec_start = (u8 *)(prot_err + 1); 779 - cap_start = dvsec_start + prot_err->dvsec_len; 780 - 781 - memcpy(&wd.ras_cap, cap_start, sizeof(wd.ras_cap)); 782 - wd.severity = cper_severity_to_aer(severity); 783 - break; 784 - default: 785 - pr_err_ratelimited("CXL CPER invalid agent type: %d\n", 786 - prot_err->agent_type); 723 + if (cxl_cper_setup_prot_err_work_data(&wd, prot_err, severity)) 787 724 return; 788 - } 789 725 790 726 if (!kfifo_put(&cxl_cper_prot_err_fifo, wd)) { 791 727 pr_err_ratelimited("CXL CPER kfifo overflow\n"); ··· 1398 1406 return ret; 1399 1407 } 1400 1408 1409 + /** 1410 + * ghes_has_active_errors - Check if there are active errors in error sources 1411 + * @ghes_list: List of GHES entries to check for active errors 1412 + * 1413 + * This function iterates through all GHES entries in the given list and 1414 + * checks if any of them has active error status by reading the error 1415 + * status register. 1416 + * 1417 + * Return: true if at least one source has active error, false otherwise. 1418 + */ 1419 + static bool __maybe_unused ghes_has_active_errors(struct list_head *ghes_list) 1420 + { 1421 + struct ghes *ghes; 1422 + 1423 + guard(rcu)(); 1424 + list_for_each_entry_rcu(ghes, ghes_list, list) { 1425 + if (ghes->error_status_vaddr && 1426 + readl(ghes->error_status_vaddr)) 1427 + return true; 1428 + } 1429 + 1430 + return false; 1431 + } 1432 + 1433 + /** 1434 + * ghes_map_error_status - Map error status address to virtual address 1435 + * @ghes: pointer to GHES structure 1436 + * 1437 + * Reads the error status address from ACPI HEST table and maps it to a virtual 1438 + * address that can be accessed by the kernel. 1439 + * 1440 + * Return: 0 on success, error code on failure. 1441 + */ 1442 + static int __maybe_unused ghes_map_error_status(struct ghes *ghes) 1443 + { 1444 + struct acpi_hest_generic *g = ghes->generic; 1445 + u64 paddr; 1446 + int rc; 1447 + 1448 + rc = apei_read(&paddr, &g->error_status_address); 1449 + if (rc) 1450 + return rc; 1451 + 1452 + ghes->error_status_vaddr = 1453 + acpi_os_ioremap(paddr, sizeof(ghes->estatus->block_status)); 1454 + if (!ghes->error_status_vaddr) 1455 + return -EINVAL; 1456 + 1457 + return 0; 1458 + } 1459 + 1460 + /** 1461 + * ghes_unmap_error_status - Unmap error status virtual address 1462 + * @ghes: pointer to GHES structure 1463 + * 1464 + * Unmaps the error status address if it was previously mapped. 1465 + */ 1466 + static void __maybe_unused ghes_unmap_error_status(struct ghes *ghes) 1467 + { 1468 + if (ghes->error_status_vaddr) { 1469 + iounmap(ghes->error_status_vaddr); 1470 + ghes->error_status_vaddr = NULL; 1471 + } 1472 + } 1473 + 1401 1474 #ifdef CONFIG_ACPI_APEI_SEA 1402 1475 static LIST_HEAD(ghes_sea); 1403 1476 ··· 1475 1418 static DEFINE_RAW_SPINLOCK(ghes_notify_lock_sea); 1476 1419 int rv; 1477 1420 1421 + if (!ghes_has_active_errors(&ghes_sea)) 1422 + return -ENOENT; 1423 + 1478 1424 raw_spin_lock(&ghes_notify_lock_sea); 1479 1425 rv = ghes_in_nmi_spool_from_list(&ghes_sea, FIX_APEI_GHES_SEA); 1480 1426 raw_spin_unlock(&ghes_notify_lock_sea); ··· 1485 1425 return rv; 1486 1426 } 1487 1427 1488 - static void ghes_sea_add(struct ghes *ghes) 1428 + static int ghes_sea_add(struct ghes *ghes) 1489 1429 { 1430 + int rc; 1431 + 1432 + rc = ghes_map_error_status(ghes); 1433 + if (rc) 1434 + return rc; 1435 + 1490 1436 mutex_lock(&ghes_list_mutex); 1491 1437 list_add_rcu(&ghes->list, &ghes_sea); 1492 1438 mutex_unlock(&ghes_list_mutex); 1439 + 1440 + return 0; 1493 1441 } 1494 1442 1495 1443 static void ghes_sea_remove(struct ghes *ghes) ··· 1505 1437 mutex_lock(&ghes_list_mutex); 1506 1438 list_del_rcu(&ghes->list); 1507 1439 mutex_unlock(&ghes_list_mutex); 1440 + ghes_unmap_error_status(ghes); 1508 1441 synchronize_rcu(); 1509 1442 } 1510 1443 #else /* CONFIG_ACPI_APEI_SEA */ 1511 - static inline void ghes_sea_add(struct ghes *ghes) { } 1444 + static inline int ghes_sea_add(struct ghes *ghes) { return -EINVAL; } 1512 1445 static inline void ghes_sea_remove(struct ghes *ghes) { } 1513 1446 #endif /* CONFIG_ACPI_APEI_SEA */ 1514 1447 ··· 1527 1458 static DEFINE_RAW_SPINLOCK(ghes_notify_lock_nmi); 1528 1459 int ret = NMI_DONE; 1529 1460 1461 + if (!ghes_has_active_errors(&ghes_nmi)) 1462 + return ret; 1463 + 1530 1464 if (!atomic_add_unless(&ghes_in_nmi, 1, 1)) 1531 1465 return ret; 1532 1466 ··· 1542 1470 return ret; 1543 1471 } 1544 1472 1545 - static void ghes_nmi_add(struct ghes *ghes) 1473 + static int ghes_nmi_add(struct ghes *ghes) 1546 1474 { 1475 + int rc; 1476 + 1477 + rc = ghes_map_error_status(ghes); 1478 + if (rc) 1479 + return rc; 1480 + 1547 1481 mutex_lock(&ghes_list_mutex); 1548 1482 if (list_empty(&ghes_nmi)) 1549 1483 register_nmi_handler(NMI_LOCAL, ghes_notify_nmi, 0, "ghes"); 1550 1484 list_add_rcu(&ghes->list, &ghes_nmi); 1551 1485 mutex_unlock(&ghes_list_mutex); 1486 + 1487 + return 0; 1552 1488 } 1553 1489 1554 1490 static void ghes_nmi_remove(struct ghes *ghes) ··· 1566 1486 if (list_empty(&ghes_nmi)) 1567 1487 unregister_nmi_handler(NMI_LOCAL, "ghes"); 1568 1488 mutex_unlock(&ghes_list_mutex); 1489 + 1490 + ghes_unmap_error_status(ghes); 1491 + 1569 1492 /* 1570 1493 * To synchronize with NMI handler, ghes can only be 1571 1494 * freed after NMI handler finishes. ··· 1576 1493 synchronize_rcu(); 1577 1494 } 1578 1495 #else /* CONFIG_HAVE_ACPI_APEI_NMI */ 1579 - static inline void ghes_nmi_add(struct ghes *ghes) { } 1496 + static inline int ghes_nmi_add(struct ghes *ghes) { return -EINVAL; } 1580 1497 static inline void ghes_nmi_remove(struct ghes *ghes) { } 1581 1498 #endif /* CONFIG_HAVE_ACPI_APEI_NMI */ 1582 1499 ··· 1741 1658 break; 1742 1659 1743 1660 case ACPI_HEST_NOTIFY_SEA: 1744 - ghes_sea_add(ghes); 1661 + rc = ghes_sea_add(ghes); 1662 + if (rc) 1663 + goto err; 1745 1664 break; 1746 1665 case ACPI_HEST_NOTIFY_NMI: 1747 - ghes_nmi_add(ghes); 1666 + rc = ghes_nmi_add(ghes); 1667 + if (rc) 1668 + goto err; 1748 1669 break; 1749 1670 case ACPI_HEST_NOTIFY_SOFTWARE_DELEGATED: 1750 1671 rc = apei_sdei_register_ghes(ghes); ··· 1897 1810 */ 1898 1811 static struct acpi_platform_list plat_list[] = { 1899 1812 {"HPE ", "Server ", 0, ACPI_SIG_FADT, all_versions}, 1813 + {"__ZX__", "EDK2 ", 3, ACPI_SIG_FADT, greater_than_or_equal}, 1814 + {"_BYO_ ", "BYOSOFT ", 3, ACPI_SIG_FADT, greater_than_or_equal}, 1900 1815 { } /* End */ 1901 1816 }; 1902 1817
+66
drivers/acpi/apei/ghes_helpers.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + // Copyright(c) 2025 Intel Corporation. All rights reserved 3 + 4 + #include <linux/printk.h> 5 + #include <linux/aer.h> 6 + #include <cxl/event.h> 7 + 8 + int cxl_cper_sec_prot_err_valid(struct cxl_cper_sec_prot_err *prot_err) 9 + { 10 + if (!(prot_err->valid_bits & PROT_ERR_VALID_AGENT_ADDRESS)) { 11 + pr_err_ratelimited("CXL CPER invalid agent type\n"); 12 + return -EINVAL; 13 + } 14 + 15 + if (!(prot_err->valid_bits & PROT_ERR_VALID_ERROR_LOG)) { 16 + pr_err_ratelimited("CXL CPER invalid protocol error log\n"); 17 + return -EINVAL; 18 + } 19 + 20 + if (prot_err->err_len != sizeof(struct cxl_ras_capability_regs)) { 21 + pr_err_ratelimited("CXL CPER invalid RAS Cap size (%u)\n", 22 + prot_err->err_len); 23 + return -EINVAL; 24 + } 25 + 26 + if ((prot_err->agent_type == RCD || prot_err->agent_type == DEVICE || 27 + prot_err->agent_type == LD || prot_err->agent_type == FMLD) && 28 + !(prot_err->valid_bits & PROT_ERR_VALID_SERIAL_NUMBER)) 29 + pr_warn_ratelimited(FW_WARN 30 + "CXL CPER no device serial number\n"); 31 + 32 + return 0; 33 + } 34 + EXPORT_SYMBOL_GPL(cxl_cper_sec_prot_err_valid); 35 + 36 + int cxl_cper_setup_prot_err_work_data(struct cxl_cper_prot_err_work_data *wd, 37 + struct cxl_cper_sec_prot_err *prot_err, 38 + int severity) 39 + { 40 + u8 *dvsec_start, *cap_start; 41 + 42 + switch (prot_err->agent_type) { 43 + case RCD: 44 + case DEVICE: 45 + case LD: 46 + case FMLD: 47 + case RP: 48 + case DSP: 49 + case USP: 50 + memcpy(&wd->prot_err, prot_err, sizeof(wd->prot_err)); 51 + 52 + dvsec_start = (u8 *)(prot_err + 1); 53 + cap_start = dvsec_start + prot_err->dvsec_len; 54 + 55 + memcpy(&wd->ras_cap, cap_start, sizeof(wd->ras_cap)); 56 + wd->severity = cper_severity_to_aer(severity); 57 + break; 58 + default: 59 + pr_err_ratelimited("CXL CPER invalid agent type: %d\n", 60 + prot_err->agent_type); 61 + return -EINVAL; 62 + } 63 + 64 + return 0; 65 + } 66 + EXPORT_SYMBOL_GPL(cxl_cper_setup_prot_err_work_data);
+2 -1
drivers/cxl/core/ras.c
··· 63 63 return 0; 64 64 } 65 65 66 - static void cxl_cper_handle_prot_err(struct cxl_cper_prot_err_work_data *data) 66 + void cxl_cper_handle_prot_err(struct cxl_cper_prot_err_work_data *data) 67 67 { 68 68 unsigned int devfn = PCI_DEVFN(data->prot_err.agent_addr.device, 69 69 data->prot_err.agent_addr.function); ··· 104 104 else 105 105 cxl_cper_trace_uncorr_prot_err(cxlmd, data->ras_cap); 106 106 } 107 + EXPORT_SYMBOL_GPL(cxl_cper_handle_prot_err); 107 108 108 109 static void cxl_cper_prot_err_work_fn(struct work_struct *work) 109 110 {
+8 -4
drivers/firmware/efi/cper-arm.c
··· 226 226 } 227 227 228 228 void cper_print_proc_arm(const char *pfx, 229 - const struct cper_sec_proc_arm *proc) 229 + const struct cper_sec_proc_arm *proc, 230 + u32 length) 230 231 { 231 232 int i, len, max_ctx_type; 232 233 struct cper_arm_err_info *err_info; ··· 239 238 240 239 len = proc->section_length - (sizeof(*proc) + 241 240 proc->err_info_num * (sizeof(*err_info))); 242 - if (len < 0) { 243 - printk("%ssection length: %d\n", pfx, proc->section_length); 244 - printk("%ssection length is too small\n", pfx); 241 + 242 + if (len < 0 || proc->section_length > length) { 243 + printk("%ssection length: %d, CPER size: %d\n", 244 + pfx, proc->section_length, length); 245 + printk("%ssection length is too %s\n", pfx, 246 + (len < 0) ? "small" : "big"); 245 247 printk("%sfirmware-generated error record is incorrect\n", pfx); 246 248 printk("%sERR_INFO_NUM is %d\n", pfx, proc->err_info_num); 247 249 return;
+7 -1
drivers/firmware/efi/cper.c
··· 560 560 } else { 561 561 offset = sizeof(*fw_err); 562 562 } 563 + if (offset > length) { 564 + printk("%s""error section length is too small: offset=%d, length=%d\n", 565 + pfx, offset, length); 566 + return; 567 + } 563 568 564 569 buf += offset; 565 570 length -= offset; ··· 664 659 665 660 printk("%ssection_type: ARM processor error\n", newpfx); 666 661 if (gdata->error_data_length >= sizeof(*arm_err)) 667 - cper_print_proc_arm(newpfx, arm_err); 662 + cper_print_proc_arm(newpfx, arm_err, 663 + gdata->error_data_length); 668 664 else 669 665 goto err_section_too_small; 670 666 #endif
+1 -1
drivers/pci/pcie/aer.c
··· 973 973 pcie_print_tlp_log(dev, &aer->header_log, info.level, 974 974 dev_fmt(" ")); 975 975 } 976 - EXPORT_SYMBOL_NS_GPL(pci_print_aer, "CXL"); 976 + EXPORT_SYMBOL_GPL(pci_print_aer); 977 977 978 978 /** 979 979 * add_error_device - list device to be handled
+5 -1
drivers/ras/ras.c
··· 72 72 ctx_err = (u8 *)ctx_info; 73 73 74 74 for (n = 0; n < err->context_info_num; n++) { 75 - sz = sizeof(struct cper_arm_ctx_info) + ctx_info->size; 75 + sz = sizeof(struct cper_arm_ctx_info); 76 + 77 + if (sz + (long)ctx_info - (long)err >= err->section_length) 78 + sz += ctx_info->size; 79 + 76 80 ctx_info = (struct cper_arm_ctx_info *)((long)ctx_info + sz); 77 81 ctx_len += sz; 78 82 }
+2
include/acpi/ghes.h
··· 21 21 struct acpi_hest_generic_v2 *generic_v2; 22 22 }; 23 23 struct acpi_hest_generic_status *estatus; 24 + unsigned int estatus_length; 24 25 unsigned long flags; 25 26 union { 26 27 struct list_head list; ··· 30 29 }; 31 30 struct device *dev; 32 31 struct list_head elist; 32 + void __iomem *error_status_vaddr; 33 33 }; 34 34 35 35 struct ghes_estatus_node {
+22
include/cxl/event.h
··· 320 320 } 321 321 #endif 322 322 323 + #ifdef CONFIG_ACPI_APEI_PCIEAER 324 + int cxl_cper_sec_prot_err_valid(struct cxl_cper_sec_prot_err *prot_err); 325 + int cxl_cper_setup_prot_err_work_data(struct cxl_cper_prot_err_work_data *wd, 326 + struct cxl_cper_sec_prot_err *prot_err, 327 + int severity); 328 + #else 329 + static inline int 330 + cxl_cper_sec_prot_err_valid(struct cxl_cper_sec_prot_err *prot_err) 331 + { 332 + return -EOPNOTSUPP; 333 + } 334 + static inline int 335 + cxl_cper_setup_prot_err_work_data(struct cxl_cper_prot_err_work_data *wd, 336 + struct cxl_cper_sec_prot_err *prot_err, 337 + int severity) 338 + { 339 + return -EOPNOTSUPP; 340 + } 341 + #endif 342 + 343 + void cxl_cper_handle_prot_err(struct cxl_cper_prot_err_work_data *wd); 344 + 323 345 #endif /* _LINUX_CXL_EVENT_H */
+2 -1
include/linux/cper.h
··· 595 595 const char *cper_mem_err_unpack(struct trace_seq *, 596 596 struct cper_mem_err_compact *); 597 597 void cper_print_proc_arm(const char *pfx, 598 - const struct cper_sec_proc_arm *proc); 598 + const struct cper_sec_proc_arm *proc, 599 + u32 length); 599 600 void cper_print_proc_ia(const char *pfx, 600 601 const struct cper_sec_proc_ia *proc); 601 602 int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg);