From: "Krzysztof Wilczyński" <kwilczynski@kernel.org>
To: Madhavan Srinivasan <maddy@linux.ibm.com>,
Bjorn Helgaas <bhelgaas@google.com>,
Michael Ellerman <mpe@ellerman.id.au>
Cc: "Bjorn Helgaas" <helgaas@kernel.org>,
"Nicholas Piggin" <npiggin@gmail.com>,
"Christophe Leroy" <chleroy@kernel.org>,
"Ilpo Järvinen" <ilpo.jarvinen@linux.intel.com>,
"Kees Cook" <kees@kernel.org>,
linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org,
linux-pci@vger.kernel.org
Subject: [PATCH 1/2] PCI/sysfs: Fix out-of-bounds read in pci_write_legacy_io()
Date: Tue, 16 Jun 2026 16:31:30 +0000 [thread overview]
Message-ID: <20260616163131.2763281-1-kwilczynski@kernel.org> (raw)
pci_write_legacy_io() loads 4 bytes from the kernfs write buffer
regardless of how many bytes userspace wrote:
if (count != 1 && count != 2 && count != 4)
return -EINVAL;
return pci_legacy_write(bus, off, *(u32 *)buf, count);
kernfs_fop_write_iter() allocates the buffer with kmalloc(len + 1),
so a 1-byte write to the legacy_io sysfs file allocates 2 bytes and
the unconditional u32 load reads up to 2 bytes past the end of the
allocation, which KASAN reports as a slab-out-of-bounds read.
Similarly, a 2-byte write overreads by 1 byte.
Thus, read only the number of bytes requested using get_unaligned_le16()
and get_unaligned_le32() for the 2 and 4 byte cases, interpreting the
buffer as little-endian to match the byte ordering of PCI I/O port
space.
The PowerPC implementation previously compensated for the generic
code's native-endian 32-bit load by shifting the value into place
for the 1 and 2 byte cases. The shifts were only correct on
big-endian kernels.
On little-endian PowerPC (POWER8 and later), they extracted the wrong
bytes, so a 1-byte write wrote an out-of-bounds byte instead of the
requested value. On big-endian, the native load also caused out_le16()
and out_le32() to reverse the user's bytes on the wire for 2 and 4 byte
writes. The little-endian helpers resolve both issues, so the shifts
are removed.
No changes are needed for the Alpha platform.
The legacy_io file is root-only and exists only on Alpha and PowerPC,
the two architectures that define HAVE_PCI_LEGACY.
Cc: stable@vger.kernel.org
Signed-off-by: Krzysztof Wilczyński <kwilczynski@kernel.org>
---
arch/powerpc/kernel/pci-common.c | 9 ++-------
drivers/pci/pci-sysfs.c | 18 +++++++++++++++---
2 files changed, 17 insertions(+), 10 deletions(-)
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index 8efe95a0c4ff..fdc57fa2ece6 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -626,19 +626,14 @@ int pci_legacy_write(struct pci_bus *bus, loff_t port, u32 val, size_t size)
return -ENXIO;
addr = hose->io_base_virt + port;
- /* WARNING: The generic code is idiotic. It gets passed a pointer
- * to what can be a 1, 2 or 4 byte quantity and always reads that
- * as a u32, which means that we have to correct the location of
- * the data read within those 32 bits for size 1 and 2
- */
switch(size) {
case 1:
- out_8(addr, val >> 24);
+ out_8(addr, val);
return 1;
case 2:
if (port & 1)
return -EINVAL;
- out_le16(addr, val >> 16);
+ out_le16(addr, val);
return 2;
case 4:
if (port & 3)
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index d37860841260..b56000ba3a33 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -933,12 +933,24 @@ static ssize_t pci_write_legacy_io(struct file *filp, struct kobject *kobj,
char *buf, loff_t off, size_t count)
{
struct pci_bus *bus = to_pci_bus(kobj_to_dev(kobj));
+ u32 val;
- /* Only support 1, 2 or 4 byte accesses */
- if (count != 1 && count != 2 && count != 4)
+ /* Only support 1, 2 or 4 byte accesses. */
+ switch (count) {
+ case 1:
+ val = *(u8 *)buf;
+ break;
+ case 2:
+ val = get_unaligned_le16(buf);
+ break;
+ case 4:
+ val = get_unaligned_le32(buf);
+ break;
+ default:
return -EINVAL;
+ }
- return pci_legacy_write(bus, off, *(u32 *)buf, count);
+ return pci_legacy_write(bus, off, val, count);
}
/**
--
2.54.0
next reply other threads:[~2026-06-16 16:31 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-16 16:31 Krzysztof Wilczyński [this message]
2026-06-16 16:31 ` [PATCH 2/2] PCI/sysfs: Fix read byte order in pci_read_legacy_io() Krzysztof Wilczyński
2026-06-16 16:36 ` sashiko-bot
2026-06-16 16:42 ` [PATCH 1/2] PCI/sysfs: Fix out-of-bounds read in pci_write_legacy_io() sashiko-bot
2026-06-16 16:47 ` Krzysztof Wilczyński
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260616163131.2763281-1-kwilczynski@kernel.org \
--to=kwilczynski@kernel.org \
--cc=bhelgaas@google.com \
--cc=chleroy@kernel.org \
--cc=helgaas@kernel.org \
--cc=ilpo.jarvinen@linux.intel.com \
--cc=kees@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=linuxppc-dev@lists.ozlabs.org \
--cc=maddy@linux.ibm.com \
--cc=mpe@ellerman.id.au \
--cc=npiggin@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.