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 : :
|