Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-or-later 2 : : /* -*- mode: c; c-basic-offset: 8; -*- 3 : : * vim: noexpandtab sw=8 ts=8 sts=0: 4 : : * 5 : : * symlink.c - operations for configfs symlinks. 6 : : * 7 : : * Based on sysfs: 8 : : * sysfs is Copyright (C) 2001, 2002, 2003 Patrick Mochel 9 : : * 10 : : * configfs Copyright (C) 2005 Oracle. All rights reserved. 11 : : */ 12 : : 13 : : #include <linux/fs.h> 14 : : #include <linux/module.h> 15 : : #include <linux/namei.h> 16 : : #include <linux/slab.h> 17 : : 18 : : #include <linux/configfs.h> 19 : : #include "configfs_internal.h" 20 : : 21 : : /* Protects attachments of new symlinks */ 22 : : DEFINE_MUTEX(configfs_symlink_mutex); 23 : : 24 : 0 : static int item_depth(struct config_item * item) 25 : : { 26 : : struct config_item * p = item; 27 : : int depth = 0; 28 : 0 : do { depth++; } while ((p = p->ci_parent) && !configfs_is_root(p)); 29 : 0 : return depth; 30 : : } 31 : : 32 : 0 : static int item_path_length(struct config_item * item) 33 : : { 34 : : struct config_item * p = item; 35 : : int length = 1; 36 : : do { 37 : 0 : length += strlen(config_item_name(p)) + 1; 38 : 0 : p = p->ci_parent; 39 : 0 : } while (p && !configfs_is_root(p)); 40 : 0 : return length; 41 : : } 42 : : 43 : 0 : static void fill_item_path(struct config_item * item, char * buffer, int length) 44 : : { 45 : : struct config_item * p; 46 : : 47 : 0 : --length; 48 : 0 : for (p = item; p && !configfs_is_root(p); p = p->ci_parent) { 49 : 0 : int cur = strlen(config_item_name(p)); 50 : : 51 : : /* back up enough to print this bus id with '/' */ 52 : 0 : length -= cur; 53 : 0 : memcpy(buffer + length, config_item_name(p), cur); 54 : 0 : *(buffer + --length) = '/'; 55 : : } 56 : 0 : } 57 : : 58 : 0 : static int configfs_get_target_path(struct config_item *item, 59 : : struct config_item *target, char *path) 60 : : { 61 : : int depth, size; 62 : : char *s; 63 : : 64 : 0 : depth = item_depth(item); 65 : 0 : size = item_path_length(target) + depth * 3 - 1; 66 : 0 : if (size > PATH_MAX) 67 : : return -ENAMETOOLONG; 68 : : 69 : : pr_debug("%s: depth = %d, size = %d\n", __func__, depth, size); 70 : : 71 : 0 : for (s = path; depth--; s += 3) 72 : 0 : strcpy(s,"../"); 73 : : 74 : 0 : fill_item_path(target, path, size); 75 : : pr_debug("%s: path = '%s'\n", __func__, path); 76 : 0 : return 0; 77 : : } 78 : : 79 : 0 : static int create_link(struct config_item *parent_item, 80 : : struct config_item *item, 81 : : struct dentry *dentry) 82 : : { 83 : 0 : struct configfs_dirent *target_sd = item->ci_dentry->d_fsdata; 84 : : char *body; 85 : : int ret; 86 : : 87 : 0 : if (!configfs_dirent_is_ready(target_sd)) 88 : : return -ENOENT; 89 : : 90 : 0 : body = kzalloc(PAGE_SIZE, GFP_KERNEL); 91 : 0 : if (!body) 92 : : return -ENOMEM; 93 : : 94 : 0 : configfs_get(target_sd); 95 : : spin_lock(&configfs_dirent_lock); 96 : 0 : if (target_sd->s_type & CONFIGFS_USET_DROPPING) { 97 : : spin_unlock(&configfs_dirent_lock); 98 : 0 : configfs_put(target_sd); 99 : 0 : kfree(body); 100 : 0 : return -ENOENT; 101 : : } 102 : 0 : target_sd->s_links++; 103 : : spin_unlock(&configfs_dirent_lock); 104 : 0 : ret = configfs_get_target_path(parent_item, item, body); 105 : 0 : if (!ret) 106 : 0 : ret = configfs_create_link(target_sd, parent_item->ci_dentry, 107 : : dentry, body); 108 : 0 : if (ret) { 109 : : spin_lock(&configfs_dirent_lock); 110 : 0 : target_sd->s_links--; 111 : : spin_unlock(&configfs_dirent_lock); 112 : 0 : configfs_put(target_sd); 113 : 0 : kfree(body); 114 : : } 115 : 0 : return ret; 116 : : } 117 : : 118 : : 119 : 0 : static int get_target(const char *symname, struct path *path, 120 : : struct config_item **target, struct super_block *sb) 121 : : { 122 : : int ret; 123 : : 124 : 0 : ret = kern_path(symname, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, path); 125 : 0 : if (!ret) { 126 : 0 : if (path->dentry->d_sb == sb) { 127 : 0 : *target = configfs_get_config_item(path->dentry); 128 : 0 : if (!*target) { 129 : : ret = -ENOENT; 130 : 0 : path_put(path); 131 : : } 132 : : } else { 133 : : ret = -EPERM; 134 : 0 : path_put(path); 135 : : } 136 : : } 137 : : 138 : 0 : return ret; 139 : : } 140 : : 141 : : 142 : 0 : int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) 143 : : { 144 : : int ret; 145 : : struct path path; 146 : : struct configfs_dirent *sd; 147 : : struct config_item *parent_item; 148 : 0 : struct config_item *target_item = NULL; 149 : : const struct config_item_type *type; 150 : : 151 : 0 : sd = dentry->d_parent->d_fsdata; 152 : : /* 153 : : * Fake invisibility if dir belongs to a group/default groups hierarchy 154 : : * being attached 155 : : */ 156 : 0 : if (!configfs_dirent_is_ready(sd)) 157 : : return -ENOENT; 158 : : 159 : 0 : parent_item = configfs_get_config_item(dentry->d_parent); 160 : 0 : type = parent_item->ci_type; 161 : : 162 : : ret = -EPERM; 163 : 0 : if (!type || !type->ct_item_ops || 164 : 0 : !type->ct_item_ops->allow_link) 165 : : goto out_put; 166 : : 167 : : /* 168 : : * This is really sick. What they wanted was a hybrid of 169 : : * link(2) and symlink(2) - they wanted the target resolved 170 : : * at syscall time (as link(2) would've done), be a directory 171 : : * (which link(2) would've refused to do) *AND* be a deep 172 : : * fucking magic, making the target busy from rmdir POV. 173 : : * symlink(2) is nothing of that sort, and the locking it 174 : : * gets matches the normal symlink(2) semantics. Without 175 : : * attempts to resolve the target (which might very well 176 : : * not even exist yet) done prior to locking the parent 177 : : * directory. This perversion, OTOH, needs to resolve 178 : : * the target, which would lead to obvious deadlocks if 179 : : * attempted with any directories locked. 180 : : * 181 : : * Unfortunately, that garbage is userland ABI and we should've 182 : : * said "no" back in 2005. Too late now, so we get to 183 : : * play very ugly games with locking. 184 : : * 185 : : * Try *ANYTHING* of that sort in new code, and you will 186 : : * really regret it. Just ask yourself - what could a BOFH 187 : : * do to me and do I want to find it out first-hand? 188 : : * 189 : : * AV, a thoroughly annoyed bastard. 190 : : */ 191 : : inode_unlock(dir); 192 : 0 : ret = get_target(symname, &path, &target_item, dentry->d_sb); 193 : : inode_lock(dir); 194 : 0 : if (ret) 195 : : goto out_put; 196 : : 197 : 0 : if (dentry->d_inode || d_unhashed(dentry)) 198 : : ret = -EEXIST; 199 : : else 200 : 0 : ret = inode_permission(dir, MAY_WRITE | MAY_EXEC); 201 : 0 : if (!ret) 202 : 0 : ret = type->ct_item_ops->allow_link(parent_item, target_item); 203 : 0 : if (!ret) { 204 : 0 : mutex_lock(&configfs_symlink_mutex); 205 : 0 : ret = create_link(parent_item, target_item, dentry); 206 : 0 : mutex_unlock(&configfs_symlink_mutex); 207 : 0 : if (ret && type->ct_item_ops->drop_link) 208 : 0 : type->ct_item_ops->drop_link(parent_item, 209 : : target_item); 210 : : } 211 : : 212 : 0 : config_item_put(target_item); 213 : 0 : path_put(&path); 214 : : 215 : : out_put: 216 : 0 : config_item_put(parent_item); 217 : 0 : return ret; 218 : : } 219 : : 220 : 0 : int configfs_unlink(struct inode *dir, struct dentry *dentry) 221 : : { 222 : 0 : struct configfs_dirent *sd = dentry->d_fsdata, *target_sd; 223 : : struct config_item *parent_item; 224 : : const struct config_item_type *type; 225 : : int ret; 226 : : 227 : : ret = -EPERM; /* What lack-of-symlink returns */ 228 : 0 : if (!(sd->s_type & CONFIGFS_ITEM_LINK)) 229 : : goto out; 230 : : 231 : 0 : target_sd = sd->s_element; 232 : : 233 : 0 : parent_item = configfs_get_config_item(dentry->d_parent); 234 : 0 : type = parent_item->ci_type; 235 : : 236 : : spin_lock(&configfs_dirent_lock); 237 : 0 : list_del_init(&sd->s_sibling); 238 : : spin_unlock(&configfs_dirent_lock); 239 : 0 : configfs_drop_dentry(sd, dentry->d_parent); 240 : 0 : dput(dentry); 241 : 0 : configfs_put(sd); 242 : : 243 : : /* 244 : : * drop_link() must be called before 245 : : * decrementing target's ->s_links, so that the order of 246 : : * drop_link(this, target) and drop_item(target) is preserved. 247 : : */ 248 : 0 : if (type && type->ct_item_ops && 249 : 0 : type->ct_item_ops->drop_link) 250 : 0 : type->ct_item_ops->drop_link(parent_item, 251 : 0 : target_sd->s_element); 252 : : 253 : : spin_lock(&configfs_dirent_lock); 254 : 0 : target_sd->s_links--; 255 : : spin_unlock(&configfs_dirent_lock); 256 : 0 : configfs_put(target_sd); 257 : : 258 : 0 : config_item_put(parent_item); 259 : : 260 : : ret = 0; 261 : : 262 : : out: 263 : 0 : return ret; 264 : : } 265 : : 266 : : const struct inode_operations configfs_symlink_inode_operations = { 267 : : .get_link = simple_get_link, 268 : : .setattr = configfs_setattr, 269 : : }; 270 : :