Look up another CVE · open CVE-2026-98216 in the interactive tracker
CVE-2026-98216
IB/hfi1: Fix the PIO_CRED credit-return mmap
Published 2026-10-06 (13 days ago) by the Linux kernel CNA. Subsystem drivers/infiniband. Debian urgency: unimportant.
What to do, per Debian release
Debian's own status for CVE-2026-98216 in every release this site tracks, and what each one means in practice. Every status below is the one the Debian Security Team publishes for this CVE. source
| Release | Status | Version | What this means |
|---|---|---|---|
| Debian 12bookworm | not affected | 6.1.190-1 | Nothing to do. bookworm never shipped the vulnerable code. |
| Debian 13trixie | fixedDSA-6568-1 · 2026-10-16 · text | 6.12.113-1 | Update the kernel and reboot. DSA-6568-1 shipped the fix on 2026-10-16, in 6.12.113-1. A running kernel keeps the old code until the machine restarts. |
| Debian 14forky | fixed | 7.2.8-1 | Update the kernel and reboot. Fixed in 7.2.8-1. A running kernel keeps the old code until the machine restarts. |
| Debian unstablesid | fixed | 7.2.8-1 | Update the kernel and reboot. Fixed in 7.2.8-1. A running kernel keeps the old code until the machine restarts. |
The vulnerability
What the bug is
hfi1_file_mmap()'s PIO_CRED case must hand user space the single credit-return page that holds this context's entry. That page is the second or third page of the per-node credit-return allocation once the hardware send context index reaches 64 or 128, so the failure below is intermittent: when the entry lands on the first page the offset is zero and everything works. Two things are wrong. First, cr_page_offset is a byte offset but .va is a struct credit_return *, so adding it is pointer arithmetic and scales the offset by sizeof(struct credit_return) == 64. memvirt then lands 256 KiB or 512 KiB past a 10240-byte allocation. With an IOMMU translating, that address is inside the vmalloc range but in no vm_area, so dma_mmap_coherent() -> iommu_dma_mmap() finds no pages, vmalloc_to_pfn() returns page_to_pfn(NULL), and remap_pfn_range() installs a frame above MAXPHYADDR. The first user read then takes: psm2_ep_open_pr: Corrupted page table at address 7a14d007e000 PGD 800000013886a067 P4D 800000013886a067 PUD 13886b067 PMD 13886c067 PTE 800049168e911235 Oops: Bad pagetable: 000d [#1] SMP PTI Second, and still wrong once the arithmetic is corrected, dma_mmap_coherent() describes a whole coherent buffer and selects the page within it with vma->vm_pgoff. Offsetting cpu_addr has no effect: for a vmap'd allocation iommu_dma_mmap() uses cpu_addr only to locate the vm_area and then maps pages[vm_pgoff], which hfi1_file_mmap() has just set to 0. User space therefore always receives the first credit-return page, every credit read is for the wrong context, and send PIO stalls forever. Use the DMA API as intended: pass the base of the allocation with its full length and select the page with vm_pgoff. A separate length is needed because memlen must keep describing the VMA for the existing size check. The dma-direct path stays correct as well, since dma_direct_mmap() adds the same vm_pgoff to the base pfn. Tested on a Dell T7610 (Xeon E5-2650 v2, Intel IOMMU in DMA-FQ mode) against a Threadripper PRO 3995WX peer, both Omni-Path 100. Before this change psm2_ep_open() Oopses the kernel; with only the arithmetic corrected psm2_ep_open() succeeds but any transfer that uses send PIO hangs, PSM2_SDMA=2 (send PIO disabled) completing normally while PSM2_SDMA=0 (send PIO only) hangs every time. With this change send PIO, send DMA and the default mixed mode all work.
Where it lives
The fix touches these files. If the subsystem is one you do not use, the practical exposure is lower, though the package is still the vulnerable one.
drivers/infiniband/hw/hfi1/file_ops.c
- What this is
- HFI1 DRIVERMAINTAINERS section matched on drivers/infiniband/hw/hfi1 · linux-rdma@vger.kernel.org · Supported
- Kernel module
- hfi1
Check it on the machine
grep -wE 'CONFIG_INFINIBAND|CONFIG_INFINIBAND_HFI1' /boot/config-$(uname -r)Reads the booted kernel's own configuration, on the machine and nowhere else. =y is built in, =m is a module, and an is not set line means the code is not there.
lsmod | grep -w hfi1Prints a line if that module is loaded right now, and nothing if it is not. One that is not loaded can still be loaded later by anything that needs it.
Show whether Debian builds this, per release
Debian builds this, but not on every flavour. At least one release below builds the code on some of its kernel flavours and not on others, so the answer depends on the architecture and flavour installed.
- bookwormMnot built on amd64/cloud-amd64, arm64/arm64, arm64/cloud-arm64, arm64/rt/arm64, armhf/armmp, armhf/armmp-lpae, armhf/rt/armmp, i386/686, i386/686-pae, i386/rt/686-pae, ppc64el/powerpc64le
- trixieMnot built on amd64/cloud-amd64, arm64/arm64, arm64/arm64-16k, arm64/cloud-arm64, arm64/rt/arm64, armel/rpi, armhf/armmp, armhf/armmp-lpae, armhf/rt/armmp, ppc64el/powerpc64le, ppc64el/powerpc64le-64k, riscv64/riscv64, s390x/s390x
- forky, sidMnot built on amd64/cloud-amd64, arm64/arm64, arm64/arm64-16k, arm64/cloud-arm64, arm64/rt-arm64, armhf/armmp, armhf/armmp-lpae, loong64/loong64, ppc64el/powerpc64le, ppc64el/powerpc64le-64k, riscv64/riscv64, s390x/s390x
- M
- a module where it is built at all; some flavours do not build it
- Build switches
- CONFIG_INFINIBAND, CONFIG_INFINIBAND_HFI1
- Reads as
- all on means the file is compiled; any one off means it is not.
From the configuration Debian publishes for every kernel flavour it builds. It covers only the architectures Debian ships a linux-config package for, and nothing about a kernel you built yourself. Debian's own status above stays authoritative about the source package.MAINTAINERS kbuild Makefiles Debian linux-config packages
Signals
- Published
- 2026-10-06 (13 days ago)source
- CVSS
- 7.1 high
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:Hsource recompute it - Attack vector
- local (AV:L)source
- EPSS
- 0.13%, higher than 2.4% of all CVEssource
- CISA KEV
- not listedthe KEV catalogue
- Debian urgency
- unimportantsource
- Subsystem
- drivers/infiniband
Upstream fixes
The versions the CNA records as introducing and fixing this, and the commit for each. source
| Introduced | Fixed in | Commit |
|---|---|---|
| 6.3 | 6.6.158 | 535530bb2ea5 |
| 6.3 | 6.12.112 | dcebe0b0bb08 |
| 6.3 | 6.18.54 | 180752deb727 |
| 6.3 | 7.2.8 | bafeac9ce5d1 |
| 6.3 | 7.3 | 62f0f34fbd2b |
Debian advisories
| Advisory | Date | Shipped to | Debian |
|---|---|---|---|
| DSA-6568-1 | 2026-10-16 | trixie 6.12.113-1 | tracker |
Why the CNA scored it this way
Quoted from the kernel CNA's own scoring file, word for word. A highlighted metric carries the most severe value CVSS v3.1 defines for it, which is what pushes the score up. source
- AV:LAttack vector, local
- The bad mapping is created by hfi1_file_mmap() PIO_CRED case, reached by a local process via open() of the /dev/hfi1_N user cdev, the ASSIGN_CTXT ioctl and mmap() of the PIO_CRED token; no remote peer supplies any data to this path.
- AC:LAttack complexity, low
- With IOMMU DMA translation (common on x86 servers), the pointer-scaled cr_page_offset deterministically sends memvirt 256/512 KiB past the credit-return buffer for send context index >=64, and the attacker can raise the index by opening more contexts; the commit's reproducer oopses every time.
- PR:LPrivileges required, low
- hfi1_user_devnode() creates the user device node with mode 0666 and hfi1_file_open() has no capability check, so any unprivileged local user on an Omni-Path node (e.g. a shared HPC node) can assign a context and issue the mmap.
- UI:NUser interaction, none
- The attacker triggers the faulty mapping and the faulting read entirely from their own process; no other user or administrator has to do anything.
- S:UScope, unchanged
- Both impacts stay within the host kernel's own authority: a kernel page or bogus PFN is mapped into a local process and the kernel oopses; no VM, IOMMU or sandbox boundary is crossed.
- C:HConfidentiality impact, high
- If the out-of-range vmalloc address lands in a non-DMA-coherent vm_area, iommu_dma_mmap() falls back to vmalloc_to_pfn() and remap_pfn_range() exposes that kernel page to userspace read-only with no reference held, so the user can read unrelated kernel memory, even after it is freed and reused.
- I:NIntegrity impact, none
- The PIO_CRED VMA is read-only: VM_WRITE is rejected with -EPERM and VM_MAYWRITE is cleared, so the mis-mapped page cannot be written from userspace, and the bug gives no kernel write primitive.
- A:HAvailability impact, high
- When the address falls in a vmalloc hole, page_to_pfn(NULL) installs a PTE for a frame above MAXPHYADDR and the first user read causes an 'Oops: Bad pagetable' kernel crash; even with the arithmetic fixed, mapping the wrong page leaves send PIO hung forever.