proc: fix /proc/net/* after setns(2)
Subsystems (3)
PATCH 1/1 proc: fix /proc/net/* after setns(2)
/proc entries under /proc/net/* can't be cached into dcache because setns(2) can change current net namespace.
Reported-by Mateusz Stępień <[email protected]>
Reported-by Ahmad Fatoum <[email protected]>
Fixes 1da4d377f943fe4194ffb9fb9c26cc58fad4dd24 ("proc: revalidate misc dentries")
Signed-off-by Alexey Dobriyan <[email protected]>
---
I'm still looking into it because modules can create entries under /proc/net/* :-(
fs/proc/generic.c | 4 +++- fs/proc/internal.h | 1 + fs/proc/proc_net.c | 10 ++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-)
fs/proc/generic.c +3 -1
@@ -256,7 +256,7 @@ struct dentry *proc_lookup_de(struct inode *dir, struct dentry *dentry, inode =proc_get_inode (dir->i_sb, de);if (!inode)return ERR_PTR (-ENOMEM ); -d_set_d_op (dentry, &proc_misc_dentry_ops); +d_set_d_op (dentry, de->proc_dops);return d_splice_alias (inode, dentry); }read_unlock (&proc_subdir_lock);
@@ -429,6 +429,8 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent,INIT_LIST_HEAD (&ent->pde_openers);proc_set_user (ent, (*parent)->uid, (*parent)->gid); + ent->proc_dops = &proc_misc_dentry_ops; + out:return ent; }
fs/proc/internal.h +1 -0
@@ -44,6 +44,7 @@ struct proc_dir_entry {struct completion *pde_unload_completion;const struct inode_operations *proc_iops;const struct file_operations *proc_fops; +const struct dentry_operations *proc_dops;union {const struct seq_operations *seq_ops;int (*single_show)(struct seq_file *,void *);
fs/proc/proc_net.c +10 -0
@@ -38,6 +38,12 @@ static struct net *get_proc_net(const struct inode *inode)return maybe_get_net (PDE_NET (PDE (inode))); } +static void pde_force_lookup (struct proc_dir_entry *pde) +{ +// /proc/net/* can be changed under us by setns(CLONE_NEWNET) + pde->proc_dops = &simple_dentry_operations; +} +static int seq_open_net (struct inode *inode,struct file *file) {unsigned int state_size =PDE (inode)->state_size;
@@ -90,6 +96,7 @@ struct proc_dir_entry *proc_create_net_data(const char *name, umode_t mode, p =proc_create_reg (name, mode, &parent, data);if (!p)return NULL ; +pde_force_lookup (p); p->proc_fops = &proc_net_seq_fops; p->seq_ops = ops; p->state_size = state_size;
@@ -133,6 +140,7 @@ struct proc_dir_entry *proc_create_net_data_write(const char *name, umode_t mode p =proc_create_reg (name, mode, &parent, data);if (!p)return NULL ; +pde_force_lookup (p); p->proc_fops = &proc_net_seq_fops; p->seq_ops = ops; p->state_size = state_size;
@@ -181,6 +189,7 @@ struct proc_dir_entry *proc_create_net_single(const char *name, umode_t mode, p =proc_create_reg (name, mode, &parent, data);if (!p)return NULL ; +pde_force_lookup (p); p->proc_fops = &proc_net_single_fops; p->single_show = show;return proc_register (parent, p);
@@ -223,6 +232,7 @@ struct proc_dir_entry *proc_create_net_single_write(const char *name, umode_t mo p =proc_create_reg (name, mode, &parent, data);if (!p)return NULL ; +pde_force_lookup (p); p->proc_fops = &proc_net_single_fops; p->single_show = show; p->write = write;
PATCH v2 1/1 proc: fix /proc/net/* after setns(2)
/proc entries under /proc/net/* can't be cached into dcache because setns(2) can change current net namespace.
v2:
write test,
add dummy ->d_revalidate hook: necessary if /proc/net/* is pinned at setns time.
Fixes 1da4d377f943fe4194ffb9fb9c26cc58fad4dd24 ("proc: revalidate misc dentries")
Signed-off-by Alexey Dobriyan <[email protected]>
Reported-by Mateusz Stępień <[email protected]>
Reported-by Ahmad Fatoum <[email protected]>
Cc Al Viro <[email protected]>
Signed-off-by Alexey Dobriyan <[email protected]>
---
fs/proc/generic.c | 4 fs/proc/internal.h | 1 fs/proc/proc_net.c | 20 ++++ tools/testing/selftests/proc/.gitignore | 1 tools/testing/selftests/proc/Makefile | 1 tools/testing/selftests/proc/setns-dcache.c | 129 ++++++++++++++++++++++++++++ 6 files changed, 155 insertions(+), 1 deletion(-)
fs/proc/generic.c +3 -1
@@ -256,7 +256,7 @@ struct dentry *proc_lookup_de(struct inode *dir, struct dentry *dentry, inode =proc_get_inode (dir->i_sb, de);if (!inode)return ERR_PTR (-ENOMEM ); -d_set_d_op (dentry, &proc_misc_dentry_ops); +d_set_d_op (dentry, de->proc_dops);return d_splice_alias (inode, dentry); }read_unlock (&proc_subdir_lock);
@@ -429,6 +429,8 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent,INIT_LIST_HEAD (&ent->pde_openers);proc_set_user (ent, (*parent)->uid, (*parent)->gid); + ent->proc_dops = &proc_misc_dentry_ops; + out:return ent; }
fs/proc/internal.h +1 -0
@@ -44,6 +44,7 @@ struct proc_dir_entry {struct completion *pde_unload_completion;const struct inode_operations *proc_iops;const struct file_operations *proc_fops; +const struct dentry_operations *proc_dops;union {const struct seq_operations *seq_ops;int (*single_show)(struct seq_file *,void *);
fs/proc/proc_net.c +20 -0
@@ -38,6 +38,22 @@ static struct net *get_proc_net(const struct inode *inode)return maybe_get_net (PDE_NET (PDE (inode))); } +static int proc_net_d_revalidate (struct dentry *dentry,unsigned int flags) +{ +return 0 ; +} + +static const struct dentry_operations proc_net_dentry_ops = { + .d_revalidate = proc_net_d_revalidate, + .d_delete = always_delete_dentry, +}; + +static void pde_force_lookup (struct proc_dir_entry *pde) +{ +/* /proc/net/ entries can be changed under us by setns(CLONE_NEWNET) */ + pde->proc_dops = &proc_net_dentry_ops; +} +static int seq_open_net (struct inode *inode,struct file *file) {unsigned int state_size =PDE (inode)->state_size;
@@ -90,6 +106,7 @@ struct proc_dir_entry *proc_create_net_data(const char *name, umode_t mode, p =proc_create_reg (name, mode, &parent, data);if (!p)return NULL ; +pde_force_lookup (p); p->proc_fops = &proc_net_seq_fops; p->seq_ops = ops; p->state_size = state_size;
@@ -133,6 +150,7 @@ struct proc_dir_entry *proc_create_net_data_write(const char *name, umode_t mode p =proc_create_reg (name, mode, &parent, data);if (!p)return NULL ; +pde_force_lookup (p); p->proc_fops = &proc_net_seq_fops; p->seq_ops = ops; p->state_size = state_size;
@@ -181,6 +199,7 @@ struct proc_dir_entry *proc_create_net_single(const char *name, umode_t mode, p =proc_create_reg (name, mode, &parent, data);if (!p)return NULL ; +pde_force_lookup (p); p->proc_fops = &proc_net_single_fops; p->single_show = show;return proc_register (parent, p);
@@ -223,6 +242,7 @@ struct proc_dir_entry *proc_create_net_single_write(const char *name, umode_t mo p =proc_create_reg (name, mode, &parent, data);if (!p)return NULL ; +pde_force_lookup (p); p->proc_fops = &proc_net_single_fops; p->single_show = show; p->write = write;
tools/testing/selftests/proc/.gitignore +1 -0
@@ -10,4 +10,5 @@ /proc-uptime-002 /read /self +/setns-dcache /thread-self
tools/testing/selftests/proc/Makefile +1 -0
@@ -14,6 +14,7 @@ TEST_GEN_PROGS += proc-uptime-001 TEST_GEN_PROGS += proc-uptime-002 TEST_GEN_PROGS += read TEST_GEN_PROGS += self +TEST_GEN_PROGS += setns-dcache TEST_GEN_PROGS += thread-self include ../lib.mk
new file mode 100644
tools/testing/selftests/proc/setns-dcache.c new file +129 -0
129 lines not on this page · raw message