All of lore.kernel.org
 help / color / mirror / Atom feed
From: Pavel Emelyanov <xemul@openvz.org>
To: Andrew Morton <akpm@linux-foundation.org>,
	David Miller <davem@davemloft.net>
Cc: Alexey Dobriyan <adobriyan@openvz.org>,
	Linux Netdev List <netdev@vger.kernel.org>,
	Linux Kernel Mailing List <linux-kernel@vger.kernel.org>,
	"Eric W. Biederman" <ebiederm@xmission.com>
Subject: [PATCH 2/2] Make /proc/net a symlink and drop proc shadows
Date: Thu, 28 Feb 2008 18:51:33 +0300	[thread overview]
Message-ID: <47C6D885.90302@openvz.org> (raw)
In-Reply-To: <47C6D743.1050802@openvz.org>

Turn /proc/net into a symlink, which behaves similar to /proc/self
link - it points to .netns/<id> directory where the <id> is the id
of net namespace, current task lives in.

# ls -l /proc/net
lrwxrwxrwx  1 root root 8 Feb 28 18:38 /proc/net -> .netns/0

The /proc/.netns dir contains subtrees for all the namespaces in 
the system:

# ls -l /proc/.netns/
total 0
dr-xr-xr-x  5 root root 0 Feb 28 18:39 0
dr-xr-xr-x  3 root root 0 Feb 28 18:39 1

To provide some security each /proc/.netns/<id> directory allows
access to tasks that live in the owning namespace only (with the
exception, that init_net tasks can see everything).

Signed-off-by: Pavel Emelyanov <xemul@openvz.org>

---

diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 68971e6..d4103e5 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -227,7 +227,7 @@ static const struct file_operations proc_file_operations = {
 	.write		= proc_file_write,
 };
 
-static int proc_notify_change(struct dentry *dentry, struct iattr *iattr)
+int proc_notify_change(struct dentry *dentry, struct iattr *iattr)
 {
 	struct inode *inode = dentry->d_inode;
 	struct proc_dir_entry *de = PDE(inode);
@@ -248,7 +248,7 @@ out:
 	return error;
 }
 
