git: 6e8233df18c8 - main - hwpmc_x86: Fix NULL deref when loading on unsupported hardware

From: Bojan Novković <bnovkov_at_FreeBSD.org>
Date: Mon, 23 Dec 2024 10:06:50 UTC
The branch main has been updated by bnovkov:

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

commit 6e8233df18c8008e1a244c8528521a0369f61369
Author:     Bojan Novković <bnovkov@FreeBSD.org>
AuthorDate: 2024-12-21 10:55:57 +0000
Commit:     Bojan Novković <bnovkov@FreeBSD.org>
CommitDate: 2024-12-23 10:00:57 +0000

    hwpmc_x86: Fix NULL deref when loading on unsupported hardware
    
    The pmc_md_{intialize, finalize} routines rely on a machine-dependent
    structure to register the appropriate PMC interrupt handler. However,
    the vendor-specific routines that allocate this structure may return
    NULL for unsupported hardware, leading to a panic when the hwpmc module
    gets loaded. This patch adds additional checks that fix this issue.
    
    Reported by:    Michael Butler (imb@protected-networks.net)
    Reviewed by:    kib
    Differential Revision:  https://reviews.freebsd.org/D48168
---
 sys/dev/hwpmc/hwpmc_x86.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/sys/dev/hwpmc/hwpmc_x86.c b/sys/dev/hwpmc/hwpmc_x86.c
index 2c6c4cd148bf..2903c25ef5c9 100644
--- a/sys/dev/hwpmc/hwpmc_x86.c
+++ b/sys/dev/hwpmc/hwpmc_x86.c
@@ -230,7 +230,7 @@ struct pmc_mdep *
 pmc_md_initialize(void)
 {
 	int i;
-	struct pmc_mdep *md;
+	struct pmc_mdep *md = NULL;
 
 	/* determine the CPU kind */
 	if (cpu_vendor_id == CPU_VENDOR_AMD ||
@@ -238,17 +238,18 @@ pmc_md_initialize(void)
 		md = pmc_amd_initialize();
 	else if (cpu_vendor_id == CPU_VENDOR_INTEL)
 		md = pmc_intel_initialize();
-	else
+
+	if (md == NULL)
 		return (NULL);
 
+	nmi_register_handler(md->pmd_intr);
 	/* disallow sampling if we do not have an LAPIC */
-	if (md != NULL && !lapic_enable_pcint())
+	if (!lapic_enable_pcint())
 		for (i = 0; i < md->pmd_nclass; i++) {
 			if (i == PMC_CLASS_INDEX_SOFT)
 				continue;
 			md->pmd_classdep[i].pcd_caps &= ~PMC_CAP_INTERRUPT;
 		}
-	nmi_register_handler(md->pmd_intr);
 
 	return (md);
 }
@@ -256,9 +257,10 @@ pmc_md_initialize(void)
 void
 pmc_md_finalize(struct pmc_mdep *md)
 {
-
-	lapic_disable_pcint();
-	nmi_remove_handler(md->pmd_intr);
+	if (md != NULL) {
+		lapic_disable_pcint();
+		nmi_remove_handler(md->pmd_intr);
+	}
 	if (cpu_vendor_id == CPU_VENDOR_AMD ||
 	    cpu_vendor_id == CPU_VENDOR_HYGON)
 		pmc_amd_finalize(md);