[PATCH 1/5] PCI: Reject negative resource alignment order
From: shao.mingyin
Date: Fri Nov 06 2026 - 11:28:31 EST
From: Shao Mingyin <shao.mingyin@xxxxxxxxxx>
pci_specified_resource_alignment() parses the pci=resource_alignment=
boot parameter with sscanf("%d%n", &align_order, ...) and rejects only
orders above 63. A negative order, e.g. "pci=resource_alignment=-5@...",
passes that check and later reaches "align = 1ULL << align_order" with a
negative shift count, which is undefined behavior; on x86 the 64-bit
shift count is masked to six bits, silently producing a 2^59-byte
alignment that mis-aligns (or fails to align) the affected IOV resources.
Reject any order outside the valid [0, 63] range and fall back to the
default page-size alignment, matching the existing handling of
out-of-range positive orders.
Fixes: 6534aac198b5 ("PCI: Bounds-check command-line resource alignment requests")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Shao Mingyin <shao.mingyin@xxxxxxxxxx>
---
Tested on 7.3.0-next-20261030 (QEMU/TCG guest) with the
pci=resource_alignment= boot parameter and a QEMU e1000 NIC; no extra
hardware is needed.
Booting with pci=resource_alignment=-5@pci:8086:100e parses a negative
order that the "> 63" check lets through, so "align = 1ULL << align_order"
shifts by -5 (masked to 2^59 on x86-64); the e1000 BAR is resized to
2^59 bytes, which cannot be assigned, and the e1000 fails to probe:
unpatched patched
requesting alignment to PCI: Invalid requested alignment
0x800000000000000 (order -5)
e1000 probe failed, no eth0 e1000 eth0 probes
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index bca3a5d84cd9..c2260ee1f956 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -6605,7 +6605,7 @@ static resource_size_t pci_specified_resource_alignment(struct pci_dev *dev,
if (sscanf(p, "%d%n", &align_order, &count) == 1 &&
p[count] == '@') {
p += count + 1;
- if (align_order > 63) {
+ if (align_order < 0 || align_order > 63) {
pr_err("PCI: Invalid requested alignment (order %d)\n",
align_order);
align_order = PAGE_SHIFT;