git: 6ba2c036a011 - main - pci_find_cap_method(): limit number of iterations for finding a capability

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Tue, 07 Jan 2025 15:35:25 UTC
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=6ba2c036a0117ac02f9979b7dc49f15e9c1ea9c9

commit 6ba2c036a0117ac02f9979b7dc49f15e9c1ea9c9
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2025-01-06 23:29:18 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2025-01-07 15:34:59 +0000

    pci_find_cap_method(): limit number of iterations for finding a capability
    
    Powered down device might return 0xff of extended config registers
    reads, causing loop.
    
    PR:     283815
    Reviewed by:    imp
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D48348
---
 sys/dev/pci/pci.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index cf01115581e1..0b02d873c5a1 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -1519,6 +1519,7 @@ pci_find_cap_method(device_t dev, device_t child, int capability,
 	pcicfgregs *cfg = &dinfo->cfg;
 	uint32_t status;
 	uint8_t ptr;
+	int cnt;
 
 	/*
 	 * Check the CAP_LIST bit of the PCI status register first.
@@ -1545,9 +1546,11 @@ pci_find_cap_method(device_t dev, device_t child, int capability,
 	ptr = pci_read_config(child, ptr, 1);
 
 	/*
-	 * Traverse the capabilities list.
+	 * Traverse the capabilities list.  Limit by total theoretical
+	 * maximum number of caps: capability needs at least id and
+	 * next registers, and any type X header cannot contain caps.
 	 */
-	while (ptr != 0) {
+	for (cnt = 0; ptr != 0 && cnt < (PCIE_REGMAX - 0x40) / 2; cnt++) {
 		if (pci_read_config(child, ptr + PCICAP_ID, 1) == capability) {
 			if (capreg != NULL)
 				*capreg = ptr;