/proc/net directories may contain content which depends on net namespace.
Such dentries should be revalidated after setns(CLONE_NEWNET).

See
        commit 1fde6f21d90f8ba5da3cb9c54ca991ed72696c43
        proc: fix /proc/net/* after setns(2)

The patch is all about "pde_force_lookup()" line.

        [redid original patch --adobriyan]

Reported-by: "Hallsmark, Per" <per.hallsm...@windriver.com>
Signed-off-by: Alexey Dobriyan <adobri...@gmail.com>
---

 fs/proc/generic.c       |   25 ++++++++++++++++++-------
 fs/proc/internal.h      |    3 +++
 fs/proc/proc_net.c      |   17 +++++++++++++++++
 include/linux/proc_fs.h |   16 ++++++++--------
 4 files changed, 46 insertions(+), 15 deletions(-)

--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -459,26 +459,37 @@ struct proc_dir_entry *proc_symlink(const char *name,
 }
 EXPORT_SYMBOL(proc_symlink);
 
-struct proc_dir_entry *proc_mkdir_data(const char *name, umode_t mode,
-               struct proc_dir_entry *parent, void *data)
+struct proc_dir_entry *_proc_mkdir(const char *name, umode_t mode,
+                                  struct proc_dir_entry **parent, void *data)
 {
        struct proc_dir_entry *ent;
 
        if (mode == 0)
                mode = S_IRUGO | S_IXUGO;
 
-       ent = __proc_create(&parent, name, S_IFDIR | mode, 2);
+       ent = __proc_create(parent, name, S_IFDIR | mode, 2);
        if (ent) {
                ent->data = data;
                ent->proc_fops = &proc_dir_operations;
                ent->proc_iops = &proc_dir_inode_operations;
-               parent->nlink++;
-               ent = proc_register(parent, ent);
-               if (!ent)
-                       parent->nlink--;
        }
        return ent;
 }
+
+struct proc_dir_entry *proc_mkdir_data(const char *name, umode_t mode,
+               struct proc_dir_entry *parent, void *data)
+{
+       struct proc_dir_entry *pde;
+
+       pde = _proc_mkdir(name, mode, &parent, data);
+       if (!pde)
+               return NULL;
+       parent->nlink++;
+       pde = proc_register(parent, pde);
+       if (!pde)
+               parent->nlink--;
+       return pde;
+}
 EXPORT_SYMBOL_GPL(proc_mkdir_data);
 
 struct proc_dir_entry *proc_mkdir_mode(const char *name, umode_t mode,
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -299,3 +299,6 @@ extern unsigned long task_statm(struct mm_struct *,
                                unsigned long *, unsigned long *,
                                unsigned long *, unsigned long *);
 extern void task_mem(struct seq_file *, struct mm_struct *);
+
+struct proc_dir_entry *_proc_mkdir(const char *name, umode_t mode,
+                                  struct proc_dir_entry **parent, void *data);
--- a/fs/proc/proc_net.c
+++ b/fs/proc/proc_net.c
@@ -251,6 +251,23 @@ struct proc_dir_entry *proc_create_net_single_write(const 
char *name, umode_t mo
 }
 EXPORT_SYMBOL_GPL(proc_create_net_single_write);
 
+struct proc_dir_entry *proc_net_mkdir(struct net *net, const char *name,
+                                     struct proc_dir_entry *parent)
+{
+       struct proc_dir_entry *pde;
+
+       pde = _proc_mkdir(name, 0, &parent, net);
+       if (!pde)
+               return NULL;
+       pde_force_lookup(pde);
+       parent->nlink++;
+       pde = proc_register(parent, pde);
+       if (!pde)
+               parent->nlink++;
+       return pde;
+}
+EXPORT_SYMBOL_GPL(proc_net_mkdir);
+
 static struct net *get_proc_task_net(struct inode *dir)
 {
        struct task_struct *task;
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -8,6 +8,7 @@
 #include <linux/types.h>
 #include <linux/fs.h>
 
+struct net;
 struct proc_dir_entry;
 struct seq_file;
 struct seq_operations;
@@ -73,6 +74,8 @@ struct proc_dir_entry *proc_create_net_single_write(const 
char *name, umode_t mo
                                                    int (*show)(struct seq_file 
*, void *),
                                                    proc_write_t write,
                                                    void *data);
+struct proc_dir_entry *proc_net_mkdir(struct net *net, const char *name, 
struct proc_dir_entry *parent);
+
 extern struct pid *tgid_pidfd_to_pid(const struct file *file);
 
 #else /* CONFIG_PROC_FS */
@@ -115,6 +118,11 @@ static inline int remove_proc_subtree(const char *name, 
struct proc_dir_entry *p
 #define proc_create_net(name, mode, parent, state_size, ops) ({NULL;})
 #define proc_create_net_single(name, mode, parent, show, data) ({NULL;})
 
+static inline struct proc_dir_entry *proc_net_mkdir(struct net *net, const 
char *name, struct proc_dir_entry *parent)
+{
+       return NULL;
+}
+
 static inline struct pid *tgid_pidfd_to_pid(const struct file *file)
 {
        return ERR_PTR(-EBADF);
@@ -122,14 +130,6 @@ static inline struct pid *tgid_pidfd_to_pid(const struct 
file *file)
 
 #endif /* CONFIG_PROC_FS */
 
-struct net;
-
-static inline struct proc_dir_entry *proc_net_mkdir(
-       struct net *net, const char *name, struct proc_dir_entry *parent)
-{
-       return proc_mkdir_data(name, 0, parent, net);
-}
-
 struct ns_common;
 int open_related_ns(struct ns_common *ns,
                   struct ns_common *(*get_ns)(struct ns_common *ns));

Reply via email to