aboutsummaryrefslogtreecommitdiffstats
path: root/fs/configfs/symlink.c
diff options
context:
space:
mode:
authorLouis Rilling <louis.rilling@kerlabs.com>2008-07-04 10:56:05 -0400
committerMark Fasheh <mfasheh@suse.com>2008-07-31 19:21:13 -0400
commit2a109f2a4155f168047aa2f5b3a170e279bef89a (patch)
tree8e9a080046fb1abdba10e288b89e92cc4c39f6ea /fs/configfs/symlink.c
parent9a73d78cda750f12e25eb811878f2d9dbab1bc6e (diff)
[PATCH] configfs: Prevent userspace from creating new entries under attaching directories
process 1: process 2: configfs_mkdir("A") attach_group("A") attach_item("A") d_instantiate("A") populate_groups("A") mutex_lock("A") attach_group("A/B") attach_item("A") d_instantiate("A/B") mkdir("A/B/C") do_path_lookup("A/B/C", LOOKUP_PARENT) ok lookup_create("A/B/C") mutex_lock("A/B") ok configfs_mkdir("A/B/C") ok attach_group("A/C") attach_item("A/C") d_instantiate("A/C") populate_groups("A/C") mutex_lock("A/C") attach_group("A/C/D") attach_item("A/C/D") failure mutex_unlock("A/C") detach_groups("A/C") nothing to do mkdir("A/C/E") do_path_lookup("A/C/E", LOOKUP_PARENT) ok lookup_create("A/C/E") mutex_lock("A/C") ok configfs_mkdir("A/C/E") ok detach_item("A/C") d_delete("A/C") mutex_unlock("A") detach_groups("A") mutex_lock("A/B") detach_group("A/B") detach_groups("A/B") nothing since no _default_ group detach_item("A/B") mutex_unlock("A/B") d_delete("A/B") detach_item("A") d_delete("A") Two bugs: 1/ "A/B/C" and "A/C/E" are created, but never removed while their parent are removed in the end. The same could happen with symlink() instead of mkdir(). 2/ "A" and "A/C" inodes are not locked while detach_item() is called on them, which may probably confuse VFS. This commit fixes 1/, tagging new directories with CONFIGFS_USET_CREATING before building the inode and instantiating the dentry, and validating the whole group+default groups hierarchy in a second pass by clearing CONFIGFS_USET_CREATING. mkdir(), symlink(), lookup(), and dir_open() simply return -ENOENT if called in (or linking to) a directory tagged with CONFIGFS_USET_CREATING. This does not prevent userspace from calling stat() successfuly on such directories, but this prevents userspace from adding (children to | symlinking from/to | read/write attributes of | listing the contents of) not validated items. In other words, userspace will not interact with the subsystem on a new item until the new item creation completes correctly. It was first proposed to re-use CONFIGFS_USET_IN_MKDIR instead of a new flag CONFIGFS_USET_CREATING, but this generated conflicts when checking the target of a new symlink: a valid target directory in the middle of attaching a new user-created child item could be wrongly detected as being attached. 2/ is fixed by next commit. Signed-off-by: Louis Rilling <louis.rilling@kerlabs.com> Signed-off-by: Joel Becker <joel.becker@oracle.com> Signed-off-by: Mark Fasheh <mfasheh@suse.com>
Diffstat (limited to 'fs/configfs/symlink.c')
-rw-r--r--fs/configfs/symlink.c15
1 files changed, 15 insertions, 0 deletions
diff --git a/fs/configfs/symlink.c b/fs/configfs/symlink.c
index 61a886dbd601..bf74973b0492 100644
--- a/fs/configfs/symlink.c
+++ b/fs/configfs/symlink.c
@@ -76,6 +76,9 @@ static int create_link(struct config_item *parent_item,
76 struct configfs_symlink *sl; 76 struct configfs_symlink *sl;
77 int ret; 77 int ret;
78 78
79 ret = -ENOENT;
80 if (!configfs_dirent_is_ready(target_sd))
81 goto out;
79 ret = -ENOMEM; 82 ret = -ENOMEM;
80 sl = kmalloc(sizeof(struct configfs_symlink), GFP_KERNEL); 83 sl = kmalloc(sizeof(struct configfs_symlink), GFP_KERNEL);
81 if (sl) { 84 if (sl) {
@@ -100,6 +103,7 @@ static int create_link(struct config_item *parent_item,
100 } 103 }
101 } 104 }
102 105
106out:
103 return ret; 107 return ret;
104} 108}
105 109
@@ -129,6 +133,7 @@ int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symna
129{ 133{
130 int ret; 134 int ret;
131 struct nameidata nd; 135 struct nameidata nd;
136 struct configfs_dirent *sd;
132 struct config_item *parent_item; 137 struct config_item *parent_item;
133 struct config_item *target_item; 138 struct config_item *target_item;
134 struct config_item_type *type; 139 struct config_item_type *type;
@@ -137,9 +142,19 @@ int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symna
137 if (dentry->d_parent == configfs_sb->s_root) 142 if (dentry->d_parent == configfs_sb->s_root)
138 goto out; 143 goto out;
139 144
145 sd = dentry->d_parent->d_fsdata;
146 /*
147 * Fake invisibility if dir belongs to a group/default groups hierarchy
148 * being attached
149 */
150 ret = -ENOENT;
151 if (!configfs_dirent_is_ready(sd))
152 goto out;
153
140 parent_item = configfs_get_config_item(dentry->d_parent); 154 parent_item = configfs_get_config_item(dentry->d_parent);
141 type = parent_item->ci_type; 155 type = parent_item->ci_type;
142 156
157 ret = -EPERM;
143 if (!type || !type->ct_item_ops || 158 if (!type || !type->ct_item_ops ||
144 !type->ct_item_ops->allow_link) 159 !type->ct_item_ops->allow_link)
145 goto out_put; 160 goto out_put;