rust/kernel/pci/irq.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
From: Sophon Z <aiqubits@hotmail.com>
IrqVectorRegistration::index() accepts a usize and documents that
out-of-bounds indices return EINVAL, while pci_irq_vector() takes an
unsigned int.
Casting an index larger than u32::MAX wraps it before the PCI core can
validate it. In particular, u32::MAX + 1 becomes zero and can resolve to
the first allocated vector. Values that fit in u32 but exceed
MSI_MAX_INDEX can also reach msi_domain_get_virq() and trigger
WARN_ON_ONCE.
Check the index against the registration length before entering the C
API, and keep the usize-to-u32 conversion checked so the ABI boundary
does not rely on an unchecked cast.
Fixes: 2fb7755b0a7e ("rust: pci: resolve IRQ in index() and embed IrqRequest in IrqVector")
Signed-off-by: Sophon Z <aiqubits@hotmail.com>
---
Changes in v3:
- Check the index against the allocated vector count before entering the C API.
- Keep the checked usize-to-u32 conversion and document the C-side warning.
- Link to v2: https://patch.msgid.link/20260831-fix-pci-irq-vector-index-truncation-v2-1-4030ea7746a9@hotmail.com
Changes in v2:
- No code changes.
- Link to v1: https://patch.msgid.link/20260831-fix-pci-irq-vector-index-truncation-v1-1-d63217d99b67@hotmail.com
---
rust/kernel/pci/irq.rs | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/rust/kernel/pci/irq.rs b/rust/kernel/pci/irq.rs
index 6741046ec1c0..dfab323f26f7 100644
--- a/rust/kernel/pci/irq.rs
+++ b/rust/kernel/pci/irq.rs
@@ -151,8 +151,14 @@ pub fn irq_type(&self) -> IrqType {
/// [`Self::len()`].
#[inline]
pub fn index(&self, index: usize) -> Result<IrqVector<'_>> {
+ if index >= self.len.get() {
+ return Err(EINVAL);
+ }
+
+ let index = u32::try_from(index).map_err(|_| EINVAL)?;
+
// SAFETY: `self.dev.as_raw()` is a valid pointer to a `struct pci_dev`.
- let irq = unsafe { bindings::pci_irq_vector(self.dev.as_raw(), index as u32) };
+ let irq = unsafe { bindings::pci_irq_vector(self.dev.as_raw(), index) };
if irq < 0 {
return Err(Error::from_errno(irq));
}
---
base-commit: cee9395acd8043be0644b25c34bfa86623f2b935
change-id: 20260831-fix-pci-irq-vector-index-truncation-6752f3751a0d
Best regards,
--
Sophon Z <aiqubits@hotmail.com>
On Mon Aug 31, 2026 at 8:17 AM BST, Sophon Z via B4 Relay wrote:
> From: Sophon Z <aiqubits@hotmail.com>
>
> IrqVectorRegistration::index() accepts a usize and documents that
> out-of-bounds indices return EINVAL, while pci_irq_vector() takes an
> unsigned int.
>
> Casting an index larger than u32::MAX wraps it before the PCI core can
> validate it. In particular, u32::MAX + 1 becomes zero and can resolve to
> the first allocated vector. Values that fit in u32 but exceed
> MSI_MAX_INDEX can also reach msi_domain_get_virq() and trigger
> WARN_ON_ONCE.
>
> Check the index against the registration length before entering the C
> API, and keep the usize-to-u32 conversion checked so the ABI boundary
> does not rely on an unchecked cast.
>
> Fixes: 2fb7755b0a7e ("rust: pci: resolve IRQ in index() and embed IrqRequest in IrqVector")
>
> Signed-off-by: Sophon Z <aiqubits@hotmail.com>
> ---
> Changes in v3:
> - Check the index against the allocated vector count before entering the C API.
> - Keep the checked usize-to-u32 conversion and document the C-side warning.
> - Link to v2: https://patch.msgid.link/20260831-fix-pci-irq-vector-index-truncation-v2-1-4030ea7746a9@hotmail.com
>
> Changes in v2:
> - No code changes.
> - Link to v1: https://patch.msgid.link/20260831-fix-pci-irq-vector-index-truncation-v1-1-d63217d99b67@hotmail.com
> ---
> rust/kernel/pci/irq.rs | 8 +++++++-
> 1 file changed, 7 insertions(+), 1 deletion(-)
>
> diff --git a/rust/kernel/pci/irq.rs b/rust/kernel/pci/irq.rs
> index 6741046ec1c0..dfab323f26f7 100644
> --- a/rust/kernel/pci/irq.rs
> +++ b/rust/kernel/pci/irq.rs
> @@ -151,8 +151,14 @@ pub fn irq_type(&self) -> IrqType {
> /// [`Self::len()`].
> #[inline]
> pub fn index(&self, index: usize) -> Result<IrqVector<'_>> {
> + if index >= self.len.get() {
> + return Err(EINVAL);
> + }
> +
> + let index = u32::try_from(index).map_err(|_| EINVAL)?;
Just having this line should be fine, no need for the length check above.
Alternatively, just have the check above, and do the cast, while documenting
that `len` fits u32 as invariant (which is always true given the length is
handed out by PCI core.
Best,
Gary
> +
> // SAFETY: `self.dev.as_raw()` is a valid pointer to a `struct pci_dev`.
> - let irq = unsafe { bindings::pci_irq_vector(self.dev.as_raw(), index as u32) };
> + let irq = unsafe { bindings::pci_irq_vector(self.dev.as_raw(), index) };
> if irq < 0 {
> return Err(Error::from_errno(irq));
> }
>
> ---
> base-commit: cee9395acd8043be0644b25c34bfa86623f2b935
> change-id: 20260831-fix-pci-irq-vector-index-truncation-6752f3751a0d
>
> Best regards,
> --
> Sophon Z <aiqubits@hotmail.com>
On Mon, Aug 31, 2026 at 9:17 AM Sophon Z via B4 Relay
<devnull+aiqubits.hotmail.com@kernel.org> wrote:
>
> Fixes: 2fb7755b0a7e ("rust: pci: resolve IRQ in index() and embed IrqRequest in IrqVector")
The tag looks good, and there is no need for Cc: stable since this is
from yesterday's -rc1, so that is good.
Nit: we usually don't do newlines between tags.
> Signed-off-by: Sophon Z <aiqubits@hotmail.com>
Is this a known identity? Please see:
https://docs.kernel.org/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin
> + let index = u32::try_from(index).map_err(|_| EINVAL)?;
Do we need the `.map_err()`?
Thanks!
Cheers,
Miguel
© 2016 - 2026 Red Hat, Inc.