/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));