commit:     35516718b31b904369ac05645cf883b707a77a51
Author:     Arisu Tachibana <alicef <AT> gentoo <DOT> org>
AuthorDate: Thu Aug 28 15:18:55 2025 +0000
Commit:     Arisu Tachibana <alicef <AT> gentoo <DOT> org>
CommitDate: Thu Aug 28 15:18:55 2025 +0000
URL:        https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=35516718

(add) proc: fix missing pde_set_flags() for net proc files

Signed-off-by: Arisu Tachibana <alicef <AT> gentoo.org>

 0000_README                                        |   4 +
 ..._missing_pde_set_flags_for_net_proc_files.patch | 129 +++++++++++++++++++++
 2 files changed, 133 insertions(+)

diff --git a/0000_README b/0000_README
index 3b747ed9..eda565a9 100644
--- a/0000_README
+++ b/0000_README
@@ -67,6 +67,10 @@ Patch:  1730_parisc-Disable-prctl.patch
 From:   https://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux.git
 Desc:   prctl: Temporarily disable prctl(PR_SET_MDWE) on parisc
 
+Patch:  1800_proc_fix_missing_pde_set_flags_for_net_proc_files.patch
+From:   
https://lore.kernel.org/all/[email protected]/
+Desc:   proc: fix missing pde_set_flags() for net proc files
+
 Patch:  2000_BT-Check-key-sizes-only-if-Secure-Simple-Pairing-enabled.patch
 From:   
https://lore.kernel.org/linux-bluetooth/[email protected]/raw
 Desc:   Bluetooth: Check key sizes only when Secure Simple Pairing is enabled. 
See bug #686758