-static int proc_getattr(struct vfsmount *mnt, struct dentry *dentry,
+int proc_getattr(struct vfsmount *mnt, struct dentry *dentry,
 			struct kstat *stat)
 {
 	struct inode *inode = dentry->d_inode;
@@ -393,8 +393,6 @@ struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry, struct nam
 			if (!memcmp(dentry->d_name.name, de->name, de->namelen)) {
 				unsigned int ino;
 
-				if (de->shadow_proc)
-					de = de->shadow_proc(current, de);
 				ino = de->low_ino;
 				de_get(de);
 				spin_unlock(&proc_subdir_lock);
diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c
index 14e9b5a..8000ea4 100644
--- a/fs/proc/proc_net.c
+++ b/fs/proc/proc_net.c
@@ -83,14 +83,6 @@ struct net *get_proc_net(const struct inode *inode)
 }
 EXPORT_SYMBOL_GPL(get_proc_net);
 
-static struct proc_dir_entry *shadow_pde;
-
-static struct proc_dir_entry *proc_net_shadow(struct task_struct *task,
-						struct proc_dir_entry *de)
-{
-	return task->nsproxy->net_ns->proc_net;
-}
-
 struct proc_dir_entry *proc_net_mkdir(struct net *net, const char *name,
 		struct proc_dir_entry *parent)
 {
@@ -102,47 +94,61 @@ struct proc_dir_entry *proc_net_mkdir(struct net *net, const char *name,
 }
 EXPORT_SYMBOL_GPL(proc_net_mkdir);
 
+static int proc_netns_id_permission(struct inode *inode, int mask,
+		struct nameidata *nd)
+{
+	struct net *net = current->nsproxy->net_ns;
+
+	if (net == &init_net || net == PDE(inode)->data)
+		return generic_permission(inode, mask, NULL);
+	else
+		return -EACCES;
+}
+
+static const struct inode_operations proc_netns_id_ops = {
+	.lookup		= proc_lookup,
+	.getattr	= proc_getattr,
+	.setattr	= proc_notify_change,
+	.permission	= proc_netns_id_permission,
+};
+
+static struct proc_dir_entry *netns_dir;
+
 static __net_init int proc_net_ns_init(struct net *net)
 {
-	struct proc_dir_entry *root, *netd, *net_statd;
-	int err;
+	struct proc_dir_entry *netd, *net_statd;
+	char id[PROC_NUMBUF];
 
-	err = -ENOMEM;
-	root = kzalloc(sizeof(*root), GFP_KERNEL);
-	if (!root)
-		goto out;
+	snprintf(id, sizeof(id), "%d", net->id);
 
-	err = -EEXIST;
-	netd = proc_net_mkdir(net, "net", root);
+	netd = proc_net_mkdir(net, id, netns_dir);
 	if (!netd)
-		goto free_root;
+		goto out;
+
+	netd->proc_iops = &proc_netns_id_ops;
 
-	err = -EEXIST;
 	net_statd = proc_net_mkdir(net, "stat", netd);
 	if (!net_statd)
 		goto free_net;
 
-	root->data = net;
-
-	net->proc_net_root = root;
 	net->proc_net = netd;
 	net->proc_net_stat = net_statd;
-	err = 0;
+	return 0;
 
-out:
-	return err;
 free_net:
-	remove_proc_entry("net", root);
-free_root:
-	kfree(root);
-	goto out;
+	remove_proc_entry(id, netns_dir);
+out:
+	return -ENOMEM;
 }
 
 static __net_exit void proc_net_ns_exit(struct net *net)
 {
+	char id[PROC_NUMBUF];
+
+	snprintf(id, sizeof(id), "%d", net->id);
+
 	remove_proc_entry("stat", net->proc_net);
-	remove_proc_entry("net", net->proc_net_root);
-	kfree(net->proc_net_root);
+	remove_proc_entry(id, netns_dir);
 }
 
 static struct pernet_operations __net_initdata proc_net_ns_ops = {
@@ -150,10 +156,36 @@ static struct pernet_operations __net_initdata proc_net_ns_ops = {
 	.exit = proc_net_ns_exit,
 };
 
+static int proc_net_readlink(struct dentry *dentry, char __user *buffer,
+			      int buflen)
+{
+	char tmp[PROC_NUMBUF];
+
+	sprintf(tmp, ".netns/%d", current->nsproxy->net_ns->id);
+	return vfs_readlink(dentry, buffer, buflen, tmp);
+}
+
+static void *proc_net_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+	char tmp[PROC_NUMBUF];
+
+	sprintf(tmp, ".netns/%d", current->nsproxy->net_ns->id);
+	return ERR_PTR(vfs_follow_link(nd, tmp));
+}
+
+static const struct inode_operations proc_net_link_ops = {
+	.readlink	= proc_net_readlink,
+	.follow_link	= proc_net_follow_link,
+};
+
 int __init proc_net_init(void)
 {
-	shadow_pde = proc_mkdir("net", NULL);
-	shadow_pde->shadow_proc = proc_net_shadow;
+	struct proc_dir_entry *nnet;
+
+	netns_dir = proc_mkdir(".netns", NULL);
+	nnet = proc_symlink("net", NULL, ".netns/0");
+
+	nnet->proc_iops = &proc_net_link_ops;
 
 	return register_pernet_subsys(&proc_net_ns_ops);
 }
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index d9a9e71..be0c9b7 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -82,7 +82,6 @@ struct proc_dir_entry {
 	int pde_users;	/* number of callers into module in progress */
 	spinlock_t pde_unload_lock; /* proc_fops checks and pde_users bumps */
 	struct completion *pde_unload_completion;
-	shadow_proc_t *shadow_proc;
 };
 
 struct kcore_list {
@@ -145,6 +144,9 @@ extern struct inode *proc_get_inode(struct super_block *, unsigned int, struct p
  */
 extern int proc_readdir(struct file *, void *, filldir_t);
 extern struct dentry *proc_lookup(struct inode *, struct dentry *, struct nameidata *);
+extern int proc_getattr(struct vfsmount *mnt, struct dentry *dentry,
+			struct kstat *stat);
+extern int proc_notify_change(struct dentry *dentry, struct iattr *iattr);
 
 extern const struct file_operations proc_kcore_operations;
 extern const struct file_operations proc_kmsg_operations;
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 28738b7..8aedfd6 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -32,7 +32,6 @@ struct net {
 
 	struct proc_dir_entry 	*proc_net;
 	struct proc_dir_entry 	*proc_net_stat;
-	struct proc_dir_entry 	*proc_net_root;
 
 	struct list_head	sysctl_table_headers;
 

  parent reply	other threads:[~2008-02-28 15:52 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-02-28 15:46 [PATCH 0/2] Fix /proc/net in presence of net namespaces Pavel Emelyanov
2008-02-28 15:49 ` [PATCH 1/2] Add an id to struct net Pavel Emelyanov
2008-02-28 15:51 ` Pavel Emelyanov [this message]
2008-02-28 19:31 ` [PATCH 0/2] Fix /proc/net in presence of net namespaces Eric W. Biederman
2008-02-28 21:17   ` serge
2008-02-28 22:39     ` Eric W. Biederman
2008-02-29  3:17       ` serge
2008-02-29  8:16         ` Pavel Emelyanov
2008-02-29 15:38           ` serge
2008-02-29  7:58       ` Pavel Emelyanov
2008-03-02  2:03         ` Eric W. Biederman
2008-03-02  2:17         ` Eric W. Biederman
2008-03-03  9:07           ` Pavel Emelyanov
2008-03-04 22:49             ` Eric W. Biederman
2008-03-05  9:43               ` Pavel Emelyanov
2008-02-29  7:44     ` Pavel Emelyanov
2008-02-29  7:42   ` Pavel Emelyanov
2008-03-02  2:29     ` Eric W. Biederman
2008-03-03  8:52       ` Pavel Emelyanov
2008-03-04 22:23         ` Eric W. Biederman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=47C6D885.90302@openvz.org \
    --to=xemul@openvz.org \
    --cc=adobriyan@openvz.org \
    --cc=akpm@linux-foundation.org \
    --cc=davem@davemloft.net \
    --cc=ebiederm@xmission.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.