NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
port-amd64/60936: interrupt disestablish/establish cycle corrupts evcnts
>Number: 60936
>Category: port-amd64
>Synopsis: interrupt disestablish/establish cycle corrupts evcnts
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: port-amd64-maintainer
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Thu Oct 29 06:30:00 +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!
Home |
Main Index |
Thread Index |
Old Index