aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2007-12-01 08:33:17 -0500
committerHerbert Xu <herbert@gondor.apana.org.au>2007-12-01 08:33:17 -0500
commit2b1e300a9dfc3196ccddf6f1d74b91b7af55e416 (patch)
tree3181bf4f2c27d185c78b26642f35ed00cb280943
parente03ba84adb62fbc6049325a5bc00ef6932fa5e39 (diff)
[NETNS]: Fix /proc/net breakage
Well I clearly goofed when I added the initial network namespace support for /proc/net. Currently things work but there are odd details visible to user space, even when we have a single network namespace. Since we do not cache proc_dir_entry dentries at the moment we can just modify ->lookup to return a different directory inode depending on the network namespace of the process looking at /proc/net, replacing the current technique of using a magic and fragile follow_link method. To accomplish that this patch: - introduces a shadow_proc method to allow different dentries to be returned from proc_lookup. - Removes the old /proc/net follow_link magic - Fixes a weakness in our not caching of proc generic dentries. As shadow_proc uses a task struct to decided which dentry to return we can go back later and fix the proc generic caching without modifying any code that uses the shadow_proc method. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Cc: "Rafael J. Wysocki" <rjw@sisk.pl> Cc: Pavel Machek <pavel@ucw.cz> Cc: Pavel Emelyanov <xemul@openvz.org> Cc: "David S. Miller" <davem@davemloft.net> Cc: Ingo Molnar <mingo@elte.hu> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r--fs/proc/generic.c12
-rw-r--r--fs/proc/proc_net.c86
-rw-r--r--include/linux/proc_fs.h3
3 files changed, 19 insertions, 82 deletions
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index a9806bc21ec3..c2b752341f89 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -374,9 +374,16 @@ static int proc_delete_dentry(struct dentry * dentry)
374 return 1; 374 return 1;
375} 375}
376 376
377static int proc_revalidate_dentry(struct dentry *dentry, struct nameidata *nd)
378{
379 d_drop(dentry);
380 return 0;
381}
382
377static struct dentry_operations proc_dentry_operations = 383static struct dentry_operations proc_dentry_operations =
378{ 384{
379 .d_delete = proc_delete_dentry, 385 .d_delete = proc_delete_dentry,
386 .d_revalidate = proc_revalidate_dentry,
380}; 387};
381 388
382/* 389/*
@@ -397,8 +404,11 @@ struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry, struct nam
397 if (de->namelen != dentry->d_name.len) 404 if (de->namelen != dentry->d_name.len)
398 continue; 405 continue;
399 if (!memcmp(dentry->d_name.name, de->name, de->namelen)) { 406 if (!memcmp(dentry->d_name.name, de->name, de->namelen)) {
400 unsigned int ino = de->low_ino; 407 unsigned int ino;
401 408
409 if (de->shadow_proc)
410 de = de->shadow_proc(current, de);
411 ino = de->low_ino;
402 de_get(de); 412 de_get(de);
403 spin_unlock(&proc_subdir_lock); 413 spin_unlock(&proc_subdir_lock);
404 error = -EINVAL; 414 error = -EINVAL;
diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c
index 131f9c68be5f..0afe21ee0607 100644
--- a/fs/proc/proc_net.c
+++ b/fs/proc/proc_net.c
@@ -50,89 +50,14 @@ struct net *get_proc_net(const struct inode *inode)
50} 50}
51EXPORT_SYMBOL_GPL(get_proc_net); 51EXPORT_SYMBOL_GPL(get_proc_net);
52 52
53static struct proc_dir_entry *proc_net_shadow; 53static struct proc_dir_entry *shadow_pde;
54 54
55static struct dentry *proc_net_shadow_dentry(struct dentry *parent, 55static struct proc_dir_entry *proc_net_shadow(struct task_struct *task,
56 struct proc_dir_entry *de) 56 struct proc_dir_entry *de)
57{ 57{
58 struct dentry *shadow = NULL; 58 return task->nsproxy->net_ns->proc_net;
59 struct inode *inode;
60 if (!de)
61 goto out;
62 de_get(de);
63 inode = proc_get_inode(parent->d_inode->i_sb, de->low_ino, de);
64 if (!inode)
65 goto out_de_put;
66 shadow = d_alloc_name(parent, de->name);
67 if (!shadow)
68 goto out_iput;
69 shadow->d_op = parent->d_op; /* proc_dentry_operations */
70 d_instantiate(shadow, inode);
71out:
72 return shadow;
73out_iput:
74 iput(inode);
75out_de_put:
76 de_put(de);
77 goto out;
78}
79
80static void *proc_net_follow_link(struct dentry *parent, struct nameidata *nd)
81{
82 struct net *net = current->nsproxy->net_ns;
83 struct dentry *shadow;
84 shadow = proc_net_shadow_dentry(parent, net->proc_net);
85 if (!shadow)
86 return ERR_PTR(-ENOENT);
87
88 dput(nd->dentry);
89 /* My dentry count is 1 and that should be enough as the
90 * shadow dentry is thrown away immediately.
91 */
92 nd->dentry = shadow;
93 return NULL;
94} 59}
95 60
96static struct dentry *proc_net_lookup(struct inode *dir, struct dentry *dentry,
97 struct nameidata *nd)
98{
99 struct net *net = current->nsproxy->net_ns;
100 struct dentry *shadow;
101
102 shadow = proc_net_shadow_dentry(nd->dentry, net->proc_net);
103 if (!shadow)
104 return ERR_PTR(-ENOENT);
105
106 dput(nd->dentry);
107 nd->dentry = shadow;
108
109 return shadow->d_inode->i_op->lookup(shadow->d_inode, dentry, nd);
110}
111
112static int proc_net_setattr(struct dentry *dentry, struct iattr *iattr)
113{
114 struct net *net = current->nsproxy->net_ns;
115 struct dentry *shadow;
116 int ret;
117
118 shadow = proc_net_shadow_dentry(dentry->d_parent, net->proc_net);
119 if (!shadow)
120 return -ENOENT;
121 ret = shadow->d_inode->i_op->setattr(shadow, iattr);
122 dput(shadow);
123 return ret;
124}
125
126static const struct file_operations proc_net_dir_operations = {
127 .read = generic_read_dir,
128};
129
130static struct inode_operations proc_net_dir_inode_operations = {
131 .follow_link = proc_net_follow_link,
132 .lookup = proc_net_lookup,
133 .setattr = proc_net_setattr,
134};
135
136static __net_init int proc_net_ns_init(struct net *net) 61static __net_init int proc_net_ns_init(struct net *net)
137{ 62{
138 struct proc_dir_entry *root, *netd, *net_statd; 63 struct proc_dir_entry *root, *netd, *net_statd;
@@ -185,9 +110,8 @@ static struct pernet_operations __net_initdata proc_net_ns_ops = {
185 110
186int __init proc_net_init(void) 111int __init proc_net_init(void)
187{ 112{
188 proc_net_shadow = proc_mkdir("net", NULL); 113 shadow_pde = proc_mkdir("net", NULL);
189 proc_net_shadow->proc_iops = &proc_net_dir_inode_operations; 114 shadow_pde->shadow_proc = proc_net_shadow;
190 proc_net_shadow->proc_fops = &proc_net_dir_operations;
191 115
192 return register_pernet_subsys(&proc_net_ns_ops); 116 return register_pernet_subsys(&proc_net_ns_ops);
193} 117}
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 1273c6ec535c..523528d237b0 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -48,6 +48,8 @@ typedef int (read_proc_t)(char *page, char **start, off_t off,
48typedef int (write_proc_t)(struct file *file, const char __user *buffer, 48typedef int (write_proc_t)(struct file *file, const char __user *buffer,
49 unsigned long count, void *data); 49 unsigned long count, void *data);
50typedef int (get_info_t)(char *, char **, off_t, int); 50typedef int (get_info_t)(char *, char **, off_t, int);
51typedef struct proc_dir_entry *(shadow_proc_t)(struct task_struct *task,
52 struct proc_dir_entry *pde);
51 53
52struct proc_dir_entry { 54struct proc_dir_entry {
53 unsigned int low_ino; 55 unsigned int low_ino;
@@ -79,6 +81,7 @@ struct proc_dir_entry {
79 int pde_users; /* number of callers into module in progress */ 81 int pde_users; /* number of callers into module in progress */
80 spinlock_t pde_unload_lock; /* proc_fops checks and pde_users bumps */ 82 spinlock_t pde_unload_lock; /* proc_fops checks and pde_users bumps */
81 struct completion *pde_unload_completion; 83 struct completion *pde_unload_completion;
84 shadow_proc_t *shadow_proc;
82}; 85};
83 86
84struct kcore_list { 87struct kcore_list {