* Re: [PATCH RFC 02/16] proc: add pde_pin() and pde_unpin()
@ 2026-11-04 19:03 Alexey Dobriyan
0 siblings, 0 replies; 2+ messages in thread
From: Alexey Dobriyan @ 2026-11-04 19:03 UTC (permalink / raw)
To: Christian Brauner
Cc: linux-fsdevel, Linus Torvalds, Al Viro, Christoph Hellwig,
Kees Cook, linux-kernel, akpm
> +/* Pin an entry that can go away around a call into it, see use_pde(). */
> +static bool pde_pin(struct proc_dir_entry *pde)
> +{
> + return pde_is_permanent(pde) || use_pde(pde);
> +}
> +
> +static void pde_unpin(struct proc_dir_entry *pde)
> +{
> + if (!pde_is_permanent(pde))
> + unuse_pde(pde);
> +}
Oh, I didn't sent this before because of theoretical bug.
If someone uses permanent bug by mistake or because of misguided
perfomance optimization...
Permanent flags is set after publishing PDE to the world,
so there is a window where +1 is done but -1 is not done.
And then 2147483647 security researchers arrive and overflow it.
There is no detection of buggy usage: proc_make_permanent on dynamic
PDEs from buggy modules. It's easy to grep but I'm not signing up for
that.
/proc/alexey
^ permalink raw reply [flat|nested] 2+ messages in thread
* [PATCH RFC 02/16] proc: add pde_pin() and pde_unpin()
2026-11-02 14:48 [PATCH RFC 00/16] proc: let procfs own the data path Christian Brauner
@ 2026-11-02 14:48 ` Christian Brauner
0 siblings, 0 replies; 2+ messages in thread
From: Christian Brauner @ 2026-11-02 14:48 UTC (permalink / raw)
To: linux-fsdevel
Cc: Linus Torvalds, Jann Horn, Josef Bacik, Chris Mason, Jeff Layton,
NeilBrown, Eric Dumazet, Thomas Gleixner, Al Viro,
Jonathan Corbet, Christoph Hellwig, Greg Kroah-Hartman,
Joel Granados, Kees Cook, Jan Kara, Jan Kara, linux-kernel,
linux-nfs, linux-acpi, linux-kselftest, linux-s390, linux-scsi,
linux-um, linux-wireless, linuxppc-dev, netdev, ntfs3,
platform-driver-x86, coreteam, kexec, linux-pci, linux-sound,
netfilter-devel, dri-devel, ibm-acpi-devel, jfs-discussion,
linux-alpha, linux-arm-kernel, linux-cifs, linux-fbdev,
linux-hwmon, linux-mm, linux-sh, linux-usb, samba-technical,
sparclinux, linux-m68k, linux-doc, linux-serial,
linux-atm-general, Takashi Iwai, linux-input, linux-raid,
linux-ext4, linux-modules, linux-debuggers,
Christian Brauner (Amutable),
Chuck Lever
Every call into an entry that can go away is wrapped in use_pde() and
unuse_pde(), and a permanent entry is called straight away. The read,
write, poll, ioctl, mmap and lseek methods all spell that out as the
same if-else. The next patches add a few more callers. So put it into
pde_pin() and pde_unpin() and use them everywhere.
No functional changes.
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
fs/proc/inode.c | 116 +++++++++++++++++++++++++++-----------------------------
1 file changed, 55 insertions(+), 61 deletions(-)
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 18f6490bfe77..66a3688757dd 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -206,6 +206,18 @@ static void unuse_pde(struct proc_dir_entry *pde)
complete(pde->pde_unload_completion);
}
+/* Pin an entry that can go away around a call into it, see use_pde(). */
+static bool pde_pin(struct proc_dir_entry *pde)
+{
+ return pde_is_permanent(pde) || use_pde(pde);
+}
+
+static void pde_unpin(struct proc_dir_entry *pde)
+{
+ if (!pde_is_permanent(pde))
+ unuse_pde(pde);
+}
+
/*
* At most 2 contexts can enter this function: the one doing the last
* close on the descriptor and whoever is deleting PDE itself.
@@ -275,14 +287,12 @@ void proc_entry_rundown(struct proc_dir_entry *de)
static loff_t proc_reg_llseek(struct file *file, loff_t offset, int whence)
{
struct proc_dir_entry *pde = PDE(file_inode(file));
- loff_t rv = -EINVAL;
+ loff_t rv;
- if (pde_is_permanent(pde)) {
- return pde->proc_ops->proc_lseek(file, offset, whence);
- } else if (use_pde(pde)) {
- rv = pde->proc_ops->proc_lseek(file, offset, whence);
- unuse_pde(pde);
- }
+ if (!pde_pin(pde))
+ return -EINVAL;
+ rv = pde->proc_ops->proc_lseek(file, offset, whence);
+ pde_unpin(pde);
return rv;
}
@@ -291,13 +301,10 @@ static ssize_t proc_reg_read_iter(struct kiocb *iocb, struct iov_iter *iter)
struct proc_dir_entry *pde = PDE(file_inode(iocb->ki_filp));
ssize_t ret;
- if (pde_is_permanent(pde))
- return pde->proc_ops->proc_read_iter(iocb, iter);
-
- if (!use_pde(pde))
+ if (!pde_pin(pde))
return -EIO;
ret = pde->proc_ops->proc_read_iter(iocb, iter);
- unuse_pde(pde);
+ pde_unpin(pde);
return ret;
}
@@ -312,14 +319,12 @@ static ssize_t pde_read(struct proc_dir_entry *pde, struct file *file, char __us
static ssize_t proc_reg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
struct proc_dir_entry *pde = PDE(file_inode(file));
- ssize_t rv = -EIO;
+ ssize_t rv;
- if (pde_is_permanent(pde)) {
- return pde_read(pde, file, buf, count, ppos);
- } else if (use_pde(pde)) {
- rv = pde_read(pde, file, buf, count, ppos);
- unuse_pde(pde);
- }
+ if (!pde_pin(pde))
+ return -EIO;
+ rv = pde_read(pde, file, buf, count, ppos);
+ pde_unpin(pde);
return rv;
}
@@ -334,14 +339,12 @@ static ssize_t pde_write(struct proc_dir_entry *pde, struct file *file, const ch
static ssize_t proc_reg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
struct proc_dir_entry *pde = PDE(file_inode(file));
- ssize_t rv = -EIO;
+ ssize_t rv;
- if (pde_is_permanent(pde)) {
- return pde_write(pde, file, buf, count, ppos);
- } else if (use_pde(pde)) {
- rv = pde_write(pde, file, buf, count, ppos);
- unuse_pde(pde);
- }
+ if (!pde_pin(pde))
+ return -EIO;
+ rv = pde_write(pde, file, buf, count, ppos);
+ pde_unpin(pde);
return rv;
}
@@ -356,14 +359,12 @@ static __poll_t pde_poll(struct proc_dir_entry *pde, struct file *file, struct p
static __poll_t proc_reg_poll(struct file *file, struct poll_table_struct *pts)
{
struct proc_dir_entry *pde = PDE(file_inode(file));
- __poll_t rv = DEFAULT_POLLMASK;
+ __poll_t rv;
- if (pde_is_permanent(pde)) {
- return pde_poll(pde, file, pts);
- } else if (use_pde(pde)) {
- rv = pde_poll(pde, file, pts);
- unuse_pde(pde);
- }
+ if (!pde_pin(pde))
+ return DEFAULT_POLLMASK;
+ rv = pde_poll(pde, file, pts);
+ pde_unpin(pde);
return rv;
}
@@ -378,14 +379,12 @@ static long pde_ioctl(struct proc_dir_entry *pde, struct file *file, unsigned in
static long proc_reg_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct proc_dir_entry *pde = PDE(file_inode(file));
- long rv = -ENOTTY;
+ long rv;
- if (pde_is_permanent(pde)) {
- return pde_ioctl(pde, file, cmd, arg);
- } else if (use_pde(pde)) {
- rv = pde_ioctl(pde, file, cmd, arg);
- unuse_pde(pde);
- }
+ if (!pde_pin(pde))
+ return -ENOTTY;
+ rv = pde_ioctl(pde, file, cmd, arg);
+ pde_unpin(pde);
return rv;
}
@@ -401,13 +400,12 @@ static long pde_compat_ioctl(struct proc_dir_entry *pde, struct file *file, unsi
static long proc_reg_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct proc_dir_entry *pde = PDE(file_inode(file));
- long rv = -ENOTTY;
- if (pde_is_permanent(pde)) {
- return pde_compat_ioctl(pde, file, cmd, arg);
- } else if (use_pde(pde)) {
- rv = pde_compat_ioctl(pde, file, cmd, arg);
- unuse_pde(pde);
- }
+ long rv;
+
+ if (!pde_pin(pde))
+ return -ENOTTY;
+ rv = pde_compat_ioctl(pde, file, cmd, arg);
+ pde_unpin(pde);
return rv;
}
#else
@@ -425,14 +423,12 @@ static int pde_mmap(struct proc_dir_entry *pde, struct file *file, struct vm_are
static int proc_reg_mmap(struct file *file, struct vm_area_struct *vma)
{
struct proc_dir_entry *pde = PDE(file_inode(file));
- int rv = -EIO;
+ int rv;
- if (pde_is_permanent(pde)) {
- return pde_mmap(pde, file, vma);
- } else if (use_pde(pde)) {
- rv = pde_mmap(pde, file, vma);
- unuse_pde(pde);
- }
+ if (!pde_pin(pde))
+ return -EIO;
+ rv = pde_mmap(pde, file, vma);
+ pde_unpin(pde);
return rv;
}
@@ -457,14 +453,12 @@ proc_reg_get_unmapped_area(struct file *file, unsigned long orig_addr,
unsigned long flags)
{
struct proc_dir_entry *pde = PDE(file_inode(file));
- unsigned long rv = -EIO;
+ unsigned long rv;
- if (pde_is_permanent(pde)) {
- return pde_get_unmapped_area(pde, file, orig_addr, len, pgoff, flags);
- } else if (use_pde(pde)) {
- rv = pde_get_unmapped_area(pde, file, orig_addr, len, pgoff, flags);
- unuse_pde(pde);
- }
+ if (!pde_pin(pde))
+ return -EIO;
+ rv = pde_get_unmapped_area(pde, file, orig_addr, len, pgoff, flags);
+ pde_unpin(pde);
return rv;
}
--
2.53.0
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-11-04 19:03 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-04 19:03 [PATCH RFC 02/16] proc: add pde_pin() and pde_unpin() Alexey Dobriyan
-- strict thread matches above, loose matches on Subject: below --
2026-11-02 14:48 [PATCH RFC 00/16] proc: let procfs own the data path Christian Brauner
2026-11-02 14:48 ` [PATCH RFC 02/16] proc: add pde_pin() and pde_unpin() Christian Brauner
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®