| From eb6d38d5427b3ad42f5268da0f1dd31bb0af1264 Mon Sep 17 00:00:00 2001 |
| From: "Eric W. Biederman" <ebiederm@xmission.com> |
| Date: Mon, 11 May 2015 16:44:25 -0500 |
| Subject: proc: Allow creating permanently empty directories that serve as mount points |
| |
| From: "Eric W. Biederman" <ebiederm@xmission.com> |
| |
| commit eb6d38d5427b3ad42f5268da0f1dd31bb0af1264 upstream. |
| |
| Add a new function proc_create_mount_point that when used to creates a |
| directory that can not be added to. |
| |
| Add a new function is_empty_pde to test if a function is a mount |
| point. |
| |
| Update the code to use make_empty_dir_inode when reporting |
| a permanently empty directory to the vfs. |
| |
| Update the code to not allow adding to permanently empty directories. |
| |
| Update /proc/openprom and /proc/fs/nfsd to be permanently empty directories. |
| |
| Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/proc/generic.c | 23 +++++++++++++++++++++++ |
| fs/proc/inode.c | 4 ++++ |
| fs/proc/internal.h | 6 ++++++ |
| fs/proc/root.c | 4 ++-- |
| 4 files changed, 35 insertions(+), 2 deletions(-) |
| |
| --- a/fs/proc/generic.c |
| +++ b/fs/proc/generic.c |
| @@ -373,6 +373,10 @@ static struct proc_dir_entry *__proc_cre |
| WARN(1, "create '/proc/%s' by hand\n", qstr.name); |
| return NULL; |
| } |
| + if (is_empty_pde(*parent)) { |
| + WARN(1, "attempt to add to permanently empty directory"); |
| + return NULL; |
| + } |
| |
| ent = kzalloc(sizeof(struct proc_dir_entry) + qstr.len + 1, GFP_KERNEL); |
| if (!ent) |
| @@ -455,6 +459,25 @@ struct proc_dir_entry *proc_mkdir(const |
| } |
| EXPORT_SYMBOL(proc_mkdir); |
| |
| +struct proc_dir_entry *proc_create_mount_point(const char *name) |
| +{ |
| + umode_t mode = S_IFDIR | S_IRUGO | S_IXUGO; |
| + struct proc_dir_entry *ent, *parent = NULL; |
| + |
| + ent = __proc_create(&parent, name, mode, 2); |
| + if (ent) { |
| + ent->data = NULL; |
| + ent->proc_fops = NULL; |
| + ent->proc_iops = NULL; |
| + if (proc_register(parent, ent) < 0) { |
| + kfree(ent); |
| + parent->nlink--; |
| + ent = NULL; |
| + } |
| + } |
| + return ent; |
| +} |
| + |
| struct proc_dir_entry *proc_create_data(const char *name, umode_t mode, |
| struct proc_dir_entry *parent, |
| const struct file_operations *proc_fops, |
| --- a/fs/proc/inode.c |
| +++ b/fs/proc/inode.c |
| @@ -423,6 +423,10 @@ struct inode *proc_get_inode(struct supe |
| inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; |
| PROC_I(inode)->pde = de; |
| |
| + if (is_empty_pde(de)) { |
| + make_empty_dir_inode(inode); |
| + return inode; |
| + } |
| if (de->mode) { |
| inode->i_mode = de->mode; |
| inode->i_uid = de->uid; |
| --- a/fs/proc/internal.h |
| +++ b/fs/proc/internal.h |
| @@ -191,6 +191,12 @@ static inline struct proc_dir_entry *pde |
| } |
| extern void pde_put(struct proc_dir_entry *); |
| |
| +static inline bool is_empty_pde(const struct proc_dir_entry *pde) |
| +{ |
| + return S_ISDIR(pde->mode) && !pde->proc_iops; |
| +} |
| +struct proc_dir_entry *proc_create_mount_point(const char *name); |
| + |
| /* |
| * inode.c |
| */ |
| --- a/fs/proc/root.c |
| +++ b/fs/proc/root.c |
| @@ -182,10 +182,10 @@ void __init proc_root_init(void) |
| #endif |
| proc_mkdir("fs", NULL); |
| proc_mkdir("driver", NULL); |
| - proc_mkdir("fs/nfsd", NULL); /* somewhere for the nfsd filesystem to be mounted */ |
| + proc_create_mount_point("fs/nfsd"); /* somewhere for the nfsd filesystem to be mounted */ |
| #if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE) |
| /* just give it a mountpoint */ |
| - proc_mkdir("openprom", NULL); |
| + proc_create_mount_point("openprom"); |
| #endif |
| proc_tty_init(); |
| proc_mkdir("bus", NULL); |