Make /proc/net a symlink on /proc/self/net (v3)
Subsystems (3)
PATCH 1/1 Make /proc/net a symlink on /proc/self/net (v3)
Current /proc/net is done with so called "shadows", but current implementation is broken and has little chances to get fixed.
The problem is that dentries subtree of /proc/net directory has fancy revalidation rules to make processes living in different net namespaces see different entries in /proc/net subtree, but currently, tasks see in the /proc/net subdir the contents of any other namespace, depending on who opened the file first.
The proposed fix is to turn /proc/net into a symlink, which points to /proc/self/net, which in turn shows what previously was in /proc/net - the network-related info, from the net namespace the appropriate task lives in.
# ls -l /proc/net lrwxrwxrwx 1 root root 8 Mar 5 15:17 /proc/net -> self/net
In other words - this behaves like /proc/mounts, but unlike "mounts", "net" is not a file, but a directory.
Changes from v2:
* Fixed discrepancy of /proc/net nlink count and selinux labeling screwup pointed out by Stephen.
To get the correct nlink count the ->getattr callback for /proc/net is overridden to read one from the net->proc_net entry.
To make selinux still work the net->proc_net entry is initialized properly, i.e. with the "net" name and the proc_net parent.
Selinux fixes are
Changes from v1:
* Fixed a task_struct leak in get_proc_task_net, pointed out by Paul.
---
fs/proc/base.c +1 -0
@@ -2274,6 +2274,7 @@ static const struct pid_entry tgid_base_stuff[] = {DIR ("task" ,S_IRUGO |S_IXUGO , task),DIR ("fd" ,S_IRUSR |S_IXUSR , fd),DIR ("fdinfo" ,S_IRUSR |S_IXUSR , fdinfo), +DIR ("net" ,S_IRUGO |S_IXUSR , net),REG ("environ" ,S_IRUSR , environ),INF ("auxv" ,S_IRUSR , pid_auxv), ONE("status", S_IRUGO, pid_status),
fs/proc/generic.c +17 -9
@@ -377,15 +377,14 @@ static struct dentry_operations proc_dentry_operations =* Don't create negative dentries here, return -ENOENT by hand * instead. */ -struct dentry *proc_lookup (struct inode * dir,struct dentry *dentry,struct nameidata *nd) +struct dentry *proc_lookup_de (struct proc_dir_entry *de,struct inode *dir, +struct dentry *dentry) {struct inode *inode =NULL ; -struct proc_dir_entry * de;int error = -ENOENT ;lock_kernel ();spin_lock (&proc_subdir_lock); - de =PDE (dir);if (de) {for (de = de->subdir; de ; de = de->next) {if (de->namelen != dentry->d_name.len)
@@ -393,8 +392,6 @@ struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry, struct namif (!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);
@@ -417,6 +414,12 @@ out_unlock:return ERR_PTR (error); } +struct dentry *proc_lookup (struct inode *dir,struct dentry *dentry, +struct nameidata *nd) +{ +return proc_lookup_de (PDE (dir), dir, dentry); +} +/* * This returns non-zero if at EOF, so that the /proc * root directory can use this and check if it should
@@ -426,10 +429,9 @@ out_unlock:* value of the readdir() call, as long as it's non-negative * for success.. */ -int proc_readdir (struct file * filp, -void * dirent,filldir_t filldir) +int proc_readdir_de (struct proc_dir_entry *de,struct file *filp,void *dirent, +filldir_t filldir) { -struct proc_dir_entry * de;unsigned int ino;int i;struct inode *inode = filp->f_path.dentry->d_inode;
@@ -438,7 +440,6 @@ int proc_readdir(struct file * filp,lock_kernel (); ino = inode->i_ino; - de =PDE (inode);if (!de) { ret = -EINVAL ; goto out;
@@ -499,6 +500,13 @@ out: unlock_kernel();return ret; } +int proc_readdir (struct file *filp,void *dirent,filldir_t filldir) +{ +struct inode *inode = filp->f_path.dentry->d_inode; + +return proc_readdir_de (PDE (inode), filp, dirent, filldir); +} +/* * These are the generic /proc directory operations. They * use the in-memory "struct proc_dir_entry" tree to parse
fs/proc/internal.h +7 -0
@@ -64,6 +64,8 @@ extern const struct file_operations proc_numa_maps_operations;extern const struct file_operations proc_smaps_operations;extern const struct file_operations proc_clear_refs_operations;extern const struct file_operations proc_pagemap_operations; +extern const struct file_operations proc_net_operations; +extern const struct inode_operations proc_net_inode_operations;void free_proc_entry (struct proc_dir_entry *de);
@@ -83,3 +85,8 @@ static inline int proc_fd(struct inode *inode) {return PROC_I (inode)->fd; } + +struct dentry *proc_lookup_de (struct proc_dir_entry *de,struct inode *ino, +struct dentry *dentry); +int proc_readdir_de (struct proc_dir_entry *de,struct file *filp,void *dirent, +filldir_t filldir);
fs/proc/proc_net.c +89 -28
162 lines not on this page · raw message
include/linux/proc_fs.h +0 -3
@@ -50,8 +50,6 @@ typedef int (read_proc_t)(char *page, char **start, off_t off,typedef int (write_proc_t )(struct file *file,const char __user *buffer,unsigned long count,void *data);typedef int (get_info_t )(char *,char **,off_t ,int ); -typedef struct proc_dir_entry *(shadow_proc_t )(struct task_struct *task, -struct proc_dir_entry *pde);struct proc_dir_entry {unsigned int low_ino;
@@ -82,7 +80,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 {
include/net/net_namespace.h +0 -1
@@ -31,7 +31,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;
From: Pavel Emelyanov <[email protected]>
Date: Fri, 07 Mar 2008 16:42:07 +0300
Quoted 2 lines
Current
/proc/netis done with so called "shadows", but current implementation is broken and has little chances to get fixed.
...
Applied, thanks Pavel.
I'm travelling so it might take a day or two for me to get this to Linus.