NetBSD Problem Report #60936

From www@netbsd.org  Thu Oct 29 06:28:06 2026
Return-Path: <www@netbsd.org>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
	(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
	 key-exchange X25519 server-signature RSA-PSS (2048 bits)
	 client-signature RSA-PSS (2048 bits))
	(Client CN "mail.netbsd.org", Issuer "YR1" (not verified))
	by mollari.NetBSD.org (Postfix) with ESMTPS id 37B9C1A923B
	for <gnats-bugs@gnats.NetBSD.org>; Thu, 29 Oct 2026 06:28:06 +0000 (UTC)
Message-Id: <20261029062804.D71141A923C@mollari.NetBSD.org>
Date: Thu, 29 Oct 2026 06:28:04 +0000 (UTC)
From: campbell+netbsd@mumble.net
Reply-To: campbell+netbsd@mumble.net
To: gnats-bugs@NetBSD.org
Subject: interrupt disestablish/establish cycle corrupts evcnts
X-Send-Pr-Version: www-1.0
X-From4GNATS: "campbell+netbsd@mumble.net via gnats" <gnats-admin@NetBSD.org>

>Number:         60936
>Category:       port-amd64
>Synopsis:       interrupt disestablish/establish cycle corrupts evcnts
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    knakahara
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Thu Oct 29 06:30:00 +0000 2026
>Last-Modified:  Thu Oct 29 07:55:23 +0000 2026
>Originator:     Taylor R Campbell
>Release:        current, 11, 10, ...
>Organization:
The Use-after-BSD Interruption, Inc.
>Environment:
>Description:

	After suspend/resume, I noticed some interrupt-related evcnts
	were missing from `vmstat -ve'.  Iterating over the allevents
	list in gdb shows that the linked list structure is corrupted.

	I suspect this is happening here:

    492 	isp = ci->ci_isources[slot];
    493 	if (isp == NULL) {
    494 		const char *via;
    495 
    496 		isp = chained;
    497 		KASSERT(isp != NULL);
    498 		if (pic->pic_type == PIC_MSI || pic->pic_type == PIC_MSIX)
    499 			via = "vec";
    500 		else
    501 			via = "pin";
    502 		snprintf(isp->is_evname, sizeof (isp->is_evname),
    503 		    "%s %d", via, pin);
    504 		evcnt_attach_dynamic(&isp->is_evcnt, EVCNT_TYPE_INTR, NULL,
    505 		    pic->pic_name, isp->is_evname);
    506 		isp->is_active_cpu = ci->ci_cpuid;
    507 		ci->ci_isources[slot] = isp;
    508 	}

	https://nxr.netbsd.org/xref/src/sys/arch/x86/x86/intr.c?r=1.169#492

	I added a check to evcnt_attach_dynamic to see whether the
	evcnt is already listed:

	TAILQ_FOREACH(ev1, &allevents, ev_list) {
		if (((char *)ev <= (char *)ev1 &&
			(char *)(ev + 1) > (char *)ev1) ||
		    ((char *)ev1 <= (char *)ev &&
			(char *)(ev1 + 1) > (char *)ev)) {
			printf("%s: overwriting %p [%s %s] as %p [%s %s]\n",
			    __func__,
			    ev1, ev1->ev_group, ev1->ev_name, ev, group, name);
			db_stacktrace();
		}
	}

	And sure enough:

[ 20843.030419] evcnt_attach_dynamic: overwriting 0xffff8c8091f6e038 [msix1 vec 0] as 0xffff8c8091f6e038 [msix1 vec 0]
[ 20843.030419] intr_allocate_slot_cpu() at netbsd:intr_allocate_slot_cpu+0x15e
[ 20843.031419] intr_allocate_slot() at netbsd:intr_allocate_slot+0x12a
[ 20843.032419] intr_establish_xname() at netbsd:intr_establish_xname+0x160
[ 20843.033419] x86_pci_msix_establish() at netbsd:x86_pci_msix_establish+0x7e
[ 20843.034419] nvme_pci_intr_establish() at netbsd:nvme_pci_intr_establish+0x133
[ 20843.035419] nvme_resume() at netbsd:nvme_resume+0x3f
[ 20843.036419] nvme_pci_resume() at netbsd:nvme_pci_resume+0x11
[ 20843.037419] device_pmf_driver_resume() at netbsd:device_pmf_driver_resume+0x3d
[ 20843.038419] pmf_device_resume() at netbsd:pmf_device_resume+0x110
[ 20843.039419] pmf_system_resume() at netbsd:pmf_system_resume+0xd9
[ 20843.040419] acpi_enter_sleep_state() at netbsd:acpi_enter_sleep_state+0x14e
[ 20843.041419] sysctl_hw_acpi_sleepstate() at netbsd:sysctl_hw_acpi_sleepstate+0xe8
[ 20843.042419] sysctl_dispatch() at netbsd:sysctl_dispatch+0xbd
[ 20843.043419] sys___sysctl() at netbsd:sys___sysctl+0xec
[ 20843.044419] syscall() at netbsd:syscall+0xaf
[ 20843.044419] --- syscall (number 202) ---

	It's not immediately clear to me how this chained intrsource
	data structure is supposed to work (well, evidently it doesn't
	work!), but it seems that either:

	(a) pci_intr_disestablish -- as used by the nvme(4) suspend
	    handler -- doesn't correctly detach the evcnt when it
	    should (possibly leading to use-after-free!), or

	(b) intr_allocate_slot_cpu needs to recognize when the chained
	    interrupt source is already attached and not issue another
	    evcnt_attach_dynamic.

>How-To-Repeat:

	suspend/resume a laptop with nvme

>Fix:

	Yes, please!

>Release-Note:

>Audit-Trail:

Responsible-Changed-From-To: port-amd64-maintainer->knakahara
Responsible-Changed-By: riastradh@NetBSD.org
Responsible-Changed-When: Thu, 29 Oct 2026 07:55:23 +0000
Responsible-Changed-Why:
Can I trouble you to take a look?  Looks like you added this code
as part of pci_intr_distribute.


>Unformatted:

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.51 2026/08/10 02:28:17 riastradh Exp $
$NetBSD: gnats_config.sh,v 1.10 2026/05/13 22:00:09 riastradh Exp $
Copyright © 1994-2026 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.