diff --git a/1800_proc_fix_missing_pde_set_flags_for_net_proc_files.patch 
b/1800_proc_fix_missing_pde_set_flags_for_net_proc_files.patch
new file mode 100644
index 00000000..8632f53b
--- /dev/null
+++ b/1800_proc_fix_missing_pde_set_flags_for_net_proc_files.patch
@@ -0,0 +1,129 @@
+Subject: [PATCH v3] proc: fix missing pde_set_flags() for net proc files
+Date: Thu, 21 Aug 2025 18:58:06 +0800
+Message-ID: <[email protected]>
+X-Mailer: git-send-email 2.25.1
+Precedence: bulk
+X-Mailing-List: [email protected]
+List-Id: <regressions.lists.linux.dev>
+List-Subscribe: <mailto:[email protected]>
+List-Unsubscribe: <mailto:[email protected]>
+MIME-Version: 1.0
+Content-Transfer-Encoding: 8bit
+Content-Type: text/plain
+X-ClientProxiedBy: w002.hihonor.com (10.68.28.120) To a011.hihonor.com
+ (10.68.31.243)
+
+To avoid potential UAF issues during module removal races, we use 
pde_set_flags()
+to save proc_ops flags in PDE itself before proc_register(), and then use
+pde_has_proc_*() helpers instead of directly dereferencing pde->proc_ops->*.
+
+However, the pde_set_flags() call was missing when creating net related proc 
files.
+This omission caused incorrect behavior which FMODE_LSEEK was being cleared
+inappropriately in proc_reg_open() for net proc files. Lars reported it in 
this link[1].
+
+Fix this by ensuring pde_set_flags() is called when register proc entry, and 
add
+NULL check for proc_ops in pde_set_flags().
+
+[1]: https://lore.kernel.org/all/[email protected]/
+
+Fixes: ff7ec8dc1b64 ("proc: use the same treatment to check proc_lseek as ones 
for proc_read_iter et.al")
+Cc: [email protected]
+Reported-by: Lars Wendler <[email protected]>
+Signed-off-by: wangzijie <[email protected]>
+---
+v3:
+- followed by Christian's suggestion to stash pde->proc_ops in a local const 
variable
+v2:
+- followed by Jiri's suggestion to refractor code and reformat commit message
+---
+ fs/proc/generic.c | 38 +++++++++++++++++++++-----------------
+ 1 file changed, 21 insertions(+), 17 deletions(-)
+
+diff --git a/fs/proc/generic.c b/fs/proc/generic.c
+index 76e800e38..bd0c099cf 100644
+--- a/fs/proc/generic.c
++++ b/fs/proc/generic.c
+@@ -367,6 +367,25 @@ static const struct inode_operations 
proc_dir_inode_operations = {
+       .setattr        = proc_notify_change,
+ };
+ 
++static void pde_set_flags(struct proc_dir_entry *pde)
++{
++      const struct proc_ops *proc_ops = pde->proc_ops;
++
++      if (!proc_ops)
++              return;
++
++      if (proc_ops->proc_flags & PROC_ENTRY_PERMANENT)
++              pde->flags |= PROC_ENTRY_PERMANENT;
++      if (proc_ops->proc_read_iter)
++              pde->flags |= PROC_ENTRY_proc_read_iter;
++#ifdef CONFIG_COMPAT
++      if (proc_ops->proc_compat_ioctl)
++              pde->flags |= PROC_ENTRY_proc_compat_ioctl;
++#endif
++      if (proc_ops->proc_lseek)
++              pde->flags |= PROC_ENTRY_proc_lseek;
++}
++
+ /* returns the registered entry, or frees dp and returns NULL on failure */
+ struct proc_dir_entry *proc_register(struct proc_dir_entry *dir,
+               struct proc_dir_entry *dp)
+@@ -374,6 +393,8 @@ struct proc_dir_entry *proc_register(struct proc_dir_entry 
*dir,
+       if (proc_alloc_inum(&dp->low_ino))
+               goto out_free_entry;
+ 
++      pde_set_flags(dp);
++
+       write_lock(&proc_subdir_lock);
+       dp->parent = dir;
+       if (pde_subdir_insert(dir, dp) == false) {
+@@ -561,20 +582,6 @@ struct proc_dir_entry *proc_create_reg(const char *name, 
umode_t mode,
+       return p;
+ }
+ 
+-static void pde_set_flags(struct proc_dir_entry *pde)
+-{
+-      if (pde->proc_ops->proc_flags & PROC_ENTRY_PERMANENT)
+-              pde->flags |= PROC_ENTRY_PERMANENT;
+-      if (pde->proc_ops->proc_read_iter)
+-              pde->flags |= PROC_ENTRY_proc_read_iter;
+-#ifdef CONFIG_COMPAT
+-      if (pde->proc_ops->proc_compat_ioctl)
+-              pde->flags |= PROC_ENTRY_proc_compat_ioctl;
+-#endif
+-      if (pde->proc_ops->proc_lseek)
+-              pde->flags |= PROC_ENTRY_proc_lseek;
+-}
+-
+ struct proc_dir_entry *proc_create_data(const char *name, umode_t mode,
+               struct proc_dir_entry *parent,
+               const struct proc_ops *proc_ops, void *data)
+@@ -585,7 +592,6 @@ struct proc_dir_entry *proc_create_data(const char *name, 
umode_t mode,
+       if (!p)
+               return NULL;
+       p->proc_ops = proc_ops;
+-      pde_set_flags(p);
+       return proc_register(parent, p);
+ }
+ EXPORT_SYMBOL(proc_create_data);
+@@ -636,7 +642,6 @@ struct proc_dir_entry *proc_create_seq_private(const char 
*name, umode_t mode,
+       p->proc_ops = &proc_seq_ops;
+       p->seq_ops = ops;
+       p->state_size = state_size;
+-      pde_set_flags(p);
+       return proc_register(parent, p);
+ }
+ EXPORT_SYMBOL(proc_create_seq_private);
+@@ -667,7 +672,6 @@ struct proc_dir_entry *proc_create_single_data(const char 
*name, umode_t mode,
+               return NULL;
+       p->proc_ops = &proc_single_ops;
+       p->single_show = show;
+-      pde_set_flags(p);
+       return proc_register(parent, p);
+ }
+ EXPORT_SYMBOL(proc_create_single_data);
+-- 
+2.25.1
+
+

Reply via email to