From: Deepanshu Kartikey <kartikey406@gmail.com>
To: bhelgaas@google.com, kw@linux.com
Cc: linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org,
Deepanshu Kartikey <kartikey406@gmail.com>,
syzbot+c7604c9fdd7580cca4e0@syzkaller.appspotmail.com
Subject: [PATCH v2] PCI/proc: check user access return values in proc_bus_pci_{read,write}()
Date: Mon, 4 May 2026 07:52:31 +0530 [thread overview]
Message-ID: <20260504022231.15501-1-kartikey406@gmail.com> (raw)
proc_bus_pci_write() ignores the return value of __get_user(). On a
faulting user pointer the extable fixup zeros the destination, and the
function writes those zeros to PCI configuration space.
syzbot triggers this with writev()-ing a NULL iov_base to
/proc/bus/pci/00/03.0 (the virtio-blk controller in the syzkaller VM):
zero is written to the Command register, clearing Bus Master Enable,
and the disk stops responding. In-flight journal writes never complete
and jbd2 hangs in wait_on_buffer() indefinitely:
INFO: task jbd2/sda1-8 blocked in I/O wait for more than 143 seconds.
__wait_on_buffer fs/buffer.c:123
jbd2_journal_commit_transaction+0x388a/0x6870 fs/jbd2/commit.c:837
kjournald2 fs/jbd2/journal.c:201
proc_bus_pci_read() has the symmetric problem with __put_user(): a
faulting user pointer silently drops config-space data and returns
success.
Switch both functions to get_user()/put_user(), which combine the
access_ok() check with the load/store and return -EFAULT on failure.
The up-front access_ok() can be removed accordingly. On error, jump to
a common label that releases the runtime-PM reference and returns
-EFAULT.
Reported-by: syzbot+c7604c9fdd7580cca4e0@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=c7604c9fdd7580cca4e0
Tested-by: syzbot+c7604c9fdd7580cca4e0@syzkaller.appspotmail.com
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
Changes in v2:
- Use get_user()/put_user() and drop access_ok() (Krzysztof)
- Rename label to err: per kernel convention (Krzysztof)
- Simplify error path to release runtime-PM and return -EFAULT (Krzysztof)
- Apply the same fix to proc_bus_pci_read() (Krzysztof)
---
drivers/pci/proc.c | 44 ++++++++++++++++++++++++++++----------------
1 file changed, 28 insertions(+), 16 deletions(-)
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index ce36e35681e8..8e624d829840 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -53,15 +53,13 @@ static ssize_t proc_bus_pci_read(struct file *file, char __user *buf,
nbytes = size - pos;
cnt = nbytes;
- if (!access_ok(buf, cnt))
- return -EINVAL;
-
pci_config_pm_runtime_get(dev);
if ((pos & 1) && cnt) {
unsigned char val;
pci_user_read_config_byte(dev, pos, &val);
- __put_user(val, buf);
+ if (put_user(val, buf))
+ goto err;
buf++;
pos++;
cnt--;
@@ -70,7 +68,8 @@ static ssize_t proc_bus_pci_read(struct file *file, char __user *buf,
if ((pos & 3) && cnt > 2) {
unsigned short val;
pci_user_read_config_word(dev, pos, &val);
- __put_user(cpu_to_le16(val), (__le16 __user *) buf);
+ if (put_user(cpu_to_le16(val), (__le16 __user *) buf))
+ goto err;
buf += 2;
pos += 2;
cnt -= 2;
@@ -79,7 +78,8 @@ static ssize_t proc_bus_pci_read(struct file *file, char __user *buf,
while (cnt >= 4) {
unsigned int val;
pci_user_read_config_dword(dev, pos, &val);
- __put_user(cpu_to_le32(val), (__le32 __user *) buf);
+ if (put_user(cpu_to_le32(val), (__le32 __user *) buf))
+ goto err;
buf += 4;
pos += 4;
cnt -= 4;
@@ -89,7 +89,8 @@ static ssize_t proc_bus_pci_read(struct file *file, char __user *buf,
if (cnt >= 2) {
unsigned short val;
pci_user_read_config_word(dev, pos, &val);
- __put_user(cpu_to_le16(val), (__le16 __user *) buf);
+ if (put_user(cpu_to_le16(val), (__le16 __user *) buf))
+ goto err;
buf += 2;
pos += 2;
cnt -= 2;
@@ -98,7 +99,8 @@ static ssize_t proc_bus_pci_read(struct file *file, char __user *buf,
if (cnt) {
unsigned char val;
pci_user_read_config_byte(dev, pos, &val);
- __put_user(val, buf);
+ if (put_user(val, buf))
+ goto err;
pos++;
}
@@ -106,6 +108,10 @@ static ssize_t proc_bus_pci_read(struct file *file, char __user *buf,
*ppos = pos;
return nbytes;
+
+err:
+ pci_config_pm_runtime_put(dev);
+ return -EFAULT;
}
static ssize_t proc_bus_pci_write(struct file *file, const char __user *buf,
@@ -129,14 +135,12 @@ static ssize_t proc_bus_pci_write(struct file *file, const char __user *buf,
nbytes = size - pos;
cnt = nbytes;
- if (!access_ok(buf, cnt))
- return -EINVAL;
-
pci_config_pm_runtime_get(dev);
if ((pos & 1) && cnt) {
unsigned char val;
- __get_user(val, buf);
+ if (get_user(val, buf))
+ goto err;
pci_user_write_config_byte(dev, pos, val);
buf++;
pos++;
@@ -145,7 +149,8 @@ static ssize_t proc_bus_pci_write(struct file *file, const char __user *buf,
if ((pos & 3) && cnt > 2) {
__le16 val;
- __get_user(val, (__le16 __user *) buf);
+ if (get_user(val, (__le16 __user *) buf))
+ goto err;
pci_user_write_config_word(dev, pos, le16_to_cpu(val));
buf += 2;
pos += 2;
@@ -154,7 +159,8 @@ static ssize_t proc_bus_pci_write(struct file *file, const char __user *buf,
while (cnt >= 4) {
__le32 val;
- __get_user(val, (__le32 __user *) buf);
+ if (get_user(val, (__le32 __user *) buf))
+ goto err;
pci_user_write_config_dword(dev, pos, le32_to_cpu(val));
buf += 4;
pos += 4;
@@ -163,7 +169,8 @@ static ssize_t proc_bus_pci_write(struct file *file, const char __user *buf,
if (cnt >= 2) {
__le16 val;
- __get_user(val, (__le16 __user *) buf);
+ if (get_user(val, (__le16 __user *) buf))
+ goto err;
pci_user_write_config_word(dev, pos, le16_to_cpu(val));
buf += 2;
pos += 2;
@@ -172,7 +179,8 @@ static ssize_t proc_bus_pci_write(struct file *file, const char __user *buf,
if (cnt) {
unsigned char val;
- __get_user(val, buf);
+ if (get_user(val, buf))
+ goto err;
pci_user_write_config_byte(dev, pos, val);
pos++;
}
@@ -182,6 +190,10 @@ static ssize_t proc_bus_pci_write(struct file *file, const char __user *buf,
*ppos = pos;
i_size_write(ino, dev->cfg_size);
return nbytes;
+
+err:
+ pci_config_pm_runtime_put(dev);
+ return -EFAULT;
}
#ifdef HAVE_PCI_MMAP
--
2.43.0
next reply other threads:[~2026-05-04 2:22 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-04 2:22 Deepanshu Kartikey [this message]
2026-05-04 2:44 ` [PATCH v2] PCI/proc: check user access return values in proc_bus_pci_{read,write}() sashiko-bot
2026-06-21 8:22 ` Deepanshu Kartikey
2026-06-22 17:19 ` Bjorn Helgaas
2026-07-25 2:06 ` Deepanshu Kartikey
2026-07-28 21:56 ` Bjorn Helgaas
2026-07-28 23:16 ` 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=20260504022231.15501-1-kartikey406@gmail.com \
--to=kartikey406@gmail.com \
--cc=bhelgaas@google.com \
--cc=kw@linux.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=syzbot+c7604c9fdd7580cca4e0@syzkaller.appspotmail.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.